outputchannel.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. ///////////////////////////////////////////////////////////////////////////////////////
  2. /// \file outputchannel.h
  3. /// \brief Classes for formatting and printing output from the model
  4. ///
  5. /// \author Joe Siltberg
  6. /// $Date: 2018-02-02 18:01:35 +0100 (Fri, 02 Feb 2018) $
  7. ///
  8. ///////////////////////////////////////////////////////////////////////////////////////
  9. #ifndef LPJ_GUESS_OUTPUT_CHANNEL_H
  10. #define LPJ_GUESS_OUTPUT_CHANNEL_H
  11. #include <string>
  12. #include <vector>
  13. /// Output types for extra column
  14. typedef enum { NOEXTRA, CTDAY, CTMONTH } columntype;
  15. namespace GuessOutput {
  16. /// Describes one column in an output table
  17. class ColumnDescriptor {
  18. public:
  19. /// Creates a ColumnDescriptor
  20. /** \param title The title for the column
  21. * \param width Width of column for output formats of fixed width
  22. * \param precision Number of digits after the decimal point
  23. */
  24. ColumnDescriptor(const char* title, int width, int precision);
  25. /// Get the column title
  26. const std::string& title() const;
  27. /// Get the column width
  28. int width() const;
  29. /// Get the column precision
  30. int precision() const;
  31. private:
  32. std::string t;
  33. int w;
  34. int p;
  35. };
  36. /// A list of column descriptors
  37. class ColumnDescriptors {
  38. public:
  39. /// Creates a ColumnDescriptors with no columns
  40. ColumnDescriptors() {}
  41. /// Creates a ColumnDescriptors where all columns have the same format
  42. ColumnDescriptors(const std::vector<std::string>& titles,
  43. int width,
  44. int precision);
  45. /// Add a ColumnDescriptor to the end of the list
  46. void operator+=(const ColumnDescriptor& col);
  47. /// Append a ColumnDescriptors to the end of this one
  48. void operator+=(const ColumnDescriptors& cols);
  49. /// Get the number of columns
  50. size_t size() const;
  51. /// Get one ColumnDescriptor
  52. const ColumnDescriptor& operator[](size_t i) const;
  53. private:
  54. std::vector<ColumnDescriptor> columns;
  55. };
  56. /// Describes an output table
  57. /** Each table is described by a name and a number of column descriptors.
  58. */
  59. class TableDescriptor {
  60. public:
  61. /// Creates a TableDescriptor
  62. TableDescriptor(const char* name,
  63. const ColumnDescriptors& columns);
  64. /// Get the name of the table
  65. const std::string& name() const;
  66. /// Get the column descriptors
  67. const ColumnDescriptors& columns() const;
  68. private:
  69. std::string n;
  70. ColumnDescriptors cols;
  71. };
  72. /// A handle to an output table
  73. /** Should be created by a call to create_table in an OutputChannel */
  74. class Table {
  75. public:
  76. /// Creates an invalid table
  77. Table();
  78. /// Creates a table with a given id
  79. Table(int id);
  80. /// Get the id of the table
  81. int id() const;
  82. /// Is this an invalid table?
  83. bool invalid() const;
  84. private:
  85. int identifier;
  86. };
  87. /// The interface to an output channel
  88. /** All output should be sent via an output channel. The output channel
  89. * takes care of formatting the values and writing it to the right files,
  90. * database tables or whatever.
  91. *
  92. * This class is an abstract base class, so a suitable sub-class should
  93. * be used, for instance FileOutputChannel for regular file output.
  94. */
  95. class OutputChannel {
  96. public:
  97. virtual ~OutputChannel() {}
  98. /// Creates an output table and returns a handle to it
  99. virtual Table create_table(const TableDescriptor& descriptor);
  100. /// Adds a value to the next row of output for a given table
  101. /** If the table is invalid, no action is taken. */
  102. virtual void add_value(const Table& table, double d);
  103. /// Finalizes the output of one row, annual output
  104. virtual void finish_row(const Table& table, double lon, double lat,
  105. int year) = 0;
  106. /// Finalizes the output of one row, daily or monthly output
  107. virtual void finish_row(const Table& table, double lon, double lat,
  108. int year, columntype ctype, int ecvalue) = 0;
  109. virtual void close_table(Table& table) = 0;
  110. protected:
  111. /// Get the table descriptor for a table
  112. const TableDescriptor& get_table_descriptor(const Table& table) const;
  113. /// Get the added values for the current row
  114. const std::vector<double> get_current_row(const Table& table) const;
  115. /// Should be called at the end of finish_row
  116. /** Removes all values stores in memory for the current row */
  117. void clear_current_row(const Table& table);
  118. private:
  119. std::vector<TableDescriptor> table_descriptors;
  120. std::vector<std::vector<double> > values;
  121. };
  122. /// An output channel for regular text files with fixed width columns
  123. /** This output channel creates one text file for each output table.
  124. */
  125. class FileOutputChannel : public OutputChannel {
  126. public:
  127. /// Creates a FileOutputChannel
  128. /** \param out_dir All output files are placed in this directory.
  129. * \param coords_precision Precision to use when printing coordinates
  130. */
  131. FileOutputChannel(const char* out_dir, int coords_precision);
  132. /// Destructor - closes all opened files
  133. ~FileOutputChannel();
  134. /// Creates an output file
  135. /** \see OutputChannel::create_table */
  136. Table create_table(const TableDescriptor& descriptor);
  137. void close_table(Table& table);
  138. /// Prints the values of the current row to the file
  139. /** \see OutputChannel::finish_row */
  140. void finish_row(const Table& table, double lon, double lat,
  141. int year);
  142. /// Function to print the values of the current row to the file
  143. void finish_row(const Table& table, double lon, double lat,
  144. int year, columntype ctype, int ecvalue);
  145. private:
  146. /// Returns the printf style format string to be used for a column
  147. const char* format(const Table& table, int column);
  148. /// Formats a column title
  149. const char* format_header(const Table& table, int column);
  150. const std::string output_directory;
  151. std::string coords_title_format;
  152. std::string coords_format;
  153. std::vector<FILE*> files;
  154. /// Whether the header has been printed for each file
  155. std::vector<bool> printed_header;
  156. };
  157. /// A convenience class for managing the output of one row to multiple tables.
  158. /** At the end of the life time of an object of this class, finish_row is
  159. * called for all tables that have gotten values.
  160. */
  161. class OutputRows {
  162. public:
  163. /// OutputRows for annual output
  164. OutputRows(OutputChannel* output_channel, double longitude, double latitude, int year);
  165. /// OutputRows for daily or monthly output
  166. OutputRows(OutputChannel* output_channel, double longitude, double latitude, int year, columntype ctype, int ecvalue);
  167. /// Calls finish_row for all involved tables
  168. ~OutputRows();
  169. /// Adds a value to one of the tables
  170. /** \see OutputChannel::add_value */
  171. void add_value(const Table& table, double d);
  172. private:
  173. OutputChannel* out;
  174. double lon;
  175. double lat;
  176. int y;
  177. columntype c;
  178. int v;
  179. std::vector<bool> used_tables;
  180. };
  181. /// Help function to prepare C:N values for output
  182. /** Avoids division by zero and limits the results to a maximum
  183. * value to avoid inf or values large enough to ruin the alignment
  184. * in the output.
  185. *
  186. * If both cmass and nmass is 0, the function returns 0.
  187. */
  188. inline double limited_cton(double cmass, double nmass) {
  189. const double MAX_CTON = 1000;
  190. if (nmass > 0.0) {
  191. return min(MAX_CTON, cmass / nmass);
  192. }
  193. else if (cmass > 0.0) {
  194. return MAX_CTON;
  195. }
  196. else {
  197. return 0.0;
  198. }
  199. }
  200. }
  201. #endif // LPJ_GUESS_OUTPUT_CHANNEL_H