cloudy  trunk
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
lines.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 #include "cddefines.h"
4 #include "lines.h"
5 #include "prt.h"
6 #include "lines_service.h"
7 #include "version.h"
8 #include "service.h"
9 
11 /* these are the definitions of the line save arrays in lines.h */
12 
14 {
15  DEBUG_ENTRY( "t_LineSave::zero()" );
16 
17  /* index within the line in the line stack
18  * default is Hbeta total - the third line in the stack
19  * 0th is a zero for sanity, 1st is unit, 2nd is a comment */
20  /* >>chng 02 apr 22 from 2 to 3 since added unit at 1 */
21  /* >>chng 06 mar 11, from 3 to -1 will now set to "H 1" 4861 */
22  ipNormWavL = -1;
23  WavLNorm = 4861.33f;
24  lgNormSet = false;
26 
27  /* the label for the normalization line */
28  strcpy( chNormLab, " " );
29 
30  /* The scale factor for the normalization line */
31  ScaleNormLine = 1.;
32 
33 }
34 
35 void LinSv::prt(FILE* ioPUN) const
36 {
37  DEBUG_ENTRY( "LinSv::prt()" );
38  fprintf(ioPUN,"%s",label().c_str());
39 }
40 
41 string LinSv::label() const
42 {
43  DEBUG_ENTRY( "LinSv::label()" );
44  string val = chALab();
45  val.resize( NCHLAB-1, ' ' );
46  val += " ";
47  char buf[100];
48  sprt_wl(buf, wavelength());
49  val += buf;
50  return val;
51 }
52 
53 string LinSv::biglabel() const
54 {
55  DEBUG_ENTRY( "LinSv::biglabel()" );
56  string val = label();
57  if (m_tr.associated())
58  {
59  val += " ";
60  val += "[";
61  val += (*m_tr.Hi()).chConfig();
62  val += "->";
63  val += (*m_tr.Lo()).chConfig();
64  val += "]";
65  }
66  return val;
67 }
68 
69 bool LinSv::isCat(const char *s) const
70 {
71  DEBUG_ENTRY( "LinSv::isCat()" );
72  return strncmp(chALab(),s,strlen(s)) == 0;
73 }
74 
75 void LinSv::chALabSet(const char *that)
76 {
77  /* check that null is correct, string overruns have
78  * been a problem in the past */
79  ASSERT( (int) strlen( that )< NCHLAB );
80  strncpy(m_chALab,that,NCHLAB-1);
81  m_chALab[NCHLAB-1] = '\0';
83 
84  strncpy(m_chCLab,that,NCHLAB-1);
85  m_chCLab[NCHLAB-1] = '\0';
87  caps(m_chCLab);
88 }
89 
90 void LinSv::init(long index, char chSumTyp, const char *chComment, const char *label,
91  const TransitionProxy& tr)
92 {
93  DEBUG_ENTRY( "LinSv::init()" );
94  /* first call to stuff lines in array, confirm that label is one of
95  * the four correct ones */
96  ASSERT( (chSumTyp == 'c') || (chSumTyp == 'h') || (chSumTyp == 'i') || (chSumTyp == 'r') || (chSumTyp == 't') );
98  ASSERT(index >= 0);
99  m_index = index;
100  /* then save it into array */
102  emslinZero();
104  chALabSet( label );
105  if (isCat("####"))
106  {
107  m_type = SEPARATOR;
108  }
109  else if (isCat("Unit"))
110  {
111  m_type = UNIT;
112  }
113  else if (isCat("UntD"))
114  {
115  m_type = UNITD;
116  }
117  else if (isCat("Inwd"))
118  {
119  m_type = INWARD;
120  }
121  else if (isCat("InwC"))
122  {
124  }
125  else if (isCat("InwT"))
126  {
128  }
129  else if (isCat("Coll"))
130  {
132  }
133  else if (isCat("Pump"))
134  {
135  m_type = PUMP;
136  }
137  else if (isCat("Heat"))
138  {
139  m_type = HEAT;
140  }
141  else if (isCat("Ca A"))
142  {
143  m_type = CASEA;
144  }
145  else if (isCat("Ca B"))
146  {
147  m_type = CASEB;
148  }
149  else if (isCat("nInu"))
150  {
151  m_type = NINU;
152  }
153  else if (isCat("nFnu"))
154  {
155  m_type = NFNU;
156  }
157  else if (isCat("Pho+"))
158  {
159  m_type = PHOPLUS;
160  }
161  else if (isCat("Pcon"))
162  {
163  m_type = PCON;
164  }
165  else if (isCat("Q(H)"))
166  {
167  m_type = QH;
168  }
169  else
170  {
171  m_type = DEFAULT;
172  }
173 
174  SumLineZero();
175  m_tr = tr;
176 }
177 
179 {
180  m_component.push_back(id);
181  if (m_component.size() == 1)
182  m_chComment += ": ";
183  else
184  m_chComment += "+";
185  if (id > 0)
186  {
187  m_chComment += "\""+LineSave.lines[id].label()+"\"";
188  }
189  else
190  {
191  m_chComment += "N/A";
192  }
193 }
194 void LinSv::addComponent(const char* species,const double wavelength1)
195 {
196  if ( LineSave.ipass == 0 )
197  {
198  long id = LineSave.findline(species,wlAirVac(wavelength1));
199  if (id <= 0)
200  {
201  fprintf( ioQQQ, "ERROR: A component to line blend \"%s\" %.3f was not identified.\n",
202  species, wavelength1 );
203  cdEXIT( EXIT_FAILURE );
204  }
205  addComponentID(id);
206  }
207 }
208 
209 // Automatically generate blend for specified species, at wavelength +/- width
210 void LinSv::makeBlend(const char* chLabel,const double wavelength1, const double width)
211 {
212  DEBUG_ENTRY("LinSv::makeBlend()");
213  if ( LineSave.ipass == 0 )
214  {
215  realnum wlo = wlAirVac(wavelength1-width),
216  whi = wlAirVac(wavelength1+width);
217 
218  /* check that chLabel[4] is null - supposed to be 4 char + end */
219  if( strlen(chLabel) > NCHLAB-1 )
220  {
221  fprintf( ioQQQ, " makeBlend called with insane species \"%s\", must be %d or less characters long.\n",
222  chLabel, NCHLAB-1 );
224  }
225 
226  char chCARD[INPUT_LINE_LENGTH];
227  strcpy( chCARD, chLabel );
228 
229  /* make sure chLabel is all caps */
230  caps(chCARD);/* convert to caps */
231 
232  /* this replaces tabs with spaces. */
233  /* \todo 2 keep this in, do it elsewhere, just warn and bail? */
234  for( char *s=chCARD; *s != '\0'; ++s )
235  {
236  if( *s == '\t' )
237  {
238  *s = ' ';
239  }
240  }
241 
242  for( long j=1; j < LineSave.nsum; j++ )
243  {
244  /* use pre-capitalized version of label to be like input chLineLabel */
245  const char *chCaps = LineSave.lines[j].chCLab();
246 
247  if (LineSave.wavelength(j) >= wlo &&
248  LineSave.wavelength(j) <= whi &&
249  strcmp(chCaps,chCARD) == 0)
250  {
251  addComponentID(j);
252  fprintf( ioQQQ,"Adding \"%s\" to blend\n",
253  LineSave.lines[j].label().c_str() );
254  }
255  }
256  }
257 }
258 string LinSv::chComment() const
259 {
260  return m_chComment;
261 }
262 
263 static bool wavelength_compare (long a, long b)
264 {
265  LinSv* a1 = &LineSave.lines[a];
266  LinSv* b1 = &LineSave.lines[b];
267  /* comparison is b-a so we get inverse wavelength order (increasing energy order) */
268  if( b1->wavelength() < a1->wavelength() )
269  return true;
270  else
271  return false;
272 }
273 
275 {
276  /* comparison is b-a so we get inverse wavelength order (increasing energy order) */
277  if( wavelength < LineSave.wavelength(a) )
278  return true;
279  else
280  return false;
281 }
282 
284 {
285  DEBUG_ENTRY( "t_LineSave::setSortWL()" );
286  SortWL.resize((unsigned)nsum);
287  for (long nlin=0; nlin < nsum; ++nlin)
288  {
289  SortWL[nlin] = nlin;
290  }
291  stable_sort(SortWL.begin(), SortWL.end(), wavelength_compare);
292 }
293 
294 long t_LineSave::findline(const char *chLabel, realnum wavelength1)
295 {
296  DEBUG_ENTRY( "t_LineSave::findline()" );
297 
298  ASSERT( nsum >= 0);
299  if (nsum == 0)
300  return -1;
301 
302  bool lgDEBUG = false;
303 
304  if( strlen(chLabel) > NCHLAB-1 )
305  {
306  fprintf( ioQQQ, " findline called with insane chLabel (between quotes) \"%s\", must be no more than %d characters long.\n",
307  chLabel, NCHLAB-1 );
308  return -2;
309  }
310 
311  char chCARD[INPUT_LINE_LENGTH];
312  strcpy( chCARD, chLabel );
313 
314  /* make sure chLabel is all caps */
315  caps(chCARD);/* convert to caps */
316  trimTrailingWhiteSpace( chCARD );
317 
318  /* this replaces tabs with spaces. */
319  /* \todo 2 keep this in, do it elsewhere, just warn and bail? */
320  for( char *s=chCARD; *s != '\0'; ++s )
321  {
322  if( *s == '\t' )
323  {
324  *s = ' ';
325  }
326  }
327 
328  /* get the error associated with specified significant figures; add
329  * FLT_EPSILON*wavelength to broaden bounds enough to allow for
330  * cancellation error
331  */
332  realnum errorwave = WavlenErrorGet( wavelength1, LineSave.sig_figs ) + FLT_EPSILON*wavelength1,
333  smallest_error=BIGFLOAT,
334  smallest_error_w_correct_label=BIGFLOAT;
335 
336  // Possibly more 'user friendly' line search mode -- not active
337  // NB falls through to previous implementation if ipass < 1, as
338  // lines will not yet be sorted
339  if (ipass == 1)
340  {
341  char wlbuf[INPUT_LINE_LENGTH];
342  // Need to search for lines within allowed band, and plausible confusions
343 
344  // Find position in list of lines
345  vector<size_t>::iterator first =
346  lower_bound(SortWL.begin(),SortWL.end(),
347  wavelength1+errorwave, wavelength_compare_realnum);
348 
349  // first is now first line below upper limit
350  if (first == SortWL.end())
351  {
352  sprt_wl(wlbuf,wavelength1);
353  fprintf(ioQQQ,"Didn't find anything at %s\n",wlbuf);
355  }
356 
357  // look for first line below lower limit -- may be the same as first if there are no matches
358  vector<size_t>::iterator second;
359  for(second=first; second != SortWL.end(); ++second)
360  {
361  if (wavelength(*second) < wavelength1-errorwave)
362  break;
363  }
364 
365  vector<size_t>::iterator found = SortWL.end();
366  int nmatch=0;
367  realnum dbest = 0.;
368  for (vector<size_t>::iterator pos = first; pos != second; ++pos)
369  {
370  if ( strcmp(lines[*pos].chCLab(),chCARD) == 0 )
371  {
372  ++nmatch;
373  realnum dwl = wavelength(*pos)-wavelength1;
374  if(nmatch >= 2 && !t_version::Inst().lgReleaseBranch
375  && !t_version::Inst().lgRelease )
376  {
377  if (nmatch == 2)
378  {
379  sprt_wl(wlbuf,wavelength1);
380  fprintf(ioQQQ,"WARNING: multiple matching lines found in search for \"%s\" %s\n",
381  chLabel,wlbuf);
382  fprintf(ioQQQ,"WARNING: match 1 is \"%s\" (dwl=%gA)\n",
383  lines[*found].biglabel().c_str(),wavelength(*found)-wavelength1);
384  }
385  fprintf(ioQQQ,"WARNING: match %d is \"%s\" (dwl=%gA)\n",
386  nmatch, lines[*pos].biglabel().c_str(),dwl);
387  }
388  if ( found == SortWL.end() )
389  {
390  found = pos;
391  dbest = fabs(wavelength(*pos)-wavelength1);
392  }
393  else if ( fabs(dwl) < dbest )
394  {
395  found = pos;
396  dbest = fabs(dwl);
397  }
398  }
399  }
400  if ( found != SortWL.end())
401  {
402  if (0)
403  fprintf(ioQQQ,"Found %s\n", lines[*found].label().c_str());
404  return *found;
405  }
406 
407  sprt_wl(wlbuf,wavelength1);
408  fprintf(ioQQQ,"WARNING: no exact matching lines found for \"%s\" %s\n",chLabel,wlbuf);
409  for (vector<size_t>::iterator pos = first; pos != second; ++pos)
410  {
411  fprintf(ioQQQ,"WARNING: Line with incorrect label found close \"%s\"\n",
412  lines[*pos].label().c_str());
413  }
414  // Haven't found a match with correct label
415  vector<size_t>::iterator best = SortWL.end();
416  realnum besterror = 0.;
417  for (;;)
418  {
419  realnum errordown = wavelength(*(first-1))-wavelength1;
420  realnum errorup = wavelength1- (second == SortWL.end() ? 0.0 : wavelength(*second)) ;
421  realnum error = 0.;
422  vector<size_t>::iterator next;
423  if ( errordown < errorup || second == SortWL.end())
424  {
425  error = errordown;
426  --first;
427  next = first;
428  }
429  else
430  {
431  error = errorup;
432  next = second;
433  ++second;
434  }
435  if ( strcmp(lines[*next].chCLab(),chCARD) == 0 )
436  {
437  if (best == SortWL.end())
438  {
439  best = next;
440  besterror = error;
441  fprintf(ioQQQ,"Taking best match as \"%s\"\n",lines[*next].label().c_str());
442  }
443  else
444  {
445  fprintf(ioQQQ,"Possible ambiguity with \"%s\"\n",lines[*next].label().c_str());
446  }
447  }
448  // Assume this is clearly unambiguous
449  if (best != SortWL.end() && error > 100.*besterror)
450  break;
451  // Assume this is clearly unmatched
452  if (error > 0.01*wavelength1)
453  break;
454  }
455  if (best != SortWL.end())
456  return *best;
457 
458  sprt_wl(wlbuf,wavelength1);
459  fprintf(ioQQQ,"PROBLEM: no matching line found in search for \"%s\" %s\n",chLabel,wlbuf);
461  }
462 
463  // Falls through to previous implementation if ipass < 1. Can
464  // be more restrictive with match handling, as this will be from
465  // a request internal to the code infrastructure, rather than
466  // user data
467 
468  long int j, index_of_closest=LONG_MIN,
469  index_of_closest_w_correct_label=-1;
470 
471  for( j=1; j < nsum; j++ )
472  {
473  realnum current_error = (realnum)fabs(wavelength(j)-wavelength1);
474  /* use pre-capitalized version of label to be like input chLineLabel */
475  const char *chCaps = lines[j].chCLab();
476 
477  if( current_error < smallest_error )
478  {
479  index_of_closest = j;
480  smallest_error = current_error;
481  }
482 
483  if( current_error < smallest_error_w_correct_label &&
484  (strcmp(chCaps,chCARD) == 0) )
485  {
486  index_of_closest_w_correct_label = j;
487  smallest_error_w_correct_label = current_error;
488  }
489 
490  /* check wavelength and chLabel for a match */
491  /*if( fabs(lines[j].wavelength- wavelength)/MAX2(DELTA,wavelength)<errorwave &&
492  strcmp(chCaps,chCARD) == 0 ) */
493  if( lgDEBUG && (current_error <= errorwave ||
494  fp_equal( wavelength1 + errorwave, wavelength(j) ) ||
495  fp_equal( wavelength1 - errorwave, wavelength(j) ))
496  && strcmp(chCaps,chCARD) == 0 )
497  {
498  /* match, so set emiss to emissivity in line */
499  /* and announce success by returning line index within stack */
500  printf("Matched %s %15.8g %ld %18.11g %s\n",
501  chCaps,wavelength1,j,wavelength(j),
502  lines[j].biglabel().c_str());
503  }
504  }
505 
506 
507  // Didn't find line, handle error
508  if( index_of_closest_w_correct_label == -1 ||
509  smallest_error_w_correct_label > errorwave )
510  {
511  /* >>chng 05 dec 21, report closest line if we did not find exact match, note that
512  * exact match returns above, where we will return negative number of lines in stack */
513  fprintf( ioQQQ," PROBLEM findline did not find line " );
514  prt_line_err( ioQQQ, chCARD, wavelength1 );
515  if( index_of_closest >= 0 )
516  {
517  fprintf( ioQQQ," The closest line (any label) was \"%s\"\n",
518  lines[index_of_closest].label().c_str() );
519  if( index_of_closest_w_correct_label >= 0 )
520  {
521  fprintf( ioQQQ," The closest with correct label was \"%s\"\n",
522  lines[index_of_closest_w_correct_label].label().c_str() );
523  fprintf( ioQQQ," Error was %15.8g vs. tolerance %15.8g\n",
524  smallest_error_w_correct_label, errorwave );
525  }
526  else
527  fprintf( ioQQQ,"\n No line found with label \"%s\".\n", chCARD );
528  fprintf( ioQQQ,"\n" );
529  }
530  else
531  {
532  fprintf( ioQQQ,".\n PROBLEM No close line was found\n" );
533  TotalInsanity();
534  }
535  return -3;
536  }
537 
538  if (lgDEBUG)
539  fprintf(ioQQQ,"Identified %ld\n",index_of_closest_w_correct_label);
540 
541 
542  return index_of_closest_w_correct_label;
543 }
544 
545 /*************************************************************************
546  *
547  * cdEmis obtain the local emissivity for a line with known index
548  *
549  ************************************************************************/
550 void cdEmis(
551  const LinSv* line,
552  /* the vol emissivity of this line in last computed zone */
553  double *emiss ,
554  // intrinsic or emergent
555  bool lgEmergent )
556 {
557  DEBUG_ENTRY( "cdEmis()" );
558 
559  if (line)
560  *emiss = line->emslin(lgEmergent);
561  else
562  *emiss = 0.;
563 }
564 
vector< long > m_component
Definition: lines.h:166
void setSortWL()
Definition: lines.cpp:283
vector< size_t > SortWL
Definition: lines.h:134
long m_index
Definition: lines.h:158
realnum WavlenErrorGet(realnum wavelength, long sig_figs)
NORETURN void TotalInsanity(void)
Definition: service.cpp:971
long findline(const char *chLabel, realnum wavelength)
Definition: lines.cpp:294
void chALabSet(const char *that)
Definition: lines.cpp:75
double emslin(int i) const
Definition: lines.h:279
static bool wavelength_compare_realnum(size_t a, realnum wavelength)
Definition: lines.cpp:274
string label() const
Definition: lines.cpp:41
t_LineSave LineSave
Definition: lines.cpp:10
bool lgNormSet
Definition: lines.h:123
void prt(FILE *fp) const
Definition: lines.cpp:35
void SumLineZero()
Definition: lines.h:262
FILE * ioQQQ
Definition: cddefines.cpp:7
string chComment() const
Definition: lines.cpp:258
vector< LinSv > lines
Definition: lines.h:132
void trimTrailingWhiteSpace(string &str)
Definition: service.cpp:153
static t_version & Inst()
Definition: cddefines.h:209
bool associated() const
Definition: transition.h:54
void prt_line_err(FILE *ioOUT, const char *label, realnum wvlng)
Definition: prt.cpp:161
bool fp_equal(sys_float x, sys_float y, int n=3)
Definition: cddefines.h:854
char m_chCLab[NCHLAB]
Definition: lines.h:161
TransitionProxy m_tr
Definition: lines.h:167
float realnum
Definition: cddefines.h:124
#define EXIT_FAILURE
Definition: cddefines.h:168
const realnum BIGFLOAT
Definition: cpu.h:244
const int INPUT_LINE_LENGTH
Definition: cddefines.h:301
realnum WavLNorm
Definition: lines.h:105
qList::iterator Hi() const
Definition: transition.h:435
#define cdEXIT(FAIL)
Definition: cddefines.h:482
static double a1[83]
static realnum b1[83]
realnum wlAirVac(double wlAir)
long int sig_figs
Definition: lines.h:109
char chNormLab[NCHLAB]
Definition: lines.h:120
void init(long index, char chSumTyp, const char *chComment, const char *label, const TransitionProxy &tr)
Definition: lines.cpp:90
#define ASSERT(exp)
Definition: cddefines.h:613
void sprt_wl(char *chString, realnum wl)
Definition: prt.cpp:56
qList::iterator Lo() const
Definition: transition.h:431
void addComponentID(long id)
Definition: lines.cpp:178
bool isCat(const char *s) const
Definition: lines.cpp:69
enum LinSv::@8 m_type
void cdEmis(const char *chLabel, realnum wavelength, double *emiss, bool lgEmergent)
Definition: cddrive.cpp:552
long int ipNormWavL
Definition: lines.h:102
char m_chALab[NCHLAB]
Definition: lines.h:160
string biglabel() const
Definition: lines.cpp:53
const char * chALab() const
Definition: lines.h:188
#define DEBUG_ENTRY(funcname)
Definition: cddefines.h:723
void addComponent(const char *species, const double wavelength)
Definition: lines.cpp:194
char chSumTyp() const
Definition: lines.h:182
static vector< realnum > wavelength
string m_chComment
Definition: lines.h:165
realnum wavelength() const
Definition: lines.h:323
const int NCHLAB
Definition: cddefines.h:304
char m_chSumTyp
Definition: lines.h:159
realnum wavelength(long index)
Definition: lines.h:145
int fprintf(const Output &stream, const char *format,...)
Definition: service.cpp:1121
void emslinZero()
Definition: lines.h:303
static bool wavelength_compare(long a, long b)
Definition: lines.cpp:263
long int nsum
Definition: lines.h:87
static const long sig_figs_max
Definition: lines.h:110
void caps(char *chCard)
Definition: service.cpp:295
void zero()
Definition: lines.cpp:13
void makeBlend(const char *species, const double wavelength, const double width)
Definition: lines.cpp:210
Definition: lines.h:157
long int ipass
Definition: lines.h:96
double ScaleNormLine
Definition: lines.h:117