cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hcmap.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 /*map_do produce map of heating-cooling space for specified zone, called as result of
4  * map command */
5 #include "cddefines.h"
6 #include "thermal.h"
7 #include "cooling.h"
8 #include "called.h"
9 #include "dense.h"
10 #include "phycon.h"
11 #include "trace.h"
12 #include "pressure.h"
13 #include "conv.h"
14 #include "hcmap.h"
15 #include "ion_trim.h"
16 #include "hmi.h"
17 
18 #ifdef EPS
19 # undef EPS
20 #endif
21 #define EPS 0.005
22 
24 
25 void map_do(
26  FILE *io,
27  const char *chType)
28 {
29  char chLabel[NCOLNT_LAB_LEN+1];
30  char units;
31  long int i,
32  ksav,
33  j,
34  jsav,
35  k,
36  nelem;
37  realnum wl;
38  double cfrac,
39  ch,
40  fac,
41  factor,
42  hfrac,
43  oldch,
44  ratio,
45  strhet,
46  strong,
47  t1,
48  tlowst,
49  tmax,
50  tmin,
51  torg;
52 
53  DEBUG_ENTRY( "map_do()" );
54 
55  t1 = phycon.te;
56  torg = phycon.te;
57  hcmap.lgMapOK = true;
58  /* flag indicating that we have computed a map */
59  hcmap.lgMapDone = true;
60 
61  /* make sure pressure has been evaluated */
62  /* this sets values of pressure.PresTotlCurr */
64 
65  /* print out all coolants if all else fails */
66  if( called.lgTalk )
67  {
68  fprintf( io, "# Cloudy punts, Te=%10.3e HTOT=%10.3e CTOT=%10.3e nzone=%4ld\n",
70  fprintf( io, "# COOLNG array is\n" );
71 
72  if( thermal.ctot > 0. )
73  {
74  coolpr(io, "ZERO",1,0.,"ZERO");
75  for( i=0; i < thermal.ncltot; i++ )
76  {
77  ratio = thermal.cooling[i]/thermal.ctot;
78  if( ratio>EPS )
79  {
80  coolpr(io, (char*)thermal.chClntLab[i],thermal.collam[i],
81  ratio,"DOIT");
82  }
83  }
84 
85  fprintf( io, "#" );
86  coolpr(io, "DONE",1,0.,"DONE");
87  fprintf( io, "# Line heating array follows\n" );
88  coolpr(io, "ZERO",1,0.,"ZERO");
89 
90  for( i=0; i < thermal.ncltot; i++ )
91  {
92  ratio = thermal.heatnt[i]/thermal.ctot;
93  if( ratio>EPS )
94  {
95  coolpr(io, (char*)thermal.chClntLab[i],thermal.collam[i],
96  ratio,"DOIT");
97  }
98  }
99 
100  fprintf( io, "#" );
101  coolpr(io,"DONE",1,0.,"DONE");
102  }
103  }
104 
105  /* map out te-ionization-cooling space before punching out. */
106  if( called.lgTalk )
107  {
108  fprintf( io, "# map of heating, cooling, vs temp, follows.\n");
109  fprintf( io,
110  "# Te\t\t Heat-------------------------------->\tCool----------------------------------------->\t dH/dT\t dC/DT\t Ne\t NH\t H2\t HII\t Helium \n" );
111  }
112 
113  if( strcmp(chType,"punt") == 0 )
114  {
115  /* this is the original use of punt, we are punting
116  * only map within factor of two of final temperature
117  * fac will the range to either side of punted temperature */
118  fac = 1.5;
119  tmin = torg/fac;
120  tmax = torg*fac;
121 
122  /* we want about 20 steps between high and low temperature
123  * default of nMapStep is 20, set with set nmaps command */
124  factor = exp10(log10(tmax/tmin)/(double)(hcmap.nMapStep));
125  TempChange(tmin , false);
126  }
127 
128  else if( strcmp(chType," map") == 0 )
129  {
130  /* create some sort of map of heating-cooling */
131  tlowst = MAX2(hcmap.RangeMap[0],phycon.TEMP_LIMIT_LOW);
132  tmin = tlowst*0.998;
133  tmax = MIN2(hcmap.RangeMap[1],phycon.TEMP_LIMIT_HIGH)*1.002;
134 
135  /* we want about nMapStep (=20) steps between high and low temperature */
136  factor = exp10(log10(tmax/tmin)/(double)(hcmap.nMapStep));
137  double TeNew;
138  if( thermal.lgTeHigh )
139  {
140  /* high te */
141  factor = 1./factor;
142  /* TeHighest is highest possible temperature, 1E10 */
143  TeNew = (MIN2(hcmap.RangeMap[1],phycon.TEMP_LIMIT_HIGH)/factor);
144  }
145 
146  else
147  {
148  /* low te */
149  TeNew = (tlowst/factor);
150  }
151  TempChange(TeNew , false);
152  }
153 
154  else
155  {
156  /* don't know what to do */
157  fprintf( ioQQQ, " PUNT called with insane argument,=%4.4s\n",
158  chType );
160  }
161 
162  /* now allocate space for te, c, h vectors in map, if not already done */
163  if( hcmap.nMapAlloc==0 )
164  {
165  /* space not allocated, do so now */
166  hcmap.nMapAlloc = hcmap.nMapStep+4;
167 
168  /* now make the space */
169  hcmap.temap = (double*)MALLOC( sizeof(double)*(size_t)(hcmap.nMapStep+4) );
170  if( hcmap.temap == NULL )
171  {
172  printf( " not enough memory to allocate hcmap.temap in map_do\n" );
174  }
175  hcmap.cmap = (double*)MALLOC( sizeof(double)*(size_t)(hcmap.nMapStep+4) );
176  if( hcmap.cmap == NULL )
177  {
178  printf( " not enough memory to allocate hcmap.cmap in map_do\n" );
180  }
181  hcmap.hmap = (double*)MALLOC( sizeof(double)*(size_t)(hcmap.nMapStep+4) );
182  if( hcmap.hmap == NULL )
183  {
184  printf( " not enough memory to allocate hcmap.hmap in map_do\n" );
186  }
187  }
188 
189  thermal.lgCNegChk = false;
190  hcmap.nmap = 0;
191  oldch = 0.;
192  TempChange(phycon.te *factor , true);
193  if( trace.nTrConvg )
194  fprintf(ioQQQ, " MAP called temp range %.4e %.4e in %li stops ===============================================\n",
195  tmin,
196  tmax,
197  hcmap.nmap);
198 
199  while( (double)phycon.te < tmax*0.999 && (double)phycon.te > tmin*1.001 )
200  {
201  /* this sets values of pressure.PresTotlCurr */
202  PresTotCurrent();
203 
204  /* must reset upper and lower bounds for ionization distributions */
205  /* fix number of stages of ionization */
206  for( nelem=ipHYDROGEN; nelem < LIMELM; nelem++ )
207  {
208  if( dense.lgElmtOn[nelem] )
209  {
210  ion_trim_untrim(nelem);
211  }
212  else
213  {
214  /* this element is turned off, make stages impossible */
215  ion_trim_invalidate(nelem);
216  }
217  }
218 
219  /* this turns on constant reevaluation of everything */
220  conv.lgSearch = true;
221 
222  if( trace.nTrConvg )
223  fprintf(ioQQQ, " MAP new temp %.4e ===============================================\n",
224  phycon.te );
225 
226  /* this counts how many times ionize is called in this model after startr,
227  * and is flag used by ionize to understand it is being called the first time*/
228  conv.nTotalIoniz = 0;
229 
230  /* now get ionization solution for this temperature */
231  if( ConvEdenIoniz() )
232  lgAbort = true;
233 
234  /* save results for later prints */
235  hcmap.temap[hcmap.nmap] = phycon.te;
236  hcmap.cmap[hcmap.nmap] = thermal.ctot;
237  hcmap.hmap[hcmap.nmap] = thermal.htot;
238 
239  wl = 0.f;
240  strong = 0.;
241 
242  for( j=0; j < thermal.ncltot; j++ )
243  {
244  if( thermal.cooling[j] > strong )
245  {
246  strcpy( chLabel, thermal.chClntLab[j] );
247  strong = thermal.cooling[j];
248  wl = thermal.collam[j];
249  }
250  }
251 
252  cfrac = strong/thermal.ctot;
253  strhet = 0.;
254  /* these will be reset in following loop*/
255  ksav = -INT_MAX;
256  jsav = -INT_MAX;
257 
258  for( k=0; k < LIMELM; k++ )
259  {
260  for( j=0; j < LIMELM; j++ )
261  {
262  if( thermal.heating(k,j) > strhet )
263  {
264  strhet = thermal.heating(k,j);
265  jsav = j;
266  ksav = k;
267  }
268  }
269  }
270 
271  ch = thermal.ctot - thermal.htot;
272  /* use ratio to check for change of sign since product
273  * can underflow at low densities */
274  if( oldch/ch < 0. && called.lgTalk )
275  {
276  fprintf( io, "# ----------------------------------------------- Probable thermal solution here. --------------------------------------------\n" );
277  }
278 
279  oldch = ch;
280  hfrac = strhet/thermal.htot;
281  if( called.lgTalk )
282  {
283  /* convert to micros if IR transition */
284  if( wl < 100000.f )
285  {
286  units = 'A';
287  }
288 
289  else
290  {
291  wl /= 10000.f;
292  units = 'm';
293  }
294 
295  if( trace.lgTrace )
296  {
297  fprintf( io, "# TRACE: te, htot, ctot%11.3e%11.3e%11.3e\n",
299  }
300 
301  /*fprintf( io,
302  "%10.4e%11.4e%4ld%4ld%6.3f%11.4e %4.4s %4ld%c%6.3f%10.2e%11.4e%11.4e%6.2f%6.2f%6.2f%6.2f\n",;*/
303  fprintf(io, PrintEfmt("%11.4e\t", phycon.te ) );
304  fprintf(io, PrintEfmt("%11.4e\t", thermal.htot ) );
305  fprintf(io," [%2ld][%2ld]\t%6.3f\t",
306  ksav, jsav,
307  hfrac);
308  fprintf(io, PrintEfmt("%11.4e\t", thermal.ctot ) );
309  fprintf(io," %-10s\t%.1f%c\t%6.3f\t",
310  chLabel ,
311  wl,
312  units,
313  cfrac );
314  fprintf(io, PrintEfmt("%10.2e\t", thermal.dHeatdT ) );
315  fprintf(io, PrintEfmt("%11.2e\t", thermal.dCooldT ) );
316  fprintf(io, PrintEfmt("%11.4e\t", dense.eden ) );
317  fprintf(io, PrintEfmt("%11.4e\t", dense.gas_phase[ipHYDROGEN] ) );
318  fprintf(io, PrintEfmt("%11.4e\t", hmi.H2_total ) );
319  if( dense.lgElmtOn[ipHELIUM] )
320  {
321  fprintf(io,"%6.2f\t%6.2f\t%6.2f\t%6.2f",
323  log10(MAX2(1e-9,dense.xIonDense[ipHELIUM][0]/dense.gas_phase[ipHELIUM])),
324  log10(MAX2(1e-9,dense.xIonDense[ipHELIUM][1]/dense.gas_phase[ipHELIUM])),
325  log10(MAX2(1e-9,dense.xIonDense[ipHELIUM][2]/dense.gas_phase[ipHELIUM])) );
326  }
327  fprintf(io,"\n");
328  fflush(io);
329  }
330 
331  TempChange(phycon.te*factor , true);
332  /* increment nmap but do not exceed nMapAlloc */
333  hcmap.nmap = MIN2(hcmap.nMapAlloc,hcmap.nmap+1);
334 
335  {
336  enum {DEBUG_LOC=false};
337  if( DEBUG_LOC )
338  {
339  static int kount = 0;
340  factor = 1.;
341  TempChange(8674900. , true);
342  ++kount;
343  if( kount >=100 )
344  {
345  fprintf(ioQQQ," exiting in map_do\n");
346  break;
347  }
348  }
349  }
350  }
351 
352  /* now check whether sharp inflections occurred, and also find the biggest jump
353  * in the heating and cooling */
354  hcmap.lgMapOK = true;
355  /* >>chng 02 mar 04, lower bound had been 1, so [i-2] below was negative */
356  for( i=2; i< hcmap.nmap-2; ++i )
357  {
358  realnum s1,s2,s3;/* the three slopes we will use */
359  s1 = hcmap.cmap[i-2] - hcmap.cmap[i-1];
360  s2 = hcmap.cmap[i-1] - hcmap.cmap[i];
361  s3 = hcmap.cmap[i] - hcmap.cmap[i+1];
362  if( s1*s3 > 0. && s2*s3 < 0. )
363  {
364  /* of the three points, the outer had the same slope
365  * (their product was positive) but there was an inflection
366  * between them (the negative product). The data chain looked like
367  * 2 4
368  * 1 3 or vice versa, either case is wrong,
369  * with the logic in the above test, the problem point will aways be s2 */
370  fprintf( io,
371  "# cooling curve had double inflection at T=%.2e. ",
372  hcmap.temap[i]);
373  fprintf( io, " Slopes were %.2e %.2e %.2e", s1, s2, s3);
374  if( fabs(s2)/hcmap.cmap[i] > 0.05 )
375  {
376  fprintf( io,
377  " error large, (rel slope of %.2e).\n",
378  s2 / hcmap.cmap[i]);
379  hcmap.lgMapOK = false;
380  }
381  else
382  {
383  fprintf( io,
384  " error is small, (rel slope of %.2e).\n",
385  s2 / hcmap.cmap[i]);
386  }
387  }
388 
389  s1 = hcmap.hmap[i-2] - hcmap.hmap[i-1];
390  s2 = hcmap.hmap[i-1] - hcmap.hmap[i];
391  s3 = hcmap.hmap[i] - hcmap.hmap[i+1];
392  if( s1*s3 > 0. && s2*s3 < 0. )
393  {
394  /* of the three points, the outer had the same slope
395  * (their product was positive) but there was an inflection
396  * between them (the negative product). The data chain looked like
397  * 2 4
398  * 1 3 or vice versa, either case is wrong */
399  fprintf( io,
400  "# heating curve had double inflection at T=%.2e.\n",
401  hcmap.temap[i] );
402  hcmap.lgMapOK = false;
403  }
404  }
405 
406  thermal.lgCNegChk = true;
407  TempChange(t1 , false);
408  return;
409 }
double htot
Definition: thermal.h:169
bool lgMapOK
Definition: hcmap.h:30
t_thermal thermal
Definition: thermal.cpp:6
void coolpr(FILE *io, const char *chLabel, realnum lambda, double ratio, const char *chJOB)
Definition: cool_pr.cpp:10
double exp10(double x)
Definition: cddefines.h:1368
double * temap
Definition: hcmap.h:42
void ion_trim_untrim(long nelem)
Definition: ion_trim.cpp:20
#define PrintEfmt(F, V)
Definition: cddefines.h:1349
void ion_trim_invalidate(long nelem)
Definition: ion_trim.cpp:26
t_conv conv
Definition: conv.cpp:5
t_phycon phycon
Definition: phycon.cpp:6
double cooling[NCOLNT]
Definition: thermal.h:104
bool lgTeHigh
Definition: thermal.h:72
Definition: hcmap.h:16
FILE * ioQQQ
Definition: cddefines.cpp:7
long int nzone
Definition: cddefines.cpp:14
bool lgTalk
Definition: called.h:12
#define MIN2(a, b)
Definition: cddefines.h:803
void TempChange(double TempNew, bool lgForceUpdate)
Definition: temp_change.cpp:32
t_dense dense
Definition: global.cpp:15
bool lgCNegChk
Definition: thermal.h:122
void PresTotCurrent(void)
long int nMapStep
Definition: hcmap.h:26
const double TEMP_LIMIT_LOW
Definition: phycon.h:121
double xIonDense[LIMELM][LIMELM+1]
Definition: dense.h:135
bool lgSearch
Definition: conv.h:168
t_trace trace
Definition: trace.cpp:5
#define MALLOC(exp)
Definition: cddefines.h:554
bool lgMapDone
Definition: hcmap.h:36
char chClntLab[NCOLNT][NCOLNT_LAB_LEN+1]
Definition: thermal.h:108
bool lgTrace
Definition: trace.h:12
const double TEMP_LIMIT_HIGH
Definition: phycon.h:123
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
#define cdEXIT(FAIL)
Definition: cddefines.h:482
void map_do(FILE *io, const char *chType)
Definition: hcmap.cpp:25
int nTrConvg
Definition: trace.h:27
double heating(long nelem, long ion)
Definition: thermal.h:186
long int nTotalIoniz
Definition: conv.h:159
long int nmap
Definition: hcmap.h:39
bool lgElmtOn[LIMELM]
Definition: dense.h:160
realnum gas_phase[LIMELM]
Definition: dense.h:76
realnum RangeMap[2]
Definition: hcmap.h:23
long int ncltot
Definition: thermal.h:106
realnum collam[NCOLNT]
Definition: thermal.h:103
const int LIMELM
Definition: cddefines.h:308
double * hmap
Definition: hcmap.h:45
double dHeatdT
Definition: thermal.h:169
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
const int ipHELIUM
Definition: cddefines.h:350
#define EPS
Definition: hcmap.cpp:21
double H2_total
Definition: hmi.h:25
#define NCOLNT_LAB_LEN
Definition: thermal.h:107
double eden
Definition: dense.h:201
#define MAX2(a, b)
Definition: cddefines.h:824
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
double * cmap
Definition: hcmap.h:48
t_hcmap hcmap
Definition: hcmap.cpp:23
t_hmi hmi
Definition: hmi.cpp:5
double te
Definition: phycon.h:21
double dCooldT
Definition: thermal.h:139
const int ipHYDROGEN
Definition: cddefines.h:349
int ConvEdenIoniz(void)
double heatnt[NCOLNT]
Definition: thermal.h:104
t_called called
Definition: called.cpp:4
long int nMapAlloc
Definition: hcmap.h:53
bool lgAbort
Definition: cddefines.cpp:10
double ctot
Definition: thermal.h:130