ARTS 2.5.11 (git: 725533f0)
make_auto_md_h.cc
Go to the documentation of this file.
1
51#include "agenda_record.h"
52#include "array.h"
53#include "arts.h"
54#include "debug.h"
55#include "file.h"
56#include "global_data.h"
57#include "methods.h"
58#include "workspace.h"
60#include "workspace_ng.h"
61#include <stdexcept>
62
63/* Adds commas and indentation to parameter lists. */
64void align(ofstream& ofs, bool& is_first_parameter, const String& indent) {
65 // Add comma and line break, if not first element:
66 if (is_first_parameter)
67 is_first_parameter = false;
68 else {
69 ofs << ",\n";
70 // Make proper indentation:
71 ofs << indent;
72 }
73}
74
76
80void write_method_header_documentation(ofstream& ofs, const MdRecord& mdd) {
82
83 const String& fullname = mdd.Name();
84
85 // This is needed to flag the first function parameter, which
86 // needs no line break before being written:
87 bool is_first_parameter = true;
88
89 // The String indent is needed to achieve the correct
90 // indentation of the functin parameters:
91 String indent(" ");
92
93 // Flag to pass the workspace to the WSM. Only true if the WSM has
94 // an Agenda as input.
95 bool pass_workspace = false;
96
97 // There are four lists of parameters that we have to
98 // write.
99 ArrayOfIndex vo = mdd.Out(); // Output
100 const ArrayOfIndex& vi = mdd.InOnly(); // Input
101 const ArrayOfIndex& vgo = mdd.GOutType(); // Generic Output
102 const ArrayOfIndex& vgi = mdd.GInType(); // Generic Input
103 // vo and vi contain handles of workspace variables,
104 // vgo and vgi handles of workspace variable groups.
105
106 // Find out if the WSM gets an agenda as input. If so, pass
107 // the current workspace to this method
108 for (Index j = 0; !pass_workspace && j < mdd.In().nelem(); j++) {
109 if (is_agenda_group_id(wsv_data[mdd.In()[j]].Group())) {
110 pass_workspace = true;
111 }
112 }
113
114 // Find out if the WSM gets an agenda as input. If so, pass
115 // the current workspace to this method
116 for (Index j = 0; !pass_workspace && j < mdd.GInType().nelem(); j++) {
117 if (is_agenda_group_id(mdd.GInType()[j])) {
118 pass_workspace = true;
119 }
120 }
121
122 // Start with the name of the one line description
123 ofs << "//! WORKSPACE METHOD: " << fullname << ".\n";
124
125 ofs << "/*!\n";
126
127 String DoxyDescription = mdd.Description();
128 size_t start_pos = 0;
129
130 while (start_pos != string::npos) {
131 start_pos = DoxyDescription.find("\n ", start_pos);
132 if (start_pos && start_pos != string::npos &&
133 DoxyDescription[start_pos] - 1 != '\n') {
134 DoxyDescription.insert(start_pos + 1, "<br>");
135 start_pos += 5;
136 }
137 }
138
139 // Some characters have to be masqueraded to appear properly in doxygen
140 // documentation
141 DoxyDescription.insert_substr("<", "\\");
142 DoxyDescription.insert_substr(">", "\\");
143
144 ofs << DoxyDescription << "\n";
145
146 // Write the authors:
147 for (Index j = 0; j < mdd.Authors().nelem(); ++j) {
148 ofs << indent << "\\author " << mdd.Authors()[j] << "\n";
149 }
150
151 ofs << "\n";
152
153 if (pass_workspace || mdd.PassWorkspace() || mdd.AgendaMethod()) {
154 ofs << indent << "\\param[in,out] "
155 << "ws Workspace\n";
156 }
157
158 // Write the Output workspace variables:
159 for (Index j = 0; j < vo.nelem(); ++j) {
160 bool inout =
161 (std::find(mdd.In().begin(), mdd.In().end(), vo[j]) != mdd.In().end());
162
163 if (inout) {
164 ofs << indent << "\\param[in,out] " << wsv_data[vo[j]].Name()
165 << " WS Input/Output\n";
166 } else {
167 ofs << indent << "\\param[out] " << wsv_data[vo[j]].Name()
168 << " WS Output\n";
169 }
170 }
171
172 // Write the Generic output workspace variables:
173 for (Index j = 0; j < vgo.nelem(); ++j) {
174 ofs << indent << "\\param[out] ";
175
176 if (mdd.GOut()[j].length())
177 ofs << mdd.GOut()[j];
178 else
179 ofs << "genericoutput" << j + 1;
180
181 if (mdd.Supergeneric())
182 ofs << " Supergeneric output\n";
183 else
184 ofs << " Generic output\n";
185 }
186
187 // Write the Generic output workspace variable names:
188 if (mdd.PassWsvNames()) {
189 for (Index j = 0; j < vgo.nelem(); ++j) {
190 ofs << indent << "\\param[in] ";
191 if (mdd.GOut()[j].length())
192 ofs << mdd.GOut()[j] << "_wsvname";
193 else
194 ofs << "genericoutput" << j + 1 << "_wsvname";
195
196 ofs << " Generic Output Name" << endl;
197 }
198 }
199
200 // Write the Input workspace variables:
201 for (Index j = 0; j < vi.nelem(); ++j) {
202 ofs << indent << "\\param[in] " << wsv_data[vi[j]].Name()
203 << " WS Input\n";
204 }
205
206 // Write the Generic input workspace variables:
207 for (Index j = 0; j < vgi.nelem(); ++j) {
208 ofs << indent << "\\param[in] ";
209 if (mdd.GIn()[j] != "")
210 ofs << mdd.GIn()[j];
211 else
212 ofs << "genericinput" << j + 1;
213
214 ofs << " Generic Input";
215
216 if (mdd.GInDefault()[j] != NODEF) {
217 ofs << " (Default: \"" << mdd.GInDefault()[j] << "\")";
218 }
219 ofs << endl;
220 }
221
222 // Write the Generic input workspace variable names:
223 if (mdd.PassWsvNames()) {
224 for (Index j = 0; j < vgi.nelem(); ++j) {
225 ofs << indent << "\\param[in] ";
226 if (mdd.GIn()[j].length())
227 ofs << mdd.GIn()[j] << "_wsvname";
228 else
229 ofs << "genericinput" << j + 1 << "_wsvname";
230
231 ofs << " Generic Input Name" << endl;
232 }
233 }
234
235 // Write agenda, if there is one:
236 if (mdd.AgendaMethod()) {
237 align(ofs, is_first_parameter, indent);
238 ofs << indent << "\\param[in] "
239 << "input_agenda Agenda from controlfile\n";
240 }
241
242 ofs << "*/\n";
243}
244
246
250void write_method_header(ofstream& ofs, const MdRecord& mdd) {
252 const Array<WsvRecord>& wsv_data = global_data::wsv_data;
253
254 // // Work out the full name to use:
255 // String fullname;
256 // {
257 // ostringstream os;
258 // os << mdd.Name() << add_to_name;
259 // fullname = os.str();
260 // }
261
262 const String& fullname = mdd.Name();
263
264 // This is needed to flag the first function parameter, which
265 // needs no line break before being written:
266 bool is_first_parameter = true;
267
268 // The String indent is needed to achieve the correct
269 // indentation of the functin parameters:
270 String indent(fullname.nelem() + 6, ' ');
271
272 // Flag to pass the workspace to the WSM. Only true if the WSM has
273 // an Agenda as input.
274 bool pass_workspace = false;
275
276 // There are four lists of parameters that we have to
277 // write.
278 ArrayOfIndex vo = mdd.Out(); // Output
279 const ArrayOfIndex& vi = mdd.InOnly(); // Input
280 const ArrayOfIndex& vgo = mdd.GOutType(); // Generic Output
281 const ArrayOfIndex& vgi = mdd.GInType(); // Generic Input
282 // vo and vi contain handles of workspace variables,
283 // vgo and vgi handles of workspace variable groups.
284
285 // Find out if the WSM gets an agenda as input. If so, pass
286 // the current workspace to this method
287 for (Index j = 0; !pass_workspace && j < mdd.In().nelem(); j++) {
288 if (is_agenda_group_id(wsv_data[mdd.In()[j]].Group())) {
289 pass_workspace = true;
290 }
291 }
292
293 // Find out if the WSM gets an agenda as input. If so, pass
294 // the current workspace to this method
295 for (Index j = 0; !pass_workspace && j < mdd.GInType().nelem(); j++) {
296 if (is_agenda_group_id(mdd.GInType()[j])) {
297 pass_workspace = true;
298 }
299 }
300
301 // There used to be a similar block here for the generic
302 // input/output variables. However, this was a mistake. For
303 // example, if a method has a vector as generic input and a
304 // vector as generic output, this does not mean that it is
305 // the same vector!
306
307 if (mdd.Supergeneric() && mdd.UsesTemplates()) {
308 ofs << "template <typename T>" << endl;
309 }
310
311 // Start with the name of the method:
312 ofs << "void " << fullname << "(";
313
314 if (pass_workspace || mdd.PassWorkspace() || mdd.AgendaMethod()) {
315 ofs << "// Workspace reference:\n";
316 ofs << indent << "Workspace& ws";
317 is_first_parameter = false;
318 }
319
320 // Write the Output workspace variables:
321 {
322 // Flag first parameter of this sort:
323 bool is_first_of_these = true;
324
325 for (Index j = 0; j < vo.nelem(); ++j) {
326 // Add comma and line break, if not first element:
327 align(ofs, is_first_parameter, indent);
328
329 // Add comment if this is the first of this sort
330 if (is_first_of_these) {
331 ofs << "// WS Output:\n";
332 ofs << indent;
333 is_first_of_these = false;
334 }
335
336 ofs << wsv_groups[global_data::wsv_data[vo[j]].Group()] << "& "
337 << global_data::wsv_data[vo[j]].Name();
338 }
339 }
340
341 // Write the Generic output workspace variables:
342 {
343 // Flag first parameter of this sort:
344 bool is_first_of_these = true;
345
346 for (Index j = 0; j < vgo.nelem(); ++j) {
347 // Add comma and line break, if not first element:
348 align(ofs, is_first_parameter, indent);
349
350 // Add comment if this is the first of this sort
351 if (is_first_of_these) {
352 ofs << "// WS Generic Output:\n";
353 ofs << indent;
354 is_first_of_these = false;
355 }
356
357 if (wsv_groups[mdd.GOutType()[j]] == "Any")
358 ofs << "T& ";
359 else
360 ofs << wsv_groups[mdd.GOutType()[j]] << "& ";
361
362 if (mdd.GOut()[j].length())
363 ofs << mdd.GOut()[j];
364 else
365 ofs << "genericoutput" << j + 1;
366 }
367 }
368
369 // Write the Generic output workspace variable names:
370 if (mdd.PassWsvNames()) {
371 // Flag first parameter of this sort:
372 bool is_first_of_these = true;
373
374 for (Index j = 0; j < vgo.nelem(); ++j) {
375 // Add comma and line break, if not first element:
376 align(ofs, is_first_parameter, indent);
377
378 // Add comment if this is the first of this sort
379 if (is_first_of_these) {
380 ofs << "// WS Generic Output Names:\n";
381 ofs << indent;
382 is_first_of_these = false;
383 }
384
385 ofs << "const String& ";
386 if (mdd.GOut()[j].length())
387 ofs << mdd.GOut()[j] << "_wsvname";
388 else
389 ofs << "genericoutput" << j + 1 << "_wsvname";
390 }
391 }
392
393 // Write the Input workspace variables:
394 {
395 // Flag first parameter of this sort.
396 bool is_first_of_these = true;
397
398 for (Index j = 0; j < vi.nelem(); ++j) {
399 // Add comma and line break, if not first element:
400 align(ofs, is_first_parameter, indent);
401
402 // Add type if this is the first of this sort.
403 if (is_first_of_these) {
404 ofs << "// WS Input:\n";
405 ofs << indent;
406 is_first_of_these = false;
407 }
408
409 ofs << "const " << wsv_groups[global_data::wsv_data[vi[j]].Group()]
410 << "& " << global_data::wsv_data[vi[j]].Name();
411 }
412 }
413
414 // Write the Generic input workspace variables:
415 {
416 // Flag first parameter of this sort.
417 bool is_first_of_these = true;
418
419 for (Index j = 0; j < vgi.nelem(); ++j) {
420 // Add comma and line break, if not first element:
421 align(ofs, is_first_parameter, indent);
422
423 // Add type if this is the first of this sort.
424 if (is_first_of_these) {
425 ofs << "// WS Generic Input:\n";
426 ofs << indent;
427 is_first_of_these = false;
428 }
429
430 if (wsv_groups[mdd.GInType()[j]] == "Any") {
431 ofs << "const T& ";
432 if (mdd.GIn()[j].length())
433 ofs << mdd.GIn()[j];
434 else
435 ofs << "genericinput" << j + 1;
436 } else {
437 ofs << "const " << wsv_groups[mdd.GInType()[j]] << "& ";
438 if (mdd.GIn()[j].length())
439 ofs << mdd.GIn()[j];
440 else
441 ofs << "genericinput" << j + 1;
442 }
443 }
444 }
445
446 // Write the Generic input workspace variable names:
447 if (mdd.PassWsvNames()) {
448 // Flag first parameter of this sort:
449 bool is_first_of_these = true;
450
451 for (Index j = 0; j < vgi.nelem(); ++j) {
452 // Add comma and line break, if not first element:
453 align(ofs, is_first_parameter, indent);
454
455 // Add comment if this is the first of this sort
456 if (is_first_of_these) {
457 ofs << "// WS Generic Input Names:\n";
458 ofs << indent;
459 is_first_of_these = false;
460 }
461
462 ofs << "const String& ";
463 if (mdd.GIn()[j].length())
464 ofs << mdd.GIn()[j] << "_wsvname";
465 else
466 ofs << "genericinput" << j + 1 << "_wsvname";
467 }
468 }
469
470 // Write agenda, if there is one:
471 if (mdd.AgendaMethod()) {
472 align(ofs, is_first_parameter, indent);
473 ofs << "// Agenda from controlfile:\n";
474 ofs << indent;
475 ofs << "const Agenda& input_agenda";
476 }
477
478 // Flag that is set to false if the WSM has verbosity as an input or
479 // output already. Otherwise it's passed as the last parameter.
480 bool pass_verbosity = true;
481
482 // Find out if the WSM has the verbosity as input.
483 for (Index j = 0; pass_verbosity && j < mdd.In().nelem(); j++) {
484 if (wsv_data[mdd.In()[j]].Name() == "verbosity") {
485 pass_verbosity = false;
486 }
487 }
488
489 // Find out if the WSM has the verbosity as output.
490 for (Index j = 0; pass_verbosity && j < mdd.Out().nelem(); j++) {
491 if (wsv_data[mdd.Out()[j]].Name() == "verbosity") {
492 pass_verbosity = false;
493 }
494 }
495
496 if (pass_verbosity) {
497 align(ofs, is_first_parameter, indent);
498 ofs << "// Verbosity object:\n";
499 ofs << indent;
500 ofs << "const Verbosity& verbosity";
501 }
502
503 ofs << ");\n\n";
504}
505
506bool md_sanity_checks(const Array<MdRecord>& md_data) {
507 ostringstream os;
508
509 bool is_sane = true;
510 for (auto i = md_data.begin(); i < md_data.end();
511 ++i) {
512 bool invalid_author = false;
513 for (auto j = i->Authors().begin();
514 !invalid_author && j < i->Authors().end();
515 ++j) {
516 if (*j == "" || *j == "unknown") invalid_author = true;
517 }
518
519 if (invalid_author) {
520 os << i->Name() << ": Missing or invalid author.\n";
521 is_sane = false;
522 }
523
524 switch (check_newline(i->Description())) {
525 case 1:
526 os << i->Name() << ": Empty description.\n";
527 is_sane = false;
528 break;
529 case 2:
530 os << i->Name() << ": Missing newline at the end of description.\n";
531 is_sane = false;
532 break;
533 case 3:
534 os << i->Name() << ": Extra newline at the end of description.\n";
535 is_sane = false;
536 break;
537 }
538 }
539
540 if (!is_sane) {
541 cerr
542 << "Error(s) found in workspace method documentation (check methods.cc):\n"
543 << os.str();
544 }
545
546 return is_sane;
547}
548
549int main() {
550 try {
551 // Make the global data visible:
554
555 // Initialize the wsv group name array:
557
558 // Initialize wsv data.
560
561 // Initialize WsvMap.
563
564 // Initialize method data.
566
567 // Expand supergeneric methods:
569
570 if (!md_sanity_checks(md_data)) return 1;
571
572 const Index n_md = md_data.nelem();
573
574 // Write auto_md.h:
575 // -----------
576 ofstream ofs;
577 open_output_file(ofs, "auto_md.h");
578
579 ofs << "// This file was generated automatically by make_auto_md_h.cc.\n";
580 ofs << "// DO NOT EDIT !\n";
581 ofs << "// Generated: " << __DATE__ << ", " << __TIME__ << "\n\n";
582
583 ofs << "#ifndef auto_md_h\n";
584 ofs << "#define auto_md_h\n\n";
585
586 ofs << "#include \"matpack_data.h\"\n"
587 << "#include \"matpack_sparse.h\"\n"
588 << "#include \"species_tags.h\"\n"
589 << "#include \"artstime.h\"\n"
590 << "#include \"gas_abs_lookup.h\"\n"
591 << "#include \"gridded_fields.h\"\n"
592 << "#include \"linemixing_hitran.h\"\n"
593 << "#include \"optproperties.h\"\n"
594 << "#include \"jacobian.h\"\n"
595 << "#include \"mc_antenna.h\"\n"
596 << "#include \"m_general.h\"\n"
597 << "#include \"parser.h\"\n"
598 << "#include \"workspace_ng.h\"\n"
599 << "#include \"cia.h\"\n"
600 << "#include \"covariance_matrix.h\"\n"
601 << "#include \"propagationmatrix.h\"\n"
602 << "#include <predefined/predef_data.h>\n"
603 << "#include \"transmissionmatrix.h\"\n"
604 << "#include \"sun.h\"\n"
605 << "#include \"telsem.h\"\n"
606 << "#include \"tessem.h\"\n"
607 << "#include \"xsec_fit.h\"\n"
608 << "#include \"absorptionlines.h\"\n"
609 << "#include \"linemixing.h\"\n"
610 << "#include \"callback.h\"\n"
611 << "\n";
612
613 ofs << "// This is only used for a consistency check. You can get the\n"
614 << "// number of WSMs from md_data.nelem().\n"
615 << "#define N_MD " << n_md << "\n\n";
616
617 // Add all the method function declarations
618 ofs << "// Method function declarations:\n\n";
619 for (Index i = 0; i < n_md; ++i) {
620 const MdRecord& mdd = md_data[i];
621 if (!mdd.UsesTemplates()) {
623 write_method_header(ofs, mdd);
624 }
625 }
626
627 // Add all the method function declarations
628 ofs << "// Supergeneric template function declarations:\n\n";
629 for (Index i = 0; i < md_data_raw.nelem(); ++i) {
630 const MdRecord& mdd = md_data_raw[i];
631 if (mdd.Supergeneric() && mdd.UsesTemplates()) {
633 write_method_header(ofs, mdd);
634 }
635 }
636
637 // Add all the get-away function declarations:
638 ofs << "// Get-away function declarations:\n\n";
639 for (Index i = 0; i < n_md; ++i) {
640 const MdRecord& mdd = md_data[i];
641 if (mdd.Supergeneric()) {
642 ofs << "void " << mdd.Name() << "_sg_" << mdd.ActualGroups()
643 << "_g(Workspace& ws, const MRecord& mr);\n";
644 } else {
645 ofs << "void " << mdd.Name()
646 << "_g(Workspace& ws, const MRecord& mr);\n";
647 }
648 }
649
650 ofs << "\n";
651
652 // Create prototypes for the agenda wrappers
653
654 // Initialize agenda data.
657
659 const Array<WsvRecord>& wsv_data = global_data::wsv_data;
660 for (Index i = 0; i < agenda_data.nelem(); i++) {
661 auto wsv_ptr = global_data::WsvMap.find(agenda_data[i].Name());
662 ARTS_USER_ERROR_IF(wsv_ptr == global_data::WsvMap.end(), "The ",
663 agenda_data[i].Name(), " agenda fails");
664 bool is_agenda_array = wsv_data[wsv_ptr->second].Group() ==
665 get_wsv_group_id("ArrayOfAgenda");
666 write_agenda_wrapper_header(ofs, agenda_data[i], is_agenda_array);
667
668 ofs << ";\n\n";
669 }
670
671 ofs << "\n#endif // auto_md_h\n";
672
673 // Close auto_md.h.
674 ofs.close();
675
676 } catch (const std::runtime_error& x) {
677 cout << "Something went wrong. Message text:\n";
678 cout << x.what() << '\n';
679 return 1;
680 }
681
682 return 0;
683}
void write_agenda_wrapper_header(ofstream &ofs, const AgRecord &agr, bool is_agenda_array)
Write a agenda wrapper header.
Declarations for AgRecord, storing lookup information for one agenda.
void define_agenda_data()
Definition agendas.cc:27
This file contains the definition of Array.
The global header file for ARTS.
void define_wsv_groups()
Define the array of workspace variable group names.
Definition groups.cc:47
This can be used to make arrays out of anything.
Definition array.h:31
Index nelem() const ARTS_NOEXCEPT
Definition array.h:75
All information for one workspace method.
Definition methods.h:21
const ArrayOfIndex & In() const
Definition methods.h:76
const String & Name() const
Definition methods.h:68
const ArrayOfIndex & InOnly() const
Definition methods.h:82
bool PassWorkspace() const
Definition methods.h:89
const ArrayOfIndex & GOutType() const
Definition methods.h:73
const String & ActualGroups() const
Definition methods.h:91
const Array< String > & GInDefault() const
Definition methods.h:80
bool PassWsvNames() const
Definition methods.h:90
const String & Description() const
Definition methods.h:69
const ArrayOfString & GOut() const
Definition methods.h:72
bool UsesTemplates() const
Definition methods.h:88
bool AgendaMethod() const
Definition methods.h:86
bool Supergeneric() const
Definition methods.h:87
const ArrayOfString & Authors() const
Definition methods.h:70
const ArrayOfIndex & Out() const
Definition methods.h:71
const ArrayOfIndex & GInType() const
Definition methods.h:78
const ArrayOfString & GIn() const
Definition methods.h:77
void insert_substr(const my_basic_string< charT > &searchstr, const my_basic_string< charT > &insstr)
Definition mystring.h:96
Index nelem() const
Definition mystring.h:172
Helper macros for debugging.
#define ARTS_USER_ERROR_IF(condition,...)
Definition debug.h:137
int check_newline(const std::string_view s)
Checks if there is exactly one newline character at the end of the string.
Definition file.cc:233
void open_output_file(ofstream &file, const std::string_view name)
Open a file for writing.
Definition file.cc:63
This file contains basic functions to handle ASCII files.
Index get_wsv_group_id(const String &name)
Returns the id of the given group.
Definition groups.cc:350
bool is_agenda_group_id(const Index group)
Check if group is an agenda group.
Definition groups.cc:389
void write_method_header_documentation(ofstream &ofs, const MdRecord &mdd)
Write method header documentation.
void write_method_header(ofstream &ofs, const MdRecord &mdd)
Write a method header.
void align(ofstream &ofs, bool &is_first_parameter, const String &indent)
int main()
bool md_sanity_checks(const Array< MdRecord > &md_data)
void define_md_data_raw()
Definition methods.cc:170
Declaration of the class MdRecord.
void expand_md_data_raw_to_md_data()
Expand supergeneric methods.
#define NODEF
Definition methods.h:18
const ArrayOfGroupRecord wsv_groups
The names associated with Wsv groups as Strings.
Definition global_data.h:74
const Array< MdRecord > md_data_raw
Lookup information for workspace methods.
Definition methods.cc:22
Array< WsvRecord > wsv_data
Definition workspace.cc:22
const Array< MdRecord > md_data
Lookup information for workspace methods.
std::map< String, Index > WsvMap
Definition workspace.cc:24
const Array< AgRecord > agenda_data
The lookup information for the agendas.
Definition agendas.cc:24
void define_wsv_data()
Definition workspace.cc:29
void define_wsv_map()
This file contains the Workspace class.