ARTS  2.2.66
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 "arts.h"
32 #include <cfloat>
33 #include <map>
34 #include "absorption.h"
35 #include "auto_md.h"
36 #include "abs_species_tags.h"
37 #include "global_data.h"
38 
40 
49 {
50  // Save input string for error messages:
51  String def_original = def;
52 
53  // Species lookup data:
55  // Name of species and isotopologue (aux variables):
56  String name, isoname;
57  // Aux index:
58  Index n;
59 
60  // Set default values for isotopologue
61  misotopologue = -1;
62 
63  // Set frequency limits to default values (no limits):
64  mlf = -1;
65  muf = -1;
66 
67  // Set CIA species to -1 by default
68  mcia_second = -1;
69 
70  // Set type to normal LBL species by default
71  mtype = TYPE_PLAIN;
72 
73  // Set line mixing type to none by default
75 
76  // We cannot set a default value for the isotopologue, because the
77  // default should be `ALL' and the value for `ALL' depends on the
78  // species.
79 
80 
81  // Extract the species name:
82  n = def.find('-'); // find the '-'
83  if (n != def.npos )
84  {
85  name = def.substr(0,n); // Extract before '-'
86  def.erase(0,n+1); // Remove from def
87  }
88  else
89  {
90  // n==def.npos means that def does not contain a '-'. In that
91  // case we assume that it contains just a species name and
92  // nothing else
93  name = def;
94  def = "";
95  }
96 
97  // Obtain species index from species name.
98  // (This will also remove possible whitespace.)
100 
101  // Remove whitespace
102  name.trim();
103 
104  // Check if species name contains the special tag for
105  // Faraday Rotation
106  if (name == "free_electrons")
107  {
109  return;
110  }
111 
112  // Check if species name contains the special tag for
113  // Particles
114  if (name == "particles")
115  {
117  return;
118  }
119 
120  if ( 0 > mspecies )
121  {
122  ostringstream os;
123  os << "Species \"" << name << "\" is not a valid species.";
124  throw runtime_error(os.str());
125  }
126 
127  // Get a reference to the relevant Species Record:
128  const SpeciesRecord& spr = species_data[mspecies];
129 
130  if ( 0 == def.nelem() )
131  {
132  // This means that there is nothing else to parse. Apparently
133  // the user wants all isotopologues and no frequency limits.
134  // Frequency defaults are already set. Set isotopologue defaults:
135  misotopologue = spr.Isotopologue().nelem();
136  // This means all isotopologues.
137 
138  return;
139  }
140 
141  // Extract the isotopologue name/Zeeman flag:
142  n = def.find('-'); // find the '-'
143  if (n != def.npos )
144  {
145  isoname = def.substr(0,n); // Extract before '-'
146  def.erase(0,n+1); // Remove from def
147 
148  if ("Z" == isoname)
149  {
150  mtype = TYPE_ZEEMAN;
151  // Zeeman flag was present, now extract the isotopologue name:
152  n = def.find('-'); // find the '-'
153  if (n != def.npos )
154  {
155  isoname = def.substr(0,n); // Extract before '-'
156  def.erase(0,n+1); // Remove from def
157  }
158  else
159  {
160  // n==def.npos means that def does not contain a '-'. In that
161  // case we assume that it contains just the isotopologue name and
162  // nothing else.
163  isoname = def;
164  def = "";
165  }
166  }
167  }
168  else
169  {
170  // n==def.npos means that def does not contain a '-'. In that
171  // case we assume that it contains just the isotopologue name or
172  // Zeeman flag and nothing else.
173  isoname = def;
174  def = "";
175  if ("Z" == isoname)
176  {
177  mtype = TYPE_ZEEMAN;
178  // This means that there is nothing else to parse. Apparently
179  // the user wants all isotopologues and no frequency limits.
180  misotopologue = spr.Isotopologue().nelem();
181  return;
182  }
183  }
184 
185  // Check for joker:
186  if ( "*" == isoname )
187  {
188  // The user wants all isotopologues. Set this accordingly:
189  misotopologue = spr.Isotopologue().nelem();
190  }
191 // else if ( "nl" == isoname ) // Check for "nl":
192 // {
193 // // The user wants no lines at all. Set this accordingly:
194 // misotopologue = -1;
195 // }
196  else if ( "CIA" == isoname ) // Check for "cia":
197  {
198  // The user wants this to use the CIA catalog:
199  mtype = TYPE_CIA;
200  misotopologue = -1;
201 
202  // We have to read in the second species, and the dataset index
203  n = def.find('-'); // find the '-'
204 
205  if (n == def.npos )
206  {
207  ostringstream os;
208  os << "Invalid species tag " << def_original << ".\n"
209  << "I am missing a minus sign (and a dataset index after that.)";
210  throw runtime_error(os.str());
211  }
212 
213  String otherspec = def.substr(0,n); // Extract before '-'
214  def.erase(0,n+1); // Remove from def
215 
216 
218 
219  if ( 0 > mcia_second )
220  {
221  ostringstream os;
222  os << "CIA species \"" << otherspec << "\" is not a valid species.";
223  throw runtime_error(os.str());
224  }
225 
226  // Convert remaining def to dataset index.
227 
228  // Check that everything remaining is just numbers.
229  for (Index i=0; i<def.nelem(); ++i)
230  if (!isdigit(def[i])) {
231  ostringstream os;
232  os << "Invalid species tag " << def_original << ".\n"
233  << "The tag should end with a dataset index";
234  throw runtime_error(os.str());
235  }
236 
237  // Do the conversion from string to index:
238  istringstream is(def);
239  is >> mcia_dataset;
240 
241  def = "";
242  }
243  else
244  {
245  // Make an array containing the isotopologue names:
246  ArrayOfString ins;
247  for ( Index i=0; i<spr.Isotopologue().nelem(); ++i )
248  ins.push_back( spr.Isotopologue()[i].Name() );
249 
250  misotopologue = find_first (ins, isoname);
251 
252  // Check if we found a matching isotopologue:
253  if ( misotopologue < 0 )
254  {
255  ostringstream os;
256  os << "Isotopologue " << isoname << " is not a valid isotopologue or "
257  << "absorption model for species " << name << ".\n"
258  << "Valid options are:\n";
259  for ( Index i=0; i<ins.nelem(); ++i )
260  os << name << "-" << ins[i] << "\n";
261  throw runtime_error(os.str());
262  }
263 
264  // Check if the found isotopologue represents a predefined model
265  // (continuum or full absorption model) and set the type accordingly:
266  if ( !isdigit(isoname[0]) )
267  mtype = TYPE_PREDEF;
268  }
269 
270  if ( 0 == def.nelem() )
271  {
272  // This means that there is nothing else to parse. Apparently
273  // the user wants no frequency limits. Frequency defaults are
274  // already set, so we can return directly.
275 
276  return;
277  }
278 
279  // Check if a line mixing type is present
280 
281  if (def.substr(0, 2) == "LM")
282  {
283  n = def.find('-'); // find the '-' or the end
284  if (n == def.npos) n = def.nelem();
285 
286  String lmtype = def.substr(0, n);
287  if (lmtype == "LM_2NDORDER")
289  else if (lmtype == "LM_NONE")
291  else
292  {
293  ostringstream os;
294  os << "Unknown line mixing type \"" << lmtype << "\"";
295  throw runtime_error(os.str());
296  }
297 
298  def.erase(0, n+1);
299 
300  // Return if there's nothing else to parse
301  if (!def.nelem()) return;
302  }
303 
304  if (def[0] != '*' && !isdigit(def[0]))
305  {
306  ostringstream os;
307  os << "Expected frequency limits, but got \"" << def << "\"";
308  throw runtime_error(os.str());
309  }
310 
311  // Look for the two frequency limits:
312 
313  // Extract first frequency
314  n = def.find('-'); // find the '-'
315  if (n != def.npos )
316  {
317  // Frequency as a String:
318  String fname;
319  fname = def.substr(0,n); // Extract before '-'
320  def.erase(0,n+1); // Remove from def
321 
322  // Check for joker:
323  if ( "*" == fname )
324  {
325  // The default for mlf is already -1, meaning `ALL'.
326  // So there is nothing to do here.
327  }
328  else if (!isdigit(fname[0]))
329  {
330  ostringstream os;
331  os << "Expected frequency limit, but got \"" << fname << "\"";
332  throw runtime_error(os.str());
333  }
334  else
335  {
336  // Convert to Numeric:
337  char *endptr;
338  mlf = strtod(fname.c_str(), &endptr);
339  if (endptr != fname.c_str() + fname.nelem())
340  {
341  ostringstream os;
342  os << "Error parsing frequency limit \"" << fname << "\"";
343  throw runtime_error(os.str());
344  }
345  }
346  }
347  else
348  {
349  // n==def.npos means that def does not contain a '-'. In this
350  // case that is not allowed!
351  throw runtime_error("You must either specify both frequency limits\n"
352  "(at least with jokers), or none.");
353  }
354 
355 
356  // Now there should only be the upper frequency left in def.
357  // Check for joker:
358  if ( "*" == def )
359  {
360  // The default for muf is already -1, meaning `ALL'.
361  // So there is nothing to do here.
362  }
363  else if (!isdigit(def[0]))
364  {
365  ostringstream os;
366  os << "Expected frequency limit, but got \"" << def << "\"";
367  throw runtime_error(os.str());
368  }
369  else
370  {
371  // Convert to Numeric:
372  char *endptr;
373  muf = strtod(def.c_str(), &endptr);
374  if (endptr != def.c_str() + def.nelem())
375  {
376  ostringstream os;
377  os << "Error parsing frequency limit \"" << def << "\"";
378  throw runtime_error(os.str());
379  }
380  }
381 }
382 
383 
385 
398 {
399  // Species lookup data:
401  // A reference to the relevant record of the species data:
402  const SpeciesRecord& spr = species_data[mspecies];
403  // For return value:
404  ostringstream os;
405 
406  // First the species name:
407  os << spr.Name() << "-";
408 
409  // Is this a CIA tag?
410  if (mtype==TYPE_CIA)
411  {
412  os << "CIA-"
414  << mcia_dataset;
415 
416  }
417  else if (mtype == TYPE_FREE_ELECTRONS || mtype == TYPE_PARTICLES)
418  {
419  os << spr.Name();
420  }
421  else
422  {
423  // Zeeman flag.
424  if (mtype==TYPE_ZEEMAN) os << "Z-";
425 
426  // Now the isotopologue. Can be a single isotopologue or ALL.
427  if ( misotopologue == spr.Isotopologue().nelem() )
428  {
429  // One larger than allowed means all isotopologues!
430  os << "*-";
431  }
432  else if ( misotopologue == -1 )
433  {
434  // -1 means no lines!
435  os << "nl-";
436  }
437  else
438  {
439  os << spr.Isotopologue()[misotopologue].Name() << "-";
440  }
441 
442  // Line Mixing Type
443 
445  {
446  os << "LM_";
447  switch (mline_mixing_type)
448  {
450  os << "2NDORDER";
451  break;
452  default:
453  throw runtime_error("Invalid line mixing type. This is impossible.");
454  }
455  os << "-";
456  }
457 
458  // Now the frequency limits, if there are any. For this we first
459  // need to determine the floating point precision.
460 
461  // Determine the precision, depending on whether Numeric is double
462  // or float:
463  int precision;
464 #ifdef USE_FLOAT
465  precision = FLT_DIG;
466 #else
467 #ifdef USE_DOUBLE
468  precision = DBL_DIG;
469 #else
470 #error Numeric must be double or float
471 #endif
472 #endif
473 
474  if ( 0 > mlf )
475  {
476  // mlf < 0 means no lower limit.
477  os << "*-";
478  }
479  else
480  {
481  os << setprecision(precision);
482  os << mlf << "-";
483  }
484 
485  if ( 0 > muf )
486  {
487  // muf < 0 means no upper limit.
488  os << "*";
489  }
490  else
491  {
492  os << setprecision(precision);
493  os << muf;
494  }
495  }
496  return os.str();
497 }
498 
499 ostream& operator << (ostream& os, const SpeciesTag& ot)
500 {
501  return os << ot.Name();
502 }
503 
505 
518 {
519  String name = "";
520  Index i;
521 
522  for ( i=0; i<tg.nelem()-1; ++i )
523  {
524  name += tg[i].Name() + ", ";
525  }
526  name += tg[i].Name();
527 
528  return name;
529 }
530 
532 
553 {
554  // Get species index of first tag:
555  Index spec_ind = tg[0].Species();
556 
557  // As a safety check, make sure that all other species indices are
558  // the same:
559  for (Index i=1; i<tg.nelem(); ++i)
560  {
561  // out1 << spec_ind << " " << tg[i].Species() << "\n";
562  if (tg[i].Species() != spec_ind)
563  {
564  ostringstream os;
565  os << "All tags in a tag group must belong to the same species!\n"
566  << "The offending tag group is: " << get_tag_group_name(tg);
567  throw runtime_error( os.str() );
568  }
569  }
570 
571  return species_name_from_species_index( spec_ind );
572 }
573 
575 
591  const Index& spec )
592 {
593  return find_next_species_tg(tgs, spec, 0);
594 }
595 
597 
615  const Index& spec,
616  const Index& start )
617 {
618  for ( Index i=start; i<tgs.nelem(); ++i )
619  {
620  // We compare the given species index spec to the index of the
621  // first element in each tag group. (All elements of a group
622  // must belong to the same species.)
623  //
624  // If they match, then this i is the index of the tag group we
625  // want.
626  if ( spec == tgs[i][0].Species() )
627  return i;
628  }
629 
630  // If we get here, then spec did not match the species of any of the
631  // tag groups.
632  return -1;
633 }
634 
635 
637 
650  const String& names )
651 {
652  // There can be a comma separated list of tag definitions, so we
653  // need to break the String apart at the commas.
654  ArrayOfString tag_def;
655 
656  bool go_on = true;
657  String these_names = names;
658  while (go_on)
659  {
660  // Index n = find_first( these_names, ',' );
661  Index n = these_names.find(',');
662  if ( n == these_names.npos ) // Value npos indicates not found.
663  {
664  // There are no more commas.
665  // cout << "these_names: (" << these_names << ")\n";
666  tag_def.push_back(these_names);
667  go_on = false;
668  }
669  else
670  {
671  tag_def.push_back(these_names.substr(0,n));
672  these_names.erase(0,n+1);
673  }
674  }
675  // tag_def now holds the different tag Strings for this group.
676 
677  // Set size to zero, in case the method has been called before.
678  tags.resize(0);
679 
680  for ( Index s=0; s<tag_def.nelem(); ++s )
681  {
682  SpeciesTag this_tag(tag_def[s]);
683 
684  // Safety checks:
685  if (s>0)
686  {
687  // Tags inside a group must belong to the same species.
688  if ( tags[0].Species() != this_tag.Species() )
689  throw runtime_error("Tags in a tag group must belong to the same species.");
690 
691  // Zeeman tags and plain line by line tags must not be mixed. (Because
692  // there can be only one line list per tag group.)
693  if (
694  ((tags[0].Type()==SpeciesTag::TYPE_ZEEMAN) &&
695  (this_tag.Type()==SpeciesTag::TYPE_PLAIN))
696  ||
697  ((tags[0].Type()==SpeciesTag::TYPE_PLAIN) &&
698  (this_tag.Type()==SpeciesTag::TYPE_ZEEMAN))
699  )
700  throw runtime_error("Zeeman tags and plain line-by-line tags must "
701  "not be mixed in the same tag group.");
702  }
703 
704  tags.push_back(this_tag);
705  }
706 }
707 
708 
710 
720 void check_abs_species( const ArrayOfArrayOfSpeciesTag& abs_species )
721 {
722  Index num_free_electrons = 0;
723  for ( Index i=0; i<abs_species.nelem(); ++i )
724  {
725  bool has_free_electrons = false;
726  bool has_particles = false;
727  bool has_line_mixing = false;
728  for ( Index s=0; s<abs_species[i].nelem(); ++s )
729  {
730  if (abs_species[i][s].Type() == SpeciesTag::TYPE_FREE_ELECTRONS)
731  {
732  num_free_electrons++;
733  has_free_electrons = true;
734  }
735 
736  if (abs_species[i][s].Type() == SpeciesTag::TYPE_PARTICLES)
737  {
738  has_particles = true;
739  }
740 
741  if (abs_species[i][s].LineMixingType() != SpeciesTag::LINE_MIXING_TYPE_NONE)
742  {
743  has_line_mixing = true;
744  }
745  }
746 
747  if (abs_species[i].nelem() > 1 && has_free_electrons)
748  throw runtime_error("'free_electrons' must not be combined "
749  "with other tags in the same group.");
750  if (num_free_electrons > 1)
751  throw runtime_error("'free_electrons' must not be defined "
752  "more than once.");
753 
754  if (abs_species[i].nelem() > 1 && has_particles)
755  throw runtime_error("'particles' must not be combined "
756  "with other tags in the same group.");
757  if (abs_species[i].nelem() > 1 && has_line_mixing)
758  throw runtime_error("Line mixing species must not be combined "
759  "with other tags in the same group.");
760  }
761 }
762 
763 
776 {
777  for ( Index s=0; s<tg.nelem(); ++s )
778  if (tg[s].Type()==SpeciesTag::TYPE_ZEEMAN)
779  return true;
780 
781  return false;
782 }
783 
784 
797  const ArrayOfArrayOfSpeciesTag& tgs1,
798  const ArrayOfSpeciesTag& tg2 )
799 {
800  bool found = false;
801 
802  for ( Index i=0;
803  i<tgs1.nelem() && !found;
804  ++i )
805  {
806  // Is at least the size correct?
807  if ( tg2.nelem() == tgs1[i].nelem() )
808  {
809  bool ok = true;
810 
811  for ( Index j=0; j<tg2.nelem(); ++j )
812  {
813  if ( tg2[j].Name() != tgs1[i][j].Name() )
814  ok = false;
815  }
816 
817  if ( ok )
818  {
819  found = true;
820  tgs1_index = i;
821  }
822  }
823  }
824 
825  if ( !found )
826  {
827  ostringstream os;
828  os << "The tag String \"" << tg2 <<
829  "\" does not match any of the given tags.\n";
830  throw runtime_error(os.str());
831  }
832 }
833 
SpeciesTag::mline_mixing_type
Index mline_mixing_type
Line Mixing Type of this tag.
Definition: abs_species_tags.h:189
SpeciesTag::SpeciesTag
SpeciesTag()
Default constructor.
Definition: abs_species_tags.h:49
SpeciesTag::TYPE_PREDEF
@ TYPE_PREDEF
Definition: abs_species_tags.h:119
auto_md.h
SpeciesTag::TYPE_PLAIN
@ TYPE_PLAIN
Definition: abs_species_tags.h:117
absorption.h
Declarations required for the calculation of absorption coefficients.
array_species_tag_from_string
void array_species_tag_from_string(ArrayOfSpeciesTag &tags, const String &names)
Converts a String to ArrayOfSpeciesTag.
Definition: abs_species_tags.cc:649
check_abs_species
void check_abs_species(const ArrayOfArrayOfSpeciesTag &abs_species)
Check the correctness of abs_species.
Definition: abs_species_tags.cc:720
SpeciesTag::LINE_MIXING_TYPE_2NDORDER
@ LINE_MIXING_TYPE_2NDORDER
Definition: abs_species_tags.h:131
SpeciesTag::LINE_MIXING_TYPE_NONE
@ LINE_MIXING_TYPE_NONE
Definition: abs_species_tags.h:130
SpeciesTag::Name
String Name() const
Return the full name of the tag.
Definition: abs_species_tags.cc:397
SpeciesTag::TYPE_ZEEMAN
@ TYPE_ZEEMAN
Definition: abs_species_tags.h:118
SpeciesTag::misotopologue
Index misotopologue
Isotopologue species index.
Definition: abs_species_tags.h:156
get_tag_group_name
String get_tag_group_name(const ArrayOfSpeciesTag &tg)
Return the name of a tag group as a string.
Definition: abs_species_tags.cc:517
global_data::species_data
const Array< SpeciesRecord > species_data
Species Data.
Definition: partition_function_data.cc:43
SpeciesTag::muf
Numeric muf
The upper line center frequency in Hz.
Definition: abs_species_tags.h:164
SpeciesTag::TYPE_FREE_ELECTRONS
@ TYPE_FREE_ELECTRONS
Definition: abs_species_tags.h:121
SpeciesTag::TYPE_PARTICLES
@ TYPE_PARTICLES
Definition: abs_species_tags.h:122
Array< String >
SpeciesTag
A tag group can consist of the sum of several of these.
Definition: abs_species_tags.h:46
species_index_from_species_name
Index species_index_from_species_name(String name)
Return species index for given species name.
Definition: absorption.cc:1260
spec
void spec(Array< SpeciesRecord >::iterator &is, Array< IsotopologueRecord >::iterator &ii, String name)
Define partition function coefficients lookup data.
Definition: partition_function_data.cc:925
is_zeeman
bool is_zeeman(const ArrayOfSpeciesTag &tg)
Is this a Zeeman tag group?
Definition: abs_species_tags.cc:775
species_name_from_species_index
String species_name_from_species_index(const Index spec_ind)
Return species name for given species index.
Definition: absorption.cc:1301
my_basic_string< char >
find_first_species_tg
Index find_first_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec)
Find first occurrence of species in tag groups.
Definition: abs_species_tags.cc:590
SpeciesTag::mcia_dataset
Index mcia_dataset
CIA dataset index.
Definition: abs_species_tags.h:197
get_species_name
String get_species_name(const ArrayOfSpeciesTag &tg)
Return the species of a tag group as a string.
Definition: abs_species_tags.cc:552
SpeciesTag::TYPE_CIA
@ TYPE_CIA
Definition: abs_species_tags.h:120
precision
#define precision
Definition: logic.cc:45
global_data.h
my_basic_string::trim
void trim()
Trim leading and trailing whitespace.
Definition: mystring.h:253
SpeciesTag::mlf
Numeric mlf
The lower limit line center frequency in Hz.
Definition: abs_species_tags.h:160
SpeciesTag::mtype
Index mtype
Type of this tag.
Definition: abs_species_tags.h:179
abs_species_tags.h
Header file for stuff related to absorption species tags.
SpeciesRecord
Contains the lookup data for one species.
Definition: absorption.h:367
my_basic_string::nelem
Index nelem() const
Number of elements.
Definition: mystring.h:278
SpeciesRecord::Isotopologue
const Array< IsotopologueRecord > & Isotopologue() const
Definition: absorption.h:425
SpeciesRecord::Name
const String & Name() const
Definition: absorption.h:423
SpeciesTag::mcia_second
Index mcia_second
2nd CIA species index.
Definition: abs_species_tags.h:193
get_tag_group_index_for_tag_group
void get_tag_group_index_for_tag_group(Index &tgs1_index, const ArrayOfArrayOfSpeciesTag &tgs1, const ArrayOfSpeciesTag &tg2)
Returns the index of the tag group tg2 within the array of tag groups tgs1.
Definition: abs_species_tags.cc:796
SpeciesTag::mspecies
Index mspecies
Molecular species index.
Definition: abs_species_tags.h:149
operator<<
ostream & operator<<(ostream &os, const SpeciesTag &ot)
Output operator for SpeciesTag.
Definition: abs_species_tags.cc:499
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:35
find_next_species_tg
Index find_next_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec, const Index &start)
Find next occurrence of species in tag groups.
Definition: abs_species_tags.cc:614
find_first
Index find_first(const Array< base > &x, const base &w)
Find first occurance.
Definition: array.h:281
my_basic_string::npos
static const Index npos
Define npos:
Definition: mystring.h:105
SpeciesTag::Type
Index Type() const
Return the type of this tag.
Definition: abs_species_tags.h:138
SpeciesTag::Species
Index Species() const
Molecular species index.
Definition: abs_species_tags.h:66
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:176
arts.h
The global header file for ARTS.