123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /******************************************************************************
- *
- * Copyright (C) 2020 by
- * The Salk Institute for Biological Studies and
- * Pittsburgh Supercomputing Center, Carnegie Mellon University
- *
- * Use of this source code is governed by an MIT-style
- * license that can be found in the LICENSE file or at
- * https://opensource.org/licenses/MIT.
- *
- ******************************************************************************/
- #include "count_buffer.h"
- #include <iomanip>
- #include <sstream>
- #include "logging.h"
- #include "util.h"
- #include "bng/filesystem_utils.h"
- using namespace std;
- const uint GDAT_COLUMN_WIDTH = 14;
- namespace MCell {
- void CountItem::write_as_dat(std::ostream& out) const {
- out << time << " " << value << "\n";
- }
- static void write_gdat_value(std::ostream& outs, double d) {
- // there is no way to set number of digits in an exponent
- // so we must do it manually
- // split exponent and base as string - we do not want to do
- // any numerical computation here
- stringstream ss;
- ss << scientific << setprecision(GDAT_COLUMN_WIDTH - 6) << d;
- string s = ss.str();
- size_t pos = s.find('e');
- assert(pos != string::npos);
- string base = s.substr(0, pos);
- int exponent = stoi(s.substr(pos + 1));
- string sign;
- if (exponent >= 0) {
- sign = "+";
- }
- else {
- // setfill/setw does not add '0' for negative values
- sign = "-";
- exponent = -exponent;
- }
- outs << base << "e" << sign << setfill('0') << setw(2) << exponent;
- }
- void CountBuffer::flush() {
- if (!fout.is_open()) {
- open(true);
- }
- if (output_format == CountOutputFormat::DAT) {
- // there is a single column
- assert(data.size() == 1);
- for (const auto& item: data[0]) {
- assert(item.column_index == 0);
- item.write_as_dat(fout);
- }
- }
- else {
- assert(data.size() >= 1);
- // output row
- // expecting that each column has the same depth
- size_t num_rows = data[0].size();
- for (size_t row = 0; row < num_rows; row++) {
- // simply use time from the first column
- double time = data[0][row].time;
- fout << " ";
- write_gdat_value(fout, time);
- // output each column
- for (size_t col = 0; col < data.size(); col++) {
- assert(row < data[col].size());
- const auto& item = data[col][row];
- release_assert(cmp_eq(item.time, time, SQRT_EPS) && "Mismatch in gdat column times");
- fout << " ";
- write_gdat_value(fout, item.value);
- }
- fout << "\n";
- }
- }
- fout.flush(); // flush the data so the user can see them
- for (auto& column: data) {
- column.clear();
- }
- }
- void CountBuffer::write_gdat_header() {
- assert(fout.is_open());
- assert(output_format == CountOutputFormat::GDAT);
- fout << "#";
- string time = "time";
- time.insert(time.begin(), GDAT_COLUMN_WIDTH - time.size(), ' ');
- fout << time;
- for (const string& name: column_names) {
- string col = name;
- if (GDAT_COLUMN_WIDTH > col.size()) {
- col.insert(col.begin(), GDAT_COLUMN_WIDTH - col.size() + 2, ' ');
- }
- else {
- col = " " + col;
- }
- fout << col;
- }
- fout << "\n";
- }
- bool CountBuffer::open(bool error_is_fatal) {
- FSUtils::make_dir_for_file_w_multiple_attempts(filename);
- if (!open_for_append) {
- // create an empty file so that we know that nothing was stored
- fout.open(filename);
- }
- else {
- // appending is used when restoring a checkpoint
- // opens a new file if the file does not exist
- fout.open(filename, std::ofstream::out | std::ofstream::app);
- }
- // write header
- if (output_format == CountOutputFormat::GDAT && !open_for_append) {
- write_gdat_header();
- }
- if (!fout.is_open()) {
- mcell_warn("Could not open file %s for writing.", filename.c_str());
- if (error_is_fatal) {
- mcell_error("Terminating due to error.");
- }
- return false;
- }
- return true;
- }
- void CountBuffer::flush_and_close() {
- flush();
- if (fout.is_open()) {
- fout.close();
- }
- else {
- bool ok = open(false);
- if (ok) {
- fout.close();
- }
- }
- }
- } /* namespace MCell */
|