cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parse_abundances.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 /*ParseAbundances parse and read in composition as set by abundances command */
4 #include "cddefines.h"
5 #include "abund.h"
6 #include "dense.h"
7 #include "elementnames.h"
8 #include "input.h"
9 #include "parser.h"
10 
11 
12 STATIC FILE *open_abn_file( string chFile )
13 {
14  FILE *ioDATA;
15 
16  // first try local directory, then data/abundances
17  if( (ioDATA = open_data( chFile.c_str(), "r", AS_LOCAL_ONLY_TRY ) ) == NULL )
18  {
19  char chPath[FILENAME_PATH_LENGTH_2] = { 0 }; /*entire path to file including file name*/
20 
21  /* change chPath to the abundances/chFile, using the proper delimiter */
22  strcpy( chPath, "abundances" );
23  strcat( chPath, input.chDelimiter );
24  strcat( chPath, chFile.c_str() );
25  ioDATA = open_data( chPath, "r" ); // will abort if not found
26  }
27 
28  return ioDATA;
29 }
30 
31 
32 
34  /* following set true by grains command,
35  * so this will not set more grains if grains already on. */
36 {
37  bool lgLog;
38  long int i;
39  double absav[LIMELM],
40  chk;
41 
42  DEBUG_ENTRY( "ParseAbundances()" );
43 
44  /* abundances no longer solar */
45  abund.lgAbnSolar = false;
46 
47  if( p.nMatch("STAR") )
48  {
49  /* Fred Hamann's star burst galaxy mixture -- includes a number which isn't an abundance */
50  abund_starburst(p);
51  return;
52  }
53 
54  /* GetQuote should be above the other options so other commands don't trip
55  * if there is any overlapping text in the quotes */
56  string chFile; /*file name for table read */
57  //records whether or not quotes were found and stores what is between them in chFile
58  bool lgMatchFound = true;
59  if( p.GetQuote( chFile ) )
60  lgMatchFound = false;
61 
62  bool lgPrint = p.nMatch( "PRINT");
63  bool lgIsotp = p.nMatch( "ISOT" );
64 
65  if(!lgMatchFound && !lgIsotp)
66  {
67  lgMatchFound = true;
68  if(p.nMatch("CAME"))
69  chFile = "Cameron.abn";
70  else if (p.nMatch("CRAB"))
71  chFile = "Crab.abn";
72  else if (p.nMatch("GASS"))
73  chFile = "solar_GASS10.abn";
74  else if (p.nMatch("H II") || p.nMatch("HII ") || p.nMatch("ORIO"))
75  chFile = "HII.abn";
76  else if (p.nMatch("ISM"))
77  chFile = "ISM.abn";
78  else if (p.nMatch("NOVA"))
79  chFile = "nova.abn";
80  else if (p.nMatch(" AGB") || p.nMatch("AGB ") || p.nMatch("PLAN"))
81  chFile = "PN.abn";
82  else if (p.nMatch("PRIM"))
83  chFile = "primordial.abn";
84  else if (p.nMatch("OLD ") && p.nMatch("SOLA"))
85  chFile = "solar84.abn";
86  else if (p.nMatch("ALLE"))
87  chFile = "allen73.abn";
88  else
89  lgMatchFound = false;
90  }
91  else if( lgIsotp && chFile.length() == 0 )
92  {
93  if( p.nMatch( "ASPL" ) )
94  chFile = "Asplund09-iso.abn";
95  else if( p.nMatch( "LODDERS03" ) )
96  chFile = "Lodders03-iso.abn";
97  else if( p.nMatch( "LODDERS09" ) )
98  chFile = "Lodders09-iso.abn";
99  else if( p.nMatch( "ROSM" ) )
100  chFile = "Rosman98-iso.abn";
101  else
102  {
103  fprintf(ioQQQ, "Unknown isotope abundances file:\t %s\n", chFile.c_str() );
105  }
106  }
107 
108  if(lgMatchFound && !lgIsotp)
109  {
110  // we have a file name - are other parameters present?
111  bool lgGrainsON = true;
112  if( p.nMatch("NO GR") != 0 )
113  lgGrainsON = false;
114 
115  bool lgQHeat = true;
116  if( p.nMatch("NO QH") != 0 )
117  lgQHeat = false;
118 
119  abund.lgAbundancesSet = true;
120 
121  // initialization
122  for( int nelem=1; nelem < LIMELM; nelem++ )
123  {
124  /* turn off all elements except Hydrogen,
125  * then turn on each element when found in the file */
126  char chDUMMY[INPUT_LINE_LENGTH];
127  sprintf(chDUMMY,"element %s off ", elementnames.chElementName[nelem] );
128  p.setline(chDUMMY);
129  // need to retain this flag, set by user to explicitly turn off element,
130  // overriding our default to turn on elements that appear in abundances list
131  bool lgSave = dense.lgElmtSetOff[nelem];
132  ParseElement( p );
133  dense.lgElmtSetOff[nelem] = lgSave;
134  }
135 
136  FILE *ioDATA = open_abn_file( chFile );
137 
138  /* Sets abundance of Hydrogen to 1.0 in the expectation
139  * that other values are abundances relative to Hydrogen,
140  * although Hydrogen's abundance will still be set to
141  * whatever value is found in the code. This is just in
142  * case it is assumed */
143  abund.solar[ipHYDROGEN] = 1.0;//The value found in abund.solar[0] before this point is found to be 1.0 as well
144 
145  char chLine[INPUT_LINE_LENGTH]; /*to store file lines*/
146  bool lgEOL;
147  while( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) != NULL )
148  {
149  if( chLine[0]=='*' )
150  break;
151 
152  /* skip comment */
153  if( chLine[0]=='#' )
154  continue;
155  if( chLine[0]=='\n' || chLine[0]=='\0' )
156  {
157  fprintf(ioQQQ, "PROBLEM in ABUNDANCES: Encountered unexpected empty line.\n");
159  }
160 
161  // If keyword "grains" is found on a line calls grain command
162  // NOQHEAT may have been on the line in the input deck, or in the abn file
163  /* copy input to CAPS to make sure hide not on it */
164  char chLineCAPS[INPUT_LINE_LENGTH];
165  strcpy( chLineCAPS , chLine );
166  caps( chLineCAPS );
167  if( nMatch("GRAINS", chLineCAPS) != 0 )
168  {
169  if( lgPrint )
170  fprintf(ioQQQ,"%s\n",chLine);
171  //Makes sure grains have not already been set and are on
172  //Either way it skips to the next loop iteration and does not check the line for elements
173  if( !p.m_lgDSet && lgGrainsON )
174  {
175  if( !lgQHeat )
176  strcat( chLineCAPS, " NO QHEAT");
177 
178  p.setline(chLineCAPS);
179  ParseGrain(p);
180  continue;
181  }
182  else
183  continue;
184  }
185 
186  i = 1;
187  bool lgFound = false;
188  for(int nelem=0; nelem<LIMELM; nelem++)
189  {
190  if( nMatch( elementnames.chElementNameShort[nelem], chLineCAPS ) != 0 )
191  {
192  lgFound = true;
193  abund.solar[nelem] = FFmtRead(chLine,&i,sizeof(chLine),&lgEOL);
194  if( abund.solar[nelem] <=0. )
195  {
196  fprintf(ioQQQ, "PROBLEM in ABUNDANCES: negative abundance not allowed.\n");
197  fprintf(ioQQQ, "Non-positive abundance found on this line: %s\n", chLine);
199  }
200 
201  // do not implicitly turn on an element that has explicitly been turned off
202  if( dense.lgElmtSetOff[nelem] )
203  break;
204 
205  /* turn on any element found while parsing the file */
206  char chDUMMY[INPUT_LINE_LENGTH];
207  sprintf(chDUMMY,"element %s on ", elementnames.chElementName[nelem] );
208  p.setline(chDUMMY);
209  ParseElement( p );
210 
211  //we shouldn't need to continue once an element name is found on the line...
212  break;
213  }
214  }
215  if( !lgFound )
216  {
217  fprintf(ioQQQ, "PROBLEM in ABUNDANCES: did not identify element name on this line: %s\n",
218  chLine);
220  }
221  }
222 
223  //Normalizes all elements in abund.solar relative to the quantity of Hydrogen
224  ASSERT( abund.solar[0]>0. );
225  for(int nelem=0; nelem<LIMELM; nelem++)
226  {
227  abund.solar[nelem] /= abund.solar[ipHYDROGEN];
228  if( lgPrint && dense.lgElmtOn[nelem] )
229  fprintf(ioQQQ,"%s\t%.3e\t%.3f\n",elementnames.chElementName[nelem],
230  abund.solar[nelem] , log10(SDIV(abund.solar[nelem])) );
231  }
232  fclose( ioDATA );
233  return;
234  }
235  else if( !lgIsotp )
236  {
237  abund.lgAbundancesSet = true;
238 
239  /* Looks for a number on the parser*/
240  absav[0] = p.FFmtRead();
241  /* this branch at least one number on the line - an abundance */
242  if( p.lgEOL() )
243  {
244  fprintf( ioQQQ, " PROBLEM in ABUNDANCES: I did not find a keyword, file name, or any numbers. Sorry.\n");
246  }
247  absav[1] = p.FFmtRead();
248  if( p.lgEOL() )
249  {
250  /* this branch, we found one, but not two, numbers -
251  * must be a few special case */
252  if( p.nMatch(" ALL") )
253  {
254  /* special option, all abundances will be this number */
255  if( absav[0] <= 0. )
256  {
257  absav[0] = exp10(absav[0]);
258  }
259  for( i=1; i < LIMELM; i++ )
260  {
261  abund.solar[i] = (realnum)absav[0];
262  }
263 
264  }
265  else
266  {
267  fprintf( ioQQQ,
268  " Only one number was found. Did you include the keyword ALL? Sorry.\n");
270  }
271 
272  /* normal return */
273  return;
274  }
275 
276  /* we get here if there is a second number - read in all abundances */
277  /* abund.npSolar is changed by ParseElement, which was called previously
278  * in this routine. It should not be changed by anything in this loop.
279  * Make sure this is the case.
280  */
281  long nElem = abund.npSolar;
282  for( i=2; i < nElem; i++ )
283  {
284  absav[i] = p.FFmtRead();
285  if( p.lgEOL() )
286  {
287  /* read CONTINUE line if J scanned off end before reading all abundances */
288  do
289  {
290  p.getline();
291  if( p.m_lgEOF )
292  {
293  fprintf( ioQQQ, " There MUST be%3ld abundances entered, there were only%3ld. Sorry.\n",
294  abund.npSolar, i );
296  }
297  } while( p.isComment() );
298 
299  p.echo();
300 
301  if( ! p.hasCommand("CONT") )
302  {
303  fprintf( ioQQQ, " There MUST be%3ld abundances entered, there were only%3ld. Sorry.\n",
304  abund.npSolar, i );
306  }
307  else
308  {
309  absav[i] = p.FFmtRead();
310  if( p.lgEOL() )
311  {
312  fprintf( ioQQQ, " There MUST be%3ld abundances entered, there were only%3ld. Sorry.\n",
313  abund.npSolar, i);
315  }
316  }
317  }
318  }
319  /* would only fail if npSolar is changed within this loop */
320  ASSERT( nElem == abund.npSolar);
321 
322  /* fell through to here after reading in N abundances for N elements
323  * check that there are no more abundances on the line - that would
324  * be an error - a typo */
325  chk = p.FFmtRead();
326  if( !p.lgEOL() || (chk!=0.) )
327  {
328  /* got another number, not lgEOL, so too many numbers */
329  fprintf( ioQQQ, " There were more than %ld abundances entered\n",
330  abund.npSolar );
331  fprintf( ioQQQ, " Could there have been a typo somewhere?\n" );
332  }
333 
334  /* are numbers scale factors, or log of abund rel to H?? */
335  lgLog = false;
336  for( i=0; i < abund.npSolar; i++ )
337  if( absav[i] < 0. )
338  lgLog = true;
339 
340  if( lgLog )
341  {
342  /* entered as log of number rel to hydrogen */
343  for( i=0; i < abund.npSolar; i++ )
344  abund.solar[abund.ipSolar[i]-1] = (realnum)exp10(absav[i]);
345  }
346  else
347  {
348  /* scale factors relative to solar */
349  for( i=0; i < abund.npSolar; i++ )
350  abund.solar[abund.ipSolar[i]-1] *= (realnum)absav[i];
351  }
352 
353  /* check whether the abundances are reasonable */
354  for( i=1; i < LIMELM; i++ )
355  {
356  if( abund.solar[i] > 0.2 )
357  {
358  fprintf( ioQQQ, " Is an abundance of %.3e relative to H reasonable for %2.2s?\n",
360  }
361  }
362  return;
363  }
364  else if( lgIsotp )
365  {
366  FILE *ioDATA = open_abn_file( chFile );
367 
368  char chLine[INPUT_LINE_LENGTH]; /*to store file lines*/
369  bool lgEOL;
370  int nRead[LIMELM] = { 0 };
371 
372  while( read_whole_line( chLine , (int)sizeof(chLine) , ioDATA ) != NULL )
373  {
374  if( chLine[0]=='*' )
375  break;
376 
377  /* skip comment */
378  if( chLine[0]=='#' )
379  continue;
380  if( chLine[0]=='\n' || chLine[0]=='\0' )
381  {
382  fprintf(ioQQQ, "PROBLEM in ABUNDANCES ISOTOPES: Encountered unexpected empty line.\n");
384  }
385 
386  long i = 1;
387  int ielem = (int)FFmtRead(chLine,&i,sizeof(chLine),&lgEOL) - 1;
388  int Aiso = (int)FFmtRead(chLine,&i,sizeof(chLine),&lgEOL);
389  realnum Fiso = (realnum)FFmtRead(chLine,&i,sizeof(chLine),&lgEOL);
390  int j = abund.IsoAbn[ielem].setAbn( Aiso, Fiso );
391  if( j == -1 )
392  {
393  fprintf(ioQQQ,
394  "PROBLEM in ABUNDANCES ISOTOPES: Could not store isotope fraction (%7.4f) for ^%d %s\n",
395  Fiso, Aiso, elementnames.chElementSym[i]);
396  cdEXIT( EXIT_FAILURE );
397  }
398  ++nRead[ielem];
399  }
400  fclose( ioDATA );
401 
402  /* Express all isotope fractions in terms of the most abundant isotope. */
403  for( int i = 0; i < LIMELM; i++ )
404  {
405  if( nRead[i] != abund.IsoAbn[i].getNiso() )
406  {
407  fprintf(ioQQQ, "Abundaces Isotopes: %s requires %d isotope pairs to be specified, but found %d\n",
408  elementnames.chElementName[i], abund.IsoAbn[i].getNiso(), nRead[i]);
410  }
411  if( abund.IsoAbn[i].isAnyIllegal() )
412  {
413  fprintf(ioQQQ, "Abundaces Isotopes: Non-positive isotope fractions are illegal.\n");
414  fprintf(ioQQQ, "File: %s\t Read: %s\t iso:", chFile.c_str(), elementnames.chElementName[i]);
417  }
418  abund.IsoAbn[i].normAbn( );
419  // abund.IsoAbn[i].prtIsoPairs( stdout );
420  }
421 
422  return;
423  }
424  //return;
425  //Should never reach this return, because if & else branch return
426 }
bool nMatch(const char *chKey) const
Definition: parser.h:150
bool hasCommand(const char *s2)
Definition: parser.cpp:746
FILE * open_data(const char *fname, const char *mode, access_scheme scheme)
Definition: cpu.cpp:765
STATIC FILE * open_abn_file(string chFile)
void echo(void) const
Definition: parser.cpp:189
double FFmtRead(void)
Definition: parser.cpp:472
double exp10(double x)
Definition: cddefines.h:1368
const int FILENAME_PATH_LENGTH_2
Definition: cddefines.h:296
t_input input
Definition: input.cpp:12
void setline(const char *const card)
Definition: parser.h:82
long nMatch(const char *chKey, const char *chCard)
Definition: service.cpp:525
int GetQuote(string &chLabel)
Definition: parser.cpp:213
bool lgElmtSetOff[LIMELM]
Definition: dense.h:164
bool isAnyIllegal(void)
Definition: abund.h:145
FILE * ioQQQ
Definition: cddefines.cpp:7
Definition: parser.h:43
void normAbn()
Definition: abund.h:130
t_dense dense
Definition: global.cpp:15
t_elementnames elementnames
Definition: elementnames.cpp:5
bool lgAbnSolar
Definition: abund.h:202
t_abund abund
Definition: abund.cpp:5
t_isotope IsoAbn[LIMELM]
Definition: abund.h:213
#define STATIC
Definition: cddefines.h:118
bool m_lgDSet
Definition: parser.h:55
int getNiso()
Definition: abund.h:66
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
#define cdEXIT(FAIL)
Definition: cddefines.h:482
char chElementNameShort[LIMELM][CHARS_ELEMENT_NAME_SHORT]
Definition: elementnames.h:21
bool lgElmtOn[LIMELM]
Definition: dense.h:160
char chElementSym[LIMELM][CHARS_ELEMENT_SYM]
Definition: elementnames.h:25
long int ipSolar[LIMELM]
Definition: abund.h:238
void ParseGrain(Parser &p)
Definition: parse_grain.cpp:12
#define ASSERT(exp)
Definition: cddefines.h:613
bool getline()
Definition: parser.cpp:273
const int LIMELM
Definition: cddefines.h:308
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
char chDelimiter[3]
Definition: input.h:83
long int npSolar
Definition: abund.h:238
bool lgEOL(void) const
Definition: parser.h:113
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
void abund_starburst(Parser &p)
sys_float SDIV(sys_float x)
Definition: cddefines.h:1002
char * read_whole_line(char *chLine, int nChar, FILE *ioIN)
Definition: service.cpp:70
char chElementName[LIMELM][CHARS_ELEMENT_NAME]
Definition: elementnames.h:17
void caps(char *chCard)
Definition: service.cpp:295
bool m_lgEOF
Definition: parser.h:55
int setAbn(int Anum, realnum abn)
Definition: abund.h:114
const int ipHYDROGEN
Definition: cddefines.h:349
bool lgAbundancesSet
Definition: abund.h:207
void prtIsoPairs(FILE *fp)
Definition: abund.h:169
void ParseElement(Parser &p)
bool isComment(void) const
Definition: parser.cpp:140
double FFmtRead(const char *chCard, long int *ipnt, long int last, bool *lgEOL)
Definition: service.cpp:381
void ParseAbundances(Parser &p)
realnum solar[LIMELM]
Definition: abund.h:210