ARTS  2.2.66
make_auto_md_h.cc
Go to the documentation of this file.
1 /* Copyright (C) 2000-2012 Stefan Buehler <sbuehler@ltu.se>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA. */
17 
68 #include "arts.h"
69 #include "array.h"
70 #include "file.h"
71 #include "methods.h"
72 #include "workspace_ng.h"
73 #include "agenda_record.h"
74 #include "global_data.h"
75 
76 /* Adds commas and indentation to parameter lists. */
77 void align(ofstream& ofs, bool& is_first_parameter, const String& indent)
78 {
79  // Add comma and line break, if not first element:
80  if (is_first_parameter)
81  is_first_parameter = false;
82  else
83  {
84  ofs << ",\n";
85  // Make proper indentation:
86  ofs << indent;
87  }
88 }
89 
91 
95 void write_method_header_documentation (ofstream& ofs, const MdRecord& mdd)
96 {
97  const Array<WsvRecord>& wsv_data = Workspace::wsv_data;
98 
99  String fullname = mdd.Name();
100 
101  // This is needed to flag the first function parameter, which
102  // needs no line break before being written:
103  bool is_first_parameter = true;
104 
105  // The String indent is needed to achieve the correct
106  // indentation of the functin parameters:
107  String indent(" ");
108 
109  // Flag to pass the workspace to the WSM. Only true if the WSM has
110  // an Agenda as input.
111  bool pass_workspace = false;
112 
113  // There are four lists of parameters that we have to
114  // write.
115  ArrayOfIndex vo=mdd.Out(); // Output
116  const ArrayOfIndex &vi = mdd.InOnly(); // Input
117  ArrayOfIndex vgo=mdd.GOutType(); // Generic Output
118  ArrayOfIndex vgi=mdd.GInType(); // Generic Input
119  // vo and vi contain handles of workspace variables,
120  // vgo and vgi handles of workspace variable groups.
121 
122  // Find out if the WSM gets an agenda as input. If so, pass
123  // the current workspace to this method
124  for (Index j = 0; !pass_workspace && j < mdd.In().nelem(); j++)
125  {
126  if (wsv_data[mdd.In()[j]].Group() == get_wsv_group_id ("Agenda"))
127  {
128  pass_workspace = true;
129  }
130  }
131 
132  // Find out if the WSM gets an agenda as input. If so, pass
133  // the current workspace to this method
134  for (Index j = 0; !pass_workspace && j < mdd.GInType().nelem(); j++)
135  {
136  if (mdd.GInType()[j] == get_wsv_group_id ("Agenda"))
137  {
138  pass_workspace = true;
139  }
140  }
141 
142  // Start with the name of the one line description
143  ofs << "//! WORKSPACE METHOD: " << fullname << ".\n";
144 
145  ofs << "/*!\n";
146 
147  String DoxyDescription = mdd.Description();
148  size_t start_pos = 0;
149 
150  while (start_pos != string::npos)
151  {
152  start_pos = DoxyDescription.find ("\n ", start_pos);
153  if (start_pos && start_pos != string::npos
154  && DoxyDescription[start_pos]-1 != '\n')
155  {
156  DoxyDescription.insert (start_pos + 1, "<br>");
157  start_pos += 5;
158  }
159  }
160 
161  // Some characters have to be masqueraded to appear properly in doxygen
162  // documentation
163  DoxyDescription.insert_substr ("<", "\\");
164  DoxyDescription.insert_substr (">", "\\");
165 
166  ofs << DoxyDescription << "\n";
167 
168  // Write the authors:
169  for (Index j=0; j<mdd.Authors().nelem(); ++j)
170  {
171  ofs << indent << "\\author " << mdd.Authors ()[j] << "\n";
172  }
173 
174  ofs << "\n";
175 
176  if (pass_workspace || mdd.PassWorkspace() || mdd.AgendaMethod())
177  {
178  ofs << indent << "\\param[in,out] " << "ws Workspace\n";
179  }
180 
181  // Write the Output workspace variables:
182  for (Index j=0; j<vo.nelem(); ++j)
183  {
184  ofs << indent << "\\param[out] "
185  << wsv_data[vo[j]].Name() << " WS Output\n";
186  }
187 
188  // Write the Generic output workspace variables:
189  for (Index j=0; j<vgo.nelem(); ++j)
190  {
191  ofs << indent << "\\param[out] ";
192 
193  if (mdd.GOut()[j].length())
194  ofs << mdd.GOut()[j];
195  else
196  ofs << "genericoutput" << j+1;
197 
198  if (mdd.Supergeneric ()) ofs << " Supergeneric output\n";
199  else ofs << " Generic output\n";
200  }
201 
202  // Write the Generic output workspace variable names:
203  if (mdd.PassWsvNames())
204  {
205  for (Index j=0; j<vgo.nelem(); ++j)
206  {
207  ofs << indent << "\\param[in] ";
208  if (mdd.GOut()[j].length())
209  ofs << mdd.GOut()[j] << "_wsvname";
210  else
211  ofs << "genericoutput" << j+1 << "_wsvname";
212 
213  ofs << " Generic Output Name" << endl;
214  }
215  }
216 
217  // Write the Input workspace variables:
218  for (Index j=0; j<vi.nelem(); ++j)
219  {
220  ofs << indent << "\\param[in] "
221  << wsv_data[vi[j]].Name() << " WS Input\n";
222  }
223 
224  // Write the Generic input workspace variables:
225  for (Index j=0; j<vgi.nelem(); ++j)
226  {
227  ofs << indent << "\\param[in] ";
228  if (mdd.GIn()[j] != "")
229  ofs << mdd.GIn()[j];
230  else
231  ofs << "genericinput" << j+1;
232 
233  ofs << " Generic Input";
234 
235  if (mdd.GInDefault()[j] != NODEF)
236  {
237  ofs << " (Default: \"" << mdd.GInDefault()[j] << "\")";
238  }
239  ofs << endl;
240  }
241 
242  // Write the Generic input workspace variable names:
243  if (mdd.PassWsvNames())
244  {
245  for (Index j=0; j<vgi.nelem(); ++j)
246  {
247  ofs << indent << "\\param[in] ";
248  if (mdd.GIn()[j].length())
249  ofs << mdd.GIn()[j] << "_wsvname";
250  else
251  ofs << "genericinput" << j+1 << "_wsvname";
252 
253  ofs << " Generic Input Name" << endl;
254  }
255  }
256 
257 
258  // Write agenda, if there is one:
259  if ( mdd.AgendaMethod() )
260  {
261  align(ofs,is_first_parameter,indent);
262  ofs << indent << "\\param[in] " << "input_agenda Agenda from controlfile\n";
263  }
264 
265  ofs << "*/\n";
266 }
267 
269 
273 void write_method_header( ofstream& ofs,
274  const MdRecord& mdd )
275 {
277  const Array<WsvRecord>& wsv_data = Workspace::wsv_data;
278 
279 // // Work out the full name to use:
280 // String fullname;
281 // {
282 // ostringstream os;
283 // os << mdd.Name() << add_to_name;
284 // fullname = os.str();
285 // }
286 
287  String fullname = mdd.Name();
288 
289  // This is needed to flag the first function parameter, which
290  // needs no line break before being written:
291  bool is_first_parameter = true;
292 
293  // The String indent is needed to achieve the correct
294  // indentation of the functin parameters:
295  String indent(fullname.nelem()+6,' ');
296 
297  // Flag to pass the workspace to the WSM. Only true if the WSM has
298  // an Agenda as input.
299  bool pass_workspace = false;
300 
301  // There are four lists of parameters that we have to
302  // write.
303  ArrayOfIndex vo=mdd.Out(); // Output
304  const ArrayOfIndex &vi = mdd.InOnly(); // Input
305  ArrayOfIndex vgo=mdd.GOutType(); // Generic Output
306  ArrayOfIndex vgi=mdd.GInType(); // Generic Input
307  // vo and vi contain handles of workspace variables,
308  // vgo and vgi handles of workspace variable groups.
309 
310  // Find out if the WSM gets an agenda as input. If so, pass
311  // the current workspace to this method
312  for (Index j = 0; !pass_workspace && j < mdd.In().nelem(); j++)
313  {
314  if (wsv_data[mdd.In()[j]].Group() == get_wsv_group_id ("Agenda"))
315  {
316  pass_workspace = true;
317  }
318  }
319 
320  // Find out if the WSM gets an agenda as input. If so, pass
321  // the current workspace to this method
322  for (Index j = 0; !pass_workspace && j < mdd.GInType().nelem(); j++)
323  {
324  if (mdd.GInType()[j] == get_wsv_group_id ("Agenda"))
325  {
326  pass_workspace = true;
327  }
328  }
329 
330  // There used to be a similar block here for the generic
331  // input/output variables. However, this was a mistake. For
332  // example, if a method has a vector as generic input and a
333  // vector as generic output, this does not mean that it is
334  // the same vector!
335 
336  if (mdd.Supergeneric() && mdd.UsesTemplates())
337  {
338  ofs << "template <typename T>" << endl;
339  }
340 
341  // Start with the name of the method:
342  ofs << "void " << fullname << "(";
343 
344  if (pass_workspace || mdd.PassWorkspace() || mdd.AgendaMethod())
345  {
346  ofs << "// Workspace reference:\n";
347  ofs << indent << "Workspace& ws";
348  is_first_parameter = false;
349  }
350 
351  // Write the Output workspace variables:
352  {
353  // Flag first parameter of this sort:
354  bool is_first_of_these = true;
355 
356  for (Index j=0; j<vo.nelem(); ++j)
357  {
358  // Add comma and line break, if not first element:
359  align(ofs,is_first_parameter,indent);
360 
361  // Add comment if this is the first of this sort
362  if (is_first_of_these)
363  {
364  ofs << "// WS Output:\n";
365  ofs << indent;
366  is_first_of_these = false;
367  }
368 
369  ofs << wsv_group_names[Workspace::wsv_data[vo[j]].Group()] << "& "
370  << Workspace::wsv_data[vo[j]].Name();
371  }
372  }
373 
374  // Write the Generic output workspace variables:
375  {
376  // Flag first parameter of this sort:
377  bool is_first_of_these = true;
378 
379  for (Index j=0; j<vgo.nelem(); ++j)
380  {
381  // Add comma and line break, if not first element:
382  align(ofs,is_first_parameter,indent);
383 
384  // Add comment if this is the first of this sort
385  if (is_first_of_these)
386  {
387  ofs << "// WS Generic Output:\n";
388  ofs << indent;
389  is_first_of_these = false;
390  }
391 
392  if (wsv_group_names[mdd.GOutType()[j]] == "Any") ofs << "T& ";
393  else ofs << wsv_group_names[mdd.GOutType()[j]] << "& ";
394 
395  if (mdd.GOut()[j].length()) ofs << mdd.GOut()[j];
396  else ofs << "genericoutput" << j+1;
397  }
398  }
399 
400  // Write the Generic output workspace variable names:
401  if (mdd.PassWsvNames())
402  {
403  // Flag first parameter of this sort:
404  bool is_first_of_these = true;
405 
406  for (Index j=0; j<vgo.nelem(); ++j)
407  {
408  // Add comma and line break, if not first element:
409  align(ofs,is_first_parameter,indent);
410 
411  // Add comment if this is the first of this sort
412  if (is_first_of_these)
413  {
414  ofs << "// WS Generic Output Names:\n";
415  ofs << indent;
416  is_first_of_these = false;
417  }
418 
419  ofs << "const String& ";
420  if (mdd.GOut()[j].length())
421  ofs << mdd.GOut()[j] << "_wsvname";
422  else
423  ofs << "genericoutput" << j+1 << "_wsvname";
424  }
425  }
426 
427  // Write the Input workspace variables:
428  {
429  // Flag first parameter of this sort.
430  bool is_first_of_these = true;
431 
432  for (Index j=0; j<vi.nelem(); ++j)
433  {
434  // Add comma and line break, if not first element:
435  align(ofs,is_first_parameter,indent);
436 
437  // Add type if this is the first of this sort.
438  if (is_first_of_these)
439  {
440  ofs << "// WS Input:\n";
441  ofs << indent;
442  is_first_of_these = false;
443  }
444 
445  ofs << "const "
446  << wsv_group_names[Workspace::wsv_data[vi[j]].Group()] << "& "
447  << Workspace::wsv_data[vi[j]].Name();
448  }
449  }
450 
451  // Write the Generic input workspace variables:
452  {
453  // Flag first parameter of this sort.
454  bool is_first_of_these = true;
455 
456  for (Index j=0; j<vgi.nelem(); ++j)
457  {
458  // Add comma and line break, if not first element:
459  align(ofs,is_first_parameter,indent);
460 
461  // Add type if this is the first of this sort.
462  if (is_first_of_these)
463  {
464  ofs << "// WS Generic Input:\n";
465  ofs << indent;
466  is_first_of_these = false;
467  }
468 
469  if (wsv_group_names[mdd.GInType()[j]] == "Any")
470  {
471  ofs << "const T& ";
472  if (mdd.GIn()[j].length()) ofs << mdd.GIn()[j];
473  else ofs << "genericinput" << j+1;
474  }
475  else
476  {
477  ofs << "const " << wsv_group_names[mdd.GInType()[j]] << "& ";
478  if (mdd.GIn()[j].length()) ofs << mdd.GIn()[j];
479  else ofs << "genericinput" << j+1;
480  }
481  }
482  }
483 
484  // Write the Generic input workspace variable names:
485  if (mdd.PassWsvNames())
486  {
487  // Flag first parameter of this sort:
488  bool is_first_of_these = true;
489 
490  for (Index j=0; j<vgi.nelem(); ++j)
491  {
492  // Add comma and line break, if not first element:
493  align(ofs,is_first_parameter,indent);
494 
495  // Add comment if this is the first of this sort
496  if (is_first_of_these)
497  {
498  ofs << "// WS Generic Input Names:\n";
499  ofs << indent;
500  is_first_of_these = false;
501  }
502 
503  ofs << "const String& ";
504  if (mdd.GIn()[j].length())
505  ofs << mdd.GIn()[j] << "_wsvname";
506  else
507  ofs << "genericinput" << j+1 << "_wsvname";
508  }
509  }
510 
511  // Write agenda, if there is one:
512  if ( mdd.AgendaMethod() )
513  {
514  align(ofs,is_first_parameter,indent);
515  ofs << "// Agenda from controlfile:\n";
516  ofs << indent;
517  ofs << "const Agenda& input_agenda";
518  }
519 
520  // Flag that is set to false if the WSM has verbosity as an input or
521  // output already. Otherwise it's passed as the last parameter.
522  bool pass_verbosity = true;
523 
524  // Find out if the WSM has the verbosity as input.
525  for (Index j = 0; pass_verbosity && j < mdd.In().nelem(); j++)
526  {
527  if (wsv_data[mdd.In()[j]].Name() == "verbosity")
528  {
529  pass_verbosity = false;
530  }
531  }
532 
533  // Find out if the WSM has the verbosity as output.
534  for (Index j = 0; pass_verbosity && j < mdd.Out().nelem(); j++)
535  {
536  if (wsv_data[mdd.Out()[j]].Name() == "verbosity")
537  {
538  pass_verbosity = false;
539  }
540  }
541 
542  if (pass_verbosity)
543  {
544  align(ofs,is_first_parameter,indent);
545  ofs << "// Verbosity object:\n";
546  ofs << indent;
547  ofs << "const Verbosity& verbosity";
548  }
549 
550  ofs << ");\n\n";
551 }
552 
553 
555 {
556  ostringstream os;
557 
558  bool is_sane = true;
559  for (Array<MdRecord>::const_iterator i = md_data.begin ();
560  i < md_data.end (); ++i)
561  {
562  bool invalid_author = false;
563  for (ArrayOfString::const_iterator j = i->Authors ().begin ();
564  !invalid_author && j < i->Authors ().end (); ++j)
565  {
566  if (*j == "" || *j == "unknown")
567  invalid_author = true;
568  }
569 
570  if (invalid_author)
571  {
572  os << i->Name () << ": Missing or invalid author.\n";
573  is_sane = false;
574  }
575 
576  switch (check_newline (i->Description ())) {
577  case 1:
578  os << i->Name () << ": Empty description.\n";
579  is_sane = false;
580  break;
581  case 2:
582  os << i->Name () << ": Missing newline at the end of description.\n";
583  is_sane = false;
584  break;
585  case 3:
586  os << i->Name () << ": Extra newline at the end of description.\n";
587  is_sane = false;
588  break;
589  }
590  }
591 
592  if (!is_sane)
593  {
594  cerr << "Error(s) found in workspace method documentation (check methods.cc):\n"
595  << os.str ();
596  }
597 
598  return is_sane;
599 }
600 
601 
602 int main()
603 {
604  try
605  {
606  // Make the global data visible:
608  using global_data::md_data;
609 
610  // Initialize the wsv group name array:
612 
613  // Initialize wsv data.
615 
616  // Initialize WsvMap.
618 
619  // Initialize method data.
621 
622  // Expand supergeneric methods:
624 
625  if (!md_sanity_checks (md_data))
626  return 1;
627 
628  const Index n_md = md_data.nelem();
629 
630  // Write auto_md.h:
631  // -----------
632  ofstream ofs;
633  open_output_file(ofs,"auto_md.h");
634 
635  ofs << "// This file was generated automatically by make_auto_md_h.cc.\n";
636  ofs << "// DO NOT EDIT !\n";
637  ofs << "// Generated: "
638  << __DATE__ << ", "
639  << __TIME__ << "\n\n";
640 
641  ofs << "#ifndef auto_md_h\n";
642  ofs << "#define auto_md_h\n\n";
643 
644  ofs << "#include \"matpackI.h\"\n"
645  << "#include \"matpackII.h\"\n"
646  << "#include \"abs_species_tags.h\"\n"
647  << "#include \"gas_abs_lookup.h\"\n"
648  << "#include \"gridded_fields.h\"\n"
649  << "#include \"optproperties.h\"\n"
650  << "#include \"jacobian.h\"\n"
651  << "#include \"mc_antenna.h\"\n"
652  << "#include \"m_general.h\"\n"
653  << "#include \"parser.h\"\n"
654  << "#include \"workspace_ng.h\"\n"
655  << "#include \"cia.h\"\n"
656  << "#include \"linemixingrecord.h\"\n"
657  << "\n";
658 
659  ofs << "// This is only used for a consistency check. You can get the\n"
660  << "// number of WSMs from md_data.nelem().\n"
661  << "#define N_MD " << n_md << "\n\n";
662 
663 
664  // Add all the method function declarations
665  ofs << "// Method function declarations:\n\n";
666  for (Index i=0; i<n_md; ++i)
667  {
668  const MdRecord& mdd = md_data[i];
669  if ( !mdd.UsesTemplates() )
670  {
672  write_method_header( ofs, mdd );
673  }
674  }
675 
676  // Add all the method function declarations
677  ofs << "// Supergeneric template function declarations:\n\n";
678  for (Index i=0; i<md_data_raw.nelem (); ++i)
679  {
680  const MdRecord& mdd = md_data_raw[i];
681  if ( mdd.Supergeneric() && mdd.UsesTemplates() )
682  {
684  write_method_header( ofs, mdd );
685  }
686  }
687 
688  // Add all the get-away function declarations:
689  ofs << "// Get-away function declarations:\n\n";
690  for (Index i=0; i<n_md; ++i)
691  {
692  const MdRecord& mdd = md_data[i];
693  if ( mdd.Supergeneric() )
694  {
695  ofs << "void " << mdd.Name()
696  << "_sg_" << mdd.ActualGroups()
697  << "_g(Workspace& ws, const MRecord& mr);\n";
698  }
699  else
700  {
701  ofs << "void " << mdd.Name()
702  << "_g(Workspace& ws, const MRecord& mr);\n";
703  }
704  }
705 
706  ofs << "\n";
707 
708  // Create prototypes for the agenda wrappers
709 
710  // Initialize agenda data.
713 
715  for (Index i = 0; i < agenda_data.nelem (); i++)
716  {
718 
719  ofs << ";\n\n";
720  }
721 
722  ofs << "\n#endif // auto_md_h\n";
723 
724  // Close auto_md.h.
725  ofs.close();
726 
727  }
728  catch (runtime_error x)
729  {
730  cout << "Something went wrong. Message text:\n";
731  cout << x.what() << '\n';
732  return 1;
733  }
734 
735  return 0;
736 }
Index get_wsv_group_id(const String &name)
Returns the id of the given group.
Definition: groups.cc:205
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:35
static Array< WsvRecord > wsv_data
Definition: workspace_ng.h:64
void write_method_header(ofstream &ofs, const MdRecord &mdd)
Write a method header.
Index nelem() const
Number of elements.
Definition: array.h:176
bool AgendaMethod() const
Definition: methods.h:107
const ArrayOfIndex & Out() const
Definition: methods.h:92
bool PassWsvNames() const
Definition: methods.h:111
This file contains basic functions to handle ASCII files.
All information for one workspace method.
Definition: methods.h:42
bool Supergeneric() const
Definition: methods.h:108
const String & Name() const
Definition: methods.h:89
void define_agenda_data()
Definition: agendas.cc:44
This file contains the definition of Array.
const ArrayOfString & GOut() const
Definition: methods.h:93
This file contains the declaration and partly the implementation of the workspace class...
The implementation for String, the ARTS string class.
Definition: mystring.h:63
const Array< String > & GInDefault() const
Definition: methods.h:101
void expand_md_data_raw_to_md_data()
Expand supergeneric methods.
Definition: methods_aux.cc:396
The global header file for ARTS.
#define NODEF
Definition: methods.h:36
void insert_substr(const my_basic_string< charT > &searchstr, const my_basic_string< charT > &insstr)
Insert string before all occurrences of the substring.
Definition: mystring.h:208
const String & ActualGroups() const
Definition: methods.h:112
static void define_wsv_data()
Definition: workspace.cc:50
const ArrayOfIndex & In() const
Definition: methods.h:97
int main()
const ArrayOfString & Authors() const
Definition: methods.h:91
Index nelem() const
Number of elements.
Definition: mystring.h:278
const Array< AgRecord > agenda_data
The lookup information for the agendas.
Definition: agendas.cc:41
bool md_sanity_checks(const Array< MdRecord > &md_data)
void write_method_header_documentation(ofstream &ofs, const MdRecord &mdd)
Write method header documentation.
const ArrayOfIndex & InOnly() const
Definition: methods.h:103
void open_output_file(ofstream &file, const String &name)
Open a file for writing.
Definition: file.cc:103
const ArrayOfIndex & GOutType() const
Definition: methods.h:94
void define_wsv_group_names()
Define the array of workspace variable group names.
Definition: groups.cc:84
const ArrayOfString wsv_group_names
The names associated with Wsv groups as Strings.
Definition: global_data.h:94
void define_md_data_raw()
Definition: methods.cc:126
void write_agenda_wrapper_header(ofstream &ofs, const AgRecord &agr)
Write a agenda wrapper header.
void align(ofstream &ofs, bool &is_first_parameter, const String &indent)
const Array< MdRecord > md_data
Lookup information for workspace methods.
Definition: methods_aux.cc:48
int check_newline(const String &s)
Checks if there is exactly one newline character at the end of the string.
Definition: file.cc:307
static void define_wsv_map()
Definition: workspace_ng.cc:53
const String & Description() const
Definition: methods.h:90
const ArrayOfIndex & GInType() const
Definition: methods.h:99
Declaration of the class MdRecord.
const ArrayOfString & GIn() const
Definition: methods.h:98
Declarations for AgRecord, storing lookup information for one agenda.
bool UsesTemplates() const
Definition: methods.h:109
const Array< MdRecord > md_data_raw
Lookup information for workspace methods.
Definition: methods.cc:39
bool PassWorkspace() const
Definition: methods.h:110