cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
energy.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 
4 #include "cddefines.h"
5 #include "continuum.h"
6 #include "rfield.h"
7 #include "doppvel.h"
8 #include "geometry.h"
9 #include "hextra.h"
10 #include "ipoint.h"
11 #include "lines.h"
12 #include "opacity.h"
13 #include "radius.h"
14 #include "secondaries.h"
15 #include "struc.h"
16 #include "thermal.h"
17 #include "warnings.h"
18 #include "wind.h"
19 #include "dynamics.h"
20 #include "lines_service.h"
21 
22 static const char *ENERGY_RYD = "Ryd";
23 static const char *ENERGY_ERG = "erg";
24 static const char *ENERGY_EV = "eV";
25 static const char *ENERGY_KEV = "keV";
26 static const char *ENERGY_MEV = "MeV";
27 static const char *ENERGY_WN = "cm^-1";
28 static const char *ENERGY_CM = "cm";
29 static const char *ENERGY_MM = "mm";
30 static const char *ENERGY_MICRON = "um";
31 static const char *ENERGY_NM = "nm";
32 static const char *ENERGY_A = "A";
33 static const char *ENERGY_HZ = "Hz";
34 static const char *ENERGY_KHZ = "kHz";
35 static const char *ENERGY_MHZ = "MHz";
36 static const char *ENERGY_GHZ = "GHz";
37 static const char *ENERGY_K = "K";
38 
39 inline bool isSameUnit(const char *unit, const char *ref)
40 {
41  return strcmp(unit,ref) == 0;
42 }
43 
44 const char *StandardEnergyUnit(const char *chCard)
45 {
46  DEBUG_ENTRY( "StandardEnergyUnit()" );
47 
48  // use " MIC" so that it cannot pick up on "W/SQM/MICRON" in flux units
49  if( nMatch(" MIC",chCard) )
50  {
51  /* micron */
52  return ENERGY_MICRON;
53  }
54  else if( nMatch(" EV ",chCard) )
55  {
56  /* eV */
57  return ENERGY_EV;
58  }
59  else if( nMatch(" KEV",chCard) )
60  {
61  /* keV */
62  return ENERGY_KEV;
63  }
64  else if( nMatch(" MEV",chCard) )
65  {
66  /* MeV */
67  return ENERGY_MEV;
68  }
69  else if( nMatch("WAVE",chCard) )
70  {
71  /* wavenumbers */
72  return ENERGY_WN;
73  }
74  else if( nMatch("CENT",chCard) || nMatch(" CM ",chCard) )
75  {
76  /* centimeter */
77  return ENERGY_CM;
78  }
79  else if( nMatch(" MM ",chCard) )
80  {
81  /* millimeter */
82  return ENERGY_MM;
83  }
84  else if( nMatch(" NM ",chCard) )
85  {
86  /* nanometer */
87  return ENERGY_NM;
88  }
89  else if( nMatch("ANGS",chCard) )
90  {
91  /* angstrom */
92  return ENERGY_A;
93  }
94  else if( nMatch(" HZ ",chCard) )
95  {
96  /* hertz */
97  return ENERGY_HZ;
98  }
99  else if( nMatch(" KHZ",chCard) )
100  {
101  /* kilohertz */
102  return ENERGY_KHZ;
103  }
104  else if( nMatch(" MHZ",chCard) )
105  {
106  /* megahertz */
107  return ENERGY_MHZ;
108  }
109  else if( nMatch(" GHZ",chCard) )
110  {
111  /* gigahertz */
112  return ENERGY_GHZ;
113  }
114  else if( nMatch("KELV",chCard) || nMatch(" K ",chCard) )
115  {
116  /* kelvin */
117  return ENERGY_K;
118  }
119  else if( nMatch(" RYD",chCard) )
120  {
121  /* RydbERG must come before ERG to avoid false trip */
122  return ENERGY_RYD;
123  }
124  // use "ERG " so that it cannot pick up on "ERG/S" in flux units
125  else if( nMatch(" ERG ",chCard) )
126  {
127  /* erg */
128  return ENERGY_ERG;
129  }
130  else
131  {
132  fprintf( ioQQQ, " No energy / wavelength unit was recognized on this line:\n %s\n\n", chCard );
133  fprintf( ioQQQ, " See Hazy for details.\n" );
135  }
136 }
137 
138 double Energy::get(const char *unit) const
139 {
140  DEBUG_ENTRY( "Energy::get()" );
141 
142  /* internal unit is Ryd */
143  if( isSameUnit(unit,ENERGY_RYD) )
144  {
145  return Ryd();
146  }
147  else if( isSameUnit(unit,ENERGY_ERG) )
148  {
149  return Erg();
150  }
151  else if( isSameUnit(unit,ENERGY_EV) )
152  {
153  return eV();
154  }
155  else if( isSameUnit(unit,ENERGY_KEV) )
156  {
157  return keV();
158  }
159  else if( isSameUnit(unit,ENERGY_MEV) )
160  {
161  return MeV();
162  }
163  else if( isSameUnit(unit,ENERGY_WN) )
164  {
165  return WN();
166  }
167  else if( isSameUnit(unit,ENERGY_CM) )
168  {
169  return cm();
170  }
171  else if( isSameUnit(unit,ENERGY_MM) )
172  {
173  return mm();
174  }
175  else if( isSameUnit(unit,ENERGY_MICRON) )
176  {
177  return micron();
178  }
179  else if( isSameUnit(unit,ENERGY_NM) )
180  {
181  return nm();
182  }
183  else if( isSameUnit(unit,ENERGY_A) )
184  {
185  return Angstrom();
186  }
187  else if( isSameUnit(unit,ENERGY_HZ) )
188  {
189  return Hz();
190  }
191  else if( isSameUnit(unit,ENERGY_KHZ) )
192  {
193  return kHz();
194  }
195  else if( isSameUnit(unit,ENERGY_MHZ) )
196  {
197  return MHz();
198  }
199  else if( isSameUnit(unit,ENERGY_GHZ) )
200  {
201  return GHz();
202  }
203  else if( isSameUnit(unit,ENERGY_K) )
204  {
205  return K();
206  }
207  else
208  {
209  fprintf( ioQQQ, " insane units in Energy::get: \"%s\"\n", unit );
211  }
212 }
213 
214 void Energy::set(double value, const char *unit)
215 {
216  DEBUG_ENTRY( "Energy::set()" );
217 
218  /* internal unit is Ryd */
219  if( isSameUnit(unit,ENERGY_RYD) )
220  {
221  set(value);
222  }
223  else if( isSameUnit(unit,ENERGY_ERG) )
224  {
225  set(value/EN1RYD);
226  }
227  else if( isSameUnit(unit,ENERGY_MEV) )
228  {
229  set(1e6*value/EVRYD);
230  }
231  else if( isSameUnit(unit,ENERGY_KEV) )
232  {
233  set(1e3*value/EVRYD);
234  }
235  else if( isSameUnit(unit,ENERGY_EV) )
236  {
237  set(value/EVRYD);
238  }
239  else if( isSameUnit(unit,ENERGY_WN) )
240  {
241  set(value/RYD_INF);
242  }
243  else if( isSameUnit(unit,ENERGY_A) )
244  {
245  set(RYDLAM/value);
246  }
247  else if( isSameUnit(unit,ENERGY_NM) )
248  {
249  set(RYDLAM/(1.e1*value));
250  }
251  else if( isSameUnit(unit,ENERGY_MICRON) )
252  {
253  set(RYDLAM/(1.e4*value));
254  }
255  else if( isSameUnit(unit,ENERGY_MM) )
256  {
257  set(RYDLAM/(1.e7*value));
258  }
259  else if( isSameUnit(unit,ENERGY_CM) )
260  {
261  set(RYDLAM/(1.e8*value));
262  }
263  else if( isSameUnit(unit,ENERGY_HZ) )
264  {
265  set(value/FR1RYD);
266  }
267  else if( isSameUnit(unit,ENERGY_KHZ) )
268  {
269  set(1e3*value/FR1RYD);
270  }
271  else if( isSameUnit(unit,ENERGY_MHZ) )
272  {
273  set(1e6*value/FR1RYD);
274  }
275  else if( isSameUnit(unit,ENERGY_GHZ) )
276  {
277  set(1e9*value/FR1RYD);
278  }
279  else if( isSameUnit(unit,ENERGY_K) )
280  {
281  set(value/TE1RYD);
282  }
283  else
284  {
285  fprintf( ioQQQ, " insane units in Energy::set: \"%s\"\n", unit );
287  }
288 }
289 
291 {
292  DEBUG_ENTRY( "EnergyEntry::p_set_ip()" );
293 
294  double energy = Ryd();
295  if( energy < rfield.emm() || energy > rfield.egamry() )
296  {
297  fprintf( ioQQQ, " The energy %g Ryd is not within the default Cloudy range\n", energy );
299  }
300  p_ip = ipoint(energy) - 1;
301  ASSERT( p_ip >= 0 );
302 }
303 
304 STATIC double sum_radiation( void );
305 
306 /*badprt print out coolants if energy not conserved */
307 STATIC void badprt(
308  /* total is total luminosity available in radiation */
309  double total);
310 
312 {
313  double outin,
314  outout,
315  outtot,
316  sum_coolants,
317  sum_recom_lines,
318  flow_energy;
319 
320  char chLine[INPUT_LINE_LENGTH];
321 
322  DEBUG_ENTRY( "lgConserveEnergy()" );
323 
324  /* check whether energy is conserved
325  * following is outward continuum */
326  outsum(&outtot,&outin,&outout);
327  /* sum_recom_lines is the sum of all recombination line energy */
328  sum_recom_lines = totlin('r');
329  if( sum_recom_lines == 0. )
330  {
331  sprintf( chLine, " !Total recombination line energy is 0." );
332  bangin(chLine);
333  }
334 
335  /* sum_coolants is the sum of all coolants */
336  sum_coolants = totlin('c');
337  if( sum_coolants == 0. )
338  {
339  sprintf( chLine, " !Total cooling is zero." );
340  bangin(chLine);
341  }
342 
343  if( !(wind.lgBallistic() || wind.lgStatic()) )
344  {
345  /* approximate energy density coming out in wind
346  * should ideally include flow into grid and internal energies */
347  flow_energy = (2.5*struc.GasPressure[0]+0.5*struc.DenMass[0]*wind.windv0*wind.windv0)
348  *(-wind.windv0);
349  }
350  else
351  {
352  flow_energy = 0.;
353  }
354 
356  (hextra.cryden == 0.) && ((hextra.TurbHeat+DoppVel.DispScale) == 0.) && !secondaries.lgCSetOn )
357  {
358  double sum_rad = sum_radiation();
359 
360  if( fabs( 1. - sum_rad/(continuum.TotalLumin*POW2(radius.rinner)) ) > 0.01 )
361  fprintf( ioQQQ, "PROBLEM DISASTER lgConserveEnergy failed %li\t%li\t%e\t%e\t%e\n",
363  sum_rad/(continuum.TotalLumin*POW2(radius.rinner)) );
364  }
365 
366  /* TotalLumin is total incident photon luminosity, evaluated in setup
367  * sum_coolants is evaluated here, is sum of all coolants */
368  /* this test is meaningless when the APERTURE command is in effect since
369  * sum_coolants and sum_recom_lines react to the APERTURE command, while
370  * continuum.TotalLumin does not */
371  if( !dynamics.lgTimeDependentStatic && (sum_coolants + sum_recom_lines + flow_energy) > continuum.TotalLumin*geometry.covgeo &&
373  {
374  if( (hextra.cryden == 0.) && ((hextra.TurbHeat+DoppVel.DispScale) == 0.) && !secondaries.lgCSetOn )
375  {
376 
377  sprintf( chLine,
378  " W-Radiated luminosity (cool+rec+wind=%.2e+%.2e+%.2e) is greater than that in incident radiation (TotalLumin=%8.2e). Power radiated was %8.2e",
379  sum_coolants, sum_recom_lines, flow_energy , continuum.TotalLumin, thermal.power );
380  warnin(chLine);
381  /* write same thing directly to output (above will be sorted later) */
382  fprintf( ioQQQ, "\n\n DISASTER This calculation DID NOT CONSERVE ENERGY!\n\n\n" );
383 
385  fprintf( ioQQQ, "Rerun with *set check energy every zone* command to do energy check for each zone.\n\n");
386 
387  lgAbort = true;
388 
389  /* the case b command can cause this problem - say so if case b was set */
390  if( opac.lgCaseB )
391  fprintf( ioQQQ, "\n The CASE B command was entered - this can have unphysical effects, including non-conservation of energy.\n Why was it needed?\n\n" );
392 
393  /* print out significant heating and cooling */
395 
396  sprintf( chLine, " W-Something is really wrong: the ratio of radiated to incident luminosity is %.2e.",
397  (sum_coolants + sum_recom_lines)/continuum.TotalLumin );
398  warnin(chLine);
399 
400  /* this can be caused by the force te command */
401  if( thermal.ConstTemp > 0. )
402  {
403  fprintf( ioQQQ, " This may have been caused by the FORCE TE command.\n" );
404  fprintf( ioQQQ, " Remove it and run again.\n" );
405  }
406  else
407  return false;
408  }
409  }
410 
411  return true;
412 }
413 
414 STATIC double sum_radiation( void )
415 {
416  double flxref = 0., flxatt = 0., conem = 0.;
417  long nEmType = 0;
418  double sum = 0.;
419 
420  const realnum *trans_coef_total=rfield.getCoarseTransCoef();
421  for( long j=0; j<rfield.nflux; j++ )
422  {
423  /* the reflected continuum */
424  flxref += (rfield.ConRefIncid[nEmType][j] + rfield.ConEmitReflec[nEmType][j] + rfield.reflin[nEmType][j]) * rfield.anu(j);
425  ASSERT( flxref >= 0. );
426 
427  /* the attenuated incident continuum */
428  flxatt += rfield.flux[nEmType][j]*radius.r1r0sq*trans_coef_total[j] * rfield.anu(j);
429  ASSERT( flxatt >= 0. );
430 
431  /* the outward emitted continuum */
432  conem += (rfield.ConEmitOut[nEmType][j] + rfield.outlin[nEmType][j] + rfield.outlin_noplot[j])*radius.r1r0sq*geometry.covgeo * rfield.anu(j);
433  ASSERT( conem >= 0. );
434  }
435 
436  sum = (flxref + flxatt + conem) * EN1RYD * POW2(radius.rinner);
437  ASSERT( sum >= 0. );
438 
439  return sum;
440 }
441 
442 /*badprt print out coolants if energy not conserved */
444  /* total is total luminosity available in radiation */
445  double total)
446 {
447  /* following is smallest ratio to print */
448  static const double RATIO = 0.02;
449  char chInfo;
450  long int i;
451  realnum sum_coolants,
452  sum_recom_lines;
453 
454  DEBUG_ENTRY( "badprt()" );
455 
456  fprintf( ioQQQ, " badprt: all entries with greater than%6.2f%% of incident continuum follow.\n",
457  RATIO*100. );
458  fprintf( ioQQQ, " badprt: Intensities are relative to total energy in incident continuum.\n" );
459 
460  /* now find sum of recombination lines */
461  chInfo = 'r';
462  sum_recom_lines = (realnum)totlin('r');
463  fprintf( ioQQQ,
464  " Sum of energy in recombination lines is %.2e relative to total incident radiation is %.2e\n",
465  sum_recom_lines,
466  sum_recom_lines/MAX2(1e-30,total) );
467 
468  fprintf(ioQQQ," all strong information lines \n line wl ener/total\n");
469  /* now print all strong lines */
470  for( i=0; i < LineSave.nsum; i++ )
471  {
472  if( LineSave.lines[i].chSumTyp() == chInfo && LineSave.lines[i].SumLine(0)/total > RATIO )
473  {
474  fprintf( ioQQQ, " ");
475  LineSave.lines[i].prt(ioQQQ);
476  fprintf( ioQQQ, " %7.3f %c\n", LineSave.lines[i].SumLine(0)/total, chInfo );
477  }
478  }
479 
480  fprintf(ioQQQ," all strong cooling lines \n line wl ener/total\n");
481  chInfo = 'c';
482  sum_coolants = (realnum)totlin('c');
483  fprintf( ioQQQ, " Sum of coolants (abs) = %.2e (rel)= %.2e\n",
484  sum_coolants, sum_coolants/MAX2(1e-30,total) );
485  for( i=0; i < LineSave.nsum; i++ )
486  {
487  if( LineSave.lines[i].chSumTyp() == chInfo && LineSave.lines[i].SumLine(0)/total > RATIO )
488  {
489  fprintf( ioQQQ, " ");
490  LineSave.lines[i].prt(ioQQQ);
491  fprintf( ioQQQ, " %7.3f %c\n", LineSave.lines[i].SumLine(0)/total, chInfo );
492  }
493  }
494 
495  fprintf(ioQQQ," all strong heating lines \n line wl ener/total\n");
496  chInfo = 'h';
497  fprintf( ioQQQ, " Sum of heat (abs) = %.2e (rel)= %.2e\n",
498  thermal.power, thermal.power/MAX2(1e-30,total) );
499  for( i=0; i < LineSave.nsum; i++ )
500  {
501  if( LineSave.lines[i].chSumTyp() == chInfo && LineSave.lines[i].SumLine(0)/total > RATIO )
502  {
503  fprintf( ioQQQ, " ");
504  LineSave.lines[i].prt(ioQQQ);
505  fprintf( ioQQQ, " %7.3f %c\n", LineSave.lines[i].SumLine(0)/total, chInfo );
506  }
507  }
508 
509  return;
510 }
double Hz() const
Definition: energy.h:61
void bangin(const char *chLine)
Definition: warnings.h:90
STATIC double sum_radiation(void)
Definition: energy.cpp:414
double emm() const
Definition: mesh.h:93
double Angstrom() const
Definition: energy.h:77
static const char * ENERGY_MHZ
Definition: energy.cpp:35
static const char * ENERGY_WN
Definition: energy.cpp:27
bool isSameUnit(const char *unit, const char *ref)
Definition: energy.cpp:39
t_thermal thermal
Definition: thermal.cpp:6
double power
Definition: thermal.h:169
static const char * ENERGY_HZ
Definition: energy.cpp:33
t_opac opac
Definition: opacity.cpp:5
long p_ip
Definition: energy.h:107
realnum ** flux
Definition: rfield.h:68
t_struc struc
Definition: struc.cpp:6
double e1(double x)
realnum * outlin_noplot
Definition: rfield.h:189
bool lgCheckEnergyEveryZone
Definition: continuum.h:102
double GHz() const
Definition: energy.h:73
realnum windv0
Definition: wind.h:11
void set(double energy)
Definition: energy.h:26
double keV() const
Definition: energy.h:53
long int iEmissPower
Definition: geometry.h:71
bool lgTimeDependentStatic
Definition: dynamics.h:102
long nMatch(const char *chKey, const char *chCard)
Definition: service.cpp:525
static const char * ENERGY_K
Definition: energy.cpp:37
t_hextra hextra
Definition: hextra.cpp:5
t_LineSave LineSave
Definition: lines.cpp:10
static const char * ENERGY_MEV
Definition: energy.cpp:26
bool lgTemperatureConstant
Definition: thermal.h:44
realnum covgeo
Definition: geometry.h:45
realnum ** outlin
Definition: rfield.h:189
FILE * ioQQQ
Definition: cddefines.cpp:7
long int nzone
Definition: cddefines.cpp:14
t_DoppVel DoppVel
Definition: doppvel.cpp:5
t_dynamics dynamics
Definition: dynamics.cpp:42
static const char * ENERGY_KEV
Definition: energy.cpp:25
double anu(size_t i) const
Definition: mesh.h:120
vector< LinSv > lines
Definition: lines.h:132
STATIC void badprt(double total)
Definition: energy.cpp:443
void warnin(const char *chLine)
Definition: warnings.h:74
realnum * DenMass
Definition: struc.h:25
double cm() const
Definition: energy.h:93
const realnum * getCoarseTransCoef()
Definition: rfield.cpp:56
Wind wind
Definition: wind.cpp:5
bool lgSphere
Definition: geometry.h:34
double WN() const
Definition: energy.h:45
long int iteration
Definition: cddefines.cpp:16
bool lgBallistic(void) const
Definition: wind.h:31
double rinner
Definition: radius.h:31
t_geometry geometry
Definition: geometry.cpp:5
long ipoint(double energy_ryd)
Definition: cont_ipoint.cpp:15
double Erg() const
Definition: energy.h:41
#define POW2
Definition: cddefines.h:979
double energy(const genericState &gs)
static const char * ENERGY_RYD
Definition: energy.cpp:22
#define STATIC
Definition: cddefines.h:118
realnum * GasPressure
Definition: struc.h:25
bool lgConserveEnergy()
Definition: energy.cpp:311
static const char * ENERGY_A
Definition: energy.cpp:32
t_continuum continuum
Definition: continuum.cpp:6
realnum TurbHeat
Definition: hextra.h:42
t_rfield rfield
Definition: rfield.cpp:9
double MeV() const
Definition: energy.h:57
bool lgCaseB
Definition: opacity.h:174
realnum DispScale
Definition: doppvel.h:51
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
static const char * ENERGY_MM
Definition: energy.cpp:29
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
static const char * ENERGY_EV
Definition: energy.cpp:24
static const char * ENERGY_ERG
Definition: energy.cpp:23
#define cdEXIT(FAIL)
Definition: cddefines.h:482
void p_set_ip()
Definition: energy.cpp:290
double nm() const
Definition: energy.h:81
double K() const
Definition: energy.h:37
realnum cryden
Definition: hextra.h:24
t_radius radius
Definition: radius.cpp:5
realnum ** reflin
Definition: rfield.h:196
realnum ** ConEmitOut
Definition: rfield.h:151
double eV() const
Definition: energy.h:49
double totlin(int chInfo)
static const char * ENERGY_GHZ
Definition: energy.cpp:36
double TotalLumin
Definition: continuum.h:71
#define ASSERT(exp)
Definition: cddefines.h:613
double kHz() const
Definition: energy.h:65
static const char * ENERGY_KHZ
Definition: energy.cpp:34
const char * StandardEnergyUnit(const char *chCard)
Definition: energy.cpp:44
realnum ConstTemp
Definition: thermal.h:56
double Ryd() const
Definition: energy.h:33
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
double egamry() const
Definition: mesh.h:97
static const char * ENERGY_MICRON
Definition: energy.cpp:30
#define MAX2(a, b)
Definition: cddefines.h:824
double mm() const
Definition: energy.h:89
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
double micron() const
Definition: energy.h:85
void outsum(double *outtot, double *outin, double *outout)
Definition: cont_ffun.cpp:345
static const char * ENERGY_CM
Definition: energy.cpp:28
bool lgStatic(void) const
Definition: wind.h:24
long int nsum
Definition: lines.h:87
double MHz() const
Definition: energy.h:69
realnum ** ConEmitReflec
Definition: rfield.h:145
t_secondaries secondaries
Definition: secondaries.cpp:5
double r1r0sq
Definition: radius.h:31
long int nflux
Definition: rfield.h:46
realnum ** ConRefIncid
Definition: rfield.h:157
double get(const char *unit) const
Definition: energy.cpp:138
bool lgAbort
Definition: cddefines.cpp:10
static const char * ENERGY_NM
Definition: energy.cpp:31