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