ARTS 2.5.9 (git: 825fa5f2)
species_tags.cc
Go to the documentation of this file.
1#include "species_tags.h"
2
3#include <cfloat>
4#include <iterator>
5#include <string_view>
6
7#include "debug.h"
8#include "partfun.h"
9
10namespace Species {
11
12Numeric Tag::Q(Numeric T) const {
13 return PartitionFunctions::Q(T, Isotopologue());
14}
15
16Numeric Tag::dQdT(Numeric T) const {
17 return PartitionFunctions::dQdT(T, Isotopologue());
18}
19
20Tag::Tag(String def) : type(TagType::Plain) {
21 // Save input string for error messages:
22 String def_original = def;
23
24 // Name of species and isotopologue (aux variables):
25 String name, isoname;
26 // Aux index:
27 Index n;
28
29 // We cannot set a default value for the isotopologue, because the
30 // default should be `ALL' and the value for `ALL' depends on the
31 // species.
32
33 // Extract the species name:
34 n = def.find('-'); // find the '-'
35 if (n != def.npos) {
36 name = def.substr(0, n); // Extract before '-'
37 def.erase(0, n + 1); // Remove from def
38 } else {
39 // n==def.npos means that def does not contain a '-'. In that
40 // case we assume that it contains just a species name and
41 // nothing else
42 name = def;
43 def = "";
44 }
45
46 // Remove whitespace
47 name.trim();
48
49 // Obtain species index from species name.
50 // (This will also remove possible whitespace.)
51 const Species spec = fromShortName(name);
53 "Bad species name: ",
54 name,
55 " extracted from: ",
56 def_original)
57
58 // Check if species name contains the special tag for
59 // Faraday Rotation
60 if (spec == Species::free_electrons) {
61 constexpr Index ind =
62 find_species_index(IsotopeRecord(Species::free_electrons));
63 spec_ind = ind;
64 type = TagType::FreeElectrons;
65 return;
66 }
67
68 // Check if species name contains the special tag for
69 // Particles
70 if (spec == Species::particles) {
71 constexpr Index ind = find_species_index(IsotopeRecord(Species::particles));
72 spec_ind = ind;
73 type = TagType::Particles;
74 return;
75 }
76
77 // Set "all" species per default by leaving the joker in
78 spec_ind = find_species_index(IsotopeRecord(spec));
80 spec_ind < 0, "Bad species extracted: ", spec, " from ", def_original)
81 if (0 == def.nelem()) {
82 return;
83 }
84
85 // Extract the isotopologue name/Zeeman flag:
86 n = def.find('-'); // find the '-'
87 if (n != def.npos) {
88 isoname = def.substr(0, n); // Extract before '-'
89 def.erase(0, n + 1); // Remove from def
90
91 if ("Z" == isoname) {
92 type = TagType::Zeeman;
93 // Zeeman flag was present, now extract the isotopologue name:
94 n = def.find('-'); // find the '-'
95 if (n != def.npos) {
96 isoname = def.substr(0, n); // Extract before '-'
97 def.erase(0, n + 1); // Remove from def
98 } else {
99 // n==def.npos means that def does not contain a '-'. In that
100 // case we assume that it contains just the isotopologue name and
101 // nothing else.
102 isoname = def;
103 def = "";
104 }
105 }
106
107 if ("XFIT" == isoname) {
108 type = TagType::XsecFit;
109 // Hitran Xsec flag was present, now extract the isotopologue name:
110 n = def.find('-'); // find the '-'
111 if (n != def.npos) {
112 isoname = def.substr(0, n); // Extract before '-'
113 def.erase(0, n + 1); // Remove from def
114 } else {
115 // n==def.npos means that def does not contain a '-'. In that
116 // case we assume that it contains just the isotopologue name and
117 // nothing else.
118 isoname = def;
119 def = "";
120 }
121 }
122 } else {
123 // n==def.npos means that def does not contain a '-'. In that
124 // case we assume that it contains just the isotopologue name or
125 // Zeeman flag and nothing else.
126 isoname = def;
127 def = "";
128 if ("Z" == isoname) {
129 type = TagType::Zeeman;
130 // This means that there is nothing else to parse. Apparently
131 // the user wants all isotopologues and no frequency limits.
132 return;
133 }
134 if ("XFIT" == isoname) {
135 type = TagType::XsecFit;
136 // This means that there is nothing else to parse. Apparently
137 // the user wants all isotopologues and no frequency limits.
138 return;
139 }
140 }
141
142 if (Joker == isoname) {
143 // The user wants all isotopologues. This already set
144 } else if ("CIA" == isoname) // Check for "cia":
145 {
146 // The user wants this to use the CIA catalog:
147 type = TagType::Cia;
148
149 // We have to read in the second species, and the dataset index
150 n = def.find('-'); // find the '-'
151
153 n == def.npos,
154 "Invalid species tag ",
155 def_original,
156 ".\n"
157 "I am missing a minus sign (and a dataset index after that.)")
158
159 String otherspec = def.substr(0, n); // Extract before '-'
160 def.erase(0, n + 1); // Remove from def
161
162 cia_2nd_species = fromShortName(otherspec);
163 ARTS_USER_ERROR_IF(not good_enum(cia_2nd_species),
164 "Bad species name: ",
165 otherspec,
166 " extracted from: ",
167 def_original)
168
169 // Convert remaining def to dataset index.
170
171 // Check that everything remaining is just numbers.
172 for (Index i = 0; i < def.nelem(); ++i)
173 ARTS_USER_ERROR_IF(!isdigit(def[i]),
174 "Invalid species tag ",
175 def_original,
176 ".\n"
177 "The tag should end with a dataset index")
178
179 // Do the conversion from string to index:
180 std::istringstream is(def);
181 is >> cia_dataset_index;
182
183 def = "";
184 } else {
185 spec_ind = find_species_index(IsotopeRecord(spec, isoname));
186
187 // Check if we found a matching isotopologue:
188 ARTS_USER_ERROR_IF(spec_ind < 0,
189 "Isotopologue ",
190 isoname,
191 " is not a valid isotopologue or "
192 "absorption model for species ",
193 name,
194 ".\n"
195 "Valid options are:\n",
197
198 // Check if the found isotopologue represents a predefined model
199 // (continuum or full absorption model) and set the type accordingly:
200 if (is_predefined_model(Isotopologue()))
201 type = TagType::Predefined;
202 }
203
204 if (0 == def.nelem()) {
205 // This means that there is nothing else to parse. Apparently
206 // the user wants no frequency limits. Frequency defaults are
207 // already set, so we can return directly.
208
209 return;
210 }
211
212 ARTS_USER_ERROR_IF(def[0] != Joker[0] && !isdigit(def[0]),
213 "Expected frequency limits, but got \"",
214 def,
215 "\"")
216
217 // Look for the two frequency limits:
218
219 // Extract first frequency
220 n = def.find('-'); // find the '-'
221 if (n != def.npos) {
222 // Frequency as a String:
223 String fname;
224 fname = def.substr(0, n); // Extract before '-'
225 def.erase(0, n + 1); // Remove from def
226
227 // Check for joker:
228 if (Joker == fname) {
229 // The default for lower_freq is already -1, meaning `ALL'.
230 // So there is nothing to do here.
231 } else {
232 ARTS_USER_ERROR_IF(!isdigit(fname[0]),
233 "Expected frequency limit, but got \"",
234 fname,
235 "\"")
236 // Convert to Numeric:
237 char* endptr;
238 lower_freq = strtod(fname.c_str(), &endptr);
239 ARTS_USER_ERROR_IF(endptr != fname.c_str() + fname.nelem(),
240 "Error parsing frequency limit \"",
241 fname,
242 "\"")
243 }
244 } else {
245 // n==def.npos means that def does not contain a '-'. In this
246 // case that is not allowed!
248 "You must either specify both frequency limits\n"
249 "(at least with jokers), or none.");
250 }
251
252 // Now there should only be the upper frequency left in def.
253 // Check for joker:
254 if (Joker== def) {
255 // The default for upper_freq is already -1, meaning `ALL'.
256 // So there is nothing to do here.
257 } else {
259 !isdigit(def[0]), "Expected frequency limit, but got \"", def, "\"")
260 // Convert to Numeric:
261 char* endptr;
262 upper_freq = strtod(def.c_str(), &endptr);
263 ARTS_USER_ERROR_IF(endptr != def.c_str() + def.nelem(),
264 "Error parsing frequency limit \"",
265 def,
266 "\"")
267 }
268}
269
271
283String Tag::Name() const {
284 std::ostringstream os;
285
286 // First the species name:
287 os << toShortName(Isotopologue().spec) << "-";
288
289 // Is this a CIA tag?
290 if (type == TagType::Cia) {
291 os << "CIA-" << toShortName(cia_2nd_species) << "-" << cia_dataset_index;
292
293 } else if (type == TagType::FreeElectrons || type == TagType::Particles) {
294 os << toShortName(Isotopologue().spec);
295 }
296 // Hitran Xsec flag.
297 else if (type == TagType::XsecFit) {
298 os << "XFIT";
299 } else {
300 // Zeeman flag.
301 if (type == TagType::Zeeman) os << "Z-";
302
303 // Now the isotopologue. Can be a single isotopologue or ALL.
304 os << Isotopologue().isotname << '-';
305
306 // Now the frequency limits, if there are any. For this we first
307 // need to determine the floating point precision.
308
309 // Determine the precision, depending on whether Numeric is double
310 // or float:
311 int precision;
312#ifdef USE_FLOAT
313 precision = FLT_DIG;
314#else
315#ifdef USE_DOUBLE
316 precision = DBL_DIG;
317#else
318#error Numeric must be double or float
319#endif
320#endif
321
322 if (0 > lower_freq) {
323 // lower_freq < 0 means no lower limit.
324 os << Joker << '-';
325 } else {
326 os << std::setprecision(precision);
327 os << lower_freq << "-";
328 }
329
330 if (0 > upper_freq) {
331 // upper_freq < 0 means no upper limit.
332 os << Joker;
333 } else {
334 os << std::setprecision(precision);
335 os << upper_freq;
336 }
337 }
338 return os.str();
339}
340} // namespace Species
341
343 // There can be a comma separated list of tag definitions, so we
344 // need to break the String apart at the commas.
345 ArrayOfString tag_def;
346
347 bool go_on = true;
348
349 while (go_on) {
350 // Index n = find_first( these_names, ',' );
351 Index n = these_names.find(',');
352 if (n == these_names.npos) // Value npos indicates not found.
353 {
354 // There are no more commas.
355 // cout << "these_names: (" << these_names << ")\n";
356 tag_def.push_back(these_names);
357 go_on = false;
358 } else {
359 tag_def.push_back(these_names.substr(0, n));
360 these_names.erase(0, n + 1);
361 }
362 }
363 // tag_def now holds the different tag Strings for this group.
364
365 // Set size to zero, in case the method has been called before.
366 resize(0);
367
368 for (Index s = 0; s < tag_def.nelem(); ++s) {
369 Species::Tag this_tag(tag_def[s]);
370
371 // Safety checks:
372 if (s > 0) {
373 // Tags inside a group must belong to the same species.
375 front().Isotopologue().spec != this_tag.Isotopologue().spec,
376 "Tags in a tag group must belong to the same species.");
377
378 // Zeeman tags and plain line by line tags must not be mixed. (Because
379 // there can be only one line list per tag group.)
380 ARTS_USER_ERROR_IF(((front().type == Species::TagType::Zeeman) &&
381 (this_tag.type == Species::TagType::Plain)) ||
382 ((front().type == Species::TagType::Plain) &&
383 (this_tag.type == Species::TagType::Zeeman)),
384 "Zeeman tags and plain line-by-line tags must "
385 "not be mixed in the same tag group.");
386 }
387
388 push_back(this_tag);
389 }
390}
391
393 Species::Species spec,
394 Index i) noexcept {
395 const Index n = specs.nelem();
396 for (; i < n; i++)
397 if (specs[i].Species() == spec) return i;
398 return -1;
399}
400
402 Species::Species spec) noexcept {
403 return find_next_species(specs, spec, 0);
404}
405
406std::pair<Index, Index> find_first_species_tag(
407 const ArrayOfArrayOfSpeciesTag& specs, const SpeciesTag& tag) noexcept {
408 for (Index i = 0; i < specs.nelem(); i++) {
409 if (auto ptr = std::find(specs[i].cbegin(), specs[i].cend(), tag);
410 ptr not_eq specs[i].cend())
411 return {i, std::distance(specs[i].cbegin(), ptr)};
412 }
413 return {-1, -1};
414}
415
416std::pair<Index, Index> find_first_isotologue(
417 const ArrayOfArrayOfSpeciesTag& specs,
418 const SpeciesIsotopeRecord& isot) noexcept {
419 for (Index i = 0; i < specs.nelem(); i++) {
420 if (auto ptr =
421 std::find_if(specs[i].cbegin(),
422 specs[i].cend(),
423 [&](auto& tag) { return tag.Isotopologue() == isot; });
424 ptr not_eq specs[i].cend())
425 return {i, std::distance(specs[i].cbegin(), ptr)};
426 }
427 return {-1, -1};
428}
429
431 Index num_free_electrons = 0;
432 for (Index i = 0; i < abs_species.nelem(); ++i) {
433 bool has_free_electrons = false;
434 bool has_particles = false;
435 bool has_hitran_xsec = false;
436 for (Index s = 0; s < abs_species[i].nelem(); ++s) {
437 if (abs_species[i][s].Type() == Species::TagType::FreeElectrons) {
438 num_free_electrons++;
439 has_free_electrons = true;
440 }
441
442 if (abs_species[i][s].Type() == Species::TagType::Particles) {
443 has_particles = true;
444 }
445
446 if (abs_species[i][s].Type() == Species::TagType::XsecFit) {
447 has_hitran_xsec = true;
448 }
449 }
450
451 ARTS_USER_ERROR_IF(abs_species[i].nelem() > 1 && has_free_electrons,
452 "'free_electrons' must not be combined "
453 "with other tags in the same group.");
454 ARTS_USER_ERROR_IF(num_free_electrons > 1,
455 "'free_electrons' must not be defined "
456 "more than once.");
457
458 ARTS_USER_ERROR_IF(abs_species[i].nelem() > 1 && has_particles,
459 "'particles' must not be combined "
460 "with other tags in the same group.");
461
462 ARTS_USER_ERROR_IF(abs_species[i].nelem() > 1 && has_hitran_xsec,
463 "'hitran_xsec' must not be combined "
464 "with other tags in the same group.");
465 }
466}
467
468String ArrayOfSpeciesTag::Name() const {
469 String out = "";
470 bool first = true;
471 for (auto& x : *this) {
472 if (not first) out += ", ";
473 out += x.Name();
474 first = false;
475 }
476 return out;
477}
478
479std::set<Species::Species> lbl_species(
480 const ArrayOfArrayOfSpeciesTag& abs_species) noexcept {
481 std::set<Species::Species> unique_species;
482 for (auto& specs : abs_species) {
483 if (specs.RequireLines()) unique_species.insert(specs.front().Spec());
484 }
485 return unique_species;
486}
487
489 const Vector& rtp_vmr,
490 const Species spec) ARTS_NOEXCEPT {
491 ARTS_ASSERT(abs_species.nelem() == rtp_vmr.nelem())
492
493 auto pos =
494 std::find_if(abs_species.begin(),
495 abs_species.end(),
496 [spec](const ArrayOfSpeciesTag& tag_group) {
497 return tag_group.nelem() and tag_group.Species() == spec;
498 });
499 return pos == abs_species.end()
500 ? 0
501 : rtp_vmr[std::distance(abs_species.begin(), pos)];
502}
503
505 for (auto& species_list : abs_species) {
506 for (auto& tag : species_list) {
507 switch (tag.type) {
508 case Species::TagType::Plain:
509 Plain = true;
510 break;
511 case Species::TagType::Zeeman:
512 Zeeman = true;
513 break;
514 case Species::TagType::Predefined:
515 Predefined = true;
516 break;
517 case Species::TagType::Cia:
518 Cia = true;
519 break;
520 case Species::TagType::FreeElectrons:
521 FreeElectrons = true;
522 break;
523 case Species::TagType::Particles:
524 Particles = true;
525 break;
526 case Species::TagType::XsecFit:
527 XsecFit = true;
528 break;
529 case Species::TagType::NoLines:
530 NoLines = true;
531 break;
532 case Species::TagType::FINAL: { /* leave last */
533 }
534 }
535 }
536 }
537}
538
539std::ostream& operator<<(std::ostream& os, SpeciesTagTypeStatus val) {
540 Species::TagType x{Species::TagType::FINAL};
541 switch (x) {
542 case Species::TagType::FINAL:
543 os << "Species tag types:\n";
544 [[fallthrough]];
545 case Species::TagType::Plain:
546 os << " Plain: " << val.Plain << '\n';
547 [[fallthrough]];
548 case Species::TagType::Zeeman:
549 os << " Zeeman: " << val.Zeeman << '\n';
550 [[fallthrough]];
551 case Species::TagType::Predefined:
552 os << " Predefined: " << val.Predefined << '\n';
553 [[fallthrough]];
554 case Species::TagType::Cia:
555 os << " Cia: " << val.Cia << '\n';
556 [[fallthrough]];
557 case Species::TagType::FreeElectrons:
558 os << " FreeElectrons: " << val.FreeElectrons << '\n';
559 [[fallthrough]];
560 case Species::TagType::Particles:
561 os << " Particles: " << val.Particles << '\n';
562 [[fallthrough]];
563 case Species::TagType::XsecFit:
564 os << " XsecFit: " << val.XsecFit << '\n';
565 [[fallthrough]];
566 case Species::TagType::NoLines:
567 os << " NoLines: " << val.NoLines;
568 }
569 return os;
570}
ArrayOfSpeciesTag() noexcept
Definition: species_tags.h:104
Index nelem() const ARTS_NOEXCEPT
Definition: array.h:92
The Joker class.
Definition: matpackI.h:126
The Vector class.
Definition: matpackI.h:910
Index nelem() const
Definition: mystring.h:189
void trim()
Trim leading and trailing whitespace.
Definition: mystring.h:169
static const Index npos
Define npos:
Definition: mystring.h:209
Helper macros for debugging.
#define ARTS_NOEXCEPT
Definition: debug.h:79
#define ARTS_ASSERT(condition,...)
Definition: debug.h:82
#define ARTS_USER_ERROR(...)
Definition: debug.h:150
#define ARTS_USER_ERROR_IF(condition,...)
Definition: debug.h:134
constexpr bool good_enum(EnumType x) noexcept
Checks if the enum number is good.
Definition: enums.h:21
#define precision
Definition: logic.cc:46
void Error(const String &msg, const Verbosity &verbosity)
WORKSPACE METHOD: Error.
Definition: m_general.cc:295
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
Numeric dQdT(Numeric T, const Species::IsotopeRecord &ir)
Definition: partfun.cc:18
Numeric Q(Numeric T, const Species::IsotopeRecord &ir)
Definition: partfun.cc:14
String isotopologues_names(Species spec)
constexpr bool is_predefined_model(const IsotopeRecord &ir) noexcept
Numeric first_vmr(const ArrayOfArrayOfSpeciesTag &abs_species, const Vector &rtp_vmr, const Species spec) ARTS_NOEXCEPT
constexpr Index find_species_index(const Species spec, const std::string_view isot) noexcept
Implements Zeeman modeling.
Definition: zeemandata.cc:333
constexpr int isdigit(int ch) noexcept
Definition: nonstd.h:24
Index find_first_species(const ArrayOfArrayOfSpeciesTag &specs, Species::Species spec) noexcept
Index find_next_species(const ArrayOfArrayOfSpeciesTag &specs, Species::Species spec, Index i) noexcept
std::pair< Index, Index > find_first_isotologue(const ArrayOfArrayOfSpeciesTag &specs, const SpeciesIsotopeRecord &isot) noexcept
std::set< Species::Species > lbl_species(const ArrayOfArrayOfSpeciesTag &abs_species) noexcept
void check_abs_species(const ArrayOfArrayOfSpeciesTag &abs_species)
std::pair< Index, Index > find_first_species_tag(const ArrayOfArrayOfSpeciesTag &specs, const SpeciesTag &tag) noexcept
std::ostream & operator<<(std::ostream &os, SpeciesTagTypeStatus val)
Species::Tag SpeciesTag
Definition: species_tags.h:100
Struct to test of an ArrayOfArrayOfSpeciesTag contains a tagtype.
Definition: species_tags.h:172
SpeciesTagTypeStatus(const ArrayOfArrayOfSpeciesTag &abs_species)
Struct containing all information needed about one isotope.
Definition: isotopologues.h:16
#define a