/* This file is part of Cloudy and is copyright (C)1978-2006 by Gary J. Ferland
 * For conditions of distribution and use see copyright notice in license.txt */
/*InitAssertResults, this must be called first, done at startup of ParseCommands*/
/*ParseAssertResults - parse input stream */
/*lgCheckAsserts, checks asserts, last thing cloudy calls, returns TRUE if all are ok, FALSE if problems */
#include "cddefines.h"
#include "input.h"
#include "conv.h"
#include "iso.h"
#include "called.h"
#include "map.h"
#include "thermal.h"
#include "pressure.h"
#include "struc.h"
#include "wind.h"
#include "h2.h"
#include "colden.h"
#include "dense.h"
#include "lines.h"
#include "secondaries.h"
#include "radius.h"
#include "version.h"
#include "hmi.h"
#include "prt.h"
#include "grainvar.h"
#include "atomfeii.h"
#include "cddrive.h"
#include "elementnames.h"
#include "assertresults.h"

/* flag to remember that InitAssertResults was called */
static int lgInitDone=FALSE , 
	/* will be set true when space for asserts is allocated */
	lgSpaceAllocated=FALSE;

/* number of asserts we can handle, used in dim of space */
#define NASSERTS 100

/* default relative error for asserted quantities */
#define DEF_ERROR 0.05

/* dim of 5 also appears in MALLOC below */
#define NCHAR 5
static char **chAssertLineLabel;

/* this will be = for equal, < or > for limit */
static char *chAssertLimit;

/* this will be a two character label identifying which type of assert */
static char **chAssertType;

/* the values and error in the asserted quantity */
static double *AssertQuantity ,*AssertQuantity2 ,*AssertError, **Param;

/* this flag says where we print linear or log quantity */
static int *lgQuantityLog;
static long nAsserts=0;
static float *wavelength ;

/*======================================================================*/
/*InitAssertResults, this must be called first, done at startup of ParseCommands*/
void InitAssertResults(void)
{
	/* set flag that init was called, and set number of asserts to zero.
	 * this is done by ParseComments for every model, even when no asserts will
	 * be done, so do not allocate space at this time */
	lgInitDone = TRUE;
	nAsserts = 0;
}

/*======================================================================*/
/*ParseAssertResults parse the assert command */
void ParseAssertResults(void)
{
	long i ,
		nelem,
		n2;
	int lgEOL;
	char chLabel[INPUT_LINE_LENGTH];

	if( !lgInitDone )
	{
		fprintf( ioQQQ, " ParseAssertResults called before InitAsserResults\n" );
		puts( "[Stop in ParseAssertResults]" );
		cdEXIT(EXIT_FAILURE);
	}

	/* has space been allocated yet? */
	if( !lgSpaceAllocated )
	{
		/* - no, we must allocate it */
		/* remember that space has been allocated */
		lgSpaceAllocated = TRUE;

		/* create space for the array of labels*/
		if( (chAssertLineLabel = ((char **)MALLOC(NASSERTS*sizeof(char *)))) == NULL )
			BadMalloc();

		/* the 2-character string saying what type of assert */
		if( (chAssertType = ((char **)MALLOC(NASSERTS*sizeof(char *)))) == NULL )
			BadMalloc();

		/* these are a pair of optional parameters */
		if( (Param = ((double **)MALLOC(NASSERTS*sizeof(double * )))) == NULL )
			BadMalloc();

		/* now fill out the 2D arrays */
		for( i=0; i<NASSERTS; ++i )
		{
			if( (chAssertLineLabel[i] = ((char *)MALLOC(NCHAR*sizeof(char )))) == NULL )
				BadMalloc();
			strcpy(chAssertLineLabel[i],"unkn" );

			/* two char plus eol */
			if( (chAssertType[i] = ((char *)MALLOC(3*sizeof(char )))) == NULL )
				BadMalloc();
			strcpy(chAssertType[i],"un" );

			/* these are a pair of optional parameters */
			if( (Param[i] = ((double *)MALLOC(NASSERTS*sizeof(double )))) == NULL )
				BadMalloc();
		}

		/* now make space for the asserted quantities  */
		if( (AssertQuantity = ((double *)MALLOC(NASSERTS*sizeof(double )))) == NULL )
			BadMalloc();

		if( (AssertQuantity2 = ((double *)MALLOC(NASSERTS*sizeof(double )))) == NULL )
			BadMalloc();

		/* now the errors */
		if( (AssertError = ((double *)MALLOC(NASSERTS*sizeof(double )))) == NULL )
			BadMalloc();

		/* now the line wavelengths */
		if( (wavelength = ((float *)MALLOC(NASSERTS*sizeof(float )))) == NULL )
			BadMalloc();

		/* now the flag saying whether should be log */
		if( (lgQuantityLog = ((int *)MALLOC(NASSERTS*sizeof(int )))) == NULL )
			BadMalloc();

		/* the flag for upper, lower limit, or equal */
		if( (chAssertLimit = ((char *)MALLOC(NASSERTS*sizeof(char )))) == NULL )
			BadMalloc();
	}
	/* end space allocation - we are ready to roll */

	/* first say we do not know what job to do */
	strcpy( chAssertType[nAsserts] , "un" );

	/* false means print linear quantity - will be set true if entered
	 * quantity comes in as a log */
	lgQuantityLog[nAsserts] = FALSE;

	/* all asserts have option for quantity to be a limit, or the quantity itself */
	if( lgMatch("<",input.chCARDCAPS ) )
	{
		chAssertLimit[nAsserts] = '<';
	}
	else if( lgMatch(">",input.chCARDCAPS ) )
	{
		chAssertLimit[nAsserts] = '>';
	}
	else
	{
		chAssertLimit[nAsserts] = '=';
	}

	/* which quantity will we check?, first is */

	/* assert mean ionization */
	if( lgMatch("IONI",input.chCARDCAPS ) )
	{

		/* say that this will be mean ionization fraction */

		/* f will indicate average over radius, F over volume -
		 * check whether keyword radius or volume occurs,
		 * default will be radius */
		if( lgMatch("VOLU",input.chCARDCAPS ) )
		{
			strcpy( chAssertType[nAsserts] , "F " );
		}
		else
		{
			/* this is default case, Fraction over radius */
			strcpy( chAssertType[nAsserts] , "f " );
		}

		/* first get element label and make null terminated string*/
		if( (nelem = GetElem(input.chCARDCAPS)) < 0 )
		{
			fprintf( ioQQQ, 
				" I could not identify an element name on this line.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}
		ASSERT( nelem>= 0);
		ASSERT( nAsserts>= 0);
		/* we now have element name, copy 4-char string (elementnames.chElementNameShort[nelem])
		 * into array that will be used to get ionization after calculation */
		strcpy( chAssertLineLabel[nAsserts], elementnames.chElementNameShort[nelem] );

		/* now get ionization stage, which will be saved into wavelength */
		i = 5;
		wavelength[nAsserts] = 
			(float)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* ionization stage must be 1 or greater, but not greater than nelem (c scale)+2 */
		if( wavelength[nAsserts] < 1 || wavelength[nAsserts] > nelem+2 )
		{
			fprintf( ioQQQ, 
				"  The ionization stage is inappropriate for this element.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* now get ionization fraction, log if number is negative or == 0, 
		 * linear if positive but less than or equal to 1.*/
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* now make sure we end up with positive linear ionization fraction that
		 * is greater than 0 but less than or equal to 1. */
		if( AssertQuantity[nAsserts] <= 0. )
		{
			/* log since negative or 0 */
			AssertQuantity[nAsserts] = 
				pow(10.,AssertQuantity[nAsserts] ) ;
			/* entered as a log, so print as a log too */
			lgQuantityLog[nAsserts] = TRUE;
		}
		else if( AssertQuantity[nAsserts] > 1. )
		{
			fprintf( ioQQQ, 
				"  The ionization fraction must be less than one.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* result cannot be zero */
		if( fabs(AssertQuantity[nAsserts]) <= SMALLDOUBLE )
		{
			fprintf( ioQQQ, 
				"  The ionization ionization fraction is too small, or zero.  Check input\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* molecular fraction averaged over model */
	else if( lgMatch("MOLE",input.chCARDCAPS )&&lgMatch("FRAC",input.chCARDCAPS ) )
	{

		/* say that this will be mean molecular fraction */

		/* mf will indicate average over radius, MF over vol -
		 * check whether keyword radius or volume occurs,
		 * default will be radius */
		/*TODO	2	NB this is not used, should do both, and more molecules (H2 only for now) */
		if( lgMatch("VOLU",input.chCARDCAPS ) )
		{
			strcpy( chAssertType[nAsserts] , "MF" );
		}
		else
		{
			/* this is default case, Fraction over radius */
			strcpy( chAssertType[nAsserts] , "mf" );
		}

		i = lgMatch(" H2 ",input.chCARDCAPS );
		if( i )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2  " );
			/* increment to get past the label */
			i += 3;
		}
		else if( lgMatch(" CO ",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "CO  " );
			i = 5;
		}
		else
		{
			fprintf( ioQQQ, 
				" I could not identify CO or H2 on this line.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* not meaningful */
		wavelength[nAsserts] = 0;

		/* i was set above for start of scan */
		/* now get log of molecular fraction */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		if( AssertQuantity[nAsserts] <= 0. )
		{
			/* if negative then entered as log, but we will compare with linear */
			AssertQuantity[nAsserts] = 
				pow(10.,AssertQuantity[nAsserts] ) ;
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
		/* print results as logs */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert line "LINE"  --  key is ine_ since linear option appears on some commands */
	else if( lgMatch("INE ",input.chCARDCAPS ) )
	{
		if(  lgMatch("LUMI",input.chCARDCAPS ) || lgMatch("INTE",input.chCARDCAPS ))
		{
			/* say that this is a line luminosity or intensity*/
			strcpy( chAssertType[nAsserts] , "Ll" );

			/* entered as a log, so print as a log too */
			lgQuantityLog[nAsserts] = TRUE;
		}
		else
		{
			/* say that this is line relative to norm line - this is the default */
			strcpy( chAssertType[nAsserts] , "Lr" );

			/* entered linear quantity, so print as linear too */
			lgQuantityLog[nAsserts] = FALSE;
		}

		/* this will check a line intensity, first get labels within quotes,
		 * will be null terminated */
		GetQuote( chLabel , input.chCARDCAPS , TRUE );

		/* check that there were exactly 4 characters in the label*/
		if( chLabel[4] != '\0' )
		{
			fprintf( ioQQQ, 
				" The label must be exactly 4 char long, between double quotes.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* copy string into array */
		strcpy( chAssertLineLabel[nAsserts], chLabel );

		/* now get line wavelength */
		i = 5;
		wavelength[nAsserts] = 
			(float)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* check for optional micron or cm units, else interpret as Angstroms */
		if( input.chCARDCAPS[i-1] == 'M' )
		{
			/* microns */
			wavelength[nAsserts] *= 1e4;
		}
		else if( input.chCARDCAPS[i-1] == 'C' )
		{
			/* centimeters */
			wavelength[nAsserts] *= 1e8;
		}

		/* now get intensity or luminosity - 
		 * rel intensity is linear and intensity or luminosity are log */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* luminosity was entered as a log */
		if( lgQuantityLog[nAsserts] )
		{
			if( AssertQuantity[nAsserts] > DBL_MAX_10_EXP || 
				AssertQuantity[nAsserts] < -DBL_MAX_10_EXP )
			{
				fprintf( ioQQQ, 
					" The asserted quantity is a log, but is too large or small, value is %e.\n",AssertQuantity[nAsserts] );
				fprintf( ioQQQ, " I would crash if I tried to use it.\n Sorry.\n" );
				puts( "[Stop in ParseAssertResults]" );
				cdEXIT(EXIT_FAILURE);
			}
			AssertQuantity[nAsserts] = 
				pow(10.,AssertQuantity[nAsserts] ) ;
		}
		if( AssertQuantity[nAsserts]<= 0. )
		{
			fprintf( ioQQQ, 
				" The relative intensity must be positive, and was %e.\n",AssertQuantity[nAsserts] );
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* optional error, default available */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert departure coefficients */
	else if( lgMatch("DEPA",input.chCARDCAPS ) )
	{
		i = 5;
		/* get expected average departure coef, almost certainly 1 */
		AssertQuantity[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* this is relative error, max departure from unity of any level or std */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}

		/* H-like key means do one of the hydrogenic ions */
		if( lgMatch("H-LI",input.chCARDCAPS ) )
		{
			/* label is dHII */
			strcpy( chAssertLineLabel[nAsserts] , "dHyd" );
			/* remember this is departure coef for some element */
			strcpy( chAssertType[nAsserts] , "D " );
			/* now get element number for h ion from element name on card */
			if( (wavelength[nAsserts] = (float)GetElem(input.chCARDCAPS)) < 0 )
			{
				fprintf( ioQQQ, 
					" I could not identify an element name on this line.\n");
				fprintf( ioQQQ, " Sorry.\n" );
				puts( "[Stop in ParseAssertResults]" );
				cdEXIT(EXIT_FAILURE);
			}
		}

		/* He-like key means do one of the helike ions */
		else if( lgMatch("HE-L",input.chCARDCAPS ) )
		{
			/* label is dHII */
			strcpy( chAssertLineLabel[nAsserts] , "d He" );
			/* remember this is departure coef for some element */
			strcpy( chAssertType[nAsserts] , "De" );
			/* now get element number for h ion from element name on card */
			if( (wavelength[nAsserts] = (float)GetElem(input.chCARDCAPS)) < 0 )
			{
				fprintf( ioQQQ, 
					" I could not identify an element name on this line.\n");
				fprintf( ioQQQ, " Sorry.\n" );
				puts( "[Stop in ParseAssertResults]" );
				cdEXIT(EXIT_FAILURE);
			}
		}

		/* this is the large FeII ion */
		else if( lgMatch("FEII",input.chCARDCAPS ) || lgMatch("FE II",input.chCARDCAPS ) )
		{
			/* label */
			strcpy( chAssertLineLabel[nAsserts] , "d Fe" );
			/* remember this is departure coef for feii */
			strcpy( chAssertType[nAsserts] , "d " );
			/* the wavelength is meaningless, but put in 2 since FeII */
			wavelength[nAsserts] = 2;
		}

		/* this is H- h minus */
		else if( lgMatch("HMIN",input.chCARDCAPS ) )
		{
			/* label */
			strcpy( chAssertLineLabel[nAsserts] , "d H-" );
			/* remember this is departure coef for H- */
			strcpy( chAssertType[nAsserts] , "d-" );
			/* the wavelength is meaningless */
			wavelength[nAsserts] = -1;
		}
		else
		{
			fprintf( ioQQQ, 
				" There must be a second key: FEII, H-LIke, HMINus, or HE-Like followed by element.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* last check for key "excited" - which means to skip the ground state */
		if( lgMatch("EXCI",input.chCARDCAPS ) )
		{
			/* this is lowest leve - do not do 0 */
			AssertQuantity2[nAsserts] = 1.;
		}
		else
		{
			/* do the ground state */
			AssertQuantity2[nAsserts] = 0.;
		}
	}

	/* assert some results from map */
	else if( lgMatch(" MAP",input.chCARDCAPS ) )
	{

		/* must have heating or cooling, since will check one or the other */
		/* check heating cooling results from map at some temperature */
		if( lgMatch("HEAT",input.chCARDCAPS ) )
		{
			strcpy( chAssertType[nAsserts] , "mh" );
		}
		else if( lgMatch("COOL",input.chCARDCAPS ) )
		{
			strcpy( chAssertType[nAsserts] , "mc" );
		}
		else
		{
			fprintf( ioQQQ, 
				" There must be a second key, HEATing or COOLing.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* i was set above for start of scan */
		/* now get temperature for AssertQuantity2 array*/
		i = 5;
		AssertQuantity2[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		if( AssertQuantity2[nAsserts] <= 10. )
		{
			/* entered as log, but we will compare with linear */
			AssertQuantity2[nAsserts] = 
				pow(10.,AssertQuantity2[nAsserts] ) ;
		}

		/* print the temperature in the wavelength column */
		wavelength[nAsserts] = (float)AssertQuantity2[nAsserts];

		/* heating or cooling, both log, put into error */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* AssertQuantity array will have heating or cooling */
		AssertQuantity[nAsserts] = pow(10., AssertQuantity[nAsserts]);

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}

		/* entered as a log, so print as a log too */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert column density of something */
	else if( lgMatch("COLU",input.chCARDCAPS ) )
	{
		/* this is column density */
		strcpy( chAssertType[nAsserts] , "cd" );

		/* this says to look for molecular column density, also could be ion stage */
		wavelength[nAsserts] = 0;

		/* we want to remember where the match occurred within the string
		 * since do not want to count the 2 as the first number */
		/* NB - can't put this expression in the if since many compilers warn against this */
		if( (i = lgMatch(" H2 ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2  " );
			/* increment to get past the 2 in the label */
			i += 3;
			if( lgMatch( "LEVE" , input.chCARDCAPS ) )
			{
				/* this is option for level-specific column density,
				 * next two numbers must be v then J */
				Param[nAsserts][0] = 
					FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
				Param[nAsserts][1] = 
					FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
				if( lgEOL )
					NoNumb( input.chCARDCAPS );
				/* wavelength will be 10. * vib + rot */
				wavelength[nAsserts] = (float)(100.*Param[nAsserts][0] + Param[nAsserts][1]);
			}
			else
			{
				/* these are flags saying not to do state specific column densities */
				Param[nAsserts][0] = -1.;
				Param[nAsserts][1] = -1.;
			}
		}
		else if( (i = lgMatch("H3+ ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H3+ " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch("H2+ ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2+ " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch(" H- ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H-  " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch("H2G ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2g " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch("H2* ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2* " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch("HEH+",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "HeH+" );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch(" O2 ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "O2  " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch("H2O ",input.chCARDCAPS )) != 0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2O " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch(" C2 ",input.chCARDCAPS ) ) !=0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "C2  " );
			/* increment to get past the 2 in the label */
			i += 3;
		}
		else if( (i = lgMatch(" C3 ",input.chCARDCAPS ) ) !=0 )
		{
			strcpy( chAssertLineLabel[nAsserts], "C3  " );
			/* increment to get past the 3 in the label */
			i += 3;
		}
		else if( lgMatch(" CO ",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "CO  " );
			i = 5;
		}
		else if( lgMatch("SIO ",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "SiO " );
			i = 5;
		}
		else if( lgMatch(" OH ",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "OH  " );
			i = 5;
		}
		else
		{
			fprintf( ioQQQ, 
				" I could not identify H2, H3+, H2+, H2g, H2*, H2H+, CO, O2, SiO, OH, C2 or C3 or on this line.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* i was set above for start of scan */
		/* now get log of column density */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* entered as log, but we will compare with linear */
		AssertQuantity[nAsserts] = 
			pow(10.,AssertQuantity[nAsserts] ) ;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
		/* the keyword log is special for this case, since H2 and CO column densities can
		 * be so very unstable.  look for work log, in which case the error is log not linear.
		 * main column is always a log */
		if( lgMatch( " LOG" , input.chCARDCAPS ) )
		{
			AssertError[nAsserts] = pow(10. , AssertError[nAsserts] );
		}

		/* entered as a log, so print as a log too although asserted quantity is now linear */
		lgQuantityLog[nAsserts] = TRUE;
	}
	/* assert rate H2 forms on grain surfaces */
	else if( lgMatch("GRAI",input.chCARDCAPS ) && lgMatch(" H2 ",input.chCARDCAPS ) )
	{
		/* this flag will mean h2 form on grains */
		strcpy( chAssertType[nAsserts] , "g2" );
		/* a label */
		strcpy( chAssertLineLabel[nAsserts], "R H2" );
		/* now get the first number on the line, which must be the 2 in H2 */
		i = 5;
		nelem = 
			(long int)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( nelem!=2 )
		{
			fprintf( ioQQQ, 
				" I did not find a 2, as in H2, as the first number on this line.\n");
			fprintf( ioQQQ, 
				" The rate should be the second number.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}
		/* now past the 2 in h2, get the real number */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* if negative (almost certainly the case) then the log of the rate coefficient */
		if( AssertQuantity[nAsserts] <=0. )
			AssertQuantity[nAsserts] = pow(10.,AssertQuantity[nAsserts]  );
		/* will not use this */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
			/* want to print as a log since so small */
			lgQuantityLog[nAsserts] = TRUE;
		}
	}

	/* assert mean temperature, assert temperature hydrogen 2 8000 */
	else if( lgMatch("TEMP",input.chCARDCAPS ) )
	{
		/* say that this will be mean temperature, electron or grain */

		/* t will indicate temperature average over radius, T over volume -
		 * check whether keyword radius or volume occurs,
		 * default will be radius */
		if( lgMatch("VOLU",input.chCARDCAPS ) )
		{
			strcpy( chAssertType[nAsserts] , "T ");
		}
		else
		{
			/* this is default case, Fraction over radius */
			strcpy( chAssertType[nAsserts] , "t ");
		}

		/* first look for keyword Grains, since label silicate may be on it,
		 * and this would trigger the element search */
		if( lgMatch("GRAI",input.chCARDCAPS ) )
		{
			/* grains, copy 4-char string "grai"
			 * into array that will be used to get temperature after calculation */
			strcpy( chAssertLineLabel[nAsserts], "GRAI" );
			/* this is to make sure that pointer to grain type is valid, we check
			 * that it is less than this below */
			nelem = NDUST-2;
			/* the first numerical arg on the temper grain command is the grain
			 * type as defined in Hazy, counting from 1.  When it is used to
			 * to get mean temps below we will subtract 1 from this to get onto
			 * the c scale.  but must leave on physical scale here to pass sanity
			 * checks that occur below */
		}

		/* face is temperature at illuminated face of cloud */
		else if( lgMatch("FACE",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "face" );
			/* not used so zero out */
			nelem = 0;
		}

		/* mean H2 temperature */
		else if( lgMatch(" H2 ",input.chCARDCAPS ) )
		{
			strcpy( chAssertLineLabel[nAsserts], "H2  " );
			/* not used so zero out */
			nelem = 0;
		}

		/* look for element label within quotes,
		 * will be null terminated */
		else if( (nelem = GetElem(input.chCARDCAPS)) >= 0 )
		{
			/* we now have element name, copy 4-char string (elementnames.chElementNameShort[nelem])
			 * into array that will be used to get ionization after calculation */
			strcpy( chAssertLineLabel[nAsserts], elementnames.chElementNameShort[nelem] );
		}
		else
		{
			fprintf( ioQQQ, 
				" I could not identify an element name on this line.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* now get ionization stage (or grain type), which will be saved into wavelength */
		i = 5;
		if( strcmp( chAssertLineLabel[nAsserts], "face" )== 0)
		{
			/* this option is temperature at illuminated face so no element */
			wavelength[nAsserts] = 0;
		}
		else if( strcmp( chAssertLineLabel[nAsserts], "H2  " )== 0)
		{
			int j;
			/* this option is temperature of H2 so element is zero */
			wavelength[nAsserts] = 0;
			/* first find the 2 in H2 */
			i = 5;
			j = (int)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
			if( j != 2 )
				TotalInsanity();
			++i;
		}
		else
		{
			wavelength[nAsserts] = 
				(float)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
			if( lgEOL )
			{
				NoNumb(input.chOrgCard);
			}
			/* ionization stage must be 1 or greater, but not greater than nelem (c scale)+2 */
			if( wavelength[nAsserts] < 1 || wavelength[nAsserts] > nelem+2 )
			{
				fprintf( ioQQQ, 
					"  The ionization stage is inappropriate for this element.\n");
				fprintf( ioQQQ, " Sorry.\n" );
				puts( "[Stop in ParseAssertResults]" );
				cdEXIT(EXIT_FAILURE);
			}
		}

		/* now get temperature, log if number is <= 10, else linear */
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* now make sure we end up with positive linear temperature
		 * number is log if <=10 unless linear keyword appears */
		if( AssertQuantity[nAsserts] <= 10. && !lgMatch( "LINE" ,input.chCARDCAPS ) )
		{
			/* log since negative or 0 */
			AssertQuantity[nAsserts] = 
				pow(10.,AssertQuantity[nAsserts] ) ;
			/* entered as a log, so print as a log too */
			lgQuantityLog[nAsserts] = TRUE;
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert log of helium hydrogen ionization correction factor */
	else if( lgMatch("HHEI",input.chCARDCAPS ) )
	{
		/* this flag will mean H-He icf */
		strcpy( chAssertType[nAsserts] , "hh" );
		/* say that this is zone numbering */
		strcpy( chAssertLineLabel[nAsserts], "HHei" );

		/* now get the ionization correction factor, it is always the linear
		 * quantity itself, since can be positive or negative*/
		i = 5;
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* will not use this */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* this large H2 molecule */
	else if( lgMatch(" H2 ",input.chCARDCAPS ) )
	{
		/* ortho to para ratio for last computed zone */
		if( lgMatch("ORTH",input.chCARDCAPS ) )
		{
			/* this flag will mean ortho to para ratio */
			strcpy( chAssertType[nAsserts] , "or" );
			/* say that this is ortho to para density ratio */
			strcpy( chAssertLineLabel[nAsserts], "orth" );
		}
		else
		{
			fprintf( ioQQQ, 
				" I could not identify a second keyword on this line.\n");
			fprintf( ioQQQ, " Sorry.\n" );
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* now get the first number, which better be the 2 in H2 */
		i = 5;
		n2 = (long)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL || n2 != 2 )
		{
			NoNumb(input.chOrgCard);
		}
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		/* will not use this */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert (probably upper limit to) number of zones */
	else if( lgMatch("NZON",input.chCARDCAPS ) )
	{
		/* this flag will mean number of zones */
		strcpy( chAssertType[nAsserts] , "z " );
		/* say that this is zone numbering */
		strcpy( chAssertLineLabel[nAsserts], "zone" );

		/* now get number of zones, which will be saved into wavelength */
		i = 5;
		wavelength[nAsserts] = 
			(float)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* copy it here although we will not use it */
		AssertQuantity[nAsserts] = (double)wavelength[nAsserts];

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert (probably upper limit to) standard deviation of pressure across model */
	else if( lgMatch("PRES",input.chCARDCAPS ) )
	{
		/* this flag indicates ratio of standard deviation to the mean pressure */
		strcpy( chAssertType[nAsserts] , "pr" );
		/* say that this is error in pressure */
		strcpy( chAssertLineLabel[nAsserts], "pres" );

		/* now get the pressure error, which will be saved into wavelength
		 * in nearly all csaes this is limit to error */
		i = 5;
		wavelength[nAsserts] = 0;
		AssertQuantity[nAsserts] = (double)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		else if( AssertQuantity[nAsserts] <= 0.)
		{
			/* number <= 0 is log of error */
			AssertQuantity[nAsserts] = pow(10. , AssertQuantity[nAsserts]);
		}

		/* optional error, default available (cannot do before loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	else if( lgMatch("PRAD",input.chCARDCAPS ) && lgMatch("DMAX",input.chCARDCAPS ) )
	{
		/* assert pradmax - max ratio of rad to gas pressure */
		/* this flag indicates ratio of rad to gas pressure */
		strcpy( chAssertType[nAsserts] , "RM" );
		/* say that this is error in pressure */
		strcpy( chAssertLineLabel[nAsserts], "Prad" );

		/* now get the pressure error, which will be saved into wavelength
		 * in nearly all csaes this is limit to error */
		i = 5;
		wavelength[nAsserts] = 0;
		AssertQuantity[nAsserts] = (double)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		else if( AssertQuantity[nAsserts] <= 0.)
		{
			/* number <= 0 is log of error */
			AssertQuantity[nAsserts] = pow(10. , AssertQuantity[nAsserts]);
		}

		/* optional error, default available (cannot do before loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert secondary ionization rate, csupra */
	else if( lgMatch("CSUP",input.chCARDCAPS ) )
	{
		/* this flag will mean secondary ionization, entered as log */
		strcpy( chAssertType[nAsserts] , "sc" );
		/* say that this is sec ioniz */
		strcpy( chAssertLineLabel[nAsserts], "sion" );

		/* now get rate, saved into assert quantity */
		i = 5;
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* entered as log, make linear */
		AssertQuantity[nAsserts] = pow(10., AssertQuantity[nAsserts] );

		/* no wavelength */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}

		/* we want to print the log of eden, not linear value */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert heating rate, erg/cm3/s, htot */
	else if( lgMatch("HTOT",input.chCARDCAPS ) )
	{
		/* this flag will mean heating, entered as log */
		strcpy( chAssertType[nAsserts] , "ht" );

		/* say that this is heating rate */
		strcpy( chAssertLineLabel[nAsserts], "heat" );

		/* now get rate, saved into assert quantity */
		i = 5;
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* entered as log, make linear */
		AssertQuantity[nAsserts] = pow(10., AssertQuantity[nAsserts] );

		/* no wavelength */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}

		/* we want to print the log of the heating, not linear value */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert number of iterations per zone, a test of convergence */
	else if( lgMatch("ITRZ",input.chCARDCAPS ) )
	{
		/* this flag will mean number of iterations per zone */
		strcpy( chAssertType[nAsserts] , "iz" );
		/* say that this is iterations per zone  */
		strcpy( chAssertLineLabel[nAsserts], "itrz" );

		/* now get quantity */
		i = 5;
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* wavelength is meaningless */
		wavelength[nAsserts] = 0;

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			/* >>chng 04 mar 05, from default 5% to very small number,
			 * since we will usually be doing upper limit */
			AssertError[nAsserts] = 0.001;
		}
	}

	/* assert electron density of the last zone */
	else if( lgMatch("EDEN",input.chCARDCAPS ) )
	{
		/* this flag will mean electron density of the last zone */
		strcpy( chAssertType[nAsserts] , "e " );
		/* say that this is electron density */
		strcpy( chAssertLineLabel[nAsserts], "eden" );

		/* now get electron density, which is a log */
		i = 5;
		AssertQuantity[nAsserts] = 
			pow(10., FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL) );
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
		wavelength[nAsserts] = 0;

		/* we want to print the log of eden, not linear value */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert thickness or depth of model */
	else if( lgMatch("THIC",input.chCARDCAPS ) || lgMatch("DEPT",input.chCARDCAPS ) )
	{
		/* this flag will mean thickness or depth */
		strcpy( chAssertType[nAsserts] , "th" );
		/* say that this is thickness */
		strcpy( chAssertLineLabel[nAsserts], "thic" );

		/* now get thickness, which is a log */
		i = 5;
		AssertQuantity[nAsserts] = 
			pow(10., FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL) );
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
		wavelength[nAsserts] = 0;

		/* we want to print the log of eden, not linear value */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert outer radius of model */
	else if( lgMatch("RADI",input.chCARDCAPS )  )
	{
		/* this flag will mean radius */
		strcpy( chAssertType[nAsserts] , "ra" );
		/* say that this is radius */
		strcpy( chAssertLineLabel[nAsserts], "radi" );

		/* now get radius, which is a log */
		i = 5;
		AssertQuantity[nAsserts] = 
			pow(10., FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL) );
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
		wavelength[nAsserts] = 0;

		/* we want to print the log of radius, not linear value */
		lgQuantityLog[nAsserts] = TRUE;
	}

	/* assert (probably upper limit to) number of iterations */
	else if( lgMatch("NITE",input.chCARDCAPS ) )
	{
		/* this flag will mean number of iterations */
		strcpy( chAssertType[nAsserts] , "Z " );
		/* say that this is iteration numbering */
		strcpy( chAssertLineLabel[nAsserts], "iter" );

		/* now get number of iterations, which will be saved into wavelength */
		i = 5;
		wavelength[nAsserts] = 
			(float)FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}
		/* copy it here although we will not use it */
		AssertQuantity[nAsserts] = (double)wavelength[nAsserts];

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}

	/* assert terminal velocity, at end of calculation
	 * input in km/s and saved that way, even though code uses cm/s */
	else if( lgMatch("VELO",input.chCARDCAPS ) )
	{
		/* this flag will mean number of iterations */
		strcpy( chAssertType[nAsserts] , "Ve" );
		/* say that this is iteration numbering */
		strcpy( chAssertLineLabel[nAsserts], "vel " );
		wavelength[nAsserts] = 0;

		/* now get velocity */
		i = 5;
		AssertQuantity[nAsserts] = 
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			NoNumb(input.chOrgCard);
		}

		/* optional error, default available (cannot do befor loop since we
		 * do not know how many numbers are on line */
		AssertError[nAsserts] =
			FFmtRead(input.chCARDCAPS ,&i, INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
		{
			/* default error was set in define above */
			AssertError[nAsserts] = DEF_ERROR;
		}
	}
	else
	{
		/* did not recognize a command */
		fprintf( ioQQQ, 
			"  Unrecognized command.  The line image was==%s==\n", 
		  input.chOrgCard );
		fprintf( ioQQQ, 
			"  The options I know about are: ionization, line, departure coef, map, column, "
			"temperature, nzone, csupre, htot, itrz, eden, thickness, niter, \n");
		fprintf( ioQQQ, " Sorry.\n" );
		puts( "[Stop in ParseAssertResults]" );
		cdEXIT(EXIT_FAILURE);
	}

	/* increment number of asserts and confirm that limit not exceeded */
	++nAsserts;
	if( nAsserts >= NASSERTS )
	{
		fprintf(ioQQQ,
			" ParseAssertResults: too many asserts, limit is NASSERT=%d\n",
			NASSERTS );
		puts( "[Stop in ParseAssertResults]" );
		cdEXIT(EXIT_FAILURE);
	}
}

/*============================================================================*/
/*lgCheckAsserts, checks asserts, last thing cloudy calls, returns TRUE if all are ok, FALSE if problems */
int lgCheckAsserts(
	/* this is the file we will write this to, usually standard output, 
	 * but can be punch */
	FILE * ioASSERT )
{
	double PredQuan[NASSERTS] , RelError[NASSERTS];
	/* this will be true if the quantity was found, and false if not.  Used to prevent
	 * big botch flag when quantity not found (as in removed old he atom) */
	int lgFound[NASSERTS];
	double relint , absint ;
	int lg1OK[NASSERTS];
	long i,j;

	/* this is a global variable in assertresults.h, and can be checked by
	 * other routines to see if asserts are ok - (most runs will not use asserts) */
	lgAssertsOK = TRUE;

	/* will be used if there were big botched asserts */
	lgBigBotch = FALSE;

	/* this will usually just return, but with table lines will check existance of some lines */
	if( lines_table() )
	{
		lgBigBotch = TRUE;
		lgAssertsOK = FALSE;
	}

	/* first check all asserts, there probably are none */
	for(i=0; i<nAsserts; ++i )
	{
		lg1OK[i] = TRUE;
		PredQuan[i] = 0.;
		RelError[i] = 0.;

		/* this flag is set false if we don't find the requested quantity */
		lgFound[i] = TRUE;

		/* which type of assert? */
		/* is it intensity? */
		if( strcmp( chAssertType[i] , "Lr")==0 )
		{
			/* this is an intensity, get the line, returns false if could not find it */
			if( cdLine( chAssertLineLabel[i] , wavelength[i] , &relint,&absint )<=0 )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find a line with label %s ",
					chAssertLineLabel[i] );
				prt_wl( ioASSERT, wavelength[i] );
				fprintf( ioASSERT, "\n" );

				fprintf( ioASSERT, 
					" assert error: The \"punch line labels\" command is a good way to get a list of line labels.\n\n");
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 100000.;
				PredQuan[i] = 0;
				lg1OK[i] = FALSE;
				lgAssertsOK = FALSE;
				lgFound[i] = FALSE;
				continue;
			}
			PredQuan[i] = relint;
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;

		}

		/*this is line luminosity */
		else if( strcmp( chAssertType[i] , "Ll")==0 )
		{
			/* this is a luminosity, get the line, returns false if could not find it */
			if( cdLine( chAssertLineLabel[i] , wavelength[i] , &relint,&absint )<=0 )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find a line with label %s ",
					chAssertLineLabel[i] );
				prt_wl( ioASSERT, wavelength[i] );
				fprintf( ioASSERT, "\n" );

				fprintf( ioASSERT, 
					" assert error: The \"punch line labels\" command is a good way to get a list of line labels.\n\n");
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 10000000.;
				PredQuan[i] = 0;
				lg1OK[i] = FALSE;
				lgFound[i] = FALSE;
				lgAssertsOK = FALSE;
				continue;
			}
			/* absint was returned as the log */
			PredQuan[i] = pow(10.,absint);
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;

		}
		else if( strcmp( chAssertType[i] , "hh" ) == 0)
		{
			double hfrac , hefrac;
			/* get H ionization fraction, returns false if could not find it */
			if( cdIonFrac(
				/* four char string, null terminzed, giving the element name */
				"hydr", 
				/* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number */
				1, 
				/* will be fractional ionization */
				&hfrac, 
				/* how to weight the average, must be "VOLUME" or "RADIUS" */
				"VOLUME" ,
				/* do not want extra factor of density */
				FALSE)  )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find h ionizaition fraction \n");
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				lgFound[i] = FALSE;
				continue;
			}
			if( cdIonFrac(
				/* four char string, null terminzed, giving the element name */
				"heli", 
				/* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number */
				1, 
				/* will be fractional ionization */
				&hefrac, 
				/* how to weight the average, must be "VOLUME" or "RADIUS" */
				"VOLUME" ,
				/* do not want extra factor of density */
				FALSE)  )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find h ionizaition fraction \n");
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				lgFound[i] = FALSE;
				continue;
			}
			/* the helium hydrogen ionization correction factor */
			PredQuan[i] = hefrac-hfrac;
			/* two icf's in difference, no need to div by mean since already on scale with unity */
			RelError[i] = fabs(AssertQuantity[i] - (hefrac-hfrac) );
		}

		else if( strcmp( chAssertType[i] , "z " ) == 0)
		{
			/* this is (probably an upper limit) to the number of zones */
			PredQuan[i] = (double)nzone;
			/* two integers in difference */
			RelError[i] = (double)(wavelength[i] - nzone);
		}

		else if( strcmp( chAssertType[i] , "or" ) == 0)
		{
			/* ortho to para ratio for large H2 molecule in last zone */
			PredQuan[i] = h2.ortho_density / SDIV( h2.para_density );

			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "g2" ) == 0)
		{
			/* check Jura rate, rate per vol that H2 forms on grain surfaces */
			PredQuan[i] = gv.rate_h2_form_grains_used_total;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "RM" ) == 0)
		{
			/* check Jura rate, rate per vol that H2 forms on grain surfaces */
			PredQuan[i] = pressure.RadBetaMax;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "pr" ) == 0)
		{
			/* standard deviation of the pressure */
			double sumx=0., sumx2=0., average;
			long int n;
			/* do sums to form standard deviation */
			for( n=0; n<nzone; n++ )
			{
				sumx += struc.pressure[n];
				sumx2 += POW2(struc.pressure[n]);
			}
			if( nzone>1 )
			{
				/* this is average */
				average = sumx/nzone;
				/* this is abs std */
				sumx = sqrt( (sumx2-POW2(sumx)/nzone)/(nzone-1) );
				/* save the relative std */
				PredQuan[i] = sumx / average;
			}
			else
			{
				PredQuan[i] = 0.;
			}

			/* two integers in difference */
			RelError[i] = 0.;
		}

		else if( strcmp( chAssertType[i] , "iz") == 0 )
		{
			/* this is number of iterations per zone, a test of convergence properties */
			PredQuan[i] = (double)(conv.nTotalIoniz)/(double)(nzone);
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "e ") == 0 )
		{
			/* this is electron density of the last zone */
			PredQuan[i] = dense.eden;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "th") == 0 )
		{
			/* this is thickness */
			PredQuan[i] = radius.depth;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "ra") == 0 )
		{
			/* this is thickness */
			PredQuan[i] = radius.Radius;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "Ve") == 0 )
		{
			/* this is final velocity of wind in km/s (code uses cm/s) */
			PredQuan[i] = wind.windv/1e5;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "sc") == 0 )
		{
			/* this is secondary ionization rate */
			PredQuan[i] = secondaries.csupra[ipHYDROGEN][0];
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "ht") == 0 )
		{
			/* this is heating rate */
			PredQuan[i] = thermal.htot;
			/* this is relative error */
			RelError[i] = 1. - PredQuan[i] / AssertQuantity[i];
		}

		else if( strcmp( chAssertType[i] , "Z ") == 0 )
		{
			/* this is (probably an upper limit) to the number of iterations */
			PredQuan[i] = (double)iteration;
			/* two integers in difference */
			RelError[i] = (double)(wavelength[i] - iteration);
			/* uncertainty in difference is zero */
			AssertError[i] = 0.;
		}

		else if( strcmp( chAssertType[i] , "D ") == 0 )
		{
			long ipZ , n;
			/* this is departure coef for H-like ion given by wavelength */
			/* stored number was element number on C scale */
			ipZ = (long)wavelength[i];
			if( !dense.lgElmtOn[ipZ] )
			{
				fprintf(ioQQQ," asserted element %ld is not turned on!\n",ipZ);
				PredQuan[i] = 0;
				RelError[i] = 0.;
			}
			else
			{
				RelError[i] = 0.;
				PredQuan[i] = 0.;
				for( n=(long)AssertQuantity2[i]; n<iso.numPrintLevels[ipH_LIKE][ipZ]; ++n )
				{
					PredQuan[i] += iso.DepartCoef[ipH_LIKE][ipZ][n];
					/* relerror is the largest deviation from unity for any single level*/
					RelError[i] = MAX2( RelError[i] , iso.DepartCoef[ipH_LIKE][ipZ][n] -1.);
					RelError[i] = MAX2( RelError[i] , 1. - iso.DepartCoef[ipH_LIKE][ipZ][n] );
				}
				PredQuan[i] /= (double)(iso.numPrintLevels[ipH_LIKE][ipZ]);
				RelError[i] /= (double)(iso.numPrintLevels[ipH_LIKE][ipZ]);
			}
		}

		/* departure coefficients for something on he-like seq */
		else if( strcmp( chAssertType[i] , "De") == 0 )
		{
			long ipZ , n;
			/* this is departure coef for He-like ion given by wavelength */
			/* stored number was element number on C scale */
			ipZ = (long)wavelength[i];
			if( !dense.lgElmtOn[ipZ] )
			{
				fprintf(ioQQQ," asserted element %ld is not turned on!\n",ipZ);
				PredQuan[i] = 0.;
				RelError[i] = 0.;
			}
			else
			{
				RelError[i] = 0.;
				PredQuan[i] = 0.;
				for( n=(long)AssertQuantity2[i]; n<iso.numPrintLevels[ipHE_LIKE][ipZ]; ++n )
				{
					double relerror;
					relerror = 0.;
					PredQuan[i] += iso.DepartCoef[ipHE_LIKE][ipZ][n];
					/* relerror is the largest deviation from unity for any single level*/
					relerror = iso.DepartCoef[ipHE_LIKE][ipZ][n] -1.;
					relerror = MAX2( relerror , 1. - iso.DepartCoef[ipHE_LIKE][ipZ][n] );
					RelError[i] = MAX2( RelError[i] , relerror / AssertQuantity[i] );
				}
				PredQuan[i] /= (double)(iso.numPrintLevels[ipHE_LIKE][ipZ]);
				/* >>chng 03 mar 13, had not div by num levels */
				RelError[i] /= (double)(iso.numPrintLevels[ipHE_LIKE][ipZ]);
			}
		}

		/* this is FeII departure coefficient */
		else if( strcmp( chAssertType[i] , "d ") == 0 )
		{
			double BigError , StdDev ;
			/* this is depature coef for FeII */
			AssertFeIIDep( &PredQuan[i] , &BigError , &StdDev );
			/* there are many missing A's in the FeII ion (no atomic data) so only the
			 * average is relevant now,  RefError returned above is single largest
			 * excursion from unity */
			RelError[i] = StdDev;
		}

		/* this is H- departure coefficient */
		else if( strcmp( chAssertType[i] , "d-") == 0 )
		{
			PredQuan[i] = hmi.hmidep;
			RelError[i] = fabs( hmi.hmidep - 1.);
		}

		/* this would be ionization fraction */
		else if( (strcmp( chAssertType[i] , "f ") == 0) || 
			(strcmp( chAssertType[i] , "F ") == 0) )
		{
			char chWeight[7];
			if( strcmp( chAssertType[i] , "F ") == 0 )
			{
				strcpy( chWeight , "VOLUME" );
			}
			else
			{
				/* this is default case, Fraction over radius */
				strcpy( chWeight , "RADIUS" );
			}
			/* get ionization fraction, returns false if could not find it */
			if( cdIonFrac(
				/* four char string, null terminzed, giving the element name */
				chAssertLineLabel[i], 
				/* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number */
				(long)wavelength[i], 
				/* will be fractional ionization */
				&relint, 
				/* how to weight the average, must be "VOLUME" or "RADIUS" */
				chWeight ,
				/* do not want extra factor of density */
				FALSE)  )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find a line with label %s %f \n",
					chAssertLineLabel[i] , wavelength[i] );
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				lgFound[i] = FALSE;
				continue;
			}
			/* this is ionization fraction */
			PredQuan[i] = relint;
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;
		}

		/* this would be column density of several molecules */
		else if( strcmp( chAssertType[i] , "cd") == 0) 
		{
			/* for H2 column density - total or for a state? */
			if( (strcmp( chAssertLineLabel[i], "H2  " ) == 0) && (Param[i][0] >= 0.) )
			{
				/* this branch get state specific column density */
				/* get total H2 column density */
				if( (relint = cdH2_colden( (long)Param[i][0] , (long)Param[i][1] ) ) < 0. )
				{
					fprintf(ioQQQ," PROBLEM lgCheckAsserts did not find v=%li, J=%li for H2 column density.\n",
						(long)Param[i][0] , (long)Param[i][1] );
					lg1OK[i] = FALSE;
					RelError[i] = 0;
					PredQuan[i] = 0;
					lgFound[i] = FALSE;
					continue;
				}
			}
			else
			{
				/* get ionization fraction, returns 0 if all ok */
				if( cdColm(
					/* four char string, null terminzed, giving the element name */
					chAssertLineLabel[i], 
					/* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number,
					* zero for molecule*/
					(long)wavelength[i], 
					/* will be fractional ionization */
					&relint) )
				{
					fprintf( ioASSERT, 
						" assert error: lgCheckAsserts could not find a molecule with label %s %f \n",
						chAssertLineLabel[i] , wavelength[i] );
					/* go to next line */
					lg1OK[i] = FALSE;
					RelError[i] = 0;
					PredQuan[i] = 0;
					lgFound[i] = FALSE;
					continue;
				}
			}
			/* this is ionization fraction */
			PredQuan[i] = relint;
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;
		}

		/* this would be molecular fraction of CO or H2 */
		else if( (strcmp( chAssertType[i] , "MF") == 0)  || (strcmp( chAssertType[i] , "mf") == 0) )
		{
			/* get molecular fraction, returns 0 if all ok */
			relint = 0.;
			if( strcmp( chAssertLineLabel[i], "H2  ") ==0)
			{
				/* get total H2 column density */
				if( cdColm("H2  " , 0, 
					/* will be fractional ionization */
					&relint) )
					TotalInsanity();

				relint = relint / colden.colden[ipCOL_HTOT];
			}
			else
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts could not find a molecule with label %s %f \n",
					chAssertLineLabel[i] , wavelength[i] );
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				continue;
			}
			/* this is ionization fraction */
			PredQuan[i] = relint;
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;
		}

		/* check heating/cooling at some temperature in a thermal map */
		else if( strcmp( chAssertType[i] , "mh") == 0 || strcmp( chAssertType[i] , "mc") == 0) 
		{
			/* check heating or cooling (stored in error array) at temperature in assert results */
			/* check that map was done, and arrays have nmap elements */
			if( map.nMapAlloc == 0 )
			{
				/* this happens if map not done and space for h/c not allocated */
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts cannot check map since map not done.\n");
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				continue;
			}
			/* now check that requested temperature is within the range of the map we computed */
			if( AssertQuantity2[i]< map.temap[0] || AssertQuantity2[i]> map.temap[map.nmap-1] )
			{
				fprintf( ioASSERT, 
					" assert error: lgCheckAsserts cannot check map since temperature not within range.\n");
				/* go to next line */
				lg1OK[i] = FALSE;
				RelError[i] = 0;
				PredQuan[i] = 0;
				continue;
			}

			/* we should have valid data - find closest tempeature >- requested temperature */
			j = 0;
			while( AssertQuantity2[i]>map.temap[j]*1.001 && j < map.nmap )
			{
				++j; 
			}

			/* j points to correct cell in heating cooling array */
			/* we will not interpolate, just use this value, and clobber te to prove it*/
			if( strcmp( chAssertType[i] , "mh") == 0 )
			{
				/* heating */
				PredQuan[i] = map.hmap[j];
				strcpy(chAssertLineLabel[i],"MapH" );
			}
			else if( strcmp( chAssertType[i] , "mc") == 0)
			{
				/* cooling */
				PredQuan[i] = map.cmap[j];
				strcpy(chAssertLineLabel[i],"MapC" );
			}
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;
		}

		/* this will be an average temperatre */
		else if( (strcmp( chAssertType[i] , "t ") == 0) || 
			(strcmp( chAssertType[i] , "T ") == 0) )
		{
			char chWeight[7];
			if( strcmp( chAssertType[i] , "T ") == 0 )
			{
				strcpy( chWeight , "VOLUME" );
			}
			else
			{
				/* this is default case, Fraction over radius */
				strcpy( chWeight , "RADIUS" );
			}

			/* options are average Te for ion, temp at ill face, or temp for grain */
			if( strcmp( chAssertLineLabel[i], "GRAI" ) == 0 )
			{
				long nd;
				/* the minus one is because the grain types are counted from one,
				 * but stuffed into the c array, that counts from zero */
				nd = (long)(wavelength[i]-1);
				if( nd < 0 || nd >= gv.nBin ) {
					fprintf( ioQQQ, "Illegal grain number found: %f\n" , wavelength[i] );
					fprintf( ioQQQ, "Use 1 for first grain that is turned on, " );
					fprintf( ioQQQ, "2 for second, etc....\n" );
					fprintf( ioQQQ, "Old style grain numbers are not valid anymore !!\n" );
					puts( "[Stop in ParseAssertResults]" );
					cdEXIT(EXIT_FAILURE);
				}
				ASSERT( nd>= 0 );
				relint = gv.bin[nd]->avdust/radius.depth_x_fillfac;
			}
			else if( strcmp( chAssertLineLabel[i], "face" ) == 0 )
			{
				/* this is the temperature at the illuminated face */
				relint = struc.testr[0];
			}
			else
			{
				/* get temperature, returns false if could not find it */
				if( cdTemp(
					/* four char string, null terminzed, giving the element name */
					chAssertLineLabel[i], 
					/* IonStage is ionization stage, 1 for atom, up to N+1 where N is atomic number */
					(long)wavelength[i], 
					/* will be mean temperatue */
					&relint, 
					/* how to weight the average, must be "VOLUME" or "RADIUS" */
					chWeight )  )
				{
					fprintf( ioASSERT, 
						" assert error: lgCheckAsserts could not find an ion with label %s ion %li \n",
						chAssertLineLabel[i] , (long)wavelength[i] );
					/* go to next line */
					lg1OK[i] = FALSE;
					RelError[i] = 0;
					PredQuan[i] = 0;
					lgFound[i] = FALSE;
					continue;
				}
			}
			/* this is the temperature */
			PredQuan[i] = relint;
			RelError[i] = 1. -  PredQuan[i]/AssertQuantity[i]  ;
		}

		else
		{
			fprintf( ioASSERT, 
				" assert error: lgCheckAsserts received an insane chAssertType=%s, impossible\n",
				chAssertType[i] );
			ShowMe();
			puts( "[Stop in ParseAssertResults]" );
			cdEXIT(EXIT_FAILURE);
		}

		if( chAssertLimit[i] == '=' )
		{
			/* predicted quantity should be within error of expected */
			if( fabs(RelError[i]) > AssertError[i] )
			{
				lg1OK[i] = FALSE;
				lgAssertsOK = FALSE;
			}
		}
		else if( chAssertLimit[i] == '<' )
		{
			/* expected is an upper limit, so PredQuan/AssertQuantity should
			 * be less than one, and so RelError should be postive 
			 * >>chng 04 feb 14,from <= to < - limit is really < not <=,
			 * in case of iterations or zones, iter < iterations would not
			 * trigger false when iter == iterations */
			if( RelError[i] <= 0.-AssertError[i])
			{
				lg1OK[i] = FALSE;
				lgAssertsOK = FALSE;
			}
		}
		else if( chAssertLimit[i] == '>' )
		{
			/* expected is a lower limit, so PredQuan/AssertQuantity should
			 * be greater than one, and so RelError should be negative */
			if( RelError[i] >= 0.+AssertError[i])
			{
				lg1OK[i] = FALSE;
				lgAssertsOK = FALSE;
			}
		}
	}

	/* only print summary if we are talking */
	if( called.lgTalk && nAsserts>0 )
	{ 
		char chVer[10];
		time_t now;
		cdVersion(chVer ) ;
		/* write start of title and version number of code */
		fprintf( ioASSERT, "=============Results of asserts: C%s ",chVer );

		/* usually print date and time info - do not if "no times" command entered, 
		 * which set this flag false */
		if( prt.lgPrintTime ) 
		{
			/* now add date of this run */
			now = time(NULL);
			/* now print this time at the end of the string.  the system put cr at the end of the string */
			fprintf(ioASSERT,"%s", ctime(&now) );
		}
		else 
		{
			fprintf(ioASSERT,"\n" );
		}

		if( lgAssertsOK )
		{
			fprintf( ioASSERT, " No errors were found.  Summary follows.\n");
		}
		else
		{
			fprintf( ioASSERT, " Errors were found.  Summary follows.\n");
		}

		fprintf( ioASSERT, 
			"                  Label line    computed    asserted Rel Err Set err\n");
		/* now print a summary */
		/*lint -e771 vars conceivably not initialized */
		for( i=0; i<nAsserts; ++i )
		{
			double prtPredQuan, prtAssertQuantity;
			/* this is option to print log of quantity rather than linear.  default is
			 * linear, and log only for a few such as ionization to see small numbers */
			if( lgQuantityLog[i] )
			{
				prtPredQuan = log10( MAX2( SMALLDOUBLE , PredQuan[i] ) );
				prtAssertQuantity = log10( MAX2( SMALLDOUBLE , AssertQuantity[i] ) );
			}
			else
			{
				prtPredQuan = PredQuan[i] ;
				prtAssertQuantity = AssertQuantity[i];
			}
			/* start of line, flag problems */
			if( lg1OK[i] )
			{
				/* the ChkAssert is a unique label so that we can grep on all outpu
				 * and see what happened, without picking up input stream */
				double relative = fabs(RelError[i] / SDIV( AssertError[i])) ;

				if( relative < 0.25 || chAssertLimit[i] != '=' )
				{
					fprintf( ioASSERT, " ChkAssert        ");
				}
				else if( relative < 0.50 )
				{
					fprintf( ioASSERT, " ChkAssert -      ");
				}
				else if( relative < 0.75 )
				{
					fprintf( ioASSERT, " ChkAssert --     ");
				}
				else if( relative < 0.90 )
				{
					fprintf( ioASSERT, " ChkAssert ---    ");
				}
				else  if( relative < 0.95 )
				{
					fprintf( ioASSERT, " ChkAssert ----   ");
				}
				else  if( relative < 0.98 )
				{
					fprintf( ioASSERT, " ChkAssert -----  ");
				}
				else 
				{
					fprintf( ioASSERT, " ChkAssert ------ ");
				}

			}
			else
			{
				fprintf( ioASSERT, " ChkAssert botch>>");
			}
			if( strcmp( chAssertType[i] , "Ll")==0  || ( strcmp( chAssertType[i] , "Lr")==0 ) )
			{
				/* special formatting for the emission lines */
				fprintf( ioASSERT , "%4s ",
					chAssertLineLabel[i] );

				prt_wl( ioASSERT , wavelength[i] );

				fprintf( ioASSERT , " %10.4f %c %9.3f %7.3f %7.3f ",
					prtPredQuan ,  
					chAssertLimit[i]  , 
					prtAssertQuantity , 
					RelError[i] , 
					AssertError[i]);
			}
			else
			{
				fprintf( ioASSERT , "%4s %6i %10.4f %c %9.3f %7.3f %7.3f ",
					chAssertLineLabel[i] , 
					(int)wavelength[i] ,
					prtPredQuan ,  
					chAssertLimit[i]  , 
					prtAssertQuantity , 
					RelError[i] , 
					AssertError[i]);
			}
			/* if botched and the botch is > 3 sigma, say BIG BOTCH,
			 * the lg1OK is needed since some tests (number of zones, etc)
			 * are limits, not the quantity, and if limit is large the
			 * miss will be big too */

			/* >>chng 02 nov 27, added lgFound so don't get big botch when line simply missing */
			if( !lg1OK[i] && (fabs(RelError[i]) > 3.*AssertError[i]) && lgFound[i] )
			{
				fprintf( ioASSERT , " <<BIG BOTCH!!\n");
				lgBigBotch = TRUE;
			}
			else
			{
				fprintf( ioASSERT , "\n");
			}
		}
		/*lint +e771 vars conceivably not initialized */
		fprintf( ioASSERT , " \n");

		/* NB - in following, perl scripts detect these strings - be careful if they
		 * are changed - the scipts may no longer detect major errors */
		if( !lgAssertsOK && lgBigBotch )
		{
			/* there were big botches */
			fprintf( ioASSERT, " BIG BOTCHED ASSERTS!!!   Big Botched Asserts!!! \n");
		}
		else if( !lgAssertsOK )
		{
			fprintf( ioASSERT, " BOTCHED ASSERTS!!!   Botched Asserts!!! \n");
		}
		/* if botched asserts then explain how we were compiled */
		if( !lgAssertsOK )
		{
			fprintf( ioQQQ, " %s\n\n", version.chInfo );
		}
	}

#	ifdef DEBUG_FUN
	fputs( " <->PrtFinal()\n", debug_fp );
#	endif

	/* return the value */
	return(lgAssertsOK);
}

