ARTS 2.5.11 (git: 6827797f)
absorptionlines.cc
Go to the documentation of this file.
1
11#include "absorptionlines.h"
12
13#include <algorithm>
14#include <limits>
15#include <numeric>
16#include <ostream>
17#include <string>
18
19#include "absorption.h"
20#include "arts_conversions.h"
21#include "debug.h"
22#include "enums.h"
23#include "file.h"
24#include "hitran_species.h"
25#include "jpl_species.h"
26#include "linescaling.h"
27#include "lineshapemodel.h"
28#include "matpack_math.h"
29#include "quantum_numbers.h"
30#include "rational.h"
31#include "wigner_functions.h"
32
34Absorption::Lines::ShapeParameters(size_t k, Numeric T, Numeric P,
35 const Vector &vmrs) const ARTS_NOEXCEPT {
36 auto &lineshape = lines[k].lineshape;
37
38 using namespace LineShape;
39 return Output{lineshape.G0(T, T0, P, vmrs), lineshape.D0(T, T0, P, vmrs),
40 lineshape.G2(T, T0, P, vmrs), lineshape.D2(T, T0, P, vmrs),
41 lineshape.FVC(T, T0, P, vmrs), lineshape.ETA(T, T0, P, vmrs),
42 lineshape.Y(T, T0, P, vmrs), lineshape.G(T, T0, P, vmrs),
43 lineshape.DV(T, T0, P, vmrs)}
44 .no_linemixing(not DoLineMixing(P));
45}
46
48 Numeric T,
49 Numeric P,
50 size_t pos) const ARTS_NOEXCEPT {
51 auto &lineshape = lines[k].lineshape[pos];
52
53 return lineshape.at(T, T0, P).no_linemixing(not DoLineMixing(P));
54}
55
57 size_t k, Numeric T, Numeric P, const Vector& vmrs) const ARTS_NOEXCEPT {
58 auto &lineshape = lines[k].lineshape;
59
60 using namespace LineShape;
61 return Output{lineshape.dG0dT(T, T0, P, vmrs), lineshape.dD0dT(T, T0, P, vmrs),
62 lineshape.dG2dT(T, T0, P, vmrs), lineshape.dD2dT(T, T0, P, vmrs),
63 lineshape.dFVCdT(T, T0, P, vmrs), lineshape.dETAdT(T, T0, P, vmrs),
64 lineshape.dYdT(T, T0, P, vmrs), lineshape.dGdT(T, T0, P, vmrs),
65 lineshape.dDVdT(T, T0, P, vmrs)}
66 .no_linemixing(not DoLineMixing(P));
67}
68
70 size_t k, Numeric T, Numeric P, size_t pos) const ARTS_NOEXCEPT {
71 auto &lineshape = lines[k].lineshape[pos];
72
73 return lineshape.dT(T, T0, P).no_linemixing(not DoLineMixing(P));
74}
75
77 const Species::Species spec) const ARTS_NOEXCEPT {
78 // Is always first if this is self and self broadening exists
79 if (selfbroadening and spec == quantumidentity.Species()) {
80 return 0;
81 }
82
83 // First and last might be artificial so they should not be checked
84 const Index s = selfbroadening;
85 const Index e = broadeningspecies.nelem() - bathbroadening;
86 for (Index i = s; i < e; i++) {
87 if (spec == broadeningspecies[i]) {
88 return i;
89 }
90 }
91
92 // At this point, the ID is not explicitly among the broadeners, but bath broadening means its VMR still might matter
93 if (bathbroadening) return broadeningspecies.nelem() - 1;
94 return -1;
95}
96
98 size_t k,
99 Numeric T,
100 Numeric P,
101 const QuantumIdentifier& vmr_qid) const ARTS_NOEXCEPT {
102 auto &lineshape = lines[k].lineshape;
103
104 const Index pos = LineShapePos(vmr_qid.Species());
105
106 LineShape::Output out{};
107 if (pos >= 0) {
108 out = lineshape[pos].at(T, T0, P);
109 const Index bath = lineshape.nelem() - 1;
110 if (bathbroadening and pos not_eq bath) {
111 out -= lineshape[bath].at(T, T0, P);
112 }
113 }
114 return out;
115}
116
118 // Default data and values for this type
120 data.selfbroadening = true;
121 data.bathbroadening = true;
122 data.lineshapetype = LineShape::Type::VP;
123 data.species.resize(2);
124
125 // This always contains the rest of the line to parse. At the
126 // beginning the entire line. Line gets shorter and shorter as we
127 // continue to extract stuff from the beginning.
128 String line;
129
130 // Look for more comments?
131 bool comment = true;
132
133 while (comment) {
134 // Return true if eof is reached:
135 if (is.eof()) return data;
136
137 // Throw runtime_error if stream is bad:
138 ARTS_USER_ERROR_IF(!is, "Stream bad.");
139
140 // Read line from file into linebuffer:
141 getline(is, line);
142
143 // It is possible that we were exactly at the end of the file before
144 // calling getline. In that case the previous eof() was still false
145 // because eof() evaluates only to true if one tries to read after the
146 // end of the file. The following check catches this.
147 if (line.nelem() == 0 && is.eof()) return data;
148
149 // @ as first character marks catalogue entry
150 char c;
151 extract(c, line, 1);
152
153 // check for empty line
154 if (c == '@') {
155 comment = false;
156 }
157 }
158
159 // read the arts identifier String
160 istringstream icecream(line);
161
162 String artsid;
163 icecream >> artsid;
164
165 if (artsid.length() != 0) {
166 // Set the species
167 const auto isotopologue = Species::Tag(Species::update_isot_name(artsid));
169 isotopologue.is_joker() or
170 isotopologue.type not_eq Species::TagType::Plain,
171 "A line catalog species can only be of the form \"Plain\", meaning it\nhas the form SPECIES-ISONUM.\n"
172 "Your input contains: ",
173 artsid,
174 ". which we cannot interpret as a plain species")
176 Species::find_species_index(isotopologue.Isotopologue())};
177
178 // Extract center frequency:
179 icecream >> double_imanip() >> data.line.F0;
180
181 Numeric psf;
182 // Extract pressure shift:
183 icecream >> double_imanip() >> psf;
184
185 // Extract intensity:
186 icecream >> double_imanip() >> data.line.I0;
187
188 // Extract reference temperature for Intensity in K:
189 icecream >> double_imanip() >> data.T0;
190
191 // Extract lower state energy:
192 icecream >> double_imanip() >> data.line.E0;
193
194 // Extract air broadening parameters:
195 Numeric agam, sgam;
196 icecream >> double_imanip() >> agam;
197 icecream >> double_imanip() >> sgam;
198
199 // Extract temperature coefficient of broadening parameters:
200 Numeric nair, nself;
201 icecream >> double_imanip() >> nair;
202 icecream >> double_imanip() >> nself;
203
204 // Extract reference temperature for broadening parameter in K:
205 Numeric tgam;
206 icecream >> double_imanip() >> tgam;
207
208 // Extract the aux parameters:
209 Index naux;
210 icecream >> naux;
211
212 // resize the aux array and read it
213 ArrayOfNumeric maux;
214 maux.resize(naux);
215
216 for (Index j = 0; j < naux; j++) {
217 icecream >> double_imanip() >> maux[j];
218 //cout << "maux" << j << " = " << maux[j] << "\n";
219 }
220
221 // Extract accuracies:
222 try {
223 Numeric unused_numeric;
224 icecream >> double_imanip() >> unused_numeric /*mdf*/;
225 icecream >> double_imanip() >> unused_numeric /*mdi0*/;
226 icecream >> double_imanip() >> unused_numeric /*dagam*/;
227 icecream >> double_imanip() >> unused_numeric /*dsgam*/;
228 icecream >> double_imanip() >> unused_numeric /*dnair*/;
229 icecream >> double_imanip() >> unused_numeric /*dnself*/;
230 icecream >> double_imanip() >> unused_numeric /*dpsf*/;
231 } catch (const std::runtime_error&) {
232 }
233
234 // Fix if tgam is different from ti0
235 if (tgam != data.T0) {
236 agam = agam * pow(tgam / data.T0, nair);
237 sgam = sgam * pow(tgam / data.T0, nself);
238 psf = psf * pow(tgam / data.T0, (Numeric).25 + (Numeric)1.5 * nair);
239 }
240
241 // Set line shape computer
242 data.line.lineshape = LineShape::Model(sgam, nself, agam, nair, psf);
243 }
244
245 // That's it!
246 data.bad = false;
247 return data;
248}
249
251 // Default data and values for this type
253 data.selfbroadening = true;
254 data.bathbroadening = false;
255 data.lineshapetype = LineShape::Type::VP;
256
257 // This always contains the rest of the line to parse. At the
258 // beginning the entire line. Line gets shorter and shorter as we
259 // continue to extract stuff from the beginning.
260 String line;
261
262 // Look for more comments?
263 bool comment = true;
264
265 while (comment) {
266 // Return true if eof is reached:
267 if (is.eof()) return data;
268
269 // Throw runtime_error if stream is bad:
270 ARTS_USER_ERROR_IF(!is, "Stream bad.");
271
272 // Read line from file into linebuffer:
273 getline(is, line);
274
275 // It is possible that we were exactly at the end of the file before
276 // calling getline. In that case the previous eof() was still false
277 // because eof() evaluates only to true if one tries to read after the
278 // end of the file. The following check catches this.
279 if (line.nelem() == 0 && is.eof()) return data;
280
281 // @ as first character marks catalogue entry
282 char c;
283 extract(c, line, 1);
284
285 // check for empty line
286 if (c == '@') {
287 comment = false;
288 }
289 }
290
291 // read the arts identifier String
292 istringstream icecream(line);
293
294 String artsid;
295 icecream >> artsid;
296
297 if (artsid.length() != 0) {
298 // Set line ID
299 const auto isotopologue = Species::Tag(Species::update_isot_name(artsid));
301 isotopologue.is_joker() or
302 isotopologue.type not_eq Species::TagType::Plain,
303 "A line catalog species can only be of the form \"Plain\", meaning it\nhas the form SPECIES-ISONUM.\n"
304 "Your input contains: ",
305 artsid,
306 ". which we cannot interpret as a plain species")
308 Species::find_species_index(isotopologue.Isotopologue())};
309
310 // Extract center frequency:
311 icecream >> double_imanip() >> data.line.F0;
312
313 // Extract intensity:
314 icecream >> double_imanip() >> data.line.I0;
315
316 // Extract reference temperature for Intensity in K:
317 icecream >> double_imanip() >> data.T0;
318
319 // Extract lower state energy:
320 icecream >> double_imanip() >> data.line.E0;
321
322 // Extract Einstein A-coefficient:
323 icecream >> double_imanip() >> data.line.A;
324
325 // Extract upper state stat. weight:
326 icecream >> double_imanip() >> data.line.gupp;
327
328 // Extract lower state stat. weight:
329 icecream >> double_imanip() >> data.line.glow;
330
332 data.lineshapetype,
333 data.selfbroadening,
334 data.bathbroadening,
335 data.line.lineshape,
336 data.species,
337 data.quantumidentity);
338 }
339
340 // That's it!
341 data.bad = false;
342 return data;
343}
344
346 // Default data and values for this type
348
349 LineShape::Model line_mixing_model;
350 bool lmd_found = false;
351
352 // This always contains the rest of the line to parse. At the
353 // beginning the entire line. Line gets shorter and shorter as we
354 // continue to extract stuff from the beginning.
355 String line;
356
357 // Look for more comments?
358 bool comment = true;
359
360 while (comment) {
361 // Return true if eof is reached:
362 if (is.eof()) return data;
363
364 // Throw runtime_error if stream is bad:
365 ARTS_USER_ERROR_IF(!is, "Stream bad.");
366
367 // Read line from file into linebuffer:
368 getline(is, line);
369
370 // It is possible that we were exactly at the end of the file before
371 // calling getline. In that case the previous eof() was still false
372 // because eof() evaluates only to true if one tries to read after the
373 // end of the file. The following check catches this.
374 if (line.nelem() == 0 && is.eof()) return data;
375
376 // @ as first character marks catalogue entry
377 char c;
378 extract(c, line, 1);
379
380 // check for empty line
381 if (c == '@') {
382 comment = false;
383 }
384 }
385
386 // read the arts identifier String
387 istringstream icecream(line);
388
389 try {
390 String artsid;
391 icecream >> artsid;
392
393 if (artsid.length() != 0) {
394 // Set line ID:
395 const auto isotopologue = Species::Tag(Species::update_isot_name(artsid));
397 isotopologue.is_joker() or
398 isotopologue.type not_eq Species::TagType::Plain,
399 "A line catalog species can only be of the form \"Plain\", meaning it\nhas the form SPECIES-ISONUM.\n"
400 "Your input contains: ",
401 artsid,
402 ". which we cannot interpret as a plain species")
404 Species::find_species_index(isotopologue.Isotopologue())};
405
406 // Extract center frequency:
407 icecream >> double_imanip() >> data.line.F0;
408
409 // Extract intensity:
410 icecream >> double_imanip() >> data.line.I0;
411
412 // Extract reference temperature for Intensity in K:
413 icecream >> double_imanip() >> data.T0;
414
415 // Extract lower state energy:
416 icecream >> double_imanip() >> data.line.E0;
417
418 // Extract Einstein A-coefficient:
419 icecream >> double_imanip() >> data.line.A;
420
421 // Extract upper state stat. weight:
422 icecream >> double_imanip() >> data.line.gupp;
423
424 // Extract lower state stat. weight:
425 icecream >> double_imanip() >> data.line.glow;
426
427 String token;
428 Index nelem;
429 icecream >> token;
430
431 while (icecream) {
432 // Read pressure broadening (LEGACY)
433 if (token == "PB") {
435 data.lineshapetype,
436 data.selfbroadening,
437 data.bathbroadening,
438 data.line.lineshape,
439 data.species,
440 data.quantumidentity);
441 icecream >> token;
442 } else if (token == "QN") {
443 // Quantum numbers
444
445 icecream >> token;
447 token != "UP", "Unknown quantum number tag: ", token)
448
449 icecream >> token;
450 String r;
451 while (icecream and token not_eq "LO") {
452 auto qn = Quantum::Number::toType(token);
453 icecream >> r;
454 icecream >> token;
455
456 if (good_enum(qn)) {
457 if (data.quantumidentity.val.has(qn)) {
459 val.set(r, true);
460 data.quantumidentity.val.set(val);
461 } else {
462 data.quantumidentity.val.add(qn).set(r, true);
463 }
464 }
465 }
466
468 !is || token != "LO",
469 "Error in catalog. Lower quantum number tag 'LO' not found.")
470
471 icecream >> token;
472 auto qn = Quantum::Number::toType(token);
473 while (icecream and
474 not(token == "LM" or token == "LF" or token == "ZM" or
475 token == "LSM" or token == "PB")) {
476 icecream >> r;
477 icecream >> token;
478
479 if (good_enum(qn)) {
480 if (data.quantumidentity.val.has(qn)) {
482 val.set(r, false);
483 data.quantumidentity.val.set(val);
484 } else {
485 data.quantumidentity.val.add(qn).set(r, false);
486 }
487 }
488
489 qn = Quantum::Number::toType(token);
490 }
491 } else if (token == "LM") {
492 LineShape::from_linemixingdata(icecream, line_mixing_model);
493 icecream >> token;
494 lmd_found = true;
495 } else if (token == "LF") {
497 data.lineshapetype,
498 data.selfbroadening,
499 data.bathbroadening,
500 data.line.lineshape,
501 data.species);
502 // if (data.selfbroadening) data.species[0] = data.quantumidentity.Species();
503 icecream >> token;
504 } else if (token == "ZM") {
505 // Zeeman effect
506 icecream >> data.line.zeeman;
507 icecream >> token;
508 } else if (token == "LSM") {
509 // Line shape modifications
510
511 // Starts with the number of modifications
512 icecream >> nelem;
513 for (Index lsm = 0; lsm < nelem; lsm++) {
514 icecream >> token;
515
516 // cutoff frequency
517 if (token == "CUT") {
518 icecream >> double_imanip() >> data.cutofffreq;
519 data.cutoff = CutoffType::ByLine;
520 }
521
522 // linemixing pressure limit
523 if (token == "LML") {
524 icecream >> double_imanip() >> data.linemixinglimit;
525 }
526
527 // mirroring
528 else if (token == "MTM") {
529 icecream >> data.mirroring;
530 }
531
532 // line normalization
533 else if (token == "LNT") {
534 icecream >> data.normalization;
535 }
536
537 else {
538 ARTS_USER_ERROR("Unknown line modifications given: ", token)
539 }
540 }
541 icecream >> token;
542 } else {
543 ARTS_USER_ERROR("Unknown line data tag in legacy reading routine: ",
544 token)
545 }
546 }
547 }
548 } catch (const std::runtime_error& e) {
549 ARTS_USER_ERROR("Parse error in catalog line: \n", line, '\n', e.what())
550 }
551
552 if (lmd_found)
553 data.line.lineshape.SetLineMixingModel(line_mixing_model.Data()[0]);
554
555 // That's it!
556 data.bad = false;
557 return data;
558}
559
561 istream& is) {
562 // Default data and values for this type
564 data.selfbroadening = true;
565 data.bathbroadening = true;
566 data.lineshapetype = LineShape::Type::VP;
567 data.species.resize(2);
568 data.species[1] = Species::Species::Bath;
569
570 // This contains the rest of the line to parse. At the beginning the
571 // entire line. Line gets shorter and shorter as we continue to
572 // extract stuff from the beginning.
573 String line;
574
575 // The first item is the molecule number:
576 Index mo;
577
578 // Look for more comments?
579 bool comment = true;
580
581 while (comment) {
582 // Return true if eof is reached:
583 if (is.eof()) return data;
584
585 // Throw runtime_error if stream is bad:
586 ARTS_USER_ERROR_IF(!is, "Stream bad.");
587
588 // Read line from file into linebuffer:
589 getline(is, line);
590
591 // It is possible that we were exactly at the end of the file before
592 // calling getline. In that case the previous eof() was still false
593 // because eof() evaluates only to true if one tries to read after the
594 // end of the file. The following check catches this.
595 if (line.nelem() == 0 && is.eof()) return data;
596
597 // If the catalogue is in dos encoding, throw away the
598 // additional carriage return
599 if (line[line.nelem() - 1] == 13) {
600 line.erase(line.nelem() - 1, 1);
601 }
602
603 mo = 0;
604 // Initialization of mo is important, because mo stays the same
605 // if line is empty.
606 extract(mo, line, 2);
607 comment = false;
608 }
609
610 // Extract isotopologue:
611 char iso;
612 extract(iso, line, 1);
613
614 // Set line data
616 data.species[0] = data.quantumidentity.Species();
617
618 // Position.
619 {
620 // HITRAN position in wavenumbers (cm^-1):
621 Numeric v;
622 // Conversion from wavenumber to Hz. If you multiply a line
623 // position in wavenumber (cm^-1) by this constant, you get the
624 // frequency in Hz.
625 constexpr Numeric w2Hz = Constant::c * 100.;
626
627 // Extract HITRAN postion:
628 extract(v, line, 12);
629
630 // ARTS position in Hz:
631 data.line.F0 = v * w2Hz;
632 }
633
634 // Intensity.
635 {
636 // HITRAN intensity is in cm-1/(molec * cm-2) at 296 Kelvin.
637 // It already includes the isotpic ratio.
638 // The first cm-1 is the frequency unit (it cancels with the
639 // 1/frequency unit of the line shape function).
640 //
641 // We need to do the following:
642 // 1. Convert frequency from wavenumber to Hz (factor 1e2 * c).
643 // 2. Convert [molec * cm-2] to [molec * m-2] (factor 1e-4).
644 // 3. Take out the isotopologue ratio.
645
646 constexpr Numeric hi2arts = 1e-2 * Constant::c;
647
648 Numeric s;
649
650 // Extract HITRAN intensity:
651 extract(s, line, 10);
652 // Convert to ARTS units (Hz / (molec * m-2) ), or shorter: Hz*m^2
653 data.line.I0 = s * hi2arts;
654 // Take out isotopologue ratio:
655 data.line.I0 /= Hitran::ratio_from_lookup(mo, iso);
656 }
657
658 // Einstein coefficient
659 { extract(data.line.A, line, 10); }
660
661 // Air broadening parameters.
662 Numeric agam, sgam;
663 {
664 // HITRAN parameter is in cm-1/atm at 296 Kelvin
665 // All parameters are HWHM (I hope this is true!)
666 Numeric gam;
667 // Conversion from wavenumber to Hz. If you multiply a value in
668 // wavenumber (cm^-1) by this constant, you get the value in Hz.
669 constexpr Numeric w2Hz = Constant::c * 1e2;
670 // Ok, put together the end-to-end conversion that we need:
671 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
672
673 // Extract HITRAN AGAM value:
674 extract(gam, line, 5);
675
676 // ARTS parameter in Hz/Pa:
677 agam = gam * hi2arts;
678
679 // Extract HITRAN SGAM value:
680 extract(gam, line, 5);
681
682 // ARTS parameter in Hz/Pa:
683 sgam = gam * hi2arts;
684
685 // If zero, set to agam:
686 if (0 == sgam) sgam = agam;
687
688 // cout << "agam, sgam = " << magam << ", " << msgam << endl;
689 }
690
691 // Lower state energy.
692 {
693 // HITRAN parameter is in wavenumbers (cm^-1).
694 // We have to convert this to the ARTS unit Joule.
695
696 // Extract from Catalogue line
697 extract(data.line.E0, line, 10);
698
699 // Convert to Joule:
700 data.line.E0 = wavenumber_to_joule(data.line.E0);
701 }
702
703 // Temperature coefficient of broadening parameters.
704 Numeric nair, nself;
705 {
706 // This is dimensionless, we can also extract directly.
707 extract(nair, line, 4);
708
709 // Set self broadening temperature coefficient to the same value:
710 nself = nair;
711 // cout << "mnair = " << mnair << endl;
712 }
713
714 // Pressure shift.
715 Numeric psf;
716 {
717 // HITRAN value in cm^-1 / atm. So the conversion goes exactly as
718 // for the broadening parameters.
719 Numeric d;
720 // Conversion from wavenumber to Hz. If you multiply a value in
721 // wavenumber (cm^-1) by this constant, you get the value in Hz.
722 constexpr Numeric w2Hz = Constant::c * 1e2;
723 // Ok, put together the end-to-end conversion that we need:
724 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
725
726 // Extract HITRAN value:
727 extract(d, line, 8);
728
729 // ARTS value in Hz/Pa
730 psf = d * hi2arts;
731 }
732 // Set the accuracies using the definition of HITRAN
733 // indices. If some are missing, they are set to -1.
734
735 // Upper state global quanta
736 {
737 Index eu;
738 extract(eu, line, 15);
739 }
740
741 // Lower state global quanta
742 {
743 Index el;
744 extract(el, line, 15);
745 }
746
747 // Upper state local quanta
748 {
749 Index eul;
750 extract(eul, line, 15);
751 }
752
753 // Lower state local quanta
754 {
755 Index ell;
756 extract(ell, line, 15);
757 }
758
759 // Accuracy index for frequency
760 {
761 Index df;
762 // Extract HITRAN value:
763 extract(df, line, 1);
764 }
765
766 // Accuracy index for intensity
767 {
768 Index di0;
769 // Extract HITRAN value:
770 extract(di0, line, 1);
771 }
772
773 // Accuracy index for air-broadened halfwidth
774 {
775 Index dgam;
776 // Extract HITRAN value:
777 extract(dgam, line, 1);
778 }
779
780 // Accuracy index for self-broadened half-width
781 {
782 Index dgam;
783 // Extract HITRAN value:
784 extract(dgam, line, 1);
785 }
786
787 // Accuracy index for temperature-dependence exponent for agam
788 {
789 Index dn;
790 // Extract HITRAN value:
791 extract(dn, line, 1);
792 }
793
794 // Accuracy index for pressure shift
795 {
796 Index dpsfi;
797 // Extract HITRAN value (given in cm-1):
798 extract(dpsfi, line, 1);
799 }
800
801 // These were all the parameters that we can extract from
802 // HITRAN 2004. However, we still have to set the reference temperatures
803 // to the appropriate value:
804
805 // Reference temperature for Intensity in K.
806 data.T0 = 296.0;
807
808 // Set line shape computer
809 data.line.lineshape = LineShape::hitran_model(sgam, nself, agam, nair, psf);
810 {
811 Index garbage;
812 extract(garbage, line, 13);
813
814 // The statistical weights
815 extract(data.line.gupp, line, 7);
816 extract(data.line.glow, line, 7);
817 }
818
819 // That's it!
820 data.bad = false;
821 return data;
822}
823
825 istream& is) {
826 // Default data and values for this type
828 data.selfbroadening = true;
829 data.bathbroadening = true;
830 data.lineshapetype = LineShape::Type::VP;
831 data.species.resize(2);
832 data.species[1] = Species::Species::Bath;
833
834 // This contains the rest of the line to parse. At the beginning the
835 // entire line. Line gets shorter and shorter as we continue to
836 // extract stuff from the beginning.
837 String line;
838
839 // The first item is the molecule number:
840 Index mo;
841
842 // Look for more comments?
843 bool comment = true;
844
845 while (comment) {
846 // Return true if eof is reached:
847 if (is.eof()) return data;
848
849 // Throw runtime_error if stream is bad:
850 ARTS_USER_ERROR_IF(!is, "Stream bad.");
851
852 // Read line from file into linebuffer:
853 getline(is, line);
854
855 // It is possible that we were exactly at the end of the file before
856 // calling getline. In that case the previous eof() was still false
857 // because eof() evaluates only to true if one tries to read after the
858 // end of the file. The following check catches this.
859 if (line.nelem() == 0 && is.eof()) return data;
860
861 // If the catalogue is in dos encoding, throw away the
862 // additional carriage return
863 if (line[line.nelem() - 1] == 13) {
864 line.erase(line.nelem() - 1, 1);
865 }
866
867 mo = 0;
868 // Initialization of mo is important, because mo stays the same
869 // if line is empty.
870 extract(mo, line, 2);
871 comment = false;
872 }
873
874 // Extract isotopologue:
875 char iso;
876 extract(iso, line, 1);
877
878 // Set line data
880 data.species[0] = data.quantumidentity.Species();
881
882 // Position.
883 {
884 // HITRAN position in wavenumbers (cm^-1):
885 Numeric v;
886 // Conversion from wavenumber to Hz. If you multiply a line
887 // position in wavenumber (cm^-1) by this constant, you get the
888 // frequency in Hz.
889 constexpr Numeric w2Hz = Constant::c * 100.;
890
891 // Extract HITRAN postion:
892 extract(v, line, 12);
893
894 // ARTS position in Hz:
895 data.line.F0 = v * w2Hz;
896 }
897
898 // Intensity.
899 {
900 // HITRAN intensity is in cm-1/(molec * cm-2) at 296 Kelvin.
901 // It already includes the isotpic ratio.
902 // The first cm-1 is the frequency unit (it cancels with the
903 // 1/frequency unit of the line shape function).
904 //
905 // We need to do the following:
906 // 1. Convert frequency from wavenumber to Hz (factor 1e2 * c).
907 // 2. Convert [molec * cm-2] to [molec * m-2] (factor 1e-4).
908 // 3. Take out the isotopologue ratio.
909
910 constexpr Numeric hi2arts = 1e-2 * Constant::c;
911
912 Numeric s;
913
914 // Extract HITRAN intensity:
915 extract(s, line, 10);
916 // Convert to ARTS units (Hz / (molec * m-2) ), or shorter: Hz*m^2
917 data.line.I0 = s * hi2arts;
918 // Take out isotopologue ratio:
919 data.line.I0 /= Hitran::ratio_from_lookup(mo, iso);
920 }
921
922 // Einstein coefficient
923 { extract(data.line.A, line, 10); }
924
925 // Air broadening parameters.
926 Numeric agam, sgam;
927 {
928 // HITRAN parameter is in cm-1/atm at 296 Kelvin
929 // All parameters are HWHM (I hope this is true!)
930 Numeric gam;
931 // Conversion from wavenumber to Hz. If you multiply a value in
932 // wavenumber (cm^-1) by this constant, you get the value in Hz.
933 constexpr Numeric w2Hz = Constant::c * 1e2;
934 // Ok, put together the end-to-end conversion that we need:
935 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
936
937 // Extract HITRAN AGAM value:
938 extract(gam, line, 5);
939
940 // ARTS parameter in Hz/Pa:
941 agam = gam * hi2arts;
942
943 // Extract HITRAN SGAM value:
944 extract(gam, line, 5);
945
946 // ARTS parameter in Hz/Pa:
947 sgam = gam * hi2arts;
948
949 // If zero, set to agam:
950 if (0 == sgam) sgam = agam;
951
952 // cout << "agam, sgam = " << magam << ", " << msgam << endl;
953 }
954
955 // Lower state energy.
956 {
957 // HITRAN parameter is in wavenumbers (cm^-1).
958 // We have to convert this to the ARTS unit Joule.
959
960 // Extract from Catalogue line
961 extract(data.line.E0, line, 10);
962
963 // Convert to Joule:
964 data.line.E0 = wavenumber_to_joule(data.line.E0);
965 }
966
967 // Temperature coefficient of broadening parameters.
968 Numeric nair, nself;
969 {
970 // This is dimensionless, we can also extract directly.
971 extract(nair, line, 4);
972
973 // Set self broadening temperature coefficient to the same value:
974 nself = nair;
975 // cout << "mnair = " << mnair << endl;
976 }
977
978 // Pressure shift.
979 Numeric psf;
980 {
981 // HITRAN value in cm^-1 / atm. So the conversion goes exactly as
982 // for the broadening parameters.
983 Numeric d;
984 // Conversion from wavenumber to Hz. If you multiply a value in
985 // wavenumber (cm^-1) by this constant, you get the value in Hz.
986 constexpr Numeric w2Hz = Constant::c * 1e2;
987 // Ok, put together the end-to-end conversion that we need:
988 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
989
990 // Extract HITRAN value:
991 extract(d, line, 8);
992
993 // ARTS value in Hz/Pa
994 psf = d * hi2arts;
995 }
996 // Set the accuracies using the definition of HITRAN
997 // indices. If some are missing, they are set to -1.
998
999 // Upper state global quanta
1000 {
1001 Index eu;
1002 extract(eu, line, 15);
1003 }
1004
1005 // Lower state global quanta
1006 {
1007 Index el;
1008 extract(el, line, 15);
1009 }
1010
1011 // Upper state local quanta
1012 {
1013 Index eul;
1014 extract(eul, line, 15);
1015 }
1016
1017 // Lower state local quanta
1018 {
1019 Index ell;
1020 extract(ell, line, 15);
1021 }
1022
1023 // Accuracy index for frequency
1024 {
1025 Index df;
1026 // Extract HITRAN value:
1027 extract(df, line, 1);
1028 }
1029
1030 // Accuracy index for intensity
1031 {
1032 Index di0;
1033 // Extract HITRAN value:
1034 extract(di0, line, 1);
1035 }
1036
1037 // Accuracy index for air-broadened halfwidth
1038 {
1039 Index dgam;
1040 // Extract HITRAN value:
1041 extract(dgam, line, 1);
1042 }
1043
1044 // Accuracy index for self-broadened half-width
1045 {
1046 Index dgam;
1047 // Extract HITRAN value:
1048 extract(dgam, line, 1);
1049 }
1050
1051 // Accuracy index for temperature-dependence exponent for agam
1052 {
1053 Index dn;
1054 // Extract HITRAN value:
1055 extract(dn, line, 1);
1056 }
1057
1058 // Accuracy index for pressure shift
1059 {
1060 Index dpsfi;
1061 // Extract HITRAN value (given in cm-1):
1062 extract(dpsfi, line, 1);
1063 }
1064
1065 // These were all the parameters that we can extract from
1066 // HITRAN 2004. However, we still have to set the reference temperatures
1067 // to the appropriate value:
1068
1069 // Reference temperature for Intensity in K.
1070 data.T0 = 296.0;
1071
1072 // Set line shape computer
1073 data.line.lineshape = LineShape::hitran_model(sgam, nself, agam, nair, psf);
1074 {
1075 Index garbage;
1076 extract(garbage, line, 13);
1077
1078 // The statistical weights
1079 extract(data.line.gupp, line, 7);
1080 extract(data.line.glow, line, 7);
1081 }
1082
1083 // ADD QUANTUM NUMBER PARSING HERE!
1084 String upper, lower;
1085 std::stringstream ss;
1086 ss.str(line);
1087 ss >> upper >> lower;
1089
1090 // That's it!
1091 data.bad = false;
1092 return data;
1093}
1094
1096 istream& is) {
1097 // Default data and values for this type
1098 SingleLineExternal data;
1099 data.selfbroadening = true;
1100 data.bathbroadening = true;
1101 data.lineshapetype = LineShape::Type::VP;
1102 data.species.resize(2);
1103 data.species[1] = Species::Species::Bath;
1104
1105 // This contains the rest of the line to parse. At the beginning the
1106 // entire line. Line gets shorter and shorter as we continue to
1107 // extract stuff from the beginning.
1108 String line;
1109
1110 // The first item is the molecule number:
1111 Index mo;
1112
1113 // Look for more comments?
1114 bool comment = true;
1115
1116 while (comment) {
1117 // Return true if eof is reached:
1118 if (is.eof()) return data;
1119
1120 // Throw runtime_error if stream is bad:
1121 ARTS_USER_ERROR_IF(!is, "Stream bad.");
1122
1123 // Read line from file into linebuffer:
1124 getline(is, line);
1125
1126 // It is possible that we were exactly at the end of the file before
1127 // calling getline. In that case the previous eof() was still false
1128 // because eof() evaluates only to true if one tries to read after the
1129 // end of the file. The following check catches this.
1130 if (line.nelem() == 0 && is.eof()) return data;
1131
1132 // If the catalogue is in dos encoding, throw away the
1133 // additional carriage return
1134 if (line[line.nelem() - 1] == 13) {
1135 line.erase(line.nelem() - 1, 1);
1136 }
1137
1138 mo = 0;
1139 // Initialization of mo is important, because mo stays the same
1140 // if line is empty.
1141 extract(mo, line, 2);
1142 comment = false;
1143 }
1144
1145 // Extract isotopologue:
1146 char iso;
1147 extract(iso, line, 1);
1148
1149 // Set line data
1151 data.species[0] = data.quantumidentity.Species();
1152
1153 // Position.
1154 {
1155 // HITRAN position in wavenumbers (cm^-1):
1156 Numeric v;
1157 // Conversion from wavenumber to Hz. If you multiply a line
1158 // position in wavenumber (cm^-1) by this constant, you get the
1159 // frequency in Hz.
1160 constexpr Numeric w2Hz = Constant::c * 100.;
1161
1162 // Extract HITRAN postion:
1163 extract(v, line, 12);
1164
1165 // ARTS position in Hz:
1166 data.line.F0 = v * w2Hz;
1167 // cout << "mf = " << mf << endl;
1168 }
1169
1170 // Intensity.
1171 {
1172 // HITRAN intensity is in cm-1/(molec * cm-2) at 296 Kelvin.
1173 // It already includes the isotpic ratio.
1174 // The first cm-1 is the frequency unit (it cancels with the
1175 // 1/frequency unit of the line shape function).
1176 //
1177 // We need to do the following:
1178 // 1. Convert frequency from wavenumber to Hz (factor 1e2 * c).
1179 // 2. Convert [molec * cm-2] to [molec * m-2] (factor 1e-4).
1180 // 3. Take out the isotopologue ratio.
1181
1182 constexpr Numeric hi2arts = 1e-2 * Constant::c;
1183
1184 Numeric s;
1185
1186 // Extract HITRAN intensity:
1187 extract(s, line, 10);
1188 // Convert to ARTS units (Hz / (molec * m-2) ), or shorter: Hz*m^2
1189 data.line.I0 = s * hi2arts;
1190 // Take out isotopologue ratio:
1191 data.line.I0 /= Hitran::ratio_from_lookup(mo, iso);
1192 }
1193
1194 // Skip transition probability:
1195 {
1196 Numeric r;
1197 extract(r, line, 10);
1198 }
1199
1200 // Air broadening parameters.
1201 Numeric agam, sgam;
1202 {
1203 // HITRAN parameter is in cm-1/atm at 296 Kelvin
1204 // All parameters are HWHM (I hope this is true!)
1205 Numeric gam;
1206 // Conversion from wavenumber to Hz. If you multiply a value in
1207 // wavenumber (cm^-1) by this constant, you get the value in Hz.
1208 constexpr Numeric w2Hz = Constant::c * 1e2;
1209 // Ok, put together the end-to-end conversion that we need:
1210 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
1211
1212 // Extract HITRAN AGAM value:
1213 extract(gam, line, 5);
1214
1215 // ARTS parameter in Hz/Pa:
1216 agam = gam * hi2arts;
1217
1218 // Extract HITRAN SGAM value:
1219 extract(gam, line, 5);
1220
1221 // ARTS parameter in Hz/Pa:
1222 sgam = gam * hi2arts;
1223
1224 // If zero, set to agam:
1225 if (0 == sgam) sgam = agam;
1226
1227 // cout << "agam, sgam = " << magam << ", " << msgam << endl;
1228 }
1229
1230 // Lower state energy.
1231 {
1232 // HITRAN parameter is in wavenumbers (cm^-1).
1233 // We have to convert this to the ARTS unit Joule.
1234
1235 // Extract from Catalogue line
1236 extract(data.line.E0, line, 10);
1237
1238 // Convert to Joule:
1239 data.line.E0 = wavenumber_to_joule(data.line.E0);
1240 }
1241
1242 // Temperature coefficient of broadening parameters.
1243 Numeric nair, nself;
1244 {
1245 // This is dimensionless, we can also extract directly.
1246 extract(nair, line, 4);
1247
1248 // Set self broadening temperature coefficient to the same value:
1249 nself = nair;
1250 // cout << "mnair = " << mnair << endl;
1251 }
1252
1253 // Pressure shift.
1254 Numeric psf;
1255 {
1256 // HITRAN value in cm^-1 / atm. So the conversion goes exactly as
1257 // for the broadening parameters.
1258 Numeric d;
1259 // Conversion from wavenumber to Hz. If you multiply a value in
1260 // wavenumber (cm^-1) by this constant, you get the value in Hz.
1261 constexpr Numeric w2Hz = Constant::c * 1e2;
1262 // Ok, put together the end-to-end conversion that we need:
1263 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
1264
1265 // Extract HITRAN value:
1266 extract(d, line, 8);
1267
1268 // ARTS value in Hz/Pa
1269 psf = d * hi2arts;
1270 }
1271 // Set the accuracies using the definition of HITRAN
1272 // indices. If some are missing, they are set to -1.
1273
1274 //Skip upper state global quanta index
1275 {
1276 Index eu;
1277 extract(eu, line, 3);
1278 }
1279
1280 //Skip lower state global quanta index
1281 {
1282 Index el;
1283 extract(el, line, 3);
1284 }
1285
1286 //Skip upper state local quanta
1287 {
1288 Index eul;
1289 extract(eul, line, 9);
1290 }
1291
1292 //Skip lower state local quanta
1293 {
1294 Index ell;
1295 extract(ell, line, 9);
1296 }
1297
1298 // Accuracy index for frequency reference
1299 {
1300 Index df;
1301 // Extract HITRAN value:
1302 extract(df, line, 1);
1303 }
1304
1305 // Accuracy index for intensity reference
1306 {
1307 Index di0;
1308 // Extract HITRAN value:
1309 extract(di0, line, 1);
1310 }
1311
1312 // Accuracy index for halfwidth reference
1313 {
1314 Index dgam;
1315 // Extract HITRAN value:
1316 extract(dgam, line, 1);
1317 }
1318
1319 // These were all the parameters that we can extract from
1320 // HITRAN. However, we still have to set the reference temperatures
1321 // to the appropriate value:
1322
1323 // Reference temperature for Intensity in K.
1324 data.T0 = 296.0;
1325
1326 // Set line shape computer
1327 data.line.lineshape = LineShape::hitran_model(sgam, nself, agam, nair, psf);
1328
1329 // That's it!
1330 data.bad = false;
1331 return data;
1332}
1333
1335 // Default data and values for this type
1336 SingleLineExternal data;
1337 data.selfbroadening = true;
1338 data.bathbroadening = true;
1339 data.lineshapetype = LineShape::Type::VP;
1340 data.species.resize(2);
1341
1342 // This contains the rest of the line to parse. At the beginning the
1343 // entire line. Line gets shorter and shorter as we continue to
1344 // extract stuff from the beginning.
1345 String line;
1346
1347 // The first item is the molecule number:
1348 Index mo;
1349
1350 // Look for more comments?
1351 bool comment = true;
1352
1353 while (comment) {
1354 // Return true if eof is reached:
1355 if (is.eof()) return data;
1356
1357 // Throw runtime_error if stream is bad:
1358 ARTS_USER_ERROR_IF(!is, "Stream bad.");
1359
1360 // Read line from file into linebuffer:
1361 getline(is, line);
1362 if (line[0] == '>' or line[0] == '%') continue;
1363
1364 // It is possible that we were exactly at the end of the file before
1365 // calling getline. In that case the previous eof() was still false
1366 // because eof() evaluates only to true if one tries to read after the
1367 // end of the file. The following check catches this.
1368 if (line.nelem() == 0 && is.eof()) return data;
1369
1370 // If the catalogue is in dos encoding, throw away the
1371 // additional carriage return
1372 if (line[line.nelem() - 1] == 13) {
1373 line.erase(line.nelem() - 1, 1);
1374 }
1375
1376 mo = 0;
1377 // Initialization of mo is important, because mo stays the same
1378 // if line is empty.
1379 extract(mo, line, 2);
1380 comment = false;
1381 }
1382
1383 // Extract isotopologue:
1384 char iso;
1385 extract(iso, line, 1);
1386
1387 // Set line data
1389
1390 // Position.
1391 {
1392 // HITRAN position in wavenumbers (cm^-1):
1393 Numeric v;
1394 // Conversion from wavenumber to Hz. If you multiply a line
1395 // position in wavenumber (cm^-1) by this constant, you get the
1396 // frequency in Hz.
1397 constexpr Numeric w2Hz = Constant::c * 100.;
1398
1399 // Extract HITRAN postion:
1400 extract(v, line, 12);
1401
1402 // ARTS position in Hz:
1403 data.line.F0 = v * w2Hz;
1404 // cout << "mf = " << mf << endl;
1405 }
1406
1407 // Intensity.
1408 {
1409 // HITRAN intensity is in cm-1/(molec * cm-2) at 296 Kelvin.
1410 // It already includes the isotpic ratio.
1411 // The first cm-1 is the frequency unit (it cancels with the
1412 // 1/frequency unit of the line shape function).
1413 //
1414 // We need to do the following:
1415 // 1. Convert frequency from wavenumber to Hz (factor 1e2 * c).
1416 // 2. Convert [molec * cm-2] to [molec * m-2] (factor 1e-4).
1417 // 3. Take out the isotopologue ratio.
1418
1419 constexpr Numeric hi2arts = 1e-2 * Constant::c;
1420
1421 Numeric s;
1422 if (line[6] == 'D') line[6] = 'E';
1423 // Extract HITRAN intensity:
1424 extract(s,
1425 line,
1426 10); // NOTE: If error shooting, FORTRAN "D" is not read properly.
1427 // Convert to ARTS units (Hz / (molec * m-2) ), or shorter: Hz*m^2
1428 data.line.I0 = s * hi2arts;
1429 // Take out isotopologue ratio:
1430 data.line.I0 /= Hitran::ratio_from_lookup(mo, iso);
1431 }
1432
1433 // Skip transition probability:
1434 {
1435 Numeric r;
1436 extract(r, line, 10);
1437 }
1438
1439 // Air broadening parameters.
1440 Numeric sgam, agam;
1441 {
1442 // HITRAN parameter is in cm-1/atm at 296 Kelvin
1443 // All parameters are HWHM (I hope this is true!)
1444 Numeric gam;
1445 // Conversion from wavenumber to Hz. If you multiply a value in
1446 // wavenumber (cm^-1) by this constant, you get the value in Hz.
1447 constexpr Numeric w2Hz = Constant::c * 1e2;
1448 // Ok, put together the end-to-end conversion that we need:
1449 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
1450
1451 // Extract HITRAN AGAM value:
1452 extract(gam, line, 5);
1453
1454 // ARTS parameter in Hz/Pa:
1455 agam = gam * hi2arts;
1456
1457 // Extract HITRAN SGAM value:
1458 extract(gam, line, 5);
1459
1460 // ARTS parameter in Hz/Pa:
1461 sgam = gam * hi2arts;
1462
1463 // If zero, set to agam:
1464 if (0 == sgam) sgam = agam;
1465
1466 // cout << "agam, sgam = " << magam << ", " << msgam << endl;
1467 }
1468
1469 // Lower state energy.
1470 {
1471 // HITRAN parameter is in wavenumbers (cm^-1).
1472 // We have to convert this to the ARTS unit Joule.
1473
1474 // Extract from Catalogue line
1475 extract(data.line.E0, line, 10);
1476
1477 // Convert to Joule:
1478 data.line.E0 = wavenumber_to_joule(data.line.E0);
1479 }
1480
1481 // Temperature coefficient of broadening parameters.
1482 Numeric nair, nself;
1483 {
1484 // This is dimensionless, we can also extract directly.
1485 extract(nair, line, 4);
1486
1487 // Set self broadening temperature coefficient to the same value:
1488 nself = nair;
1489 // cout << "mnair = " << mnair << endl;
1490 }
1491
1492 // Pressure shift.
1493 Numeric psf;
1494 {
1495 // HITRAN value in cm^-1 / atm. So the conversion goes exactly as
1496 // for the broadening parameters.
1497 Numeric d;
1498 // Conversion from wavenumber to Hz. If you multiply a value in
1499 // wavenumber (cm^-1) by this constant, you get the value in Hz.
1500 constexpr Numeric w2Hz = Constant::c * 1e2;
1501 // Ok, put together the end-to-end conversion that we need:
1502 constexpr Numeric hi2arts = w2Hz / Conversion::atm2pa(1);
1503
1504 // Extract HITRAN value:
1505 extract(d, line, 8);
1506
1507 // ARTS value in Hz/Pa
1508 psf = d * hi2arts;
1509 }
1510 // Set the accuracies using the definition of HITRAN
1511 // indices. If some are missing, they are set to -1.
1512
1513 //Skip upper state global quanta index
1514 {
1515 Index eu;
1516 extract(eu, line, 3);
1517 }
1518
1519 //Skip lower state global quanta index
1520 {
1521 Index el;
1522 extract(el, line, 3);
1523 }
1524
1525 //Skip upper state local quanta
1526 {
1527 Index eul;
1528 extract(eul, line, 9);
1529 }
1530
1531 //Skip lower state local quanta
1532 {
1533 Index ell;
1534 extract(ell, line, 9);
1535 }
1536
1537 // Accuracy index for frequency reference
1538 {
1539 Index df;
1540 // Extract HITRAN value:
1541 extract(df, line, 1);
1542 }
1543
1544 // Accuracy index for intensity reference
1545 {
1546 Index di0;
1547 // Extract HITRAN value:
1548 extract(di0, line, 1);
1549 }
1550
1551 // Accuracy index for halfwidth reference
1552 {
1553 Index dgam;
1554 // Extract HITRAN value:
1555 extract(dgam, line, 1);
1556 }
1557
1558 // These were all the parameters that we can extract from
1559 // HITRAN. However, we still have to set the reference temperatures
1560 // to the appropriate value:
1561
1562 // Reference temperature for Intensity in K.
1563 // (This is fix for HITRAN)
1564 data.T0 = 296.0;
1565
1566 // Skip four
1567 {
1568 Index four;
1569 extract(four, line, 4);
1570 }
1571
1572 // This is the test for the last two characters of the line
1573 {
1574 /*
1575 * 0 is nothing,
1576 * -1 is linemixing on the next line,
1577 * -3 is the non-resonant line
1578 */
1579 Index test;
1580 extract(test, line, 2);
1581 //If the tag is as it should be, then a minus one means that more should be read
1582 if (test == -1 || test == -3)
1583 getline(is, line);
1584 else // the line is done and we are happy to leave
1585 {
1586 data.line.lineshape =
1587 LineShape::hitran_model(sgam, nself, agam, nair, psf);
1588
1589 data.bad = false;
1590 return data;
1591 }
1592 }
1593
1594 // In case we are unable to leave, the next line is a line mixing parameter line
1595
1596 // First is the molecular number. This should be the same as above.
1597 {
1598 Index mo2;
1599 extract(mo2, line, 2);
1600 // Skip one
1601
1602 ARTS_USER_ERROR_IF(mo != mo2, "There is an error in the line mixing\n");
1603 }
1604
1605 Vector Y(4), G(4), T(4);
1606
1607 // These are constants for AER but should be included because we need their grid.
1608 T[0] = 200;
1609 T[1] = 250;
1610 T[2] = 296;
1611 T[3] = 340;
1612
1613 // Next is the Y and G at various temperatures
1614 {
1615 Numeric Y_200K;
1616 extract(Y_200K, line, 13);
1617 Y[0] = Y_200K;
1618 }
1619 {
1620 Numeric G_200K;
1621 extract(G_200K, line, 11);
1622 G[0] = G_200K;
1623 }
1624 {
1625 Numeric Y_250K;
1626 extract(Y_250K, line, 13);
1627 Y[1] = Y_250K;
1628 }
1629 {
1630 Numeric G_250K;
1631 extract(G_250K, line, 11);
1632 G[1] = G_250K;
1633 }
1634 {
1635 Numeric Y_296K;
1636 extract(Y_296K, line, 13);
1637 Y[2] = Y_296K;
1638 }
1639 {
1640 Numeric G_296K;
1641 extract(G_296K, line, 11);
1642 G[2] = G_296K;
1643 }
1644 {
1645 Numeric Y_340K;
1646 extract(Y_340K, line, 13);
1647 Y[3] = Y_340K;
1648 }
1649 {
1650 Numeric G_340K;
1651 extract(G_340K, line, 11);
1652 G[3] = G_340K;
1653 }
1654
1655 // Cpnvert from per Atm and per Atm^2
1656 Y /= Conversion::atm2pa(1);
1658
1659 // ARTS uses (1-iY) as line-mixing factor, LBLRTM uses (1+iY), so we must change sign
1660 Y *= -1;
1661
1662 // Test that this is the end
1663 {
1664 Index test;
1665 extract(test, line, 2);
1666 if (test == -1) {
1668 nself,
1669 agam,
1670 nair,
1671 psf,
1672 {T[0],
1673 T[1],
1674 T[2],
1675 T[3],
1676 Y[0],
1677 Y[1],
1678 Y[2],
1679 Y[3],
1680 G[0],
1681 G[1],
1682 G[2],
1683 G[3]});
1684
1685 data.bad = false;
1686 return data;
1687 }
1688 if (test == -3) {
1690 nself,
1691 agam,
1692 nair,
1693 psf,
1694 {T[0],
1695 T[1],
1696 T[2],
1697 T[3],
1698 Y[0],
1699 Y[1],
1700 Y[2],
1701 Y[3],
1702 G[0],
1703 G[1],
1704 G[2],
1705 G[3]});
1706
1707 data.bad = false;
1708 return data;
1709 }
1710 return data;
1711 }
1712}
1713
1714std::vector<Absorption::Lines> Absorption::split_list_of_external_lines(
1715 std::vector<SingleLineExternal>& external_lines,
1716 const std::vector<QuantumNumberType>& localquantas,
1717 const std::vector<QuantumNumberType>& globalquantas) {
1718 std::vector<Lines> lines(0);
1719
1720 // Loop but make copies because we will need to modify some of the data
1721 while (external_lines.size()) {
1722 auto& sle = external_lines.back();
1723
1724 // Adapt broadening to fit with line catalog
1725 if (sle.selfbroadening) sle.species.front() = sle.quantumidentity.Species();
1726 if (sle.bathbroadening) sle.species.back() = Species::Species::Bath;
1727
1729 sle.quantumidentity.isotopologue_index};
1730 for (auto qn : globalquantas)
1731 if (sle.quantumidentity.val.has(qn))
1732 global_id.val.set(sle.quantumidentity.val[qn]);
1733
1734 Quantum::Number::LocalState local_id{};
1735 for (auto qn : localquantas)
1736 if (sle.quantumidentity.val.has(qn))
1737 local_id.val.set(sle.quantumidentity.val[qn]);
1738
1739 // Set the line
1740 auto line = sle.line;
1741 line.localquanta = local_id;
1742
1743 // Either find a line like this in the list of lines or start a new Lines
1744 auto band = std::find_if(lines.begin(), lines.end(), [&](const Lines& li) {
1745 return li.MatchWithExternal(sle, global_id);
1746 });
1747 if (band not_eq lines.end()) {
1748 band->AppendSingleLine(line);
1749 } else {
1750 lines.push_back(Lines(sle.selfbroadening,
1751 sle.bathbroadening,
1752 sle.cutoff,
1753 sle.mirroring,
1754 sle.population,
1755 sle.normalization,
1756 sle.lineshapetype,
1757 sle.T0,
1758 sle.cutofffreq,
1759 sle.linemixinglimit,
1760 global_id,
1761 sle.species,
1762 {line}));
1763 }
1764 external_lines.pop_back();
1765 }
1766
1767 return lines;
1768}
1769
1770namespace Absorption {
1771std::ostream& operator<<(std::ostream& os, const Absorption::Lines& lines) {
1772 for (auto& line : lines.lines) os << line << '\n';
1773 return os;
1774}
1775
1776std::istream& operator>>(std::istream& is, Lines& lines) {
1777 for (auto& line : lines.lines) is >> line;
1778 return is;
1779}
1780
1781std::ostream& operator<<(std::ostream& os, const Absorption::SingleLine& line) {
1782 os << line.F0 << ' ' << line.I0 << ' ' << line.E0 << ' ' << line.glow << ' '
1783 << line.gupp << ' ' << line.A << ' ' << line.zeeman << ' '
1784 << line.lineshape;
1785 if (line.localquanta.val.nelem()) os << ' ' << line.localquanta.values();
1786 return os;
1787}
1788
1789std::istream& operator>>(std::istream& is, Absorption::SingleLine& line) {
1790 is >> double_imanip() >> line.F0 >> line.I0 >> line.E0 >> line.glow >>
1791 line.gupp >> line.A;
1792 return is >> line.zeeman >> line.lineshape >> line.localquanta;
1793}
1794} // namespace Absorption
1795
1798}
1799
1801 std::ostringstream os;
1802
1803 os << "\nLines meta-data:\n";
1804 os << '\t' << "Species identity:\n";
1805 os << "\t\tSpecies: " << SpeciesName() << '\n';
1806 os << "\t\tIdentity: " << quantumidentity << '\n';
1807 os << '\t' << cutofftype2metadatastring(cutoff, cutofffreq);
1808 os << '\t' << populationtype2metadatastring(population);
1809 os << '\t' << normalizationtype2metadatastring(normalization);
1810 os << '\t' << LineShape::shapetype2metadatastring(lineshapetype);
1811 os << '\t' << mirroringtype2metadatastring(mirroring);
1812 os << '\t' << "The reference temperature for all line parameters is " << T0
1813 << " K.\n";
1814 if (linemixinglimit < 0)
1815 os << '\t' << "If applicable, there is no line mixing limit.\n";
1816 else
1817 os << '\t' << "If applicable, there is a line mixing limit at "
1818 << linemixinglimit << " Pa.\n";
1819
1820 if (not NumLines()) {
1821 os << "\tNo line data is available.\n";
1822 } else {
1823 os << "\tThere are " << NumLines() << " lines available.\n";
1824
1825 auto& line = lines.front();
1826 os << "\tThe front line has:\n";
1827 os << "\t\t"
1828 << "f0: " << line.F0 << " Hz\n";
1829 os << "\t\t"
1830 << "i0: " << line.I0 << " m^2/Hz\n";
1831 os << "\t\t"
1832 << "e0: " << line.E0 << " J\n";
1833 os << "\t\t"
1834 << "Lower stat. weight: " << line.glow << " [-]\n";
1835 os << "\t\t"
1836 << "Upper stat. weight: " << line.gupp << " [-]\n";
1837 os << "\t\t"
1838 << "A: " << line.A << " 1/s\n";
1839 os << "\t\t"
1840 << "Zeeman splitting of lower state: " << line.zeeman.gl() << " [-]\n";
1841 os << "\t\t"
1842 << "Zeeman splitting of upper state: " << line.zeeman.gu() << " [-]\n";
1843 os << "\t\t"
1844 << "Local quantum numbers: " << line.localquanta.val << "\n";
1845
1847 line.lineshape, selfbroadening, broadeningspecies, T0);
1848 os << "\t\t"
1849 << "Line shape parameters (are normalized by sum(VMR)):\n";
1850 for (auto& ls_form : ls_meta) os << "\t\t\t" << ls_form << "\n";
1851 }
1852
1853 return os.str();
1854}
1855
1856void Absorption::Lines::RemoveLine(Index i) noexcept {
1857 lines.erase(lines.begin() + i);
1858}
1859
1861 auto line = lines[i];
1862 RemoveLine(i);
1863 return line;
1864}
1865
1867 std::reverse(lines.begin(), lines.end());
1868}
1869
1870Numeric Absorption::Lines::SpeciesMass() const noexcept {
1871 return quantumidentity.Isotopologue().mass;
1872}
1873
1875 const ConstVectorView& atm_vmrs,
1876 const ArrayOfArrayOfSpeciesTag& atm_spec) const {
1877 return LineShape::vmrs(atm_vmrs, atm_spec, broadeningspecies);
1878}
1879
1881 const ConstVectorView& atm_vmrs,
1882 const ArrayOfArrayOfSpeciesTag& atm_spec,
1883 const SpeciesIsotopologueRatios& ir,
1884 const Numeric& bath_mass) const {
1885 Vector mass = LineShape::mass(atm_vmrs, atm_spec, broadeningspecies, ir);
1886 if (bathbroadening and bath_mass > 0) mass[mass.nelem() - 1] = bath_mass;
1887 return mass;
1888}
1889
1891 const ConstVectorView& atm_vmrs,
1892 const ArrayOfArrayOfSpeciesTag& atm_spec) const {
1893 ARTS_USER_ERROR_IF(atm_vmrs.nelem() not_eq atm_spec.nelem(),
1894 "Bad species and vmr lists");
1895
1896 for (Index i = 0; i < atm_spec.nelem(); i++)
1897 if (atm_spec[i].nelem() and atm_spec[i].Species() == Species())
1898 return atm_vmrs[i];
1899 return 0;
1900}
1901
1903 Rational Jf, Rational Ji, Rational lf, Rational li, Rational k) {
1904 if (not iseven(Jf + lf + 1))
1905 return -sqrt(2 * Jf + 1) * wigner3j(Jf, k, Ji, li, lf - li, -lf);
1906 return +sqrt(2 * Jf + 1) * wigner3j(Jf, k, Ji, li, lf - li, -lf);
1907}
1908
1910 Rational Ji,
1911 Rational N) {
1912 if (not iseven(Jf + N))
1913 return -sqrt(6 * (2 * Jf + 1) * (2 * Ji + 1)) *
1914 wigner6j(1, 1, 1, Ji, Jf, N);
1915 return +sqrt(6 * (2 * Jf + 1) * (2 * Ji + 1)) * wigner6j(1, 1, 1, Ji, Jf, N);
1916}
1917
1919 // Default data and values for this type
1920 SingleLineExternal data;
1921 data.selfbroadening = true;
1922 data.bathbroadening = true;
1923 data.lineshapetype = LineShape::Type::VP;
1924 data.species.resize(2);
1925
1926 // This contains the rest of the line to parse. At the beginning the
1927 // entire line. Line gets shorter and shorter as we continue to
1928 // extract stuff from the beginning.
1929 String line;
1930
1931 // Look for more comments?
1932 bool comment = true;
1933
1934 while (comment) {
1935 // Return true if eof is reached:
1936 if (is.eof()) return data;
1937
1938 // Throw runtime_error if stream is bad:
1939 ARTS_USER_ERROR_IF(!is, "Stream bad.");
1940
1941 // Read line from file into linebuffer:
1942 getline(is, line);
1943
1944 // It is possible that we were exactly at the end of the file before
1945 // calling getline. In that case the previous eof() was still false
1946 // because eof() evaluates only to true if one tries to read after the
1947 // end of the file. The following check catches this.
1948 if (line.nelem() == 0 && is.eof()) return data;
1949
1950 // Because of the fixed FORTRAN format, we need to break up the line
1951 // explicitly in apropriate pieces. Not elegant, but works!
1952
1953 // Extract center frequency:
1954 // Initialization of v is important, because v stays the same
1955 // if line is empty.
1956 // JPL position in MHz:
1957 Numeric v = 0.0;
1958
1959 // Extract JPL position:
1960 extract(v, line, 13);
1961
1962 // check for empty line
1963 if (v != 0.0) {
1964 // ARTS position in Hz:
1965 data.line.F0 = v * 1E6;
1966
1967 comment = false;
1968 }
1969 }
1970
1971 // Accuracy for line position
1972 {
1973 Numeric df;
1974 extract(df, line, 8);
1975 }
1976
1977 // Intensity.
1978 {
1979 // JPL has log (10) of intensity in nm2 MHz at 300 Kelvin.
1980 //
1981 // We need to do the following:
1982 // 1. take 10^intensity
1983 // 2. convert to cm-1/(molecule * cm-2): devide by c * 1e10
1984 // 3. Convert frequency from wavenumber to Hz (factor 1e2 * c)
1985 // 4. Convert [molec * cm-2] to [molec * m-2] (factor 1e-4)
1986
1987 Numeric s;
1988
1989 // Extract JPL intensity:
1990 extract(s, line, 8);
1991
1992 // remove log
1993 s = pow((Numeric)10., s);
1994
1995 // Convert to ARTS units (Hz / (molec * m-2) ), or shorter: Hz*m^2
1996 data.line.I0 = s / 1E12;
1997 }
1998
1999 // Degrees of freedom
2000 {
2001 Index dr;
2002
2003 // Extract degrees of freedom
2004 extract(dr, line, 2);
2005 }
2006
2007 // Lower state energy.
2008 {
2009 // JPL parameter is in wavenumbers (cm^-1).
2010 // We have to convert this to the ARTS unit Joule.
2011
2012 // Extract from Catalogue line
2013 extract(data.line.E0, line, 10);
2014
2015 // Convert to Joule:
2016 data.line.E0 = wavenumber_to_joule(data.line.E0);
2017 }
2018
2019 // Upper state degeneracy
2020 {
2021 Index gup;
2022
2023 // Extract upper state degeneracy
2024 extract(gup, line, 3);
2025 }
2026
2027 // Tag number
2028 Index tag;
2029 {
2030 // Extract Tag number
2031 extract(tag, line, 7);
2032
2033 // make sure tag is not negative (damned jpl cat):
2034 tag = tag > 0 ? tag : -tag;
2035 }
2036
2037 // Set line ID
2039
2040 // Air broadening parameters: unknown to jpl, use old iup forward
2041 // model default values, which is mostly set to 0.0025 GHz/hPa, even
2042 // though for some lines the pressure broadening is given explicitly
2043 // in the program code. The explicitly given values are ignored and
2044 // only the default value is set. Self broadening was in general not
2045 // considered in the old forward model.
2046 Numeric agam, sgam;
2047 {
2048 // ARTS parameter in Hz/Pa:
2049 agam = 2.5E4;
2050
2051 // ARTS parameter in Hz/Pa:
2052 sgam = agam;
2053 }
2054
2055 // Temperature coefficient of broadening parameters. Was set to 0.75
2056 // in old forward model, even though for some lines the parameter is
2057 // given explicitly in the program code. The explicitly given values
2058 // are ignored and only the default value is set. Self broadening
2059 // not considered.
2060 Numeric nair, nself;
2061 {
2062 nair = 0.75;
2063 nself = 0.0;
2064 }
2065
2066 // Reference temperature for broadening parameter in K, was
2067 // generally set to 300 K in old forward model, with the exceptions
2068 // as already mentioned above: //DEPRECEATED but is same as for mti0 so moving on
2069 // {
2070 // mtgam = 300.0;
2071 // }
2072
2073 // Pressure shift: not given in JPL, set to 0
2074 Numeric psf;
2075 { psf = 0.0; }
2076
2077 // These were all the parameters that we can extract from
2078 // JPL. However, we still have to set the reference temperatures
2079 // to the appropriate value:
2080
2081 // Reference temperature for Intensity in K.
2082 data.T0 = 300.0;
2083
2084 // Set line shape computer
2085 data.line.lineshape = LineShape::Model(sgam, nself, agam, nair, psf);
2086
2087 // That's it!
2088 data.bad = false;
2089 return data;
2090}
2091
2093 const Index nb = broadeningspecies.nelem();
2094
2095 // Check that the isotopologue is ok
2096 if (not Isotopologue().OK()) return false;
2097
2098 // Test that self and bath is covered by the range if set positive
2099 if (nb < (Index(selfbroadening) + Index(bathbroadening))) return false;
2100
2101 // Test that the temperature is physical
2102 if (T0 <= 0) return false;
2103
2104 // Test that all lines have the correct sized line shape model
2105 if (std::any_of(lines.cbegin(), lines.cend(), [nb](auto& line) {
2106 return line.LineShapeElems() != nb;
2107 }))
2108 return false;
2109
2110 // Test that all lines have the correct sized local quantum numbers
2111 if (std::any_of(lines.cbegin(), lines.cend(), [&](auto& line) {
2112 return line.LocalQuantumElems() != lines.front().LocalQuantumElems();
2113 }))
2114 return false;
2115
2116 // Otherwise everything is fine!
2117 return true;
2118}
2119
2120Numeric Absorption::Lines::DopplerConstant(Numeric T) const noexcept {
2121 return std::sqrt(Constant::doppler_broadening_const_squared * T /
2122 SpeciesMass());
2123}
2124
2125namespace Absorption {
2126String cutofftype2metadatastring(CutoffType in, Numeric cutoff) {
2127 std::ostringstream os;
2128 switch (in) {
2129 case CutoffType::None:
2130 os << "No cut-off will be applied.\n";
2131 break;
2132 case CutoffType::ByLine:
2133 os << "The lines will be cut-off " << cutoff
2134 << " Hz from the line center + D0.\n";
2135 break;
2136 case CutoffType::FINAL:
2137 break;
2138 }
2139 return os.str();
2140}
2141
2143 for (auto& val : localquanta.val) qid.val.set(val); // Copy to same struct
2144
2145 zeeman = Zeeman::Model(qid);
2146}
2147
2152 .Data()[0]);
2153}
2154
2156 const LineShape::ModelParameters Y = {
2157 LineShape::TemperatureModel::LM_AER, d[4], d[5], d[6], d[7]};
2158 const LineShape::ModelParameters G = {
2159 LineShape::TemperatureModel::LM_AER, d[8], d[9], d[10], d[11]};
2160 for (auto& sm : lineshape.Data()) {
2161 sm.Y() = Y;
2162 sm.G() = G;
2163 }
2164}
2165
2168 bif >> F0 >> I0 >> E0 >> glow >> gupp >> A >> zeeman;
2169
2171 lineshape.read(bif);
2172
2174 for (auto& val : localquanta.val) val.read(bif);
2175
2176 return bif;
2177}
2178
2181 bof << F0 << I0 << E0 << glow << gupp << A << zeeman;
2182
2184 lineshape.write(bof);
2185
2187 for (auto& val : localquanta.val) val.write(bof);
2188
2189 return bof;
2190}
2191
2194 NumLines() not_eq 0 and NumLocalQuanta() not_eq sl.LocalQuantumElems(),
2195 "Error calling appending function, bad size of quantum numbers\n"
2196 "Type of quantum numbers in band: ",
2197 lines.front().localquanta.val,
2198 "\nType of quantum numbers in new line:",
2199 sl.localquanta.val);
2200
2202 NumLines() not_eq 0 and
2203 sl.LineShapeElems() not_eq lines[0].LineShapeElems(),
2204 "Error calling appending function, bad size of broadening species");
2205
2206 lines.push_back(std::move(sl));
2207}
2208
2211}
2212
2214 const QuantumIdentifier& qid) const
2216 if (sle.bad) return false;
2217 if (sle.selfbroadening not_eq selfbroadening) return false;
2218 if (sle.bathbroadening not_eq bathbroadening) return false;
2219 if (sle.cutoff not_eq cutoff) return false;
2220 if (sle.mirroring not_eq mirroring) return false;
2221 if (sle.population not_eq population) return false;
2222 if (sle.normalization not_eq normalization) return false;
2223 if (sle.lineshapetype not_eq lineshapetype) return false;
2224 if (sle.T0 not_eq T0) return false;
2225 if (sle.cutofffreq not_eq cutofffreq) return false;
2226 if (sle.linemixinglimit not_eq linemixinglimit) return false;
2227 if (quantumidentity not_eq qid) return false;
2228 if (not std::equal(sle.species.cbegin(),
2229 sle.species.cend(),
2230 broadeningspecies.cbegin(),
2231 broadeningspecies.cend()))
2232 return false;
2233 if (NumLines() not_eq 0 and
2234 not lines.front().localquanta.same_types_as(sle.line.localquanta))
2235 return false;
2236 if (NumLines() not_eq 0 and
2237 not sle.line.lineshape.Match(lines.front().lineshape).first)
2238 return false;
2239 return true;
2240}
2241
2242std::pair<bool, bool> Lines::Match(const Lines& l) const noexcept {
2243 // Note: The pair here is first: matching and second: nullable
2244 if (l.selfbroadening not_eq selfbroadening) return {false, false};
2245 if (l.bathbroadening not_eq bathbroadening) return {false, false};
2246 if (l.cutoff not_eq cutoff) return {false, false};
2247 if (l.mirroring not_eq mirroring) return {false, false};
2248 if (l.population not_eq population) return {false, false};
2249 if (l.normalization not_eq normalization) return {false, false};
2250 if (l.lineshapetype not_eq lineshapetype) return {false, false};
2251 if (l.T0 not_eq T0) return {false, false};
2252 if (l.cutofffreq not_eq cutofffreq) return {false, false};
2253 if (l.linemixinglimit not_eq linemixinglimit) return {false, false};
2254 if (l.quantumidentity not_eq quantumidentity) return {false, false};
2255 if (not std::equal(l.broadeningspecies.cbegin(),
2256 l.broadeningspecies.cend(),
2257 broadeningspecies.cbegin(),
2258 broadeningspecies.cend()))
2259 return {false, false};
2260 if (NumLines() not_eq 0 and l.NumLines() not_eq 0 and
2261 not lines.front().localquanta.same_types_as(l.lines.front().localquanta))
2262 return {false, false};
2263 if (NumLines() not_eq 0 and l.NumLines() not_eq 0) {
2264 if (auto matchpair =
2265 l.lines.front().lineshape.Match(lines.front().lineshape);
2266 not matchpair.first)
2267 return matchpair;
2268 }
2269
2270 return {true, true};
2271}
2272
2274 std::sort(
2275 lines.begin(), lines.end(), [](const SingleLine& a, const SingleLine& b) {
2276 return a.F0 < b.F0;
2277 });
2278}
2279
2281 std::sort(lines.begin(),
2282 lines.end(),
2283 [](const SingleLine& a, const SingleLine& b) { return a.A < b.A; });
2284}
2285
2287 return NumLines() ? LineShape::ModelShape2MetaData(lines[0].lineshape) : "";
2288}
2289
2290Species::Species Lines::Species() const noexcept {return quantumidentity.Species();}
2291
2293
2294Index Lines::NumLines() const noexcept {return Index(lines.size());}
2295
2297
2298Index Lines::NumLocalQuanta() const noexcept {
2299 return lines.size() ? lines.front().localquanta.val.nelem() : 0;
2300}
2301
2302bool Lines::OnTheFlyLineMixing() const noexcept {
2303 return population == PopulationType::ByMakarovFullRelmat or
2304 population == PopulationType::ByRovibLinearDipoleLineMixing;
2305}
2306
2307bool Lines::DoLineMixing(Numeric P) const noexcept {
2308 return linemixinglimit < 0 ? true : linemixinglimit > P;
2309}
2310
2311bool Lines::DoVmrDerivative(const QuantumIdentifier &qid) const noexcept {
2312 return qid.Isotopologue() == quantumidentity.Isotopologue() or
2313 (qid.Isotopologue().joker() and
2314 qid.Species() == quantumidentity.Species()) or
2315 std::any_of(broadeningspecies.begin(), broadeningspecies.end(),
2316 [s = qid.Species()](auto &a) { return a == s; });
2317}
2318
2319bool Lines::AnyLinemixing() const noexcept {
2320 for (auto &line : lines) {
2321 for (auto &shape : line.lineshape.Data()) {
2322 if (shape.Y().type not_eq LineShape::TemperatureModel::None or
2323 shape.G().type not_eq LineShape::TemperatureModel::None or
2324 shape.DV().type not_eq LineShape::TemperatureModel::None) {
2325 return true;
2326 }
2327 }
2328 }
2329 return false;
2330}
2331
2332Index Lines::BroadeningSpeciesPosition(Species::Species spec) const noexcept {
2333 if (auto ptr =
2334 std::find(broadeningspecies.cbegin(), broadeningspecies.cend(), spec);
2335 ptr not_eq broadeningspecies.cend())
2336 return std::distance(broadeningspecies.cbegin(), ptr);
2337 return -1;
2338}
2339
2342 ARTS_ASSERT(qns.val.has(QuantumNumberType::F) or
2343 qns.val.has(QuantumNumberType::J))
2344 return qns.val.has(QuantumNumberType::F) ? qns.val[QuantumNumberType::F]
2345 : qns.val[QuantumNumberType::J];
2346}
2347
2349 if (type == Zeeman::Polarization::None) return 1;
2350
2351 // Select F before J but assume one of them exist
2352 auto& val = get(lines[k].localquanta);
2353 return Zeeman::nelem(val.upp(), val.low(), type);
2354}
2355
2356Numeric Lines::ZeemanStrength(size_t k,
2358 Index i) const ARTS_NOEXCEPT {
2359 if (type == Zeeman::Polarization::None) return 1.0;
2360
2361 // Select F before J but assume one of them exist
2362 auto& val = get(lines[k].localquanta);
2363 return lines[k].zeeman.Strength(val.upp(), val.low(), type, i);
2364}
2365
2366Numeric Lines::ZeemanSplitting(size_t k,
2368 Index i) const ARTS_NOEXCEPT {
2369 if (type == Zeeman::Polarization::None) return 0.0;
2370
2371 // Select F before J but assume one of them exist
2372 auto& val = get(lines[k].localquanta);
2373 return lines[k].zeeman.Splitting(val.upp(), val.low(), type, i);
2374}
2375
2377 for (auto& line : lines) line.SetAutomaticZeeman(quantumidentity);
2378}
2379
2380Numeric Lines::F_mean(const ConstVectorView& wgts) const noexcept {
2381 const Numeric val =
2382 std::inner_product(lines.cbegin(),
2383 lines.cend(),
2384 wgts.begin(),
2385 0.0,
2386 std::plus<>(),
2387 [](const auto& a, const auto& b) { return a.F0 * b; });
2388 const Numeric div = sum(wgts);
2389 return val / div;
2390}
2391
2392Numeric Lines::F_mean(Numeric T) const noexcept {
2393 if (T <= 0) T = T0;
2394
2395 const Index n = NumLines();
2396 const Numeric QT = single_partition_function(T, Isotopologue());
2397 const Numeric QT0 = single_partition_function(T0, Isotopologue());
2398 const Numeric ratiopart = QT0 / QT;
2399
2400 Vector wgts(n);
2401 for (Index i = 0; i < n; i++) {
2402 const Numeric pop0 =
2403 (lines[i].gupp / QT0) * boltzman_factor(T0, lines[i].E0);
2404 const Numeric pop = pop0 * ratiopart * boltzman_ratio(T, T0, lines[i].E0);
2405 const Numeric dip_squared =
2406 -lines[i].I0 /
2407 (pop0 * lines[i].F0 *
2408 std::expm1(-(Constant::h * lines[i].F0) / (Constant::k * T0)));
2409 wgts[i] = pop * dip_squared;
2410 }
2411
2412 return F_mean(wgts);
2413}
2414
2415Numeric Lines::CutoffFreq(size_t k, Numeric shift) const noexcept {
2416 switch (cutoff) {
2417 case CutoffType::ByLine:
2418 return lines[k].F0 + cutofffreq +
2419 (mirroring == MirroringType::Manual ? -shift : shift);
2420 case CutoffType::None:
2421 return std::numeric_limits<Numeric>::max();
2422 case CutoffType::FINAL:
2423 break;
2424 }
2425 return std::numeric_limits<Numeric>::max();
2426}
2427
2428Numeric Lines::CutoffFreqMinus(size_t k, Numeric shift) const noexcept {
2429 switch (cutoff) {
2430 case CutoffType::ByLine:
2431 return lines[k].F0 - cutofffreq +
2432 (mirroring == MirroringType::Manual ? -shift : shift);
2433 case CutoffType::None:
2434 return std::numeric_limits<Numeric>::lowest();
2435 case CutoffType::FINAL:
2436 break;
2437 }
2438
2439 return std::numeric_limits<Numeric>::lowest();
2440}
2441
2443 for (auto& line : lines) line.read(is);
2444 return is;
2445}
2446
2448 for (auto& line : lines) line.write(os);
2449 return os;
2450}
2451
2453 QuantumIdentifier qid = quantumidentity;
2454 for (auto& a : lines[k].localquanta.val) qid.val.set(a);
2455 return qid;
2456}
2457
2459 const Index n = NumLines();
2460 const Index m = NumBroadeners();
2461 if (not n) return;
2462
2463 for (Index j = 0; j < m; j++) {
2464 for (Index i = 0; i < LineShape::nVars; i++) {
2465 // Find a common type (same or none) or throw if there is none
2466 LineShape::TemperatureModel t = LineShape::TemperatureModel::None;
2467 for (auto& line : lines) {
2468 if (auto& data = line.lineshape[j].Data()[i];
2470 if (t == LineShape::TemperatureModel::None) t = data.type;
2472 t not_eq data.type,
2473 "Cannot make a common line shape model for the band as there are multiple non-empty types: ",
2474 data.type,
2475 " and ",
2476 t)
2477 }
2478 }
2479
2480 // Set the common type
2481 for (auto& line : lines) {
2482 if (auto& data = line.lineshape[j].Data()[i]; data.type not_eq t) {
2484 }
2485 }
2486 }
2487 }
2488}
2489} // namespace Absorption
2490
2492 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2493 for (auto& abs_lines : abs_lines_per_species) {
2494 for (auto& band : abs_lines) {
2495 switch (band.population) {
2496 case Absorption::PopulationType::LTE:
2497 LTE = true;
2498 break;
2499 case Absorption::PopulationType::NLTE:
2500 NLTE = true;
2501 break;
2502 case Absorption::PopulationType::VibTemps:
2503 VibTemps = true;
2504 break;
2505 case Absorption::PopulationType::ByHITRANFullRelmat:
2506 ByHITRANFullRelmat = true;
2507 break;
2508 case Absorption::PopulationType::ByHITRANRosenkranzRelmat:
2510 break;
2511 case Absorption::PopulationType::ByMakarovFullRelmat:
2512 ByMakarovFullRelmat = true;
2513 break;
2514 case Absorption::PopulationType::ByRovibLinearDipoleLineMixing:
2516 break;
2517 case Absorption::PopulationType::FINAL: { /* leave list */
2518 }
2519 }
2520 }
2521 }
2522}
2523
2525 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2526 for (auto& abs_lines : abs_lines_per_species) {
2527 for (auto& band : abs_lines) {
2528 switch (band.cutoff) {
2529 case Absorption::CutoffType::None:
2530 None = true;
2531 break;
2532 case Absorption::CutoffType::ByLine:
2533 ByLine = true;
2534 break;
2535 case Absorption::CutoffType::FINAL: { /* leave list */
2536 }
2537 }
2538 }
2539 }
2540}
2541
2543 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2544 for (auto& abs_lines : abs_lines_per_species) {
2545 for (auto& band : abs_lines) {
2546 switch (band.lineshapetype) {
2547 case LineShape::Type::DP:
2548 DP = true;
2549 break;
2550 case LineShape::Type::LP:
2551 LP = true;
2552 break;
2553 case LineShape::Type::VP:
2554 VP = true;
2555 break;
2556 case LineShape::Type::SDVP:
2557 SDVP = true;
2558 break;
2559 case LineShape::Type::HTP:
2560 HTP = true;
2561 break;
2562 case LineShape::Type::SplitLP:
2563 SplitLP = true;
2564 break;
2565 case LineShape::Type::SplitVP:
2566 SplitVP = true;
2567 break;
2568 case LineShape::Type::SplitSDVP:
2569 SplitSDVP = true;
2570 break;
2571 case LineShape::Type::SplitHTP:
2572 SplitHTP = true;
2573 break;
2574 case LineShape::Type::FINAL: { /* leave list */
2575 }
2576 }
2577 }
2578 }
2579}
2580
2582 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2583 for (auto& abs_lines : abs_lines_per_species) {
2584 for (auto& band : abs_lines) {
2585 switch (band.mirroring) {
2586 case Absorption::MirroringType::None:
2587 None = true;
2588 break;
2589 case Absorption::MirroringType::Lorentz:
2590 Lorentz = true;
2591 break;
2592 case Absorption::MirroringType::SameAsLineShape:
2593 SameAsLineShape = true;
2594 break;
2595 case Absorption::MirroringType::Manual:
2596 Manual = true;
2597 break;
2598 case Absorption::MirroringType::FINAL: { /* leave list */
2599 }
2600 }
2601 }
2602 }
2603}
2604
2606 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2607 for (auto& abs_lines : abs_lines_per_species) {
2608 for (auto& band : abs_lines) {
2609 switch (band.normalization) {
2610 case Absorption::NormalizationType::None:
2611 None = true;
2612 break;
2613 case Absorption::NormalizationType::VVH:
2614 VVH = true;
2615 break;
2616 case Absorption::NormalizationType::VVW:
2617 VVW = true;
2618 break;
2619 case Absorption::NormalizationType::RQ:
2620 RQ = true;
2621 break;
2622 case Absorption::NormalizationType::SFS:
2623 SFS = true;
2624 break;
2625 case Absorption::NormalizationType::FINAL: { /* leave list */
2626 }
2627 }
2628 }
2629 }
2630}
2631
2632namespace {
2633template <typename T>
2634constexpr std::size_t req_spaces(T my_enum) {
2635 constexpr std::size_t n = []() {
2636 std::size_t longest = 0;
2637 for (auto& x : Absorption::enumstrs::CutoffTypeNames) {
2638 longest = std::max(x.length(), longest);
2639 }
2640 for (auto& x : Absorption::enumstrs::MirroringTypeNames) {
2641 longest = std::max(x.length(), longest);
2642 }
2643 for (auto& x : Absorption::enumstrs::NormalizationTypeNames) {
2644 longest = std::max(x.length(), longest);
2645 }
2646 for (auto& x : Absorption::enumstrs::PopulationTypeNames) {
2647 longest = std::max(x.length(), longest);
2648 }
2649 for (auto& x : LineShape::enumstrs::TypeNames) {
2650 longest = std::max(x.length(), longest);
2651 }
2652 return longest + 1;
2653 }();
2654 return n - toString(my_enum).length();
2655}
2656
2657auto spaces(std::size_t n) { return std::basic_string(n, ' '); }
2658} // namespace
2659
2660std::ostream& operator<<(std::ostream& os, AbsorptionCutoffTagTypeStatus val) {
2661 // Trick to never forget to update
2662 Absorption::CutoffType x{Absorption::CutoffType::FINAL};
2663 switch (x) {
2664 case Absorption::CutoffType::FINAL:
2665 os << "Cutoff tag types:\n";
2666 [[fallthrough]];
2667 case AbsorptionCutoffType::ByLine:
2668 os << " ByLine:" << spaces(req_spaces(AbsorptionCutoffType::ByLine))
2669 << val.ByLine << '\n';
2670 [[fallthrough]];
2671 case AbsorptionCutoffType::None:
2672 os << " None:" << spaces(req_spaces(AbsorptionCutoffType::None))
2673 << val.None;
2674 }
2675 return os;
2676}
2677
2678std::ostream& operator<<(std::ostream& os,
2680 // Trick to never forget to update
2681 Absorption::MirroringType x{Absorption::MirroringType::FINAL};
2682 switch (x) {
2683 case Absorption::MirroringType::FINAL:
2684 os << "Mirroring tag types:\n";
2685 [[fallthrough]];
2686 case Absorption::MirroringType::None:
2687 os << " None:" << spaces(req_spaces(Absorption::MirroringType::None))
2688 << val.None << '\n';
2689 [[fallthrough]];
2690 case Absorption::MirroringType::Lorentz:
2691 os << " Lorentz:"
2692 << spaces(req_spaces(Absorption::MirroringType::Lorentz))
2693 << val.Lorentz << '\n';
2694 [[fallthrough]];
2695 case Absorption::MirroringType::SameAsLineShape:
2696 os << " SameAsLineShape:"
2697 << spaces(req_spaces(Absorption::MirroringType::SameAsLineShape))
2698 << val.SameAsLineShape << '\n';
2699 [[fallthrough]];
2700 case Absorption::MirroringType::Manual:
2701 os << " Manual:"
2702 << spaces(req_spaces(Absorption::MirroringType::Manual)) << val.Manual;
2703 }
2704 return os;
2705}
2706
2707std::ostream& operator<<(std::ostream& os,
2709 // Trick to never forget to update
2710 Absorption::NormalizationType x{Absorption::NormalizationType::FINAL};
2711 switch (x) {
2712 case Absorption::NormalizationType::FINAL:
2713 os << "Normalization tag types:\n";
2714 [[fallthrough]];
2715 case Absorption::NormalizationType::None:
2716 os << " None:"
2717 << spaces(req_spaces(Absorption::NormalizationType::None)) << val.None
2718 << '\n';
2719 [[fallthrough]];
2720 case Absorption::NormalizationType::VVH:
2721 os << " VVH:" << spaces(req_spaces(Absorption::NormalizationType::VVH))
2722 << val.VVH << '\n';
2723 [[fallthrough]];
2724 case Absorption::NormalizationType::VVW:
2725 os << " VVW:" << spaces(req_spaces(Absorption::NormalizationType::VVW))
2726 << val.VVW << '\n';
2727 [[fallthrough]];
2728 case Absorption::NormalizationType::RQ:
2729 os << " RQ:" << spaces(req_spaces(Absorption::NormalizationType::RQ))
2730 << val.RQ << '\n';
2731 [[fallthrough]];
2732 case Absorption::NormalizationType::SFS:
2733 os << " SFS:" << spaces(req_spaces(Absorption::NormalizationType::SFS))
2734 << val.SFS;
2735 }
2736 return os;
2737}
2738
2739std::ostream& operator<<(std::ostream& os,
2741 // Trick to never forget to update
2742 Absorption::PopulationType x{Absorption::PopulationType::FINAL};
2743 switch (x) {
2744 case Absorption::PopulationType::FINAL:
2745 os << "Population tag type:\n";
2746 [[fallthrough]];
2747 case Absorption::PopulationType::LTE:
2748 os << " LTE:" << spaces(req_spaces(Absorption::PopulationType::LTE))
2749 << val.LTE << '\n';
2750 [[fallthrough]];
2751 case Absorption::PopulationType::NLTE:
2752 os << " NLTE:" << spaces(req_spaces(Absorption::PopulationType::NLTE))
2753 << val.NLTE << '\n';
2754 [[fallthrough]];
2755 case Absorption::PopulationType::VibTemps:
2756 os << " VibTemps:"
2757 << spaces(req_spaces(Absorption::PopulationType::VibTemps))
2758 << val.VibTemps << '\n';
2759 [[fallthrough]];
2760 case Absorption::PopulationType::ByHITRANRosenkranzRelmat:
2761 os << " ByHITRANRosenkranzRelmat:"
2762 << spaces(req_spaces(
2763 Absorption::PopulationType::ByHITRANRosenkranzRelmat))
2764 << val.ByHITRANRosenkranzRelmat << '\n';
2765 [[fallthrough]];
2766 case Absorption::PopulationType::ByHITRANFullRelmat:
2767 os << " ByHITRANFullRelmat:"
2768 << spaces(req_spaces(Absorption::PopulationType::ByHITRANFullRelmat))
2769 << val.ByHITRANFullRelmat << '\n';
2770 [[fallthrough]];
2771 case Absorption::PopulationType::ByMakarovFullRelmat:
2772 os << " ByMakarovFullRelmat:"
2773 << spaces(req_spaces(Absorption::PopulationType::ByMakarovFullRelmat))
2774 << val.ByMakarovFullRelmat << '\n';
2775 [[fallthrough]];
2776 case Absorption::PopulationType::ByRovibLinearDipoleLineMixing:
2777 os << " ByRovibLinearDipoleLineMixing:"
2778 << spaces(req_spaces(
2779 Absorption::PopulationType::ByRovibLinearDipoleLineMixing))
2781 }
2782 return os;
2783}
2784
2785std::ostream& operator<<(std::ostream& os,
2787 // Trick to never forget to update
2788 LineShapeType x{LineShapeType::FINAL};
2789 switch (x) {
2790 case LineShapeType::FINAL:
2791 os << "Line shape tag type:\n";
2792 [[fallthrough]];
2793 case LineShapeType::DP:
2794 os << " DP:" << spaces(req_spaces(LineShapeType::DP)) << val.DP
2795 << '\n';
2796 [[fallthrough]];
2797 case LineShapeType::LP:
2798 os << " LP:" << spaces(req_spaces(LineShapeType::LP)) << val.LP
2799 << '\n';
2800 [[fallthrough]];
2801 case LineShapeType::VP:
2802 os << " VP:" << spaces(req_spaces(LineShapeType::VP)) << val.VP
2803 << '\n';
2804 [[fallthrough]];
2805 case LineShapeType::SDVP:
2806 os << " SDVP:" << spaces(req_spaces(LineShapeType::SDVP)) << val.SDVP
2807 << '\n';
2808 [[fallthrough]];
2809 case LineShapeType::HTP:
2810 os << " HTP:" << spaces(req_spaces(LineShapeType::HTP)) << val.HTP
2811 << '\n';
2812 [[fallthrough]];
2813 case LineShapeType::SplitLP:
2814 os << " SplitLP:" << spaces(req_spaces(LineShapeType::SplitLP)) << val.SplitLP
2815 << '\n';
2816 [[fallthrough]];
2817 case LineShapeType::SplitVP:
2818 os << " SplitVP:" << spaces(req_spaces(LineShapeType::SplitVP)) << val.SplitVP
2819 << '\n';
2820 [[fallthrough]];
2821 case LineShapeType::SplitSDVP:
2822 os << " SplitSDVP:" << spaces(req_spaces(LineShapeType::SplitSDVP)) << val.SplitSDVP
2823 << '\n';
2824 [[fallthrough]];
2825 case LineShapeType::SplitHTP:
2826 os << " SplitHTP:" << spaces(req_spaces(LineShapeType::SplitHTP)) << val.SplitHTP;
2827 }
2828 return os;
2829}
2830
2831std::ostream& operator<<(std::ostream& os, AbsorptionTagTypesStatus val) {
2832 return os << "Catalog tag summary:\n " << val.cutoff << "\n "
2833 << val.lineshapetype << "\n " << val.mirroring << "\n "
2834 << val.normalization << "\n " << val.population;
2835}
2836
2838 Index i,
2839 const ArrayOfArrayOfSpeciesTag& abs_species,
2840 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2841 const Index n = abs_species.nelem();
2842
2843 Index ispec{0};
2844 while (ispec < n and i >= abs_lines_per_species[ispec].nelem()) {
2845 i -= abs_lines_per_species[ispec].nelem();
2846 ++ispec;
2847 }
2848
2849 return {ispec, i};
2850}
2851
2852namespace Absorption {
2853bool any_cutoff(const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species) {
2854 return std::any_of(
2855 abs_lines_per_species.cbegin(),
2856 abs_lines_per_species.cend(),
2857 [](auto& abs_lines) {
2858 return std::any_of(
2859 abs_lines.cbegin(), abs_lines.cend(), [](auto& band) {
2860 return band.cutoff not_eq CutoffType::None;
2861 });
2862 });
2863}
2864
2865Rational Lines::max(QuantumNumberType x) const {
2866 ARTS_USER_ERROR_IF(Quantum::Number::common_value_type(x) == Quantum::Number::ValueType::S, "Cannot get a rational out from quantum number type ", x)
2867 if (quantumidentity.val.has(x)) {
2868 auto& val = quantumidentity.val[x];
2869 return std::max(val.low(), val.upp());
2870 }
2871
2872 Rational out{std::numeric_limits<Index>::lowest()};
2873 for (auto& line : lines) {
2874 ARTS_USER_ERROR_IF(not line.localquanta.val.has(x), "No ", x, " in some line(s)")
2875 auto& val = line.localquanta.val[x];
2876 out = std::max(std::max(val.low(), val.upp()), out);
2877 }
2878 return out;
2879}
2880
2882Index nelem(const Lines &l) { return l.NumLines(); }
2883
2885Index nelem(const Array<Lines> &l) {
2886 Index n = 0;
2887 for (auto &x : l)
2888 n += nelem(x);
2889 return n;
2890}
2891
2893Index nelem(const Array<Array<Lines>> &l) {
2894 Index n = 0;
2895 for (auto &x : l)
2896 n += nelem(x);
2897 return n;
2898}
2899} // namespace Absorption
Numeric wavenumber_to_joule(Numeric e)
A little helper function to convert energy from units of wavenumber (cm^-1) to Joule (J).
Definition: absorption.cc:68
Declarations required for the calculation of absorption coefficients.
std::ostream & operator<<(std::ostream &os, AbsorptionCutoffTagTypeStatus val)
AbsorptionSpeciesBandIndex flat_index(Index i, const ArrayOfArrayOfSpeciesTag &abs_species, const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species)
Get a flat index pair for species and band.
Contains the absorption namespace.
Common ARTS conversions.
This can be used to make arrays out of anything.
Definition: array.h:31
Index nelem() const ARTS_NOEXCEPT
Definition: array.h:75
Main line shape model class.
void SetLineMixingModel(SingleSpeciesModel x)
Sets the same line mixing model to all species.
bifstream & read(bifstream &bif)
Binary read for Model.
bofstream & write(bofstream &bof) const
Binary write for Model.
const std::vector< SingleSpeciesModel > & Data() const noexcept
The line shape model data.
void set(Value v)
Sets the value if it exists or adds it otherwise.
bool has(Types... ts) const ARTS_NOEXCEPT
Returns whether all the Types are part of the list, the types must be sorted.
Value & add(Type t)
Add for manipulation.
Index nelem() const ARTS_NOEXCEPT
Return number of quantum numbers.
Main Zeeman Model.
Definition: zeemandata.h:279
Binary output file stream class.
Definition: bifstream.h:26
Binary output file stream class.
Definition: bofstream.h:25
Input manipulator class for doubles to enable nan and inf parsing.
Definition: double_imanip.h:25
Index nelem() const
Definition: mystring.h:172
Helper macros for debugging.
#define ARTS_NOEXCEPT
Definition: debug.h:81
#define ARTS_ASSERT(condition,...)
Definition: debug.h:84
#define ARTS_USER_ERROR(...)
Definition: debug.h:151
#define ARTS_USER_ERROR_IF(condition,...)
Definition: debug.h:135
constexpr std::string_view toString(EnergyLevelMapType x) noexcept
constexpr bool good_enum(EnumType x) noexcept
Checks if the enum number is good.
Definition: enums.h:21
This file contains basic functions to handle ASCII files.
Numeric boltzman_factor(Numeric T, Numeric E0)
Computes exp(- E0/kT)
Definition: linescaling.cc:90
Numeric boltzman_ratio(const Numeric &T, const Numeric &T0, const Numeric &E0)
Computes exp(E0/c (T - T0) / (T * T0))
Definition: linescaling.cc:75
Numeric single_partition_function(const Numeric &T, const Species::IsotopeRecord &ir)
Computes the partition function at one temperature.
Definition: linescaling.cc:4
Constains various line scaling functions.
Contains the line shape namespace.
LineShape::Type LineShapeType
void extract(T &x, String &line, std::size_t n)
Extract something from the beginning of a string.
Definition: mystring.h:216
Namespace to contain things required for absorption calculations.
SingleLineExternal ReadFromHitranOnlineStream(istream &is)
Read from HITRAN online.
String cutofftype2metadatastring(CutoffType in, Numeric cutoff)
SingleLineExternal ReadFromJplStream(istream &is)
Read from JPL.
const Quantum::Number::Value & get(const Quantum::Number::LocalState &qns) ARTS_NOEXCEPT
Numeric reduced_rovibrational_dipole(Rational Jf, Rational Ji, Rational lf, Rational li, Rational k=Rational(1))
Compute the reduced rovibrational dipole moment.
SingleLineExternal ReadFromArtscat3Stream(istream &is)
Read from ARTSCAT-3.
Index nelem(const Lines &l)
Number of lines.
SingleLineExternal ReadFromLBLRTMStream(istream &is)
Read from LBLRTM.
std::ostream & operator<<(std::ostream &os, const Absorption::Lines &lines)
std::istream & operator>>(std::istream &is, Lines &lines)
Numeric cutoff
SingleLineExternal ReadFromArtscat5Stream(istream &is)
Read from ARTSCAT-5.
bool any_cutoff(const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species)
Numeric reduced_magnetic_quadrapole(Rational Jf, Rational Ji, Rational N)
Compute the reduced magnetic quadrapole moment.
SingleLineExternal ReadFromHitran2004Stream(istream &is)
Read from newer HITRAN.
SingleLineExternal ReadFromHitran2001Stream(istream &is)
Read from HITRAN before 2004.
SingleLineExternal ReadFromArtscat4Stream(istream &is)
Read from ARTSCAT-4.
std::vector< Lines > split_list_of_external_lines(std::vector< SingleLineExternal > &external_lines, const std::vector< QuantumNumberType > &localquantas={}, const std::vector< QuantumNumberType > &globalquantas={})
Splits a list of lines into proper Lines.
constexpr Numeric doppler_broadening_const_squared
Doppler broadening constant squared [kg/T]^2.
constexpr Numeric k
Boltzmann constant convenience name [J/K].
constexpr Numeric c
Speed of light convenience name [m/s].
constexpr Numeric h
Planck constant convenience name [J s].
constexpr auto atm2pa(auto x) noexcept
Conversion from Atm to Pa.
QuantumIdentifier id_from_lookup(Index mol, char isochar)
Finds the ID of the ARTS species from HITRAN.
Numeric ratio_from_lookup(Index mol, char isochar)
Finds the isotopologue ratio of the species from HITRAN.
QuantumIdentifier id_from_lookup(Index tag)
Finds the ID of the ARTS species from JPL.
Definition: jpl_species.cc:204
Model vector2modellm(Vector x, LegacyLineMixingData::TypeLM type)
LineShape::Model from legacy input vector.
Computations of line shape derived parameters.
Definition: lineshape.cc:27
Model lblrtm_model(Numeric sgam, Numeric nself, Numeric agam, Numeric nair, Numeric psf, std::array< Numeric, 12 > aer_interp)
constexpr ModelParameters modelparameterGetEmpty(const TemperatureModel t) noexcept
std::istream & from_linefunctiondata(std::istream &data, Type &type, bool &self, bool &bath, Model &m, ArrayOfSpecies &species)
constexpr bool modelparameterEmpty(const ModelParameters mp) noexcept
Model hitran_model(Numeric sgam, Numeric nself, Numeric agam, Numeric nair, Numeric psf)
Vector mass(const ConstVectorView &atmospheric_vmrs, const ArrayOfArrayOfSpeciesTag &atmospheric_species, const ArrayOfSpecies &lineshape_species, const SpeciesIsotopologueRatios &ir) ARTS_NOEXCEPT
Returns a mass vector for this model's main calculations.
std::istream & from_pressurebroadeningdata(std::istream &data, LineShape::Type &type, bool &self, bool &bath, Model &m, ArrayOfSpecies &species, const QuantumIdentifier &qid)
Legacy reading of old deprecated PressureBroadeningData class.
ArrayOfString ModelMetaDataArray(const LineShape::Model &m, const bool self, const ArrayOfSpecies &sts, const Numeric T0)
String ModelShape2MetaData(const Model &m)
std::istream & from_artscat4(std::istream &is, Type &type, bool &self, bool &bath, Model &m, ArrayOfSpecies &species, const QuantumIdentifier &qid)
std::istream & from_linemixingdata(std::istream &data, Model &lsc)
Legacy reading of old deprecated LineMixingData class.
constexpr Index nVars
Current max number of line shape variables.
Vector vmrs(const ConstVectorView &atmospheric_vmrs, const ArrayOfArrayOfSpeciesTag &atmospheric_species, const ArrayOfSpecies &lineshape_species) ARTS_NOEXCEPT
Returns a VMR vector for this model's main calculations.
constexpr auto pow2(auto x) noexcept
power of two
constexpr ValueType common_value_type(ValueType a, ValueType b) noexcept
Return a common type between a and b.
ValueList from_hitran(std::string_view upp, std::string_view low)
String update_isot_name(const String &old_name)
Updates the name of the isotopologue based on updates of the isotopologues.
constexpr Index find_species_index(const Species spec, const std::string_view isot) noexcept
constexpr Index nelem(Rational Ju, Rational Jl, Polarization type) noexcept
Gives the number of elements of the polarization type of this transition.
Definition: zeemandata.h:125
Polarization
Zeeman polarization selection.
Definition: zeemandata.h:27
Quantum::Number::Type QuantumNumberType
AbsorptionCutoffTagTypeStatus(const ArrayOfArrayOfAbsorptionLines &)
AbsorptionLineShapeTagTypeStatus(const ArrayOfArrayOfAbsorptionLines &)
AbsorptionMirroringTagTypeStatus(const ArrayOfArrayOfAbsorptionLines &)
AbsorptionNormalizationTagTypeStatus(const ArrayOfArrayOfAbsorptionLines &)
AbsorptionPopulationTagTypeStatus(const ArrayOfArrayOfAbsorptionLines &)
Helper struct for flat_index.
AbsorptionNormalizationTagTypeStatus normalization
AbsorptionPopulationTagTypeStatus population
AbsorptionLineShapeTagTypeStatus lineshapetype
AbsorptionCutoffTagTypeStatus cutoff
AbsorptionMirroringTagTypeStatus mirroring
void sort_by_einstein()
Sort inner line list by Einstein coefficient.
void sort_by_frequency()
Sort inner line list by frequency.
Index NumBroadeners() const ARTS_NOEXCEPT
Number of broadening species.
SingleLine PopLine(Index) noexcept
Pops a single line.
Index BroadeningSpeciesPosition(Species::Species spec) const noexcept
Position of species if available or -1 else.
PopulationType population
Line population distribution.
Index NumLocalQuanta() const noexcept
Number of broadening species.
void RemoveLine(Index) noexcept
Removes a single line.
Numeric F_mean(Numeric T=0) const noexcept
Mean frequency by weight of line strength.
void SetAutomaticZeeman() noexcept
Set Zeeman effect for all lines that have the correct quantum numbers.
Vector BroadeningSpeciesVMR(const ConstVectorView &, const ArrayOfArrayOfSpeciesTag &) const
Returns the VMRs of the broadening species.
Numeric ZeemanSplitting(size_t k, Zeeman::Polarization type, Index i) const ARTS_NOEXCEPT
Returns the splitting of a Zeeman split line.
Array< SingleLine > lines
A list of individual lines.
Index NumLines() const noexcept
Number of lines.
bofstream & write(bofstream &os) const
Binary write for Lines.
Species::Species Species() const noexcept
Species Enum.
Numeric DopplerConstant(Numeric T) const noexcept
bool OnTheFlyLineMixing() const noexcept
On-the-fly line mixing.
Numeric ZeemanStrength(size_t k, Zeeman::Polarization type, Index i) const ARTS_NOEXCEPT
Returns the strength of a Zeeman split line.
QuantumIdentifier QuantumIdentityOfLine(Index k) const noexcept
bool OK() const ARTS_NOEXCEPT
bifstream & read(bifstream &is)
Binary read for Lines.
bool MatchWithExternal(const SingleLineExternal &sle, const QuantumIdentifier &quantumidentity) const ARTS_NOEXCEPT
Checks if an external line matches this structure.
Species::IsotopeRecord Isotopologue() const noexcept
Isotopologue Index.
String LineShapeMetaData() const noexcept
Meta data for the line shape if it exists.
void MakeLineShapeModelCommon()
Make a common line shape if possible.
String SpeciesName() const noexcept
Species Name.
Index LineShapePos(const Species::Species spec) const ARTS_NOEXCEPT
Position among broadening species or -1.
LineShape::Output ShapeParameters(size_t k, Numeric T, Numeric P, const Vector &vmrs) const ARTS_NOEXCEPT
Line shape parameters.
Index ZeemanCount(size_t k, Zeeman::Polarization type) const ARTS_NOEXCEPT
Returns the number of Zeeman split lines.
Numeric CutoffFreq(size_t k, Numeric shift=0) const noexcept
Returns cutoff frequency or maximum value.
void ReverseLines() noexcept
Reverses the order of the internal lines.
std::pair< bool, bool > Match(const Lines &l) const noexcept
Checks if another line list matches this structure.
void AppendSingleLine(SingleLine &&sl)
Appends a single line to the absorption lines.
ArrayOfSpecies broadeningspecies
A list of broadening species.
Numeric SelfVMR(const ConstVectorView &, const ArrayOfArrayOfSpeciesTag &) const
Returns the VMR of the species.
Numeric CutoffFreqMinus(size_t k, Numeric shift=0) const noexcept
Returns negative cutoff frequency or lowest value.
bool AnyLinemixing() const noexcept
String MetaData() const
Returns a printable statement about the lines.
bool DoLineMixing(Numeric P) const noexcept
Returns if the pressure should do line mixing.
Numeric SpeciesMass() const noexcept
Mass of the molecule.
QuantumIdentifier quantumidentity
Catalog ID.
bool DoVmrDerivative(const QuantumIdentifier &qid) const noexcept
LineShape::Output ShapeParameters_dVMR(size_t k, Numeric T, Numeric P, const QuantumIdentifier &vmr_qid) const ARTS_NOEXCEPT
Line shape parameters vmr derivative.
LineShape::Output ShapeParameters_dT(size_t k, Numeric T, Numeric P, const Vector &vmrs) const ARTS_NOEXCEPT
Line shape parameters temperature derivatives.
Vector BroadeningSpeciesMass(const ConstVectorView &, const ArrayOfArrayOfSpeciesTag &, const SpeciesIsotopologueRatios &, const Numeric &bath_mass=0) const
Returns the mass of the broadening species.
Single line reading output.
Computations and data for a single absorption line.
Numeric E0
Lower state energy level.
bofstream & write(bofstream &bof) const
Binary write for AbsorptionLines.
bifstream & read(bifstream &bif)
Binary read for AbsorptionLines.
Numeric F0
Central frequency.
Quantum::Number::LocalState localquanta
Local quantum numbers.
LineShape::Model lineshape
Line shape model.
void SetAutomaticZeeman(QuantumIdentifier qid)
Set Zeeman effect by automatic detection.
Zeeman::Model zeeman
Zeeman model.
Numeric A
Einstein spontaneous emission coefficient.
Numeric glow
Lower level statistical weight.
void SetLineMixing2AER(const Vector &d)
Set the line mixing model to AER kind.
Numeric gupp
Upper level statistical weight.
void SetLineMixing2SecondOrderData(const Vector &d)
Set the line mixing model to 2nd order.
Numeric I0
Reference intensity.
Coefficients and temperature model for SingleSpeciesModel.
Main output of Model.
constexpr Output & no_linemixing(bool do_no_linemixing)
Turns of line mixing if true. Return *this.
A logical struct for global quantum numbers with species identifiers.
Species::Species Species() const noexcept
Species::IsotopeRecord Isotopologue() const noexcept
A logical struct for local quantum numbers.
A complete quantum number value with type information.
constexpr void set(std::string_view s, bool upp)
Set level value.
Struct containing all information needed about one isotope.
Definition: isotopologues.h:16
String FullName() const noexcept
Definition: isotopologues.h:49
#define d
#define v
#define a
#define c
#define b
Numeric wigner6j(const Rational j1, const Rational j2, const Rational j3, const Rational l1, const Rational l2, const Rational l3)
Wigner 6J symbol.
Numeric wigner3j(const Rational j1, const Rational j2, const Rational j3, const Rational m1, const Rational m2, const Rational m3)
Wigner 3J symbol.
Wigner symbol interactions.