ARTS 2.5.0 (git: 9ee3ac6c)
species_tags.cc
Go to the documentation of this file.
1#include <cfloat>
2
3#include "species_tags.h"
4
5namespace Species {
6Tag::Tag(String def) : spec_ind(-1), lower_freq(-1), upper_freq(-1), type(TagType::Plain), cia_2nd_species(Species::FINAL), cia_dataset_index(-1) {
7 // Save input string for error messages:
8 String def_original = def;
9
10 // Name of species and isotopologue (aux variables):
11 String name, isoname;
12 // Aux index:
13 Index n;
14
15 // We cannot set a default value for the isotopologue, because the
16 // default should be `ALL' and the value for `ALL' depends on the
17 // species.
18
19 // Extract the species name:
20 n = def.find('-'); // find the '-'
21 if (n != def.npos) {
22 name = def.substr(0, n); // Extract before '-'
23 def.erase(0, n + 1); // Remove from def
24 } else {
25 // n==def.npos means that def does not contain a '-'. In that
26 // case we assume that it contains just a species name and
27 // nothing else
28 name = def;
29 def = "";
30 }
31
32 // Remove whitespace
33 name.trim();
34
35 // Obtain species index from species name.
36 // (This will also remove possible whitespace.)
37 const Species spec = fromShortName(name);
38 ARTS_USER_ERROR_IF (not good_enum(spec), "Bad species name: ", name, " extracted from: ", def_original)
39
40 // Check if species name contains the special tag for
41 // Faraday Rotation
42 if (spec == Species::free_electrons) {
43 constexpr Index ind = find_species_index(IsotopeRecord(Species::free_electrons));
44 spec_ind = ind;
45 type = TagType::FreeElectrons;
46 return;
47 }
48
49 // Check if species name contains the special tag for
50 // Particles
51 if (spec == Species::particles) {
52 constexpr Index ind = find_species_index(IsotopeRecord(Species::particles));
53 spec_ind = ind;
54 type = TagType::Particles;
55 return;
56 }
57
58 // Set "all" species per default by leaving the joker in
59 spec_ind = find_species_index(IsotopeRecord(spec));
60 ARTS_USER_ERROR_IF(spec_ind < 0, "Bad species extracted: ", spec, " from ", def_original)
61 if (0 == def.nelem()) {
62 return;
63 }
64
65 // Extract the isotopologue name/Zeeman flag:
66 n = def.find('-'); // find the '-'
67 if (n != def.npos) {
68 isoname = def.substr(0, n); // Extract before '-'
69 def.erase(0, n + 1); // Remove from def
70
71 if ("Z" == isoname) {
72 type = TagType::Zeeman;
73 // Zeeman flag was present, now extract the isotopologue name:
74 n = def.find('-'); // find the '-'
75 if (n != def.npos) {
76 isoname = def.substr(0, n); // Extract before '-'
77 def.erase(0, n + 1); // Remove from def
78 } else {
79 // n==def.npos means that def does not contain a '-'. In that
80 // case we assume that it contains just the isotopologue name and
81 // nothing else.
82 isoname = def;
83 def = "";
84 }
85 }
86
87 if ("HXSEC" == isoname) {
88 type = TagType::HitranXsec;
89 // Hitran Xsec flag was present, now extract the isotopologue name:
90 n = def.find('-'); // find the '-'
91 if (n != def.npos) {
92 isoname = def.substr(0, n); // Extract before '-'
93 def.erase(0, n + 1); // Remove from def
94 } else {
95 // n==def.npos means that def does not contain a '-'. In that
96 // case we assume that it contains just the isotopologue name and
97 // nothing else.
98 isoname = def;
99 def = "";
100 }
101 }
102 } else {
103 // n==def.npos means that def does not contain a '-'. In that
104 // case we assume that it contains just the isotopologue name or
105 // Zeeman flag and nothing else.
106 isoname = def;
107 def = "";
108 if ("Z" == isoname) {
109 type = TagType::Zeeman;
110 // This means that there is nothing else to parse. Apparently
111 // the user wants all isotopologues and no frequency limits.
112 return;
113 }
114 if ("HXSEC" == isoname) {
115 type = TagType::HitranXsec;
116 // This means that there is nothing else to parse. Apparently
117 // the user wants all isotopologues and no frequency limits.
118 return;
119 }
120 }
121
122 if ("*" == isoname) {
123 // The user wants all isotopologues. This already set
124 }
125 else if ("CIA" == isoname) // Check for "cia":
126 {
127 // The user wants this to use the CIA catalog:
128 type = TagType::Cia;
129
130 // We have to read in the second species, and the dataset index
131 n = def.find('-'); // find the '-'
132
133 ARTS_USER_ERROR_IF (n == def.npos,
134 "Invalid species tag ", def_original, ".\n"
135 "I am missing a minus sign (and a dataset index after that.)")
136
137 String otherspec = def.substr(0, n); // Extract before '-'
138 def.erase(0, n + 1); // Remove from def
139
140 cia_2nd_species = fromShortName(otherspec);
141 ARTS_USER_ERROR_IF (not good_enum(cia_2nd_species), "Bad species name: ", otherspec, " extracted from: ", def_original)
142
143 // Convert remaining def to dataset index.
144
145 // Check that everything remaining is just numbers.
146 for (Index i = 0; i < def.nelem(); ++i)
147 ARTS_USER_ERROR_IF (!isdigit(def[i]),
148 "Invalid species tag ", def_original, ".\n"
149 "The tag should end with a dataset index")
150
151 // Do the conversion from string to index:
152 std::istringstream is(def);
153 is >> cia_dataset_index;
154
155 def = "";
156 } else {
157 spec_ind = find_species_index(IsotopeRecord(spec, isoname));
158
159 // Check if we found a matching isotopologue:
160 ARTS_USER_ERROR_IF (spec_ind < 0,
161 "Isotopologue ", isoname, " is not a valid isotopologue or "
162 "absorption model for species ", name, ".\n"
163 "Valid options are:\n", isotopologues_names(spec))
164
165 // Check if the found isotopologue represents a predefined model
166 // (continuum or full absorption model) and set the type accordingly:
167 if (is_predefined_model(Isotopologue())) type = TagType::Predefined;
168 }
169
170 if (0 == def.nelem()) {
171 // This means that there is nothing else to parse. Apparently
172 // the user wants no frequency limits. Frequency defaults are
173 // already set, so we can return directly.
174
175 return;
176 }
177
178 ARTS_USER_ERROR_IF (def[0] != '*' && !isdigit(def[0]),
179 "Expected frequency limits, but got \"", def, "\"")
180
181 // Look for the two frequency limits:
182
183 // Extract first frequency
184 n = def.find('-'); // find the '-'
185 if (n != def.npos) {
186 // Frequency as a String:
187 String fname;
188 fname = def.substr(0, n); // Extract before '-'
189 def.erase(0, n + 1); // Remove from def
190
191 // Check for joker:
192 if ("*" == fname) {
193 // The default for lower_freq is already -1, meaning `ALL'.
194 // So there is nothing to do here.
195 } else {
196 ARTS_USER_ERROR_IF (!isdigit(fname[0]),
197 "Expected frequency limit, but got \"", fname, "\"")
198 // Convert to Numeric:
199 char* endptr;
200 lower_freq = strtod(fname.c_str(), &endptr);
201 ARTS_USER_ERROR_IF (endptr != fname.c_str() + fname.nelem(),
202 "Error parsing frequency limit \"", fname, "\"")
203 }
204 } else {
205 // n==def.npos means that def does not contain a '-'. In this
206 // case that is not allowed!
208 "You must either specify both frequency limits\n"
209 "(at least with jokers), or none.");
210 }
211
212 // Now there should only be the upper frequency left in def.
213 // Check for joker:
214 if ("*" == def) {
215 // The default for upper_freq is already -1, meaning `ALL'.
216 // So there is nothing to do here.
217 } else {
218 ARTS_USER_ERROR_IF (!isdigit(def[0]),
219 "Expected frequency limit, but got \"", def, "\"")
220 // Convert to Numeric:
221 char* endptr;
222 upper_freq = strtod(def.c_str(), &endptr);
223 ARTS_USER_ERROR_IF (endptr != def.c_str() + def.nelem(),
224 "Error parsing frequency limit \"", def, "\"")
225 }
226}
227
229
241String Tag::Name() const {
242 std::ostringstream os;
243
244 // First the species name:
245 os << toShortName(Isotopologues[spec_ind].spec) << "-";
246
247 // Is this a CIA tag?
248 if (type == TagType::Cia) {
249 os << "CIA-" << toShortName(cia_2nd_species) << "-" << cia_dataset_index;
250
251 } else if (type == TagType::FreeElectrons || type == TagType::Particles) {
252 os << toShortName(Isotopologues[spec_ind].spec);
253 }
254 // Hitran Xsec flag.
255 else if (type == TagType::HitranXsec) {
256 os << "HXSEC";
257 } else {
258 // Zeeman flag.
259 if (type == TagType::Zeeman) os << "Z-";
260
261 // Now the isotopologue. Can be a single isotopologue or ALL.
262 os << Isotopologues[spec_ind].isotname << '-';
263
264 // Now the frequency limits, if there are any. For this we first
265 // need to determine the floating point precision.
266
267 // Determine the precision, depending on whether Numeric is double
268 // or float:
269 int precision;
270 #ifdef USE_FLOAT
271 precision = FLT_DIG;
272 #else
273 #ifdef USE_DOUBLE
274 precision = DBL_DIG;
275 #else
276 #error Numeric must be double or float
277 #endif
278 #endif
279
280 if (0 > lower_freq) {
281 // lower_freq < 0 means no lower limit.
282 os << "*-";
283 } else {
284 os << std::setprecision(precision);
285 os << lower_freq << "-";
286 }
287
288 if (0 > upper_freq) {
289 // upper_freq < 0 means no upper limit.
290 os << "*";
291 } else {
292 os << std::setprecision(precision);
293 os << upper_freq;
294 }
295 }
296 return os.str();
297}
298} // namespace Species
299
301 // There can be a comma separated list of tag definitions, so we
302 // need to break the String apart at the commas.
303 ArrayOfString tag_def;
304
305 bool go_on = true;
306
307 while (go_on) {
308 // Index n = find_first( these_names, ',' );
309 Index n = these_names.find(',');
310 if (n == these_names.npos) // Value npos indicates not found.
311 {
312 // There are no more commas.
313 // cout << "these_names: (" << these_names << ")\n";
314 tag_def.push_back(these_names);
315 go_on = false;
316 } else {
317 tag_def.push_back(these_names.substr(0, n));
318 these_names.erase(0, n + 1);
319 }
320 }
321 // tag_def now holds the different tag Strings for this group.
322
323 // Set size to zero, in case the method has been called before.
324 resize(0);
325
326 for (Index s = 0; s < tag_def.nelem(); ++s) {
327 Species::Tag this_tag(tag_def[s]);
328
329 // Safety checks:
330 if (s > 0) {
331 // Tags inside a group must belong to the same species.
332 ARTS_USER_ERROR_IF (front().Isotopologue().spec != this_tag.Isotopologue().spec,
333 "Tags in a tag group must belong to the same species.");
334
335 // Zeeman tags and plain line by line tags must not be mixed. (Because
336 // there can be only one line list per tag group.)
337 ARTS_USER_ERROR_IF (((front().type == Species::TagType::Zeeman) &&
338 (this_tag.type == Species::TagType::Plain)) ||
339 ((front().type == Species::TagType::Plain) &&
340 (this_tag.type == Species::TagType::Zeeman)),
341 "Zeeman tags and plain line-by-line tags must "
342 "not be mixed in the same tag group.");
343 }
344
345 push_back(this_tag);
346 }
347}
348
349Index find_next_species(const ArrayOfArrayOfSpeciesTag& specs, Species::Species spec, Index i) noexcept {
350 const Index n=specs.nelem();
351 for (; i<n; i++) if(specs[i].Species() == spec) return i;
352 return -1;
353}
354
355Index find_first_species(const ArrayOfArrayOfSpeciesTag& specs, Species::Species spec) noexcept {
356 return find_next_species(specs, spec, 0);
357}
358
359std::pair<Index, Index> find_first_species_tag(const ArrayOfArrayOfSpeciesTag& specs, const SpeciesTag& tag) noexcept {
360 for (Index i=0; i<specs.nelem(); i++) {
361 if (auto ptr = std::find(specs[i].cbegin(), specs[i].cend(), tag); ptr not_eq specs[i].cend())
362 return {i, std::distance(specs[i].cbegin(), ptr)};
363 }
364 return {-1, -1};
365}
366
367std::pair<Index, Index> find_first_isotologue(const ArrayOfArrayOfSpeciesTag& specs, const SpeciesIsotopeRecord& isot) noexcept {
368 for (Index i=0; i<specs.nelem(); i++) {
369 if (auto ptr = std::find_if(specs[i].cbegin(), specs[i].cend(), [&](auto& tag){return tag.Isotopologue() == isot;}); ptr not_eq specs[i].cend())
370 return {i, std::distance(specs[i].cbegin(), ptr)};
371 }
372 return {-1, -1};
373}
374
375
377 Index num_free_electrons = 0;
378 for (Index i = 0; i < abs_species.nelem(); ++i) {
379 bool has_free_electrons = false;
380 bool has_particles = false;
381 bool has_hitran_xsec = false;
382 for (Index s = 0; s < abs_species[i].nelem(); ++s) {
383 if (abs_species[i][s].Type() == Species::TagType::FreeElectrons) {
384 num_free_electrons++;
385 has_free_electrons = true;
386 }
387
388 if (abs_species[i][s].Type() == Species::TagType::Particles) {
389 has_particles = true;
390 }
391
392 if (abs_species[i][s].Type() == Species::TagType::HitranXsec) {
393 has_hitran_xsec = true;
394 }
395 }
396
397 ARTS_USER_ERROR_IF (abs_species[i].nelem() > 1 && has_free_electrons,
398 "'free_electrons' must not be combined "
399 "with other tags in the same group.");
400 ARTS_USER_ERROR_IF (num_free_electrons > 1,
401 "'free_electrons' must not be defined "
402 "more than once.");
403
404 ARTS_USER_ERROR_IF (abs_species[i].nelem() > 1 && has_particles,
405 "'particles' must not be combined "
406 "with other tags in the same group.");
407
408 ARTS_USER_ERROR_IF (abs_species[i].nelem() > 1 && has_hitran_xsec,
409 "'hitran_xsec' must not be combined "
410 "with other tags in the same group.");
411 }
412}
413
414String ArrayOfSpeciesTag::Name() const
415{
416 String out="";
417 bool first = true;
418 for (auto& x: *this) {
419 if (not first) out += ", ";
420 out += x.Name();
421 first = false;
422 }
423 return out;
424}
425
426std::set<Species::Species> lbl_species(const ArrayOfArrayOfSpeciesTag& abs_species) noexcept {
427 std::set<Species::Species> unique_species;
428 for (auto& specs: abs_species) {
429 if (specs.RequireLines()) unique_species.insert(specs.front().Spec());
430 }
431 return unique_species;
432}
433
char * isot
void Error(const String &msg, const Verbosity &verbosity)
WORKSPACE METHOD: Error.
Definition: m_general.cc:397
ArrayOfSpeciesTag() noexcept
Definition: species_tags.h:103
Index nelem() const ARTS_NOEXCEPT
Number of elements.
Definition: array.h:195
Index nelem() const
Number of elements.
Definition: mystring.h:253
void trim()
Trim leading and trailing whitespace.
Definition: mystring.h:232
static const Index npos
Define npos:
Definition: mystring.h:107
#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:43
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
Index nelem(const Lines &l)
Number of lines.
char Type type
VectorView std(VectorView std, const Vector &y, const ArrayOfVector &ys, const Index start, const Index end_tmp)
Compute the standard deviation of the ranged ys.
Definition: raw.cc:205
String isotopologues_names(Species spec)
constexpr bool is_predefined_model(const IsotopeRecord &ir) noexcept
constexpr std::array Isotopologues
Definition: isotopologues.h:50
constexpr Index find_species_index(const Species spec, const std::string_view isot) noexcept
constexpr Rational end(Rational Ju, Rational Jl, Polarization type) noexcept
Gives the largest M for a polarization type of this transition.
Definition: zeemandata.h:109
constexpr int isdigit(int ch) noexcept
Definition: nonstd.h:24
#define a
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
Species::Tag SpeciesTag
Definition: species_tags.h:99
Struct containing all information needed about one isotope.
Definition: isotopologues.h:14