outputchannel.h 8.2 KB

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