https://github.com/sevenian3/ChromaStarPy
Tip revision: 103d3d0df6d9574c49818f149e1cae8100455d10 authored by Ian Short on 06 July 2023, 18:09:20 UTC
Create ReadMe
Create ReadMe
Tip revision: 103d3d0
Jola.py
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 28 16:10:08 2017
@author: ishort
"""
#/**
# * Collection of methods for computing molecular band opacity in the
# * Just-overlapping-line approximation (JOLA)
# * Just-overlapping line approximation treats molecular ro-vibrational bands as pseudo-continuum
# * opacity sources by "smearing" out the individual rotational fine-structure lines
# *See 1982A&A...113..173Z, Zeidler & Koestler, 1982
# */
import math
import Useful
def jolaGrid(jolaLambda, jolaNumPoints):
#//Try linear wavelength sampling of JOLA band for now...
jolaPoints = [0.0 for i in range(jolaNumPoints)]
iLambD = 0.0
deltaLamb = (jolaLambda[1] - jolaLambda[0]) / jolaNumPoints
for iL in range(jolaNumPoints):
iLambD = float(iL)
jolaPoints[iL] = jolaLambda[0] + iLambD*deltaLamb #//nm
#//System.out.println("iL: " + iL + " jolaPoints " + jolaPoints[iL]);
return jolaPoints #//nm
#} //end method jolaGrid
def jolaProfilePR(omega0, logf, vibConst,
jolaPoints, alphP, alphR, numDeps, temp):
"""//
//JOLA profile for P (Delta J = 1) and R (Delta J = -1) branches
//Equation 19 from Zeidler & Koestler"""
nm2cm = 1.0e-7
log10E = math.log10(math.e)
numPoints = len(jolaPoints)
#// derivative of rotational-line oscillator strength with respect to frequency
dfBydw = [ [ 0.0 for i in range(numDeps) ] for j in range(numPoints) ]
fvv = math.exp(logf)
logHcBbyK = Useful.logH() + Useful.logC() + math.log(vibConst[0]) \
- Useful.logK()
#//System.out.println("omega0 " + omega0 + " logf " + log10E*logf + " vibConst " + vibConst[0] + " " + vibConst[1] + " alphP " + alphP + " alphR " + alphR);
Bsum = vibConst[1] + vibConst[0]
Bdiff = vibConst[1] - vibConst[0]
#//value of J-related "m" at band-head:
mH = -1.0 * Bsum / (2.0*Bdiff) #//Eq. 14
#//Frequency (or wavenumber??) at band head:
wH = ( -1.0 * Bdiff * mH*mH ) + omega0 #//Eq. 15
#//System.out.println("1.0/wH " + 1.0/wH + " 1.0/omega0 " + 1.0/omega0);
mTheta1 = 1.0 #//R branch?
mTheta2 = 1.0 #//P branch?
#double m1, m2; // related to J, for R & P branches, respectively
alpha1 = 1.0
alpha2 = 1.0
#//value of m is closely related to rotational quantum number J,
#//Near band origin, frequency, w, range should correspond to -1 <= m <= 1 - ???:
#//double wMin = Useful.c / (1.0e-7*jolaPoints[numPoints-1]); //first frequency omega
#//double wMax = Useful.c / (1.0e-7*jolaPoints[0]); //last frequency omega
#//double deltaW = 0.02;
#double w, logW, m1Fctr, m2Fctr, mHelp, wMinuswHOverBDiff;
#double denom1, denom2, m1Term, m2Term;
#double help1, logHcBbyKt, hcBbyKt;
#//Outer loop over frequency omega
#// for (int iW = -1; iW <= 1; iW++){
#for (int iW = numPoints-1; iW >= 0; iW--){
for iW in range(numPoints-1, 0, -1):
#//dW = (double) iW;
#//w = wMin + (dW*deltaW);
#//logW = Useful.logC() - Math.log(1.0e-7*jolaPoints[iW]); //if w is freq in Hz
logW = 0.0 - math.log(nm2cm*jolaPoints[iW]) #//if w is waveno in cm^-1
w = math.exp(logW)
#//System.out.println("logW " + log10E*logW);
#//I have no idea if this is right...
wMinuswHOverBDiff = (w - wH) / Bdiff
mHelp = math.sqrt(abs(wMinuswHOverBDiff)) #//Eq. 17
m1 = mH + mHelp
m2 = mH - mHelp #//Eq. 18
#//System.out.println("mH " + mH + " m1 " + m1 + " m2 " + m2);
m1Fctr = (m1*m1 - m1)
m2Fctr = (m2*m2 - m2)
#//The following association between the sign of m1 or m2 and whether
#//it's the P or the R branch might be backwards:
if (m1 < 0):
alpha1 = alphP
if (m1 >= 0):
alpha1 = alphR
if (m2 < 0):
alpha2 = alphP
if (m2 >= 0):
alpha2 = alphR
denom1 = abs(Bsum + 2.0*m1*Bdiff)
denom2 = abs(Bsum + 2.0*m2*Bdiff)
for iD in range(numDeps):
if (wMinuswHOverBDiff > 0):
logHcBbyKt = logHcBbyK - temp[1][iD]
hcBbyKt = math.exp(logHcBbyKt)
help1 = -1.0 * hcBbyKt * m1Fctr
m1Term = alpha1 * mTheta1 * math.exp(help1) / denom1
help1 = -1.0 * hcBbyKt * m2Fctr
m2Term = alpha2 * mTheta2 * math.exp(help1) / denom2
#//Can this be used like a differential cross-section (once converted to sigma)?
#// System.out.println("fvv " + fvv + " hcBbyKt " + hcBbyKt + " m1Term " + m1Term + " m2Term " + m2Term);
dfBydw[iW][iD] = fvv * hcBbyKt * ( m1Term + m2Term ) #// Eq. 19
else:
dfBydw[iW][iD] = 0.0
#}
#// if (iD%10 == 1){
#// System.out.println("PR iD " + iD + " iW " + iW + " dfBydw " + dfBydw[iW][iD]);
#// }
#} //iD - depth loop
#} //iW - frequency loop
return dfBydw
#} //end method jolaProfilePR
#//
def jolaProfileQ(omega0, logf, vibConst,
jolaPoints, alphQ, numDeps, temp):
"""//JOLA profile for Q (Delta J = 0) branch
//Equation 24 from Zeidler & Koestler"""
nm2cm = 1.0e-7
numPoints = len(jolaPoints)
#// derivative of rotational-line oscillator strength with respect to frequency
dfBydw = [ [ 0.0 for i in range(numDeps) ] for j in range(numPoints) ]
fvv = math.exp(logf)
logHcBbyK = Useful.logH() + Useful.logC() + math.log(vibConst[0]) \
- Useful.logK()
Bsum = vibConst[1] + vibConst[0]
Bdiff = vibConst[1] - vibConst[0]
#double mQ; #// related to J, for R & P branches, respectively
#//value of m is closely related to rotational quantum number J,
#//Near band origin, frequency, w, range should correspond to -1 <= m <= 1 - ???:
#// double wMin = Useful.c / (1.0e-7*lambda[1]); //first frequency omega
#// double wMax = Useful.c / (1.0e-7*lambda[0]); //last frequency omega
#// double deltaW = 0.02;
#double w, logW, mQFctr, mHelp;
#double denom, mQTerm, wMinusw0OverBDiff;
#double help1, logHcBbyKt, hcBbyKt;
#//Outer loop over frequency omega
#//for (int iW = -1; iW <= 1; iW++){
#for (int iW = numPoints-1; iW >= 0; iW--){
for iW in range(numPoints-1, 0, -1):
#//dW = (double) iW;
#//w = wMin + (dW*deltaW);
#//logW = Useful.logC() - Math.log(1.0e-7*jolaPoints[iW]); //if w is freq in Hz
logW = 0.0 - math.log(nm2cm*jolaPoints[iW]) #//if w is waveno in cm^-1
w = math.exp(logW)
#//I have no idea if this is right...
wMinusw0OverBDiff = (w - omega0) / Bdiff
mHelp = 0.25 + math.abs(wMinusw0OverBDiff)
mHelp = math.sqrt(mHelp) #//Eq. 17
mQ = -0.5 + mHelp
mQFctr = (mQ*mQ - mQ)
denom = math.abs(Bdiff);
for iD in range(numDeps):
if (wMinusw0OverBDiff > 0):
logHcBbyKt = logHcBbyK - temp[1][iD]
hcBbyKt = math.exp(logHcBbyKt)
help1 = -1.0 * hcBbyKt * mQFctr
mQTerm = math.exp(help1) / denom
#//Can this be used like a differential cross-section (once converted to sigma)?
#//System.out.println("alphQ " + alphQ + " fvv " + " logHcBbyKt " + logHcBbyKt + " mQTerm " + mQTerm);
dfBydw[iW][iD] = alphQ * fvv * hcBbyKt * mQTerm #// Eq. 24
else:
dfBydw[iW][iD] = 0.0;
#//if (iD%10 == 1){
#//System.out.println("Q iD " + iD + " iW " + iW + " dfBydw " + dfBydw[iW][iD]);
#//}
#//iD - depth loop
#} //iW - frequency loop
return dfBydw
#} //end method jolaProfileQ
# //
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
#} //end method jolaKap