cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rt_continuum.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 /*RT_continuum attenuation of diffuse and beamed continua */
4 /*pnegopc save negative opacities on io unit, iff 'set negopc' command was given */
5 #include "cddefines.h"
6 #include "rt.h"
7 #include "rfield.h"
8 #include "opacity.h"
9 #include "dense.h"
10 #include "geometry.h"
11 #include "trace.h"
12 #include "radius.h"
13 #include "iso.h"
14 #include "hextra.h"
15 #include "mole.h"
16 #include "freebound.h"
17 #include "cosmology.h"
18 #include "vectorize.h"
19 
20 /*cmshft - so Compton scattering shift of spectrum
21  * this code is a placeholder */
22 STATIC void cmshft(void)
23 {
24  DEBUG_ENTRY( "cmshft()" );
25 
26  /* first check whether Compton scattering is in as heat/cool */
27  if( !rfield.lgComptonOn )
28  {
29  return;
30  }
31 
32  if( rfield.lgComptonOn )
33  {
34  return;
35  }
36 
37  /* do reshuffle */
38  for( long i=0; i < rfield.nflux; i++ )
39  {
40  continue;
41  }
42  return;
43 }
44 
45 
46 #if !defined(NDEBUG)
47 /*pnegopc save negative opacities on io unit, iff 'set negopc' command was given */
48 STATIC void pnegopc(void)
49 {
50  FILE *ioFile;
51 
52  DEBUG_ENTRY( "pnegopc()" );
53 
54  if( opac.lgNegOpacIO )
55  {
56  /* option to save negative opacities */
57  ioFile = open_data( "negopc.txt", "w" );
58  for( long i=0; i < rfield.nflux; i++ )
59  {
60  fprintf( ioFile, "%10.2e %10.2e \n", rfield.anu(i),
61  opac.opacity_abs[i] );
62  }
63  fclose( ioFile);
64  }
65  return;
66 }
67 #endif
68 
69 /*RT_continuum attenuation of diffuse and beamed continua */
70 void RT_continuum(void)
71 {
72  DEBUG_ENTRY( "RT_continuum()" );
73 
74  if( trace.lgTrace && trace.lgConBug )
75  {
76  fprintf( ioQQQ, " Energy, flux, OTS:\n" );
77  for( long i=0; i < rfield.nflux; i++ )
78  {
79  fprintf( ioQQQ, "%6ld%10.2e%10.2e%10.2e", i, rfield.anu(i),
80  rfield.flux[0][i] + rfield.outlin[0][i] + rfield.ConInterOut[i],
82  }
83  fprintf( ioQQQ, "\n" );
84  }
85 
86  /* begin sanity check in debug mode */
87 # if !defined(NDEBUG)
88  bool lgFlxNeg = false;
89  for( long i=0; i < rfield.nflux; i++ )
90  {
91  if( rfield.flux[0][i] < 0. )
92  {
93  fprintf( ioQQQ, " radius_increment finds negative intensity in flux.\n" );
94  fprintf( ioQQQ, " Intensity, frequency, pointer=%11.3e%11.3e%6ld\n",
95  rfield.flux[0][i], rfield.anu(i), i );
96  lgFlxNeg = true;
97  }
98  if( rfield.otscon[i] < 0. )
99  {
100  fprintf( ioQQQ, " radius_increment finds negative intensity in otscon.\n" );
101  fprintf( ioQQQ, " Intensity, frequency, pointer=%11.3e%11.3e%6ld\n",
102  rfield.otscon[i], rfield.anu(i), i );
103  lgFlxNeg = true;
104  }
105  if( opac.tmn[i] < 0. )
106  {
107  fprintf( ioQQQ, " radius_increment finds negative tmn.\n" );
108  fprintf( ioQQQ, " value, frequency, pointer=%11.3e%11.3e%6ld %4.4s\n",
109  opac.tmn[i], rfield.anu(i), i, rfield.chLineLabel[i].c_str() );
110  lgFlxNeg = true;
111  }
112  if( rfield.otslin[i] < 0. )
113  {
114  fprintf( ioQQQ, " radius_increment finds negative intensity in otslin.\n" );
115  fprintf( ioQQQ, " Intensity, frequency, pointer=%11.3e%11.3e%6ld %4.4s\n",
116  rfield.otslin[i], rfield.anu(i), i, rfield.chLineLabel[i].c_str() );
117  lgFlxNeg = true;
118  }
119  if( rfield.outlin[0][i] < 0. )
120  {
121  fprintf( ioQQQ, " radius_increment finds negative intensity in outlin.\n" );
122  fprintf( ioQQQ, " Intensity, frequency, pointer=%11.3e%11.3e%6ld %4.4s\n",
123  rfield.outlin[0][i], rfield.anu(i), i, rfield.chLineLabel[i].c_str() );
124  lgFlxNeg = true;
125  }
126  if( rfield.ConInterOut[i] < 0. )
127  {
128  fprintf( ioQQQ, " radius_increment finds negative intensity in ConInterOut.\n" );
129  fprintf( ioQQQ, " Intensity, frequency, pointer=%11.3e%11.3e%6ld %4.4s\n",
130  rfield.ConInterOut[i], rfield.anu(i), i, rfield.chContLabel[i].c_str() );
131  lgFlxNeg = true;
132  }
133  if( opac.opacity_abs[i] < 0. )
134  {
135  opac.lgOpacNeg = true;
136  /* this sub will save negative opacities on io unit,
137  * iff 'set negopc' command was given */
138  pnegopc();
139  }
140  }
141  if( lgFlxNeg )
142  {
143  fprintf( ioQQQ, " Insanity has occurred, this is zone%4ld\n",
144  nzone );
145  ShowMe();
147  }
148  /*end sanity check*/
149 # endif
150 
151  // ratio of inner to outer radii, at this point
152  // radius is the outer radius of this zone
153  double DilutionHere = POW2((radius.Radius - radius.drad*radius.dRadSign)/
154  radius.Radius);
155 
156  rfield.EnergyIncidCont = 0.;
157  rfield.EnergyDiffCont = 0.;
158 
159  // attenuation of flux by optical depths IN THIS ZONE
160  // DirectionalCosin is 1/COS(theta), is usually 1, reset with illuminate command,
161  // option for illumination of slab at an angle
163  for( long i=0; i < rfield.nflux; i++ )
164  rfield.vexp_arg[i] = -opac.opacity_abs[i]*fac;
166  // this loop should not be to <= nflux since highest cell is for
167  // continuum unit integration
168  // scattering opacities are included in energy exchange here in the
169  // sphere case, since photons diffuse out of the closed sphere.
170  // scattering opacities are not included as extinction sources in the
171  // sphere case
172  for( long i=0; i < rfield.nflux; i++ )
173  {
174  if( cosmology.lgDo )
175  {
176  opac.TauAbsGeo[0][i] = 0.;
177  opac.TauScatGeo[0][i] = 0.;
178  opac.TauAbsFace[i] = 0.;
179  opac.TauScatFace[i] = 0.;
180  }
181 
182  double dTau_abs = opac.opacity_abs[i]*radius.drad_x_fillfac;
183  double dTau_sct = opac.opacity_sct[i]*radius.drad_x_fillfac;
184 
185  // sum total continuous optical depths
186  opac.TauAbsGeo[0][i] += (realnum)(dTau_abs);
187  opac.TauScatGeo[0][i] += (realnum)(dTau_sct);
188 
189  // following only optical depth to illuminated face
190  opac.TauAbsFace[i] += (realnum)(dTau_abs);
191  opac.TauScatFace[i] += (realnum)(dTau_sct);
192 
193  // these are total in inward direction, large if spherical
194  opac.TauTotalGeo[0][i] = opac.TauAbsGeo[0][i] + opac.TauScatGeo[0][i];
195 
196  // e(-tau) in inward direction, up to illuminated face
197  opac.ExpmTau[i] *= (realnum)opac.ExpZone[i];
198 
199  // e2(tau) in inward direction, up to illuminated face
201  ASSERT( opac.E2TauAbsFace[i] <= 1. && opac.E2TauAbsFace[i] >= 0. );
202 
203  // on second and later iterations define outward E2
204  if( iteration > 1 )
205  {
206  // e2 from current position to outer edge of shell
208  opac.E2TauAbsOut[i] = (realnum)e2( tau );
209  ASSERT( opac.E2TauAbsOut[i]>=0. && opac.E2TauAbsOut[i]<=1. );
210  }
211 
212  // DilutionHere is square of ratio of inner to outer radius
213  double AttenuationDilutionFactor = opac.ExpZone[i]*DilutionHere;
214  ASSERT( AttenuationDilutionFactor <= 1.0 );
215 
216  // continuum has three parts
217  rfield.flux_beam_const[i] *= (realnum)AttenuationDilutionFactor;
218  rfield.flux_beam_time[i] *= (realnum)AttenuationDilutionFactor;
219  rfield.flux_isotropic[i] *= (realnum)AttenuationDilutionFactor;
222 
223  // update SummedCon here since flux changed
224  rfield.SummedCon[i] = rfield.flux[0][i] + rfield.SummedDif[i];
226 
227  // outward lines and diffuse continua
228  rfield.outlin[0][i] *= (realnum)AttenuationDilutionFactor;
229  rfield.outlin_noplot[i] *= (realnum)AttenuationDilutionFactor;
230 
231  // interactive outward diffuse continuum
232  // This fixit() originally was a call to TestCode() and was merged from the rt branch.
233  // The rt branch was subsequently modified, apparantly to fix the problem mentioned below.
234  // These changes on the rt branch seem to have never been merged to the trunk.
235  // See also the mail on cloudy-dev "!Test code is in place." dated 2016-02-10 09:34 UTC
236  fixit("moved from rt_diffuse; this preserves the original order of the next 2 lines and is incorrect");
238  rfield.ConInterOut[i] *= (realnum)AttenuationDilutionFactor;
239 
240  // this is not the interacting continuum
241  rfield.ConEmitOut[0][i] *= (realnum)AttenuationDilutionFactor;
243 
244  // set occupation numbers, first attenuated incident continuum
246 
247  // local diffuse continua
249 
250  // outward diffuse continuum
252 
253  // integrated energy flux, ergs s^-1 cm^-2
256  rfield.ConInterOut[i])* rfield.anu(i);
257  }
258 
260 
261  // convert Ryd to erg
262  rfield.EnergyIncidCont *= (realnum)EN1RYD;
263  rfield.EnergyDiffCont *= (realnum)EN1RYD;
264 
265  // sanity check, compare total Lyman continuum optical depth
266  // with amount of extinction there
267  // this is amount continuum attenuated to illuminated face,
268  // but only do test if flux positive, not counting scattering opacity,
269  // and correction for spherical dilution not important
270  if( rfield.flux[0][iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]>SMALLFLOAT &&
271  (rfield.flux[0][iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]/
272  SDIV(rfield.flux_total_incident[0][iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]) ) > SMALLFLOAT &&
273  !opac.lgScatON &&
274  radius.depth/radius.Radius < 1e-4 )
275  {
276  // ratio of current to incident continuum, converted to optical depth
277  /* >>chng 99 apr 23, this crashed on alpha due to underflow to zero in argy
278  * to log. defended two ways - above checks that ratio of fluxes is large enough,
279  * and here convert to double.
280  * error found by Peter van Hoof */
281  double tau_effec = -log((double)rfield.flux[0][iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]/
282  (double)opac.tmn[iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]/
283  (double)rfield.flux_total_incident[0][iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]);
284 
285  // this is computed absorption optical depth to illuminated face
286  double tau_true = opac.TauAbsFace[iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]*geometry.DirectionalCosin;
287 
288  // first test is relative error, second is to absolute error and comes
289  // in for very small tau, where differences are in the round-off
290  if( fabs( tau_effec - tau_true ) / MAX2(tau_effec , tau_true) > 0.01 &&
291  // for very small inner optical depths, the tmn correction is major,
292  // and this test is not precise
293  fabs(tau_effec-tau_true)>MAX2(0.001,1.-opac.tmn[iso_sp[ipH_LIKE][ipHYDROGEN].fb[0].ipIsoLevNIonCon-1]) )
294  {
295  // in print below must add extra HI col den since this will later be
296  // incremented in RT_tau_inc
297  fprintf( ioQQQ,
298  " PROBLEM radius_increment Lyman continuum insanity zone %li, effective tau=%g, atomic tau=%g simple tau=%g\n",
299  nzone,
300  tau_effec ,
301  tau_true ,
303  TotalInsanity();
304  }
305  }
306 
307  // do scattering opacity, not included when sphere is set
308  if( opac.lgScatON )
309  {
310  for( long i=0; i < rfield.nflux; i++ )
311  {
312  // Lightman and White equation 11 in small epsilon limit,
313  // >>refer continuum RT Lightman, A.P., & White, T.R. 1988, ApJ, 335, 57 */
314  double AttenuationScatteringFactor = 1./(1. + radius.drad_x_fillfac*opac.opacity_sct[i]);
315  ASSERT( AttenuationScatteringFactor <= 1.0 );
316  rfield.flux_beam_const[i] *= (realnum)AttenuationScatteringFactor;
317  rfield.flux_beam_time[i] *= (realnum)AttenuationScatteringFactor;
318  rfield.flux_isotropic[i] *= (realnum)AttenuationScatteringFactor;
321 
322  rfield.ConInterOut[i] *= (realnum)AttenuationScatteringFactor;
323  rfield.ConEmitOut[0][i] *= (realnum)AttenuationScatteringFactor;
324  rfield.outlin[0][i] *= (realnum)AttenuationScatteringFactor;
325  rfield.outlin_noplot[i] *= (realnum)AttenuationScatteringFactor;
326  }
327  }
328 
329  // this dilution is needed to conserve volume in spherical models. tests such
330  // as parispn.in will fault if this is removed
332 
333  // this is a unit of energy that will be passed through the code as a test
334  // that all integrations are carried out. A similar test is set in lineset1
335  // and verified in PrtFinal. The opacity at this cell is zero so only
336  // geometrical dilution will affect the integral
337  // Radius is currently outer edge of zone, so radius-drad/2 is radius
338  // of center of zone
339  rfield.ConEmitLocal[nzone][rfield.nflux] = 1.e-10f * Dilution;
340  rfield.DiffuseEscape[rfield.nflux] = 1.e-10f * Dilution;
341  // must do unit integration somewhere
344 
345  // opacity should be zero at this energy so J not changed elsewhere
346  ASSERT( opac.opacity_abs[rfield.nflux] == 0. );
347 
348  // placeholder code for Compton scattering
349  cmshft();
350 
351  // attenuate neutrons if they are present
352  if( hextra.lgNeutrnHeatOn )
353  {
354  // correct for optical depth effects
357  // correct for spherical effects
358  hextra.totneu *= (realnum)DilutionHere;
359  }
360 
361  // following radiation factors are extinguished by 1/r**2ilution, electron
362  // scattering by free and bound electrons
363 
364  // do all emergent spectrum from illuminated face if model is NOT spherical
365  if( !geometry.lgSphere )
366  {
367  double Reflec_Diffuse_Cont;
368 
369  // emission starting at the the plasma frequency
370  for( long i=rfield.ipPlasma-1; i < rfield.nflux; i++ )
371  {
372  if( opac.TauAbsGeo[0][i] < 30. )
373  {
374  // ConEmitLocal is diffuse emission per unit vol, fill factor
375  // the 1/2 comes from isotropic emission
376  Reflec_Diffuse_Cont = rfield.ConEmitLocal[nzone][i]/2.*
378 
379  // ConEmitReflec - reflected diffuse continuum
380  rfield.ConEmitReflec[0][i] += (realnum)(Reflec_Diffuse_Cont);
381 
382  // the reflected part of the incident continuum
383  rfield.ConRefIncid[0][i] += (realnum)(rfield.flux[0][i]*opac.opacity_sct[i]*
385 
386  // reflected line emission
387  rfield.reflin[0][i] += (realnum)(rfield.outlin[0][i]*opac.opacity_sct[i]*
389  }
390  }
391  }
392  return;
393 }
double Radius
Definition: radius.h:31
double depth
Definition: radius.h:31
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:765
vector< double, allocator_avx< double > > vexp_arg
Definition: rfield.h:131
realnum * flux_isotropic
Definition: rfield.h:71
double * opacity_abs
Definition: opacity.h:104
void setTrimming()
Definition: rfield.cpp:92
T * get_ptr(T *v)
Definition: cddefines.h:1109
NORETURN void TotalInsanity(void)
Definition: service.cpp:971
t_opac opac
Definition: opacity.cpp:5
realnum ** flux
Definition: rfield.h:68
vector< string > chContLabel
Definition: rfield.h:213
realnum * DiffuseEscape
Definition: rfield.h:174
const realnum SMALLFLOAT
Definition: cpu.h:246
realnum * outlin_noplot
Definition: rfield.h:189
realnum ** flux_total_incident
Definition: rfield.h:199
t_hextra hextra
Definition: hextra.cpp:5
bool lgNeutrnHeatOn
Definition: hextra.h:81
realnum * OccNumbContEmitOut
Definition: rfield.h:62
double * SummedCon
Definition: rfield.h:161
bool lgScatON
Definition: opacity.h:196
realnum * SummedOcc
Definition: rfield.h:163
sys_float sexp(sys_float x)
Definition: service.cpp:999
realnum ** outlin
Definition: rfield.h:189
FILE * ioQQQ
Definition: cddefines.cpp:7
double * opacity_sct
Definition: opacity.h:107
molezone * findspecieslocal(const char buf[])
long int nzone
Definition: cddefines.cpp:14
realnum * TauScatFace
Definition: opacity.h:100
vector< freeBound > fb
Definition: iso.h:481
bool lgDo
Definition: cosmology.h:44
double anu(size_t i) const
Definition: mesh.h:120
bool lgNegOpacIO
Definition: opacity.h:199
t_dense dense
Definition: global.cpp:15
bool lgOpacNeg
Definition: opacity.h:192
double CrsSecNeutron
Definition: hextra.h:87
t_iso_sp iso_sp[NISO][LIMELM]
Definition: iso.cpp:11
void vexp(const double x[], double y[], long nlo, long nhi)
realnum EnergyIncidCont
Definition: rfield.h:467
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:135
bool lgSphere
Definition: geometry.h:34
long int iteration
Definition: cddefines.cpp:16
realnum * otslin
Definition: rfield.h:183
t_trace trace
Definition: trace.cpp:5
STATIC void pnegopc(void)
double drad
Definition: radius.h:31
double rinner
Definition: radius.h:31
realnum ** ConEmitLocal
Definition: rfield.h:139
t_geometry geometry
Definition: geometry.cpp:5
bool lgConBug
Definition: trace.h:97
#define POW2
Definition: cddefines.h:979
#define STATIC
Definition: cddefines.h:118
bool lgTrace
Definition: trace.h:12
long int ipPlasma
Definition: rfield.h:436
realnum ** TauScatGeo
Definition: opacity.h:92
void RT_continuum(void)
realnum * E2TauAbsOut
Definition: opacity.h:140
t_rfield rfield
Definition: rfield.cpp:9
realnum * convoc
Definition: rfield.h:113
realnum * ConInterOut
Definition: rfield.h:154
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
realnum * otscon
Definition: rfield.h:183
#define cdEXIT(FAIL)
Definition: cddefines.h:482
realnum DirectionalCosin
Definition: geometry.h:25
realnum * TauAbsFace
Definition: opacity.h:100
realnum * OccNumbIncidCont
Definition: rfield.h:117
double column(const genericState &gs)
vector< string > chLineLabel
Definition: rfield.h:210
t_radius radius
Definition: radius.cpp:5
double dRadSign
Definition: radius.h:74
realnum * TauAbsTotal
Definition: opacity.h:142
realnum ** reflin
Definition: rfield.h:196
realnum ** ConEmitOut
Definition: rfield.h:151
realnum totneu
Definition: hextra.h:79
realnum gas_phase[LIMELM]
Definition: dense.h:76
double dVolOutwrd
Definition: radius.h:103
realnum ** TauTotalGeo
Definition: opacity.h:96
#define ASSERT(exp)
Definition: cddefines.h:613
const int ipH_LIKE
Definition: iso.h:64
T pow2(T a)
Definition: cddefines.h:981
double drad_x_fillfac
Definition: radius.h:77
vector< double, allocator_avx< double > > ExpZone
Definition: opacity.h:133
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
realnum * E2TauAbsFace
Definition: opacity.h:137
t_cosmology cosmology
Definition: cosmology.cpp:8
realnum * OccNumbDiffCont
Definition: rfield.h:120
STATIC void cmshft(void)
realnum EnergyDiffCont
Definition: rfield.h:467
realnum ** TauAbsGeo
Definition: opacity.h:91
#define MAX2(a, b)
Definition: cddefines.h:824
realnum * ExpmTau
Definition: opacity.h:145
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
realnum * SummedDif
Definition: rfield.h:162
double e2(double x)
sys_float SDIV(sys_float x)
Definition: cddefines.h:1002
#define fixit(a)
Definition: cddefines.h:417
realnum * tmn
Definition: opacity.h:149
realnum ** ConEmitReflec
Definition: rfield.h:145
realnum * flux_beam_time
Definition: rfield.h:74
double r1r0sq
Definition: radius.h:31
void ShowMe(void)
Definition: service.cpp:205
realnum * flux_beam_const
Definition: rfield.h:74
const int ipHYDROGEN
Definition: cddefines.h:349
long int nflux
Definition: rfield.h:46
realnum ** ConRefIncid
Definition: rfield.h:157
bool lgComptonOn
Definition: rfield.h:279