123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- ///////////////////////////////////////////////////////////////////////////////////////
- /// \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 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);
- }
- }
|