ARTS  2.3.1285(git:92a29ea9-dirty)
linefunctiondata.h
Go to the documentation of this file.
1 /* Copyright (C) 2018
2  Richard Larsson <larsson@mps.mpg.de>
3 
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of the GNU General Public License as published by the
7  Free Software Foundation; either version 2, or (at your option) any
8  later version.
9 
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20  USA. */
21 
29 #ifndef linefunctiondata_h
30 #define linefunctiondata_h
31 
32 // Actually needed
33 #include "abs_species_tags.h"
34 #include "jacobian.h"
35 
36 // Using some algorithms
37 #include <numeric>
38 #include "constants.h"
39 
40 
43 
44 
47 
48 
51 
52 
53 namespace LineShape {
54 
56  enum class TemperatureModel : Index {
57  None, // 0
58  T0, // Constant, X0
59  T1, // Standard, X0 * (T0/T) ^ X1
60  T2, // X0 * (T0/T) ^ X1 * (1 + X2 * log(T/T0));
61  T3, // X0 + X1 * (T - T0)
62  T4, // (X0 + X1 * (T0/T - 1)) * (T0/T)^X2;
63  T5, // X0 * (T0/T)^(0.25 + 1.5*X1)
64  LM_AER // Interpolation AER-style
65  // ALWAYS ADD NEW AT THE END
66  };
67 
69  switch(type) {
70  case TemperatureModel::None: return "#";
71  case TemperatureModel::T0: return "T0";
72  case TemperatureModel::T1: return "T1";
73  case TemperatureModel::T2: return "T2";
74  case TemperatureModel::T3: return "T3";
75  case TemperatureModel::T4: return "T4";
76  case TemperatureModel::T5: return "T5";
77  case TemperatureModel::LM_AER: return "LM_AER";
78  }
79  std::terminate(); // Not allowed to reach, fix higher level code
80  }
81 
83  if(type == "#") return TemperatureModel::None;
84  else if(type == String("T0")) return TemperatureModel::T0;
85  else if(type == String("T1")) return TemperatureModel::T1;
86  else if(type == String("T2")) return TemperatureModel::T2;
87  else if(type == String("T3")) return TemperatureModel::T3;
88  else if(type == String("T4")) return TemperatureModel::T4;
89  else if(type == String("T5")) return TemperatureModel::T5;
90  else if(type == String("LM_AER")) return TemperatureModel::LM_AER;
91  else {
93  os << "Type: " << type << ", is not accepted. "
94  << "See documentation for accepted types\n";
95  throw std::runtime_error(os.str());
96  }
97  }
98 
100  enum class Variable {
101  G0=0, // Pressure broadening speed-independent
102  D0=1, // Pressure f-shifting speed-dependent
103  G2=2, // Pressure broadening speed-dependent
104  D2=3, // Pressure f-shifting speed-independent
105  FVC=4, // Frequency of velocity-changing collisions
106  ETA=5, // Correlation
107  Y=6, // First order line mixing coefficient
108  G=7, // Second order line mixing coefficient
109  DV=8 // Second order line mixing f-shifting
110  // ALWAYS ADD NEW AT THE END
111  };
112 
113  inline std::ostream& operator<<(std::ostream& os, Variable v) {
114  switch(v) {
115  case Variable::G0: os << "G0"; break;
116  case Variable::D0: os << "D0"; break;
117  case Variable::G2: os << "G2"; break;
118  case Variable::D2: os << "D2"; break;
119  case Variable::FVC: os << "FVC"; break;
120  case Variable::ETA: os << "ETA"; break;
121  case Variable::Y: os << "Y"; break;
122  case Variable::G: os << "G"; break;
123  case Variable::DV: os << "DV"; break;
124  }
125  return os;
126  }
127 
128  inline String variable2string(Variable type) noexcept {
129  #define VARIABLE2STRINGDEF(X) case Variable::X: return # X
130  switch(type) {
140  }
141  #undef VARIABLE2STRINGDEF
142  std::terminate(); // Not allowed to reach, fix higher level code
143  }
144 
145  inline Variable string2variable(const String& type) {
146  #define STRING2VARIABLEDEF(X) if(type == # X) return Variable::X
148  else STRING2VARIABLEDEF(D0);
149  else STRING2VARIABLEDEF(G2);
150  else STRING2VARIABLEDEF(D2);
151  else STRING2VARIABLEDEF(FVC);
152  else STRING2VARIABLEDEF(ETA);
153  else STRING2VARIABLEDEF(Y);
154  else STRING2VARIABLEDEF(G);
155  else STRING2VARIABLEDEF(DV);
156  else {
158  os << "Type: " << type << ", is not accepted. "
159  << "See documentation for accepted types\n";
160  throw std::runtime_error(os.str());
161  }
162  }
163 
169  // ALWAYS ADD NEW AT THE END
170  };
171 
173  if(type =="X0")
174  return mp.X0;
175  else if(type =="X1")
176  return mp.X1;
177  else if(type =="X2")
178  return mp.X2;
179  else {
181  os << "Type: " << type << ", is not accepted. "
182  << "See documentation for accepted types\n";
183  throw std::runtime_error(os.str());
184  }
185  std::terminate();
186  }
187 
188  inline std::ostream& operator<<(std::ostream& os, const ModelParameters& mp) {
189  os << temperaturemodel2string(mp.type) << ' ' << mp.X0 << ' ' << mp.X1 << ' ' << mp.X2;
190  return os;
191  }
192 
193  inline std::istream& operator>>(std::istream& is, ModelParameters& mp) {
194  String tmp;
195  is >> tmp >> mp.X0 >> mp.X1 >> mp.X2;
196  mp.type = string2temperaturemodel(tmp);
197  return is;
198  }
199 
201  constexpr Index nVars=9;
202  constexpr Index nmaxInterpModels=12;
203 
205  private:
206  std::array<ModelParameters, nVars> X;
207  std::array<Numeric, nmaxInterpModels> V;
208 
210  Variable var) const noexcept
211  {
212  // Data starts at 4 for Y and 8 for G, and must be either
213  const Index i = (var == Variable::Y) ? 4 : 8;
214 
215  if(T < V[1])
216  return V[i+0] + (T-V[0]) * (V[i+1]-V[i+0]) / (V[1]-V[0]);
217  else if(T > V[2])
218  return V[i+2] + (T-V[2]) * (V[i+3]-V[i+2]) / (V[3]-V[2]);
219  else
220  return V[i+1] + (T-V[1]) * (V[i+2]-V[i+1]) / (V[2]-V[1]);
221  }
222 
224  Variable var) const noexcept
225  {
226  // Data starts at 4 for Y and 8 for G, and must be either
227  const Index i = (var == Variable::Y) ? 4 : 8;
228 
229  if(T < V[1])
230  return (V[i+1]-V[i+0]) / (V[1]-V[0]);
231  else if(T > V[2])
232  return (V[i+3]-V[i+2]) / (V[3]-V[2]);
233  else
234  return (V[i+2]-V[i+1]) / (V[2]-V[1]);
235  }
236 
237  public:
238  constexpr
248  std::array<Numeric, nmaxInterpModels> interp = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) :
249  X({G0, D0, G2, D2, FVC, ETA, Y, G, DV}), V(interp)
250  {}
251 
252  #define x0 X[Index(var)].X0
253  #define x1 X[Index(var)].X1
254  #define x2 X[Index(var)].X2
255 
256  // Standard compute feature
257  Numeric compute(Numeric T, Numeric T0, Variable var) const noexcept {
258  using std::pow;
259  using std::log;
260 
261  switch(X[Index(var)].type) {
263  return 0;
265  return x0;
267  return x0 * pow(T0/T, x1);
269  return x0 * pow(T0/T, x1) * (1 + x2 * log(T/T0));
271  return x0 + x1 * (T - T0);
273  return (x0 + x1 * (T0/T - 1.)) * pow(T0/T, x2);
275  return x0 * pow(T0/T, 0.25 + 1.5*x1);
277  return special_linemixing_aer(T, var);
278  }
279  std::terminate();
280  }
281 
282  // Standard compute feature for derivative wrt x0
284  using std::pow;
285  using std::log;
286 
287  switch(X[Index(var)].type) {
289  return 0;
291  return 1;
293  return pow(T0/T, x1);
295  return pow(T0/T, x1) * (1 + x2 * log(T/T0));
297  return 1;
299  return pow(T0/T, x2);
301  return pow(T0/T, 1.5*x1 + 0.25);
303  return 0;
304  }
305  std::terminate();
306  }
307 
308  // Standard compute feature for derivative wrt x1
310  using std::pow;
311  using std::log;
312 
313  switch(X[Index(var)].type) {
315  return 0;
317  return 0;
319  return x0*pow(T0/T, x1)*log(T0/T);
321  return x0*pow(T0/T,x1)*(x2*log(T/T0)+1.)*log(T0/T);
323  return (T - T0);
325  return pow(T0/T, x2)*(T0/T - 1.);
327  return 1.5*x0*pow(T0/T, 1.5*x1 + 0.25)*log(T0/T);
329  return 0;
330  }
331  std::terminate();
332  }
333 
334  // Standard compute feature for derivative wrt x2
336  using std::pow;
337  using std::log;
338 
339  switch(X[Index(var)].type) {
341  return 0;
343  return 0;
345  return 0;
347  return x0*pow(T0/T, x1)*log(T/T0);
349  return 0;
351  return pow(T0/T,x2)*(x0+x1*(T0/T-1))*log(T0/T);
353  return 0;
355  return 0;
356  }
357  std::terminate();
358  }
359 
360  // Standard compute feature for derivative wrt T
362  using std::pow;
363  using std::log;
364 
365  switch(X[Index(var)].type) {
367  return 0;
369  return 0;
371  return -x0*x1*pow(T0/T, x1)/T;
373  return -x0*x1*pow(T0/T,x1)*(x2*log(T/T0)+1.)/T+x0*x2*pow(T0/T,x1)/T;
375  return x1;
377  return -x2*pow(T0/T,x2)*(x0+x1*(T0/T-1.))/T-T0*x1*pow(T0/T,x2)/pow(T,2);
379  return -x0*pow(T0/T,1.5*x1 + 0.25)*(1.5*x1 + 0.25)/T;
381  return special_linemixing_aer_dT(T, var);
382  }
383  std::terminate();
384  }
385 
386  // Standard compute feature for derivative wrt T0
388  using std::pow;
389  using std::log;
390 
391  switch(X[Index(var)].type) {
393  return 0;
395  return 0;
397  return x0*x1*pow(T0/T, x1)/T0;
399  return x0*x1*pow(T0/T,x1)*(x2*log(T/T0)+1.)/T0-x0*x2*pow(T0/T,x1)/T0;
401  return -x1;
403  return x2*pow(T0/T,x2)*(x0+x1*(T0/T-1.))/T0+x1*pow(T0/T,x2)/T;
405  return x0*pow(T0/T,1.5*x1 + 0.25)*(1.5*x1 + 0.25)/T0;
407  return 0;
408  }
409  std::terminate();
410  }
411 
412  #undef x0
413  #undef x1
414  #undef x2
415 
416  // Access normal data
417  #define ACCESS_INTERNAL(VARPOS) \
418  ModelParameters& VARPOS() noexcept {return X[Index(Variable::VARPOS)];} \
419  ModelParameters VARPOS() const noexcept {return X[Index(Variable::VARPOS)];}
422  ACCESS_INTERNAL(FVC); ACCESS_INTERNAL(ETA);
424  #undef ACCESS_INTERNAL
425 
426  // Access to all data
427  std::array<ModelParameters, nVars>& Data() noexcept {return X;}
428  const std::array<ModelParameters, nVars>& Data() const noexcept {return X;}
429  std::array<Numeric, nmaxInterpModels>& Interp() noexcept {return V;}
430  const std::array<Numeric, nmaxInterpModels>& Interp() const noexcept {return V;}
431 
432  void Set(Variable var, const ModelParameters& x) noexcept {
433  #define MODELPARAMCASESETTER(X) case Variable::X: X () = x; break
434  switch(var) {
444  }
445  #undef MODELPARAMCASESETTER
446  }
447 
448  ModelParameters Get(Variable var) const noexcept {
449  #define MODELPARAMCASEGETTER(X) case Variable::X: return X ();
450  switch(var) {
460  }
461  #undef MODELPARAMCASEGETTER
462  std::terminate();
463  }
464 
465  // Read complete binary data... FIXME? adopt for versioning? constexpr numbers above are assumed
466  std::istream& read(std::istream& is) {
467  is.read(reinterpret_cast<char*>(this), sizeof(SingleSpeciesModel));
468  return is;
469  }
470 
471  // Write complete binary data
472  std::ostream& write(std::ostream& os) const {
473  os.write(reinterpret_cast<const char*>(this), sizeof(SingleSpeciesModel));
474  return os;
475  }
476  };
477 
478  inline std::ostream& operator<<(std::ostream& os, const SingleSpeciesModel& ssm) {
479  for(const auto& mp: ssm.Data()) os << mp << ' ';
480  for(const auto& num: ssm.Interp()) os << num << ' ';
481  return os;
482  }
483 
484  inline std::istream& operator>>(std::istream& is, SingleSpeciesModel& ssm) {
485  for(auto& mp: ssm.Data()) is >> mp;
486  for(auto& num: ssm.Interp()) is >> num;
487  return is;
488  }
489 
490  enum class Type {
491  DP, // Doppler
492  LP, // Lorentz
493  VP, // Voigt
494  SDVP, // Speed-dependent Voigt
495  HTP, // Hartmann-Tran
496  };
497 
498  inline String shapetype2string(Type type) noexcept {
499  switch(type) {
500  case Type::DP: return "DP";
501  case Type::LP: return "LP";
502  case Type::VP: return "VP";
503  case Type::SDVP: return "SDVP";
504  case Type::HTP: return "HTP";
505  }
506  std::terminate(); // Not allowed to reach, fix higher level code
507  }
508 
509  inline Type string2shapetype(const String& type) {
510  if(type == "DP") return Type::DP;
511  else if(type == String("LP")) return Type::LP;
512  else if(type == String("VP")) return Type::VP;
513  else if(type == String("SDVP")) return Type::SDVP;
514  else if(type == String("HTP")) return Type::HTP;
515  else {
517  os << "Type: " << type << ", is not accepted. "
518  << "See documentation for accepted types\n";
519  throw std::runtime_error(os.str());
520  }
521  }
522 
523  struct Output {
524  Numeric
525  G0, // Pressure broadening speed-independent
526  D0, // Pressure f-shifting speed-independent
527  G2, // Pressure broadening speed-dependent
528  D2, // Pressure f-shifting speed-dependent
529  FVC, // Frequency of velocity-changing collisions
530  ETA, // Correlation
531  Y, // First order line mixing coefficient
532  G, // Second order line mixing coefficient
533  DV; // Second order line mixing f-shifting
534  };
535 
536  inline std::ostream& operator<<(std::ostream& os, Output x) {
537  return os << "G0: " << x.G0
538  << " D0: " << x.D0
539  << " G2: " << x.G2
540  << " D2: " << x.D2
541  << " FVC: " << x.FVC
542  << " ETA: " << x.ETA
543  << " Y: " << x.Y
544  << " G: " << x.G
545  << " DV: " << x.DV;
546  }
547 
548  constexpr Output mirroredOutput(Output x) noexcept {
549  return {x.G0, -x.D0, x.G2, -x.D2, x.FVC, x.ETA, x.Y, x.G, -x.DV};
550  }
551 
552 
553  constexpr Output negativeOutput(Output x) noexcept {
554  return {-x.G0, -x.D0, -x.G2, -x.D2, -x.FVC, -x.ETA, -x.Y, -x.G, -x.DV};
555  }
556 
557 
558  constexpr Output si2cgs(Output x) noexcept {
560  return {freq2kaycm(x.G0), freq2kaycm(x.D0),
561  freq2kaycm(x.D2), freq2kaycm(x.G2),
562  freq2kaycm(x.FVC), x.ETA,
563  x.Y, x.G, freq2kaycm(x.DV)};
564  }
565 
566 
567  constexpr Output differenceOutput(Output y, Output x) noexcept {
568  return {y.G0-x.G0, y.D0-x.D0, y.G2-x.G2, y.D2-x.D2,
569  y.FVC-x.FVC, y.ETA-x.ETA, y.Y-x.Y, y.G-x.G, y.DV-x.DV};
570  }
571 
572 
573  static constexpr const char*const bath_broadening = "AIR";
574  static constexpr const char*const self_broadening = "SELF";
575 
576  class Model {
577  private:
579  bool mself;
580  bool mbath;
582  std::vector<SingleSpeciesModel> mdata;
583 
584  bool OK() const noexcept {
585  Index n = mdata.size();
586  Index k = mspecies.nelem();
587  Index m = Index(mself) + Index(mbath);
588  bool needs_any = mtype not_eq Type::DP;
589  if(n not_eq k or m > n or (needs_any and not n))
590  return false;
591  else
592  return true;
593  }
594  public:
595  // No line shape parameters means this is a Doppler line
596  Model() noexcept : mtype(Type::DP), mself(false), mbath(false),
597  mspecies(0), mdata(0) {}
598 
599  // Standard HITRAN means this is a Voigt line (with interp it is lblrtm line mixing)
600  Model(Numeric sgam, Numeric nself, Numeric agam, Numeric nair, Numeric psf,
601  std::array<Numeric, nmaxInterpModels> interp = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) noexcept :
602  mtype(Type::VP), mself(true), mbath(true), mspecies(2), mdata(2) {
603  mdata.front().G0() = {TemperatureModel::T1, sgam, nself, 0};
604  mdata.front().D0() = {TemperatureModel::T5, psf, nair, 0};
605  mdata.front().Interp() = interp;
606 
607  mdata.back(). G0() = {TemperatureModel::T1, agam, nair, 0};
608  mdata.back(). D0() = {TemperatureModel::T5, psf, nair, 0};
609  mdata.back ().Interp() = interp;
610  }
611 
612  Model(const SingleSpeciesModel& bath, Type type) noexcept :
613  mtype(type), mself(false), mbath(true), mspecies(1), mdata(1, bath) {}
614 
615  Model(Type type, bool self, bool bath, const ArrayOfSpeciesTag& species,
616  const std::vector<SingleSpeciesModel>& ssms) :
617  mtype(type), mself(self), mbath(bath), mspecies(species), mdata(ssms) {
618  if(not OK())
619  throw std::runtime_error("Bad initialization with different sizes or bad types, see documentation for valid initializations of LineShape::Model");
620  }
621 
622  // Check if this model has the same species as another model
623  bool same_broadening_species(const Model& other) const noexcept {
624  if(mself not_eq other.mself)
625  return false;
626  else if(mbath not_eq other.mbath)
627  return false;
628  else if(mspecies.nelem() not_eq other.mspecies.nelem())
629  return false;
630  else {
631  for(Index i=Index(mself); i<mspecies.nelem()-Index(mbath); i++)
632  if(mspecies[i].Species() not_eq other.mspecies[i].Species())
633  return false;
634  return true;
635  }
636  }
637 
638  // The VMR vector required based on atmospheric species and self-existence
639  Vector vmrs(const ConstVectorView& atmospheric_vmrs,
640  const ArrayOfArrayOfSpeciesTag& atmospheric_species,
641  const QuantumIdentifier& self) const {
642  if(atmospheric_species.nelem() != atmospheric_vmrs.nelem())
643  throw std::runtime_error("Bad atmospheric inputs");
644 
645  // Initialize list of VMRS to 0
646  Vector line_vmrs(mspecies.nelem(), 0);
647  const Index back = mspecies.nelem()-1; // Last index
648 
649  if(mtype == Type::DP)
650  return line_vmrs;
651 
652  // Loop species ignoring self and bath
653  for(Index i=0; i<mspecies.nelem(); i++) {
654  if(mbath and i == back) {}
655  else {
656  // Select target in-case this is self-broadening
657  const auto target = (mself and i == 0) ?
658  self.Species() :
659  mspecies[i].Species() ;
660 
661  // Find species in list or do nothing at all
662  Index this_species_index = -1;
663  for(Index j=0; j<atmospheric_species.nelem(); j++)
664  if(atmospheric_species[j][0].Species() == target)
665  this_species_index = j;
666 
667  // Set to non-zero in-case species exists
668  if(this_species_index not_eq -1)
669  line_vmrs[i] = atmospheric_vmrs[this_species_index];
670  }
671  }
672 
673  // Renormalize, if bath-species exist this is automatic.
674  if(mbath)
675  line_vmrs[back] = 1.0 - line_vmrs.sum();
676  else
677  line_vmrs /= line_vmrs.sum();
678 
679  // The result must be non-zero, a real number, and finite
680  if(not std::isnormal(line_vmrs.sum()))
681  throw std::runtime_error("Bad VMRs, your atmosphere does not support the line of interest");
682 
683  return line_vmrs;
684  }
685 
686  Index this_species(const Index& self_species) const noexcept {
687  if(mself)
688  return 0;
689  for(Index i=mself; i<nelem()-mbath; i++)
690  if(self_species == mspecies[i].Species())
691  return i;
692  return -1;
693  }
694 
695  Index this_species(const QuantumIdentifier& self) const noexcept {
696  return this_species(self.Species());
697  }
698 
699  // All main calculations
700  #define LSPC(XVAR, PVAR) \
701  Numeric XVAR (Numeric T, Numeric T0, Numeric P [[maybe_unused]], const Vector& vmrs) const noexcept { \
702  return PVAR * std::inner_product(mdata.cbegin(), mdata.cend(), vmrs.begin(), 0.0, \
703  std::plus<Numeric>(), [=](const SingleSpeciesModel& x, Numeric vmr) -> Numeric \
704  {return vmr * x.compute(T, T0, Variable::XVAR);}); \
705  }
706  LSPC(G0, P) LSPC(G2, P) LSPC(D0, P) LSPC(D2, P) LSPC(ETA, 1) LSPC(FVC, P) LSPC(Y, P) LSPC(G, P*P) LSPC(DV, P*P)
707  #undef LSPC
708 
709  // All VMR derivatives
710  #define LSPC(XVAR, PVAR) \
711  Numeric d ## XVAR ## _dVMR (Numeric T, Numeric T0, Numeric P [[maybe_unused]], const Index deriv_pos) const noexcept { \
712  if(deriv_pos not_eq -1) return PVAR * mdata[deriv_pos].compute(T, T0, Variable::XVAR); \
713  else return 0; \
714  }
715  LSPC(G0, P) LSPC(G2, P) LSPC(D0, P) LSPC(D2, P) LSPC(ETA, 1) LSPC(FVC, P) LSPC(Y, P) LSPC(G, P*P) LSPC(DV, P*P)
716  #undef LSPC
717 
718  // All shape model derivatives
719  #define LSPC(XVAR, PVAR) \
720  Numeric d ## XVAR ## _dT (Numeric T, Numeric T0, Numeric P [[maybe_unused]], const Vector& vmrs) const noexcept { \
721  return PVAR * std::inner_product(mdata.cbegin(), mdata.cend(), vmrs.begin(), 0.0, \
722  std::plus<Numeric>(), [=](const SingleSpeciesModel& x, Numeric vmr) -> Numeric \
723  {return vmr * x.compute_dT (T, T0, Variable::XVAR);}); \
724  }
725  LSPC(G0, P) LSPC(G2, P) LSPC(D0, P) LSPC(D2, P) LSPC(ETA, 1) LSPC(FVC, P) LSPC(Y, P) LSPC(G, P*P) LSPC(DV, P*P)
726  #undef LSPC
727 
728  // All shape model derivatives
729  #define LSPDC(XVAR, DERIV, PVAR) \
730  Numeric d ## XVAR ## DERIV (Numeric T, Numeric T0, Numeric P [[maybe_unused]], \
731  Index deriv_pos, const Vector& vmrs) const noexcept { \
732  if(deriv_pos not_eq -1) \
733  return vmrs[deriv_pos] * PVAR * mdata[deriv_pos].compute ## DERIV (T, T0, Variable::XVAR); \
734  else return 0; \
735  }
736  LSPDC(G0, _dT0, P ) LSPDC(G0, _dX0, P ) LSPDC(G0, _dX1, P ) LSPDC(G0, _dX2, P )
737  LSPDC(G2, _dT0, P ) LSPDC(G2, _dX0, P ) LSPDC(G2, _dX1, P ) LSPDC(G2, _dX2, P )
738  LSPDC(D0, _dT0, P ) LSPDC(D0, _dX0, P ) LSPDC(D0, _dX1, P ) LSPDC(D0, _dX2, P )
739  LSPDC(D2, _dT0, P ) LSPDC(D2, _dX0, P ) LSPDC(D2, _dX1, P ) LSPDC(D2, _dX2, P )
740  LSPDC(ETA, _dT0, 1 ) LSPDC(ETA, _dX0, 1 ) LSPDC(ETA, _dX1, 1 ) LSPDC(ETA, _dX2, 1 )
741  LSPDC(FVC, _dT0, P ) LSPDC(FVC, _dX0, P ) LSPDC(FVC, _dX1, P ) LSPDC(FVC, _dX2, P )
742  LSPDC(Y, _dT0, P ) LSPDC(Y, _dX0, P ) LSPDC(Y, _dX1, P ) LSPDC(Y, _dX2, P )
743  LSPDC(G, _dT0, P*P) LSPDC(G, _dX0, P*P) LSPDC(G, _dX1, P*P) LSPDC(G, _dX2, P*P)
744  LSPDC(DV, _dT0, P*P) LSPDC(DV, _dX0, P*P) LSPDC(DV, _dX1, P*P) LSPDC(DV, _dX2, P*P)
745  #undef LSPDC
746 
747  Output GetParams(Numeric T, Numeric T0, Numeric P, const Vector& vmrs) const {
748  return {G0(T, T0, P, vmrs), D0(T, T0, P, vmrs),
749  G2(T, T0, P, vmrs), D2(T, T0, P, vmrs),
750  FVC(T, T0, P, vmrs), ETA(T, T0, P, vmrs),
751  Y(T, T0, P, vmrs), G(T, T0, P, vmrs), DV(T, T0, P, vmrs)};
752  }
753 
755  return {dG0_dT(T, T0, P, vmrs), dD0_dT(T, T0, P, vmrs),
756  dG2_dT(T, T0, P, vmrs), dD2_dT(T, T0, P, vmrs),
757  dFVC_dT(T, T0, P, vmrs), dETA_dT(T, T0, P, vmrs),
758  dY_dT(T, T0, P, vmrs), dG_dT(T, T0, P, vmrs), dDV_dT(T, T0, P, vmrs)};
759  }
760 
761  Output GetVMRDerivs(Numeric T, Numeric T0, Numeric P, const Index pos) const noexcept {
762  return {dG0_dVMR(T, T0, P, pos), dD0_dVMR(T, T0, P, pos),
763  dG2_dVMR(T, T0, P, pos), dD2_dVMR(T, T0, P, pos),
764  dFVC_dVMR(T, T0, P, pos), dETA_dVMR(T, T0, P, pos),
765  dY_dVMR(T, T0, P, pos), dG_dVMR(T, T0, P, pos), dDV_dVMR(T, T0, P, pos)};
766  }
767 
769  if(pos < 0)
770  return 0;
771 
772  #define RETURNINTERNALDERIVATIVE(TYPE) \
773  case JacPropMatType::LineShape ## TYPE ## X0: return d ## TYPE ## _dX0(T, T0, P, pos, vmrs); \
774  case JacPropMatType::LineShape ## TYPE ## X1: return d ## TYPE ## _dX1(T, T0, P, pos, vmrs); \
775  case JacPropMatType::LineShape ## TYPE ## X2: return d ## TYPE ## _dX2(T, T0, P, pos, vmrs)
776  switch(deriv) {
786  default: return 0;
787  }
788  #undef RETURNINTERNALDERIVATIVE
789  }
790 
791  // Size and size manipulation
792  Index nelem() const {return mspecies.nelem();}
793  void resize(Index n) {mspecies.resize(n); mdata.resize(n);}
794  void reserve(Index n) {mspecies.reserve(n); mdata.reserve(n);}
795 
796  friend inline std::istream& operator>>(std::istream& is, Model& m);
797  friend inline std::ostream& operator<<(std::ostream& os, const Model& m);
798  friend std::istream& from_artscat4(std::istream& is, Model& lsc, const QuantumIdentifier& qid);
799  friend std::istream& from_linefunctiondata(std::istream& data, Model& lsc);;
800 
801  Type ModelType() const noexcept {return mtype;}
802  bool Self() const noexcept {return mself;}
803  bool Bath() const noexcept {return mbath;}
804  const std::vector<SingleSpeciesModel>& Data() const noexcept {return mdata;}
805  const ArrayOfSpeciesTag& Species() const noexcept {return mspecies;}
806 
807  std::vector<SingleSpeciesModel>& Data() noexcept {return mdata;}
808 
809  void Set(const ModelParameters& param, const String& spec, const Variable var);
810 
811  ModelParameters Get(const String& spec, const Variable var) const {
812  bool self = spec == self_broadening;
813  bool bath = spec == bath_broadening;
814  if(mself and self)
815  return mdata.front().Get(var);
816  else if(self)
817  throw std::runtime_error("No self species but trying to get self in line shape model");
818  else if(mbath and bath)
819  return mdata.back().Get(var);
820  else if(bath)
821  throw std::runtime_error("No bath species but trying to get bath in line shape model");
822  else {
823  const SpeciesTag sp(spec);
824  for(Index i=Index(mself); i<nelem()-Index(mbath); i++)
825  if(sp.Species() == mspecies[i].Species())
826  return mdata[i].Get(var);
828  os << "No species of type " << spec << " found in line shape model\n";
829  os << "Available species are: " << mspecies << "\n";
830  throw std::runtime_error(os.str());
831  }
832  }
833 
834  void Remove(Index i) {
835  mspecies.erase(mspecies.begin()+i);
836  mdata.erase(mdata.begin()+i);
837  if(i == 0 and mself) mself=false;
838  else if(i == nelem() and mbath) mbath=false;
839  }
840 
842  for(auto& ssm: mdata) {
843  ssm.Y() = x.Y();
844  ssm.G() = x.G();
845  ssm.DV() = x.DV();
846  if(x.Y().type == TemperatureModel::LM_AER or
847  x.G().type == TemperatureModel::LM_AER)
848  ssm.Interp() = x.Interp();
849  }
850  }
851  };
852 
853  std::istream& from_artscat4(std::istream& is, Model& lsc, const QuantumIdentifier& qid);
854  std::istream& from_linefunctiondata(std::istream& data, Model& lsc);
855  std::istream& from_linemixingdata(std::istream& data, Model& lsc);
856  std::istream& from_pressurebroadeningdata(std::istream& data, Model& lsc, const QuantumIdentifier& qid);
857 
858  inline std::ostream& operator<<(std::ostream& os, const Model& m) {
859  os << shapetype2string(m.mtype) << ' ' << m.nelem()
860  << ' ' << m.mself
861  << ' ' << m.mbath;
862  for(Index i=0; i<m.nelem(); i++) {
863  if(m.mself and i==0) os << ' ' << self_broadening;
864  else if(m.mbath and i==m.nelem()-1) os << ' ' << bath_broadening;
865  else os << ' ' << m.mspecies[i].SpeciesNameMain();
866  }
867  for(auto& d: m.mdata) os << ' ' << d;
868  return os;
869  }
870 
871  inline std::istream& operator>>(std::istream& is, Model& m) {
872  String tmp;
873  Index nelem;
874  is >> tmp >> nelem >> m.mself >> m.mbath;
875  m.mtype = string2shapetype(tmp);
876  m.mspecies.resize(nelem);
877  m.mdata.resize(nelem);
878  for(Index i=0; i<m.nelem(); i++) {
879  is >> tmp;
880  if(m.mself and i==0) {}
881  else if(m.mbath and i==m.nelem()-1) {}
882  else m.mspecies[i] = SpeciesTag(tmp);
883  }
884  for(auto& d: m.mdata) is >> d;
885  return is;
886  }
887 
888  // Legacy dealing with reading old LineFunctionData
889  namespace LegacyLineFunctionData {
892  switch(type) {
893  case TemperatureModel::None: return 0;
894  case TemperatureModel::T0: return 1;
895  case TemperatureModel::T1: return 2;
896  case TemperatureModel::T2: return 3;
897  case TemperatureModel::T3: return 2;
898  case TemperatureModel::T4: return 3;
899  case TemperatureModel::T5: return 2;
900  case TemperatureModel::LM_AER: return 12;
901  }
902  std::terminate(); // Not allowed to reach, fix higher level code
903  }
904 
906  inline std::vector<Variable> lineshapetag2variablesvector(String type) {
907  if(type == String("DP")) return {};
908  else if(type == String("LP")) return {Variable::G0, Variable::D0};
909  else if(type == String("VP")) return {Variable::G0, Variable::D0};
910  else if(type == String("SDVP")) return {Variable::G0, Variable::D0, Variable::G2, Variable::D2};
912  else {
914  os << "Type: " << type << ", is not accepted. "
915  << "See documentation for accepted types\n";
916  throw std::runtime_error(os.str());
917  }
918  }
919 
921  inline std::vector<Variable> linemixingtag2variablesvector(String type) {
922  if(type == "#") return {};
923  else if(type == "LM1") return {Variable::Y};
924  else if(type == "LM2") return {Variable::Y, Variable::G, Variable::DV};
925  else if(type == "INT") return {};
926  else if(type == "ConstG") return {Variable::G};
927  else {
929  os << "Type: " << type << ", is not accepted. "
930  << "See documentation for accepted types\n";
931  throw std::runtime_error(os.str());
932  }
933  }
934  };
935 
936  namespace LegacyLineMixingData {
937  enum class TypeLM {
938  LM_NONE, // Reserved for no line mixing
939  LM_LBLRTM, // Reserved for LBLRTM line mixing
940  LM_LBLRTM_O2NonResonant, // Reserved for the non-resonant O2 line in LBLRTM
941  LM_1STORDER, // Reserved for Tretyakov et al. 2005 1st order of line mixing
942  LM_2NDORDER, // Reserved for Makarov et al. 2011 second order of line mixing
943  LM_BYBAND // Reserved for Paris data of relaxation matrix line mixing for band
944  };
945 
947  if(type == "NA") // The standard case
948  return TypeLM::LM_NONE;
949  else if(type == "LL") // The LBLRTM case
950  return TypeLM::LM_LBLRTM;
951  else if(type == "NR") // The LBLRTM O2 non-resonant case
952  return TypeLM::LM_LBLRTM_O2NonResonant;
953  else if(type == "L2") // The 2nd order case
954  return TypeLM::LM_2NDORDER;
955  else if(type == "L1") // The 2nd order case
956  return TypeLM::LM_1STORDER;
957  else if(type == "BB") // The band class
958  return TypeLM::LM_BYBAND;
959  else {
961  os << "Type: " << type << ", is not accepted. "
962  << "See documentation for accepted types\n";
963  throw std::runtime_error(os.str());
964  }
965  }
966 
968  switch(type) {
969  case TypeLM::LM_NONE: // The standard case
970  return 0;
971  case TypeLM::LM_LBLRTM: // The LBLRTM case
972  return 12;
973  case TypeLM::LM_LBLRTM_O2NonResonant: // Nonresonant is just a tag
974  return 1;
975  case TypeLM::LM_2NDORDER: // The 2nd order case
976  return 10;
977  case TypeLM::LM_1STORDER: // The 2nd order case
978  return 3;
979  case TypeLM::LM_BYBAND: // The band class
980  return 1;
981  }
982  std::terminate();
983  }
984 
986  };
987 
988  namespace LegacyPressureBroadeningData {
989  enum class TypePB {
990  PB_NONE, // No pressure broadening
991  PB_AIR_BROADENING, // Air broadening and self broadening only
992  PB_AIR_AND_WATER_BROADENING, // Air, water, and self broadening
993  PB_PLANETARY_BROADENING, // Gas broadening as done for solar system planets
994  // PB_SD_AIR_VOLUME, // HTP in air for SD limit NOT SUPPORTED
995  // PB_HTP_AIR_VOLUME, // HTP in air NOT SUPPORTED
996  // PB_VOIGT_TEST_WATER, // Voigt parameters for testing NOT SUPPORTED
997  // PB_SD_TEST_WATER, // SD parameters for testing NOT SUPPORTED
998  // PB_PURELY_FOR_TESTING // Testing tag for new input structures --- can be changed by anyone... NOT SUPPORTED
999  };
1000 
1002  if(type == "NA") // The none case
1003  return TypePB::PB_NONE;
1004  else if(type == "N2") // Air Broadening is N2 broadening mostly...
1005  return TypePB::PB_AIR_BROADENING;
1006  else if(type == "WA") // Water and Air Broadening
1007  return TypePB::PB_AIR_AND_WATER_BROADENING;
1008  else if(type == "AP") // Planetary broadening
1009  return TypePB::PB_PLANETARY_BROADENING;
1010  else {
1011  std::ostringstream os;
1012  os << "Type: " << type << ", is not accepted. "
1013  << "See documentation for accepted types\n";
1014  throw std::runtime_error(os.str());
1015  }
1016  }
1017 
1019  if(t == TypePB::PB_PLANETARY_BROADENING and
1020  (qid.Species() == SpeciesTag(String("N2")).Species() or
1021  qid.Species() == SpeciesTag(String("O2")).Species() or
1022  qid.Species() == SpeciesTag(String("H2O")).Species() or
1023  qid.Species() == SpeciesTag(String("CO2")).Species() or
1024  qid.Species() == SpeciesTag(String("H2")).Species() or
1025  qid.Species() == SpeciesTag(String("He")).Species()))
1026  return true;
1027  else if(t == TypePB::PB_AIR_AND_WATER_BROADENING and
1028  qid.Species() == SpeciesTag(String("H2O")).Species())
1029  return true;
1030  else
1031  return false;
1032  }
1033 
1035  switch(type) {
1036  case TypePB::PB_NONE:
1037  return 0;
1038  case TypePB::PB_AIR_BROADENING:
1039  return 10;
1040  case TypePB::PB_AIR_AND_WATER_BROADENING:
1041  return 9;
1042  case TypePB::PB_PLANETARY_BROADENING:
1043  return 20;
1044  }
1045  std::terminate();
1046  }
1047 
1049  };
1050 };
1051 
1052 #endif // linefunctiondata_h
Model(Type type, bool self, bool bath, const ArrayOfSpeciesTag &species, const std::vector< SingleSpeciesModel > &ssms)
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
bool same_broadening_species(const Model &other) const noexcept
std::istream & operator>>(std::istream &is, ModelParameters &mp)
Input operator for ModelParameters.
constexpr SingleSpeciesModel(ModelParameters G0={TemperatureModel::None, 0, 0, 0}, ModelParameters D0={TemperatureModel::None, 0, 0, 0}, ModelParameters G2={TemperatureModel::None, 0, 0, 0}, ModelParameters D2={TemperatureModel::None, 0, 0, 0}, ModelParameters FVC={TemperatureModel::None, 0, 0, 0}, ModelParameters ETA={TemperatureModel::None, 0, 0, 0}, ModelParameters Y={TemperatureModel::None, 0, 0, 0}, ModelParameters G={TemperatureModel::None, 0, 0, 0}, ModelParameters DV={TemperatureModel::None, 0, 0, 0}, std::array< Numeric, nmaxInterpModels > interp={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
void var(VectorView var, const Vector &y, const ArrayOfVector &ys, const Index start=0, const Index end=-1)
Compute the variance of the ranged ys.
Definition: raw.cc:49
TemperatureModel string2temperaturemodel(const String &type)
Turns predefined strings into a TemperatureModel type.
LegacyLineMixingData::TypeLM string2typelm(String type)
Line mixing types from string.
Vector vmrs(const ConstVectorView &atmospheric_vmrs, const ArrayOfArrayOfSpeciesTag &atmospheric_species, const QuantumIdentifier &self, const ArrayOfSpeciesTag &lineshape_species, bool self_in_list, bool bath_in_list, Type type)
Returns a VMR vector for this model&#39;s main calculations.
std::istream & from_linefunctiondata(std::istream &data, Model &lsc)
Index typepb2nelem(LegacyPressureBroadeningData::TypePB type)
Pressure broadening types to number of elements.
bool OK() const noexcept
const std::array< ModelParameters, nVars > & Data() const noexcept
#define x2
Index nelem() const
Number of elements.
Definition: array.h:195
void resize(Index n)
QuantumIdentifier::QType Index LowerQuantumNumbers Species
#define x0
Main output of Model.
std::vector< SingleSpeciesModel > & Data() noexcept
Output GetVMRDerivs(Numeric T, Numeric T0, Numeric P, const Index pos) const noexcept
std::vector< Variable > linemixingtag2variablesvector(String type)
Line mixing models.
Index temperaturemodel2legacynelem(TemperatureModel type) noexcept
Length per variable.
ArrayOfSpeciesTag mspecies
std::vector< SingleSpeciesModel > mdata
Routines for setting up the jacobian.
The Vector class.
Definition: matpackI.h:860
Model vector2modellm(Vector x, LegacyLineMixingData::TypeLM type)
LineShape::Model from legacy input vector.
ArrayOfString all_coefficientsLineFunctionData()
{"X0", "X1", "X2"}
Index Species() const
Molecular species index.
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPos &tc)
Red 1D Interpolate.
Constants of physical expressions as constexpr.
Main line shape model class.
void reserve(Index n)
Numeric & SingleModelParameter(ModelParameters &mp, const String &type)
Get a coefficient from ModelParameters by name.
Index typelm2nelem(LegacyLineMixingData::TypeLM type)
Line mixing types to number.
Numeric compute_dT(Numeric T, Numeric T0, Variable var) const noexcept
Numeric special_linemixing_aer(Numeric T, Variable var) const noexcept
#define MODELPARAMCASEGETTER(X)
Model vector2modelpb(Vector x, LegacyPressureBroadeningData::TypePB type, bool self_in_list)
ArrayOfString all_variablesLineFunctionData()
{"G0", "D0", "G2", "D2", "ETA", "FVC", "Y", "G", "DV"}
bool Bath() const noexcept
Numeric compute(Numeric T, Numeric T0, Variable var) const noexcept
constexpr Output negativeOutput(Output x) noexcept
Output turned negative.
G0 G2 FVC Y DV Numeric Numeric Numeric Zeeman LowerQuantumNumbers void * data
Numeric compute_dX0(Numeric T, Numeric T0, Variable var) const noexcept
Numeric GetInternalDeriv(Numeric T, Numeric T0, Numeric P, Index pos, const Vector &vmrs, JacPropMatType deriv) const
const std::vector< SingleSpeciesModel > & Data() const noexcept
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:51
#define RETURNINTERNALDERIVATIVE(TYPE)
#define x1
JacPropMatType
List of Jacobian properties for analytical line shape related derivatives.
Definition: jacobian.h:46
#define LSPDC(XVAR, DERIV, PVAR)
Computations of line shape derived parameters.
bool self_listed(const QuantumIdentifier &qid, LegacyPressureBroadeningData::TypePB t)
Pressure broadening if self exist.
std::istream & from_artscat4(std::istream &is, Model &lsc, const QuantumIdentifier &qid)
Model(const SingleSpeciesModel &bath, Type type) noexcept
constexpr Index nmaxTempModelParams
Current max number of coefficients.
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:53
void Species(Index sp)
Set the Species.
Definition: quantum.h:481
constexpr Index nmaxInterpModels
void Remove(Index i)
A tag group can consist of the sum of several of these.
Variable
List of possible shape variables.
Coefficients and temperature model for SingleSpeciesModel.
#define ACCESS_INTERNAL(VARPOS)
std::ostream & operator<<(std::ostream &os, Variable v)
Output operator for Variable to be human-readable.
void Set(Variable var, const ModelParameters &x) noexcept
LegacyPressureBroadeningData::TypePB string2typepb(String type)
Pressure broadening types from string.
Class to identify and match lines by their quantum numbers.
Definition: quantum.h:390
std::istream & read(std::istream &is)
Output GetTemperatureDerivs(Numeric T, Numeric T0, Numeric P, const Vector &vmrs) const
#define MODELPARAMCASESETTER(X)
void SetLineMixingModel(SingleSpeciesModel x)
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Index this_species(const QuantumIdentifier &self) const noexcept
std::array< ModelParameters, nVars > X
Numeric special_linemixing_aer_dT(Numeric T, Variable var) const noexcept
const ArrayOfSpeciesTag & Species() const noexcept
String shapetype2string(Type type) noexcept
Turns selected Type into a string.
Numeric pow(const Rational base, Numeric exp)
Power of.
Definition: rational.h:628
std::istream & from_linemixingdata(std::istream &data, Model &lsc)
Legacy reading of old deprecated LineMixingData class.
std::array< Numeric, nmaxInterpModels > V
basic_ostringstream< char, string_char_traits< char >, alloc > ostringstream
Definition: sstream.h:204
This can be used to make arrays out of anything.
Definition: array.h:40
String temperaturemodel2string(TemperatureModel type) noexcept
Turns selected TemperatureModel type into a string.
Numeric compute_dX2(Numeric T, Numeric T0, Variable var) const noexcept
Vector vmrs(const ConstVectorView &atmospheric_vmrs, const ArrayOfArrayOfSpeciesTag &atmospheric_species, const QuantumIdentifier &self) const
constexpr Output differenceOutput(Output y, Output x) noexcept
Diff of two output.
Numeric compute_dT0(Numeric T, Numeric T0, Variable var) const noexcept
std::array< ModelParameters, nVars > & Data() noexcept
constexpr Output si2cgs(Output x) noexcept
Output turned from SI to CGS units.
const std::array< Numeric, nmaxInterpModels > & Interp() const noexcept
A constant view of a Vector.
Definition: matpackI.h:476
std::ostream & write(std::ostream &os) const
#define LSPC(XVAR, PVAR)
constexpr Output mirroredOutput(Output x) noexcept
Output to be used by mirroring calls.
Header file for stuff related to absorption species tags.
Index nelem() const
constexpr Numeric freq2kaycm(T x)
Definition: constants.h:387
std::istream & from_pressurebroadeningdata(std::istream &data, Model &lsc, const QuantumIdentifier &qid)
Index nelem(const Lines &l)
Number of lines.
Numeric compute_dX1(Numeric T, Numeric T0, Variable var) const noexcept
TemperatureModel
Temperature models.
#define VARIABLE2STRINGDEF(X)
#define STRING2VARIABLEDEF(X)
JacPropMatType select_derivativeLineShape(const String &var, const String &coeff)
Select the derivative that will be used in Jacobian calculations — also checks validity of var and c...
bool Self() const noexcept
ModelParameters Get(Variable var) const noexcept
Index this_species(const Index &self_species) const noexcept
Compute the line shape parameters for a single broadening species.
Model(Numeric sgam, Numeric nself, Numeric agam, Numeric nair, Numeric psf, std::array< Numeric, nmaxInterpModels > interp={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) noexcept
std::array< Numeric, nmaxInterpModels > & Interp() noexcept
ModelParameters Get(const String &spec, const Variable var) const
Type string2shapetype(const String &type)
Turns predefined strings into a Type.
constexpr Index nVars
Current max number of line shape variables.
String variable2string(Variable type) noexcept
Turns selected Variable type into a string.
Type ModelType() const noexcept
my_basic_string< char > String
The String type for ARTS.
Definition: mystring.h:280
Variable string2variable(const String &type)
Turns predefined strings into a Variable type.
std::vector< Variable > lineshapetag2variablesvector(String type)
Line shape models.