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