root/branches/newmole/source/cddrive.cpp

Revision 2582, 58.7 kB (checked in by rporter, 2 weeks ago)

branches/newmole - bring in trunk r2541:2581

  • Property svn:eol-style set to native
Line 
1/* This file is part of Cloudy and is copyright (C)1978-2008 by Gary J. Ferland and
2 * others.  For conditions of distribution and use see copyright notice in license.txt */
3/*cdDrive main routine to call cloudy under all circumstances) */
4/*cdReasonGeo write why the model stopped and type of geometry on io file */
5/*cdWarnings write all warnings entered into comment stack */
6/*cdEms obtain the local emissivity for a line, for the last computed zone */
7/*cdColm get the column density for a constituent  */
8/*cdLine get the predicted line intensity, also index for line in stack */
9/*cdLine_ip get the predicted line intensity, using index for line in stack */
10/*cdDLine get the predicted emergent line intensity, also index for line in stack */
11/*cdCautions print out all cautions after calculation, on arbitrary io unit */
12/*cdTemp_last routine to query results and return temperature of last zone */
13/*cdDepth_depth get depth structure from previous iteration */
14/*cdTimescales returns thermal, recombination, and H2 formation timescales */
15/*cdSurprises print out all surprises on arbitrary unit number */
16/*cdNotes print stack of notes about current calculation */
17/*cdPressure_last routine to query results and return pressure of last zone */
18/*cdTalk tells the code whether to print results or be silent */
19/*cdOutp redirect output to arbitrary Fortran unit number */
20/*cdRead routine to read in command lines when cloudy used as subroutine */
21/*cdErrors produce summary of all warnings, cautions, etc, on arbitrary io unit */
22/*cdIonFrac get ionization fractions for a constituent */
23/*cdTemp get mean electron temperature for any element */
24/*cdCooling_last routine to query results and return cooling of last zone */
25/*cdHeating_last routine to query results and return heating of last zone */
26/*cdEDEN_last return electron density of last zone */
27/*cdNoExec call this routine to tell code not to actually execute */
28/*cdDate - puts date of code into string */
29/*cdVersion produces string that gives version number of the code */
30/*cdExecTime any routine can call this, find the time [s] since cdInit was called */
31/*cdPrintCommands( FILE *) prints all input commands into file */
32/*cdDrive main routine to call cloudy under all circumstances) */
33/*cdNwcns get the number of cautions and warnings, to tell if calculation is ok */
34/*debugLine provides a debugging hook into the main line array  */
35/*cdEms_ip obtain the local emissivity for a line with known index */
36/*cdnZone gets number of zones */
37/*cdClosePunchFiles closes all the punch files that have been used */
38/*cdLineListPunch create a file with a list of all emission lines punched,
39 *and their index within the emission line stack */
40/*cdB21cm - returns B as measured by 21 cm */
41/*cdPrtWL print line wavelengths in Angstroms in the standard format */
42#include "cddefines.h"
43#include "trace.h"
44#include "conv.h"
45#include "init.h"
46#include "lines.h"
47#include "pressure.h"
48#include "prt.h"
49#include "colden.h"
50#include "dense.h"
51#include "radius.h"
52#include "struc.h"
53#include "mole.h"
54#include "elementnames.h"
55#include "mean.h"
56#include "phycon.h"
57#include "called.h"
58#include "parse.h"
59#include "input.h"
60#include "taulines.h"
61#include "version.h"
62#include "thermal.h"
63#include "optimize.h"
64#include "grid.h"
65#include "timesc.h"
66#include "cloudy.h"
67#include "warnings.h"
68#include "lines_service.h"
69#include "cddrive.h"
70
71/*************************************************************************
72 *
73 * cdDrive - main routine to call cloudy - returns 0 if all ok, 1 if problems
74 *
75 ************************************************************************/
76
77int cdDrive(void )
78{
79        bool lgBAD;
80
81        DEBUG_ENTRY( "cdDrive()" );
82        /*********************************
83         * main routine to call cloudy   *
84         *********************************/
85
86        /* this is set false when code loaded, set true when cdInit called,
87         * this is check that cdInit was called first */
88        if( !lgcdInitCalled )
89        {
90                printf(" cdInit was not called first - this must be the first call.\n");
91                cdEXIT(EXIT_FAILURE);
92        }
93
94        if( trace.lgTrace )
95        {
96                fprintf( ioQQQ,
97                        "cdDrive: lgOptimr=%1i lgVaryOn=%1i lgNoVary=%1i input.nSave:%li\n",
98                        optimize.lgOptimr , optimize.lgVaryOn , optimize.lgNoVary, input.nSave );
99        }
100
101        /* should we call cloudy, or the optimization driver?
102         * possible to have VARY on line without OPTIMIZE being set
103         * lgNoVary set with "no optimize" command */
104        if( optimize.lgOptimr && optimize.lgVaryOn && !optimize.lgNoVary )
105                optimize.lgVaryOn = true;
106        else
107                optimize.lgVaryOn = false;
108
109        /* one time initialization of core load - returns if already called
110         * called here rather than in cdInit since at this point we know if
111         * single sim or grid */
112        InitCoreload();
113        /* count now many sims have been done in this coreload, above set to
114         * zero if first call, does nothing on subsequent calls
115         * this increment brings to 1 on first sim */
116        ++nSimThisCoreload;
117
118        if( optimize.lgVaryOn )
119        {
120                /* this branch called if optimizing or grid calculation */
121                if( trace.lgTrace )
122                        fprintf( ioQQQ, "cdDrive: calling grid_do\n");
123                /* option to drive optimizer set if OPTIMIZE was in input stream */
124                lgBAD = grid_do();
125        }
126        else
127        {
128                if( trace.lgTrace )
129                        fprintf( ioQQQ, "cdDrive: calling cloudy\n");
130                try {
131
132                        /* optimize did not occur, only compute one model, call cloudy */
133                        lgBAD = cloudy();
134                }
135                catch( bad_mpi &bad_info )
136                {
137                        fprintf( ioQQQ, "An MPI run failed.  The fail mode is %li\n", bad_info.failMode() );
138                        ClosePunchFiles( false );
139                        lgAbort = true;
140                        lgBAD = true;
141                }
142        }
143
144        /* reset flag saying that cdInit has not been called */
145        lgcdInitCalled = false;
146
147        if( lgAbort || lgBAD )
148        {
149                if( trace.lgTrace )
150                        fprintf( ioQQQ, "cdDrive: returning failure during call. \n");
151                /* lgAbort set true if something wrong, so return lgBAD false. */
152                return(1);
153        }
154        else
155        {
156                /* everything is ok, return 0 */
157                return(0);
158        }
159}
160
161/*************************************************************************
162*
163* cdPrtWL write emission line wavelength
164*
165************************************************************************/
166
167/*cdPrtWL print line wavelengths in Angstroms in the standard format -
168 * a wrapper for prt_wl which must be kept parallel with sprt_wl
169 * both of those live in pdt.c */
170void cdPrtWL( FILE *io , realnum wl )
171{
172
173        DEBUG_ENTRY( "cdPrtWL()" );
174
175        prt_wl( io , wl );
176        return;
177}
178
179
180/*************************************************************************
181 *
182 * cdReasonGeo write why the model stopped and type of geometry on io file
183 *
184 ************************************************************************/
185
186
187/*cdReasonGeo write why the model stopped and type of geometry on io file */
188void cdReasonGeo(FILE * ioOUT)
189{
190
191        DEBUG_ENTRY( "cdReasonGeo()" );
192
193        /*this is the reason the calculation stopped*/
194        fprintf( ioOUT, "%s", warnings.chRgcln[0] );
195        fprintf( ioOUT , "\n" );
196        /* this is the geometry */
197        fprintf( ioOUT, "%s", warnings.chRgcln[1] );
198        fprintf( ioOUT , "\n" );
199        return;
200}
201
202
203/*************************************************************************
204 *
205 * cdWarnings write all warnings entered into comment stack
206 *
207 ************************************************************************/
208
209/*cdWarnings write all warnings entered into comment stack */
210
211void cdWarnings(FILE *ioPNT )
212{
213        long int i;
214
215        DEBUG_ENTRY( "cdWarnings()" );
216
217        if( warnings.nwarn > 0 )
218                {
219                        for( i=0; i < warnings.nwarn; i++ )
220                        {
221                                /* these are all warnings that were entered in comment */
222                                fprintf( ioPNT, "%s", warnings.chWarnln[i] );
223                                fprintf( ioPNT, "\n" );
224                        }
225                }
226
227        return;
228}
229
230
231/*************************************************************************
232 *
233 * cdCautions print out all cautions after calculation, on arbitrary io unit
234 *
235 ************************************************************************/
236
237/*cdCautions print out all cautions after calculation, on arbitrary io unit */
238
239void cdCautions(FILE * ioOUT)
240{
241        long int i;
242
243        DEBUG_ENTRY( "cdCautions()" );
244
245        if( warnings.ncaun > 0 )
246        {
247                for( i=0; i < warnings.ncaun; i++ )
248                {
249                        fprintf( ioOUT, "%s", warnings.chCaunln[i] );
250                        fprintf( ioOUT, "\n" );
251                }
252        }
253        return;
254}
255
256/*************************************************************************
257 *
258 * cdTimescales returns thermal, recombination, and H2 formation timescales
259 *
260 ************************************************************************/
261
262void cdTimescales(
263        /* the thermal cooling timescale */
264        double *TTherm ,
265        /* the hydrogen recombination timescale */
266        double *THRecom ,
267        /* the H2 formation timescale */
268        double *TH2 )
269{
270
271        DEBUG_ENTRY( "cdTimescales()" );
272
273        /* these were all evaluated in AgeCheck, which was called by PrtComment */
274
275        /* thermal or cooling timescale */
276        *TTherm = timesc.time_therm_long;
277
278        /* the hydrogen recombination timescale */
279        *THRecom = timesc.time_Hrecom_long;
280
281        /* longer of the the H2 formation and destruction timescales */
282        *TH2 = MAX2( timesc.time_H2_Dest_longest , timesc.time_H2_Form_longest );
283        return;
284}
285
286
287/*************************************************************************
288 *
289 * cdSurprises print out all surprises on arbitrary unit number
290 *
291 ************************************************************************/
292
293/*cdSurprises print out all surprises on arbitrary unit number */
294
295void cdSurprises(FILE * ioOUT)
296{
297        long int i;
298
299        DEBUG_ENTRY( "cdSurprises()" );
300
301        if( warnings.nbang > 0 )
302        {
303                for( i=0; i < warnings.nbang; i++ )
304                {
305                        fprintf( ioOUT, "%s", warnings.chBangln[i] );
306                        fprintf( ioOUT, "\n" );
307                }
308        }
309
310        return;
311}
312
313
314/*************************************************************************
315 *
316 * cdNotes print stack of notes about current calculation
317 *
318 ************************************************************************/
319
320/*cdNotes print stack of notes about current calculation */
321
322void cdNotes(FILE * ioOUT)
323{
324        long int i;
325
326        DEBUG_ENTRY( "cdNotes()" );
327
328        if( warnings.nnote > 0 )
329        {
330                for( i=0; i < warnings.nnote; i++ )
331                {
332                        fprintf( ioOUT, "%s", warnings.chNoteln[i] );
333                        fprintf( ioOUT, "\n" );
334                }
335        }
336        return;
337}
338
339/*************************************************************************
340 *
341 * cdCooling_last routine to query results and return cooling of last zone
342 *
343 ************************************************************************/
344
345/*cdCooling_last routine to query results and return cooling of last zone */
346double cdCooling_last(void) /* return cooling for last zone */
347{
348        return (thermal.ctot);
349}
350
351/*************************************************************************
352 *
353 * cdVersion - puts version number of code into string
354 * incoming string must have sufficient length and will become null
355 * terminated string
356 *
357 ************************************************************************/
358
359void cdVersion(char chString[])
360{
361        strcpy( chString , t_version::Inst().chVersion );
362        return;
363}
364
365/*************************************************************************
366 *
367 * cdDate - puts date of code into string
368 * incoming string must have at least 8 char and will become null
369 * terminated string
370 *
371 ************************************************************************/
372
373/* cdDate - puts date of code into string  */
374void cdDate(char chString[])
375{
376        strcpy( chString , t_version::Inst().chDate );
377        return;
378}
379
380
381/*************************************************************************
382 *
383 * cdHeating_last routine to query results and return heating of last zone
384 *
385 ************************************************************************/
386
387/*cdHeating_last routine to query results and return heating of last zone */
388
389double cdHeating_last(void) /* return heating for last zone */
390{
391        return (thermal.htot);
392}
393
394
395/*************************************************************************
396 *
397 * cdEDEN_last return electron density of last zone
398 *
399 ************************************************************************/
400
401/*cdEDEN_last return electron density of last zone */
402
403double cdEDEN_last(void) /* return electron density for last zone */
404{
405        return ( dense.eden );
406}
407
408/*************************************************************************
409 *
410 * cdNoExec call this routine to tell code not to actually execute
411 *
412 ************************************************************************/
413
414/*cdNoExec call this routine to tell code not to actually execute */
415#include "noexec.h"
416
417void cdNoExec(void)
418{
419
420        DEBUG_ENTRY( "cdNoExec()" );
421
422        /* option to read in all input quantiles and NOT execute the actual model
423         * only check on input parameters - set by calling cdNoExec */
424        noexec.lgNoExec = true;
425
426        return;
427}
428
429
430/*************************************************************************
431 *
432 * cdSetExecTime routine to initialize variables keeping track of time at start of calculation
433 *
434 ************************************************************************/
435
436/* set to false initially, then to true when cdSetExecTime() is called to
437 * initialize the clock */
438static bool lgCalled=false;
439
440/* >>chng 06 dec 19, RP rm "|| defined(__HP_aCC)" to run on hp */
441#if defined(_MSC_VER)
442/* _MSC_VER branches assume getrusage isn't implemented by MS
443 * also is not implemented on our HP superdome */
444struct timeval {
445        long    tv_sec;         /* seconds */
446        long    tv_usec;        /* microseconds */
447};
448#else
449#include <sys/time.h>
450#include <sys/resource.h>
451#endif
452
453/* will be used to save initial time */
454static struct timeval before;
455
456/* cdClock stores time since arbitrary datum in clock_dat           */
457STATIC void cdClock(struct timeval *clock_dat)
458{
459        DEBUG_ENTRY( "cdClock()" );
460
461/* >>chng 06 sep 2 rjrw: use long recurrence, fine grain UNIX clock *
462 * -- maintain system dependences in a single routine               */
463#if defined(_MSC_VER) || defined(__HP_aCC)
464        clock_t clock_val;
465        /* >>chng 05 dec 21, from above to below due to negative exec times */
466        /*return(  (double)(clock() - before) / (double)CLOCKS_PER_SEC );*/
467        clock_val = clock();
468        clock_dat->tv_sec = clock_val/CLOCKS_PER_SEC;
469        clock_dat->tv_usec = 1000000*(clock_val-(clock_dat->tv_sec*CLOCKS_PER_SEC))/CLOCKS_PER_SEC;
470        /*>>chng 06 oct 05, this produced very large number, time typically 50% too long
471        clock_dat->tv_usec = 0;*/
472#else
473        struct rusage rusage;
474        if(getrusage(RUSAGE_SELF,&rusage) != 0)
475        {
476                fprintf( ioQQQ, "DISASTER cdClock called getrusage with invalid arguments.\n" );
477                fprintf( ioQQQ, "Sorry.\n" );
478                cdEXIT(EXIT_FAILURE);
479        }
480        clock_dat->tv_sec = rusage.ru_utime.tv_sec;
481        clock_dat->tv_usec = rusage.ru_utime.tv_usec;
482#endif
483
484}
485/* cdSetExecTime is called by cdInit when everything is initialized,
486 * so that every time cdExecTime is called the elapsed time is returned */
487void cdSetExecTime(void)
488{
489        cdClock(&before);
490        lgCalled = true;
491}
492/* cdExecTime returns the elapsed time cpu time (sec) that has elapsed
493 * since cdInit called cdSetExecTime.*/
494double cdExecTime(void)
495{
496        DEBUG_ENTRY( "cdExecTime()" );
497
498        struct timeval clock_dat;
499        /* check that we were properly initialized */
500        if( lgCalled)
501        {
502                cdClock(&clock_dat);
503                /*fprintf(ioQQQ,"\n DEBUG sec %.2e usec %.2e\n",
504                        (double)(clock_dat.tv_sec-before.tv_sec),
505                        1e-6*(double)(clock_dat.tv_usec-before.tv_usec));*/
506                return (double)(clock_dat.tv_sec-before.tv_sec)+1e-6*(double)(clock_dat.tv_usec-before.tv_usec);
507        }
508        else
509        {
510                /* this is a big problem, we were asked for the elapsed time but
511                 * the timer was not initialized by calling SetExecTime */
512                fprintf( ioQQQ, "DISASTER cdExecTime was called before SetExecTime, impossible.\n" );
513                fprintf( ioQQQ, "Sorry.\n" );
514                cdEXIT(EXIT_FAILURE);
515        }
516}
517
518/*************************************************************************
519 *
520 * cdPrintCommands prints all input commands into file
521 *
522 ************************************************************************/
523
524/* cdPrintCommands( FILE *)
525 * prints all input commands into file */
526void cdPrintCommands( FILE * ioOUT )
527{
528        long int i;
529        fprintf( ioOUT, " Input commands follow:\n" );
530        fprintf( ioOUT, "c ======================\n" );
531
532        for( i=0; i <= input.nSave; i++ )
533        {
534                fprintf( ioOUT, "%s\n", input.chCardSav[i] );
535        }
536        fprintf( ioOUT, "c ======================\n" );
537}
538
539
540/*************************************************************************
541 *
542 * cdEms obtain the local emissivity for a line, for the last computed zone
543 *
544 ************************************************************************/
545
546/* \todo 2 This routine, cdLine, cdEmis_ip, and cdLine_ip should be consolidated somewhat.
547 * in particular so that this routine has the same "closest line" reporting that cdLine has. */
548long int cdEmis(
549        /* return value will be index of line within stack,
550         * negative of number of lines in the stack if the line could not be found*/
551        /* 4 char null terminated string label */
552        char *chLabel,
553        /* line wavelength */
554        realnum wavelength,
555        /* the vol emissivity of this line in last computed zone */
556        double *emiss )
557{
558        /* use following to store local image of character strings */
559        char chCARD[INPUT_LINE_LENGTH];
560        char chCaps[5];
561        long int j;
562        realnum errorwave;
563
564        DEBUG_ENTRY( "cdEms()" );
565
566        /* routine returns the emissivity in the desired line
567         * only used internally by the code, to do punch lines structure */
568
569        strcpy( chCARD, chLabel );
570
571        /* make sure chLabel is all caps */
572        caps(chCARD);/* convert to caps */
573
574        /* get the error associated with 4 significant figures */
575        errorwave = WavlenErrorGet( wavelength );
576
577        for( j=0; j < LineSave.nsum; j++ )
578        {
579                /* change chLabel to all caps to be like input chLineLabel */
580                cap4(chCaps , (char*)LineSv[j].chALab);
581
582                /* check wavelength and chLabel for a match */
583                /*if( fabs(LineSv[j].wavelength- wavelength)/MAX2(DELTA,wavelength)<errorwave &&
584                        strcmp(chCaps,chCARD) == 0 ) */
585                if( fabs(LineSv[j].wavelength-wavelength) < errorwave && strcmp(chCaps,chCARD) == 0 )
586                {
587                        /* match, so set emiss to emissivity in line */
588                        *emiss = LineSv[j].emslin[LineSave.lgLineEmergent];
589                        /* and announce success by returning line index within stack */
590                        return j;
591                }
592        }
593
594        /* we fell through without finding the line - return false */
595        return -LineSave.nsum;
596}
597
598/*************************************************************************
599 *
600 * cdEms_ip obtain the local emissivity for a line with known index
601 *
602 ************************************************************************/
603
604void cdEmis_ip(
605        /* index of the line in the stack */
606        long int ipLine,
607        /* the vol emissivity of this line in last computed zone */
608        double *emiss )
609{
610        DEBUG_ENTRY( "cdEmis_ip()" );
611
612        /* returns the emissivity in a line - implements punch lines structure
613         * this version uses previously stored line index to save speed */
614        ASSERT( ipLine >= 0 && ipLine < LineSave.nsum );
615        *emiss = LineSv[ipLine].emslin[LineSave.lgLineEmergent];
616        return;
617}
618
619/*************************************************************************
620 *
621 * cdColm get the column density for a constituent - 0 return if ok, 1 if problems
622 *
623 ************************************************************************/
624
625int cdColm(
626        /* return value is zero if all ok, 1 if errors happened */
627        /* 4-char + eol string that is first
628         * 4 char of element name as spelled by Cloudy, upper or lower case */
629        const char *chLabel,   
630
631        /* integer stage of ionization, 1 for atom, 2 for A+, etc,
632         * 0 is special flag for CO, H2, OH, or excited state */
633        long int ion,
634
635        /* the column density derived by the code [cm-2] */
636        double *theocl )       
637{
638        long int nelem;
639        /* use following to store local image of character strings */
640        char chLABEL_CAPS[20];
641
642        DEBUG_ENTRY( "cdColm()" );
643
644        /* check that chLabel[4] is null - supposed to be 4 char + end */
645        if( chLabel[4]!=0 )
646        {
647                fprintf( ioQQQ, " cdColm called with insane ion label, =%s, must be 4 character + end of string.\n",
648                  chLabel );
649                return(1);
650        }
651
652        strcpy( chLABEL_CAPS, chLabel );
653        /* convert element label to all caps */
654        caps(chLABEL_CAPS);
655
656        /* zero ionization stage has special meaning.  The quantities recognized are
657         * the molecules, "H2  ", "OH  ", "CO  ", etc
658         * "CII*" excited state C+ */
659        if( ion < 0 )
660        {
661                fprintf( ioQQQ, " cdColm called with insane ion, =%li\n",
662                  ion );
663                return(1);
664        }
665
666        else if( ion == 0 )
667        {
668                /* this case molecular column density */
669                /* want the molecular hydrogen H2 column density */
670                if( strcmp( chLABEL_CAPS , "H2  " )==0 )
671                {
672                        *theocl = colden.colden[ipCOL_H2g] + colden.colden[ipCOL_H2s];
673                }
674
675                /* H- column density  */
676                else if( strcmp( chLABEL_CAPS , "H-  " )==0 )
677                {
678                        *theocl = colden.colden[ipCOL_HMIN];
679                }
680
681                /* H2+ column density ipCOL_H2p is 4 */
682                else if( strcmp( chLABEL_CAPS , "H2+ " )==0 )
683                {
684                        *theocl = colden.colden[ipCOL_H2p];
685                }
686
687                /* H3+ column density */
688                else if( strcmp( chLABEL_CAPS , "H3+ " )==0 )
689                {
690                        *theocl = colden.colden[ipCOL_H3p];
691                }
692
693                /* H2g - ground H2 column density */
694                else if( strcmp( chLABEL_CAPS , "H2G " )==0 )
695                {
696                        *theocl = colden.colden[ipCOL_H2g];
697                }
698
699                /* H2* - excited H2 - column density */
700                else if( strcmp( chLABEL_CAPS , "H2* " )==0 )
701                {
702                        *theocl = colden.colden[ipCOL_H2s];
703                }
704
705                /* HeH+ column density */
706                else if( strcmp( chLABEL_CAPS , "HEH+" )==0 )
707                {
708                        *theocl = colden.colden[ipCOL_HeHp];
709                }
710
711                /* carbon monoxide column density */
712                else if( strcmp( chLABEL_CAPS , "CO  " )==0 )
713                {
714                        *theocl = findspecies("CO")->column;
715                }
716
717                /* OH column density */
718                else if( strcmp( chLABEL_CAPS , "OH  " )==0 )
719                {
720                        *theocl = findspecies("OH")->column;
721                }
722
723                /* H2O column density */
724                else if( strcmp( chLABEL_CAPS , "H2O " )==0 )
725                {
726                        *theocl = findspecies("H2O")->column;
727                }
728
729                /* O2 column density */
730                else if( strcmp( chLABEL_CAPS , "O2  " )==0 )
731                {
732                        *theocl = findspecies("O2")->column;
733                }
734
735                /* SiO column density */
736                else if( strcmp( chLABEL_CAPS , "SIO " )==0 )
737                {
738                        *theocl = findspecies("SiO")->column;
739                }
740
741                /* C2 column density */
742                else if( strcmp( chLABEL_CAPS , "C2  " )==0 )
743                {
744                        *theocl = findspecies("C2")->column;
745                }
746
747                /* C3 column density */
748                else if( strcmp( chLABEL_CAPS , "C3  " )==0 )
749                {
750                        *theocl = findspecies("C3")->column;
751                }
752
753                /* CN column density */
754                else if( strcmp( chLABEL_CAPS , "CN  " )==0 )
755                {
756                        *theocl = findspecies("CN")->column;
757                }
758
759                /* CH column density */
760                else if( strcmp( chLABEL_CAPS , "CH  " )==0 )
761                {
762                        *theocl = findspecies("CH")->column;
763                }
764
765                /* CH+ column density */
766                else if( strcmp( chLABEL_CAPS , "CH+ " )==0 )
767                {
768                        *theocl = findspecies("CH+")->column;
769                }
770
771                /* ===========================================================*/
772                /* end special case molecular column densities, start special cases
773                 * excited state column densities */
774                /* CII^* column density, population of J=3/2 upper level of split ground term */
775                else if( strcmp( chLABEL_CAPS , "CII*" )==0 )
776                {
777                        *theocl = colden.C2Colden[1];
778                }
779                else if( strcmp( chLABEL_CAPS , "C11*" )==0 )
780                {
781                        *theocl = colden.C1Colden[0];
782                }
783                else if( strcmp( chLABEL_CAPS , "C12*" )==0 )
784                {
785                        *theocl = colden.C1Colden[1];
786                }
787                else if( strcmp( chLABEL_CAPS , "C13*" )==0 )
788                {
789                        *theocl = colden.C1Colden[2];
790                }
791                else if( strcmp( chLABEL_CAPS , "O11*" )==0 )
792                {
793                        *theocl = colden.O1Colden[0];
794                }
795                else if( strcmp( chLABEL_CAPS , "O12*" )==0 )
796                {
797                        *theocl = colden.O1Colden[1];
798                }
799                else if( strcmp( chLABEL_CAPS , "O13*" )==0 )
800                {
801                        *theocl = colden.O1Colden[2];
802                }
803                /* CIII excited states, upper level of 1909 */
804                else if( strcmp( chLABEL_CAPS , "C30*" )==0 )
805                {
806                        *theocl = colden.C3Colden[1];
807                }
808                else if( strcmp( chLABEL_CAPS , "C31*" )==0 )
809                {
810                        *theocl = colden.C3Colden[2];
811                }
812                else if( strcmp( chLABEL_CAPS , "C32*" )==0 )
813                {
814                        *theocl = colden.C3Colden[3];
815                }
816                else if( strcmp( chLABEL_CAPS , "SI2*" )==0 )
817                {
818                        *theocl = colden.Si2Colden[1];
819                }
820                else if( strcmp( chLABEL_CAPS , "HE1*" )==0 )
821                {
822                        *theocl = colden.He123S;
823                }
824                /* special option, "H2vJ" */
825                else if( strncmp(chLABEL_CAPS , "H2" , 2 ) == 0 )
826                {
827                        long int iVib = chLABEL_CAPS[2] - '0';
828                        long int iRot = chLABEL_CAPS[3] - '0';
829                        if( iVib<0 || iRot < 0 )
830                        {
831                                fprintf( ioQQQ, " cdColm called with insane v,J for H2=\"%4.4s\" caps=\"%4.4s\"\n",
832                                  chLabel , chLABEL_CAPS );
833                                return( 1 );
834                        }
835                        *theocl = cdH2_colden( iVib , iRot );
836                }
837
838                /* clueless as to what was meant - bail */
839                else
840                {
841                        fprintf( ioQQQ, " cdColm called with unknown element chLabel, org=\"%4.4s \" 0 caps=\"%4.4s\" 0\n",
842                          chLabel , chLABEL_CAPS );
843                        return(1);
844                }
845        }
846        else
847        {
848                /* this case, ionization stage of some element */
849                /* find which element this is */
850                nelem = 0;
851                while( nelem < LIMELM &&
852                        strncmp(chLABEL_CAPS,elementnames.chElementNameShort[nelem],4) != 0 )
853                {
854                        ++nelem;
855                }
856
857                /* this is true if we have one of the first 30 elements in the label,
858                 * nelem is on C scale */
859                if( nelem < LIMELM )
860                {
861
862                        /* sanity check - does this ionization stage exist?
863                         * max2 is to pick up H2 as H 3 */
864                        if( ion > MAX2(3,nelem + 2) )
865                        {
866                                fprintf( ioQQQ,
867                                  " cdColm asked to return ionization stage %ld for element %s but this is not physical.\n",
868                                  ion, chLabel );
869                                return(1);
870                        }
871
872                        /* the column density, ion is on physics scale, but means are on C scale */
873                        *theocl = mean.xIonMeans[0][nelem][ion-1];
874                        /*>>chng 06 jan 23, div by factor of two
875                         * special case of H2 when being tricked as H 3 - this stores 2H_2 so that
876                         * the fraction of H in H0 and H+ is correct - need to remove this extra
877                         * factor of two here */
878                        if( nelem==ipHYDROGEN && ion==3 )
879                                *theocl /= 2.;
880                }
881                else
882                {
883                        fprintf( ioQQQ,
884                          " cdColm did not understand this combination of ion %4ld and element %4.4s.\n",
885                          ion, chLabel );
886                        return(1);
887                }
888        }
889        return(0);
890}
891
892
893/*************************************************************************
894 *
895 *cdErrors produce summary of all warnings, cautions, etc, on arbitrary io unit
896 *
897 ************************************************************************/
898
899void cdErrors(FILE *ioOUT)
900{
901        long int nc,
902          nn,
903          npe,
904          ns,
905          nte,
906          nw ,
907          nIone,
908          nEdene;
909        bool lgAbort_loc;
910
911        DEBUG_ENTRY( "cdErrors()" );
912
913        /* first check for number of warnings, cautions, etc */
914        cdNwcns(&lgAbort_loc,&nw,&nc,&nn,&ns,&nte,&npe, &nIone, &nEdene );
915
916        /* only say something is one of these problems is nonzero */
917        if( nw || nc || nte || npe ||   nIone || nEdene || lgAbort_loc )
918        {
919                /* say the title of the model */
920                fprintf( ioOUT, "%75.75s\n", input.chTitle );
921
922                if( lgAbort_loc )
923                        fprintf(ioOUT," Calculation ended with abort!\n");
924
925                /* print warnings on the io unit */
926                if( nw != 0 )
927                {
928                        cdWarnings(ioOUT);
929                }
930
931                /* print cautions on the io unit */
932                if( nc != 0 )
933                {
934                        cdCautions(ioOUT);
935                }
936
937                if( nte != 0 )
938                {
939                        fprintf( ioOUT , "Te failures=%4ld\n", nte );
940                }
941
942                if( npe != 0 )
943                {
944                        fprintf( ioOUT , "Pressure failures=%4ld\n", npe );
945                }
946
947                if( nIone != 0 )
948                {
949                        fprintf( ioOUT , "Ionization failures=%4ld\n", nte );
950                }
951
952                if( nEdene != 0 )
953                {
954                        fprintf( ioOUT , "Electron density failures=%4ld\n", npe );
955                }
956        }
957        return;
958}
959
960/*************************************************************************
961 *
962 *cdDepth_depth get depth structure from previous iteration
963 *
964 ************************************************************************/
965void cdDepth_depth( double cdDepth[] )
966{
967        lo