/* 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 */
/*ParseAtomHeLike parse parameters off the helium command */
#include "cddefines.h" 
#include "iso.h" 
#include "taulines.h" 
#include "phycon.h" 
#include "helike.h" 
#include "helike_recom.h" 
#include "parse.h" 

/*ParseAtomHeLike parse parameters off the helium command */
void ParseAtomHeLike(char *chCard )
{
	long int i, 
		nHe,
		nelem;
	int lgEOL;

#	ifdef DEBUG_FUN
	fputs( "<+>ParseAtomHeLike()\n", debug_fp );
#	endif

	/* collisions - don't pick up the levels collapsed command */
	if( lgMatch("COLL",chCard) && !lgMatch("LEVE" , chCard ) )
	{
		if( lgMatch("EXCI",chCard) )
		{
			/* turn off collisional excitation */
			iso.lgColl_excite[ipHE_LIKE] = FALSE;
			phycon.lgPhysOK = FALSE;
		}
		else if( lgMatch("IONI",chCard) )
		{
			/* turn off collisional ionization */
			iso.lgColl_ionize[ipHE_LIKE] = FALSE;
			phycon.lgPhysOK = FALSE;
		}
		else if( lgMatch("L-MI",chCard) )
		{
			if( lgMatch("THER",chCard) )
			{
				/* use l-mix from 
				 *>>refer	l-mix	all Vrinceanu, D. & Flannery, M. R. 2001, PhysRevA 63, 032701 */
				if( lgMatch("NO T",chCard) )			
				{
					/* This is the "NO Thermal average" command.  It
					 * causes collisions strengths to be evaluated at kT rather than
					 * integrated over a Maxwellian peaked at kT. */
					helike.lgCS_therm_ave = FALSE;
				}
				else
				{
					helike.lgCS_therm_ave = TRUE;
				}
			}
			else if( lgMatch("PENG",chCard) )
			{
				helike.lgCS_Vrinceanu = FALSE;
			}
			else if( lgMatch(" OFF" , chCard ) )
			{
				/* >>chng 02 feb 07, change from 2s2p to l-mixing */
				/* this is the atom he-like collision l-mixing command */
				/* turn off same-n collisions */
				iso.lgColl_l_mixing[ipHE_LIKE] = FALSE;
				phycon.lgPhysOK = FALSE;
				helike.lgCS_Vrinceanu = FALSE;
				helike.lgCS_therm_ave = TRUE;
			}
			else
			{
				fprintf( ioQQQ, " needs parameter\n" );
				puts( "[Stop in ParseSet]" );
				cdEXIT(EXIT_FAILURE);
			}
		}
		else if( lgMatch(" OFF" , chCard ) )
		{
			/* turn everything off, since no keyword given */
			iso.lgColl_excite[ipHE_LIKE] = FALSE;
			iso.lgColl_ionize[ipHE_LIKE] = FALSE;
			iso.lgColl_l_mixing[ipHE_LIKE] = FALSE;
			phycon.lgPhysOK = FALSE;
		}
		else
		{
			fprintf( ioQQQ, " needs parameter\n" );
			puts( "[Stop in ParseSet]" );
			cdEXIT(EXIT_FAILURE);
		}
	}
	
	else if( lgMatch("DIEL",chCard) )
	{
		/* This sets which set of data to use for dielectronic recombination.	*/
		if( lgMatch(" OFF",chCard) )
		{
			helike.lgDielRecom = 0;
		}
		else if( lgMatch(" GU ",chCard) )
		{
			helike.lgDielRecom = 1;
		}
		else
			helike.lgDielRecom = 2;
	}

	else if( lgMatch("ERRO",chCard) && lgMatch("GENE" , chCard ) )
	{

		/* Rates will be modified by a randomly generated error that falls within
		 * the range specifically set for each rate (or set of rates).	*/
		helike.lgRandErrGen = TRUE;
		i = 5;
		helike.modelRank = (int)FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);

		helike.modelRank = MAX2( 0, helike.modelRank );
		if( lgEOL )
			/* Changed to avoid lint complaint */
			/* helike.modelRank = (unsigned)time(NULL); */
			helike.modelRank = abs((int)time(NULL));

		/* this allows a seed that is dependent upon the processor rank
		 * in a parallel run. */
		srand( (unsigned)helike.modelRank );
	}

	else if( lgMatch(" FSM",chCard) )
	{
		/* turn on fine structure mixing of spontaneous decays.  
		 * >>refer	Helike	FSM	Bauman, R., MacAdams, K., and Ferland, G. (2003).	*/
		if( lgMatch(" OFF",chCard) )
			helike.lgFSM = FALSE;
		else
			helike.lgFSM = TRUE;
	}

	else if( lgMatch("GBAR",chCard) )
	{
		/* the HEGBAR command - to change cs of higher levels */
		/* first turn all off, one will be turned back on */
		helike.lgCS_Vriens = FALSE;
		helike.lgCS_None = FALSE;
		helike.lgCS_new = FALSE;

		/* now turn one on */
		if( lgMatch("VRIE",chCard) )
		{
			/* option to change how collisions for unknown levels affect things */
			helike.lgCS_Vriens = TRUE;
		}
		else if( lgMatch(" NEW",chCard) )
		{
			/* option to change how collisions for unknown levels affect things */
			i = 5;
			helike.lgCS_new = (int)FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);

			/* there are two options, 1 and 2, for which fit - default (no number)
			 * will be 1, the broken power law fit */
			if( lgEOL )
				helike.lgCS_new = 1;

			ASSERT( helike.lgCS_new );
		}
		else if( lgMatch(" OFF",chCard) )
		{
			/* option to change how collisions for unknown levels affect things */
			helike.lgCS_None = TRUE;
		}
		else
		{
			fprintf( ioQQQ, " needs parameter\n" );
			puts( "[Stop in ParseSet]" );
			cdEXIT(EXIT_FAILURE);
		}
	}

	else if( lgMatch("BENJ",chCard) )
	{
		/* use set of physics to replicate Benjamin et al HeI papers */
		/* affects are:
				use his recombination coefficients, rather than Milne relation results
				do not use fake 0.1 collisions for transitions with no data
				no collisional excitation to n=5 
				forces max n to 5	*/

		helike.lgSetBenjamin = TRUE;
	}

	else if( lgMatch("LYMA",chCard) )
	{
		/* option to set number of "extra" lyman lines, used for optical depths only */
		i = 5;
		iso.nLyman[ipHE_LIKE] = (long int)FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);
		if( lgEOL )
			NoNumb(chCard);
	}

	/* >>chng 05 dec 21, add the ATOM HE-LIKE NO RECOMB INTERPOLATE command,
	 * syas to not interpolate on look-up tables but compute recom on the fly instead */
	else if( lgMatch("RECO",chCard) &&
		lgMatch(" NO ",chCard) && lgMatch("INTE",chCard) )
	{
		/* flag set by atom he-like no recomb interp command, 
		* says to generate recombination coefficients
		* on the fly */
		helike.lgNoRecombInterp = TRUE;
	}

	else if( lgMatch("REDI",chCard) )
	{
		int ipRedis=0;
		/* there are three functions, PRD_, CRD_, and CRDW,
		 * representing partial redistribution, 
		 * complete redistribution (doppler core only, no wings)
		 * and complete with wings */
		/* partial redistribution */
		if( lgMatch(" PRD",chCard) )
		{
			ipRedis = ipPRD;
		}
		/* complete redistribution no wings */
		else if( lgMatch(" CRD",chCard) )
		{
			ipRedis = ipCRD;
		}
		/* complete redistribution with wings */
		else if( lgMatch("CRDW",chCard) )
		{
			ipRedis = ipCRDW;
		}

		/* if not SHOW option (handled below) then we have a problem */
		else if( !lgMatch("SHOW",chCard) )
		{
			fprintf(ioQQQ," There should have been a second keyword on this command.\n");
			fprintf(ioQQQ," Options are _PRD, _CRD, CRDW (_ is space).  Sorry.\n");
			puts( "[Stop in ParseAtomHeLike]" );
			cdEXIT(EXIT_FAILURE);
		}

		/* resonance lines - not Lya*/
		if( lgMatch("ALPH",chCard) )
		{
			iso.ipLyaRedist[ipHE_LIKE] = ipRedis;
		}
		/* Lya itself */
		if( lgMatch("RESO",chCard) )
		{
			iso.ipResoRedist[ipHE_LIKE] = ipRedis;
		}
		/* subordinate lines */
		else if( lgMatch("SUBO",chCard) )
		{
			iso.ipSubRedist[ipHE_LIKE] = ipRedis;
		}
		/* the show option, say what we are assuming */
		else if( lgMatch("SHOW",chCard) )
		{
			fprintf(ioQQQ," Ly a is ");
			if( iso.ipLyaRedist[ipHE_LIKE] ==ipCRDW )
			{
				fprintf(ioQQQ,"complete redistribution with wings\n");
			}
			else if( iso.ipLyaRedist[ipHE_LIKE] ==ipCRD )
			{
				fprintf(ioQQQ,"complete redistribution with core only.\n");
			}
			else if( iso.ipLyaRedist[ipHE_LIKE] ==ipPRD )
			{
				fprintf(ioQQQ,"partial redistribution.\n");
			}
			else if( iso.ipLyaRedist[ipHE_LIKE] ==ipLY_A )
			{
				fprintf(ioQQQ,"special Lya.\n");
			}
			else
			{
				fprintf(ioQQQ," PROBLEM Impossible value for iso.ipLyaRedist.\n");
				TotalInsanity();
			}

			fprintf(ioQQQ," Other He resonance lines are ");
			if( iso.ipResoRedist[ipHE_LIKE] ==ipCRDW )
			{
				fprintf(ioQQQ,"complete redistribution with wings\n");
			}
			else if( iso.ipResoRedist[ipHE_LIKE] ==ipCRD )
			{
				fprintf(ioQQQ,"complete redistribution with core only.\n");
			}
			else if( iso.ipResoRedist[ipHE_LIKE] ==ipPRD )
			{
				fprintf(ioQQQ,"partial redistribution.\n");
			}
			else
			{
				fprintf(ioQQQ," PROBLEM Impossible value for iso.ipResoRedist.\n");
				TotalInsanity();
			}

			fprintf(ioQQQ," He subordinate lines are ");
			if( iso.ipSubRedist[ipHE_LIKE] ==ipCRDW )
			{
				fprintf(ioQQQ,"complete redistribution with wings\n");
			}
			else if( iso.ipSubRedist[ipHE_LIKE] ==ipCRD )
			{
				fprintf(ioQQQ,"complete redistribution with core only.\n");
			}
			else if( iso.ipSubRedist[ipHE_LIKE] ==ipPRD )
			{
				fprintf(ioQQQ,"partial redistribution.\n");
			}
			else
			{
				fprintf(ioQQQ," PROBLEM Impossible value for iso.ipSubRedist.\n");
				TotalInsanity();
			}
		}
		else
		{
			fprintf(ioQQQ," here should have been another keyword on this command.\n");
			fprintf(ioQQQ," Options are ALPHA, RESONANCE, SUBORDINATE.  Sorry.\n");
			puts( "[Stop in ParseAtomHeLike]" );
			cdEXIT(EXIT_FAILURE);
		}
	}

	else if( lgMatch("LEVE",chCard) )
	{
		/* the number of levels read in is n, the principal quantum number
		 * only lines with upper levels less than n will be printed */

		/* number of levels for helium iso-sequence */
		/* there are two options here,
		 * when keyword ELEMENT appears, scan off element name and change levels only for
		 * that one.
		 * when there is no ELEMENT then set all he-like levels to same number */

		/* lgHydroMalloc is FALSE at start of calculation, set true when space 
		 * allocated for the hydrogen and helium lines.  Once done we must ignore all 
		 * future changes in the number of levels */
		if( !lgHydroMalloc )
		{
			i = 5;
			nHe = (long int)FFmtRead(chCard,&i,INPUT_LINE_LENGTH,&lgEOL);

			if( lgMatch("HUGE",chCard) )
			{
                helike.lgHugeCaseB = TRUE;
			}
			else if( !lgEOL )
			{
				/* if small He then only sample cs at kT, if large and greater
				 * accuracy is needed, take true average */
				if( nHe < 30 )
					helike.lgCS_therm_ave = FALSE;
				else
					helike.lgCS_therm_ave = TRUE;
			}

			if( lgEOL )
			{
				/* must be a number, or a key, either large (or limit) or small
				 * if no number but LARGER or SMALL then set to preset number */
				if( lgMatch("LARG",chCard) )
				{
					/* there is no real limit, but this includes all levels with tabulated rec coef
					 * set to 20 in helike.h*/
					nHe = HE_RREC_MAXN;
				}

				/* this is small or compact keyword */
				else if( lgMatch("SMAL",chCard) || lgMatch("COMP",chCard) )
				{
					/* a small atom only has n=3, 13 levels */
					nHe = 3;
				}

				/* this is huge keyword, it disables lots of physics so that the helium 
				 * case B, recombination-cascade spectrum can be calculated more easily
				 * for very large model atoms.  */
				else if( lgMatch("HUGE",chCard) )
				{
					helike.lgHugeCaseB = TRUE;
					/* the default huge atom */
					nHe = 100;
				}

				/* this is limit keyword, sets to largest possible value */
				else
				{
					/* punch out if no number */
					NoNumb(chCard);
				}
			}
			else if( ( nHe < 3 ) && !lgMatch("COLL",chCard) )
			{
				/* only enforce this limit if not working on collapsed levels */
				fprintf( ioQQQ, " cannot have fewer than 3 levels, the requested number was %li\n" ,
					nHe  );
				fprintf( ioQQQ, " Sorry.\n" );
				puts( "[Stop in ParseAtomHeLike]" );
				cdEXIT(EXIT_FAILURE);
			}

			if( lgMatch("COLL",chCard) )
			{
				if( (nHe<1) && !helike.lgSetBenjamin )
				{
					fprintf( ioQQQ, "He-like: there must be at least one collapsed level.\n");
					puts( "[Stop in ParseAtomHeLike]" );
					cdEXIT(EXIT_FAILURE);
				}

				if( lgEOL )
					NoNumb(chCard);

				/* set collapsed levels for entire sequence or just one element */
				if( lgMatch("ELEM",chCard) )
				{
					/* check which element is on the line, nelem is atomic number on C scale */
					nelem = GetElem(chCard);
					/* number of collapsed levels for the he atoms,
					* these are the highest levels and are unresolved in l and s */
					iso.nCollapsed_max[ipHE_LIKE][nelem] = nHe;
				}
				else
				{
					/* keyword element did not appear, so set all he-like species to this number */
					for( nelem=ipHELIUM; nelem<LIMELM; ++nelem )
					{
						iso.nCollapsed_max[ipHE_LIKE][nelem] = nHe;
					}
				}
			}

			/* not collapsed, not this is total number of levels */
			/* we now have the desired number of levels, and it has been fully qualified. 
			 * now check whether ELEMENT keyword is on line, if not then set all to
			 * the number, if so then only element in use */
			else if( lgMatch("ELEM",chCard) )
			{
				/* check which element is on the line, nelem is atomic number on C scale */
				nelem = GetElem(chCard);
				iso.n_HighestResolved_max[ipHE_LIKE][nelem] = nHe;
				iso.numLevels_max[ipHE_LIKE][nelem] = nHe*nHe + nHe + 1;
			}
			else
			{
				/* keyword element did not appear, so set all he-like species to this number */
				for( i=ipHELIUM; i<LIMELM; ++i )
				{
					iso.n_HighestResolved_max[ipHE_LIKE][i] = nHe;
					iso.numLevels_max[ipHE_LIKE][i] = nHe*nHe + nHe + 1;
				}
			}
		}
	}

	/* which type of matrix solution, populations or lowt */
	else if( lgMatch("MATR",chCard) )
	{
		if( lgMatch(" POP",chCard) )
		{
			strcpy( iso.chTypeAtomSet[ipHE_LIKE] , "POPU" );
		}
		else if( lgMatch(" LOW",chCard) )
		{
			strcpy( iso.chTypeAtomSet[ipHE_LIKE] , "LOWT" );
		}
		else
		{
			fprintf( ioQQQ, " There should have been a keyword on the MATRIX option.\n");
			fprintf( ioQQQ, " The keywords are POPulations, and LOWte.\n");
			fprintf( ioQQQ, " Stop in ParseAtomHeLike\n" );
			puts( "[Stop in ParseAtomHeLike]" );
			cdEXIT(EXIT_FAILURE);
		}
	}

	else if( lgMatch("TOPO",chCard) )
	{
		if( lgMatch(" OFF",chCard) )
		{
			helike.lgTopoff = FALSE;
			fprintf( ioQQQ, "HE-LIKE TOPOFF is OFF\n");
		}
		else
			helike.lgTopoff = TRUE;
	}

	else
	{
		fprintf( ioQQQ, " There should have been a keyword - STOP\n" );
		puts( "[Stop in ParseAtomHeLike]" );
		cdEXIT(EXIT_FAILURE);
	}

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