def jolaKap(jolaLogNums, dfBydw, jolaPoints, numDeps, temp, rho): log10E = math.log10(math.e) nm2cm = 1.0e-7 numPoints = len(jolaPoints) logKappaJola = [[0.0 for i in range(numDeps)] for j in range(numPoints)] #//Initialize this carefully: for iD in range(numDeps): for iW in range(numPoints): logKappaJola[iW][iD] = -999.0 #double stimEmExp, stimEmLogExp, stimEmLogExpHelp, stimEm; #double freq, lastFreq, w, lastW, deltaW, thisDeltaF; logSigma = -999.0 logFreq = Useful.logC() - math.log(nm2cm * jolaPoints[0]) logW = 0.0 - math.log(nm2cm * jolaPoints[0]) #//if w is waveno in cm^-1 #//lastFreq = Math.exp(logFreq) lastW = math.exp(logW) #//try accumulating oscillator strenth, f, across band - assumes f = 0 at first (largest) lambda- ?? thisF = 0.0 #//If f is cumulative in wavenumber, then we have to make the wavenumber loop the inner one even if it #//means re-calculating depth-independent quantities each time: for iD in range(numDeps): thisF = 0.0 #//re-set accumulator #//loop in order of *increasing* wavenumber #for (int iW = numPoints-1; iW >=1; iW--){ for iW in range(numPoints - 1, 1, -1): #//df/dv is a differential oscillator strength in *frequency* space: logFreq = Useful.logC() - math.log(nm2cm * jolaPoints[iW]) freq = math.exp(logFreq) logW = 0.0 - math.log( nm2cm * jolaPoints[iW]) #//if w is waveno in cm^-1 w = math.exp(logW) #//if w is waveno in cm^-1 #//System.out.println("w " + w); #//deltaW = Math.abs(freq - lastFreq); deltaW = abs(w - lastW) #//For LTE stimulated emission correction: stimEmLogExpHelp = Useful.logH() + logFreq - Useful.logK() #// for (int iD = 0; iD < numDeps; iD++){ thisDeltaF = deltaW * dfBydw[iW][iD] if (thisDeltaF > 0.0): #thisF += thisDeltaF #//cumulative version thisF = thisDeltaF #//non-cumulative version logSigma = math.log(thisF) + math.log( math.pi) + 2.0 * Useful.logEe() - Useful.logMe( ) - Useful.logC() else: logSigma = -999.0 #// LTE stimulated emission correction: stimEmLogExp = stimEmLogExpHelp - temp[1][iD] stimEmExp = -1.0 * math.exp(stimEmLogExp) stimEm = (1.0 - math.exp(stimEmExp)) #//extinction coefficient in cm^2 g^-1: logKappaJola[iW][iD] = logSigma + jolaLogNums[iD] - rho[1][ iD] + math.log(stimEm) #//logKappaJola[iW][iD] = -999.0; #//if (iD%10 == 1){ #//System.out.println("iD " + iD + " iW " + iW + " logFreq " + log10E*logFreq + " logW " + log10E*logW + " logStimEm " + log10E*Math.log(stimEm)); #//System.out.println("iD " + iD + " iW " + iW + " thisDeltaF " + thisDeltaF + " logSigma " + log10E*logSigma + " jolaLogNums " + log10E*jolaLogNums[iD] + " rho " + log10E*rho[1][iD] + " logKappaJola " + log10E*logKappaJola[iW][iD]); #//} #// } //iD loop - depths lastFreq = freq #} //iW loop - wavelength #} //iD loop - depths return logKappaJola
def sahaRHS(chiI, logUwU, logUwL, temp): """RHS of partial pressure formulation of Saha equation in standard form (N_U*P_e/N_L on LHS) // Returns depth distribution of LHS: Phi(T) === N_U*P_e/N_L (David Gray notation) // Input parameters: // chiI - ground state ionization energy of lower stage // log10UwUArr, log10UwLArr - array of temperature-dependent partition function for upper and lower ionization stage // Also needs atsmopheric structure information: // numDeps // temp structure // // Atomic element "A" is the one whose ionization fractions are being computed // Element "B" refers to array of other species with which A forms molecules "AB" """ ln10 = math.log(10.0) logE = math.log10(math.e) #// for debug output log2pi = math.log(2.0 * math.pi) log2 = math.log(2.0) #// var numMols = dissEArr.length; #// Parition functions passed in are 2-element vectore with remperature-dependent base 10 log Us #// Convert to natural logs: #double Ttheta, thisTemp; #//Default initializations: #//We need one more stage in size of saha factor than number of stages we're actualy populating thisLogUwU = 0.0 thisLogUwL = 0.0 logE10 = math.log(10.0) #//We need one more stage in size of saha factor than number of stages we're actualy populating #logUwU = [0.0 for i in range(5)] #logUwL = [0.0 for i in range(5)] for kk in range(len(logUwL)): logUwU[kk] = logUwL[kk] # logUwL[kk] = logE10*log10UwLArr[kk] #//System.out.println("chiL before: " + chiL); #// If we need to subtract chiI from chiL, do so *before* converting to tiny numbers in ergs! #//atomic ionization stage Boltzmann factors: #double logChiI, logBoltzFacI; #double boltzFacI; logChiI = math.log(chiI) + Useful.logEv() logBoltzFacI = logChiI - Useful.logK() boltzFacI = math.exp(logBoltzFacI) #//Extra factor of k to get k^5/2 in the P_e formulation of Saha Eq. logSahaFac = log2 + (3.0 / 2.0) * (log2pi + Useful.logMe() + Useful.logK() - 2.0 * Useful.logH()) + Useful.logK() #//double[] logLHS = new double[numDeps]; #double logLHS; #// For atomic ionization stages: #double logSaha, saha, expFac; #// for (int id = 0; id < numDeps; id++) { #// #//Determine temperature dependent partition functions Uw: thisTemp = temp[0] #Ttheta = 5040.0 / thisTemp """ if (Ttheta >= 1.0): thisLogUwU = logUwU[0] thisLogUwL = logUwL[0] if (Ttheta <= 0.5): thisLogUwU = logUwU[1] thisLogUwL = logUwL[1] if (Ttheta > 0.5 and Ttheta < 1.0): thisLogUwU = ( logUwU[1] * (Ttheta - 0.5)/(1.0 - 0.5) ) + ( logUwU[0] * (1.0 - Ttheta)/(1.0 - 0.5) ) thisLogUwL = ( logUwL[1] * (Ttheta - 0.5)/(1.0 - 0.5) ) + ( logUwL[0] * (1.0 - Ttheta)/(1.0 - 0.5) ) """ if (thisTemp <= 130): thisLogUwU = logUwU[0] thisLogUwL = logUwL[0] if (thisTemp > 130 and thisTemp <= 500): thisLogUwU = logUwU[1] * (thisTemp - 130)/(500 - 130) \ + logUwU[0] * (500 - thisTemp)/(500 - 130) thisLogUwL = logUwL[1] * (thisTemp - 130)/(500 - 130) \ + logUwL[0] * (500 - thisTemp)/(500 - 130) if (thisTemp > 500 and thisTemp <= 3000): thisLogUwU = logUwU[2] * (thisTemp - 500)/(3000 - 500) \ + logUwU[1] * (3000 - thisTemp)/(3000 - 500) thisLogUwL = logUwL[2] * (thisTemp - 500)/(3000 - 500) \ + logUwL[1] * (3000 - thisTemp)/(3000 - 500) if (thisTemp > 3000 and thisTemp <= 8000): thisLogUwU = logUwU[3] * (thisTemp - 3000)/(8000 - 3000) \ + logUwU[2] * (8000 - thisTemp)/(8000 - 3000) thisLogUwL = logUwL[3] * (thisTemp - 3000)/(8000 - 3000) \ + logUwL[2] * (8000 - thisTemp)/(8000 - 3000) if (thisTemp > 8000 and thisTemp < 10000): thisLogUwU = logUwU[4] * (thisTemp - 8000)/(10000 - 8000) \ + logUwU[3] * (10000 - thisTemp)/(10000 - 8000) thisLogUwL = logUwL[4] * (thisTemp - 8000)/(10000 - 8000) \ + logUwL[3] * (10000 - thisTemp)/(10000 - 8000) if (thisTemp >= 10000): thisLogUwU = logUwU[4] thisLogUwL = logUwL[4] #//Ionization stage Saha factors: #//Need T_kin^5/2 in the P_e formulation of Saha Eq. logSaha = logSahaFac - (boltzFacI / temp[0]) + ( 5.0 * temp[1] / 2.0) + thisLogUwU - thisLogUwL #// saha = Math.exp(logSaha); #//logLHS[id] = logSaha; logLHS = logSaha #// } //id loop return logLHS
def levelPops(lam0In, logNStage, chiL, logUw, gwL, numDeps, temp): """ Returns depth distribution of occupation numbers in lower level of b-b transition, // Input parameters: // lam0 - line centre wavelength in nm // logNStage - log_e density of absorbers in relevent ion stage (cm^-3) // logFlu - log_10 oscillator strength (unitless) // chiL - energy of lower atomic E-level of b-b transition in eV // Also needs atsmopheric structure information: // numDeps // temp structure """ c = Useful.c() logC = Useful.logC() k = Useful.k() logK = Useful.logK() logH = Useful.logH() logEe = Useful.logEe() logMe = Useful.logMe() ln10 = math.log(10.0) logE = math.log10(math.e) #// for debug output log2pi = math.log(2.0 * math.pi) log2 = math.log(2.0) #//double logNl = logNlIn * ln10; // Convert to base e #// Parition functions passed in are 2-element vectore with remperature-dependent base 10 log Us #// Convert to natural logs: #double thisLogUw, Ttheta; thisLogUw = 0.0 # //default initialization #logUw = [ 0.0 for i in range(5) ] logE10 = math.log(10.0) #print("log10UwStage ", log10UwStage) #for kk in range(len(logUw)): # logUw[kk] = logE10*log10UwStage[kk] #// lburns new loop logGwL = math.log(gwL) #//System.out.println("chiL before: " + chiL); #// If we need to subtract chiI from chiL, do so *before* converting to tiny numbers in ergs! #////For testing with Ca II lines using gS3 internal line list only: #//boolean ionized = true; #//if (ionized) { #// //System.out.println("ionized, doing chiL - chiI: " + ionized); #// // chiL = chiL - chiI; #// chiL = chiL - 6.113; #// } #// // #//Log of line-center wavelength in cm logLam0 = math.log(lam0In) #// * 1.0e-7); #// energy of b-b transition logTransE = logH + logC - logLam0 #//ergs if (chiL <= 0.0): chiL = 1.0e-49 logChiL = math.log( chiL) + Useful.logEv() #// Convert lower E-level from eV to ergs logBoltzFacL = logChiL - Useful.logK( ) #// Pre-factor for exponent of excitation Boltzmann factor boltzFacL = math.exp(logBoltzFacL) boltzFacGround = 0.0 / k #//I know - its zero, but let's do it this way anyway' #// return a 1D numDeps array of logarithmic number densities #// level population of lower level of bb transition (could be in either stage I or II!) logNums = [0.0 for i in range(numDeps)] #double num, logNum, expFac; for id in range(numDeps): #//Determine temperature dependenet partition functions Uw: #Ttheta = 5040.0 / temp[0][id] #//NEW Determine temperature dependent partition functions Uw: lburns thisTemp = temp[0][id] """ if (Ttheta >= 1.0): thisLogUw = logUw[0] if (Ttheta <= 0.5): thisLogUw = logUw[1] if (Ttheta > 0.5 and Ttheta < 1.0): thisLogUw = ( logUw[1] * (Ttheta - 0.5)/(1.0 - 0.5) ) \ + ( logUw[0] * (1.0 - Ttheta)/(1.0 - 0.5) ) """ if (thisTemp >= 10000): thisLogUw = logUw[4] if (thisTemp <= 130): thisLogUw = logUw[0] if (thisTemp > 130 and thisTemp <= 500): thisLogUw = logUw[1] * (thisTemp - 130)/(500 - 130) \ + logUw[0] * (500 - thisTemp)/(500 - 130) if (thisTemp > 500 and thisTemp <= 3000): thisLogUw = logUw[2] * (thisTemp - 500)/(3000 - 500) \ + logUw[1] * (3000 - thisTemp)/(3000 - 500) if (thisTemp > 3000 and thisTemp <= 8000): thisLogUw = logUw[3] * (thisTemp - 3000)/(8000 - 3000) \ + logUw[2] * (8000 - thisTemp)/(8000 - 3000) if (thisTemp > 8000 and thisTemp < 10000): thisLogUw = logUw[4] * (thisTemp - 8000)/(10000 - 8000) \ + logUw[3] * (10000 - thisTemp)/(10000 - 8000) #print("logUw ", logUw, " thisLogUw ", thisLogUw) #//System.out.println("LevPops: ionized branch taken, ionized = " + ionized); #// Take stat weight of ground state as partition function: logNums[id] = logNStage[id] - boltzFacL / temp[0][ id] + logGwL - thisLogUw #// lower level of b-b transition #print("LevelPopsServer.stagePops id ", id, " logNStage[id] ", logNStage[id], " boltzFacL ", boltzFacL, " temp[0][id] ", temp[0][id], " logGwL ", logGwL, " thisLogUw ", thisLogUw, " logNums[id] ", logNums[id]); #// System.out.println("LevelPops: id, logNums[0][id], logNums[1][id], logNums[2][id], logNums[3][id]: " + id + " " #// + Math.exp(logNums[0][id]) + " " #// + Math.exp(logNums[1][id]) + " " #// + Math.exp(logNums[2][id]) + " " #// + Math.exp(logNums[3][id])); #//System.out.println("LevelPops: id, logNums[0][id], logNums[1][id], logNums[2][id], logNums[3][id], logNums[4][id]: " + id + " " #// + logE * (logNums[0][id]) + " " #// + logE * (logNums[1][id]) + " " #// + logE * (logNums[2][id]) + " " # // + logE * (logNums[3][id]) + " " #// + logE * (logNums[4][id]) ); #//System.out.println("LevelPops: id, logIonFracI, logIonFracII: " + id + " " + logE*logIonFracI + " " + logE*logIonFracII #// + "logNum, logNumI, logNums[0][id], logNums[1][id] " #// + logE*logNum + " " + logE*logNumI + " " + logE*logNums[0][id] + " " + logE*logNums[1][id]); #//System.out.println("LevelPops: id, logIonFracI: " + id + " " + logE*logIonFracI #// + "logNums[0][id], boltzFacL/temp[0][id], logNums[2][id]: " #// + logNums[0][id] + " " + boltzFacL/temp[0][id] + " " + logNums[2][id]); #//id loop #stop return logNums
def stagePops2(logNum, Ne, chiIArr, logUw, \ numMols, logNumB, dissEArr, logUwB, logQwABArr, logMuABArr, \ numDeps, temp): #line 1: //species A data - ionization equilibrium of A #line 2: //data for set of species "B" - molecular equlibrium for set {AB} """Ionization equilibrium routine that accounts for molecule formation: // Returns depth distribution of ionization stage populations // Input parameters: // logNum - array with depth-dependent total element number densities (cm^-3) // chiI1 - ground state ionization energy of neutral stage // chiI2 - ground state ionization energy of singly ionized stage // Also needs atsmopheric structure information: // numDeps // temp structure // rho structure // Atomic element A is the one whose ionization fractions are being computed // Element B refers to array of other species with which A forms molecules AB """ ln10 = math.log(10.0) logE = math.log10(math.e) #// for debug output log2pi = math.log(2.0 * math.pi) log2 = math.log(2.0) numStages = len( chiIArr ) #// + 1; //need one more stage above the highest stage to be populated #// var numMols = dissEArr.length; #// Parition functions passed in are 2-element vectore with remperature-dependent base 10 log Us #// Convert to natural logs: #double Ttheta, thisTemp; #//Default initializations: #//We need one more stage in size of saha factor than number of stages we're actualy populating thisLogUw = [0.0 for i in range(numStages + 1)] for i in range(numStages + 1): thisLogUw[i] = 0.0 logE10 = math.log(10.0) #//We need one more stage in size of saha factor than number of stages we're actualy populating #double[][] logUw = new double[numStages+1][2]; #logUw = [ [ 0.0 for i in range(5) ] for j in range(numStages+1) ] #for i in range(numStages): # for kk in range(5): # logUw[i][kk] = logE10*log10UwAArr[i][kk] #// lburns- what variable can we use instead of 5? #//Assume ground state statistical weight (or partition fn) of highest stage is 1.0; #//var logGw5 = 0.0; #for kk in range(5): # logUw[numStages][kk] = 0.0 #// lburns #//System.out.println("chiL before: " + chiL); #// If we need to subtract chiI from chiL, do so *before* converting to tiny numbers in ergs! #//atomic ionization stage Boltzmann factors: #double logChiI, logBoltzFacI; boltzFacI = [0.0 for i in range(numStages)] #print("numStages ", numStages, " Useful.logEv ", Useful.logEv()) for i in range(numStages): #print("i ", i, " chiIArr ", chiIArr[i]) logChiI = math.log(chiIArr[i]) + Useful.logEv() logBoltzFacI = logChiI - Useful.logK() boltzFacI[i] = math.exp(logBoltzFacI) logSahaFac = log2 + (3.0 / 2.0) * (log2pi + Useful.logMe() + Useful.logK() - 2.0 * Useful.logH()) #// return a 2D 5 x numDeps array of logarithmic number densities #// Row 0: neutral stage ground state population #// Row 1: singly ionized stage ground state population #// Row 2: doubly ionized stage ground state population #// Row 3: triply ionized stage ground state population #// Row 4: quadruply ionized stage ground state population #double[][] logNums = new double[numStages][numDeps]; logNums = [[0.0 for i in range(numDeps)] for j in range(numStages)] #//We need one more stage in size of saha factor than number of stages we're actualy populating #// for index accounting pirposes #// For atomic ionization stages: # double[][] logSaha = new double[numStages+1][numStages+1]; # double[][] saha = new double[numStages+1][numStages+1]; logSaha = [[0.0 for i in range(numStages + 1)] for j in range(numStages + 1)] saha = [[0.0 for i in range(numStages + 1)] for j in range(numStages + 1)] #// logIonFrac = [0.0 for i in range(numStages)] #double expFac, logNe; #// Now - molecular variables: #//Treat at least one molecule - if there are really no molecules for an atomic species, #//there will be one phantom molecule in the denominator of the ionization fraction #//with an impossibly high dissociation energy ifMols = True if (numMols == 0): ifMols = False numMols = 1 #//This should be inherited, but let's make sure: dissEArr[0] = 19.0 #//eV #//Molecular partition functions - default initialization: #double[] thisLogUwB = new double[numMols]; thisLogUwB = [0.0 for i in range(numMols)] for iMol in range(numMols): thisLogUwB[ iMol] = 0.0 #// variable for temp-dependent computed partn fn of array element B thisLogUwA = 0.0 #// element A thisLogQwAB = math.log(300.0) #//For clarity: neutral stage of atom whose ionization equilibrium is being computed is element A #// for molecule formation: logUwA = [0.0 for i in range(5)] if (numMols > 0): for kk in range(len(logUwA)): logUwA[kk] = logUw[0][kk] #// lburns #// Array of elements B for all molecular species AB: #double[][] logUwB = new double[numMols][2]; #logUwB = [ [ 0.0 for i in range(5) ] for j in range(numMols) ] #//if (numMols > 0){ #for iMol in range(numMols): # for kk in range(5): # #print("iMol ", iMol, " kk ", kk) # logUwB[iMol][kk] = logE10*log10UwBArr[iMol][kk] #// lburns new loop #//} #//// Molecular partition functions: #// double[] logQwAB = new double[numMols]; #// //if (numMols > 0){ #// for (int iMol = 0; iMol < numMols; iMol++){ #// logQwAB[iMol] = logE10*log10QwABArr[iMol]; #// } # //} #//Molecular dissociation Boltzmann factors: boltzFacIAB = [0.0 for i in range(numMols)] logMolSahaFac = [0.0 for i in range(numMols)] #//if (numMols > 0){ #double logDissE, logBoltzFacIAB; for iMol in range(numMols): logDissE = math.log(dissEArr[iMol]) + Useful.logEv() logBoltzFacIAB = logDissE - Useful.logK() boltzFacIAB[iMol] = math.exp(logBoltzFacIAB) logMolSahaFac[iMol] = (3.0 / 2.0) * ( log2pi + logMuABArr[iMol] + Useful.logK() - 2.0 * Useful.logH()) #//console.log("iMol " + iMol + " dissEArr[iMol] " + dissEArr[iMol] + " logDissE " + logE*logDissE + " logBoltzFacIAB " + logE*logBoltzFacIAB + " boltzFacIAB[iMol] " + boltzFacIAB[iMol] + " logMuABArr " + logE*logMuABArr[iMol] + " logMolSahaFac " + logE*logMolSahaFac[iMol]); #//} #// For molecular species: logSahaMol = [0.0 for i in range(numMols)] invSahaMol = [0.0 for i in range(numMols)] for id in range(numDeps): #//// reduce or enhance number density by over-all Rosseland opcity scale parameter #// #//Row 1 of Ne is log_e Ne in cm^-3 logNe = Ne[1][id] #//Determine temperature dependent partition functions Uw: thisTemp = temp[0][id] #Ttheta = 5040.0 / thisTemp """ if (Ttheta >= 1.0): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][0] for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][0] if (Ttheta <= 0.5): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][1] for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][1] if (Ttheta > 0.5 and Ttheta < 1.0): for iStg in range(numStages): thisLogUw[iStg] = ( logUw[iStg][1] * (Ttheta - 0.5)/(1.0 - 0.5) ) \ + ( logUw[iStg][0] * (1.0 - Ttheta)/(1.0 - 0.5) ) """ #// NEW Determine temperature dependent partition functions Uw: lburns if (thisTemp <= 130): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][0] for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][0] if (thisTemp > 130 and thisTemp <= 500): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][1] * (thisTemp - 130)/(500 - 130) \ + logUw[iStg][0] * (500 - thisTemp)/(500 - 130) for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][1] * (thisTemp - 130)/(500 - 130) \ + logUwB[iMol][0] * (500 - thisTemp)/(500 - 130) if (thisTemp > 500 and thisTemp <= 3000): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][2] * (thisTemp - 500)/(3000 - 500) \ + logUw[iStg][1] * (3000 - thisTemp)/(3000 - 500) for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][2] * (thisTemp - 500)/(3000 - 500) \ + logUwB[iMol][1] * (3000 - thisTemp)/(3000 - 500) if (thisTemp > 3000 and thisTemp <= 8000): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][3] * (thisTemp - 3000)/(8000 - 3000) \ + logUw[iStg][2] * (8000 - thisTemp)/(8000 - 3000) for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][3] * (thisTemp - 3000)/(8000 - 3000) \ + logUwB[iMol][2] * (8000 - thisTemp)/(8000 - 3000) if (thisTemp > 8000 and thisTemp < 10000): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][4] * (thisTemp - 8000)/(10000 - 8000) \ + logUw[iStg][3] * (10000 - thisTemp)/(10000 - 8000) for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][4] * (thisTemp - 8000)/(10000 - 8000) \ + logUwB[iMol][3] * (10000 - thisTemp)/(10000 - 8000) if (thisTemp >= 10000): for iStg in range(numStages): thisLogUw[iStg] = logUw[iStg][4] for iMol in range(numMols): thisLogUwB[iMol] = logUwB[iMol][4] thisLogUw[numStages] = 0.0 for iMol in range(numMols): if (thisTemp < 3000.0): thisLogQwAB = ( logQwABArr[iMol][1] * (3000.0 - thisTemp)/(3000.0 - 500.0) ) \ + ( logQwABArr[iMol][2] * (thisTemp - 500.0)/(3000.0 - 500.0) ) if ((thisTemp >= 3000.0) and (thisTemp <= 8000.0)): thisLogQwAB = ( logQwABArr[iMol][2] * (8000.0 - thisTemp)/(8000.0 - 3000.0) ) \ + ( logQwABArr[iMol][3] * (thisTemp - 3000.0)/(8000.0 - 3000.0) ) if (thisTemp > 8000.0): thisLogQwAB = ( logQwABArr[iMol][3] * (10000.0 - thisTemp)/(10000.0 - 8000.0) ) \ + ( logQwABArr[iMol][4] * (thisTemp - 8000.0)/(10000.0 - 8000.0) ) #// iMol loop #//For clarity: neutral stage of atom whose ionization equilibrium is being computed is element A #// for molecule formation: thisLogUwA = thisLogUw[0] #//Ionization stage Saha factors: for iStg in range(numStages): #print("iStg ", iStg) #stop logSaha[iStg + 1][iStg] = logSahaFac - logNe - ( boltzFacI[iStg] / temp[0][id]) + (3.0 * temp[1][id] / 2.0) + thisLogUw[iStg + 1] - thisLogUw[iStg] saha[iStg + 1][iStg] = math.exp(logSaha[iStg + 1][iStg]) #// if (id == 36){ #// console.log("iStg " + iStg + " boltzFacI[iStg] " + boltzFacI[iStg] + " thisLogUw[iStg] " + logE*thisLogUw[iStg] + " thisLogUw[iStg+1] " + logE*thisLogUw[iStg+1]); #// console.log("iStg+1 " + (iStg+1) + " iStg " + iStg + " logSahaji " + logE*logSaha[iStg+1][iStg] + " saha[iStg+1][iStg] " + saha[iStg+1][iStg]); #// } #//Molecular Saha factors: for iMol in range(numMols): logSahaMol[iMol] = logMolSahaFac[iMol] - logNumB[iMol][id] - ( boltzFacIAB[iMol] / temp[0][id]) + ( 3.0 * temp[1][id] / 2.0) + thisLogUwB[iMol] + thisLogUwA - thisLogQwAB #//For denominator of ionization fraction, we need *inverse* molecular Saha factors (N_AB/NI): logSahaMol[iMol] = -1.0 * logSahaMol[iMol] invSahaMol[iMol] = math.exp(logSahaMol[iMol]) #//TEST invSahaMol[iMol] = 1.0e-99; //test #// if (id == 36){ #// console.log("iMol " + iMol + " boltzFacIAB[iMol] " + boltzFacIAB[iMol] + " thisLogUwB[iMol] " + logE*thisLogUwB[iMol] + " logNumB[iMol][id] " + logE*logNumB[iMol][id] + " logMolSahaFac[iMol] " + logMolSahaFac[iMol]); #// console.log("iMol " + iMol + " logSahaMol " + logE*logSahaMol[iMol] + " invSahaMol[iMol] " + invSahaMol[iMol]); #// } #//logSaha32 = logSahaFac - logNe - (boltzFacI2 / temp[0][id]) + (3.0 * temp[1][id] / 2.0) + thisLogUw3 - thisLogUw2; // log(RHS) of standard Saha equation #//saha32 = Math.exp(logSaha32); //RHS of standard Saha equation #//Compute log of denominator is ionization fraction, f_stage denominator = 1.0 #//default initialization - leading term is always unity #//ion stage contributions: for jStg in range(1, numStages + 1): addend = 1.0 #//default initialization for product series for iStg in range(jStg): #//console.log("jStg " + jStg + " saha[][] indices " + (iStg+1) + " " + iStg); addend = addend * saha[iStg + 1][iStg] denominator = denominator + addend #//molecular contribution if (ifMols == True): for iMol in range(numMols): denominator = denominator + invSahaMol[iMol] #// logDenominator = math.log(denominator) #//if (id == 36){ #// console.log("logDenominator " + logE*logDenominator); #// } #//var logDenominator = Math.log( 1.0 + saha21 + (saha32 * saha21) + (saha43 * saha32 * saha21) + (saha54 * saha43 * saha32 * saha21) ); logIonFrac[ 0] = -1.0 * logDenominator #// log ionization fraction in stage I #//if (id == 36){ # //console.log("jStg 0 " + " logIonFrac[jStg] " + logE*logIonFrac[0]); #//} for jStg in range(1, numStages): addend = 0.0 #//default initialization for product series for iStg in range(jStg): #//console.log("jStg " + jStg + " saha[][] indices " + (iStg+1) + " " + iStg); addend = addend + logSaha[iStg + 1][iStg] logIonFrac[jStg] = addend - logDenominator #//if (id == 36){ #// console.log("jStg " + jStg + " logIonFrac[jStg] " + logE*logIonFrac[jStg]); #//} #//logIonFracI = -1.0 * logDenominator; // log ionization fraction in stage I #//logIonFracII = logSaha21 - logDenominator; // log ionization fraction in stage II #//logIonFracIII = logSaha32 + logSaha21 - logDenominator; //log ionization fraction in stage III #//logIonFracIV = logSaha43 + logSaha32 + logSaha21 - logDenominator; //log ionization fraction in stage III #//if (id == 36) { #// System.out.println("logSaha21 " + logE*logSaha21 + " logSaha32 " + logE*logSaha32); #// System.out.println("IonFracII " + Math.exp(logIonFracII) + " IonFracI " + Math.exp(logIonFracI) + " logNe " + logE*logNe); #//} #//System.out.println("LevelPops: id, ionFracI, ionFracII: " + id + " " + Math.exp(logIonFracI) + " " + Math.exp(logIonFracII) ); # //System.out.println("LevPops: ionized branch taken, ionized = " + ionized); for iStg in range(numStages): logNums[iStg][id] = logNum[id] + logIonFrac[iStg] #//id loop return logNums
def lineKap(lam0In, logNums, logFluIn, linePoints, lineProf, numDeps, zScale, tauRos, temp, rho, logFudgeTune): logE10 = math.log(10.0) #//natural log of 10 c = Useful.c() logC = Useful.logC() k = Useful.k() logK = Useful.logK() logH = Useful.logH() logEe = Useful.logEe() logMe = Useful.logMe() ln10 = math.log(10.0) logE = math.log10(math.e) #// for debug output log2pi = math.log(2.0 * math.pi) log2 = math.log(2.0) lam0 = lam0In #// * 1.0E-7; //nm to cm logLam0 = math.log(lam0) #//double logNl = logNlIn * ln10; // Convert to base e logFlu = logFluIn * ln10 #// Convert to base e logKScale = math.log10(zScale) #//chiI = chiI * Useful.eV; // Convert lower E-level from eV to ergs #//double boltzFacI = chiI / k; // Pre-factor for exponent of excitation Boltzmann factor #//double logSahaFac = log2 + (3.0/2.0) * ( log2pi + logMe + logK - 2.0*logH); #//chiL = chiL * Useful.eV; // Convert lower E-level from eV to ergs #//double boltzFac = chiL / k; // Pre-factor for exponent of excitation Boltzmann factor numPoints = len(linePoints[0]) #//System.out.println("LineKappa: numPoints: " + numPoints); #double logPreFac; #//This converts f_lu to a volume extinction coefficient per particle - Rutten, p. 23 logPreFac = logFlu + math.log(math.pi) + 2.0 * logEe - logMe - logC #//System.out.println("LINEKAPPA: logPreFac " + logPreFac); #//Assume wavelength, lambda, is constant throughout line profile for purpose #// of computing the stimulated emission correction #double logExpFac; logExpFac = logH + logC - logK - logLam0 #//System.out.println("LINEKAPPA: logExpFac " + logExpFac); #// int refRhoIndx = TauPoint.tauPoint(numDeps, tauRos, 1.0); #// double refLogRho = rho[1][refRhoIndx]; #//System.out.println("LINEKAPPA: refRhoIndx, refRho " + refRhoIndx + " " + logE*refRho); #// return a 2D numPoints x numDeps array of monochromatic *LINE* extinction line profiles logKappaL = [[0.0 for i in range(numDeps)] for j in range(numPoints)] #double num, logNum, logExpFac2, expFac, stimEm, logStimEm, logSaha, saha, logIonFrac; #double logNe; for id in range(numDeps): logExpFac2 = logExpFac - temp[1][id] expFac = -1.0 * math.exp(logExpFac2) stimEm = 1.0 - math.exp(expFac) logStimEm = math.log(stimEm) logNum = logNums[id] #//if (id == refRhoIndx) { #// System.out.println("LINEKAPPA: logStimEm " + logE*logStimEm); #//} for il in range(numPoints): #// From Radiative Transfer in Stellar Atmospheres (Rutten), p.31 #// This is a *volume* co-efficient ("alpha_lambda") in cm^-1: logKappaL[il][id] = logPreFac + logStimEm + logNum + math.log( lineProf[il][id]) #//if (id == 36) { #// System.out.println("il " + il + " logNum " + logE*logNum + " Math.log(lineProf[il][id]) " + logE*Math.log(lineProf[il][id])); #//// //System.out.println("logPreFac " + logPreFac + " logStimEm " + logStimEm); #//} #//System.out.println("LINEKAPPA: id, il " + id + " " + il + " logKappaL " + logE * logKappaL[il][id]); #//Convert to mass co-efficient in g/cm^2: #// This direct approach won't work - is not consistent with fake Kramer's law scaling of Kapp_Ros with g instead of rho logKappaL[il][id] = logKappaL[il][id] - rho[1][id] #//Try something: #// #// ********************** #// Opacity problem #2 #// #//Line opacity needs to be enhanced by same factor as the conitnuum opacity #// - related to Opacity problem #1 (logFudgeTune in GrayStarServer3.java) - ?? #// logKappaL[il][id] = logKappaL[il][id] + logE10 * logFudgeTune #//if (id == 12) { #// System.out.println("LINEKAPPA: id, il " + id + " " + il + " logKappaL " + logE * logKappaL[il][id] #// + " logPreFac " + logE*logPreFac + " logStimEm " + logE*logStimEm + " logNum " + logE*logNum #// + " log(lineProf[il]) " + logE*Math.log(lineProf[il][id]) + " rho[1][id] " + logE * rho[1][id]); #// } #//if (id == refRhoIndx-45) { #// System.out.println("LINEKAPPA: id, il " + id + " " + il + " logKappaL " + logE*logKappaL[il][id] #// + " logPreFac " + logE*logPreFac + " logStimEm " + logE*logStimEm + " logNum " + logE*logNum + " logRho " + logE*rho[1][id] #// + " log(lineProf[1]) " + logE*Math.log(lineProf[1][il]) ); #//} #} // il - lambda loop #} // id - depth loop return logKappaL