cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
atom_level2.cpp
Go to the documentation of this file.
1 /* This file is part of Cloudy and is copyright (C)1978-2022 by Gary J. Ferland and
2  * others. For conditions of distribution and use see copyright notice in license.txt */
3 /*atom_level2 do level population and cooling for two level atom,
4  * side effects:
5  * set elements of transition struc
6  * cooling via CoolAdd( chLab, (long)t->WLAng , t->cool());
7  * cooling derivative */
8 #include "cddefines.h"
9 #include "phycon.h"
10 #include "transition.h"
11 #include "rfield.h"
12 #include "thermal.h"
13 #include "cooling.h"
14 #include "atoms.h"
15 #include "ionbal.h"
16 #include "dense.h"
17 #include "lines_service.h"
18 #include "ionbal.h"
19 
20 
21 /* There are two special uses of this function:
22  * - With hyperfine transitions:
23  * Then, IndirectRate are out of the ground state. The de-excitations to
24  * the ground state are distributed between the two levels according to
25  * their statistical weights.
26  * - With Opacity Project lines:
27  * IndirectRate is given as 0, causing the previous total to be incremented
28  * by the upward rate of OP transitions.
29  * By default, the function is invoked with the indirect rate set to 0. */
30 void atom_level2( const TransitionProxy &t, const bool lgHFS )
31 {
32  long int ion,
33  ip,
34  nelem;
35  double AbunxIon,
36  a21,
37  boltz,
38  col12,
39  col21,
40  coolng,
41  g1,
42  g2,
43  omega,
44  pfs1,
45  pfs2,
46  r,
47  rate12,
48  ri21;
49 
50 
51  DEBUG_ENTRY( "atom_level2()" );
52 
53  /* result is density (cm-3) of excited state times A21
54  * result normalized to N1+N2=ABUND
55  * routine increments dCooldT, call CoolAdd
56  * CDSQTE is EDEN / SQRTE * 8.629E-6
57  */
58 
59  ion = (*t.Hi()).IonStg();
60  nelem = (*t.Hi()).nelem();
61 
62  /* dense.xIonDense[nelem][i] is density of ith ionization stage (cm^-3) */
63  AbunxIon = dense.xIonDense[nelem-1][ion-1];
64 
65 
66  /* continuum pointer */
67  ip = t.ipCont();
68 
69  /* approximate Boltzmann factor to see if results zero */
70  boltz = rfield.ContBoltz[ip-1];
71 
72 
73  /* statistical weights of upper and lower levels */
74  g1 = (*t.Lo()).g();
75  g2 = (*t.Hi()).g();
76 
77 
78  /* indirect excitations from lower level that populate upper level */
79  double IndirLU = 0.0;
80 
81  if( lgHFS )
82  IndirLU = ionbal.ExcitationGround[nelem-1][ion-1] * g2 / (g1 + g2);
83 
84  /* collision strength for this transition, omega is zero for hydrogenic
85  * species which are done in special hydro routines */
86  omega = t.Coll().col_str();
87 
88  /* ROUGH check whether upper level has significant population,*/
89  r = (boltz*dense.cdsqte + t.Emis().pump() + IndirLU)/(dense.cdsqte + t.Emis().Aul());
90 
91  /* following first test needed for 32 bit cpu on search phase
92  * >>chng 96 jul 02, was 1e-30 crashed on dec, change to 1e-25
93  * if( AbunxIon.lt.1e-25 .or. boltz.gt.30. ) then
94  * >>chng 96 jul 11, to below, since can be strong pumping when
95  * Boltzmann factor essentially zero */
96  /* omega in following is zero for hydrogenic species, since done
97  * in hydro routines, so this should cause us to quit on this test */
98  /* >>chng 99 nov 29, from 1e-25 to 1e-30 to keep same result for
99  * very low density models, where AbunxIon is very small but still significant*/
100  /*if( omega*AbunxIon < 1e-25 || r < 1e-25 )*/
101  if( omega*AbunxIon < 1e-30 || r < 1e-25 )
102  {
103  /* put in pop since possible just too cool */
104  (*t.Lo()).Pop() = AbunxIon;
105  t.Emis().PopOpc() = AbunxIon;
106  (*t.Hi()).Pop() = 0.;
107  t.Emis().xIntensity() = 0.;
108  t.Emis().xObsIntensity() = 0.;
109  t.Coll().cool() = 0.;
110  t.Emis().ots() = 0.;
111  t.Emis().ColOvTot() = 0.;
112  t.Coll().heat() = 0.;
113  /* level populations */
114  atoms.PopLevels[0] = AbunxIon;
115  atoms.PopLevels[1] = 0.;
116  atoms.DepLTELevels[0] = 1.;
117  atoms.DepLTELevels[1] = 0.;
118  return;
119  }
120 
121  /* net rate down A21*(escape + destruction) */
122  a21 = t.Emis().Aul()*(t.Emis().Ploss());
123 
124  /* now get real Boltzmann factor */
125  boltz = t.EnergyK()/phycon.te;
126 
127  ASSERT( boltz > 0. );
128  boltz = sexp(boltz);
129 
130  ASSERT( g1 > 0. && g2 > 0. );
131 
132  /* this lacks the upper statistical weight */
133  col21 = dense.cdsqte*omega;
134  /* upward coll rate s-1 */
135  col12 = col21/g1*boltz;
136  /* downward coll rate s-1 */
137  col21 /= g2;
138 
139 
140  /* rate 1 to 2 is both collisions and pumping */
141  /* the total excitation rate from lower to upper, collisional and pumping */
142  rate12 = col12 + t.Emis().pump() + IndirLU;
143 
144  /* include Opacity Project excitations */
145  if( ! lgHFS )
146  ionbal.ExcitationGround[nelem-1][ion-1] += rate12;
147 
148  /* induced emissions down */
149  ri21 = (t.Emis().pump()+IndirLU)*g1/g2;
150 
151  /* this is the ratio of lower to upper level populations */
152  r = (a21 + col21 + ri21)/rate12;
153 
154  /* upper level pop */
155  pfs2 = AbunxIon/(r + 1.);
156  atoms.PopLevels[1] = pfs2;
157  (*t.Hi()).Pop() = pfs2;
158 
159  /* pop of ground */
160  pfs1 = pfs2*r;
161  atoms.PopLevels[0] = pfs1;
162 
163  /* compute ratio Aul/(Aul+Cul) */
164  /* level population with correction for stimulated emission */
165  (*t.Lo()).Pop() = atoms.PopLevels[0];
166 
167 
168  t.Emis().PopOpc() = (atoms.PopLevels[0] - atoms.PopLevels[1]*g1/g2 );
169 
170  /* departure coef of excited state rel to ground */
171  atoms.DepLTELevels[0] = 1.;
172  if( boltz > 1e-20 && atoms.PopLevels[1] > 1e-20 )
173  {
174  /* this line could have zero boltz factor but radiatively excited
175  * dec alpha does not obey () in fast mode?? */
177  (boltz*g2/g1);
178  }
179  else
180  {
181  atoms.DepLTELevels[1] = 0.;
182  }
183 
184 
185  /* number of escaping line photons, used elsewhere for outward beam
186  * and line intensity */
187  set_xIntensity( t );
188 
189 
190  /* ratio of collisional to total (collisional + pumped) excitation */
191  t.Emis().ColOvTot() = (col12 + IndirLU) /rate12;
192 
193 
194  /* two cases - collisionally excited (usual case) or
195  * radiatively excited - in which case line can be a heat source
196  * following are correct heat exchange, they will mix to get correct deriv
197  * the sum of heat-cool will add up to EnrUL - EnrLU - this is a trick to
198  * keep stable solution by effectively dividing up heating and cooling,
199  * so that negative cooling does not occur */
200 
201  //double Enr12 = plower*col12*t.EnergyErg;
202  //double Enr21 = pfs2*col21*t.EnergyErg;
203 
204  /* energy exchange due to this level
205  * net cooling due to excit minus part of de-excit -
206  * note that ColOvTot cancels out in the sum heat - cool */
207  //coolng = Enr12 - Enr21*t.Emis().ColOvTot();
208 
209  /* this form of coolng is guaranteed to be non-negative */
210  //coolng = t.EnergyErg()*AbunxIon*col12*(a21 + ri21)/(a21 + col21 + ri21 + rate12);
211  coolng = t.EnergyErg()*(pfs1*col12-pfs2*col21);
212  //ASSERT( coolng >= 0. );
213 
214  t.Coll().cool() = MAX2(0.,coolng);
215 
216  /* net heating is remainder */
217  //t.Coll().heat() = t.EnergyErg()*AbunxIon*col21*(t.Emis().pump())/(a21 + col21 + ri21 + rate12);
218  t.Coll().heat() = MAX2(0.,-coolng);
219 
220  /* expression pre jul 3 95, changed for case where line heating dominates
221  * coolng = (plower*col12 - pfs2*col21)*t.t(ipLnEnrErg)
222  * t.t(ipLnCool) = cooling */
223 
224  /* add to cooling - heating part was taken out above,
225  * and is not added in here - it will be added to thermal.heating(0,22)
226  * in CoolSum */
227  CoolAdd( chIonLbl(t).c_str(), t.WLAng() , t.Coll().cool());
228  thermal.elementcool[nelem-1] += MAX2( 0., t.Coll().cool() );
229 
230  /* derivative of cooling function */
231  thermal.dCooldT += coolng * (t.EnergyK() * thermal.tsq1 - thermal.halfte );
232  return;
233 }
234 
235 
236 
237 void atom_level2( const TransitionProxy &t )
238 {
239  atom_level2( t, false );
240 
241  return;
242 }
void CoolAdd(const char *chLabel, realnum lambda, double cool)
Definition: cool_etc.cpp:13
vector< double, allocator_avx< double > > ContBoltz
Definition: rfield.h:124
double & ots() const
Definition: emission.h:700
t_thermal thermal
Definition: thermal.cpp:6
string chIonLbl(const TransitionProxy &t)
Definition: transition.cpp:233
realnum EnergyErg() const
Definition: transition.h:90
void set_xIntensity(const TransitionProxy &t)
double cdsqte
Definition: dense.h:246
double DepLTELevels[LIMLEVELN+1]
Definition: atoms.h:141
t_phycon phycon
Definition: phycon.cpp:6
sys_float sexp(sys_float x)
Definition: service.cpp:999
realnum EnergyK() const
Definition: transition.h:85
t_dense dense
Definition: global.cpp:15
double ** ExcitationGround
Definition: ionbal.h:124
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:135
t_ionbal ionbal
Definition: ionbal.cpp:8
void atom_level2(const TransitionProxy &t, const bool lgHFS)
Definition: atom_level2.cpp:30
double & heat() const
Definition: collision.h:224
double tsq1
Definition: thermal.h:142
double & xIntensity() const
Definition: emission.h:540
realnum Ploss() const
Definition: emission.h:130
EmissionList::reference Emis() const
Definition: transition.h:447
t_rfield rfield
Definition: rfield.cpp:9
long & ipCont() const
Definition: transition.h:489
t_atoms atoms
Definition: atoms.cpp:5
qList::iterator Hi() const
Definition: transition.h:435
double halfte
Definition: thermal.h:142
#define ASSERT(exp)
Definition: cddefines.h:613
qList::iterator Lo() const
Definition: transition.h:431
realnum & col_str() const
Definition: collision.h:191
CollisionProxy Coll() const
Definition: transition.h:463
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
double & cool() const
Definition: collision.h:220
double & PopOpc() const
Definition: emission.h:670
double elementcool[LIMELM+1]
Definition: thermal.h:111
#define MAX2(a, b)
Definition: cddefines.h:824
double & ColOvTot() const
Definition: emission.h:630
double & xObsIntensity() const
Definition: emission.h:545
double te
Definition: phycon.h:21
double dCooldT
Definition: thermal.h:139
double PopLevels[LIMLEVELN+1]
Definition: atoms.h:141
realnum & Aul() const
Definition: emission.h:690
realnum & WLAng() const
Definition: transition.h:468
double & pump() const
Definition: emission.h:530