ARTS 2.5.11 (git: 725533f0)
make_auto_md_cc.cc
Go to the documentation of this file.
1#include "agenda_record.h"
2#include "array.h"
3#include "arts.h"
4#include "debug.h"
5#include "file.h"
6#include "global_data.h"
7#include "methods.h"
8#include "workspace.h"
10#include "workspace_ng.h"
11
12/* Adds commas and indentation to parameter lists. */
13void align(ofstream& ofs, bool& is_first_parameter, const String& indent) {
14 // Add comma and line break, if not first element:
15 if (is_first_parameter)
16 is_first_parameter = false;
17 else {
18 ofs << ",\n";
19 // Make proper indentation:
20 ofs << indent;
21 }
22}
23
24int main() {
25 try {
26 // Make the global data visible:
29
31
32 // Initialize the wsv group name array:
34
35 // Initialize wsv data.
37
38 // Initialize WsvMap.
40
41 // Initialize method data.
43
44 // Expand supergeneric methods:
46
47 const Index n_md = md_data.nelem();
48
49 // Write auto_md.cc:
50 // -----------
51 ofstream ofs;
52 open_output_file(ofs, "auto_md.cc");
53
54 ofs << "// This file was generated automatically by make_auto_md_cc.cc.\n";
55 ofs << "// DO NOT EDIT !\n";
56 ofs << "// Generated: " << __DATE__ << ", " << __TIME__ << "\n\n";
57
58 ofs << "#include \"arts.h\"\n"
59 << "#include \"auto_md.h\"\n"
60 << "#include \"wsv_aux.h\"\n"
61 << "#include \"mc_interp.h\"\n"
62 << "#include \"m_append.h\"\n"
63 << "#include \"m_delete.h\"\n"
64 << "#include \"m_copy.h\"\n"
65 << "#include \"m_conversion.h\"\n"
66 << "#include \"m_extract.h\"\n"
67 << "#include \"m_general.h\"\n"
68 << "#include \"m_gridded_fields.h\"\n"
69 << "#include \"m_ignore.h\"\n"
70 << "#include \"m_nc.h\"\n"
71 << "#include \"m_reduce.h\"\n"
72 << "#include \"m_select.h\"\n"
73 << "#include \"m_xml.h\"\n"
74 << "#include \"m_basic_types.h\"\n"
75 << "#include \"propagationmatrix.h\"\n"
76 << "#include \"transmissionmatrix.h\"\n"
77 << "#include \"agenda_record.h\"\n"
78 << "#include \"workspace_ng.h\"\n"
79 << "#include \"global_data.h\"\n"
80 << "#include \"absorptionlines.h\"\n"
81 << "\n";
82
83 //ofs << "static Index agendacallcount = 0;\n";
84
85 // Write all get-away functions:
86 // -----------------------------
87 for (Index i = 0; i < n_md; ++i) {
88 const MdRecord& mdd = md_data[i];
89
90 // This is needed to flag the first function parameter, which
91 // needs no line break before being written:
92 bool is_first_parameter = true;
93 // The String indent is needed to achieve the correct
94 // indentation of the functin parameters:
95 String indent = String(mdd.Name().nelem() + 3, ' ');
96 ;
97 // Flag to pass the workspace to the WSM. Only true if the WSM has
98 // an Agenda as input.
99 bool pass_workspace = false;
100
101 // There are four lists of parameters that we have to
102 // write.
103 ArrayOfIndex vo = mdd.Out(); // Output
104 const ArrayOfIndex& vi = mdd.InOnly(); // Input
105 ArrayOfIndex vgo = mdd.GOutType(); // Generic Output
106 ArrayOfIndex vgi = mdd.GInType(); // Generic Input
107 // vo and vi contain handles of workspace variables,
108 // vgo and vgi handles of workspace variable groups.
109
110 // There used to be a similar block here for the generic
111 // input/output variables. However, this was a mistake. For
112 // example, if a method has a vector as generic input and a
113 // vector as generic output, this does not mean that it is
114 // the same vector!
115
116 {
117 String ws, mr;
118
119 // Use parameter name only if it is used inside the function
120 // to avoid warnings
121 ws = " ws";
122 // if (!mdd.AgendaMethod() && !mdd.PassWorkspace() && !vo.nelem () && !vi.nelem () && !vgo.nelem () && !vgi.nelem ())
123 // {
124 // ws = "";
125 // }
126
127 // Find out if the WSM gets an agenda as input. If so, pass
128 // the current workspace to this method
129 for (Index j = 0; !pass_workspace && j < mdd.In().nelem(); j++) {
130 if (is_agenda_group_id(wsv_data[mdd.In()[j]].Group())) {
131 pass_workspace = true;
132 }
133 }
134
135 // Find out if the WSM gets an agenda as input. If so, pass
136 // the current workspace to this method
137 for (Index j = 0; !pass_workspace && j < mdd.GInType().nelem(); j++) {
138 if (is_agenda_group_id(mdd.GInType()[j])) {
139 pass_workspace = true;
140 }
141 }
142
143 // Use parameter name only if it is used inside the function
144 // to avoid warnings
145 if (vo.nelem() || vi.nelem() || vgo.nelem() || vgi.nelem() ||
146 mdd.AgendaMethod()) {
147 mr = " mr";
148 }
149
150 if (mdd.Supergeneric()) {
151 ofs << "void " << mdd.Name() << "_sg_" << mdd.ActualGroups()
152 << "_g(Workspace&" << ws << ", const MRecord&" << mr << ")\n"
153 << "{\n";
154 } else {
155 ofs << "void " << mdd.Name() << "_g(Workspace&" << ws
156 << ", const MRecord&" << mr << ")\n"
157 << "{\n";
158 }
159 }
160
161 // Erase all Output only variables to uncover if they are
162 // misused as Input variables
163#ifndef NDEBUG
164 // Determine indexes of variables in vo that are only use as output
165 ArrayOfIndex voutonly; // Output only
166 for (Index k = 0; k < vo.nelem(); ++k) {
167 bool output_only = true;
168 for (ArrayOfIndex::const_iterator j = mdd.In().begin();
169 j != mdd.In().end();
170 ++j)
171 if (vo[k] == *j) {
172 output_only = false;
173 break;
174 }
175
176 if (output_only) voutonly.push_back(k);
177 }
178
179 // Set builtin-type variables to a certain value,
180 // initialize objects with their default constructor
181 for (Index j = 0; j < voutonly.nelem(); j++) {
182 ostringstream docstr;
183 docstr << " // " << wsv_data[vo[voutonly[j]]].Name() << "\n";
184
185 String gname = wsv_groups[wsv_data[vo[voutonly[j]]].Group()];
186 ostringstream initstr;
187 if (gname == "Numeric")
188 initstr << " = NAN;";
189 else if (gname == "Index")
190 initstr << " = -1;";
191 else
192 initstr << " = " << gname << "();";
193
194 // Only zero-out the variable if it is not passed as an input
195 // variable for any other parameter
196 ofs << " if (mr.In().end() == find(mr.In().begin(), mr.In().end(),"
197 << " mr.Out()[" << voutonly[j] << "]))\n";
198 ofs << " (*(static_cast<" << wsv_groups[wsv_data[vo[voutonly[j]]].Group()]
199 << "*>(ws[mr.Out()[" << voutonly[j] << "]].get())))" << initstr.str();
200 ofs << docstr.str();
201 }
202#endif /* NDEBUG */
203
204 ofs << " " << mdd.Name() << "(";
205
206 if (pass_workspace || mdd.PassWorkspace() || mdd.AgendaMethod()) {
207 ofs << "ws";
208 is_first_parameter = false;
209 }
210
211 // Write the Output workspace variables:
212 for (Index j = 0; j < vo.nelem(); ++j) {
213 // Check by assert whether the group identifier is too
214 // large to correspond to a group. This can easily
215 // happen if somebody puts a variable identifier instead
216 // of a group identifier in the argument of GOUTPUT:
217 ARTS_ASSERT(wsv_data[vo[j]].Group() < wsv_groups.nelem());
218
219 // Add comma and line break, if not first element:
220 align(ofs, is_first_parameter, indent);
221
222 ofs << "*(static_cast<" << wsv_groups[wsv_data[vo[j]].Group()]
223 << "*>(ws[mr.Out()[" << j << "]].get()))";
224 }
225
226 // Write the Generic output workspace variables:
227 for (Index j = 0; j < vgo.nelem(); ++j) {
228 // Check by assert whether the group identifier is too
229 // large to correspond to a group. This can easily
230 // happen if somebody puts a variable identifier instead
231 // of a group identifier in the argument of GOUTPUT:
232 ARTS_ASSERT(vgo[j] < wsv_groups.nelem());
233
234 // Add comma and line break, if not first element:
235 align(ofs, is_first_parameter, indent);
236
237 ofs << "*(static_cast<" << wsv_groups[vgo[j]] << "*>(ws[mr.Out()["
238 << j + vo.nelem() << "]].get()))";
239 }
240
241 // Write the Generic output workspace variable names:
242 if (mdd.PassWsvNames()) {
243 for (Index j = 0; j < vgo.nelem(); ++j) {
244 // Add comma and line break, if not first element:
245 align(ofs, is_first_parameter, indent);
246
247 ofs << "(*ws.wsv_data_ptr)[mr.Out()[" << j + vo.nelem()
248 << "]].Name()";
249 }
250 }
251
252 // Write the Input workspace variables:
253 for (Index j = 0; j < vi.nelem(); ++j) {
254 // Add comma and line break, if not first element:
255 align(ofs, is_first_parameter, indent);
256
257 if (is_agenda_group_id(wsv_data[vi[j]].Group())) {
258 ofs << "*(static_cast<" << wsv_groups[wsv_data[vi[j]].Group()]
259 << "*>(ws[mr.In()[" << j << "]].get()))";
260 } else {
261 ofs << "*(static_cast<" << wsv_groups[wsv_data[vi[j]].Group()]
262 << "*>(ws[mr.In()[" << j << "]].get()))";
263 }
264 }
265
266 // Write the control parameters:
267 {
268 if (mdd.SetMethod()) {
269 // Add comma and line break, if not first element:
270 align(ofs, is_first_parameter, indent);
271
272 ofs << "mr.SetValue()";
273 } else {
274 // Write the Generic input workspace variables:
275 for (Index j = 0; j < vgi.nelem(); ++j) {
276 // Check by assert whether the group identifier is too
277 // large to correspond to a group. This can easily
278 // happen if somebody puts a variable identifier instead
279 // of a group identifier in the argument of GINPUT:
280 ARTS_ASSERT(vgi[j] < wsv_groups.nelem());
281
282 // Add comma and line break, if not first element:
283 align(ofs, is_first_parameter, indent);
284
285 ofs << "*(static_cast<" << wsv_groups[vgi[j]] << "*>(ws[mr.In()["
286 << j + vi.nelem() << "]].get()))";
287 }
288
289 // Write the Generic input workspace variable names:
290 if (mdd.PassWsvNames()) {
291 for (Index j = 0; j < vgi.nelem(); ++j) {
292 // Add comma and line break, if not first element:
293 align(ofs, is_first_parameter, indent);
294
295 ofs << "(*ws.wsv_data_ptr)[mr.In()[" << j + vi.nelem()
296 << "]].Name()";
297 }
298 }
299 }
300 }
301
302 // Write the agenda, if there is one.
303 if (mdd.AgendaMethod()) {
304 align(ofs, is_first_parameter, indent);
305 ofs << "mr.Tasks()";
306 }
307
308 // Flag that is set to false if the WSM has verbosity as an input or
309 // output already. Otherwise it's passed as the last parameter.
310 bool pass_verbosity = true;
311
312 // Find out if the WSM has the verbosity as input.
313 for (Index j = 0; pass_verbosity && j < mdd.In().nelem(); j++) {
314 if (wsv_data[mdd.In()[j]].Name() == "verbosity") {
315 pass_verbosity = false;
316 }
317 }
318
319 // Find out if the WSM has the verbosity as output.
320 for (Index j = 0; pass_verbosity && j < mdd.Out().nelem(); j++) {
321 if (wsv_data[mdd.Out()[j]].Name() == "verbosity") {
322 pass_verbosity = false;
323 }
324 }
325
326 if (pass_verbosity) {
327 static Index verbosity_wsv_id = global_data::WsvMap.at("verbosity");
328 static Index verbosity_group_id = get_wsv_group_id("Verbosity");
329 align(ofs, is_first_parameter, indent);
330 ofs << "*(static_cast<" << wsv_groups[verbosity_group_id] << "*>(ws["
331 << verbosity_wsv_id << "].get()))";
332 }
333
334 ofs << ");\n";
335 ofs << "}\n\n";
336 }
337
338 // Add getaways, the array that hold pointers to the getaway functions:
339 {
340 String indent = " ";
341 bool is_first_parameter = true;
342
343 ofs << "// The array holding the pointers to the getaway functions.\n"
344 << "void (*getaways[])(Workspace&, const MRecord&)\n"
345 << " = {";
346 for (Index i = 0; i < n_md; ++i) {
347 const MdRecord& mdd = md_data[i];
348
349 // Add comma and line break, if not first element:
350 align(ofs, is_first_parameter, indent);
351
352 if (mdd.Supergeneric()) {
353 ofs << mdd.Name() << "_sg_" << mdd.ActualGroups() << "_g";
354 } else {
355 ofs << mdd.Name() << "_g";
356 }
357 }
358 // Add empty slot which can be used by the API for external callbacks.
359 ofs << ", nullptr};\n\n";
360 }
361
362 // Agenda execute helper function
363
364 ofs << "void auto_md_agenda_execute_helper(bool& agenda_failed, String& agenda_error_msg, Workspace& ws, const Agenda& input_agenda)\n";
365 ofs << "{\n";
366 ofs << " const ArrayOfIndex& outputs_to_push = input_agenda.get_output2push();\n";
367 ofs << " const ArrayOfIndex& outputs_to_dup = input_agenda.get_output2dup();\n";
368 ofs << "\n";
369 ofs << " for (auto&& i : outputs_to_push)\n";
370 ofs << " {\n";
371 ofs << " // Even if a variable is only used as WSM output inside this agenda,\n";
372 ofs << " // It is possible that it is used as input further down by another agenda,\n";
373 ofs << " // which we can't see here. Therefore initialized variables have to be\n";
374 ofs << " // duplicated.\n";
375 ofs << " if (ws.is_initialized(i))\n";
376 ofs << " ws.duplicate(i);\n";
377 ofs << " else\n";
378 ofs << " ws.emplace(i);\n";
379 ofs << " }\n";
380 ofs << "\n";
381 ofs << " for (auto&& i : outputs_to_dup)\n";
382 ofs << " ws.duplicate(i);\n";
383 ofs << "\n";
384 ofs << " agenda_failed = false;\n";
385 ofs << " try\n";
386 ofs << " {\n";
387 ofs << " input_agenda.execute(ws);\n";
388 ofs << " }\n";
389 ofs << " catch (const std::exception &e)\n";
390 ofs << " {\n";
391 ofs << " ostringstream os;\n";
392 ofs << " os << \"Run-time error in agenda: \"\n";
393 ofs << " << input_agenda.name() << \'\\n\' << e.what();\n";
394 ofs << " agenda_failed = true;\n";
395 ofs << " agenda_error_msg = os.str();\n";
396 ofs << " }\n";
397 ofs << "\n";
398 ofs << " for (auto&& i : outputs_to_push)\n";
399 ofs << " ws.pop(i);\n";
400 ofs << "\n";
401 ofs << " for (auto&& i : outputs_to_dup)\n";
402 ofs << " ws.pop(i);\n";
403 ofs << "}\n\n";
404
405 // Create implementation of the agenda wrappers
406
407 // Initialize agenda data.
410
412 for (Index i = 0; i < agenda_data.nelem(); i++) {
413 const AgRecord& agr = agenda_data[i];
414 const ArrayOfIndex& ago = agr.Out();
415 const ArrayOfIndex& agi = agr.In();
416 ostringstream ain_push_os, ain_pop_os;
417 ostringstream aout_push_os, aout_pop_os;
418
419 auto wsv_ptr = global_data::WsvMap.find(agr.Name());
420 ARTS_USER_ERROR_IF(wsv_ptr == global_data::WsvMap.end(), "The agenda ", agr.Name(), " fails")
421 bool is_agenda_array = wsv_data[wsv_ptr->second].Group() == get_wsv_group_id("ArrayOfAgenda");
422 write_agenda_wrapper_header(ofs, agr, is_agenda_array);
423
424 ofs << "\n";
425 ofs << "{\n";
426
427 if (ago.nelem() || agi.nelem()) {
428 if (is_agenda_array) {
429 ofs << " if (agenda_array_index < 0 || agenda_array_index >= input_agenda_array.nelem())\n"
430 << " {\n"
431 << " std::ostringstream os;\n"
432 << " os << \"Agenda index \" << agenda_array_index\n"
433 << " << \" out of bounds. 0 <= index < \" << input_agenda_array.nelem();\n"
434 << " throw std::runtime_error(os.str());\n"
435 << " }\n\n"
436 << " const Agenda& input_agenda = input_agenda_array[agenda_array_index];\n\n";
437 }
438 ofs << " using global_data::AgendaMap;\n"
439 << " using global_data::agenda_data;\n"
440 << "\n"
441 << " if (!input_agenda.checked())\n"
442 << " throw std::runtime_error(\"" << agr.Name()
443 << " is uninitialized. Use *AgendaSet* to add methods to it.\\n"
444 << "Agenda variables defined in the controlfile cannot be executed.\\nThe agenda must "
445 << "be copied to a workspace variable for execution.\");\n"
446 << "\n"
447 << " const AgRecord& agr =\n"
448 << " agenda_data[AgendaMap.find (input_agenda.name ())->second];\n"
449 << "\n";
450 }
451 if (ago.nelem()) {
452 for (Index j = 0; j < ago.nelem(); j++) {
453 // Mark agenda output-only variables as uninitialized
454 auto it = agi.begin();
455 while (it != agi.end() && *it != ago[j]) it++;
456 if (it == agi.end()) {
457 aout_push_os << " auto borrowed_out_"<<j<<"{ws.borrow_uninitialized (aout[" << j << "], "
458 << wsv_data[ago[j]].Name() << ")};\n";
459 } else {
460 aout_push_os << " auto borrowed_out_"<<j<<"{ws.borrow (aout[" << j << "], "
461 << wsv_data[ago[j]].Name() << ")};\n";
462 }
463 }
464 }
465 if (agi.nelem()) {
466 for (Index j = 0; j < agi.nelem(); j++) {
467 // Ignore Input parameters that are also output
468 auto it = ago.begin();
469 while (it != ago.end() && *it != agi[j]) it++;
470 if (it == ago.end()) {
471 ain_push_os << " auto borrowed_in_"<<j<<"{ws.borrow (ain[" << j << "], "
472 << wsv_data[agi[j]].Name() << ")};\n";
473 }
474 }
475 }
476
477 if (aout_push_os.str().length()) {
478 ofs << " const ArrayOfIndex& aout = agr.Out();\n";
479 ofs << aout_push_os.str() << "\n";
480 }
481 if (ain_push_os.str().length()) {
482 ofs << " const ArrayOfIndex& ain = agr.In();\n";
483 ofs << ain_push_os.str() << "\n";
484 }
485
486 ofs << " bool agenda_failed;\n";
487 ofs << " String agenda_error_msg;\n";
488 ofs << " auto_md_agenda_execute_helper(agenda_failed, agenda_error_msg, ws, input_agenda);\n\n";
489
490 if (aout_pop_os.str().length()) {
491 ofs << aout_pop_os.str() << "\n";
492 }
493 if (ain_pop_os.str().length()) {
494 ofs << ain_pop_os.str() << "\n";
495 }
496
497 ofs << " if (agenda_failed) throw runtime_error (agenda_error_msg);\n";
498 ofs << "}\n\n";
499 }
500
501 // Create implementation of the GroupCreate WSMs
502 //
503 for (auto&& it : wsv_groups) {
504 if (it == "Any") continue;
505 ofs << "/* Workspace method: Doxygen documentation will be auto-generated */\n"
506 << "void " << it << "Create(";
507
508 if (it == "Agenda") ofs << "Workspace& ws, ";
509
510 ofs << it << "& var, const Verbosity&)\n"
511 << "{ ";
512
513 // Treat atomic types separately.
514 // For objects the default constructor is used.
515 if (it == "Index")
516 ofs << "var = 0;";
517 else if (it == "Numeric")
518 ofs << "var = 0.;";
519 else {
520 ofs << "var = " << it << '(';
521 if (it == "Agenda") ofs << "ws";
522 ofs << ");";
523 }
524
525 ofs << " }\n\n";
526
527 if (it not_eq "Agenda" and it not_eq "ArrayOfAgenda") {
528 ofs << "/* Workspace method: Doxygen documentation will be auto-generated */\n"
529 << "void " << it << "Set(" << it << "& out, const " << it
530 << "& value, const Verbosity&) { out = value; }\n\n";
531 }
532 }
533 } catch (const std::runtime_error& x) {
534 cout << "Something went wrong. Message text:\n";
535 cout << x.what() << '\n';
536 return 1;
537 }
538
539 return 0;
540}
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
Lookup information for one agenda.
const ArrayOfIndex & Out() const
const ArrayOfIndex & In() const
const String & Name() const
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
bool PassWsvNames() const
Definition methods.h:90
bool AgendaMethod() const
Definition methods.h:86
bool Supergeneric() const
Definition methods.h:87
bool SetMethod() const
Definition methods.h:85
const ArrayOfIndex & Out() const
Definition methods.h:71
const ArrayOfIndex & GInType() const
Definition methods.h:78
Index nelem() const
Definition mystring.h:172
Helper macros for debugging.
#define ARTS_ASSERT(condition,...)
Definition debug.h:86
#define ARTS_USER_ERROR_IF(condition,...)
Definition debug.h:137
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 align(ofstream &ofs, bool &is_first_parameter, const String &indent)
int main()
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.
my_basic_string< char > String
The String type for ARTS.
Definition mystring.h:199
const ArrayOfGroupRecord wsv_groups
The names associated with Wsv groups as Strings.
Definition global_data.h:74
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.