28 STATIC void find_solution(
long nelem,
long ion_range, valarray<double> &xmat, valarray<double> &source);
30 STATIC void fill_array(
long int nelem,
long ion_range, valarray<double> &xmat, valarray<double> &auger );
32 STATIC void fill_ext_src_and_snk(
long nelem,
long ion_low,
long ion_range, valarray<double> &xmat, valarray<double> &source );
36 STATIC void HomogeneousSource(
long nelem,
long ion_low,
long ion_range, valarray<double> &xmat, valarray<double> &source,
double abund_total );
38 STATIC void renorm_solution(
long nelem,
long ion_range,
long ion_low,
double *source,
double abund_total,
bool *lgNegPop );
44 STATIC void PrintRates(
long nelem,
bool lgNegPop,
double abund_total, valarray<double> &auger,
bool lgPrintIt );
46 void solveions(
double *ion,
double *rec,
double *snk,
double *src,
47 long int nlev,
long int nmax);
51 # define MAT(M_,I_,J_) ((M_)[(I_)*(ion_range)+(J_)])
54 # define MAT1(M_,I_,J_) ((M_)[(I_)*(ion_range1)+(J_)])
57 # define MAT2(M_,I_,J_) ((M_)[(I_)*(ion_range2)+(J_)])
61 double abund_total = 0.0;
63 bool lgNegPop =
false;
71 valarray<double> xmat(ion_range*ion_range);
72 valarray<double> source(ion_range);
73 valarray<double> auger(
LIMELM+1);
81 for (
long it=0; it<4; ++it)
104 enum {DEBUG_LOC=
false};
113 for(
long ion=
dense.
IonLow[nelem]; ion <= limit; ion++ )
143 renorm_solution( nelem, ion_range, ion_low, &source[0], abund_total, &lgNegPop );
154 xmat.resize(ion_range*ion_range);
155 source.resize(ion_range);
165 if (thiserror > error)
182 PrintRates( nelem, lgNegPop, abund_total, auger, lgPrintIt );
202 for(
long ion=0; ion<nelem+2; ++ion )
215 valarray<double> xmatsave(ion_range*ion_range);
216 valarray<double> sourcesave(ion_range);
217 valarray<int32> ipiv(ion_range);
222 for(
long i=0; i< ion_range; ++i )
224 sourcesave[i] = source[i];
225 for(
long j=0; j< ion_range; ++j )
227 MAT( xmatsave, i, j ) =
MAT( xmat, i, j );
239 fprintf(
ioQQQ,
"Error for nelem %ld, active ion range %ld--%ld\n",
242 for(
long j=0; j<nelem+2; ++j )
245 for(
long j=0; j<ion_range; ++j )
254 getrf_wrapper(ion_range, ion_range, &xmat[0], ion_range, &ipiv[0], &nerror);
258 " DISASTER ion_solver: dgetrf finds singular or ill-conditioned matrix nelem=%li %s ion_range=%li, nConv %li IonLow %li IonHi %li\n",
265 for(
long i=0; i<ion_range; ++i )
267 for(
long j=0;j<ion_range;j++ )
274 for(
long i=0; i<ion_range;i++ )
281 getrs_wrapper(
'N', ion_range, 1, &xmat[0], ion_range, &ipiv[0], &source[0], ion_range, &nerror);
284 fprintf(
ioQQQ,
" DISASTER ion_solver: dgetrs finds singular or ill-conditioned matrix nelem=%li ionrange=%li\n",
292 enum {DEBUG_LOC=
false};
295 fprintf(
ioQQQ,
"debuggg ion_solver1 %ld\t%.2f\t%.4e\t%.4e\tIon\t%.3e\tRec\t%.3e\n",
304 fprintf(
ioQQQ,
" Poprat %.3e nomol %.3e\n",source[1]/source[0],
309 for(
long i=0; i<ion_range; i++ )
318 STATIC void renorm_solution(
long nelem,
long ion_range,
long ion_low,
double *source,
double abund_total,
bool *lgNegPop )
324 ASSERT( ion_range <= nelem + 2 );
326 ASSERT( ion_low <= nelem + 1 );
334 for(
long i=0; i<ion_range; i++) {
336 for(
long j=0; j<ion_range; j++) {
337 test = test+source[j]*
MAT(xmatsave,j,i);
344 fprintf(
ioQQQ,
" ion %li abundance %.3e\n",nelem,abund_total);
348 fprintf(
ioQQQ,
" %li %.3e %.3e : %.3e\n",ion,source[ion-ion_low],
349 source[ion-ion_low+1]/source[ion-ion_low],
352 fprintf(
ioQQQ,
" %li %.3e [One ratio infinity]\n",ion,source[ion-ion_low]);
353 test += source[ion-ion_low];
381 for(
long i=0; i < ion_range; i++ )
383 long ion = i+ion_low;
391 if( source[i]<-2e-9 )
394 " PROBLEM negative ion population in ion_solver, nelem=%li, %s ion=%li val=%.3e Search?%c zone=%li iteration=%li\n",
403 fixit(
"break PrintRates into one NegPop case and one trace? No auger defined here.");
407 fixit(
"Kill this bit and force exit on negative populations.");
412 if( ion > nelem-
NISO && ion < nelem + 1 )
414 long int ipISO = nelem - ion;
417 iso_sp[ipISO][nelem].st[level].Pop() = 0.;
423 double renormnew = 1.;
428 for(
long i=0;i < ion_range; i++ )
435 renormnew = abund_total / dennew;
446 for(
long i=0;i < ion_range; i++ )
448 source[i] *= renormnew;
451 long ion = i+ion_low;
452 fprintf(
ioQQQ,
"PROBLEM DISASTER Huge density in ion_solver, nelem %ld ion %ld source %e renormnew %e\n",
453 nelem, ion, source[i], renormnew );
472 for(
long i=0; i < ion_range; i++ )
474 long ion = i+ion_low;
486 fixit(
"this should only be done if trimming is not disabled?");
517 double abund_total = 0.;
528 fprintf(
ioQQQ,
"%ld %13.8g %13.8g %13.8g %13.8g\n",nelem,tot1,tot2,abund_total,tot2/tot1 - 1.0);
538 STATIC void fill_array(
long int nelem,
long ion_range, valarray<double> &xmat, valarray<double> &auger )
545 valarray<double> sink(ion_range);
546 valarray<int32> ipiv(ion_range);
572 ASSERT( ion_range <= nelem+2 );
580 for(
long ion_from=0; ion_from <= limit; ion_from++ )
582 for(
long ion_to=0; ion_to < nelem+2; ion_to++ )
591 for(
long i=0; i<
LIMELM+1; ++i )
597 for(
long i=0; i< ion_range; ++i )
599 for(
long j=0; j< ion_range; ++j )
601 MAT( xmat, i, j ) = 0.;
616 if( ion_to != ion_from )
620 MAT( xmat, ion_from-ion_low, ion_from-ion_low ) -= rateone;
621 MAT( xmat, ion_from-ion_low, ion_to-ion_low ) += rateone;
624 MAT( xmat, ion_from-ion_low, ion_from-ion_low ) -= rateone;
625 MAT( xmat, ion_from-ion_low, ion_to-ion_low ) += rateone;
630 for(
long ion=
dense.
IonLow[nelem]; ion <= limit; ion++ )
649 if( ion+1-ion_low < ion_range )
673 auger[IonProduced-1] += rateone;
683 long ipISO=nelem-ion;
696 MAT( xmat, ion-ion_low, ion-ion_low ) -= ction;
697 MAT( xmat, ion-ion_low, ion+1-ion_low ) += ction;
704 long ipISO=nelem-ion;
723 MAT( xmat, ion+1-ion_low, ion+1-ion_low ) -= ctrec;
724 MAT( xmat, ion+1-ion_low, ion-ion_low ) += ctrec;
729 for(
long ion_to=ion_from+1; ion_to <=
dense.
IonHigh[nelem]; ion_to++ )
734 MAT( xmat, ion_from-ion_low, ion_from-ion_low ) -=
ionbal.
RateIoniz[nelem][ion_from][ion_to];
735 MAT( xmat, ion_from-ion_low, ion_to-ion_low ) +=
ionbal.
RateIoniz[nelem][ion_from][ion_to];
754 for(
long i=0; i<ion_range;i++ )
759 for(
long i=0; i<ion_range;i++ )
761 long ion = i+ion_low;
772 STATIC void HomogeneousSource(
long nelem,
long ion_low,
long ion_range, valarray<double> &xmat, valarray<double> &source,
double abund_total )
774 bool lgHomogeneous =
true;
783 totsrc = totscl = maxdiag = 0.;
784 for(
long i=0; i<ion_range;i++ )
786 long ion = i + ion_low;
789 fixit(
"need better way to determine total without molecular sinks");
793 double diag = -(
MAT( xmat, i, i )+
mole.
sink[nelem][ion]);
801 const double CONDITION_SCALE = 1e8;
802 double conserve_scale = maxdiag/CONDITION_SCALE;
803 ASSERT( conserve_scale > 0.0 );
806 if( totsrc > 1e-10*totscl )
807 lgHomogeneous =
false;
809 fixit(
"dynamics rates need to be moved into fill_array?");
815 for(
long i=0; i<ion_range;i++ )
817 long ion = i+ion_low;
823 lgHomogeneous =
false;
833 if( !lgHomogeneous && ion_range==2 )
836 double a =
MAT( xmat, 0, 0 ),
837 b =
MAT( xmat, 1, 0 ) ,
838 c =
MAT( xmat, 0, 1 ) ,
839 d =
MAT( xmat, 1, 1 );
842 double ratio1 = a/b , ratio2 = c/d , fratio1=fabs(a/b),fratio2=fabs(c/d);
843 if( fabs(ratio1-ratio2) <= DBL_EPSILON*1e4*
MAX2(fratio1,fratio2) )
845 lgHomogeneous =
true;
853 lgHomogeneous =
true;
860 if( 1 || lgHomogeneous )
862 double rate_ioniz=1., rate_recomb ;
865 for(
long i=0; i<ion_range-1;i++)
867 long ion = i+ion_low;
874 if( rate_recomb <= 0.)
877 rate_ioniz /= rate_recomb;
887 for(
long i=0; i<ion_range;i++ )
889 MAT(xmat,i,jmax) -= conserve_scale;
891 source[jmax] -= abund_total*conserve_scale;
905 enum {DEBUG_LOC=
false};
906 if( DEBUG_LOC &&
nzone==1 && lgPrintIt )
909 " DEBUG ion_solver: nelem=%li ion_range=%li, limit=%li, nConv %li xmat follows\n",
913 for(
long i=0; i<ion_range; ++i )
915 for(
long j=0;j<ion_range;j++ )
922 for(
long i=0; i<ion_range;i++ )
934 STATIC void PrintRates(
long nelem,
bool lgNegPop,
double abund_total, valarray<double> &auger,
bool lgPrintIt )
943 fprintf(
ioQQQ,
" PROBLEM Negative population found for abundance of ionization stage of element %4.4s, ZONE=%4ld\n",
1006 const char* format =
" %9.2e";
1009 "\n %s ion_solver ion/rec rt [s-1] %s nz%.2f Te%.4e ne%.4e Tot abun:%.3e ion abun%.2e mole%.2e Search? %c\n",
1039 if( ion > nelem -
NISO )
1041 long ipISO = nelem-ion;
1045 ColIoniz *=
iso_sp[ipISO][nelem].
st[0].Pop();
1069 double PhotIoniz = 0.;
1070 for(
long ipShell = 0; ipShell <
Heavy.
nsShells[nelem][ion]; ipShell++ )
1074 if( ion > nelem -
NISO )
1076 long ipISO = nelem-ion;
1080 PhotIoniz *=
iso_sp[ipISO][nelem].
st[0].Pop();
1083 PhotIoniz +=
iso_sp[ipISO][nelem].
fb[ipLevel].gamnc *
iso_sp[ipISO][nelem].
st[ipLevel].Pop();
1110 source = auger[ion-1];
1147 long ipISO=nelem-ion;
1319 void solveions(
double *ion,
double *rec,
double *snk,
double *src,
1320 long int nlev,
long int nmax)
1331 for(i=nmax;i<nlev-1;i++)
1332 src[i+1] = src[i]*ion[i]/rec[i];
1333 for(i=nmax-1;i>=0;i--)
1334 src[i] = src[i+1]*rec[i]/ion[i];
1339 for(i=0;i<nlev-1;i++)
1349 src[i+1] += ion[i]*src[i];
1350 snk[i] = bet*rec[i];
1351 kap = kap*snk[i]+snk[i+1];
1361 for(i=nlev-2;i>=0;i--)
1363 src[i] += snk[i]*src[i+1];
1392 for(
long ion = 0; ion<=nelem+1; ion++ )
double ** DR_Badnell_rate_coef
STATIC double get_total_abundance_ions(long int nelem)
void getrs_wrapper(char trans, long N, long nrhs, double *A, long lda, int32 *ipiv, double *B, long ldb, int32 *info)
realnum xMolecules(long nelem)
realnum SetIoniz[LIMELM][LIMELM+1]
ConvergenceCounter register_(const string name)
long int IonHigh[LIMELM+1]
bool lgTimeDependentStatic
void ion_solver(long int nelem, bool lgPrintIt)
bool fp_equal_tol(sys_float x, sys_float y, sys_float tol)
realnum GasPhaseAbundErrorAllowed
void IonNelem(bool lgPrintIt, long int nelem)
STATIC void find_solution(long nelem, long ion_range, valarray< double > &xmat, valarray< double > &source)
t_elementnames elementnames
t_iso_sp iso_sp[NISO][LIMELM]
double xIonDense[LIMELM][LIMELM+1]
double CharExcRecTotal[NCX]
double CharExcIonTotal[NCX]
STATIC void store_new_densities(long nelem, long ion_range, long ion_low, double *source)
STATIC void PrintRates(long nelem, bool lgNegPop, double abund_total, valarray< double > &auger, bool lgPrintIt)
long int IonLow[LIMELM+1]
long nelec_eject(long n, long i, long ns) const
void getrf_wrapper(long M, long N, double *A, long lda, int32 *ipiv, int32 *info)
long int nsShells[LIMELM][LIMELM]
realnum elec_eject_frac(long n, long i, long ns, long ne) const
STATIC void fill_ext_src_and_snk(long nelem, long ion_low, long ion_range, valarray< double > &xmat, valarray< double > &source)
void iso_departure_coefficients(long ipISO, long nelem)
void iso_satellite_update(long nelem)
void iso_charge_transfer_update(long nelem)
double ** UTA_ionize_rate
realnum *** xMoleChTrRate
STATIC void HomogeneousSource(long nelem, long ion_low, long ion_range, valarray< double > &xmat, valarray< double > &source, double abund_total)
int32 solve_system(const valarray< double > &a, valarray< double > &b, long int n, error_print_t error_print)
void iso_solve(long ipISO, long nelem, double &maxerr)
char chElementNameShort[LIMELM][CHARS_ELEMENT_NAME_SHORT]
double **** PhotoRate_Shell
STATIC void fill_array(long int nelem, long ion_range, valarray< double > &xmat, valarray< double > &auger)
char chElementSym[LIMELM][CHARS_ELEMENT_SYM]
realnum gas_phase[LIMELM]
void ion_trim_small(long nelem, double abund_total)
double *** CollIonRate_Ground
STATIC bool lgTrivialSolution(long nelem, double abund_total)
#define DEBUG_ENTRY(funcname)
STATIC void clean_up(long nelem, double abund_total)
void solveions(double *ion, double *rec, double *snk, double *src, long int nlev, long int nmax)
void iso_renorm(long nelem, long ipISO, double &renorm)
double RateIonizTot(long nelem, long ion) const
int fprintf(const Output &stream, const char *format,...)
void ion_wrapper(long nelem)
sys_float SDIV(sys_float x)
char chElementName[LIMELM][CHARS_ELEMENT_NAME]
bool lgElemsConserved(void)
t_secondaries secondaries
double CharExcIonOf[NCX][LIMELM][LIMELM+1]
realnum GrainChTrRate[LIMELM][LIMELM+1][LIMELM+1]
double CharExcRecTo[NCX][LIMELM][LIMELM+1]
void iso_set_ion_rates(long ipISO, long nelem)
STATIC void renorm_solution(long nelem, long ion_range, long ion_low, double *source, double abund_total, bool *lgNegPop)
double ** RR_rate_coef_used