123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- ///////////////////////////////////////////////////////////////////////////////////////
- /// \file outputchannel.cpp
- /// \brief Classes for formatting and printing output from the model
- ///
- /// \author Joe Siltberg
- /// $Date: 2013-10-10 10:20:33 +0200 (Thu, 10 Oct 2013) $
- ///
- ///////////////////////////////////////////////////////////////////////////////////////
- #include "config.h"
- #include "guess.h"
- #include "outputchannel.h"
- #include <vector>
- namespace GuessOutput {
- ColumnDescriptor::ColumnDescriptor(const char* title,
- int width,
- int precision)
- : t(title),
- w(width),
- p(precision) {
- }
- const std::string& ColumnDescriptor::title() const {
- return t;
- }
- int ColumnDescriptor::width() const {
- return w;
- }
- int ColumnDescriptor::precision() const {
- return p;
- }
- ColumnDescriptors::ColumnDescriptors(const std::vector<std::string>& titles,
- int width,
- int precision) {
- for (size_t i = 0; i < titles.size(); i++) {
- columns.push_back(ColumnDescriptor(titles[i].c_str(),
- width,
- precision));
- }
- }
- void ColumnDescriptors::operator+=(const ColumnDescriptor& col) {
- columns.push_back(col);
- }
- void ColumnDescriptors::operator+=(const ColumnDescriptors& cols) {
- columns.insert(columns.end(), cols.columns.begin(), cols.columns.end());
- }
- size_t ColumnDescriptors::size() const {
- return columns.size();
- }
- const ColumnDescriptor& ColumnDescriptors::operator[](size_t i) const {
- return columns[i];
- }
- TableDescriptor::TableDescriptor(const char* name,
- const ColumnDescriptors& columns)
- : n(name),
- cols(columns) {
- }
- const std::string& TableDescriptor::name() const {
- return n;
- }
- const ColumnDescriptors& TableDescriptor::columns() const {
- return cols;
- }
- Table::Table()
- : identifier(-1) {
- }
- Table::Table(int id)
- : identifier(id) {
- }
- int Table::id() const {
- return identifier;
- }
- bool Table::invalid() const {
- return identifier == -1;
- }
- Table OutputChannel::create_table(const TableDescriptor& descriptor) {
- Table table((int) table_descriptors.size());
- table_descriptors.push_back(descriptor);
- values.resize(table_descriptors.size());
- return table;
- }
- void OutputChannel::add_value(const Table& table, double d) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- // make sure this row isn't already full
- const TableDescriptor& td = table_descriptors[table.id()];
- if (values[table.id()].size() == td.columns().size()) {
- fail("Added too many values to a row in table %s!",
- td.name().c_str());
- }
- values[table.id()].push_back(d);
- }
- const TableDescriptor&
- OutputChannel::get_table_descriptor(const Table& table) const {
- return table_descriptors[table.id()];
- }
- const TableDescriptor&
- OutputChannel::get_table_descriptor(int id) const {
- return table_descriptors.at(id);
- }
- const std::vector<double>
- OutputChannel::get_current_row(const Table& table) const {
- return values[table.id()];
- }
- void OutputChannel::clear_current_row(const Table& table) {
- values[table.id()].clear();
- std::vector<double>().swap(values[table.id()]);
- }
- FileOutputChannel::FileOutputChannel(const char* out_dir,
- int coords_precision)
- : output_directory(out_dir) {
- // calculate suitable width for the coords columns,
- // longitudes take at most 4 characters (-180) before the decimal
- // point, add the decimal point, coords_precision and a little margin:
- const int LON_MAX_LEN = 4;
- const int MARGIN = 2;
- int coords_width = LON_MAX_LEN+1+coords_precision+MARGIN;
- xtring str;
- str.printf("%%%ds", coords_width);
- coords_title_format = (char*)str;
- str.printf("%%%d.%df", coords_width, coords_precision);
- coords_format = (char*)str;
- }
- FileOutputChannel::~FileOutputChannel() {
- for (size_t i = 0; i < files.size(); i++) {
- fclose(files[i]);
- }
- }
- Table FileOutputChannel::create_table(const TableDescriptor& descriptor) {
- Table table;
- FILE* file = NULL;
- if (descriptor.name() != "") {
- std::string full_path = output_directory + descriptor.name();
- file = fopen(full_path.c_str(), "w");
- if (file == NULL) {
- fail("Could not open %s for output\n"\
- "Close the file if it is open in another application",
- full_path.c_str());
- }
- else {
- table = OutputChannel::create_table(descriptor);
- files.push_back(file);
- printed_header.push_back(false);
- }
- }
- return table;
- }
- void FileOutputChannel::finish_row(const Table& table,
- double lon,
- double lat,
- int year) {
- finish_row(table, lon, lat, year, NOEXTRA, 0);
- }
- void FileOutputChannel::close_table(Table& table) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- FILE* file = files[table.id()];
- fclose(file);
- }
- void FileOutputChannel::finish_row(const Table& table,
- double lon,
- double lat,
- int year,
- columntype ctype,
- int ecvalue) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- FILE* file = files[table.id()];
- // make sure all columns have been added
- const std::vector<double>& row = get_current_row(table);
- const TableDescriptor& td = get_table_descriptor(table);
- if (row.size() < td.columns().size()) {
- fail("Too few values in a row in table %s", td.name().c_str());
- }
- // print the header if this is the first output for this file
- if (!printed_header[table.id()]) {
- // print title for coordinates and time columns
- fprintf(file, coords_title_format.c_str(), "Lon");
- fprintf(file, coords_title_format.c_str(), "Lat");
- fprintf(file, "%6s", "Year");
- if (ctype == CTDAY) {
- fprintf(file, "%5s", "Day");
- }
- else if (ctype == CTMONTH) {
- fprintf(file, "%5s", "Mth");
- }
- // print each column title
- int nbr_cols = (int) get_table_descriptor(table).columns().size();
- for (int i = 0; i < nbr_cols; i++) {
- fputs(format_header(table, i), file);
- }
- fprintf(file, "\n");
- printed_header[table.id()] = true;
- }
- // print out coordinates and time
- fprintf(file, coords_format.c_str(), lon);
- fprintf(file, coords_format.c_str(), lat);
- fprintf(file, "%6d", year);
- if (ctype != NOEXTRA) {
- fprintf(file, "%5d", ecvalue);
- }
- // print out the values
- for (size_t i = 0; i < row.size(); i++) {
- fprintf(file, format(table, (int)i), row[i]);
- }
- fprintf(file, "\n");
- fflush(file);
- // start on a new row
- clear_current_row(table);
- }
- const char* FileOutputChannel::format(const Table& table, int column) {
- const TableDescriptor& td = get_table_descriptor(table);
- const ColumnDescriptor& cd = td.columns()[column];
- // NB: not thread safe
- static char buf[100];
- sprintf(buf, " %%%d.%df", cd.width(), cd.precision());
- return buf;
- }
- const char* FileOutputChannel::format_header(const Table& table, int column) {
- const TableDescriptor& td = get_table_descriptor(table);
- const ColumnDescriptor& cd = td.columns()[column];
- // NB: not thread safe
- static char format[100];
- static char buf[100];
- sprintf(format, " %%%ds", cd.width());
- sprintf(buf, format, cd.title().c_str());
- return buf;
- }
- OutputRows::OutputRows(OutputChannel* output_channel,
- double longitude,
- double latitude,
- int year)
- : out(output_channel),
- lon(longitude),
- lat(latitude),
- y(year),
- c(NOEXTRA),
- v(0) {
- }
- OutputRows::OutputRows(OutputChannel* output_channel,
- double longitude,
- double latitude,
- int year,
- columntype ctype,
- int ecvalue)
- : out(output_channel),
- lon(longitude),
- lat(latitude),
- y(year),
- c(ctype),
- v(ecvalue) {
- }
- OutputRows::~OutputRows() {
- for (size_t i = 0; i < used_tables.size(); i++) {
- if (used_tables[i]) {
- if (c == NOEXTRA) {
- out->finish_row(Table(i), lon, lat, y);
- }
- else {
- out->finish_row(Table(i), lon, lat, y, c, v);
- }
- }
- }
- }
- void OutputRows::add_value(const Table& table,double d) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- int id = table.id();
- // remember that this table has gotten a value
- if (id >= static_cast<int>(used_tables.size())) {
- used_tables.resize(id+1);
- }
- used_tables[id] = true;
-
- // send the value to the output channel
- out->add_value(table, d);
- }
- #ifdef COMPRESS_OUTPUT
- GZFileOutputChannel::~GZFileOutputChannel() {
- for (size_t i = 0; i < gzfiles.size(); i++) {
- if ( gzfiles[i] != NULL ) {
- gzclose(gzfiles[i]);
- }
- else {
- if (!printed_header[i]) {
- const TableDescriptor& descriptor = get_table_descriptor(i);
- dprintf("warning! no output created for table %s\n", descriptor.name().c_str());
- }
- }
- }
- }
- Table GZFileOutputChannel::create_table(const TableDescriptor& descriptor) {
- Table table;
- if (descriptor.name() != "") {
- table = OutputChannel::create_table(descriptor);
- // file will be created when first line is written
- gzfiles.push_back(NULL);
- printed_header.push_back(false);
- }
- return table;
- }
- void GZFileOutputChannel::close_table(Table& table) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- // untested - destructor always used
- gzFile gzfile = gzfiles[table.id()];
- if ( gzfile != NULL ) {
- gzclose(gzfile);
- gzfiles[table.id()] = NULL;
- }
- else {
- if (!printed_header[table.id()]) {
- const TableDescriptor& descriptor = get_table_descriptor(table);
- dprintf("warning! no output created for table %s\n", descriptor.name().c_str());
- }
- }
- }
- void GZFileOutputChannel::finish_row(const Table& table,
- double lon,
- double lat,
- int year,
- columntype ctype,
- int ecvalue) {
- // do nothing for unused tables
- if (table.invalid()) {
- return;
- }
- gzFile gzfile = gzfiles[table.id()];
- // make sure all columns have been added
- const std::vector<double>& row = get_current_row(table);
- const TableDescriptor& td = get_table_descriptor(table);
-
- if (row.size() < td.columns().size()) {
- fail("Too few values in a row in table %s", td.name().c_str());
- }
- // print the header and open .gz file if this is the first output for this table
- if (!printed_header[table.id()]) {
- FILE* file = NULL;
- std::string full_path = output_directory + td.name() + ".hdr";
- file = fopen(full_path.c_str(), "w");
- if (file == NULL) {
- fail("Could not open %s for output\n"\
- "Close the file if it is open in another application",
- full_path.c_str());
- }
- // print title for coordinates and time columns
- fprintf(file, coords_title_format.c_str(), "Lon");
- fprintf(file, coords_title_format.c_str(), "Lat");
- fprintf(file, "%6s", "Year");
- if (ctype == CTDAY) {
- fprintf(file, "%5s", "Day");
- }
- else if (ctype == CTMONTH) {
- fprintf(file, "%5s", "Mth");
- }
- // print each column title
- int nbr_cols = (int) get_table_descriptor(table).columns().size();
- for (int i = 0; i < nbr_cols; i++) {
- fputs(format_header(table, i), file);
- }
- fprintf(file, "\n");
- printed_header[table.id()] = true;
- fclose(file);
- // create .gz file
- full_path = output_directory + td.name() + ".gz";
- gzfile = gzopen(full_path.c_str(), "wb");
- if (gzfile == NULL) {
- fail("Could not open %s for output\n" \
- "Close the file if it is open in another application",
- full_path.c_str());
- }
- else {
- gzfiles[table.id()] = gzfile;
- }
- }
- // use buffer to write only once to gzfile
- xtring line(1024);
- xtring buffer(1024);
- // print out coordinates and time
- buffer.printf(coords_format.c_str(), lon);
- line+=buffer;
- buffer.printf(coords_format.c_str(), lat);
- line+=buffer;
- buffer.printf("%6d", year);
- line+=buffer;
- if (ctype != NOEXTRA) {
- buffer.printf("%5d", ecvalue);
- line+=buffer;
- }
- // print out the values
- for (size_t i = 0; i < row.size(); i++) {
- buffer.printf(format(table, (int)i), row[i]);
- line+=buffer;
- }
- buffer.printf("\n");
- line+=buffer;
- // write line to file
- if ( gzfile == NULL ) {
- fail("Problem with output file for table %s\n", td.name().c_str());
- }
- gzputs(gzfile, line);
- //gzfile->flush(); // don't flush every line since this degrades performance
- // start on a new row
- clear_current_row(table);
- }
- #endif // COMPRESS_OUTPUT
- }
|