ARTS  2.3.1285(git:92a29ea9-dirty)
abs_species_tags.cc
Go to the documentation of this file.
1 /* Copyright (C) 2002-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 
31 #include "abs_species_tags.h"
32 #include <cfloat>
33 #include <map>
34 #include "absorption.h"
35 #include "arts.h"
36 #include "auto_md.h"
37 #include "global_data.h"
38 
40 
48 SpeciesTag::SpeciesTag(String def) : misotopologue(-1), mlf(-1), muf(-1), mtype(TYPE_PLAIN), mcia_second(-1), mcia_dataset(-1) {
49  // Save input string for error messages:
50  String def_original = def;
51 
52  // Species lookup data:
54  // Name of species and isotopologue (aux variables):
55  String name, isoname;
56  // Aux index:
57  Index n;
58 
59  // We cannot set a default value for the isotopologue, because the
60  // default should be `ALL' and the value for `ALL' depends on the
61  // species.
62 
63  // Extract the species name:
64  n = def.find('-'); // find the '-'
65  if (n != def.npos) {
66  name = def.substr(0, n); // Extract before '-'
67  def.erase(0, n + 1); // Remove from def
68  } else {
69  // n==def.npos means that def does not contain a '-'. In that
70  // case we assume that it contains just a species name and
71  // nothing else
72  name = def;
73  def = "";
74  }
75 
76  // Obtain species index from species name.
77  // (This will also remove possible whitespace.)
79 
80  // Remove whitespace
81  name.trim();
82 
83  // Check if species name contains the special tag for
84  // Faraday Rotation
85  if (name == "free_electrons") {
87  return;
88  }
89 
90  // Check if species name contains the special tag for
91  // Particles
92  if (name == "particles") {
94  return;
95  }
96 
97  if (0 > mspecies) {
98  ostringstream os;
99  os << "Species \"" << name << "\" is not a valid species.";
100  throw runtime_error(os.str());
101  }
102 
103  // Get a reference to the relevant Species Record:
104  const SpeciesRecord& spr = species_data[mspecies];
105 
106  if (0 == def.nelem()) {
107  // This means that there is nothing else to parse. Apparently
108  // the user wants all isotopologues and no frequency limits.
109  // Frequency defaults are already set. Set isotopologue defaults:
110  misotopologue = spr.Isotopologue().nelem();
111  // This means all isotopologues.
112 
113  return;
114  }
115 
116  // Extract the isotopologue name/Zeeman flag:
117  n = def.find('-'); // find the '-'
118  if (n != def.npos) {
119  isoname = def.substr(0, n); // Extract before '-'
120  def.erase(0, n + 1); // Remove from def
121 
122  if ("Z" == isoname) {
123  mtype = TYPE_ZEEMAN;
124  // Zeeman flag was present, now extract the isotopologue name:
125  n = def.find('-'); // find the '-'
126  if (n != def.npos) {
127  isoname = def.substr(0, n); // Extract before '-'
128  def.erase(0, n + 1); // Remove from def
129  } else {
130  // n==def.npos means that def does not contain a '-'. In that
131  // case we assume that it contains just the isotopologue name and
132  // nothing else.
133  isoname = def;
134  def = "";
135  }
136  }
137 
138  if ("HXSEC" == isoname) {
140  // Hitran Xsec flag was present, now extract the isotopologue name:
141  n = def.find('-'); // find the '-'
142  if (n != def.npos) {
143  isoname = def.substr(0, n); // Extract before '-'
144  def.erase(0, n + 1); // Remove from def
145  } else {
146  // n==def.npos means that def does not contain a '-'. In that
147  // case we assume that it contains just the isotopologue name and
148  // nothing else.
149  isoname = def;
150  def = "";
151  }
152  }
153  } else {
154  // n==def.npos means that def does not contain a '-'. In that
155  // case we assume that it contains just the isotopologue name or
156  // Zeeman flag and nothing else.
157  isoname = def;
158  def = "";
159  if ("Z" == isoname) {
160  mtype = TYPE_ZEEMAN;
161  // This means that there is nothing else to parse. Apparently
162  // the user wants all isotopologues and no frequency limits.
163  misotopologue = spr.Isotopologue().nelem();
164  return;
165  }
166  if ("HXSEC" == isoname) {
168  // This means that there is nothing else to parse. Apparently
169  // the user wants all isotopologues and no frequency limits.
170  misotopologue = spr.Isotopologue().nelem();
171  return;
172  }
173  }
174 
175  // Check for joker:
176  if ("*" == isoname) {
177  // The user wants all isotopologues. Set this accordingly:
178  misotopologue = spr.Isotopologue().nelem();
179  }
180  // else if ( "nl" == isoname ) // Check for "nl":
181  // {
182  // // The user wants no lines at all. Set this accordingly:
183  // misotopologue = -1;
184  // }
185  else if ("CIA" == isoname) // Check for "cia":
186  {
187  // The user wants this to use the CIA catalog:
188  mtype = TYPE_CIA;
189  misotopologue = -1;
190 
191  // We have to read in the second species, and the dataset index
192  n = def.find('-'); // find the '-'
193 
194  if (n == def.npos) {
195  ostringstream os;
196  os << "Invalid species tag " << def_original << ".\n"
197  << "I am missing a minus sign (and a dataset index after that.)";
198  throw runtime_error(os.str());
199  }
200 
201  String otherspec = def.substr(0, n); // Extract before '-'
202  def.erase(0, n + 1); // Remove from def
203 
205 
206  if (0 > mcia_second) {
207  ostringstream os;
208  os << "CIA species \"" << otherspec << "\" is not a valid species.";
209  throw runtime_error(os.str());
210  }
211 
212  // Convert remaining def to dataset index.
213 
214  // Check that everything remaining is just numbers.
215  for (Index i = 0; i < def.nelem(); ++i)
216  if (!isdigit(def[i])) {
217  ostringstream os;
218  os << "Invalid species tag " << def_original << ".\n"
219  << "The tag should end with a dataset index";
220  throw runtime_error(os.str());
221  }
222 
223  // Do the conversion from string to index:
224  istringstream is(def);
225  is >> mcia_dataset;
226 
227  def = "";
228  } else {
229  // Make an array containing the isotopologue names:
230  ArrayOfString ins;
231  for (Index i = 0; i < spr.Isotopologue().nelem(); ++i)
232  ins.push_back(spr.Isotopologue()[i].Name());
233 
234  misotopologue = find_first(ins, isoname);
235 
236  // Check if we found a matching isotopologue:
237  if (misotopologue < 0) {
238  ostringstream os;
239  os << "Isotopologue " << isoname << " is not a valid isotopologue or "
240  << "absorption model for species " << name << ".\n"
241  << "Valid options are:\n";
242  for (Index i = 0; i < ins.nelem(); ++i)
243  os << name << "-" << ins[i] << "\n";
244  throw runtime_error(os.str());
245  }
246 
247  // Check if the found isotopologue represents a predefined model
248  // (continuum or full absorption model) and set the type accordingly:
249  if (!isdigit(isoname[0])) mtype = TYPE_PREDEF;
250  }
251 
252  if (0 == def.nelem()) {
253  // This means that there is nothing else to parse. Apparently
254  // the user wants no frequency limits. Frequency defaults are
255  // already set, so we can return directly.
256 
257  return;
258  }
259 
260  if (def[0] != '*' && !isdigit(def[0])) {
261  ostringstream os;
262  os << "Expected frequency limits, but got \"" << def << "\"";
263  throw runtime_error(os.str());
264  }
265 
266  // Look for the two frequency limits:
267 
268  // Extract first frequency
269  n = def.find('-'); // find the '-'
270  if (n != def.npos) {
271  // Frequency as a String:
272  String fname;
273  fname = def.substr(0, n); // Extract before '-'
274  def.erase(0, n + 1); // Remove from def
275 
276  // Check for joker:
277  if ("*" == fname) {
278  // The default for mlf is already -1, meaning `ALL'.
279  // So there is nothing to do here.
280  } else if (!isdigit(fname[0])) {
281  ostringstream os;
282  os << "Expected frequency limit, but got \"" << fname << "\"";
283  throw runtime_error(os.str());
284  } else {
285  // Convert to Numeric:
286  char* endptr;
287  mlf = strtod(fname.c_str(), &endptr);
288  if (endptr != fname.c_str() + fname.nelem()) {
289  ostringstream os;
290  os << "Error parsing frequency limit \"" << fname << "\"";
291  throw runtime_error(os.str());
292  }
293  }
294  } else {
295  // n==def.npos means that def does not contain a '-'. In this
296  // case that is not allowed!
297  throw runtime_error(
298  "You must either specify both frequency limits\n"
299  "(at least with jokers), or none.");
300  }
301 
302  // Now there should only be the upper frequency left in def.
303  // Check for joker:
304  if ("*" == def) {
305  // The default for muf is already -1, meaning `ALL'.
306  // So there is nothing to do here.
307  } else if (!isdigit(def[0])) {
308  ostringstream os;
309  os << "Expected frequency limit, but got \"" << def << "\"";
310  throw runtime_error(os.str());
311  } else {
312  // Convert to Numeric:
313  char* endptr;
314  muf = strtod(def.c_str(), &endptr);
315  if (endptr != def.c_str() + def.nelem()) {
316  ostringstream os;
317  os << "Error parsing frequency limit \"" << def << "\"";
318  throw runtime_error(os.str());
319  }
320  }
321 }
322 
324 
337  // Species lookup data:
339  // A reference to the relevant record of the species data:
340  const SpeciesRecord& spr = species_data[mspecies];
341  // For return value:
342  ostringstream os;
343 
344  // First the species name:
345  os << spr.Name() << "-";
346 
347  // Is this a CIA tag?
348  if (mtype == TYPE_CIA) {
349  os << "CIA-" << species_name_from_species_index(mcia_second) << "-"
350  << mcia_dataset;
351 
352  } else if (mtype == TYPE_FREE_ELECTRONS || mtype == TYPE_PARTICLES) {
353  os << spr.Name();
354  }
355  // Hitran Xsec flag.
356  else if (mtype == TYPE_HITRAN_XSEC) {
357  os << "HXSEC";
358  } else {
359  // Zeeman flag.
360  if (mtype == TYPE_ZEEMAN) os << "Z-";
361 
362  // Now the isotopologue. Can be a single isotopologue or ALL.
363  if (misotopologue == spr.Isotopologue().nelem()) {
364  // One larger than allowed means all isotopologues!
365  os << "*-";
366  } else if (misotopologue == -1) {
367  // -1 means no lines!
368  os << "nl-";
369  } else {
370  os << spr.Isotopologue()[misotopologue].Name() << "-";
371  }
372 
373  // Now the frequency limits, if there are any. For this we first
374  // need to determine the floating point precision.
375 
376  // Determine the precision, depending on whether Numeric is double
377  // or float:
378  int precision;
379 #ifdef USE_FLOAT
380  precision = FLT_DIG;
381 #else
382 #ifdef USE_DOUBLE
383  precision = DBL_DIG;
384 #else
385 #error Numeric must be double or float
386 #endif
387 #endif
388 
389  if (0 > mlf) {
390  // mlf < 0 means no lower limit.
391  os << "*-";
392  } else {
393  os << setprecision(precision);
394  os << mlf << "-";
395  }
396 
397  if (0 > muf) {
398  // muf < 0 means no upper limit.
399  os << "*";
400  } else {
401  os << setprecision(precision);
402  os << muf;
403  }
404  }
405  return os.str();
406 }
407 
410 }
411 
413  // Species lookup data:
415 
416  // A reference to the relevant record of the species data:
417  const Array<IsotopologueRecord> iso = species_data[mspecies].Isotopologue();
418 
419  // Return either the mass of the first element or the mass of the isotopologue
420  return iso[(misotopologue > -1 and misotopologue < iso.nelem())
421  ? misotopologue
422  : 0]
423  .Mass();
424 }
425 
426 bool SpeciesTag::IsSpecies(const String& s) const {
428 }
429 
430 bool SpeciesTag::IsIsotopologue(const String& i) const {
431  // Species lookup data:
433  // A reference to the relevant record of the species data:
434  const SpeciesRecord& spr = species_data[mspecies];
435 
436  // Now the isotopologue. Can be a single isotopologue or ALL.
437  if (misotopologue == spr.Isotopologue().nelem())
438  return true;
439  else if (misotopologue < 0)
440  return false;
441  else
442  return i == spr.Isotopologue()[misotopologue].Name();
443 
445 }
446 
447 ostream& operator<<(ostream& os, const SpeciesTag& ot) {
448  return os << ot.Name();
449 }
450 
452 
465  String name = "";
466  Index i;
467 
468  for (i = 0; i < tg.nelem() - 1; ++i) {
469  name += tg[i].Name() + ", ";
470  }
471  name += tg[i].Name();
472 
473  return name;
474 }
475 
477 
498  // Get species index of first tag:
499  Index spec_ind = tg[0].Species();
500 
501  // As a safety check, make sure that all other species indices are
502  // the same:
503  for (Index i = 1; i < tg.nelem(); ++i) {
504  // out1 << spec_ind << " " << tg[i].Species() << "\n";
505  if (tg[i].Species() != spec_ind) {
506  ostringstream os;
507  os << "All tags in a tag group must belong to the same species!\n"
508  << "The offending tag group is: " << get_tag_group_name(tg);
509  throw runtime_error(os.str());
510  }
511  }
512 
513  return species_name_from_species_index(spec_ind);
514 }
515 
517 
533  const Index& spec) {
534  return find_next_species_tg(tgs, spec, 0);
535 }
536 
538 
556  const Index& spec,
557  const Index& start) {
558  for (Index i = start; i < tgs.nelem(); ++i) {
559  // We compare the given species index spec to the index of the
560  // first element in each tag group. (All elements of a group
561  // must belong to the same species.)
562  //
563  // If they match, then this i is the index of the tag group we
564  // want.
565  if (spec == tgs[i][0].Species()) return i;
566  }
567 
568  // If we get here, then spec did not match the species of any of the
569  // tag groups.
570  return -1;
571 }
572 
574 
587  const String& names) {
588  // There can be a comma separated list of tag definitions, so we
589  // need to break the String apart at the commas.
590  ArrayOfString tag_def;
591 
592  bool go_on = true;
593  String these_names = names;
594  while (go_on) {
595  // Index n = find_first( these_names, ',' );
596  Index n = these_names.find(',');
597  if (n == these_names.npos) // Value npos indicates not found.
598  {
599  // There are no more commas.
600  // cout << "these_names: (" << these_names << ")\n";
601  tag_def.push_back(these_names);
602  go_on = false;
603  } else {
604  tag_def.push_back(these_names.substr(0, n));
605  these_names.erase(0, n + 1);
606  }
607  }
608  // tag_def now holds the different tag Strings for this group.
609 
610  // Set size to zero, in case the method has been called before.
611  tags.resize(0);
612 
613  for (Index s = 0; s < tag_def.nelem(); ++s) {
614  SpeciesTag this_tag(tag_def[s]);
615 
616  // Safety checks:
617  if (s > 0) {
618  // Tags inside a group must belong to the same species.
619  if (tags[0].Species() != this_tag.Species())
620  throw runtime_error(
621  "Tags in a tag group must belong to the same species.");
622 
623  // Zeeman tags and plain line by line tags must not be mixed. (Because
624  // there can be only one line list per tag group.)
625  if (((tags[0].Type() == SpeciesTag::TYPE_ZEEMAN) &&
626  (this_tag.Type() == SpeciesTag::TYPE_PLAIN)) ||
627  ((tags[0].Type() == SpeciesTag::TYPE_PLAIN) &&
628  (this_tag.Type() == SpeciesTag::TYPE_ZEEMAN)))
629  throw runtime_error(
630  "Zeeman tags and plain line-by-line tags must "
631  "not be mixed in the same tag group.");
632  }
633 
634  tags.push_back(this_tag);
635  }
636 }
637 
639 
649 void check_abs_species(const ArrayOfArrayOfSpeciesTag& abs_species) {
650  Index num_free_electrons = 0;
651  for (Index i = 0; i < abs_species.nelem(); ++i) {
652  bool has_free_electrons = false;
653  bool has_particles = false;
654  bool has_hitran_xsec = false;
655  for (Index s = 0; s < abs_species[i].nelem(); ++s) {
656  if (abs_species[i][s].Type() == SpeciesTag::TYPE_FREE_ELECTRONS) {
657  num_free_electrons++;
658  has_free_electrons = true;
659  }
660 
661  if (abs_species[i][s].Type() == SpeciesTag::TYPE_PARTICLES) {
662  has_particles = true;
663  }
664 
665  if (abs_species[i][s].Type() == SpeciesTag::TYPE_HITRAN_XSEC) {
666  has_hitran_xsec = true;
667  }
668  }
669 
670  if (abs_species[i].nelem() > 1 && has_free_electrons)
671  throw std::runtime_error(
672  "'free_electrons' must not be combined "
673  "with other tags in the same group.");
674  if (num_free_electrons > 1)
675  throw std::runtime_error(
676  "'free_electrons' must not be defined "
677  "more than once.");
678 
679  if (abs_species[i].nelem() > 1 && has_particles)
680  throw std::runtime_error(
681  "'particles' must not be combined "
682  "with other tags in the same group.");
683 
684  if (abs_species[i].nelem() > 1 && has_hitran_xsec)
685  throw std::runtime_error(
686  "'hitran_xsec' must not be combined "
687  "with other tags in the same group.");
688  }
689 }
690 
702 bool is_zeeman(const ArrayOfSpeciesTag& tg) {
703  for (Index s = 0; s < tg.nelem(); ++s)
704  if (tg[s].Type() == SpeciesTag::TYPE_ZEEMAN) return true;
705 
706  return false;
707 }
708 
721  const ArrayOfArrayOfSpeciesTag& tags1,
722  const ArrayOfSpeciesTag& tag2) {
723  bool found = false;
724 
725  for (Index i = 0; i < tags1.nelem() && !found; ++i) {
726  // Is at least the size correct?
727  if (tag2.nelem() == tags1[i].nelem()) {
728  bool ok = true;
729 
730  for (Index j = 0; j < tag2.nelem(); ++j) {
731  if (tag2[j].Name() != tags1[i][j].Name()) ok = false;
732  }
733 
734  if (ok) {
735  found = true;
736  tags1_index = i;
737  }
738  }
739  }
740 
741  if (!found) {
742  ostringstream os;
743  os << "The tag String \"" << tag2
744  << "\" does not match any of the given tags.\n";
745  throw runtime_error(os.str());
746  }
747 }
748 
749 
751 {
752  for (Index i=0; i<list_of_tags.nelem(); i++) {
753  for (Index j=0; j<list_of_tags[i].nelem(); j++) {
754  if (list_of_tags[i][j] == tag) {
755  return i;
756  }
757  }
758  }
759  return -1;
760 }
761 
void iso(Array< IsotopologueRecord >::iterator &ii, String name, const ArrayOfNumeric &coeff, const ArrayOfNumeric &temp_range, const Index &coefftype)
Initialize isotopologue and move iterator to next one.
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
#define precision
Definition: logic.cc:43
Index misotopologue
Isotopologue species index.
Index find_first(const Array< base > &x, const base &w)
Find first occurance.
Definition: array.h:292
SpeciesTag()
Default constructor.
Index nelem() const
Number of elements.
Definition: array.h:195
void get_tag_group_index_for_tag_group(Index &tags1_index, const ArrayOfArrayOfSpeciesTag &tags1, const ArrayOfSpeciesTag &tag2)
Returns the index of the tag group tg2 within the array of tag groups tgs1.
String Name() const
Return the full name of the tag.
void check_abs_species(const ArrayOfArrayOfSpeciesTag &abs_species)
Check the correctness of abs_species.
Index Species() const
Molecular species index.
Index Type() const
Return the type of this tag.
String get_tag_group_name(const ArrayOfSpeciesTag &tg)
Return the name of a tag group as a string.
bool is_zeeman(const ArrayOfSpeciesTag &tg)
Is this a Zeeman tag group?
const Array< SpeciesRecord > species_data
Species Data.
Numeric mlf
The lower limit line center frequency in Hz.
String species_name_from_species_index(const Index spec_ind)
Return species name for given species index.
Definition: absorption.cc:569
const Array< IsotopologueRecord > & Isotopologue() const
Definition: absorption.h:199
The global header file for ARTS.
bool IsSpecies(const String &s) const
Check if the species is same as SpeciesTag(s).Species()
_CS_string_type str() const
Definition: sstream.h:491
Contains the lookup data for one species.
Definition: absorption.h:144
A tag group can consist of the sum of several of these.
Index find_first_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec)
Find first occurrence of species in tag groups.
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Numeric SpeciesMass() const
Mass of main species.
Index nelem() const
Number of elements.
Definition: mystring.h:246
const String & Name() const
Definition: absorption.h:197
Declarations required for the calculation of absorption coefficients.
bool IsIsotopologue(const String &i) const
Check if the isotopologue is same as SpeciesTag(s).Isotopologue()
Index mspecies
Molecular species index.
Numeric muf
The upper line center frequency in Hz.
Index species_index_from_species_name(String name)
Return species index for given species name.
Definition: absorption.cc:531
void trim()
Trim leading and trailing whitespace.
Definition: mystring.h:225
String get_species_name(const ArrayOfSpeciesTag &tg)
Return the species of a tag group as a string.
Index find_next_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec, const Index &start)
Find next occurrence of species in tag groups.
Index mcia_dataset
CIA dataset index.
Header file for stuff related to absorption species tags.
Index nelem(const Lines &l)
Number of lines.
constexpr Rational start(Rational Ju, Rational Jl, Polarization type) noexcept
Gives the lowest M for a polarization type of this transition.
Definition: zeemandata.h:77
Index mtype
Type of this tag.
static const Index npos
Define npos:
Definition: mystring.h:106
String SpeciesNameMain() const
Name of main species.
ostream & operator<<(ostream &os, const SpeciesTag &ot)
Output operator for SpeciesTag.
void array_species_tag_from_string(ArrayOfSpeciesTag &tags, const String &names)
Converts a String to ArrayOfSpeciesTag.
Index mcia_second
2nd CIA species index.