cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parse_optimize.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 /*ParseOptimize parse the optimize command lines */
4 /*GetOptColDen read observed column densities & errors for optimizer */
5 /*GetOptLineInt parse observed line intensities for optimization routines */
6 /*GetOptTemp read observed temperatures & errors for optimizer */
7 #include "cddefines.h"
8 #include "trace.h"
9 #include "optimize.h"
10 #include "prt.h"
11 #include "flux.h"
12 #include "predcont.h"
13 #include "parser.h"
14 #include "lines_service.h"
15 #include "lines.h"
16 
17 static const realnum DEFERR = 0.05f;
18 
19 /*GetOptLineInt parse observed line intensities for optimization routines */
20 STATIC void GetOptLineInt(Parser &p );
21 
22 /*GetOptColDen read observed column densities & errors for optimizer */
23 STATIC void GetOptColDen(Parser &p );
24 
25 /*GetOptTemp read observed temperatures & errors for optimizer */
26 STATIC void GetOptTemp(Parser &p );
27 
28 /* ParseOptimize - called from ParseCommands if OPTIMIZE command found */
30  /* command line, which was changed to all caps in main parsing routine */
31  Parser &p)
32 {
33  DEBUG_ENTRY( "ParseOptimize()" );
34 
35  /* this must come first so that contents of filename do not trigger wrong command */
36  if( p.nMatch("FILE") )
37  {
38  /* option to send final set of parameters to an input file
39  * get name within double quotes,
40  * and set to blanks in chCard and OrgCard */
41  /* chCard is all caps at this point. GetQuote will work with
42  * original version of command line, which preserves case of
43  * characters. Also removes string between quotes */
44  /* GetQuote will abort if it fails, so we can ignore the return value */
45  string str;
46  if (p.GetQuote( str ))
47  p.StringError();
48  strcpy(chOptimFileName, str.c_str());
49  }
50 
51  else if( p.nMatch("COLU") )
52  {
53  /* optimize column density */
54  /* read column densities to match */
55  GetOptColDen(p);
56 
57  optimize.lgOptimize = true;
58  }
59 
60  else if( p.nMatch("CONT") && p.nMatch("FLUX") )
61  {
62  /* optimize continuum flux at arbitrary wavelength */
63  double energy = p.FFmtRead();
64  if( p.lgEOL() )
65  p.NoNumb("energy");
66  const char* unit = p.StandardEnergyUnit();
67  long ind = t_PredCont::Inst().add( energy, unit );
68  Energy E( energy, unit );
69 
70  double flux = p.FFmtRead();
71  if( p.lgEOL() )
72  p.NoNumb("flux");
73  if( flux <= 0. || p.nMatch( " LOG" ) )
74  flux = exp10(flux);
75  Flux F( E, flux, p.StandardFluxUnit() );
76 
77  double relerr = p.FFmtRead();
78  if( p.lgEOL() )
79  relerr = DEFERR;
80  /* value is an upper limit only, use negative error to flag */
81  if( p.nMatch("<" ) )
82  relerr = -relerr;
83 
84  optimize.ContIndex.push_back( ind );
85  optimize.ContEner.push_back( E );
86  optimize.ContNFnu.push_back( F );
87  optimize.ContNFnuErr.push_back( chi2_type(relerr) );
88  optimize.lgOptimize = true;
89  }
90 
91  else if( p.nMatch("CONT") )
92  {
93  /* set flag saying that optimization should start from continue file */
94  optimize.lgOptCont = true;
95  optimize.lgOptimize = true;
96  }
97 
98  else if( p.nMatch("DIAM") )
99  {
100  /* optimize angular diameter */
103  if( p.lgEOL() )
105  /* value is an upper limit only, use negative error to flag */
106  if( p.nMatch( "<" ) )
108 
109  if( p.nMatch( " LOG" ) )
111 
112  optimize.lgOptDiam = true;
113  /* angular diameter is default in arcsec, or in cm of keyword present */
114  optimize.lgDiamInCM = ( p.nMatch( " CM " ) != 0 );
115  optimize.lgOptimize = true;
116  }
117 
118  else if( p.nMatch("INCR") )
119  {
120  /* scan off increments for the previously selected parameter */
121  if( optimize.nparm > 0 )
122  {
123  /* also called during optimization process, ignore then */
125  (realnum)p.FFmtRead();
126  }
127  else
128  {
130  {
131  fprintf( ioQQQ, " The OPTIMIZE INCREMENT command needs to follow the"
132  " command being varied.\n None was found. Bailing out...\n" );
134  }
135  }
136  }
137 
138  else if( p.nMatch("LUMI") || p.nMatch("INTE") )
139  {
140  /* scan off intensity or luminosity of normalization line */
143  if( p.lgEOL() )
145 
146  // default intrinsic intensity, accept emergent
147  optimize.nOptLum = p.nMatch("EMER") ? 1 : 0;
148 
149  /* set flag to say that intensity or luminosity of line set */
150  optimize.lgOptLum = true;
151  optimize.lgOptimize = true;
152  }
153 
154  else if( p.nMatch("ITER") )
155  {
156  /* scan off number of iterations */
157  optimize.nIterOptim = (long)p.FFmtRead();
158  }
159 
160  else if( p.nMatch("LINE") )
161  {
162  /* read lines to match */
163  GetOptLineInt(p);
164 
165  optimize.lgOptimize = true;
166  }
167 
168  else if( p.nMatch("PHYM") )
169  {
170  /* use PvH's PHYMIR to optimize parameters */
171  strcpy( optimize.chOptRtn, "PHYM" );
172 # if defined(__unix) || defined(__APPLE__)
173  // turn parallel mode off if explicitly requested or if we are in single rank mode
174  // the latter means that each rank runs its own model in single-CPU mode
175  optimize.lgParallel = ! ( p.nMatch("SEQU") || cpu.i().lgMPISingleRankMode() );
176 # else
177  optimize.lgParallel = false;
178 # endif
179  if( optimize.lgParallel )
180  {
181  long dum = (long)p.FFmtRead();
182  /* default is the total number of available CPUs */
183  optimize.useCPU = p.lgEOL() ? cpu.i().nCPU() : dum;
184  }
185  else
186  {
187  optimize.useCPU = 1;
188  }
189  }
190 
191  else if( p.nMatch("RANG") )
192  {
193  /* scan off range for the previously selected variable */
194  if( optimize.nparm > 0 )
195  {
196  bool lgFirstOneReal = false;
197 
198  optimize.varang[optimize.nparm-1][0] =
199  (realnum)p.FFmtRead();
200  if( p.lgEOL() )
201  {
202  optimize.varang[optimize.nparm-1][0] = -FLT_MAX;
203  }
204  else
205  {
206  lgFirstOneReal = true;
207  }
208 
209  optimize.varang[optimize.nparm-1][1] =
210  (realnum)p.FFmtRead();
211  if( p.lgEOL() )
212  {
213  optimize.varang[optimize.nparm-1][1] = FLT_MAX;
214  }
215  else if( lgFirstOneReal )
216  {
217  /* >>chng 06 aug 22, swap if second range parameter is less than the first,
218  * and always increment optimize.nRangeSet */
221  {
222  realnum temp = optimize.varang[optimize.nparm-1][0];
224  optimize.varang[optimize.nparm-1][1] = temp;
225  }
226  }
227  }
228  }
229 
230  else if( p.nMatch("SUBP") )
231  {
232  /* use subplex to optimize parameters */
233  strcpy( optimize.chOptRtn, "SUBP" );
234  }
235 
236  /* match a temperature */
237  else if( p.nMatch("TEMP") )
238  {
239  /* read temperatures to match */
240  GetOptTemp(p);
241 
242  optimize.lgOptimize = true;
243  }
244 
245  else if( p.nMatch("TOLE") )
246  {
247  /* scan off tolerance of fit, sum of residuals must be smaller than this
248  * default is 0.10 */
250  }
251 
252  else if( p.nMatch("TRAC") )
253  {
254  if( p.nMatch("STAR") )
255  {
256  /* trace start iteration number
257  * turn on trace printout starting on nth call to cloudy */
258  optimize.nTrOpt = (long)p.FFmtRead();
259  if( p.lgEOL() )
260  {
261  fprintf( ioQQQ, " optimize trace start command:\n" );
262  fprintf( ioQQQ, " The iteration number must appear.\n" );
264  }
265  optimize.lgTrOpt = true;
266  }
267  else if( p.nMatch("FLOW") )
268  {
269  /* trace flow
270  * follow logical flow within code */
271  optimize.lgOptimFlow = true;
272  }
273  else
274  {
275  fprintf( ioQQQ, " optimize trace flow command:\n" );
276  fprintf( ioQQQ, " One of the sub keys START or FLOW must appear.\n" );
278  }
279  }
280 
281  else
282  {
283  p.PrintLine(ioQQQ);
284  fprintf( ioQQQ, " is unrecognized keyword, consult HAZY.\n" );
286  }
287  return;
288 }
289 
290 /*GetOptColDen read observed column densities & errors for optimizer */
292 {
293 
294  DEBUG_ENTRY( "GetOptColDen()" );
295 
296  /* read observed column densities & errors */
297 
298  /* get first line */
299  p.getline();
300  if( p.m_lgEOF )
301  {
302  fprintf( ioQQQ, " Hit EOF while reading column density list; use END to end list.\n" );
304  }
305 
306  while( !p.m_lgEOF )
307  {
308  /* order on line is element label (col 1-4), ionization stage, column density, err */
309  /* copy cap'd version of first 4 char of chCard to chColDen_label */
310  optimize.chColDen_label.push_back(p.getFirstChunk(4));
311 
312  /* now get the ion stage, this should be 1 for atom, up to element
313  * number plus one */
314  long ion = nint(p.FFmtRead());
315  if( p.lgEOL() )
316  {
317  p.PrintLine( ioQQQ );
318  fprintf( ioQQQ, " The ionization stage MUST appear on this line. Sorry.\n" );
320  }
321 
322  /* the ion must be 1 or greater unless requesting a special,
323  * like a molecule or excited state population, in which
324  * case ion = 0
325  * can't check on upper limit yet since have not resolved element name */
326  if( ion < 0 )
327  {
328  p.PrintLine( ioQQQ );
329  fprintf( ioQQQ, " An ionization stage of %ld does not make sense. Sorry.\n", ion );
331  }
332  optimize.ion_ColDen.push_back(ion);
333 
334  optimize.ColDen_Obs.push_back( realnum(exp10(p.FFmtRead())) );
335  if( p.lgEOL() )
336  {
337  p.PrintLine( ioQQQ );
338  fprintf( ioQQQ, " An observed column density MUST be entered. Sorry.\n" );
340  }
341 
342  realnum err = realnum(p.FFmtRead());
343  if( err <= 0.0 )
344  {
345  /* this is the relative error allowed */
346  err = realnum(DEFERR);
347  }
348 
349  /* check if number is a limit - if '<' appears on the line then it is */
350  if( p.nMatch( "<" ) )
351  {
352  /* value is an upper limit only, use negative error to flag */
353  err = -err;
354  }
355  optimize.ColDen_error.push_back(err);
356 
357  p.getline();
358  if( p.m_lgEOF )
359  {
360  fprintf( ioQQQ, " Hit EOF while reading column density list; use END to end list.\n" );
362  }
363 
364  if( p.hasCommand( "END" ) )
365  {
366  p.m_lgEOF = true;
367  }
368  }
369 
370  if( trace.lgTrace && optimize.lgTrOpt )
371  {
372  fprintf( ioQQQ, "%ld columns were entered, they were;\n",
373  (long int) optimize.ColDen_Obs.size() );
374  for( long i=0; i < long(optimize.ColDen_Obs.size()); i++ )
375  {
376  fprintf( ioQQQ, " %4.4s ion=%5ld%10.2e%10.2e\n",
379  }
380  }
381  return;
382 }
383 
384 /*GetOptLineInt parse observed line intensities for optimization routines */
386 {
387  DEBUG_ENTRY( "GetOptLineInt()" );
388 
389  // default intrinsic intensity, accept emergent
390  optimize.nEmergent = p.nMatch("EMER") ? 1 : 0;
391 
392  /* read observed line fluxes & errors */
393  p.getline();
394  if( p.m_lgEOF )
395  {
396  fprintf( ioQQQ, " Hit EOF while reading line list; use END to end list.\n" );
398  }
399 
400  while( !p.m_lgEOF )
401  {
402  LineID line=p.getLineID();
403  /* order on line is label (col 1-4), wavelength, flux, error */
404  optimize.chLineLabel.push_back( line.chLabel.c_str() );
405  optimize.wavelength.push_back( line.wave );
406 
407  /* get the error associated with specified significant figures */
408  optimize.errorwave.push_back( WavlenErrorGet(line.wave, LineSave.sig_figs ) );
409 
410  /* next get the observed intensity */
411  realnum xLineInt = realnum(p.FFmtRead());
412  if( p.lgEOL() )
413  {
414  fprintf( ioQQQ, " The wavelength and relative intensity MUST be entered on this line. Sorry.\n" );
415  fprintf( ioQQQ, " The command line is the following:\n " );
416  p.PrintLine(ioQQQ);
418  }
419 
420  if( xLineInt <= 0. )
421  {
422  fprintf( ioQQQ, " An observed intensity of %.2e is not allowed. Sorry.\n",
423  xLineInt );
424  fprintf( ioQQQ, " The command line is the following:\n" );
425  p.PrintLine(ioQQQ);
427  }
428  optimize.xLineInt_Obs.push_back(xLineInt);
429 
430  /* finally the optional error */
431  realnum err = realnum(p.FFmtRead());
432  /* most often will use the default */
433  if( err <= 0.0 )
434  err = realnum(DEFERR);
435 
436  /* check if number is a limit - if '<' appears on the line then it is */
437  if( p.nMatch( "<" ) )
438  {
439  /* value is an upper limit only, use negative error to flag */
440  err = -err;
441  }
442  optimize.xLineInt_error.push_back(err);
443 
444  if( !p.lgReachedEnd() )
445  {
446  fprintf( ioQQQ, "GetOptLineInt: found junk at end of input line:\n" );
447  p.showLocation();
449  }
450 
451  /* get next line */
452  p.getline();
453  if( p.m_lgEOF )
454  {
455  fprintf( ioQQQ, " Hit EOF while reading line list for optimize command; use END to end list.\n" );
457  }
458 
459  if( p.hasCommand( "END" ) )
460  p.m_lgEOF = true;
461  }
462 
463  if( trace.lgTrace && trace.lgTrOptm )
464  {
465  fprintf( ioQQQ, "%ld lines were entered, they were:\n",
466  (long int) optimize.xLineInt_Obs.size() );
467 
468  for( long i=0; i < long(optimize.xLineInt_Obs.size()); i++ )
469  {
470  fprintf( ioQQQ, " %4.4s ", optimize.chLineLabel[i].c_str() );
472 
473  fprintf( ioQQQ, " %10.2e%10.2e\n",
476  }
477  }
478  return;
479 }
480 
481 /*GetOptTemp parse observed line intensities for optimization routines */
483 {
484  DEBUG_ENTRY( "GetOptTemp()" );
485 
486  /* read observed line fluxes & errors - first set total number of observe temps */
487  p.getline();
488  if( p.m_lgEOF )
489  {
490  fprintf( ioQQQ, " Hit EOF while reading line list; use END to end list.\n" );
492  }
493 
494  /* make line caps so we can parse it */
495  while( !p.m_lgEOF )
496  {
497  /* order on line is label (col 1-4), ion, temperature, error */
498  optimize.chTempLab.push_back( p.getFirstChunk(4) );
499 
500  /* next get the ion stage */
501  optimize.ionTemp.push_back( nint(p.FFmtRead()) );
502 
503  /* next get the observed temperature */
504  realnum temp_obs = realnum(p.FFmtRead());
505  if( p.lgEOL() )
506  {
507  fprintf( ioQQQ, " The ion stage and temperature MUST be entered on this line. Sorry.\n" );
508  fprintf( ioQQQ, " The command line is the following:\n " );
509  p.PrintLine(ioQQQ);
511  }
512  /* temperatures less than or equal to 10 are logs */
513  if( temp_obs <= 10. )
514  temp_obs = realnum(exp10( (double)temp_obs ) );
515  optimize.temp_obs.push_back(temp_obs);
516 
517  /* finally the optional error */
518  realnum temp_error = realnum(p.FFmtRead());
519  /* most often will use the default */
520  if( temp_error <= 0.f )
521  temp_error = realnum(DEFERR);
522  /* check if number is a limit - if '<' appears on the line then it is */
523  if( p.nMatch( "<" ) )
524  temp_error = -temp_error;
525  optimize.temp_error.push_back(temp_error);
526 
527  /* check for radius or volume for how to weight the mean temp
528  * this will be the default */
529  /* >>chng 05 dec 29, from chCard to chCap, unlike much of code in this file,
530  * chCard has been read in by this routine and contains the original form of
531  * the command line. It was converted to caps and stored in chCap above.
532  * As it was written only VOLUME was matched, would not match volume.
533  * Bug caught and corrected by Bohdan Melekh */
534  if( p.nMatch( "VOLUME" ) )
535  optimize.chTempWeight.push_back("volume");
536  else
537  optimize.chTempWeight.push_back("radius");
538 
539  /* get next line */
540  p.getline();
541  if( p.m_lgEOF )
542  {
543  fprintf( ioQQQ, " Hit EOF while reading line list for optimize command; use END to end list.\n" );
545  }
546 
547  if( p.hasCommand( "END" ) )
548  p.m_lgEOF = true;
549  }
550 
551  if( trace.lgTrace && trace.lgTrOptm )
552  {
553  fprintf( ioQQQ, "%ld temperatures were entered, they were;\n",
554  (long int) optimize.temp_obs.size() );
555 
556  for( long i=0; i < long(optimize.temp_obs.size()); i++ )
557  {
558  fprintf( ioQQQ, " %4.4s ", optimize.chTempLab[i].c_str() );
559  fprintf( ioQQQ, " %li " , optimize.ionTemp[i] );
560 
561  fprintf( ioQQQ, " %.2e %.2e\n",
562  optimize.temp_obs[i],
563  optimize.temp_error[i] );
564  }
565  }
566  return;
567 }
bool nMatch(const char *chKey) const
Definition: parser.h:150
realnum optint
Definition: optimize.h:253
bool hasCommand(const char *s2)
Definition: parser.cpp:746
void prt_wl(FILE *ioOUT, realnum wl)
Definition: prt.cpp:44
STATIC void GetOptTemp(Parser &p)
realnum wave
Definition: lines.h:18
double FFmtRead(void)
Definition: parser.cpp:472
realnum WavlenErrorGet(realnum wavelength, long sig_figs)
double exp10(double x)
Definition: cddefines.h:1368
long int nRangeSet
Definition: optimize.h:204
STATIC void GetOptLineInt(Parser &p)
vector< realnum > ColDen_Obs
Definition: optimize.h:214
vector< realnum > xLineInt_error
Definition: optimize.h:226
t_cpu_i & i()
Definition: cpu.h:419
vector< Flux > ContNFnu
Definition: optimize.h:244
chi2_type optDiam
Definition: optimize.h:238
bool lgReachedEnd()
Definition: parser.cpp:109
bool lgTrOpt
Definition: optimize.h:256
int GetQuote(string &chLabel)
Definition: parser.cpp:213
chi2_type optDiamErr
Definition: optimize.h:239
realnum varang[LIMPAR][2]
Definition: optimize.h:201
t_LineSave LineSave
Definition: lines.cpp:10
vector< string > chLineLabel
Definition: optimize.h:219
bool lgVaryOn
Definition: optimize.h:173
Definition: lines.h:14
FILE * ioQQQ
Definition: cddefines.cpp:7
string chLabel
Definition: lines.h:17
Definition: parser.h:43
bool lgInitialParse
Definition: optimize.h:182
Definition: flux.h:9
NORETURN void StringError() const
Definition: parser.cpp:203
static T & Inst()
Definition: cddefines.h:209
vector< realnum > temp_error
Definition: optimize.h:232
long int nIterOptim
Definition: optimize.h:209
t_trace trace
Definition: trace.cpp:5
LineID getLineID()
Definition: parser.cpp:569
string StandardFluxUnit(void) const
Definition: parser.cpp:290
STATIC void GetOptColDen(Parser &p)
double energy(const genericState &gs)
#define STATIC
Definition: cddefines.h:118
bool lgTrace
Definition: trace.h:12
bool lgParallel
Definition: optimize.h:263
long int nparm
Definition: optimize.h:204
void showLocation(FILE *io=ioQQQ) const
Definition: parser.cpp:115
vector< realnum > ColDen_error
Definition: optimize.h:215
long int nTrOpt
Definition: optimize.h:255
bool lgTrOptm
Definition: trace.h:64
float realnum
Definition: cddefines.h:124
const char * StandardEnergyUnit(void) const
Definition: parser.cpp:286
#define EXIT_FAILURE
Definition: cddefines.h:168
int nEmergent
Definition: optimize.h:218
vector< realnum > xLineInt_Obs
Definition: optimize.h:225
#define cdEXIT(FAIL)
Definition: cddefines.h:482
int nOptLum
Definition: optimize.h:260
NORETURN void NoNumb(const char *chDesc) const
Definition: parser.cpp:345
vector< string > chTempLab
Definition: optimize.h:229
long int sig_figs
Definition: lines.h:109
string getFirstChunk(long i)
Definition: parser.cpp:554
t_optimize optimize
Definition: optimize.cpp:6
static const realnum DEFERR
realnum optier
Definition: optimize.h:254
vector< realnum > wavelength
Definition: optimize.h:221
char chOptRtn[5]
Definition: optimize.h:268
double chi2_type
Definition: optimize.h:49
vector< long > ContIndex
Definition: optimize.h:242
bool getline()
Definition: parser.cpp:273
vector< chi2_type > ContNFnuErr
Definition: optimize.h:245
bool lgOptimize
Definition: optimize.h:257
Definition: energy.h:9
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
vector< long > ionTemp
Definition: optimize.h:230
long useCPU
Definition: optimize.h:265
bool lgDiamInCM
Definition: optimize.h:237
vector< Energy > ContEner
Definition: optimize.h:243
vector< realnum > temp_obs
Definition: optimize.h:231
bool lgEOL(void) const
Definition: parser.h:113
bool lgOptCont
Definition: optimize.h:264
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
vector< string > chColDen_label
Definition: optimize.h:212
bool lgOptDiam
Definition: optimize.h:236
long nCPU() const
Definition: cpu.h:388
void ParseOptimize(Parser &p)
int PrintLine(FILE *fp) const
Definition: parser.h:206
long nint(double x)
Definition: cddefines.h:758
bool lgOptLum
Definition: optimize.h:259
vector< string > chTempWeight
Definition: optimize.h:233
realnum OptGlobalErr
Definition: optimize.h:247
static t_cpu cpu
Definition: cpu.h:427
bool m_lgEOF
Definition: parser.h:55
realnum OptIncrm[LIMPAR]
Definition: optimize.h:201
bool lgOptimFlow
Definition: optimize.h:252
vector< long > ion_ColDen
Definition: optimize.h:213
bool lgMPISingleRankMode() const
Definition: cpu.h:393
char chOptimFileName[INPUT_LINE_LENGTH]
Definition: optimize.cpp:7
vector< realnum > errorwave
Definition: optimize.h:223