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