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