def radPress(numDeps, temp): pRad = [[0.0 for i in range(numDeps)] for j in range(2)] logC = Useful.logC() logSigma = Useful.logSigma() radFac = math.log(4.0) + logSigma - math.log(3.0) - logC for i in range(numDeps): pRad[1][i] = radFac + 4.0 * temp[1][i] pRad[0][i] = math.exp(pRad[1][i]) return pRad
def hydroFormalSoln(numDeps, grav, tauRos, kappa, temp, guessPGas): """This approach is based on integrating the formal solution of the hydrostaitc equilibrium equation // on the otical depth (Tau) scale. Advantage is that it makes better use of the itial guess at // pgas // // Takes in *Gas* pressure, converts tot *total pressure*, then returns *Gas* pressure // """ press = [[0.0 for i in range(numDeps)] for j in range(2)] logC = Useful.logC() logSigma = Useful.logSigma() radFac = math.log(4.0) + logSigma - math.log(3.0) - logC logEg = math.log(grav) #//Natural log g!! #// no needed if integrating in natural log?? //double logLogE = Math.log(Math.log10(Math.E)); log1p5 = math.log(1.5) logE = math.log10(math.e) #//Compute radiation pressure for this temperature structure and add it to Pgas #// #double pT, pRad; logPRad = [0.0 for i in range(numDeps)] logPTot = [0.0 for i in range(numDeps)] #// System.out.println("hydroFormalSoln: "); for i in range(numDeps): logPRad[i] = radFac + 4.0 * temp[1][i] pRad = math.exp(logPRad[i]) #//System.out.println("i " + i + " pRad " + pRad); pT = guessPGas[0][i] + pRad #// System.out.println("i " + i + " guessPGas[1] " + logE*guessPGas[1][i]); logPTot[i] = math.log(pT) #double help, logHelp, logPress; #double term, logSum, integ, logInteg, lastInteg; #double deltaLogT; sum = [0.0 for i in range(numDeps)] #//Upper boundary - inherit from intiial guess: #//Carefull here - P at upper boundary can be an underestimate, but it must not be greater than value at next depth in! #// press[1][0] = logPTot[0]; #// press[1][0] = guessPGas[1][0]; #// press[1][0] = Math.log(1.0e-4); //try same upper boundary as Phoenix #// #// press[0][0] = Math.exp(press[1][0]); press[0][0] = 0.1 * guessPGas[0][0] press[1][0] = math.log(press[0][0]) #//Corresponding value of basic integrated quantity at top of atmosphere: logSum = 1.5 * press[1][0] + math.log(0.666667) - logEg sum[0] = math.exp(logSum) #// Integrate inward on logTau scale #// CAUTION; This is not an integral for Delta P, but for P once integral at each tau is exponentiated by 2/3! #// Accumulate basic integral to be exponentiated, then construct pressure values later: #//Jump start integration with an Euler step: deltaLogT = tauRos[1][1] - tauRos[1][0] #// log of integrand logInteg = tauRos[1][1] + 0.5 * logPTot[1] - kappa[1][1] lastInteg = math.exp(logInteg) sum[1] = sum[0] + lastInteg * deltaLogT #// Continue with extended trapezoid rule: for i in range(2, numDeps): deltaLogT = tauRos[1][i] - tauRos[1][i - 1] logInteg = tauRos[1][i] + 0.5 * logPTot[i] - kappa[1][i] integ = math.exp(logInteg) term = 0.5 * (integ + lastInteg) * deltaLogT sum[i] = sum[i - 1] + term #//accumulate basic integrated quantity lastInteg = integ #//System.out.println("hydroFormalSoln: "); for i in range(1, numDeps): #//Evaluate total pressures from basic integrated quantity at edach depth #// our integration variable is the natural log, so I don't think we need the 1/log(e) factor logPress = 0.666667 * (log1p5 + logEg + math.log(sum[i])) #//Subtract radiation pressure: logHelp = logPRad[i] - logPress help = math.exp(logHelp) # For hot and low g stars: limit Prad to 50% Ptot so we doen't get netaive Pgas and rho values: if (help > 0.5): help = 0.5 press[1][i] = logPress + math.log(1.0 - help) #//System.out.println("i " + i + " guessPGas[1] " + logE*guessPGas[1][i] + " press[1] " + logE*press[1][i]); press[0][i] = math.exp(press[1][i]) return press #//*Gas* pressure
def convec(numDeps, tauRos, depths, temp, press, rho, kappa, kappaSun, zScale, teff, logg, mmw): logE = math.log10(math.E) #// for debug output ln10 = math.log(10.0) #//needed to convert logg from base 10 to base e convTemp = [[0.0 for i in range(numDeps)] for j in range(2)] #//Schwarzschild criterion for convective instability: gamma = 5.0 / 3.0 #//adiabatic gamma for ideal monatomic gas - the photon gas is negligible in stars w convection gammaFac = gamma / ( gamma - 1.0 ) #// yeah, yeah - I know it's 2.5, but let's show where it comes from for the record... invGamFac = 1.0 / gammaFac #//CHEAT: Set gammaThing to value that makes convection just disappear at bottom of mid-F star (7000 K) #//double gammaThing = 1.60; #//double invGamThing = 1.0 / gammaThing; #double invGamThing; #//System.out.println("gammaThing " + gammaThing); #double deltaP, deltaT; //, dlnPdlnT; #double dlnTdlnP, dlnMudlnP, deltaMu; #double Hp, logHp; #//double HpSun = 1.2535465715411615E7; //cm, as computed by GrayStar at depth index=36 HpSun = 2.0e7 #//cm, approximately as computed by GrayStar at depth index=36 logHpSun = math.log(HpSun) #//Compute the presure scale height as a reality check: HpRefDep = 36 #//index of reference depth for computing pressure scale height logHp = press[1][HpRefDep] - rho[1][HpRefDep] - ln10 * logg Hp = math.exp(logHp) #//Try scaling gamma to "fix" the convective boundary #//invGamThing = invGamFac * HpSun/Hp; #//System.out.println("Hp/HpSun " + Hp/HpSun); #//double[] mmw = State.mmwFn(numDeps, temp, zScale); #//Search outward for top of convection zone isStable = False iBound = numDeps - 1 #//initialize index of depth where convection begins to bottom of atmosphere for i in range(numDeps - 2, 0, -1): #//System.out.println("Hp " + Hp); #//1st order finite difference - erratic? #//double deltaP = press[1][i] - press[1][i-1]; #//double deltaT = temp[1][i] - temp[1][i-1]; #//Try "2nd order" finite difference - non-uniform spacing in deltaT deltaP = press[1][i + 1] - press[1][i - 1] deltaT = temp[1][i + 1] - temp[1][i - 1] deltaMu = (mmw[i + 1] - mmw[i]) * Useful.amu #//dlnPdlnT = deltaP / deltaT; dlnTdlnP = deltaT / deltaP dlnMudlnP = deltaMu / deltaP #//System.out.format("%12.8f %12.8f%n", logE * tauRos[1][i], dlnPlndT); #// This can be finicky - let's say we have not found the radiative zone unless two consecutive layers meet the criterion #//if (dlnPdlnT > gammaThing) { if (dlnTdlnP < invGamFac + dlnMudlnP): #//Convectively stable if (isStable == False): #//The previous convectively unstable layer was an isolated anomoly - we're have NOT found the zone! Reset: isStable = true iBound = i #//System.out.println("First stable layer was found, tauRos " + logE * tauRos[1][i] + " NOW: isStable " + isStable); #} #} #} #//System.out.println("Convec: iBound " + iBound); #//Radiative zone - leave temperatures alone: for i in range(iBound): convTemp[0][i] = temp[0][i] convTemp[1][i] = temp[1][i] baseTemp = temp[0][iBound] baseLogTemp = temp[1][iBound] baseTau = tauRos[0][iBound] baseLogTau = tauRos[1][iBound] #//double baseDepth = depths[iBound] logSigma = Useful.logSigma() logK = Useful.logK() logAmu = Useful.logAmu() mixLSun = 1.0 #// convective mixing length in pressure scale heights (H_P) betaSun = 0.5 #// factor for square of convective bubble velocity (range: 0.0 - 1.0) #double Cp, logCp; //Specific heat capacity at constant pressure mixL = mixLSun #//initialization beta = betaSun #//initialization teffSun = 5778.0 loggSun = 4.44 #//Shameless fix: #//It seems mixL and beta need to be temp and press dependent: if (teff < teffSun): mixL = mixLSun * math.pow( teff / teffSun, 4.0) #//lower teff -> smaller mixL -> steeper SAdGrad beta = betaSun * math.pow( teff / teffSun, 4.0) #//lower teff -> smaller beta -> steeper SAdGrad mixL = mixL * math.pow( loggSun / logg, 2.0) #// lower logg -> larger mixL -> smaller sAdGrad beta = beta * math.pow( loggSun / logg, 2.0) #// lower logg -> larger beta -> smaller sAdGrad """/* //Shameless fix: beta = betaSun; // no fix? mixL = mixLSun * Math.pow(Hp / HpSun, 4.0); //lower teff -> smaller Hp -> smaller mixL -> steeper SAdGrad //mixL = mixL * Math.pow(logg / loggSun, 4.0); // lower logg -> smaller mixL -> larger sAdGrad */""" logMixL = math.log(mixL) logBeta = math.log(beta) logFluxSurfBol = logSigma + 4.0 * math.log(teff) #// This will get hairy when we take it super-adiabatic so let's take it *really* easy and make every factor and term clear: logInvGamFac = math.log(invGamFac) #//Get the mean molecular weight in amu from State - Row 0 is "mu" in amu: #double mu, logMu, logFctr1, logFctr2, logFctr3; #double nextTemp, lastTemp, nextTemp2; #//Adiabatic dT/dx gradients in various coordinates #//tau, logTau space #double logAdGradTauMag, logAdGradLogTauMag, adGradLogTau; #//SuperAdiabatic dT/dx gradients in various coordinates #double deltaTau, logDeltaTau, deltaLogTau, logDeltaLogTau; #double sAdGradLogTau, logSadGradR, logSadGradTau, logSadGradLogTau; #double lastLogTau; #//r space: #double logAdGradRMag, adGradR; #//SuperAdiabatic dT/dx gradients in various coordinates #double deltaR, logDeltaR; #/* # double sAdGradR; # double lastDepth; # */ lastTemp = baseTemp lastLogTau = baseLogTau #//lastDepth = baseDepth; #//System.out.println( #// "tauRos[1][i] (tauRos[1][i]-lastLogTau) adGradLogTau rho[1][i] kappa[1][i] lastTemp nextTemp"); for i in range(iBound, numDeps): mu = mmw[i] logMu = math.log(mu) logFctr1 = logMu + logAmu - logK #//System.out.println("logFactr1 " + logE*logFctr1 + " logInvGamFac " + logE*logInvGamFac + " logg " + logg); logCp = math.log( 5.0 / 2.0 ) - logFctr1 #//ideal monatomic gas - underestimate that neglects partial ionization #// ** Caution: These are log_e of the *magnitude* of the temperature gradients! #//The adiabatic dT/dTau in r space logAdGradRMag = logInvGamFac + logFctr1 + ln10 * logg #//logg is in base 10 #//This is baaad stuff - remember our tuaRos scale has *nothing* to do with our kappa values! #//The adiabatic dT/dTau in tau space - divide dT/dr by rho and kappa and make it +ve becasue we're in tau-space: #//Bad fake to fix artificially small dT/dr at low Teff - use kappaSun instead of kappa logAdGradTauMag = logAdGradRMag - rho[1][i] - kappa[1][i] #//The adiabatic dT/dLnTau in log_e(tau) space logAdGradLogTauMag = tauRos[1][i] + logAdGradTauMag #//Build the T(tau) in the convection zone: #// Work in logTau space - numerically safer?? adGradLogTau = math.exp( logAdGradLogTauMag) #//No minus sign - logTau increases inward... nextTemp = lastTemp + adGradLogTau * (tauRos[1][i] - lastLogTau) #//System.out.format("%12.8f %12.8f %12.8f %12.8f %12.8f %7.1f %7.1f%n", logE * tauRos[1][i], logE * (tauRos[1][i] - lastLogTau), adGradLogTau, logE * rho[1][i], logE * kappa[1][i], lastTemp, nextTemp); """/* // Do in geometric depth space adGradR = Math.exp(logAdGradRMag); // no minus sign - our depths *increase* inwards (they're NOT heights!) nextTemp = lastTemp + adGradR * (depths[i] - lastDepth); //System.out.format("%12.8f %12.8f %12.8f %7.1f %7.1f%n", logE*tauRos[1][i], (depths[i] - lastDepth), adGradR, lastTemp, nextTemp); */""" #//Okay - now the difference between the superadiabatic and adiabatic dT/dr: logFctr2 = rho[1][i] + logCp + 2.0 * logMixL #// ** NOTE ** Should temp in the following line be the *convective* temp of the last depth??? #// logg is in base 10 - convert to base e logFctr3 = 3.0 * (ln10 * logg - math.log(lastTemp)) / 2.0 #//Difference between SuperAdibatic dT/dr and Adiabtic dT/dr in r-space - Carroll & Ostlie 2nd Ed. p. 328 #//System.out.println("logFluxSurfBol " + logE * logFluxSurfBol + " logFctr2 " + logE * logFctr2 + " logFctr1 " + logE * logFctr1 + " logFctr3 " + logE * logFctr3 + " logBeta " + logE * logBeta); logDeltaR = logFluxSurfBol - logFctr2 + 2.0 * logFctr1 + logFctr3 - 0.5 * logBeta logDeltaR = 2.0 * logDeltaR / 3.0 #//DeltaR is above formula to the 2/3 power #//This is baaad stuff - remember our tuaRos scale has *nothing* to do with our kappa values! #//Bad fake to fix artificially small dT/dr at low Teff - use kappaSun instead of kappa logDeltaTau = logDeltaR - rho[1][i] - kappa[1][i] logDeltaLogTau = tauRos[1][i] + logDeltaTau sAdGradLogTau = adGradLogTau + math.exp(logDeltaLogTau) #//System.out.format("%12.8f %12.8f %12.8f %12.8f%n", logE*tauRos[1][i], logE*logDeltaR, logE*logDeltaTau, logE*logDeltaLogTau); nextTemp2 = lastTemp + sAdGradLogTau * (tauRos[1][i] - lastLogTau) """/* // Do in geometric depth space sAdGradR = adGradR + Math.exp(logDeltaR); nextTemp2 = lastTemp + sAdGradR * (depths[i] - lastDepth); */""" #// set everything to nextTemp2 for superadibatic dT/dr, and to nexTemp for adiabatic dT/dr convTemp[0][i] = nextTemp2 convTemp[1][i] = math.log(nextTemp2) lastTemp = nextTemp2 lastLogTau = tauRos[1][i] #//lastDepth = depths[i] #} return convTemp