/* 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 */
/*ipoint returns pointer to any energy within energy mesh */
/*ipFineCont returns array index within fine energy mesh */
/*ipContEnergy generate unique pointer to energy within continuum array
 * continuum energy in Rydbergs */
/*ipLineEnergy generate unique pointer to line energy within energy mesh
 * line energy in Rydbergs */
#include "cddefines.h"
#include "continuum.h"
#include "rfield.h"
#include "ipoint.h"

long ipoint(double freq)
{
	long int i, 
	  ipoint_v;

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

	if( freq < continuum.filbnd[0] || freq > continuum.filbnd[continuum.nrange] )
	{
		fprintf( ioQQQ, " ipoint:\n" );
		fprintf( ioQQQ, " The freq array is not defined at nu=%11.3e. The bounds are%11.3e%11.3e\n", 
		  freq, continuum.filbnd[0], continuum.filbnd[continuum.nrange] );
		fprintf( ioQQQ, " ipoint is aborting to get trace, to find how this happened\n" );
		ShowMe();
		cdEXIT(EXIT_FAILURE);
	}

	for( i=0; i < continuum.nrange; i++ )
	{
		if( freq >= continuum.filbnd[i] && freq <= continuum.filbnd[i+1] )
		{

			/* ths is on the fortran scale of array index counting, so is one above the
			 * c scale.  later the -1 will appear on any index references */
			ipoint_v = (long int)(log10(freq/continuum.filbnd[i])/continuum.fildel[i] + 
			  1.0 + continuum.ifill0[i]);

			ASSERT( ipoint_v >= 0 );
			/* recall on F scale */
			ipoint_v = MIN2( rfield.nupper , ipoint_v );
			
#			ifdef DEBUG_FUN
			fputs( " <->ipoint()\n", debug_fp );
#			endif
			return( ipoint_v );
		}
	}

	fprintf( ioQQQ, " IPOINT logic error, energy=%10.2e\n", 
	  freq );

	puts( "[Stop in ipoint]" );
	/* ssecond exit not possible, here to shut up some compilers */
	cdEXIT(EXIT_FAILURE);
}

/*ipContEnergy generate unique pointer to energy within continuum array
 * continuum energy in Rydbergs */
long ipContEnergy(double energy, 
  const char *chLabel)/* 4 char label for continuum, like those returned by chLineLbl */
{
	long int ipConSafe_v;

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

	ipConSafe_v = ipoint(energy);

	/* write label in this cell if not anything there yet */
	if( strcmp(rfield.chContLabel[ipConSafe_v-1],"    ") == 0 )
	{
		strcpy( rfield.chContLabel[ipConSafe_v-1], chLabel );
	}

	/* this is a quick way to find all continua that occur within a given cell,
	 * recall the off-by-one aspect of C */
	{
		/*@-redef@*/
		enum {DEBUG_LOC=FALSE};
		/*@+redef@*/
		if( DEBUG_LOC )
		{
			/* recall the off-by-one aspect of C */
			if( ipConSafe_v == 1296 )
				fprintf(ioQQQ,"%s\n", chLabel );
		}
	}

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

/*ipLineEnergy generate unique pointer to line energy within energy mesh
 * line energy in Rydbergs */
long ipLineEnergy(double energy, 
  /* 4 char label for  line, like those returned by chLineLbl */
  const char *chLabel , 
  /* will make sure energy is < this pointer if greater than 0, does nothing if <= 0*/
  long ipIonEnergy )
{
	long int ipLine_ret;

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

	ipLine_ret = ipoint(energy);
	ASSERT( ipLine_ret );
	/* make sure pointer is below next higher continuum if positive */
	if( ipIonEnergy > 0 )
	{
		ipLine_ret = MIN2( ipLine_ret , ipIonEnergy-1 );
	}

	ASSERT( ipLine_ret > 0 );
	/* stuff in a label if none there,
	 * note that this is offset one below actual number to be on C scale of arrays */
	if( strcmp(rfield.chLineLabel[ipLine_ret-1],"    ")==0 )
	{
		strcpy( rfield.chLineLabel[ipLine_ret-1], chLabel );
	}
	/* this keeps track of the number of lines within this cell */
	++rfield.line_count[ipLine_ret-1];

	/* this is a quick way to find all lines that occur within a given cell,
	 * recall the off-by-one aspect of C */
	{
		/*@-redef@*/
		enum {DEBUG_LOC=FALSE};
		/*@+redef@*/
		if( DEBUG_LOC )
		{
			/* recall the off-by-one aspect of C - add one to the real index */
			if( ipLine_ret == 2795 )
				fprintf(ioQQQ,"%s\n", chLabel );
		}
	}

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

/*ipFineCont returns array index within fine energy mesh */
long ipFineCont(
	/* energy in Ryd */
	double freq )
{
	long int ipoint_v;

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

	if( freq < rfield.fine_ener_lo || freq > rfield.fine_ener_hi )
	{
		return -1;
	}

	/* ths is on the fortran scale of array index counting, so is one above the
	 * c scale.  later the -1 will appear on any index references */
	ipoint_v = (long int)(log10(freq/rfield.fine_ener_lo)/log10(1.+rfield.fine_resol));

	ASSERT( ipoint_v >= 0 && ipoint_v< rfield.nfine_malloc );
	
#	ifdef DEBUG_FUN
	fputs( " <->ipFineCont()\n", debug_fp );
#	endif
	return( ipoint_v );
}
