https://github.com/sevenian3/ChromaStarPy
Raw File
Tip revision: 103d3d0df6d9574c49818f149e1cae8100455d10 authored by Ian Short on 06 July 2023, 18:09:20 UTC
Create ReadMe
Tip revision: 103d3d0
ChromaStarGasPy.py
# -*- coding: utf-8 -*-
"""
Spyder Editor

This is the main source file for ChromaStarPy.  We start here.

"""

"""
/*
 * The openStar project: stellar atmospheres and spectra
 *
 * ChromaStarPy
 *
 * Version 2020-05-15
 * Use date based versioning with ISO 8601 date (YYYY-MM-DD)
 *
 * December 2017
 * 
 * C. Ian Short
 * Saint Mary's University
 * Department of Astronomy and Physics
 * Institute for Computational Astrophysics (ICA)
 * Halifax, NS, Canada
 *  * ian.short@smu.ca
 * www.ap.smu.ca/~ishort/
 *
 *
 * Philip D. Bennett
 * Saint Mary's University
 * Department of Astronomy and Physics
 * Eureka Scientific
 * Halifax, NS, Canada
 *
 *
 *  * Co-developers:
 *  *
 *  * Lindsey Burns (SMU) - 2017 - "lburns"
 *  * Jason Bayer (SMU) - 2017 - "JB"
 *
 * 
 * Open source pedagogical computational stellar astrophysics
 *
 * 1D, static, plane-parallel, LTE stellar atmospheric model
 * Voigt spectral line profile
 *
 * July 2019 - Equation sof state (EOS) and chemical/ionization equilibrium now computed
 * with Phil Bennett's "GAS" package.  Includes 51 molecules, including 16 polyatomic
 * molecules
 * 
 * 
 *
 * Suitable for pedagogical purposes only
 * 
 *
 * python V. 3
 *
 * System requirements for Java version: Java run-time environment (JRE)
 * System requirements for JavaScript version: JavaScript intrepretation enabld in WWW browser (usually by default)
 *
 * Code provided "as is" - there is no formal support 
 *
 */

"""

"""/*
 * The MIT License (MIT)
 * Copyright (c) 2016 C. Ian Short 
 *
 * Permission is hereby granted, free of charge, to any person 
 obtaining a copy of this software and associated documentation 
 files (the "Software"), to deal in the Software without 
 restriction, including without limitation the rights to use, 
 copy, modify, merge, publish, distribute, sublicense, and/or 
 sell copies of the Software, and to permit persons to whom the 
 Software is furnished to do so, subject to the following 
 conditions:
 *
 * The above copyright notice and this permission notice shall 
 be included in all copies or substantial portions of the 
 Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 
 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
 OTHER DEALINGS IN THE SOFTWARE.
*
 */"""
 
#from decimal import Decimal as D

import Input
import Restart
import Useful
import LamGrid
import TauScale
import ScaleSolar
import State
import Hydrostat
import ScaleT4250g20
import ScaleT5000
import ScaleT10000
import LevelPopsGasServer
import Kappas
import KappasMetal
import KappasRaylGas
import DepthScale
import IonizationEnergy
import PartitionFn
import AtomicMass
import ToolBox
import Thetas
import MolecData
import Jola
import SpecSyn
import SpecSyn2
import HjertingComponents
import LineGrid
import LineProf
import LineKappa
import LineTau2
import FormalSoln
import Flux
import FluxTrans
import LDC
import PostProcess

#Integrated Planetary transit light curve modelling
import TransitLightCurve2
#No - only valid for ingress and egress
import TransitLightCurveAnlytc2

# GAS ESO/checmial equilibrium package, ported from Phil Bennett/Athena
#Requires special python ports of some blas and lapack routines - part of CSPy distribution
#import CSBlockData
#import GasData
#import GasData2
import CSGsRead2
import CSGasEst
import CSGas

#from Documents.ChromaStarPy.GAS import BlockData
#from Documents.ChromaStarPy.GAS.GsRead2 import gsread
#from Documents.ChromaStarPy.GAS.GasEst import gasest
#from Documents.ChromaStarPy.GAS.Gas import gas

#plotting:
import matplotlib
import matplotlib.pyplot as plt

#Type %matplotlib qt5 at python IDE prompt before running to get multiple plots in different qt windows.

import math
import numpy

from functools import reduce
import subprocess
import os
import sys

#debugging in spyder
import pdb

#############################################
#
#
#
#    Initial set-up:
#     - import all python modules
#     - set input parameters for *everything* (atmospheric modeling
#        spectrum synthesis, user-defined 2-level atom & line, 
#        post-processing, ...)
#     - prepare reference solar model and template models
#        for re-scaling to initial guess
#     
#
#
##############################################


#Detect python version
pythonV = sys.version_info
if pythonV[0] != 3:
    print("")
    print("")
    print(" ********************************************* ")
    print("")
    print("WARNING!!  WARNING!!   WARNING!!")
    print("")
    print("")
    print("ChromaStarPy developed for python V. 3!!" )
    print("")
    print("May not work in other version")
    print("")
    print("")
    print("*********************************************** ")
    print("")
    print("")



thisOS = "unknown" #default
myOS= ""
#returns 'posix' form unix-like OSes and 'nt' for Windows??
thisOS = os.name
print("")
print("Running on OS: ", thisOS)
print("")

absPath0 = "./"  #default

if thisOS == "nt": 
    #windows
    absPath0 = subprocess.check_output("cd", shell=True)    
    backSpace = 2
elif thisOS == "posix":
    absPath0 = subprocess.check_output("pwd", shell=True)
    backSpace = 1
    
absPath0 = bytes.decode(absPath0)

#remove OS_dependent trailing characters 'r\n'
nCharsPath = len(absPath0)
nCharsPath -= backSpace
absPath0 = absPath0[0: nCharsPath]

slashIndex = absPath0.find('\\') #The first backslash is the escape character!
while slashIndex != -1:
    #python strings are immutable:
    absPathCopy = absPath0[0: slashIndex]
    absPathCopy += '/'
    absPathCopy += absPath0[slashIndex+1: len(absPath0)]
    absPath0 = absPathCopy
    #print(absPathCopy, absPath0)
    slashIndex = absPath0.find('\\')
    
absPath = absPath0 + '/'

#Deprecated
#makePlot = Input.makePlot
#print("")
#print("Will make plot: ", makePlot)
#print("")
makePlotStruc = Input.makePlotStruc
makePlotSED = Input.makePlotSED
makePlotSpec = Input.makePlotSpec
makePlotLDC = Input.makePlotLDC
makePlotFT = Input.makePlotFT
makePlotTLA = Input.makePlotTLA
makePlotTrans = Input.makePlotTrans
makePlotPPress = Input.makePlotPPress

print("")
print("Type %matplotlib qt5 at python IDE prompt before running to get multiple plots in different qt windows")
print("")

#stop
#color platte for plt plotting
#palette = ['black', 'brown','red','orange','yellow','green','blue','indigo','violet']
#grayscale
#stop
#Grayscale:
numPal = 12
palette = ['0.0' for i in range(numPal)]
delPal = 0.04
#for i in range(numPal):
#    ii = float(i)
#    helpPal = 0.481 - ii*delPal
#    palette[i] = str(helpPal) 
      
palette = [ str( 0.481 - float(i)*delPal ) for i in range(numPal) ]
numClrs = len(palette)


#General file for printing ad hoc quantities
dbgHandle = open("debug.out", 'w')
outPath = absPath + "/Outputs/"

fileStem = Input.fileStem+"Gas"
#Not usedoutFileString = outPath+fileStem+"Gas.*"
print(" ")
print("Writing to files ", outPath + fileStem)
print(" ")


""" test
#// Representative spectral line and associated atomic parameters
#//NaID
userLam0 = 589.592   #nm 
userA12 = 6.24    #// A_12 logarithmic abundance = log_10(N/H_H) = 12
userLogF = math.log10(math.e)*math.log(0.320)  #// log(f) oscillaotr strength // saturated line
testAij = math.log(6.14e+07)
userStage = 0 #//ionization stage of user species (0 (I) - 3 (IV)
userChiI1 = 5.5 #// ground state chi_I, eV
userChiI2 = 8.0 #// 1st ionized state chi_I, eV
userChiI3 = 20.0 #// 2nd ionized state chi_I, eV
userChiI4 = 40.0  #// 3rd ionized state chi_I, eV
userChiL = 0.0 #// lower atomic E-level, eV
userGw1 = 2  #// ground state state. weight or partition fn (stage I) - unitless
userGw2 = 1  #// ground state state. weight or partition fn (stage II) - unitless
userGw3 = 1  #// ground state state. weight or partition fn (stage III) - unitless
userGw4 = 1  #// ground state state. weight or partition fn (stage IV) - unitless
userGwL = 2 #// lower E-level state. weight - unitless
userMass = 22.0  #//amu
userLogGammaCol = 1.0  #log_10 Lorentzian broadening enhancement factor
"""

#True for Voigt computed with true convolution instead of power-law expansion approx - probably not working well right now
ifVoigt = False
#Scattering term in line source fn - not yet enabled   
ifScatt = False 

#// Argument 0: Effective temperature, Teff, in K:
#teff = float(teffStr) 
teff = Input.teff       
#print(type(teff))

#// Argument 1: Logarithmic surface gravity, g, in cm/s/s:
#logg = float(loggStr)
logg = Input.logg

#//Argument 2: Linear sclae factor for solar Rosseland oapcity distribution
#log10ZScale = float(logZStr)
log10ZScale = Input.log10ZScale



#//Argument 3: Stellar mass, M, in solar masses
#massStar = float(massStarStr)
massStar = Input.massStar

#// Sanity check:
F0Vtemp = 7300.0;  #// Teff of F0 V star (K) 
                          
if (teff < 3000.0): 
    teff = 3000.0
#    teffStr = "3000"

if (teff > 50000.0):
    teff = 50000.0
#    teffStr = "50000"
    
#//logg limit is strongly Teff-dependent:
minLogg = 3.0; #//safe initialization
minLoggStr = "3.0";
if (teff <= 4000.0):
    minLogg = 0.0
#    minLoggStr = "0.0"
elif ((teff > 4000.0) and (teff <= 5000.0)): 
    minLogg = 0.5
#    minLoggStr = "0.5"
elif ((teff > 5000.0) and (teff <= 6000.0)): 
    minLogg = 1.5
#    minLoggStr = "1.5"
elif ((teff > 6000.0) and (teff <= 7000.0)): 
    minLogg = 2.0
#    minLoggStr = "2.0"
elif ((teff > 7000.0) and (teff < 9000.0)): 
    minLogg = 2.5
#    minLoggStr = "2.5"
elif (teff >= 9000.0): 
    minLogg = 3.0
#    minLoggStr = "3.0"

if (logg < minLogg): 
    logg = minLogg
#    loggStr = minLoggStr

if (logg > 7.0): 
    logg = 7.0
#    loggStr = "7.0"
        
if (log10ZScale < -3.0): 
    log10ZScale = -3.0
#    logZStr = "-3.0"
        
if (log10ZScale > 1.0): 
    log10ZScale = 1.0
#    logZStr = "1.0"

if (massStar < 0.1): 
    massStar = 0.1
#    massStarStr = "0.1"
        
if (massStar > 20.0): 
    massStar = 20.0
#    massStarStr = "20.0"

grav = math.pow(10.0, logg)
zScale = math.pow(10.0, log10ZScale)

#// Argument 5: microturbulence, xi_T, in km/s:
#xiT = float(xiTStr)
xiT = Input.xiT

if (xiT < 0.0): 
    xiT = 0.0
#    xitStr = "0.0"
        
if (xiT > 8.0): 
    xiT = 8.0
#    xitStr = "8.0"
    
#// Add new variables to hold values for new metallicity controls lburns
#logHeFe = float(logHeFeStr)  #// lburns
#logCO = float(logCOStr) #// lburns
#logAlphaFe = float(logAlphaFeStr) #// lburns
logHeFe = Input.logHeFe
logCO = Input.logCO
logAlphaFe = Input.logAlphaFe

#// For new metallicity commands lburns
#// For logHeFe: (lburns)
if (logHeFe < -1.0):
    logHeFe = -1.0;
#    logHeFeStr = "-1.0";
    
if (logHeFe > 1.0):
    logHeFe = 1.0
#    logHeFeStr = "1.0"
    
#// For logCO: (lburns)
if (logCO < -2.0):
    logCO = -2.0
#    logCOStr = "-2.0"

if (logCO > 2.0):
    logCO = 2.0
#    logCOStr = "2.0"

#// For logAlphaFe: (lburns)
if (logAlphaFe < -0.5):
    logAlphaFe = -0.5
#    logAlphaFeStr = "-0.5"

if (logAlphaFe > 0.5):
    logAlphaFe = 0.5
#    logAlphaFeStr = "0.5"

        

#// Argument 6: minimum ratio of monochromatic line center to background continuous
#// extinction for inclusion of linein spectrum 
#lineThreshStr = args[5];
#lineThreshStr = "-3.0"; #//test
#lineThresh = float(lineThreshStr)
lineThresh = Input.lineThresh    

if (lineThresh < -4.0): 
    lineThresh = -4.0
#    lineThreshStr = "-4.0"
        
if (lineThresh > 6.0): 
    lineThresh = 6.0
#    lineThreshStr = "6.0"
        

#// Argument 7: minimum ratio of monochromatic line center to background continuous
#voigtThresh = float(voigtThreshStr);
voigtThresh = Input.voigtThresh    

if (voigtThresh < lineThresh): 
    voigtThresh = lineThresh
#    voigtThreshStr = lineThreshStr
        
if (voigtThresh > 6.0): 
    voigtThresh = 6.0
#    voigtThreshStr = "6.0"
        
#//User defined spetrum synthesis region:
lamUV = numpy.double(260.0);
lamIR = numpy.double(2600.0);

#// Argument 8: starting wavelength for spectrum synthesis 

#lambdaStart = float(lambdaStartStr)
lambdaStart = Input.lambdaStart

if (lambdaStart < lamUV): 
    lambdaStart = lamUV
#    lambdaStartStr = str(lamUV)
        
if (lambdaStart > lamIR - 1.0): 
    lambdaStart = lamIR - 1.0
#    lambdaStartStr = str(lamIR - 1.0)
        
#// Argument 9: stopping wavelength for spectrum synthesis 
#lambdaStop = float(lambdaStopStr)
lambdaStop = Input.lambdaStop    

if (lambdaStop < lamUV + 1.0): 
    lambdaStop = lamUV + 1.0
#    lambdaStartStr = str(lamUV + 1.0)
        
if (lambdaStop > lamIR):
    lambdaStop = lamIR
#    lambdaStartStr = str(lamIR)

#//Prevent negative or zero lambda range:
if (lambdaStop <= lambdaStart):
    lambdaStop = lambdaStart + 0.5 #//0.5 nm = 5 A
#    lambdaStopStr = str(lambdaStop)

"""
#//limit size of synthesis region (nm):
maxSynthRange = 5.0 #//set default to minimum value //nm
#//if we're not in the blue we can get away wth more:
if (lambdaStart > 350.0):
    maxSynthRange = 10.0
if (lambdaStart > 550.0):
    maxSynthRange = 20.0
if (lambdaStart > 700.0):
    maxSynthRange = 50.0
if (lambdaStart > 1000.0):
    maxSynthRange = 100.0
if (lambdaStart > 1600.0):
    maxSynthRange = 200.0

#//console.log("maxSynthRange " + maxSynthRange + " lambdaStop " + lambdaStop);
if (lambdaStop > (lambdaStart+maxSynthRange)):
    #//console.log("lambdaStop > (lambdaStart+maxSynthRange) condition");
    lambdaStop = lambdaStart + maxSynthRange #//10 nm = 100 A
    lambdaStopStr = str(lambdaStop)
#//console.log("lambdaStop " + lambdaStop);
"""
if (lambdaStop > lamIR):
    #//console.log("lambdaStop > lamIR condition");
    lambdaStop = lamIR
#    lambdaStopStr = str(lamIR)

#//console.log("lambdaStop " + lambdaStop);

nm2cm = numpy.double(1.0e-7)
cm2nm = numpy.double(1.0e7)     
lambdaStart = nm2cm * lambdaStart #//nm to cm 
lambdaStop = nm2cm * lambdaStop  #//nm to cm
lamUV = nm2cm * lamUV
lamIR = nm2cm * lamIR
      
#//argument 10: line sampling selection (fine or coarse)
#sampling = "fine"

sampling = Input.sampling
vacAir = Input.vacAir

#// Argument 11: Lorentzian line broadening enhancement 
#logGammaCol = float(logGammaColStr)
logGammaCol = Input.logGammaCol

if (logGammaCol < 0.0):
    logGammaCol = 0.0
#    logGammaColStr = "0.0"
        
if (logGammaCol > 1.0):
    logGammaCol = 1.0
#    logGammaColStr = "1.0"
        
#// Argument 12: log_10 gray mass extinction fudge 
#logKapFudge = float(logKapFudgeStr)
logKapFudge = Input.logKapFudge

if (logKapFudge < -2.0):
    logKapFudge = -2.0
#    logKapFudgeStr = "-2.0"
        
if (logKapFudge > 2.0):
    logKapFudge = 2.0
#    logKapFudgeStr = "2.0"
        

#// Argument 13: macroturbulent velocity broadening parameter (sigma) (km/s) 
#macroV = float(macroVStr)
macroV = Input.macroV    
#// Argument 14: surface equatorial linear rotational velocity (km/s) 
#rotV  = float(rotVStr)
rotV = Input.rotV
#// Argument 15: inclination of rotation axis wrt line-of-sight (degrees) 
#rotI  = float(rotIStr)
rotI = Input.rotI
#print("Before test rotI ", rotI, " rotIStr ", rotIStr)
#// Argument 16: number of outer HSE-EOS-Opac iterations
#nOuterIter = int(nOuterIterStr)
nOuterIter = Input.nOuterIter
#// Argument 17: number of inner Pe-IonFrac iterations
#nInnerIter = int(nInnerIterStr)
nInnerIter = Input.nInnerIter
#//Argument 18: If TiO JOLA bands should be included:
#ifTiO = int(ifTiOStr)
ifMols = Input.ifMols

if (macroV < 0.0):
    macroV = 0.0
#    macroVStr = "0.0"
        
if (macroV > 8.0):
    macroV = 8.0
#    macroVStr = "8.0"
        

if (rotV < 0.0):
    rotV = 0.0
#    rotVStr = "0.0"
        
if (rotV > 300.0):
    rotV = 300.0
#    rotVStr = "300.0"
        

if (rotI < 0.0): 
    rotI = 0.0
#    rotIStr = "0.0"
        
if (rotI > 90.0):
    rotI = 90.0
#    rotIStr = "90.0"
        
if (nOuterIter < 1): 
    nOuterIter = 1
#    nOuterIterStr = "1"
        
if (nOuterIter > 30):
    nOuterIter = 30
#    nOuterIterStr = "12"
        
if (nInnerIter < 1):
    nInnerIter = 1
#    nInnerIterStr = "1"
        
if (nInnerIter > 30):
    nInnerIter = 30
#    nInnerIterStr = "12"
    
#print("After test rotI ", rotI, " rotIStr ", rotIStr)    
    
#//For rotation:
inclntn = math.pi * rotI / 180.0  #//degrees to radians
vsini = rotV * math.sin(inclntn)

#// Argument 19: wavelength of narrow Gaussian filter in nm
#diskLambda = float(diskLambdaStr)  #//nm
diskLambda = Input.diskLambda
#// Argument 20: bandwidth, sigma, of narrow Gaussian filter in nm
#diskSigma = float(diskSigmaStr)  #//nm
diskSigma = Input.diskSigma
#// Argument 21: radial velocity of star in km/s
#RV = float(RVStr)  #//nm   
RV = Input.RV
#// Argument 22: Spectrum synthesis wavelength scale options:

if (diskLambda < lamUV):
    diskLambda = lamUV
#    diskLambdaStr = str(lamUV)    
if (diskLambda > lamIR):
    diskLambda = lamIR
#    diskLambdaStr = str(lamIR)
    
if (diskSigma < 0.005):
    diskSigma = 0.005
#    diskSigmaStr = "0.005";
if (diskSigma > 10.0):
    diskSigma = 10.0
#    diskSigmaStr = "10"
    
if (RV < -200.0):
    RV = -200.0
#    RVStr = "-200"
if (RV > 200.0):
    RV = 200.0
#    RVStr = "200"
    
#vacAir = "vacuum" #//test

#// Representative spectral line and associated atomic parameters
#//
"""
userLam0 = float(userLam0Str)
userA12 = float(userA12Str)
userLogF = float(userLogFStr)
userStage = float(userStageStr)
userChiI1 = float(userChiI1Str)
userChiI2 = float(userChiI2Str)
userChiI3 = float(userChiI3Str)
userChiI4 = float(userChiI4Str)
userChiL = float(userChiLStr)
userGw1 = float(userGw1Str)
userGw2 = float(userGw2Str)
userGw3 = float(userGw3Str)
userGw4 = float(userGw4Str)
userGwL = float(userGwLStr)
userMass = float(userMassStr)
userLogGammaCol = float(userGammaColStr)
"""
userLam0 = Input.userLam0
userA12 = Input.userA12
userLogF = Input.userLogF
userStage = Input.userStage
userChiI1 = Input.userChiI1
userChiI2 = Input.userChiI2
userChiI3 = Input.userChiI3
userChiI4 = Input.userChiI4
userChiL = Input.userChiL
userGw1 = Input.userGw1
userGw2 = Input.userGw2
userGw3 = Input.userGw3
userGw4 = Input.userGw4
userGwL = Input.userGwL
userMass = Input.userMass
userLogGammaCol = Input.userLogGammaCol

if (userLam0 < 260.0):
    userLam0 = 260.0
#    userLamStr = "260"
if (userLam0 > 2600.0):
    userLam0 = 2600.0
#    userLamStr = "2600"

if (userA12 < 2.0):
    userA12 = 2.0
#    userNStr = "2.0"
#//Upper limit set high to accomodate Helium!:
if (userA12 > 11.0):
    userA12 = 11.0
#    userNStr = "11.0"

if (userLogF < -6.0):
    userLogF = -6.0
#    userFStr = "-6.0"
if (userLogF > 1.0):
    userLogF = 1.0
#    userFStr = "1.0"

if ( (userStage != 0) and (userStage != 1) and (userStage != 2) and (userStage != 3) ):
    userStage = 0
    userStageStr = "I"

if (userChiI1 < 3.0):
    userChiI1 = 3.0
#    userIonStr = "3.0"
if (userChiI1 > 25.0):
    userChiI1 = 25.0
#    userIonStr = "25.0"

if (userChiI2 < 5.0):
    userChiI2 = 5.0
#    userIonStr = "5.0"
if (userChiI2 > 55.0):
    userChiI2 = 55.0
#    userIonStr = "55.0"

if (userChiI3 < 5.0):
    userChiI3 = 5.0
#    userIonStr = "5.0"
if (userChiI3 > 55.0):
    userChiI3 = 55.0
#    userIonStr = "55.0"

if (userChiI4 < 5.0):
    userChiI4 = 5.0
#    userIonStr = "5.0"
if (userChiI4 > 55.0):
    userChiI4 = 55.0
#    userIonStr = "55.0"

#// Note: Upper limit of chiL depends on value of chiI1 above!
if (userChiL < 0.0):
    userChiL = 0.0 #// Ground state case!
#    userExcStr = "0.0"
if ( (userStage == 0) and (userChiL >= userChiI1) ):
    #//ionized = false;
    userChiL = 0.9 * userChiI1
#    userExcStr = userIonStr

if ( (userStage == 1) and (userChiL >= userChiI2) ):
    #//ionized = false;
    userChiL = 0.9 * userChiI2
#    userExcStr = userIonStr

if ( (userStage == 2) and (userChiL >= userChiI3) ):
    #//ionized = false;
    userChiL = 0.9 * userChiI3
#    userExcStr = userIonStr

if ( (userStage == 3) and (userChiL >= userChiI4) ):
    #//ionized = false;
    userChiL = 0.9 * userChiI4
#    userExcStr = userIonStr

if (userGw1 < 1.0):
    userGw1 = 1.0
#    userWghtStr = "1"
if (userGw1 > 100.0):
    userGw1 = 100.0
#    userWghtStr = "100"

if (userGw2 < 1.0):
    userGw2 = 1.0
#    userWghtStr = "1";
if (userGw2 > 100.0):
    userGw2 = 100.0
#    userWghtStr = "100";

if (userGw3 < 1.0):
    userGw3 = 1.0
#    userWghtStr = "1"
if (userGw3 > 100.0):
    userGw3 = 100.0
#    userWghtStr = "100"

if (userGw4 < 1.0):
    userGw4 = 1.0
#    userWghtStr = "1"
if (userGw4 > 100.0):
    userGw4 = 100.0
#    userWghtStr = "100"

if (userGwL < 1.0):
    userGwL = 1.0
#    userLWghtStr = "1"
if (userGwL > 100.0):
    userGwL = 100.0
#    userLWghtStr = "100"

if (userMass < 1.0):
    userMass = 1.0
#    userMassStr = "1.0"
if (userMass > 200.0):
    userMass = 200.0
#    userMassStr = "200"
    
if (userLogGammaCol < 0.0):
    userLogGammaCol = 0.0
#    useLogGammaColStr = "0.0"
if (userLogGammaCol > 1.0):
    userLogGammaCol = 1.0
#    useLogGammaColStr = "1.0"

userLam0 = userLam0 * nm2cm #// line centre lambda from nm to cm

#

#Planetary transit light-curve modelling input:
# Oribital period is not a free parameter - it is set by the 
# size of the orbit and the planet's mass by basic 
#Kepler's 3rd law

#Sanity checks on inputs occur after stellar 'radius' defined below...

#For development - plantary transit light curve stuff
#TransLight(rotI, radius, rOrbit, rPlanet, cosTheta, phi):
#ifTransit = True
#rOrbit = 1.0 # AU
#rPlanet = 1.0 #Earth radii
#mPlanet = 1.0 #Earth masses
ifTransit = Input.ifTransit
rOrbit = Input.rOrbit # AU
rPlanet = Input.rPlanet #Earth radii
#mPlanet = Input.mPlanet #Earth masses (not needed (yet??))


#Upper limit ensures Kepler III is valid

#if (mPlanet > 0.1*massStar): 
#    mPlanet = 0.1*massStar
#        
#if (mPlanet <= 0.0): 
#    mPlanet = 0.001*massStar



#stop
#Create output file

"""
#File for structure output:
strucStem = "Teff" + teffStr + "Logg" + loggStr + "Z" + logZStr + "M" + massStarStr+"xiT"+xiTStr + \
"HeFe" + logHeFeStr + "CO" + logCOStr + "AlfFe" + logAlphaFeStr + "v" + runVers
strucFile = "struc." + strucStem + ".out"
specFile = "spec." + strucStem + "L"+lambdaStartStr+"-"+lambdaStopStr+"xiT"+xiTStr+"LThr"+lineThreshStr+ \
"GamCol"+logGammaColStr+"Mac"+macroVStr+"Rot"+rotVStr+"-"+rotIStr+"RV"+RVStr + ".out"
sedFile = "sed." + strucStem + "L"+lambdaStartStr+"-"+lambdaStopStr+"xiT"+xiTStr+"lThr"+lineThreshStr+ \
"Mac" + macroVStr + "Rot"+rotVStr+"-"+rotIStr+"RV"+ RVStr + ".out" 
ldcFile = "ldc." + strucStem + "L" + diskLambdaStr + "S" + diskSigmaStr + ".out"
lineFile = "line." + strucStem + "L0" + userLam0Str + ".out"
"""
#Echo input parameters *actually used* to console:
inputParamString = "Teff " + str(teff) + " logg " + str(logg) + " [Fe/H] " + str(log10ZScale) + " massStar " + \
      str(massStar) + " xiT " + str(xiT) + " HeFe " + str(logHeFe) + " CO " + str(logCO) + " AlfFe " + str(logAlphaFe) + \
       " lineThresh " + str(lineThresh) + " voigtThresh " + \
      str(voigtThresh) + " lambda0 " + str(lambdaStart) + " lambda1 " + str(lambdaStop) + " logGamCol " + \
      str(logGammaCol) + " logKapFudge " + str(logKapFudge) + " macroV " + str(macroV) + " rotV " + str(rotV) + \
      " rotI " + str(rotI) + " RV " + str(RV) + " nInner " + str(nInnerIter) + " nOuter " + str(nOuterIter) + \
      " ifMols " + str(ifMols) + " sampling " + sampling
print(inputParamString)

#stop
#// Wavelengths in Air : 
#    if ($("#air").is(":checked")) {
#        vacAir = $("#air").val(); // radio 
#    }
#// Wavelengths in vacuum: (default)
#    if ($("#vacuum").is(":checked")) {
#       vacAir = $("#vacuum").val(); // radio 
#    }
    
#//
#// ************************ 
#//
#//  OPACITY  PROBLEM #1 - logFudgeTune:  late type star coninuous oapcity needs to have by multiplied 
#//  by 10.0^0.5 = 3.0 for T_kin(tau~1) to fall around Teff and SED to look like B_lmabda(Trad=Teff).
#//   - related to Opacity problem #2 in LineKappa.lineKap() - ??
#//
logFudgeTune = 0.0
#//sigh - don't ask me - makes the Balmer lines show up around A0:
if (teff <= F0Vtemp):
    logFudgeTune = 0.5
    #logFudgeTune = 0.0
      
if (teff > F0Vtemp):
    logFudgeTune = 0.0

logTotalFudge = logKapFudge + logFudgeTune

logE = math.log10(math.e) #// for debug output
logE10 = math.log(10.0) #//natural log of 10

tiny = numpy.double(1.0e-49)
logTiny = math.log(tiny)

#//Gray structure and Voigt line code code begins here:
#// Initial set-up:
#// optical depth grid
numDeps = 48
log10MinDepth = numpy.double(-6.0)
log10MaxDepth = numpy.double(2.0)
#//int numThetas = 10;  #// Guess

#//wavelength grid (cm):
lamSetup = [ numpy.double(0.0) for i in range(3) ]
#for i in range(3):
#    lamSetup.append(0.0)

lamSetup[0] = numpy.double(260.0) * nm2cm  #// test Start wavelength, cm
#lamSetup[0] = numpy.double(100.0) * 1.0e-7;  // test Start wavelength, cm
lamSetup[1] = numpy.double(2600.0) * nm2cm #// test End wavelength, cm
lamSetup[2] = numpy.double(250);  #// test number of lambda
#//int numLams = (int) (( lamSetup[1] - lamSetup[0] ) / lamSetup[2]) + 1;  
numLams = int(lamSetup[2])

#//CONTINUUM lambda scale (nm)
lambdaScale = LamGrid.lamgrid(numLams, lamSetup) #//cm
        
#// Solar parameters:
teffSun = 5778.0
loggSun = 4.44
gravSun = math.pow(10.0, loggSun)
log10ZScaleSun = 0.0
zScaleSun = math.exp(log10ZScaleSun)

#//Solar units:
massSun = 1.0
radiusSun = 1.0
#//double massStar = 1.0; //solar masses // test
logRadius = 0.5 * (math.log(massStar) + math.log(gravSun) - math.log(grav))
radius = math.exp(logRadius); #//solar radii
#//double radius = Math.sqrt(massStar * gravSun / grav); // solar radii
logLum = 2.0 * math.log(radius) + 4.0 * math.log(teff / teffSun)
bolLum = math.exp(logLum) #// L_Bol in solar luminosities 
#//cgs units:
#rSun = 6.955e10 #// solar radii to cm

cgsRadius = radius * Useful.rSun()
omegaSini = (1.0e5 * vsini) / cgsRadius #// projected rotation rate in 1/sec
macroVkm = macroV * 1.0e5  #//km/s to cm/s

#//Composition by mass fraction - needed for opacity approximations
#//   and interior structure
massX = 0.70 #//Hydrogen
massY = 0.28 #//Helium
massZSun = 0.02 #// "metals"
massZ = massZSun * zScale #//approximation


#For planetary transit light curve:
#Now we can do sanity checks on these inputs:
rPlanetSol = rPlanet * Useful.rEarth() / Useful.rSun() #Earth radii to solar radii    
if (rPlanetSol > 0.1*radius): 
    rPlanetSol = 0.1*radius 
    rPlanet = rPlanetSol * Useful.rSun() / Useful.rEarth()       
if (rPlanet <= 0.0): 
    rPlanetSol = 0.001*radius
    rPlanet = rPlanetSol * Useful.rSun() / Useful.rEarth() 

rOrbitSol = rOrbit * Useful.AU2cm() / Useful.rSun()
if (rOrbitSol < radius):
    rOrbitSol = radius
    rOrbit = rOrbitSol * Useful.rSun() / Useful.AU2cm()
if (rOrbit > 100.0):
    rOrbit = 100.0 

logMassStar = math.log(massStar) + Useful.logMSun() #MSun to g
#print("MassStar ", math.exp(logMassStar))
logROrbCm = math.log(rOrbit) + Useful.logAU2cm() #AU to cm
#print("ROrbCm ", math.exp(logROrbCm))

#linear velocity of planetary orbit from Kepler's 3rd law
#Assumes planet at same distance as stellar surface
logVtransSq = Useful.logGConst() + logMassStar - logROrbCm
logVtrans = 0.5*logVtransSq
vTrans = math.exp(logVtrans)  #cm/s approximately at star's surface 
#print("vTrans ", vTrans)

#For period calculation only:
#angular velocity of planetary orbit from Kepler's 3rd law
logOmegaSq = Useful.logGConst() + logMassStar - 3*logROrbCm
logOmega = 0.5 * logOmegaSq  # RAD/s
#print("Omega ", math.exp(logOmega))

#Orbital period - for interest
logPplanet = math.log(2.0) + math.log(math.pi) - logOmega
pPlanet = math.exp(logPplanet)
print("Planetary orbital period (s) ", pPlanet)  # in s
#Establish ephemeris with zero epoch (phase = 0) at mid-transit
#time interval should be equal to or less than time taken for plane to
#move through its own diameter - time interval of ingress or egress 
#ingressT = ( 2.0*rPlanet*Useful.rEarth() ) / vTrans
#print("Old ingressT ", ingressT)

#//double logNH = 17.0

#//
#////Detailed checmical composition:
#//Abundance table adapted from PHOENIX V. 15 input bash file
#// Grevesse Asplund et al 2010
#//Solar abundances:
#// c='abundances, Anders & Grevesse',

nelemAbnd = 41
numStages = 7
  
nome = [0 for i in range(nelemAbnd)] 
eheu = [0.0 for i in range(nelemAbnd)] #log_10 "A_12" values
logAz = [0.0 for i in range(nelemAbnd)] #N_z/H_H for element z
cname = ["" for i in range(nelemAbnd)]
logNH = [0.0 for i in range(numDeps)]
#double[][] logNz = new double[nelemAbnd][numDeps]; //N_z for element z
#logNz *normally* holds total population of that element over all ionization stages
logNz = [ [ 0.0 for i in range(numDeps) ] for j in range(nelemAbnd) ] #N_z for element z
#double[][][] masterStagePops = new double[nelemAbnd][numStages][numDeps];
masterStagePops = [ [ [ 0.0 for i in range(numDeps) ] for j in range(numStages) ] for k in range(nelemAbnd) ]

#//nome is the Kurucz code - in case it's ever useful
nome[0]=   100 
nome[1]=   200 
nome[2]=   300 
nome[3]=   400 
nome[4]=   500 
nome[5]=   600 
nome[6]=   700 
nome[7]=   800 
nome[8]=   900 
nome[9]=  1000 
nome[10]=  1100 
nome[11]=  1200 
nome[12]=  1300 
nome[13]=  1400 
nome[14]=  1500 
nome[15]=  1600 
nome[16]=  1700 
nome[17]=  1800 
nome[18]=  1900 
nome[19]=  2000 
nome[20]=  2100 
nome[21]=  2200 
nome[22]=  2300 
nome[23]=  2400 
nome[24]=  2500 
nome[25]=  2600 
nome[26]=  2700 
nome[27]=  2800 
nome[28]=  2900
nome[29]=  3000 
nome[30]=  3100 
nome[31]=  3600 
nome[32]=  3700 
nome[33]=  3800 
nome[34]=  3900 
nome[35]=  4000
nome[36]=  4100 
nome[37]=  5600 
nome[38]=  5700
nome[39]=  5500  
nome[40]=  3200  
"""
#//log_10 "A_12" values:
eheu[0]= 12.00  
eheu[1]= 10.93 
eheu[2]=  1.05
eheu[3]=  1.38  
eheu[4]=  2.70 
eheu[5]=  8.43
eheu[6]=  7.83  
eheu[7]=  8.69 
eheu[8]=  4.56
eheu[9]=  7.93  
eheu[10]=  6.24
eheu[11]=  7.60  
eheu[12]=  6.45 
eheu[13]=  7.51
eheu[14]=  5.41  
eheu[15]=  7.12 
eheu[16]=  5.50
eheu[17]=  6.40  
eheu[18]=  5.03 
eheu[19]=  6.34
eheu[20]=  3.15  
eheu[21]=  4.95 
eheu[22]=  3.93
eheu[23]=  5.64  
eheu[24]=  5.43 
eheu[25]=  7.50
eheu[26]=  4.99 
eheu[27]=  6.22
eheu[28]=  4.19  
eheu[29]=  4.56 
"""
#Reset 1st 30 element abundances to Phoenix values for 
#comparison of GAS package molecular equilibrium with PPRESS
eheu[0]= 12.00 
eheu[1]= 10.99 
eheu[2]=  1.16 
eheu[3]=  1.15
eheu[4]=  2.60 
eheu[5]=  8.55 
eheu[6]=  7.97 
eheu[7]=  8.87 
eheu[8]=  4.56 
eheu[9]=  8.08 
eheu[10]=  6.33 
eheu[11]=  7.58 
eheu[12]=  6.47 
eheu[13]=  7.55 
eheu[14]=  5.45 
eheu[15]=  7.21 
eheu[16]=  5.50 
eheu[17]=  6.52 
eheu[18]=  5.12 
eheu[19]=  6.36 
eheu[20]=  3.17 
eheu[21]=  5.02 
eheu[22]=  4.00 
eheu[23]=  5.67 
eheu[24]=  5.39 
eheu[25]=  7.50 
eheu[26]=  4.92 
eheu[27]=  6.25
eheu[28]=  4.21 
eheu[29]=  4.60
# Remainder are original CSPy values as of Jan 2020
eheu[30]=  3.04
eheu[31]=  3.25  
eheu[32]=  2.52 
eheu[33]=  2.87
eheu[34]=  2.21  
eheu[35]=  2.58 
eheu[36]=  1.46
eheu[37]=  2.18  
eheu[38]=  1.10 
eheu[39]=  1.12
eheu[40]=  3.65 #// Ge - out of sequence 

cname[0]="H";
cname[1]="He";
cname[2]="Li";
cname[3]="Be";
cname[4]="B";
cname[5]="C";
cname[6]="N";
cname[7]="O";
cname[8]="F";
cname[9]="Ne";
cname[10]="Na";
cname[11]="Mg";
cname[12]="Al";
cname[13]="Si";
cname[14]="P";
cname[15]="S";
cname[16]="Cl";
cname[17]="Ar";
cname[18]="K";
cname[19]="Ca";
cname[20]="Sc";
cname[21]="Ti";
cname[22]="V";
cname[23]="Cr";
cname[24]="Mn";
cname[25]="Fe";
cname[26]="Co";
cname[27]="Ni";
cname[28]="Cu";
cname[29]="Zn";
cname[30]="Ga";
cname[31]="Kr";
cname[32]="Rb";
cname[33]="Sr";
cname[34]="Y";
cname[35]="Zr";
cname[36]="Nb";
cname[37]="Ba";
cname[38]="La";
cname[39]="Cs";
cname[40]="Ge";



CSGsRead2.gsread(cname, eheu)


gsNspec = CSGsRead2.nspec
gsName = CSGsRead2.name
#GAS composition shoudl be corrected to CSPy values at this point:
gsComp = CSGsRead2.comp
# Number of atomic elements in GAS package:
gsNumEls = len(gsComp)

#Array of pointers FROM CSPy elements TO GAS elements
#CAUTION: elements are not contiguous in GAS' species array (are
# NOT the first gsNumEls entries!)

#Default value of -1 means CSPy element NOT in GAS package
csp2gas = [-1 for i in range(nelemAbnd)]
csp2gasIon1 = [-1 for i in range(nelemAbnd)]
csp2gasIon2 = [-1 for i in range(nelemAbnd)]

#gas2csp = [-1 for i in range(gsNspec)]

for i in range(nelemAbnd):
    for j in range(gsNspec):
        #print("i ", i, " j ", j, " cname ", cname[i], " gsName ", gsName[j]);
        #Captures neutral stages only in gsName[] 
        if (cname[i].strip() == gsName[j].strip()):
            csp2gas[i] = j
        if (cname[i].strip()+"+" == gsName[j].strip()):
            csp2gasIon1[i] = j
        if (cname[i].strip()+"++" == gsName[j].strip()):
            csp2gasIon2[i] = j          
            
#for i in range(gsNspec):
#    for j in range(nelemAbnd):
#        if (gsName[i].strip() == cname[j].strip()):
#            gas2csp[i] = j
            
#print("csp2gas ", csp2gas)
    
gsLogk = CSGsRead2.logk

gsFirstMol = -1  # index of 1st molecular species in Gas' species list
for i in range(gsNspec):
    gsFirstMol+=1
    if (gsLogk[0][i] != 0.0):
        break

# Number of molecular species in GAS package:
gsNumMols = gsNspec - gsFirstMol

# Number of ionic species in GAS package:
gsNumIons = gsNspec - gsNumEls - gsNumMols
#print("gsNspec ", gsNspec, " gsFirstMol ", gsFirstMol, " gsNumMols ", 
      #gsNumMols, " gsNumIon ", gsNumIons)

 
#//Set up for molecules with JOLA bands:
jolaTeff = 5000.0
numJola = 7 #//for now
#//int numJola = 1; //for now

jolaSpecies = ["" for i in range(numJola)]  #molecule name
jolaSystem = ["" for i in range(numJola)]   #band system
jolaDeltaLambda = [0 for i in range(numJola)]
jolaWhichF = ["" for i in range(numJola)]

if (teff <= jolaTeff):

    jolaSpecies[0] = "TiO" #// molecule name
    jolaSystem[0] = "TiO_C3Delta_X3Delta" #//band system
    jolaWhichF[0] = "Jorgensen"
    #jolaDeltaLambda[0] = 0 
    jolaSpecies[1] = "TiO" #// molecule name
    jolaSystem[1] = "TiO_c1Phi_a1Delta" #//band system 
    jolaWhichF[1] = "Jorgensen"
    #jolaDeltaLambda[1] = 1 
    jolaSpecies[2] = "TiO" #// molecule name
    jolaSystem[2] = "TiO_A3Phi_X3Delta" #//band system 
    jolaWhichF[2] = "Jorgensen"
    #jolaDeltaLambda[2] = 1 
    jolaSpecies[3] = "TiO" #// molecule name
    jolaSystem[3] = "TiO_B3Pi_X3Delta" #//band system 
    jolaWhichF[3] = "Jorgensen"
    jolaSpecies[4] = "TiO" #// molecule name
    jolaSystem[4] = "TiO_E3Pi_X3Delta" #//band system  
    jolaWhichF[4] = "Jorgensen"
    jolaSpecies[5] = "TiO" #// molecule name
    jolaSystem[5] = "TiO_b1Pi_a1Delta" #//band system 
    jolaWhichF[5] = "Jorgensen"
    jolaSpecies[6] = "TiO" #// molecule name
    jolaSystem[6] = "TiO_b1Pi_d1Sigma" #//band system
    jolaWhichF[6] = "Jorgensen"

    #"G-band" at 4300 A - MK classification diagnostic:
    #Needs Allen's approach to getting f
    #jolaSpecies[7] = "CH" #// molecule name
    #jolaSystem[7] = "CH_A2Delta_X2Pi" #//band system  
    #jolaWhichF[7] = "Allen"
        
ATot = 0.0
thisAz = 0.0 
eheuScale = 0.0

#// Set value of eheuScale for new metallicity options. 06/17 lburns
if (logHeFe != 0.0):
    eheu[1] = eheu[1] + logHeFe

if (logAlphaFe != 0.0):
    eheu[7] = eheu[7] + logAlphaFe
    eheu[9] = eheu[9] + logAlphaFe;
    eheu[11] = eheu[11] + logAlphaFe
    eheu[13] = eheu[13] + logAlphaFe
    eheu[15] = eheu[15] + logAlphaFe
    eheu[17] = eheu[17] + logAlphaFe
    eheu[19] = eheu[19] + logAlphaFe
    eheu[21] = eheu[21] + logAlphaFe
        
if (logCO > 0.0):
    eheu[5] = eheu[5] + logCO
    #//console.log("logCO " + logCO);
        
if (logCO < 0.0):
    eheu[7] = eheu[7] + math.abs(logCO)
    #//console.log("logCO " + logCO);
        
#//console.log("logCO " + logCO);



#for i in range(nelemAbnd):
#     eheuScale = eheu[i]  #//default initialization //still base 10
#     if (i > 1): #//if not H or He
#         eheuScale = eheu[i] + log10ZScale #//still base 10  
#     
#     #//logAz[i] = logE10 * (eheu[i] - 12.0); //natural log
#     logAz[i] = logE10 * (eheuScale - 12.0) #//natural log
#     thisAz = math.exp(logAz[i])
#     ATot = ATot + thisAz;
     #//System.out.println("i " + i + " logAz " + logE*logAz[i]);
     
#H and He do NOT get re-scaled with metallicity parameter:
logAz[0:2] = [ logE10 * (x - 12.0) for x in eheu[0:2] ]
#Everything else does:
logAz[2:] = [ logE10 * (x + log10ZScale - 12.0) for x in eheu[2:] ]

#print("logAz ", [logE*x for x in logAz] )

expAz = [ math.exp(x) for x in logAz ]
ATot = sum(expAz)
logATot = math.log(ATot) #//natural log

#print("logATot ", logATot)



"""//Apr 2016: Replace the following initial guesses with the following PSEUDOCODE:
   //
   // PHOENIX models at Teff0=5000 K, log(g0)=4.5, M0=0.0 (linear "zscl" = 10.0^M)
   //                   Teff0=10000 K, log(g0)=4.0, M0=0.0 (linear "zscl" = 10.0^M)
   //                   --> Tk0(tau), Pe0(tau), Pg0(tau)
   //
   //From Gray 3rd Ed. Ch.9, esp p. 189, 196
   // 1) Tk(tau)=Teff/Teff0*tk0(tau)
   // 2) Pg(tau)=(g/g0)^exp * Pg0(tau); exp = 0.64(bottom) - 0.54(top) for "cool" models
   //                                   exp = 0.85(bottom) - 0.53(top) for "hotter" models
   //    Pg(tau)= zscl^-0.333*Pg0(tau) if metals neutral - cooler models  
   //    Pg(tau)= zscl^-0.5*Pg0(tau) if metals ionized - hotter models
   //    Pg(tau) = {(1+4A_He)/(1+4A_He0)}^2/3 * Pg0(tau)  

   // 3) Pe(tau)=(g/g0)^exp * Pe0(tau); exp = 0.33(bottom) - 0.48(top) for "cool" models
   //                                   exp = 0.82(bottom) - 0.53(top) for "hotter" models
   //    Pe(tau)=exp(omega*Teff)/exp(omega*Teff0)* Pe0(tau), Teff < 10000 K
   //             - omega = 0.0015@log(tau)=1.0 & 0.0012@log(tau)=-1 to -3   
   //    Pe(tau)= zscl^+0.333*Pe0(tau) if metals neutral - cooler models  
   //    Pe(tau)= zscl^+0.5*Pe0(tau) if metals ionized - hotter models  
   //    Pe(tau) = {(1+4A_He)/(1+4A_He0)}^1/3 * Pe0(tau)"""
   


#//
#// END Initial guess for Sun section:
#//
#//Rescaled  kinetic temperature structure: 
#//double F0Vtemp = 7300.0;  // Teff of F0 V star (K) 
   
tauRos = [ [numpy.double(0.0) for i in range(numDeps)] for j in range(2) ]                         
temp = [ [numpy.double(0.0) for i in range(numDeps)] for j in range(2) ]
guessPGas = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
guessPe = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
guessNe = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
kappaRos = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
kappa500 = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
pGas = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
newPe = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
pRad = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
rho = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
newNe = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
mmw = [ numpy.double(0.0) for i in range(numDeps) ]

depths = [ 0.0 for i in range(numDeps) ]

if Input.specSynMode == True:
    
    
    #ensure self-consistency between parameters and model being read in:
    
    print(" ")
    print(" !!!!!!!!!! ALERT !!!!!!!!!!!!!!!!! ")
    print(" ")
    print("Spectrum synthesis mode - structure will NOT be re-converged")
    print(" ")
    print(" !!!!!!!!!! ALERT !!!!!!!!!!!!!!!!! ")
    print(" ")
    
    if (Restart.teffRS != teff):
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.teff = ", teff, " BUT Restart.teff =", Restart.teffRS)
        print(" ")
        print(" Calling sys.exit() ")
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ")
        sys.exit()

    if (Restart.loggRS != logg):
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.logg = ", logg, " BUT Restart.logg =", Restart.loggRS)
        print(" ")
        print(" Calling sys.exit() ")
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ") 
        sys.exit()        

    if (Restart.log10ZScaleRS != log10ZScale):
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.log10ZScale = ", log10ZScale, " BUT Restart.log10ZScale =", Restart.log10ZScaleRS)
        print(" ")
        print(" Calling sys.exit() ")
        print(" ")
        print(" !!!!!!!!!! BOOM !!!!!!!!!!!!!!!!! ")
        print(" ")  
        sys.exit()        

    if (Restart.massStarRS != massStar):
        print(" ")
        print(" !!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.massStar = ", massStar, " BUT Restart.massStar =", Restart.massStarRS)
        print(" ")
        print(" !!!!!!!!!! Warning !!!!!!!!!!!!!!!!! ")
        print(" ") 

    if (Restart.logKapFudgeRS != logKapFudge):
        print(" ")
        print(" !!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.logKapFudge = ", logKapFudge, " BUT Restart.logKapFudge =", Restart.logKapFudgeRS)
        print(" ")
        print(" !!!!!!!!!! Warning !!!!!!!!!!!!!!!!! ")
        print(" ")  

    if (Restart.logHeFeRS != logHeFe):
        print(" ")
        print(" !!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.logHeFe = ", logHeFe, " BUT Restart.logHeFe =", Restart.logHeFeRS)
        print(" ")
        print(" !!!!!!!!!! Warning !!!!!!!!!!!!!!!!! ")
        print(" ")           

    if (Restart.logCORS != logCO):
        print(" ")
        print(" !!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.logCO = ", logCO, " BUT Restart.logCO =", Restart.logCORS)
        print(" ")
        print(" !!!!!!!!!! Warning !!!!!!!!!!!!!!!!! ")
        print(" ")           

    if (Restart.logAlphaFeRS != logAlphaFe):
        print(" ")
        print(" !!!!!!!!!! WARNING !!!!!!!!!!!!!!!!! ")
        print(" ")
        print("Input.logAlphaFe = ", logAlphaFe, " BUT Restart.logAlphaFe =", Restart.logAlphaFeRS)
        print(" ")
        print(" !!!!!!!!!! Warning !!!!!!!!!!!!!!!!! ")
        print(" ") 

          
    teff = Restart.teffRS
    logg = Restart.loggRS
    log10ZScale = Restart.log10ZScaleRS
    massStar = Restart.massStarRS    
    xiT = Restart.xiTRS    
    logKapFudge = Restart.logKapFudgeRS
    logHeFe = Restart.logHeFeRS
    logCO = Restart.logCORS
    logAlphaFe = Restart.logAlphaFeRS        

    tauRos[0] = [ numpy.double(x) for x in Restart.tauRosRS[0] ]
    tauRos[1] = [ numpy.double(x) for x in Restart.tauRosRS[1] ]    
    temp[0] = [ numpy.double(x) for x in Restart.tempRS[0] ]
    temp[1] = [ numpy.double(x) for x in Restart.tempRS[1] ]
    pGas[0] = [ numpy.double(x) for x in Restart.pGasRS[0] ]
    pGas[1] = [ numpy.double(x) for x in Restart.pGasRS[1] ]
    newPe[0] = [ numpy.double(x) for x in Restart.peRS[0] ]
    newPe[1] = [ numpy.double(x) for x in Restart.peRS[1] ]
    # set up everything as in normal structure mode:
    guessPGas[0] = [ numpy.double(x) for x in Restart.pGasRS[0] ]
    guessPGas[1] = [ numpy.double(x) for x in Restart.pGasRS[1] ]
    guessPe[0] = [ numpy.double(x) for x in Restart.peRS[0] ]
    guessPe[1] = [ numpy.double(x) for x in Restart.peRS[1] ]    
    guessNe[1] = [newPe[1][iD] - temp[1][iD] - Useful.logK() for iD in range(numDeps)]
    guessNe[0] = [math.exp(guessNe[1][iD]) for iD in range(numDeps)]   
    pRad[0] = [ numpy.double(x) for x in Restart.pRadRS[0] ]
    pRad[1] = [ numpy.double(x) for x in Restart.pRadRS[1] ]
    rho[0] = [ numpy.double(x) for x in Restart.rhoRS[0] ]
    rho[1] = [ numpy.double(x) for x in Restart.rhoRS[1] ]
    kappa500[0] = [ numpy.double(x) for x in Restart.kappa500RS[0] ]
    kappa500[1] = [ numpy.double(x) for x in Restart.kappa500RS[1] ]
    kappaRos[0] = [ numpy.double(x) for x in Restart.kappaRosRS[0] ]
    kappaRos[1] = [ numpy.double(x) for x in Restart.kappaRosRS[1] ]
    mmw = [ numpy.double(x) for x in Restart.mmwRS ]
    
    #We are reading in a converged model - minimal processing:
    nOuterIter = 1
    nInnerIter = 1
    
else:
    
        
    tauRos = TauScale.tauScale(numDeps, log10MinDepth, log10MaxDepth)
    if (teff <= F0Vtemp):
        if (logg > 3.5):
            #//We're a cool dwarf! - rescale from Teff=5000 reference model!
            #print("cool star branch")
            temp = ScaleT5000.phxRefTemp(teff, numDeps, tauRos)
        else:
            #We're a cool giant - rescale from teff=4250, log(g) = 2.0 model
            temp = ScaleT4250g20.phxRefTemp(teff, numDeps, tauRos)
    elif (teff > F0Vtemp): 
        #//We're a HOT star! - rescale from Teff=10000 reference model! 
        temp = ScaleT10000.phxRefTemp(teff, numDeps, tauRos)
    
    #//Scaled from Phoenix solar model:
        

    #//double[][] guessKappa = new double[2][numDeps];
    if (teff <= F0Vtemp):
        if (logg > 3.5):
            #//We're a cool dwarf - rescale from  Teff=5000 reference model!
            #// logAz[1] = log_e(N_He/N_H)
            guessPGas = ScaleT5000.phxRefPGas(grav, zScale, logAz[1], numDeps, tauRos)
            guessPe = ScaleT5000.phxRefPe(teff, grav, numDeps, tauRos, zScale, logAz[1])
            guessNe = ScaleT5000.phxRefNe(numDeps, temp, guessPe) 
            #//Ne = ScaleSolar.phxSunNe(grav, numDeps, tauRos, temp, kappaScale);
            #//guessKappa = ScaleSolar.phxSunKappa(numDeps, tauRos, kappaScale);
        else:
            #We're a cool giant - rescale from teff=4250, log(g) = 2.0 model
            guessPGas = ScaleT4250g20.phxRefPGas(grav, zScale, logAz[1], numDeps, tauRos)
            guessPe = ScaleT4250g20.phxRefPe(teff, grav, numDeps, tauRos, zScale, logAz[1])
            guessNe = ScaleT4250g20.phxRefNe(numDeps, temp, guessPe)                 
    elif (teff > F0Vtemp):
        #//We're a HOT star!! - rescale from Teff=10000 reference model 
        #// logAz[1] = log_e(N_He/N_H)
        guessPGas = ScaleT10000.phxRefPGas(grav, zScale, logAz[1], numDeps, tauRos)
        guessPe = ScaleT10000.phxRefPe(teff, grav, numDeps, tauRos, zScale, logAz[1])
        guessNe = ScaleT10000.phxRefNe(numDeps, temp, guessPe)
        #//logKapFudge = -1.5;  //sigh - don't ask me - makes the Balmer lines show up around A0 

##In every case - initialization:        
#newNe[0] = [ guessNe[0][i] for i in range(numDeps)]
#newNe[1] = [ guessNe[1][i] for i in range(numDeps)]
    
    
    
#//Now do the same for the Sun, for reference:
tempSun = ScaleSolar.phxSunTemp(teffSun, numDeps, tauRos)
#//Now do the same for the Sun, for reference:
pGasSunGuess = ScaleSolar.phxSunPGas(gravSun, numDeps, tauRos)
NeSun = ScaleSolar.phxSunNe(gravSun, numDeps, tauRos, tempSun, zScaleSun)
kappaSun = ScaleSolar.phxSunKappa(numDeps, tauRos, zScaleSun)
mmwSun = State.mmwFn(numDeps, tempSun, zScaleSun)
rhoSun = State.massDensity(numDeps, tempSun, pGasSunGuess, mmwSun, zScaleSun)
pGasSun = Hydrostat.hydroFormalSoln(numDeps, gravSun, tauRos, kappaSun, tempSun, pGasSunGuess)

#Total population of element over all ionization stages:
logNz = State.getNz(numDeps, temp, guessPGas, guessPe, ATot, nelemAbnd, logAz)
#for i in range(numDeps): 
#    logNH[i] = logNz[0][i]
##//set the initial guess H^+ number density to the e^-1 number density
#    masterStagePops[0][1][i] = guessPe[1][i] #//iElem = 0: H; iStage = 1: II
    #//System.out.println("i " + i + " logNH[i] " + logE*logNH[i]);
logNH = [ x for x in logNz[0] ]
masterStagePops[0][1] = [ numpy.double(x) for x in guessPe[1] ]
    
#//Load the total no. density of each element into the nuetral stage slots of the masterStagePops array as a first guess at "species B" neutral
#//populations for the molecular Saha eq. - Reasonable first guess at low temp where molecuales form

#for iElem in range(nelemAbnd):
#    for iD in range(numDeps):
#        masterStagePops[iElem][0][iD] = logNz[iElem][iD]

#Initial default - set neutral stage population to total number density of that element:     
masterStagePops[:][0][:] = [ [ logNz[i][j] for j in range(numDeps) ] for i in range(nelemAbnd) ]



warning = "";
if (teff < F0Vtemp):
    #//warning = "<span style='color:red'><em>T</em><sub>eff</sub> < 6000 K <br />Cool star mode";
    warning = "Cool star mode"
    print(warning)
else:
    #//warning = "<span style='color:blue'><em>T</em><sub>eff</sub> > 6000 K <br />Hot star mode</span>";
    warning = "Hot star mode"
    print(warning)
    
#//Add subclass to each spectral class (lburns)
spectralClass = " "
subClass = " " #//Create a variable for the subclass of the star. lburns
luminClass = "V" #//defaults to V
#//Determine the spectralClass and subClass of main sequence stars, subdwarfs and white dwarfs
#//var luminClass = "V" or luminClass = "VI" or luminClass = "WD"
#// Based on the data in Appendix G of An Introduction to Modern Astrophysics, 2nd Ed. by
#// Carroll & Ostlie
if ((logg >= 4.0) and (logg <= 6.0)):
    if (teff < 3000.0):
        spectralClass = "L";
    elif ((teff >= 3000.0) and (teff < 3900.0)):
        spectralClass = "M";
        if ((teff >= 3000.0) and (teff <= 3030.0)):
            subClass = "6";
        elif ((teff > 3030.0) and (teff <= 3170.0)):
            subClass = "5";
        elif ((teff > 3170.0) and (teff <= 3290.0)):
            subClass = "4";
        elif ((teff > 3290.0) and (teff <= 3400.0)):
            subClass = "3";
        elif ((teff > 3400.0) and (teff <= 3520.0)):
            subClass = "2";
        elif ((teff > 3520.0) and (teff <= 3660.0)):
            subClass = "1";
        elif ((teff > 3660.0) and (teff < 3900.0)):
            subClass = "0";
        
    elif ((teff >= 3900.0) and (teff < 5200.0)):
        spectralClass = "K";
        if ((teff >= 3900.0) and (teff <= 4150.0)):
            subClass = "7";
        elif ((teff > 4150.0) and (teff <= 4410.0)):
            subClass = "5";
        elif ((teff > 4410.0) and (teff <= 4540.0)):
            subClass = "4";
        elif ((teff > 4540.0) and (teff <= 4690.0)):
            subClass = "3";
        elif ((teff > 4690.0) and (teff <= 4990.0)):
            subClass = "1";
        elif ((teff > 4990.0) and (teff < 5200.0)):
            subClass = "0";
        
    elif ((teff >= 5200.0) and (teff < 5950.0)):
        spectralClass = "G";
        if ((teff >= 5200.0) and (teff <= 5310.0)):
            subClass = "8";
        elif ((teff > 5310.0) and (teff <= 5790.0)):
            subClass = "2";
        elif ((teff > 5790.0) and (teff < 5950.0)):
            subClass = "0";
        
    elif ((teff >= 5950.0) and (teff < 7300.0)):
        spectralClass = "F";
        if ((teff >= 5950.0) and (teff <= 6250.0)):
            subClass = "8";
        elif ((teff > 6250.0) and (teff <= 6650.0)):
            subClass = "5";
        elif ((teff > 6650.0) and (teff <= 7050.0)):
            subClass = "2";
        elif ((teff > 7050.0) and (teff < 7300.0)):
            subClass = "0";
        
    elif ((teff >= 7300.0) and (teff < 9800.0)):
        spectralClass = "A";
        if ((teff >= 7300.0) and (teff <= 7600.0)):
            subClass = "8";
        elif ((teff > 7600.0) and (teff <= 8190.0)):
            subClass = "5";
        elif ((teff > 8190.0) and (teff <= 9020.0)):
            subClass = "2";
        elif ((teff > 9020.0) and (teff <= 9400.0)):
            subClass = "1";
        elif ((teff > 9400.0) and (teff < 9800.0)):
            subClass = "0";
        
    elif ((teff >= 9800.0) and (teff < 30000.0)):
        spectralClass = "B";
        if ((teff >= 9300.0) and (teff <= 10500.0)):
            subClass = "9";
        elif ((teff > 10500.0) and (teff <= 11400.0)):
            subClass = "8";
        elif ((teff > 11400.0) and (teff <= 12500.0)):
            subClass = "7";
        elif ((teff > 12500.0) and (teff <= 13700.0)):
            subClass = "6";
        elif ((teff > 13700.0) and (teff <= 15200.0)):
            subClass = "5";
        elif ((teff > 15200.0) and (teff <= 18800.0)):
            subClass = "3";
        elif ((teff > 18800.0) and (teff <= 20900.0)):
            subClass = "2";
        elif ((teff > 20900.0) and (teff <= 25400.0)):
            subClass = "1";
        elif ((teff > 25400.0) and (teff < 30000.0)):
            subClass = "0";
        
    elif (teff >= 30000.0):
        spectralClass = "O";
        if ((teff >= 30000.0) and (teff <= 35800.0)):
            subClass = "8";
        elif ((teff > 35800.0) and (teff <= 37500.0)):
            subClass = "7";
        elif ((teff > 37500.0) and (teff <= 39500.0)):
            subClass = "6";
        elif ((teff > 39500.0) and (teff <= 42000.0)):
            subClass = "5";
        
    

#//Determine the spectralClass and subClass of giants and subgiants. lburns
#//var luminClass = "III" or luminClass = "IV"
#//Determine the spectralClass and subClass of giants and subgiants. lburns
#//var luminClass = "III" or luminClass = "IV"
if ((logg >= 1.5) and (logg < 4.0)):
    if (teff < 3000.0):
        spectralClass = "L";
    elif ((teff >= 3000.0) and (teff < 3700.0)):
        spectralClass = "M";
        if ((teff >= 3000.0) and (teff <= 3330.0)):
            subClass = "6";
        elif ((teff > 3330.0) and (teff <= 3380.0)):
            subclass = "5";
        elif ((teff > 3380.0) and (teff <= 3440.0)):
            subClass = "4";
        elif ((teff > 3440.0) and (teff <= 3480.0)):
            subClass = "3";
        elif ((teff > 3480.0) and (teff <= 3540.0)):
            subClass = "2";
        elif ((teff > 3540.0) and (teff <= 3600.0)):
            subClass = "1";
        elif ((teff > 3600.0) and (teff < 3700.0)):
            subClass = "0";
        
    elif ((teff >= 3700.0) and (teff < 4700.0)):
        spectralClass = "K"
        if ((teff >= 3700.0) and (teff <= 3870.0)):
            subClass = "7";
        elif ((teff > 3870.0) and (teff <= 4050.0)):
            subClass = "5";
        elif ((teff > 4050.0) and (teff <= 4150.0)):
            subClass = "4";
        elif ((teff > 4150.0) and (teff <= 4260.0)):
            subClass = "3";
        elif ((teff > 4260.0) and (teff <= 4510.0)):
            subClass = "1";
        elif ((teff > 4510.0) and (teff < 4700.0)):
            subClass = "0";
        
    elif ((teff >= 4700.0) and (teff < 5500.0)):
        spectralClass = "G";
        if ((teff >= 4700.0) and (teff <= 4800.0)):
            subClass = "8";
        elif ((teff > 4800.0) and (teff <= 5300.0)):
            subClass = "2";
        elif ((teff > 5300.0) and (teff < 5500.0)):
            subClass = "0";
        
    elif ((teff >= 5500.0) and (teff < 7500.0)):
        spectralClass = "F";
        if ((teff >= 5500.0) and (teff <= 6410.0)):
            subClass = "5";
        elif ((teff > 6410.0) and (teff <= 7000.0)):
            subClass = "2";
        elif ((teff > 7000.0) and (teff < 7500.0)):
            subClass = "0";
        
    elif ((teff >= 7500.0) and (teff < 10300.0)):
        spectralClass = "A";
        if ((teff >= 7500.0) and (teff <= 7830.0)):
            subClass = "8";
        elif ((teff > 7830.0) and (teff <= 8550.0)):
            subClass = "5";
        elif ((teff > 8550.0) and (teff <= 9460.0)):
            subClass = "2";
        elif ((teff > 9460.0) and (teff <= 9820.0)):
            subClass = "1";
        elif ((teff > 9820.0) and (teff < 10300.0)):
            subClass = "0";
        
    elif ((teff >= 10300.0) and (teff < 29300.0)):
        spectralClass = "B";
        if ((teff >= 10300.0) and (teff <= 10900.0)):
            subClass = "9";
        elif ((teff > 10900.0) and (teff <= 11700.0)):
            subClass = "8";
        elif ((teff > 11700.0) and (teff <= 12700.0)):
            subClass = "7";
        elif ((teff > 12700.0) and (teff <= 13800.0)):
            subClass = "6";
        elif ((teff > 13800.0) and (teff <= 15100.0)):
            subClass = "5";
        elif ((teff > 15100.0) and (teff <= 18300.0)):
            subClass = "3";
        elif ((teff > 18300.0) and (teff <= 20200.0)):
            subClass = "2";
        elif ((teff > 20200.0) and (teff <= 24500.0)):
            subClass = "1";
        elif ((teff > 24500.0) and (teff < 29300.0)):
            subClass = "0";
        
    elif ((teff >= 29300.0) and (teff < 40000.0)):
        spectralClass = "O";
        if ((teff >= 29300.0) and (teff <= 35000.0)):
            subClass = "8";
        elif ((teff > 35000.0) and (teff <= 36500.0)):
            subClass = "7";
        elif ((teff > 36500.0) and (teff <= 37800.0)):
            subClass = "6";
        elif ((teff > 37800.0) and (teff < 40000.0)):
            subClass = "5";
        
    


#//Determine the spectralClass and subClass of supergiants and bright giants. lburns
#//var luminClass = "I" or luminClass = "II"
if ((logg >= 0.0) and (logg < 1.5)):
    if (teff < 2700.0):
        spectralClass = "L";
    elif ((teff >= 2700.0) and (teff < 3650.0)):
        spectralClass = "M";
        if ((teff >= 2700.0) and (teff <= 2710.0)):
            subClass = "6";
        elif ((teff > 2710.0) and (teff <= 2880.0)):
            subClass = "5";
        elif ((teff > 2880.0) and (teff <= 3060.0)):
            subClass = "4";
        elif ((teff > 3060.0) and (teff <= 3210.0)):
            subClass = "3";
        elif ((teff > 3210.0) and (teff <= 3370.0)):
            subClass = "2";
        elif ((teff > 3370.0) and (teff <= 3490.0)):
            subClass = "1";
        elif ((teff > 3490.0) and (teff < 3650.0)):
            subClass = "0";
        
    elif ((teff >= 3650.0) and (teff < 4600.0)):
        spectralClass = "K";
        if ((teff >= 3650.0) and (teff <= 3830.0)):
            subClass = "7";
        elif ((teff > 3830.0) and (teff <= 3990.0)):
            subClass = "5";
        elif ((teff > 3990.0) and (teff <= 4090.0)):
            subClass = "4";
        elif ((teff > 4090.0) and (teff <= 4190.0)):
            subClass = "3";
        elif ((teff > 4190.0) and (teff <= 4430.0)):
            subClass = "1";
        elif ((teff > 4430.0) and (teff < 4600.0)):
            subClass = "0";
        
    elif ((teff >= 4600.0) and (teff < 5500.0)):
        spectralClass = "G";
        if ((teff >= 4600.0) and (teff <= 4700.0)):
            subClass = "8";
        elif ((teff > 4700.0) and (teff <= 5190.0)):
            subClass = "2";
        elif ((teff > 5190.0) and (teff < 5500.0)):
            subClass = "0";
        
    elif ((teff >= 5500.0) and (teff < 7500.0)):
        spectralClass = "F";
        if ((teff >= 5500.0) and (teff <= 5750.0)):
            subClass = "8";
        elif ((teff > 5750.0) and (teff <= 6370.0)):
            subClass = "5";
        elif ((teff > 6370.0) and (teff <= 7030.0)):
            subClass = "2";
        elif ((teff > 7030.0) and (teff < 7500.0)):
            subClass = "0";
        
    elif ((teff >= 7500.0) and (teff < 10000.0)):
        spectralClass = "A";
        if ((teff >= 7500.0) and (teff <= 7910.0)):
            subClass = "8";
        elif ((teff > 7910.0) and (teff <= 8610.0)):
            subClass = "5";
        elif ((teff > 8610.0) and (teff <= 9380.0)):
            subClass = "2";
        elif ((teff > 9380.0) and (teff < 10000.0)):
            subClass = "0";
        
    elif ((teff >= 10000.0) and (teff < 27000.0)):
        spectralClass = "B";
        if ((teff >= 10000.0) and (teff <= 10500.0)):
            subClass = "9";
        elif ((teff > 10500.0) and (teff <= 11100.0)):
            subClass = "8";
        elif ((teff > 11100.0) and (teff <= 11800.0)):
            subClass = "7";
        elif ((teff > 11800.0) and (teff <= 12600.0)):
            subClass = "6";
        elif ((teff > 12600.0) and (teff <= 13600.0)):
            subClass = "5";
        elif ((teff > 13600.0) and (teff <= 16000.0)):
            subClass = "3";
        elif ((teff > 16000.0) and (teff <= 17600.0)):
            subClass = "2";
        elif ((teff > 17600.0) and (teff <= 21400.0)):
            subClass = "1";
        elif ((teff > 21400.0) and (teff < 27000.0)):
            subClass = "0";
        
    elif ((teff >= 27000.0) and (teff < 42000.0)):
        spectralClass = "O";
        if ((teff >= 27000.0) and (teff <= 34000.0)):
            subClass = "8";
        elif ((teff > 34000.0) and (teff <= 36200.0)):
            subClass = "7";
        elif ((teff > 36200.0) and (teff <= 38500.0)):
            subClass = "6";
        elif ((teff > 38500.0) and (teff < 42000.0)):
            subClass = "5";
        
    


#//Determine luminClass based on logg
if ((logg >= 0.5) and (logg < 1.0)):
    luminClass = "I";
elif ((logg >= 1.0) and (logg < 1.5)):
    luminClass = "II";
elif ((logg >= 1.5) and (logg < 3.0)):
    luminClass = "III";
elif ((logg >= 3.0) and (logg < 4.0)):
    luminClass = "IV";
elif ((logg >= 4.0) and (logg < 5.0)):
    luminClass = "V";
elif ((logg >= 5.0) and (logg < 6.0)):
    luminClass = "VI";
elif ((logg >= 5.0)):
    luminClass = "WD";
    

spectralType = spectralClass + subClass + " " + luminClass
print("Spectral type: ", spectralType)      
#Initial guess atmospheric structure output: 
#Convert everything to log_10 OR re-scaled units for plotting, printing, etc:
    
log10e = math.log10(math.e)


#
#
#// END initial guess for Sun section
#
#
###################################################################
#
#
#
#   Converge atmospheric structure 
#
#    - Includes *initial* ionization equilibrium *without* molecules (for now)
#
#
#
###################################################################


#log10mmw = [0.0 for i in range(numDeps)]
#//
#// *********************
#//Jul 2016: Replace the following procedure for model building with the following PSEUDOCODE:
#//
#// 1st guess Tk(tau), Pe(tau), Pg(tau) from rescaling reference hot or cool model above
#// 1) Converge Pg-Pe relation for Az abundance distribution and  T_Kin(Tau)
#//   assuming all free e^-s from single ionizations - *inner* convergence
#// 2) Get Ne, rho, mu from Phil Bennet's GAS apckage
#// 3) kappa(tau) from Gray Ch. 8 sources - H, He, and e^- oapcity sources only
#// 4) P_Tot(tau) from HSE on tau scale with kappa from 4)
#//    - PRad(tau) from Tk(tau)
#//    - New Pg(tau) from P_Tot(tau)-PRad(tau)
#// 5) Iterate Pg - kappa relation to convergence - *outer* convergence
#// 6)Get rho(tau) = Sigma_z(m_z*N_z(tau)) and mu(tau) = rho(tau) / N(tau)
#//   and depth scale
#//
#//  ** Atmospheric structure converged **
#//
#// THEN for spectrum synthesis:
#//
#// 1) number densities of absorpbers from partial pressures (pps) from Phil
#  Bennett's GAS package)
#// 2) Temp correction??   


#/    **** STOP ****  No - do we *really* need N_HI, ... for kappa if we use rho in HSE? - Yes - needed even if kappa
#//    is in cm^-1 instead of cm^2/g - sigh

species = " "  #; //default initialization
#  double rho[][] = new double[2][numDeps];
#  double[][] tauOneStagePops = new double[nelemAbnd][numStages];

tauOneStagePops = [ [ numpy.double(0.0) for i in range(numStages) ] for j in range(nelemAbnd) ]
unity = numpy.double(1.0)
zScaleList = 1.0 #//initialization   

numAtmPrtTmps = 5
numMolPrtTmps = 5
#  double[][] log10UwAArr = new double[numStages][2];
log10UwAArr = [ [ 0.0 for k in range(numAtmPrtTmps) ] for j in range(numStages) ] 
#for i in range(numStages):
#    for k in range(len(log10UwAArr[0])):
#        log10UwAArr[i][k] = 0.0 #//lburns default initialization - logarithmic
  
 
#//Ground state ionization E - Stage I (eV) 
#  double[] chiIArr = new double[numStages]
chiIArr = [ 999999.0 for i in range(numStages) ]
#// //Ground state ionization E - Stage II (eV)
#//
""" now GAS
#//For diatomic molecules:
speciesAB = " "
speciesA = " "
speciesB = " "
# double massA, massB, logMuAB;
"""
# double[][] masterMolPops = new double[nMols][numDeps];
#masterMolPops = [ [ -49.0 for i in range(numDeps) ] for j in range(nMols) ]
#Now with GAS:


#//initialize masterMolPops for mass density (rho) calculation:
masterMolPops = [ [ logTiny for i in range(numDeps) ] for j in range(gsNumMols) ]
for i in range(gsNumMols):
    for j in range(numDeps):
        masterMolPops[i][j] = -49.0  #//these are logarithmic
    
  
Ng = [ numpy.double(0.0) for i in range(numDeps) ]

  #double logMmw;
logKappa = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(numLams) ]
logKappaHHe = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(numLams) ]
logKappaMetalBF = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(numLams) ]
logKappaRayl = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(numLams) ]

newTemp = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]


#//
#//
#//We converge the Pgas - Pe relation first under the assumption that all free e^-s are from single ionizations
#// a la David Gray Ch. 9.  
#// This approach separates converging ionization fractions and Ne for spectrum synthesis purposes from
#// converging the Pgas-Pe-N_H-N_He relation for computing the mean opacity for HSE
#//
thisTemp = [ 0.0 for i in range(2) ]
log10UwUArr = [ 0.0 for i in range(numAtmPrtTmps) ]
log10UwLArr = [ 0.0 for i in range(numAtmPrtTmps) ]
#double chiI, peNumerator, peDenominator, logPhi, logPhiOverPe, logOnePlusPhiOverPe, logPeNumerTerm, logPeDenomTerm;

log300 = math.log(300.0)
log2 = math.log(2.0)

#GAS package parameters:
isolv = 1
tol = 1.0e-2
maxit = 10

#GAS package interface variables:
gsP0 = [0.0e0 for i in range(40)]
topP0 = [0.0e0 for i in range(40)]
gsPp = [0.0e0 for i in range(150)]
#For reporting purposes only:
log10MasterGsPp = [ [logTiny for iD in range(numDeps)] for iSpec in range(gsNspec) ]
#ppix = [0.0e0 for i in range(30)]
#a = [0.0e0 for i in range(625)]

#//Begin Pgas-kapp iteration

#Test: 
GAStemp = 6000.0
#GAStemp = 100000.0

for pIter in range(nOuterIter):
#//

    #Try making return value a tuple:

    
        
    if (teff <= GAStemp):
    #if (teff <= 100000.0):   #test        
        
        for iD in range(numDeps):

            #print("isolv ", isolv, " temp ", temp[0][iD], " guessPGas ", guessPGas[0][iD])
            gasestReturn = CSGasEst.gasest(isolv, temp[0][iD], guessPGas[0][iD])
            gsPe0 = gasestReturn[0]
            gsP0 = gasestReturn[1]
            neq = gasestReturn[2]
        
            if (iD == 1):
                topP0 = [ (0.5 * gsP0[iSpec]) for iSpec in range(40) ]    
                
            #Upper boundary causes problems:
            if (pIter > 0 and iD == 0):
                gsPe0 = 0.5 * newPe[0][1]
                gsP0 = [ topP0[iSpec] for iSpec in range(40) ] 
                
            
            #print("Calling GAS 1 iD ", iD, " temp ", temp[0][iD])
            #print("iD ", iD, " gsPe0 ", gsPe0, " gsP0[0] ", gsP0[0], " neq ", neq)

            
            gasReturn = CSGas.gas(isolv, temp[0][iD], guessPGas[0][iD], gsPe0, gsP0, neq, tol, maxit)
            #a = gasReturn[0]
            #nit = gasReturn[1]
            gsPe = gasReturn[2]
            #pd = gasReturn[3]
            gsPp = gasReturn[4]
            #Can't pythonize this - gsPp padded at end with 0.0s
            #log10MasterGsPp[:][iD] = [math.log10(x) for x in gsPp]
            #for iSpec in range(gsNspec):
            #    log10MasterGsPp[iSpec][iD] = math.log10(gsPp[iSpec])
            #print("1: ", gsPp[0]/guessPGas[0][iD])
            #ppix = gasReturn[5]
            gsMu = gasReturn[6]
            gsRho = gasReturn[7]
        
            #print("iD ", iD, " gsPe ", gsPe, " gsPp[0] ", gsPp[0], " gsMu ", gsMu, " gsRho ", gsRho)
        
            newPe[0][iD] = gsPe
            newPe[1][iD] = math.log(gsPe)
            newNe[0][iD] = gsPe / Useful.k() / temp[0][iD]
            newNe[1][iD] = math.log(newNe[0][iD])
            guessPe[0][iD] = newPe[0][iD]
            guessPe[1][iD] = newPe[1][iD]
            guessNe[0][iD] = newNe[0][iD]
            guessNe[1][iD] = newNe[1][iD]        
        
            rho[0][iD] = gsRho
            rho[1][iD] = math.log(gsRho)
            mmw[iD] = gsMu * Useful.amu()
            
                    #Take neutral stage populations for atomic species from GAS: 
            for iElem in range(nelemAbnd):
            
                if (csp2gas[iElem] != -1):
                    #element is in GAS package:  
                    #Neutral stage onnly:
                    thisN = gsPp[csp2gas[iElem]] / Useful.k() / temp[0][iD]    
                    masterStagePops[iElem][0][iD] = math.log(thisN)
            
            #print("iD ", iD, cname[19], gsName[csp2gas[19]], " logNCaI ", logE*masterStagePops[19][0][iD])
            
            for i in range(gsNumMols):
                thisN = gsPp[i+gsFirstMol] / Useful.k() / temp[0][iD]
                masterMolPops[i][iD] = math.log(thisN)
        
            #Needed  now GAS??  
            for iA in range(nelemAbnd):
                if (csp2gas[iA] != -1):
                    #element is in GAS package:  
                    #Captures neutral stage only
                    logNz[iA][iD] = math.log10(gsPp[csp2gas[iA]]) - Useful.logK() - temp[1][iD]
                    
        for iElem in range(26):
            species = cname[iElem] + "I"
            chiIArr[0] = IonizationEnergy.getIonE(species)
            #//THe following is a 2-element vector of temperature-dependent partitio fns, U, 
            #// that are base e log_e U
            log10UwAArr[0] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "II"
            chiIArr[1] = IonizationEnergy.getIonE(species)
            log10UwAArr[1] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "III"
            chiIArr[2] = IonizationEnergy.getIonE(species)
            log10UwAArr[2] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "IV"
            chiIArr[3] = IonizationEnergy.getIonE(species)
            log10UwAArr[3] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "V"
            chiIArr[4] = IonizationEnergy.getIonE(species)
            log10UwAArr[4] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "VI"
            chiIArr[5] = IonizationEnergy.getIonE(species)
            log10UwAArr[5] = PartitionFn.getPartFn2(species) #//base e log_e U
            #//double logN = (eheu[iElem] - 12.0) + logNH;


        
            #Neeed?  Now GAS:
            logNums = LevelPopsGasServer.stagePops3(masterStagePops[iElem][0], guessNe, chiIArr, log10UwAArr,   \
                                #thisNumMols, logNumBArr, dissEArr, log10UwBArr, logQwABArr, logMuABArr, \
                                numDeps, temp)

        #for iStage in range(numStages):
        #    for iTau in range(numDeps):
        #
        #        masterStagePops[iElem][iStage][iTau] = logNums[iStage][iTau]
        #masterStagePops[iElem][:][:] = [ [logNums[iStage][iTau] for iTau in range(numDeps)] for iStage in range(numStages) ]
        
            masterStagePops[iElem][:] = [x for x in logNums[:]]                    
        
        
            
    if (teff > GAStemp):  #teff > FoVtemp:
            
            #//  Converge Pg-Pe relation starting from intital guesses at Pg and Pe
            #//  - assumes all free electrons are from single ionizations
            #//  - David Gray 3rd Ed. Eq. 9.8:
        #print("guessPe[1] ", [logE*x for x in guessPe[1]] )
        for neIter in range(nInnerIter):
            
            for iD in range(numDeps):
                #//System.out.println("iD    logE*newPe[1][iD]     logE*guessPe[1]     logE*guessPGas[1]");
        
                #//re-initialize accumulators:
                thisTemp[0] = temp[0][iD]
                thisTemp[1] = temp[1][iD]
                peNumerator = 0.0 
                peDenominator = 0.0
                for iElem in range(nelemAbnd):
                    species = cname[iElem] + "I"
                    chiI = IonizationEnergy.getIonE(species)
                    #//THe following is a 2-element vector of temperature-dependent partitio fns, U, 
                #// that are base e log_e U
                    log10UwLArr = PartitionFn.getPartFn2(species) #//base e log_e U
                    species = cname[iElem] + "II"
                    log10UwUArr = PartitionFn.getPartFn2(species) #//base e log_e U
                    logPhi = LevelPopsGasServer.sahaRHS(chiI, log10UwUArr, log10UwLArr, thisTemp)
                    #if (iD%10 == 0):
                    #    print("iD ", iD, " iElem ", iElem, " logPhi ", logE*logPhi)
                    logPhiOverPe = logPhi - guessPe[1][iD]
                    logOnePlusPhiOverPe = math.log(1.0 + math.exp(logPhiOverPe)) 
                    logPeNumerTerm = logAz[iElem] + logPhiOverPe - logOnePlusPhiOverPe
                    peNumerator = peNumerator + math.exp(logPeNumerTerm)
                    logPeDenomTerm = logAz[iElem] + math.log(1.0 + math.exp(logPeNumerTerm))
                    peDenominator = peDenominator + math.exp(logPeDenomTerm)
                    #if (iD%10 == 0):
                    #    print("iD ", iD, " iElem ", iElem, " peNum ", peNumerator, " peDen ", peDenominator)                    
                #print("peNum ", math.log10(peNumerator), " peDen ", math.log10(peDenominator))
                #//iElem chemical element loop
                newPe[1][iD] = guessPGas[1][iD] + math.log(peNumerator) - math.log(peDenominator) 
                newPe[0][iD] = math.exp(newPe[1][iD])
                guessPe[1][iD] = newPe[1][iD]
                guessPe[0][iD] = math.exp(guessPe[1][iD])
            
        newNe[1] = [newPe[1][iD] - temp[1][iD] - Useful.logK() for iD in range(numDeps)]
        newNe[0] = [math.exp(newNe[1][iD]) for iD in range(numDeps)]   
        #guessNe[1][:] = [newNe[1][iD] for iD in range(numDeps)]
        #guessNe[0][:] = [newNe[0][iD] for iD in range(numDeps)]
        guessNe[1][:] = [ x for x in newNe[1][:] ]
        guessNe[0][:] = [ x for x in newNe[0][:] ]

        #print("newPe ", [logE*x for x in newPe[1]])
        #print("guessNe ", [logE*x for x in guessNe[1]])       
        #print("iD ", iD, " logT ", logE*temp[1][iD], " logNe ", logE*newNe[1][iD], " logRho ", logE*rho[1][iD], " mmw ", logE*math.log(mmw[iD]*Useful.amu()) )
        
    #if (teff > 100000.0):     #test
        
        logNz = State.getNz(numDeps, temp, guessPGas, guessPe, ATot, nelemAbnd, logAz)
    #for i in range(numDeps): 
    #    logNH[i] = logNz[0][i]
    #logNH[:] = [ logNz[0][i] for i in range(numDeps) ]
        logNH = [ x for x in logNz[0] ]
        
        zScaleList = 1.0 #//initialization   
        
        for iElem in range(26):
            species = cname[iElem] + "I"
            chiIArr[0] = IonizationEnergy.getIonE(species)
                #//THe following is a 2-element vector of temperature-dependent partitio fns, U, 
            #// that are base e log_e U
            log10UwAArr[0] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "II"
            chiIArr[1] = IonizationEnergy.getIonE(species)
            log10UwAArr[1] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "III"
            chiIArr[2] = IonizationEnergy.getIonE(species)
            log10UwAArr[2] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "IV"
            chiIArr[3] = IonizationEnergy.getIonE(species)
            log10UwAArr[3] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "V"
            chiIArr[4] = IonizationEnergy.getIonE(species)
            log10UwAArr[4] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "VI"
            chiIArr[5] = IonizationEnergy.getIonE(species)
            log10UwAArr[5] = PartitionFn.getPartFn2(species) #//base e log_e U
            
            logNums = LevelPopsGasServer.stagePops(logNz[iElem], guessNe, chiIArr, log10UwAArr,\
                     numDeps, temp)

            #for iStage in range(numStages):
            #    for iTau in range(numDeps):
            #
            #        masterStagePops[iElem][iStage][iTau] = logNums[iStage][iTau]
            #masterStagePops[iElem][:][:] = [ [logNums[iStage][iTau] for iTau in range(numDeps)] for iStage in range(numStages) ]
            masterStagePops[iElem][:] = [x for x in logNums[:]]
            
        #print("logNz[0] ", [logE*x for x in logNz[0]])
        #print("masterStagePops[0][0] ", [logE*x for x in masterStagePops[0][0]])            
    
            
        #//double logN = (eheu[iElem] - 12.0) + logNH;
        
            #//Get mass density from chemical composition: 
        rho = State.massDensity2(numDeps, nelemAbnd, logNz, cname)

        #//Total number density of gas particles: nuclear species + free electrons:
        #//AND
        # //Compute mean molecular weight, mmw ("mu"):
        #for i in range(numDeps):
        #    Ng[i] = newNe[0][i] #//initialize accumulation with Ne 
        #Ng[:] = [ newNe[0][i] for i in range(numDeps) ]
        Ng[:] = [ x for x in newNe[0] ]
    
        #Seems like this can't be "de-looped" without resorting to cryptic black boxes in python, like zip()
        for i in range(numDeps):
            for j in range(nelemAbnd):
                Ng[i] =  Ng[i] + math.exp(logNz[j][i]) #//initialize accumulation 
      
        #logMmw = rho[1][i] - math.log(Ng[i]) # // in g
        #mmw[i] = math.exp(logMmw) 
    
        mmw = [ rho[1][i] - math.log(Ng[i]) for i in range(numDeps) ]
        mmw = [ math.exp(x) for x in mmw ]

    
#//
#//Refine the number densities of the chemical elements at all depths  
    #logNz = State.getNz(numDeps, temp, guessPGas, guessPe, ATot, nelemAbnd, logAz)
    #for i in range(numDeps): 
    #    logNH[i] = logNz[0][i]
    #logNH[:] = [ logNz[0][i] for i in range(numDeps) ]
    
    
    #Needed now GAS??
    #logNH = [ x for x in logNz[0] ]
        #//System.out.println("i " + i + " logNH[i] " + logE*logNH[i]); 

#//
#//  Compute ionization fractions of H & He for kappa calculation 
#//
#//  Default inializations:

    #//these 2-element temperature-dependent partition fns are logarithmic  


#//
#////H & He only for now... we only compute H, He, and e^- opacity sources: 
#   //for (int iElem = 0; iElem < 2; iElem++){
#//H to Fe only for now... we only compute opacity sources for elements up to Fe: 
    

        
    #for iD in range(numDeps):
        #print("CSGPy: iD ", iD, cname[0], " logNCaI ", logE*masterStagePops[0][0][iD])
        #print("Ne ", newPe[0][iD], " logNe ", newPe[1][iD])      
            
                #//save ion stage populations at tau = 1:
            #//iTau loop
        #//iStage loop
    #//iElem loop

    #//Get mass density from chemical composition: 
#Needed?  Now Gas package
    #rho = State.massDensity2(numDeps, nelemAbnd, logNz, cname)

#Needed?  Now Gas package
#//Total number density of gas particles: nuclear species + free electrons:
#//AND
# //Compute mean molecular weight, mmw ("mu"):
    #for i in range(numDeps):
    #    Ng[i] = newNe[0][i] #//initialize accumulation with Ne 
    #Ng[:] = [ newNe[0][i] for i in range(numDeps) ]
    #Ng[:] = [ x for x in newNe[0] ]
    
    #Seems like this can't be "de-looped" without resorting to cryptic black boxes in python, like zip()
    #for i in range(numDeps):
    #    for j in range(nelemAbnd):
    #        Ng[i] =  Ng[i] + math.exp(logNz[j][i]) #//initialize accumulation 
      
        #logMmw = rho[1][i] - math.log(Ng[i]) # // in g
        #mmw[i] = math.exp(logMmw) 
    
    #mmw = [ rho[1][i] - math.log(Ng[i]) for i in range(numDeps) ]
    #mmw = [ math.exp(x) for x in mmw ]

    

#//H & He only for now... we only compute H, He, and e^- opacity sources: 
    logKappaHHe = Kappas.kappas2(numDeps, newPe, zScale, temp, rho,  \
                     numLams, lambdaScale, logAz[1],  \
                     masterStagePops[0][0], masterStagePops[0][1],  \
                     masterStagePops[1][0], masterStagePops[1][1], newNe,  \
                     teff, logTotalFudge)


#//Add in metal b-f opacity from adapted Moog routines:
    logKappaMetalBF = KappasMetal.masterMetal(numDeps, numLams, temp, lambdaScale, masterStagePops)
#//Add in Rayleigh scattering opacity from adapted Moog routines:
    logKappaRayl = KappasRaylGas.masterRayl(numDeps, numLams, temp, lambdaScale, masterStagePops, gsName, gsFirstMol, masterMolPops)
    
    #print("logKappaHHe ", [logKappaHHe[:][36]])
    #print("logKappaMetalBF ", [logKappaMetalBF[:][36]])
    #print("logKappaRayl ", [logKappaRayl[:][36]])
    
    #for i in range(numLams):
    #    print("logKappaHHe " , logE*logKappaHHe[i][36]);
    #for i in range(numLams):
    #    print("logKappaMetalBF " , logE*logKappaMetalBF[i][36]);
    #for i in range(numLams):
    #   print("logKappaRayl " , logE*logKappaRayl[i][36]);


#//Convert metal b-f & Rayleigh scattering opacities to cm^2/g and sum up total opacities
    #double logKapMetalBF, logKapRayl, kapContTot;
    #for iL in range(numLams):
    #    for iD in range(numDeps):
    #        logKapMetalBF = logKappaMetalBF[iL][iD] - rho[1][iD] 
    #        logKapRayl = logKappaRayl[iL][iD] - rho[1][iD] 
    #        kapContTot = math.exp(logKappaHHe[iL][iD]) + math.exp(logKapMetalBF) + math.exp(logKapRayl) 
    #        logKappa[iL][iD] = math.log(kapContTot)
    
    logKappa = [ [ math.exp(logKappaHHe[iL][iD]) + \
            math.exp(logKappaMetalBF[iL][iD] - rho[1][iD]) +\
            math.exp(logKappaRayl[iL][iD] - rho[1][iD]) for iD in range(numDeps)] for iL in range(numLams) ]
    logKappa = [ [math.log(logKappa[iL][iD]) for iD in range(numDeps)] for iL in range(numLams) ]
          
    kappaRos = Kappas.kapRos(numDeps, numLams, lambdaScale, logKappa, temp); 

#//Extract the "kappa_500" monochroamtic continuum oapcity scale
#// - this means we'll try interpreting the prescribed tau grid (still called "tauRos")as the "tau500" scale
    it500 = ToolBox.lamPoint(numLams, lambdaScale, 500.0e-7)
    #for i in range(numDeps):
    #    kappa500[1][i] = logKappa[it500][i]
    #    kappa500[0][i] = math.exp(kappa500[1][i])
    kappa500[1] = [ x for x in logKappa[it500] ]
    kappa500[0] = [ math.exp(x) for x in logKappa[it500] ] 
        
    pGas = Hydrostat.hydroFormalSoln(numDeps, grav, tauRos, kappaRos, temp, guessPGas)
    pRad = Hydrostat.radPress(numDeps, temp)

#//Update Pgas guess for iteration:
    #for i in range(numDeps):
#// Now we can update guessPGas:
    #    guessPGas[0][i] = pGas[0][i]
    #    guessPGas[1][i] = pGas[1][i]
    #    log10pgas[i] = log10e * pGas[1][i]
    #    log10pe[i] = log10e * (newNe[1][i] + Useful.logK() + temp[1][i])
    #    pe[i] = newNe[1][i] + Useful.logK() + temp[1][i]
    #    log10prad[i] = log10e * pRad[1][i]
    #    log10ne[i] = log10e * newNe[1][i]
        
    guessPGas[0] = [ x for x in pGas[0] ]
    guessPGas[1] = [ x for x in pGas[1] ]
    log10pgas = [ log10e * x for x in pGas[1] ]
    log10pe = [ log10e * (newNe[1][i] + Useful.logK() + temp[1][i]) for i in range(numDeps) ]
    pe = [ newNe[1][i] + Useful.logK() + temp[1][i] for i in range(numDeps) ]
    log10prad = [ log10e * x for x in pRad[1] ]
    log10ne = [ log10e * x for x in newNe[1] ]


    #Uncomment this block to inspect iteration-by-iteration convergence
    #Graphically inspect convergence:  Issue 'matplotlib qt5' in console before running code

    thisClr = palette[pIter%numClrs]
    #plt.plot(log10tauRos, log10pgas, color=thisClr)
    #plt.plot(log10tauRos, log10pgas, color=thisClr)
    #plt.plot(log10tauRos, log10pe, color=thisClr, linestyle='--')     
    #plt.plot(tauRos[1][:], newNe[1][:], thisClr)
#print("logKappa ", logKappa[:][36])

#//end Pgas-kappa iteration, nOuter
#Save as encapsulated postscript (eps) for LaTex
#plt.savefig('PConverge.eps', format='eps', dpi=1000)    
    
#//diagnostic
#//   int tauKapPnt01 = ToolBox.tauPoint(numDeps, tauRos, 0.01);
#//   System.out.println("logTauRos " + logE*tauRos[1][tauKapPnt01] + " temp " + temp[0][tauKapPnt01] + " pGas " + logE*pGas[1][tauKapPnt01]);
#//   System.out.println("tau " + " temp " + " logPgas " + " logPe " + " logRho "); 
#//   for (int iD = 1; iD < numDeps; iD+=5){
#//       System.out.println(" " + tauRos[0][iD] + " " + temp[0][iD] + " " +  logE*pGas[1][iD] + " " + logE*newPe[1][iD] + " " + logE*rho[1][iD]); 
#//   }
#//   for (int iL = 0; iL < numLams; iL++){
#//       //System.out.println(" " + lambdaScale[iL] + " " + logE*logKappa[iL][tauKapPnt01]); 
#//       System.out.println(" " + lambdaScale[iL]); 
#//       for (int iD = 1; iD < numDeps; iD+=5){
#//           System.out.println(" " + logE*(logKappa[iL][iD]+rho[1][iD]));  //cm^-1
#//       }
#//   } 
#   //int tauKapPnt1 = ToolBox.tauPoint(numDeps, tauRos, 1.0);
#   //System.out.println("logTauRos " + logE*tauRos[1][tauKapPnt1] + " temp " + temp[0][tauKapPnt1] + " pGas " + logE*pGas[1][tauKapPnt1]);
#   //for (int iL = 0; iL < numLams; iL++){
#   //    //System.out.println(" " + lambdaScale[iL] + " " + logE*logKappa[iL][tauKapPnt1]); 
#   //} 

 #       // Then construct geometric depth scale from tau, kappa and rho
 
#for iD in range(numDeps):
#    print("2 : ", (10.0**log10MasterGsPp[0][iD])/pGas[0][iD])
    
depths = DepthScale.depthScale(numDeps, tauRos, kappaRos, rho)

ifTcorr = False
ifConvec = False    
#//int numTCorr = 10;  //test
numTCorr = 0
for i in range(numTCorr):
    #//newTemp = TCorr.tCorr(numDeps, tauRos, temp);
    #Not yet newTemp = MulGrayTCorr.mgTCorr(numDeps, teff, tauRos, temp, rho, kappaRos)
    #//newTemp = MulGrayTCorr.mgTCorr(numDeps, teff, tauRos, temp, rho, kappa500);
    #for iTau in range(numDeps):
    #    temp[1][iTau] = newTemp[1][iTau]
    #    temp[0][iTau] = newTemp[0][iTau]
    temp[1] = [ x for x in newTemp[1] ]
    temp[0] = [ x for x in newTemp[0] ]

"""/*
     //Convection:
     // Teff below which stars are convective.  
     //  - has to be finessed because Convec.convec() does not work well :-(
     double convTeff = 6500.0;
     double[][] convTemp = new double[2][numDeps];
     if (teff < convTeff) {
     convTemp = Convec.convec(numDeps, tauRos, depths, temp, press, rho, kappaRos, kappaSun, zScale, teff, logg);
     for (int iTau = 0; iTau < numDeps; iTau++) {
     temp[1][iTau] = convTemp[1][iTau];
     temp[0][iTau] = convTemp[0][iTau];
      }
     }
     */"""

#if ((ifTcorr == True) or (ifConvec == True)):
    #//Recall hydrostat with updates temps            
    #//Recall state withupdated Press                    
    #//recall kappas withupdates rhos
    #//Recall depths with re-updated kappas




###################################################
#
#
#
# Re-converge Ionization/chemical equilibrium WITH molecules
#
#
#
####################################################

#//
#// Now that the atmospheric structure is settled: 
#// Separately converge the Ne-ionization-fractions-molecular equilibrium for
#// all elements and populate the ionization stages of all the species for spectrum synthesis:
#//
#//stuff to save ion stage pops at tau=1:
    

iTauOne = ToolBox.tauPoint(numDeps, tauRos, unity)

#//
#//  Default inializations:
zScaleList = 1.0 #/initialization
#//these 2-element temperature-dependent partition fns are logarithmic
    
#//Default initialization:
#for i in range(numAssocMols):
#    for j in range(numDeps):
#        logNumBArr[i][j] = -49.0
#              
#    for k in range(numAtmPrtTmps):
#        log10UwBArr[i][k] = 0.0 #// default initialization lburns
#          
#    
#    dissEArr[i] = 29.0  #//eV
#    for kk in range(numMolPrtTmps):
#        logQwABArr[i][kk] = math.log(300.0)
#           
#    logMuABArr[i] = math.log(2.0) + Useful.logAmu()  #//g
#    mname_ptr[i] = 0
#    specB_ptr[i] = 0
 

#Iterations needed?   Now ga?
#for neIter2 in range(nInnerIter):
    
#Final run through Phil's GAS EOS/Chemic equil. for consistency with last HSE call above:

    
if (teff <= GAStemp):
        
    for iD in range(numDeps):    
        
        #print("isolv ", isolv, " temp ", temp[0][iD], " guessPGas ", guessPGas[0][iD])
        gasestReturn = CSGasEst.gasest(isolv, temp[0][iD], guessPGas[0][iD])
        gsPe0 = gasestReturn[0]
        gsP0 = gasestReturn[1]
        neq = gasestReturn[2]
        
        #print("iD ", iD, " gsPe0 ", gsPe0, " gsP0 ", gsP0, " neq ", neq)

        gasReturn = CSGas.gas(isolv, temp[0][iD], guessPGas[0][iD], gsPe0, gsP0, neq, tol, maxit)
        #a = gasReturn[0]
        #nit = gasReturn[1]
        gsPe = gasReturn[2]
        #pd = gasReturn[3]
        gsPp = gasReturn[4]
        #Can't pythonize this - gsPp padded at end with 0.0s
        #log10MasterGsPp[:][iD] = [math.log10(x) for x in gsPp]
        for iSpec in range(gsNspec):
            log10MasterGsPp[iSpec][iD] = math.log10(gsPp[iSpec])
            #print("1: ", gsPp[0]/guessPGas[0][iD])
            #ppix = gasReturn[5]
        gsMu = gasReturn[6]
        gsRho = gasReturn[7]
        
        
        newPe[0][iD] = gsPe
        newPe[1][iD] = math.log(gsPe)
        newNe[0][iD] = gsPe / Useful.k() / temp[0][iD]
        newNe[1][iD] = math.log(newNe[0][iD])
        guessPe[0][iD] = newPe[0][iD]
        guessPe[1][iD] = newPe[1][iD]
        
        rho[0][iD] = gsRho
        rho[1][iD] = math.log(gsRho)
        mmw[iD] = gsMu * Useful.amu()
        
        #print("iD ", iD, " logT ", logE*temp[1][iD], " logNe ", logE*newNe[1][iD], " logRho ", logE*rho[1][iD], " mmw ", logE*math.log(mmw[iD]*Useful.amu()) )
        
        
        #Take neutral stage populations for atomic species from GAS: 
        for iElem in range(nelemAbnd):
            
            if (csp2gas[iElem] != -1):
                #element is in GAS package:
                #neutral stage only
                thisN = gsPp[csp2gas[iElem]] / Useful.k() / temp[0][iD]    
                masterStagePops[iElem][0][iD] = math.log(thisN)
            
            #print("iD ", iD, cname[19], gsName[csp2gas[19]], " logNCaI ", logE*masterStagePops[19][0][iD])
            
        for i in range(gsNumMols):
            thisN = gsPp[i+gsFirstMol] / Useful.k() / temp[0][iD]
            masterMolPops[i][iD] = math.log(thisN)
        
        #Needed  now GAS??  
        for iA in range(nelemAbnd):
            if (csp2gas[iA] != -1):
                #element is in GAS package:
                #neutral stage only
                logNz[iA][iD] = math.log10(gsPp[csp2gas[iA]]) - Useful.logK() - temp[1][iD]

    #end iD loop        

    #Catch species NOT in Phil's GAS Chem. Equil. package   
    for iElem in range(nelemAbnd):
        
        if (csp2gas[iElem] == -1):

            species = cname[iElem] + "I"
            chiIArr[0] = IonizationEnergy.getIonE(species)
            #//The following is a 2-element vector of temperature-dependent partitio fns, U,
            #// that are base e log_e U
            log10UwAArr[0] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "II"
            chiIArr[1] = IonizationEnergy.getIonE(species)
            log10UwAArr[1] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "III"
            chiIArr[2] = IonizationEnergy.getIonE(species)
            log10UwAArr[2] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "IV"
            chiIArr[3] = IonizationEnergy.getIonE(species)
            log10UwAArr[3]= PartitionFn.getPartFn2(species) #//base 1e log_e U
            species = cname[iElem] + "V"
            chiIArr[4] = IonizationEnergy.getIonE(species)
            log10UwAArr[4]= PartitionFn.getPartFn2(species) #//base 1e log_e U
            species = cname[iElem] + "VI"
            chiIArr[5] = IonizationEnergy.getIonE(species)
            log10UwAArr[5]= PartitionFn.getPartFn2(species) #//base e log_e U
    
        

            #Element NOT in GAS package - compute ionization equilibrium:
            logNums = LevelPopsGasServer.stagePops(logNz[iElem], guessNe, chiIArr, log10UwAArr, \
                                                   #thisNumMols, logNumBArr, dissEArr, log10UwBArr, logQwABArr, logMuABArr, \
                            numDeps, temp);

    #for iStage in range(numStages):
    #    for iTau in range(numDeps):
    #        masterStagePops[iElem][iStage][iTau] = logNums[iStage][iTau]
    #    #//save ion stage populations at tau = 1:
    #    #} //iTau loop
    #    tauOneStagePops[iElem][iStage] = logNums[iStage][iTauOne]
        
    #} //iStage loop
            masterStagePops[iElem] = [ [ logNums[iStage][iTau] for iTau in range(numDeps) ] for iStage in range(numStages) ]
            tauOneStagePops[iElem] = [ logNums[iStage][iTauOne] for iStage in range(numStages) ]
    #} //iElem loop

if (teff > GAStemp):
    
    for neIter2 in range(nInnerIter):
    
        for iElem in range(nelemAbnd):

            species = cname[iElem] + "I"
            chiIArr[0] = IonizationEnergy.getIonE(species)
            #//The following is a 2-element vector of temperature-dependent partitio fns, U,
            #// that are base e log_e U
            log10UwAArr[0] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "II"
            chiIArr[1] = IonizationEnergy.getIonE(species)
            log10UwAArr[1] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "III"
            chiIArr[2] = IonizationEnergy.getIonE(species)
            log10UwAArr[2] = PartitionFn.getPartFn2(species) #//base e log_e U
            species = cname[iElem] + "IV"
            chiIArr[3] = IonizationEnergy.getIonE(species)
            log10UwAArr[3]= PartitionFn.getPartFn2(species) #//base 1e log_e U
            species = cname[iElem] + "V"
            chiIArr[4] = IonizationEnergy.getIonE(species)
            log10UwAArr[4]= PartitionFn.getPartFn2(species) #//base 1e log_e U
            species = cname[iElem] + "VI"
            chiIArr[5] = IonizationEnergy.getIonE(species)
            log10UwAArr[5]= PartitionFn.getPartFn2(species) #//base e log_e U
    
#} //end Ne - ionzation fraction -molecular equilibrium iteration neIter2
            logNums = LevelPopsGasServer.stagePops(logNz[iElem], guessNe, chiIArr, log10UwAArr, \
                  numDeps, temp);

            #for iStage in range(numStages):
            #    for iTau in range(numDeps):
            #        masterStagePops[iElem][iStage][iTau] = logNums[iStage][iTau]
            #    #//save ion stage populations at tau = 1:
            #    #} //iTau loop
            #    tauOneStagePops[iElem][iStage] = logNums[iStage][iTauOne]
        
            #} //iStage loop
            masterStagePops[iElem] = [ [ logNums[iStage][iTau] for iTau in range(numDeps) ] for iStage in range(numStages) ]
            tauOneStagePops[iElem] = [ logNums[iStage][iTauOne] for iStage in range(numStages) ]
            #Fill in in PP report:
            if (csp2gas[iElem] != -1):
                log10MasterGsPp[csp2gas[iElem]] = [ logE*(logNums[0][iTau] + temp[1][iTau] + Useful.logK())\
                               for iTau in range(numDeps) ]
            if (csp2gasIon1[iElem] != -1):
                log10MasterGsPp[csp2gasIon1[iElem]] = [ logE*(logNums[1][iTau] + temp[1][iTau] + Useful.logK())\
                               for iTau in range(numDeps) ]
            if (csp2gasIon2[iElem] != -1):
                log10MasterGsPp[csp2gasIon2[iElem]] = [ logE*(logNums[2][iTau] + temp[1][iTau] + Useful.logK())\
                               for iTau in range(numDeps) ]
            

        log10UwA = [0.0 for i in range(numAtmPrtTmps)]
        newNe[0] = [ 0.0 for iTau in range(numDeps) ]
     
    #This is cumulative and not trivially pythonizable
        for iTau in range(numDeps):
            for iElem in range(nelemAbnd):
                #//1 e^- per ion, #//2 e^- per ion
                newNe[0][iTau] = newNe[0][iTau]   \
                + math.exp(masterStagePops[iElem][1][iTau])  \
                + 2.0 * math.exp(masterStagePops[iElem][2][iTau])   
            #//+ 3.0 * Math.exp(masterStagePops[iElem][3][iTau])   #//3 e^- per ion
            #//+ 4.0 * Math.exp(masterStagePops[iElem][4][iTau]);  #//3 e^- per ion
        #}
        #    newNe[1][iTau] = math.log(newNe[0][iTau])
        #    #// Update guess for iteration:
        #    guessNe[0][iTau] = newNe[0][iTau]
        #    guessNe[1][iTau] = newNe[1][iTau] 
        #newNe[0] = [ [ newNe[0][iTau]   \
        #        + math.exp(masterStagePops[iElem][1][iTau])  \
        #        + 2.0 * math.exp(masterStagePops[iElem][2][iTau]) \
        #        for iElem in range(nelemAbnd) ] for iTau in range(numDeps) ]
        newNe[1] = [ math.log(x) for x in newNe[0] ]
        guessNe[0] = [ x for x in newNe[0][:] ]
        guessNe[1] = [ x for x in newNe[1][:] ]

        log10pe = [ log10e * (newNe[1][i] + Useful.logK() + temp[1][i]) for i in range(numDeps) ]
        log10ne = [ log10e * x for x in newNe[1] ]

#//
#Some atmospheric structure output AGAIN after chemical equilibrium: 
#Convert everything to log_10 OR re-scaled units for plotting, printing, etc:


#log10mmw = [0.0 for i in range(numDeps)]
#for i in range(numDeps):
#    log10pe[i] = log10e * (newNe[1][i] + Useful.logK() + temp[1][i])
#    log10ne[i] = log10e * newNe[1][i]
log10pe = [ log10e * (newNe[1][i] + Useful.logK() + temp[1][i]) for i in range(numDeps) ]
log10ne = [ log10e * x for x in newNe[1] ]
 

# Create a restart module for use in spectrum synthesis mode:

 #outFile = outPath + strucFile
outFile = outPath + fileStem + "_restart.py"
#print vertical atmospheric structure as a python source file for re-import to ChromaStarPy
# Can be used as a converged model for an almost pure spectrum syntehsis run
#with open(outFile, 'w', encoding='utf-8') as strucHandle:
with open(outFile, 'w') as restartHandle:

    headerString = "# " + inputParamString
    restartHandle.write(headerString + "\n")
    
    restartHandle.write("\n")
    outLine = "teffRS = " + str(teff) + " # K\n"
    restartHandle.write(outLine)
    outLine = "loggRS = " + str(logg) + " #log (cm/^2)\n"
    restartHandle.write(outLine)
    outLine = "log10ZScaleRS = " + str(log10ZScale) + "\n"
    restartHandle.write(outLine)
    outLine = "massStarRS = " + str(massStar) + " # (M_Sun) \n"
    restartHandle.write(outLine)    
    outLine = "xiTRS = " + str(xiT) + " # (km/s) \n"
    restartHandle.write(outLine)
    outLine = "logKapFudgeRS = " + str(logKapFudge) + "\n"
    restartHandle.write(outLine)    
    outLine = "logHeFeRS = " + str(logHeFe) + "\n"
    restartHandle.write(outLine)
    outLine = "logCORS = " + str(logCO) + "\n"
    restartHandle.write(outLine)
    outLine = "logAlphaFeRS = " + str(logAlphaFe) + "\n"
    restartHandle.write(outLine) 

    restartHandle.write("\n")    
    numDepsStr = str(numDeps)
    outLine = "numDeps = " + numDepsStr + "\n"
    restartHandle.write(outLine)
    restartHandle.write("\n")    

    outLine = "tauRosRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("tauRosRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(tauRos[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(tauRos[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("tauRosRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(tauRos[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(tauRos[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine) 
    
    outLine = "tempRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("tempRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(temp[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(temp[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)
    ### This won't work: restartHandle.write( [ str( temp[0][i] ) + ', ' for i in range(numDeps-1) ]\
                         # + str(temp[0][numDeps-1]) + ']\n')

    restartHandle.write("tempRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(temp[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(temp[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    outLine = "pGasRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("pGasRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(pGas[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(pGas[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("pGasRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(pGas[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(pGas[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    outLine = "peRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("peRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(newPe[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(newPe[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("peRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(newPe[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(newPe[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)
    
    outLine = "pRadRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("pRadRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(pRad[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(pRad[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("pRadRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(pRad[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(pRad[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)    
    
    outLine = "rhoRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("rhoRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(rho[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(rho[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("rhoRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(rho[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(rho[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    outLine = "kappa500RS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("kappa500RS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(kappa500[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(kappa500[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("kappa500RS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(kappa500[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(kappa500[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)        

    outLine = "kappaRosRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("kappaRosRS[0] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(kappaRos[0][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(kappaRos[0][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)

    restartHandle.write("kappaRosRS[1] = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(kappaRos[1][i]) + ', '
        restartHandle.write(outLine)
    outLine = str(kappaRos[1][numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)        

    outLine = "mmwRS = [ [ 0.0 for i in range(" + numDepsStr + ") ] for j in range(2) ]\n"
    restartHandle.write(outLine)
    restartHandle.write("mmwRS = [\\\n") #continuation line '\' has to be escaped
    for i in range(numDeps-1):
        outLine = str(mmw[i]) + ', '
        restartHandle.write(outLine)
    outLine = str(mmw[numDeps-1]) + '\\\n]\n'
    restartHandle.write(outLine)
    
############################################################
#
#
#
# Surface radiation field
#
#  - flux distribution (SED)
#  - high resolution synthetic spectrum
#
#
###############################################################

#//Okay - Now all the emergent radiation stuff:
#// Set up theta grid
#//  cosTheta is a 2xnumThetas array:
#// row 0 is used for Gaussian quadrature weights
#// row 1 is used for cos(theta) values
#// Gaussian quadrature:
#// Number of angles, numThetas, will have to be determined after the fact
cosTheta = Thetas.thetas()
numThetas = len(cosTheta[0])

#//establish a phi grid for non-axi-symmetric situations (eg. spots, in situ rotation, ...)
#//    //number of phi values per quandrant of unit circle centered on sub-stellar point
#//        //    in plane of sky:
#//        //For geometry calculations: phi = 0 is direction of positive x-axis of right-handed
#//        // 2D Cartesian coord system in plane of sky with origin at sub-stellar point (phi
#//        // increases CCW)
numPhiPerQuad = 6
numPhi = 4 * numPhiPerQuad
numPhiD = numpy.double(numPhi)
phi = [numpy.double(0.0) for i in range(numPhi)]
#//Compute phi values in whole range (0 - 2pi radians):
delPhi = numpy.double(2.0 * math.pi / numPhiD)
#double ii
#for i in range(numPhi):
#    ii = float(i)
#    phi[i] = delPhi * ii
phi = [ delPhi * numpy.double(i) for i in range(numPhi) ]

#Planetary transit quantities
#Angle of orbital axis wrt plane-of-sky
iPrime = numpy.double(90.0) - rotI
    
#Degrees to RAD
iPrimeRad = iPrime * math.pi / numpy.double(180.0)
    
#Right angle triangle with hypoteneuse = rOrbit
#  angle = rotIRad, 
#  and opposite = planet's minimum impact parameters wrt substellar point
#impact parameter (minimum offset from substellar point)in AU
impct = rOrbit * math.sin(iPrimeRad)
#impact parameter in solar radii
impct = impct * Useful.AU2cm() / Useful.rSun()
if ( impct >= (radius-(2*rPlanetSol)) ):
    #There is no eclipse (transit)
    ifTransit = False
    print("TRANSIT FALSE triggered:")
    print("radius ", radius, " rPlanetSol ", rPlanetSol, " impct ", impct)
#print("rotI ", rotI, " iPrime ", iPrime, " iPrimeRad ", iPrimeRad,\
#      " impct/radius ", impct/radius)
#thetaMinRad is also the minimum theta of the eclipse path chord, in RAD

#Initialization:
#Duration of ingress (and egress) from 1st contact to planetary mid-point contact     
ingressT1 = 0.0 
#Duration of ingress (and egress) from planetary mid-point contact to 2nd contact     
ingressT2 = 0.0
numTransThetas = 0.0
thetaMinRad = 1.0
iFirstTheta = 0
contact1x = 0.0
contact2x = 0.0
contactMidx = 0.0
cosThetaMax = 0.0
midContAngle = 0.0
halfHelpAngle = 0.0
logOmegaLens = logTiny
#omegaLens = 0.0
if (ifTransit):
    #First contact position along cord, in solar radii:
    contact1x = math.sqrt( (radius + rPlanetSol)**2 - impct**2 )
    #Planetary mid-point contact
    contactMidx = math.sqrt(radius**2 - impct**2)
    #Second contact position along cord in solar radii:
    contact2x = math.sqrt( (radius - rPlanetSol)**2 - impct**2 ) 
    #ingressT = ( (contact1x - contact2x)*Useful.rSun() ) / vTrans
    ingressT1 = ( (contact1x - contactMidx)*Useful.rSun() ) / vTrans
    ingressT2 = ( (contactMidx - contact2x)*Useful.rSun() ) / vTrans    
    #print("New ingressT1 ", ingressT1, " ingressT2 ", ingressT2)
    #cos(theta) *decreases* with increasing theta in Quadrant I:
    thetaMinRad =  math.asin(impct/radius)
    cosThetaMax = math.cos(thetaMinRad) 

    #print(" thetaMinRad ", thetaMinRad,\
    #      " cosThetaMax ", cosThetaMax)
   
    #quantities for computing the blocking factor at planetary mid-point contact 
    #Angle at planet's centre of lens-like occultation sector area:
    midContAngle = 2.0 * math.atan(radius/rPlanetSol)
    #Area of lens-shaped area occulted at planetary mid-point contact in solar-radii^2
    # - (2*angle/2*Pi) * Pi*rPlanet^2 = angle*rPlanet^2 
    logOmegaLens = math.log(midContAngle) + 2.0*math.log(rPlanetSol)
    #As fraction of host star projected radius
    logOmegaLens = logOmegaLens - math.log(math.pi) - 2.0*math.log(radius)
    #print("midContAngle ", midContAngle, " logOmegaLens ", logOmegaLens)
    #omegaLens = math.exp(logOmegaLens)       
            
i = 0

#ifFirst = False
#for i in range(numThetas):
#cosTheta[1] *decreases* (ie. theta increases) with increasing array number 
if (ifTransit):
    while ( (cosTheta[1][i] >= cosThetaMax)
           & (i < numThetas) ):
        #print("In while loop: i ", i, " cosTheta[1] ", cosTheta[1][i])
        #if (ifFirst == False):
        #    iFirstTheta = i
        #    ifFirst = True
        # We are on the eclipse semi-chord:
        i+=1
    iFirstTheta = i
    
numTransThetas = numThetas - i
numTransThetas2 = (2*numTransThetas + 4)
#print("iFirstTheta ", iFirstTheta, " numTransThetas ", numTransThetas, " numTransThetas2 ", numTransThetas2) 
transit = [0.0 for i in range(numTransThetas)]
transit2 = [0.0 for i in range(numTransThetas2)]
transDuration = 0.0
transTime0 = 0.0
transTime1 = 0.0
totalDuration = 0.0
deltaT = 0.0
numEpochs = 0
ephemT = [ 0.0 for x in range(numEpochs) ] 

#Mandel & Agol (2002)'s "p" parameter
pMA = rPlanetSol / radius

# blocking factor should be projected planet area over that annulus area 
#transit[][] is array of distances traveled, r, along semi-chord from position of
#minimum impact parameter, and corresponding theta values:
# 2D array of 2 x numThetas
#row 0 is log_e of ratio of projected planet area to area of annulus for each theta being transited
#row 1 is times corresponding to linear distance travelled along transit 
#  semi-path at surface of star in solar radii

#transit = [[numpy.double(0.0) for i in range(numTransThetas)] for j in range(2)] # Default
#Row 0 is logarithmic ratio of planet area to annulus area 
# - set default value to log of neglible value:
#transit[0] = [logTiny for i in range(numThetas)]
print("ifTransit ", ifTransit)
if (ifTransit):
    transit = TransitLightCurve2.transLight2(radius, cosTheta, vTrans, iFirstTheta, numTransThetas, impct)
    #print("numTransThetas ", numTransThetas)
    #reflect the half-transit profile and add the first and last points just before
    #ingress and just after egress    
    for i in range(numTransThetas):
        transit2[2+i] = -1.0 * transit[(numTransThetas-1)-i]
        #print("1st half: i ", i, " (numTransThetas-1)-i ", (numTransThetas-1)-i)
    for i in range(numTransThetas):
        transit2[2+(numTransThetas+i)] = transit[i]
        #print("2nd half: i ", i)
    transit2[1] = transit2[2] - ingressT2    
    transit2[0] = transit2[1] - ingressT1
    transit2[numTransThetas2-2] = transit2[numTransThetas2-3] + ingressT2
    transit2[numTransThetas2-1] = transit2[numTransThetas2-2] + ingressT1

    transDuration = transit2[numTransThetas2-1] - transit2[0]
    #print("transit2[0] ", transit2[0], " transit2[numTransThetas2-1] ", transit2[numTransThetas2-1])
    transTime0 = transit2[0] - transDuration/4
    transTime1 = transit2[numTransThetas2-1] + transDuration/4
    totalDuration = transTime1 - transTime0
    #print("transTime0 ", transTime0, " transTime1 ", transTime1)
    #print("transDuration ", transDuration, " totalDuration ", totalDuration)
    #numEpochs = 200
    #deltaT = transDuration / numEpochs
    #Make time sampling interval equal to the time of ingress/egress
    deltaT = min(ingressT1, ingressT2) #/ 2.0
    numEpochs = int(totalDuration / deltaT)
    #print("deltaT ", deltaT, " numEpochs ", numEpochs)
    #ephemeris in time units (s)
    ephemT = [ ((x*deltaT)+transTime0) for x in range(numEpochs) ]  
         
    
#boolean lineMode;

#//
#// ************
#//
#//  Spectrum synthesis section:
#// Set up continuum info:
isCool = 7300.0  #//Class A0

#//Set up opacity:
#// lambda break-points and gray levels:
#// No. multi-gray bins = num lambda breakpoints +1
minLambda = 30.0  #//nm
maxLambda = 1.0e6  #//nm

#// JOLA molecular bands here:
#// 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 & Koester, 1982

#double jolaOmega0;  //band origin ?? //Hz OR waveno in cm^-1 ??
#//double[] jolaLogF; //total vibrational band oscillator strength (f_v'v")
#double jolaRSqu; //needed for total vibrational band oscillator strength (f_v'v")
jolaB = [0.0 for i in range(2)] #// B' value of upper vibational state (energy in cm^-1)??
jolaLambda = [0.0 for i in range(2)]
jolaAlphP = 0.0 #// alpha_P - weight of P branch (Delta J = -1)
jolaAlphR = 0.0 #/ alpha_R - weight of R branch (Delta J = 1)
jolaAlphQ = 0.0 #// alpha_Q - weight of Q branch (Delta J = 0)
#//Allen's Astrophysical quantities, 4th Ed., 4.12.2 - 4.13.1:
#// Electronic transition moment, Re
#//"Line strength", S = |R_e|^2*q_v'v" or just |R_e|^2 (R_00 is for the band head)
#//Section 4.4.2 - for atoms or molecules:
#// then: gf = (8pi^2m_e*nu/3he^2) * S
#//
#// ^48Ti^16O systems: Table 4.18, p. 91
#//  C^3Delta - X^3Delta ("alpha system") (Delta Lambda = 0??, p. 84 - no Q branch??)
#//  c^1Phi - a^1Delta ("beta system") (Delta Lambda = 1??, p. 84)
#//  A^3Phi - X^3Delta ("gamma system") (Delta Lambda = 0??, p. 84 - no Q branch??)
#// //
#// Rotational & vibrational constants for TiO states:, p. 87, Table 4.17
#// C^3Delta, X^3Delta a^1Delta, -- No "c^1Phi" - ??
#//
#//General TiO molecular rotational & vibrational constants - Table 3.12, p. 47

#//Zeidler & Koester 1982 p. 175, Sect vi):
#//If Q branch (deltaLambda = +/-1): alpP = alpR = 0.25, alpQ = 0.5
#//If NO Q branch (deltaLambda = 0): alpP = alpR = 0.5, alpQ = 0.0

#//number of wavelength point sampling a JOLA band
jolaNumPoints = 30 
#//int jolaNumPoints = 10; 

#// branch weights for transitions of DeltaLambda = +/- 1
jolaAlphP_DL1 = 0.25
jolaAlphR_DL1 = 0.25
jolaAlphQ_DL1 = 0.5
#// branch weights for transitions of DeltaLambda = 0
jolaAlphP_DL0 = 0.5
jolaAlphR_DL0 = 0.5
jolaAlphQ_DL0 = 0.0 #//no Q branch in this case

#double jolaS; //line strength
#double jolaLogF; //line strength

logSTofHelp = math.log(8.0/3.0) + 2.0*math.log(math.pi) + Useful.logMe() - Useful.logH() - 2.0*Useful.logEe()
#//Hand-tuned for now - Maybe this is the "script S" factor in Allen 4th Ed., p. 88 (S = |R|^2*q_v'v"*scriptS)
jolaQuantumS = 1.0 #//default for multiplicative factor 
logNumJola = [0.0 for i in range(numDeps)]
jolaProfPR = [ [0.0 for i in range(numDeps)] for j in range(jolaNumPoints) ]  #// For unified P & R branch
jolaProfQ = [ [0.0 for i in range(numDeps)] for j in range(jolaNumPoints) ]  #//For Q branch
#//Differential cross-section - the main "product" of the JOLA approximation:
dfBydv = [ [0.0 for i in range(numDeps)] for j in range(jolaNumPoints) ]  

#//
dataPath = "InputData/"
#//
#//
#// **************  Atomic line list:
#//
#//NIST Atomic Spectra Database Lines Data
#//Kramida, A., Ralchenko, Yu., Reader, J., and NIST ASD Team (2015). NIST Atomic Spectra Database (ver. 5.3), [Online]. Available: http://physics.nist.gov/asd [2017, January 30]. National Institute of Standards and Technology, Gaithersburg, MD.
#//
#//Stuff for byte file method:
#//
#// *** NOTE: bArrSize must have been noted from the stadout of LineListServer and be consistent
#// with whichever line list is linked to gsLineListBytes.dat, and be st manually here:
lineListBytes = absPath + dataPath + "atomLineListFeb2017Bytes.dat"
#lineListBytes = "gsLineListBytes.dat"
#//

#//System.out.println(" *********************************************** ");
#//System.out.println("  ");
#//System.out.println("  ");
print("READING LINE LIST")
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println(" *********************************************** ");

with open(lineListBytes, 'rb') as fHandle:    
    #Java: barray = ByteFileRead.readFileBytes(lineListBytes, bArrSize);
    barray = fHandle.read()
    
#fHandle closed automatically when with: exited   

#Java: String decoded = new String(barray, 0, bArrSize);  // example for one encoding type 
decoded = barray.decode('utf-8')

#//System.out.println(" *********************************************** ");
#//System.out.println("  ");
#//System.out.println("  ");
print("LINE LIST READ")
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println(" *********************************************** ");

arrayLineString = decoded.split("%%")
#//Number of lines MUST be the ONLY entry on the first line 

numLineList = len(arrayLineString) - 1
#numLineList = 1 #//test


#//Atomic lines:
#//Okay, here we go:
list2Lam0 = [0.0 for i in range(numLineList)]  #// nm
list2Element = ["" for i in range(numLineList)] #//element
list2StageRoman = ["" for i in range(numLineList)] #//ion stage
list2Stage = [0 for i in range(numLineList)] #//ion stage
list2Mass = [0.0 for i in range(numLineList)] #// amu
list2LogGammaCol = [0.0 for i in range(numLineList)]
#//Einstein coefficient for spontaneous de-exciation:
list2LogAij = [0.0 for i in range(numLineList)] #//log base 10
#//Log of unitless oscillator strength, f 
list2Logf = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage I (eV) 
list2ChiI1 = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage II (eV)
list2ChiI2 = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage III (eV) 
list2ChiI3 = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage IV (eV)
list2ChiI4 = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage V (eV)
list2ChiI5 = [0.0 for i in range(numLineList)]
#//Ground state ionization E - Stage VI (eV)
list2ChiI6 = [0.0 for i in range(numLineList)]
#//Excitation E of lower E-level of b-b transition (eV)
list2ChiL = [0.0 for i in range(numLineList)]
#//Unitless statisital weight, Ground state - Stage I
#//double[] list2Gw1 = new double[numLineList];
#//Unitless statisital weight, Ground state - Stage II
#//double[] list2Gw2 = new double[numLineList];
#//Unitless statisital weight, Ground state - Stage III
#//double[] list2Gw3 = new double[numLineList];
#//Unitless statisital weight, Ground state - Stage IV
#//double[] list2Gw4 = new double[numLineList];
#//double[] list2Gw4 = new double[numLineList];
#//Unitless statisital weight, lower E-level of b-b transition                 
list2GwL = [0.0 for i in range(numLineList)]
#//double[] list2GwU For now we'll just set GwU to 1.0
#// Is stage II?

#//Atomic Data sources:
 
#double thisF;
list2_ptr = 0 #//pointer into line list2 that we're populating
numFields = 7 #//number of field per record 
#// 0: element, 1: ion stage, 2: lambda_0, 3: logf, 4: g_l, 5: chi_l
thisRecord = ["" for i in range(numFields)] 
    
#String myString;  //useful helper

for iLine in range(numLineList):

    
    #// "|" turns out to mean something in regexp, so we need to escape with '\\':
    thisRecord = arrayLineString[iLine].split("|")
    #//System.out.println("thisRecord[0] " + thisRecord[0]
    #//                 + "thisRecord[1] " + thisRecord[1] 
    #//                 + "thisRecord[2] " + thisRecord[2] 
    #//                 + "thisRecord[3] " + thisRecord[3] 
    #//                 + "thisRecord[4] " + thisRecord[4] 
    #//                 + "thisRecord[5] " + thisRecord[5]);
                 
       
    myString = thisRecord[0].strip() 
    list2Element[iLine] = myString
    myString = thisRecord[1].strip()
    list2StageRoman[iLine] = myString  
    myString = thisRecord[2].strip() 
    list2Lam0[iLine] = float(myString)
    myString = thisRecord[3].strip()
    list2LogAij[iLine] = float(myString)
    myString = thisRecord[4].strip()
    list2Logf[iLine] = float(myString)
    myString = thisRecord[5].strip()
    list2ChiL[iLine] = float(myString)
    #//// Currently not used
    #//        myString = thisRecord[6].trim();
    #//        list2ChiU = Double.parseDouble(myString);
    #//        myString = thisRecord[7].trim();
    #//        list2Jl = Double.parseDouble(myString);
    #//        myString = thisRecord[8].trim();
    #//        list2Ju = Double.parseDouble(myString);
    myString = thisRecord[9].strip()
    list2GwL[iLine] = float(myString)
    #//// Currently not used
    #//        myString = thisRecord[10].trim();
    #//        list2GwU = Double.parseDouble(myString);
        
    #//Get the chemical element symbol - we don't know if it's one or two characters
    if (list2StageRoman[list2_ptr] == "I"):
        list2Stage[list2_ptr] = 0
             
    if (list2StageRoman[list2_ptr] == "II"):
        list2Stage[list2_ptr] = 1
             
    if (list2StageRoman[list2_ptr] == "III"):
        list2Stage[list2_ptr] = 2
             
    if (list2StageRoman[list2_ptr] == "IV"):
        list2Stage[list2_ptr] = 3
             
    if (list2StageRoman[list2_ptr] == "V"):
        list2Stage[list2_ptr] = 4
             
    if (list2StageRoman[list2_ptr] == "VI"):
        list2Stage[list2_ptr] = 5
             
    if (list2StageRoman[list2_ptr] == "VII"):
        list2Stage[list2_ptr] = 6
             
#//wavelength in nm starts at position 23 and is in %8.3f format - we're not expecting anything greater than 9999.999 nm

#// Some more processing:
    list2Mass[list2_ptr] = AtomicMass.getMass(list2Element[list2_ptr])
    species = list2Element[list2_ptr] + "I"
    list2ChiI1[list2_ptr] = IonizationEnergy.getIonE(species) 
    species = list2Element[list2_ptr] + "II"
    list2ChiI2[list2_ptr] = IonizationEnergy.getIonE(species)
    species = list2Element[list2_ptr] + "III"
    list2ChiI3[list2_ptr] = IonizationEnergy.getIonE(species) 
    species = list2Element[list2_ptr] + "IV"
    list2ChiI4[list2_ptr] = IonizationEnergy.getIonE(species)
    species = list2Element[list2_ptr] + "V"
    list2ChiI5[list2_ptr] = IonizationEnergy.getIonE(species)
    species = list2Element[list2_ptr] + "VI"
    list2ChiI6[list2_ptr] = IonizationEnergy.getIonE(species)

    #//We're going to have to fake the ground state statistical weight for now - sorry:
    #//list2Gw1[list2_ptr] = 1.0;
    #//list2Gw2[list2_ptr] = 1.0; 
    #//list2Gw3[list2_ptr] = 1.0;
    #//list2Gw4[list2_ptr] = 1.0; 
    list2LogGammaCol[list2_ptr] = logGammaCol 

    #//We've gotten everything we need from the NIST line list:
    list2_ptr+=1
        
    #} //iLine loop 

numLines2 = list2_ptr
#numLines2 = 0  #test
#//
#
#//Okay - what kind of mess did we make...
#
#
#// END FILE I/O SECTION


#//System.out.println(" *********************************************** ");
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println("BEFORE TRIAGE");
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println(" *********************************************** ");
#//
#//Triage: For each line: Voigt, Gaussian, or neglect??

#//
gaussLineCntr = 0 #//initialize accumulator
#//int sedLineCntr = 0; //initialize accumulator
#//No! boolean[] ifThisLine = new boolean[numLines2]; //initialize line strength flag
gaussLine_ptr = [0 for i in range(numLines2)] #//array of pointers to lines that make the cut in the 
#//int sedLine_ptr[] = new int[numLines2]; //array of pointers to lines that make the cut in the 
                                                  #// master line list  
        
isFirstLine = True #//initialization
firstLine = 0 #//default initialization
#// This holds 2-element temperature-dependent base 10 logarithmic parition fn:
thisUwV = [0.0 for i in range(numAtmPrtTmps)]
#// Below created a loop to initialize each value to zero for the five temperatures lburns
#for i in range(len(thisUwV)):
#    thisUwV[i] = 0.0  #//default initialization



for iLine in range(numLines2):

    #//No! ifThisLine[iLine] = false;
    #//if H or He, make sure kappaScale is unity:
    if ((list2Element[iLine] == "H") \
    or (list2Element[iLine] == "He")):
        zScaleList = 1.0
        #//list2Gw1[iLine] = 2.0;  //fix for H lines
        if (list2Lam0[iLine] <= 657.0):
            list2GwL[iLine] = 8.0  #//fix for Balmer lines
        else:
            list2GwL[iLine] = 18.0  #//fix for Paschen lines        
    else: 
        zScaleList = zScale


    list2Lam0[iLine] = list2Lam0[iLine] * nm2cm  #// nm to cm
    iAbnd = 0 #//initialization
    logNums_ptr = 0
    #//System.out.println("iLine " + iLine + " list2Element[iLine] " + list2Element[iLine]);
    #Not trivially pythonizable:
    for jj in range(nelemAbnd):
        #//System.out.println("jj " + jj + " cname[jj]" + cname[jj]+"!");
        if (list2Element[iLine] == cname[jj]):
            if (list2Stage[iLine] == 0):
                 species = cname[jj] + "I"
                 logNums_ptr = 0
            
            if (list2Stage[iLine] == 1):
                 species = cname[jj] + "II"
                 logNums_ptr = 1
            
            if (list2Stage[iLine] == 2):
                 species = cname[jj] + "III"
                 logNums_ptr = 4
            
            if (list2Stage[iLine] == 3):
                 species = cname[jj] + "IV"
                 logNums_ptr = 5
            
            if (list2Stage[iLine] == 4):
                 species = cname[jj] + "V"
                 logNums_ptr = 6
            
            if (list2Stage[iLine] == 5):
                 species = cname[jj] + "VI"
                 logNums_ptr = 7
            
            thisUwV = PartitionFn.getPartFn2(species) #//base e log_e U
            break   #//we found it
        
        iAbnd+=1
    #} //jj loop
            
    list2LogNums = [ [ 0.0 for i in range(numDeps) ] for j in range(numStages+2) ]
    #for iTau in range(numDeps):
    #    list2LogNums[0][iTau] = masterStagePops[iAbnd][0][iTau]
    #    list2LogNums[1][iTau] = masterStagePops[iAbnd][1][iTau]
    #    list2LogNums[4][iTau] = masterStagePops[iAbnd][2][iTau]
    #    list2LogNums[5][iTau] = masterStagePops[iAbnd][3][iTau]
    #    list2LogNums[6][iTau] = masterStagePops[iAbnd][4][iTau]
    #    list2LogNums[7][iTau] = masterStagePops[iAbnd][5][iTau]
    list2LogNums[0] = [ x for x in masterStagePops[iAbnd][0] ]
    list2LogNums[1] = [ x for x in masterStagePops[iAbnd][1] ]
    list2LogNums[4] = [ x for x in masterStagePops[iAbnd][2] ]
    list2LogNums[5] = [ x for x in masterStagePops[iAbnd][3] ]
    list2LogNums[6] = [ x for x in masterStagePops[iAbnd][4] ]
    list2LogNums[7] = [ x for x in masterStagePops[iAbnd][5] ]
    
    #if ( ((list2Lam0[iLine]) > lambdaStart) and ((list2Lam0[iLine]) < lambdaStop) and species=="CaI"):
    #    print("iLine ", iLine, " species ", species, " logNums_ptr ", logNums_ptr, " list2Lam0 ", list2Lam0[iLine], \
    #          " list2Logf[iLine] ", list2Logf[iLine] , " list2ChiL ", list2ChiL[iLine], " thisUwV ", thisUwV, \
    #          " list2GwL ", list2GwL[iLine])
    
            
    numHelp = LevelPopsGasServer.levelPops(list2Lam0[iLine], list2LogNums[logNums_ptr], list2ChiL[iLine], thisUwV, \
                list2GwL[iLine], numDeps, temp)
    
            
    #for iTau in range(numDeps):
    #    list2LogNums[2][iTau] = numHelp[iTau]
    #    list2LogNums[3][iTau] = numHelp[iTau] / 2.0 #//fake for testing with gS3 line treatment
    list2LogNums[2] = [ x for x in numHelp ]
    list2LogNums[3] = [ x/2.0 for x in numHelp ]
   
    #if ( ((list2Lam0[iLine]) > lambdaStart) and ((list2Lam0[iLine]) < lambdaStop) and species=="CaI"):
    #    print("list2LogNums[2] ", list2LogNums[2])         

    #//linePoints: Row 0 in cm (will need to be in nm for Plack.planck), Row 1 in Doppler widths
    #//For now - initial strength check with delta fn profiles at line centre for triage:
    listNumPointsDelta = 1
    listLinePointsDelta = LineGrid.lineGridDelta(list2Lam0[iLine], list2Mass[iLine], xiT, numDeps, teff)
    listLineProfDelta = LineProf.delta(listLinePointsDelta, list2Lam0[iLine], numDeps, tauRos, list2Mass[iLine], xiT, teff) 
    listLogKappaLDelta = LineKappa.lineKap(list2Lam0[iLine], list2LogNums[2], list2Logf[iLine], listLinePointsDelta, listLineProfDelta,
                    numDeps, zScaleList, tauRos, temp, rho, logFudgeTune)
   

    
    """/* Let's not do this - too slow:
            // Low resolution SED lines and high res spectrum synthesis region lines are mutually
            // exclusive sets in wavelength space:
            //Does line qualify for inclusion in SED as low res line at all??
            // Check ratio of line centre opacity to continuum at log(TauRos) = -5, -3, -1
            if ( (logE*(listLogKappaLDelta[0][6] - kappa[1][6]) > sedThresh)  
              || (logE*(listLogKappaLDelta[0][18] - kappa[1][18]) > sedThresh)  
              || (logE*(listLogKappaLDelta[0][30] - kappa[1][30]) > sedThresh) ){ 
                   if ( ( list2Stage[iLine] == 0) || (list2Stage[iLine] == 1) 
                    ||  ( list2Stage[iLine] == 2) || (list2Stage[iLine] == 3) ){
                        if ( (list2Lam0[iLine] > lamUV) and (list2Lam0[iLine] < lamIR) ){
                           if ( (list2Lam0[iLine] < lambdaStart) || (list2Lam0[iLine] > lambdaStop) ){ 
                      //No! ifThisLine[iLine] = true;
                      sedLine_ptr[sedLineCntr] = iLine;
                      sedLineCntr++;
      //System.out.println("SED passed, iLine= " + iLine + " sedLineCntr " + sedLineCntr 
      //   + " list2Lam0[iLine] " + list2Lam0[iLine] 
      //   + " list2Element[iLine] " + list2Element[iLine]
      //   + " list2Stage[iLine] " + list2Stage[iLine]); 
                                 }
                            }
                      } 
                }
    */"""

    #//Does line qualify for inclusion in high res spectrum synthesis region??
    #// Check ratio of line centre opacity to continuum at log(TauRos) = -5, -3, -1
    #//Find local value of lambda-dependent continuum kappa - list2Lam0 & lambdaScale both in cm here: 
    thisLambdaPtr = ToolBox.lamPoint(numLams, lambdaScale, list2Lam0[iLine])
    if ( (logE*(listLogKappaLDelta[0][6] - logKappa[thisLambdaPtr][6]) > lineThresh)  
    or (logE*(listLogKappaLDelta[0][18] - logKappa[thisLambdaPtr][18]) > lineThresh)  
    or (logE*(listLogKappaLDelta[0][30] - logKappa[thisLambdaPtr][30]) > lineThresh) ): 
        if ( ( list2Stage[iLine] == 0) or (list2Stage[iLine] == 1) 
		  or ( list2Stage[iLine] == 2) or (list2Stage[iLine] == 3) 
        or  ( list2Stage[iLine] == 4) or (list2Stage[iLine] == 5) ):
            if ( (list2Lam0[iLine] > lambdaStart) and (list2Lam0[iLine] < lambdaStop) ): 
                #special test condition
                #if (list2Element[iLine] == "Na"):
			           #//No! ifThisLine[iLine] = true;
                    gaussLine_ptr[gaussLineCntr] = iLine
                    gaussLineCntr+=1
                    if (isFirstLine == True):
                        firstLine = iLine
                        isFirstLine = False

#//
#} //iLine loop

#//
#
#//We need to have at least one line in region:
areNoLines = False #//initialization
if (gaussLineCntr == 0):
    gaussLineCntr = 1
    gaussLine_ptr[0] = firstLine
    areNoLines = True
         

numGaussLines = gaussLineCntr
#//System.out.println(" *********************************************** ");
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println("AFTER TRIAGE");
#//System.out.println("  ");
#//System.out.println("  ");
#//System.out.println(" *********************************************** ");

#//Notes
#//if Hydrogen or Helium, kappaScale should be unity for these purposes:
#//double kappaScaleList = 1.0; //initialization                   
#//

listNumCore = 3  #//half-core //default initialization
listNumWing = 1  #//per wing
#//int sedNumWing = 1;  //per wing
#//int thisNumCore = sedNumCore; //default initialization
#//int thisNumWing = sedNumWing; //default initialization
if (sampling == "coarse"):
    listNumCore = 3  #//half-core
    listNumWing = 3  #//per wing
else: 
    listNumCore = 5  #//half-core
    listNumWing = 10  #//per wing
         
#//Delta fn - for testing and strength triage
#        //int listNumPoints = 1;
#//All gaussian
#        //int listNumPoints = 2 * listNumCore - 1; // + 1;  //Extra wavelength point at end for monochromatic continuum tau scale
#////All full voigt:
listNumPoints = (2 * (listNumCore + listNumWing) - 1) #// + 1;  //Extra wavelength point at end for monochromatic continuum tau scale
#//int sedNumPoints = (2 * (sedNumCore + sedNumWing) - 1); // + 1;  //Extra wavelength point at end for monochromatic continuum tau scale
#//int thisNumPoints = sedNumPoints; //default initialization
numNow = numLams  #//initialize dynamic counter of how many array elements are in use
#int numMaster;
if (ifMols == 1):
    numMaster = numLams + (numGaussLines * listNumPoints) + (numJola * jolaNumPoints) #// + (numSedLines * sedNumPoints); //total size (number of wavelengths) of master lambda & total kappa arrays 
else:
    numMaster = numLams + (numGaussLines * listNumPoints)
    
masterLams = [0.0 for i in range(numMaster)]
#//Line blanketed opacity array:

logMasterKaps = [ [ 0.0 for i in range(numDeps) ] for j in range(numMaster) ]
#//seed masterLams and logMasterKaps with continuum SED lambdas and kappas:
#//This just initializes the first numLams of the numMaster elements

#//Initialize monochromatic line blanketed opacity array:
#// Seed first numLams wavelengths with continuum wavelength and kappa values 
for iL in range(numLams):
    masterLams[iL] = lambdaScale[iL]
    for iD in range(numDeps):
        logMasterKaps[iL][iD] = logKappa[iL][iD] 
#This pythonization will not work
#masterLams[0: numLams] = [ lambdaScale[iL] for iL in range(numLams) ]
#logMasterKaps[0: numLams][:] = [ [ logKappa[iL][iD] for iD in range(numDeps) ] for iL in range(numLams) ]           

        
#//initialize the remainder with dummy values - these values will be clobbered as line wavelengths are inserted, 
#// and don't matter
for iL in range(numLams, numMaster):
    masterLams[iL] = lambdaScale[numLams - 1]
    for iD in range(numDeps):
        logMasterKaps[iL][iD] = logKappa[numLams-1][iD]
#This pythonization will not work        
#masterLams[numLams: numMaster-1] = [ lambdaScale[numLams - 1] for iL in range(numLams, numMaster) ]
#logMasterKaps[numLams: numMaster-1][:] = [ [ logKappa[numLams-1][iD] for iD in range(numDeps) ] for iL in range(numLams, numMaster) ] 
           
#stop
#//Stuff for the the Teff recovery test:
#double lambda1, lambda2, fluxSurfBol, logFluxSurfBol;
fluxSurfBol = 0
 
#//Get the components for the power series expansion approximation of the Hjerting function
#//for treating Voigt profiles:
hjertComp = HjertingComponents.hjertingComponents()

#// This holds 2-element temperature-dependent base 10 logarithmic parition fn:
#for k in range(numAtmPrtTmps):
#    thisUwV[k] = 0.0 #//default initialization
thisUwV = [ 0.0 for i in range(numAtmPrtTmps) ]



listLineProf = [ [ 0.0 for i in range(numDeps) ] for j in range(listNumPoints) ]

print("Beginning spectrum synthesis, numVoigtLines ", numGaussLines)
#// Put in high res spectrum synthesis lines:
for iLine in range(numGaussLines):


    #//if H or He, make sure kappaScale is unity:
    if ((list2Element[gaussLine_ptr[iLine]] == "H")
    or (list2Element[gaussLine_ptr[iLine]] == "He")):
        zScaleList = 1.0
        #//list2Gw1[gaussLine_ptr[iLine]] = 2.0;  //fix for H lines
        if (list2Lam0[gaussLine_ptr[iLine]] <= 657.0e-7):
            list2GwL[gaussLine_ptr[iLine]] = 8.0  #//fix for Balmer lines
        else:
            list2GwL[gaussLine_ptr[iLine]] = 18.0  #//fix for Paschen lines
    else:
        zScaleList = zScale;
    

    #//
    iAbnd = 0 #//initialization
    logNums_ptr = 0
    for jj in range(nelemAbnd):
        if (list2Element[gaussLine_ptr[iLine]] == cname[jj]):
            if (list2Stage[gaussLine_ptr[iLine]] == 0):
                species = cname[jj] + "I"
                logNums_ptr = 0
                
            if (list2Stage[gaussLine_ptr[iLine]] == 1):
                species = cname[jj] + "II"
                logNums_ptr = 1
                
            if (list2Stage[gaussLine_ptr[iLine]] == 2):
                species = cname[jj] + "III"
                logNums_ptr = 4
                
            if (list2Stage[gaussLine_ptr[iLine]] == 3):
                species = cname[jj] + "IV"
                logNums_ptr = 5
                
            if (list2Stage[gaussLine_ptr[iLine]] == 4):
                species = cname[jj] + "V"
                logNums_ptr = 6
                
            if (list2Stage[gaussLine_ptr[iLine]] == 5):
                species = cname[jj] + "VI"
                logNums_ptr = 7
                
            thisUwV = PartitionFn.getPartFn2(species) #//base e log_e U
            break   #//we found it
             #}
        iAbnd+=1
    #} //jj loop
        
    list2LogNums = [ [ 0.0 for i in range(numDeps) ] for j in range(numStages+2) ]
    #for iTau in range(numDeps):
    #    list2LogNums[0][iTau] = masterStagePops[iAbnd][0][iTau]
    #    list2LogNums[1][iTau] = masterStagePops[iAbnd][1][iTau]
    #    list2LogNums[4][iTau] = masterStagePops[iAbnd][2][iTau]
    #    list2LogNums[5][iTau] = masterStagePops[iAbnd][3][iTau]
    #    list2LogNums[6][iTau] = masterStagePops[iAbnd][4][iTau]
    #    list2LogNums[7][iTau] = masterStagePops[iAbnd][5][iTau]
    list2LogNums[0] = [ masterStagePops[iAbnd][0][iTau] for iTau in range(numDeps) ]
    list2LogNums[1] = [ masterStagePops[iAbnd][1][iTau] for iTau in range(numDeps) ]
    list2LogNums[4] = [ masterStagePops[iAbnd][2][iTau] for iTau in range(numDeps) ]
    list2LogNums[5] = [ masterStagePops[iAbnd][3][iTau] for iTau in range(numDeps) ]
    list2LogNums[6] = [ masterStagePops[iAbnd][4][iTau] for iTau in range(numDeps) ]
    list2LogNums[7] = [ masterStagePops[iAbnd][5][iTau] for iTau in range(numDeps) ]
            
    numHelp = LevelPopsGasServer.levelPops(list2Lam0[gaussLine_ptr[iLine]], list2LogNums[logNums_ptr], list2ChiL[gaussLine_ptr[iLine]], thisUwV,
                    list2GwL[gaussLine_ptr[iLine]], numDeps, temp)
                              

    #for iTau in range(numDeps):
    #    list2LogNums[2][iTau] = numHelp[iTau]
    #    list2LogNums[3][iTau] = -19.0 #//upper E-level - not used - fake for testing with gS3 line treatment
    list2LogNums[2] = [ x for x in numHelp ]
    list2LogNums[3] = [ -19.0 for i in range(numDeps) ] #//upper E-level - not used - fake for testing with gS3 line treatment
    #print("iLine ", iLine, " iAbnd ", iAbnd)
    #print("list2LogNums ", list2LogNums[2])    
        #if ( (list2Element[gaussLine_ptr[iLine]] == "Na") and (list2Stage[gaussLine_ptr[iLine]] == 0) ):
            #if (iTau%5 == 1):
            #    outline = ("iTau "+ str(iTau)+ " Na I list2LogNums[2]: "+ str(log10e*list2LogNums[2][iTau]) + "\n")
            #    outHandle.write(outline)
    #if ( ((list2Lam0[gaussLine_ptr[iLine]]) > lambdaStart) and ((list2Lam0[gaussLine_ptr[iLine]]) < lambdaStop) and species=="CaI"):
    #    print("iLine ", iLine , " gaussLine_ptr ", gaussLine_ptr[iLine] ," list2Lam0 ", list2Lam0[gaussLine_ptr[iLine]], " list2LogAij ", list2LogAij[gaussLine_ptr[iLine]], " list2Logf ", list2Logf[gaussLine_ptr[iLine]])
    #    print("list2Mass ", list2Mass[gaussLine_ptr[iLine]], " list2LogGammaCol ", list2LogGammaCol[gaussLine_ptr[iLine]])

    #if ( ((list2Lam0[gaussLine_ptr[iLine]]) > lambdaStart) and ((list2Lam0[gaussLine_ptr[iLine]]) < lambdaStop) and species=="CaI"):
    #    print("list2LogNums[2] ", list2LogNums[2])             

    #//Proceed only if line strong enough: 
    #// 
    #//ifThisLine[gaussLine_ptr[iLine]] = true; //for testing
    #//No! if (ifThisLine[gaussLine_ptr[iLine]] == true){
              
    #// Gaussian only approximation to profile (voigt()):
    #//            double[][] listLinePoints = LineGrid.lineGridGauss(list2Lam0[gaussLine_ptr[iLine]], list2Mass[gaussLine_ptr[iLine]], xiT, numDeps, teff, listNumCore);
    #//            double[][] listLineProf = LineProf.gauss(listLinePoints, list2Lam0[gaussLine_ptr[iLine]],
    #//                    numDeps, teff, tauRos, temp, tempSun);
    #// Gaussian + Lorentzian approximation to profile (voigt()):
    listLinePoints = LineGrid.lineGridVoigt(list2Lam0[gaussLine_ptr[iLine]], list2Mass[gaussLine_ptr[iLine]], xiT, 
                                            numDeps, teff, listNumCore, listNumWing, species)
    #print("species: ", species)
    #if ( (list2Element[gaussLine_ptr[iLine]] == "Na") and (list2Stage[gaussLine_ptr[iLine]] == 0) ):
    #    outline = ("iLine "+ str(iLine)+ " gaussLine_ptr "+ str(gaussLine_ptr[iLine])+ " list2Lam0 "+ str(list2Lam0[gaussLine_ptr[iLine]])+ " list2LogAij "+ 
    #      str(list2LogAij[gaussLine_ptr[iLine]])+ " list2LogGammaCol "+ str(list2LogGammaCol[gaussLine_ptr[iLine]])+ " list2Logf "+ 
    #      str(list2Logf[gaussLine_ptr[iLine]]) + "\n")
    #    outHandle.write(outline)
    if (species == "HI"):
 #//System.out.println("Calling Stark...");
        listLineProf = LineProf.stark(listLinePoints, list2Lam0[gaussLine_ptr[iLine]], list2LogAij[gaussLine_ptr[iLine]],
                      list2LogGammaCol[gaussLine_ptr[iLine]],
                      numDeps, teff, tauRos, temp, pGas, newNe, tempSun, pGasSun, hjertComp, species)
    else:
        #print("voigt branch called")
        listLineProf = LineProf.voigt(listLinePoints, list2Lam0[gaussLine_ptr[iLine]], list2LogAij[gaussLine_ptr[iLine]],
                      list2LogGammaCol[gaussLine_ptr[iLine]],
                      numDeps, teff, tauRos, temp, pGas, tempSun, pGasSun, hjertComp, dbgHandle)
                
        
    listLogKappaL = LineKappa.lineKap(list2Lam0[gaussLine_ptr[iLine]], list2LogNums[2], list2Logf[gaussLine_ptr[iLine]], listLinePoints, listLineProf,
                       numDeps, zScaleList, tauRos, temp, rho, logFudgeTune)
    #print("listLogKappaL ", listLogKappaL[:][16])
    #stop                        
    #if ( (list2Element[gaussLine_ptr[iLine]] == "Na") and (list2Stage[gaussLine_ptr[iLine]] == 0) ):
    #        for iTau in range(numDeps):
    #            if (iTau%5 == 1):
    #                for iL in range(listNumPoints):
    #                    if (iL%2 == 0):
    #                        print("iTau ", iTau, " iL ", iL, " listLinePoints[0]&[1] ", listLinePoints[0][iL], " ", listLinePoints[1][iL], 
    #                              " listLineProf ", listLineProf[iL][iTau],  " listLogKappaL ", log10e*listLogKappaL[iL][iTau])
    listLineLambdas = [0.0 for i in range(listNumPoints)]
    #for il in range(listNumPoints):
    #    #// // lineProf[gaussLine_ptr[iLine]][*] is DeltaLambda from line centre in cm
    #    listLineLambdas[il] = listLinePoints[0][il] + list2Lam0[gaussLine_ptr[iLine]]
    listLineLambdas = [ x + list2Lam0[gaussLine_ptr[iLine]] for x in listLinePoints[0] ]
            

    masterLamsOut = SpecSyn.masterLambda(numLams, numMaster, numNow, masterLams, listNumPoints, listLineLambdas)
    logMasterKapsOut = SpecSyn2.masterKappa(numDeps, numLams, numMaster, numNow, masterLams, masterLamsOut, \
                                           logMasterKaps, listNumPoints, listLineLambdas, listLogKappaL)

    numNow = numNow + listNumPoints
    #numNow = numNow + listNumPoints
    #plt.plot(masterLamsOut, [logMasterKapsOut[i][12] for i in range(numNow)]) 
    #plt.plot(masterLamsOut, [logMasterKapsOut[i][12] for i in range(numNow)], '.')      
    #//update masterLams and logMasterKaps:

    for iL in range(numNow):
        masterLams[iL] = masterLamsOut[iL]
        for iD in range(numDeps):
            #//Still need to put in multi-Gray levels here:
            logMasterKaps[iL][iD] = logMasterKapsOut[iL][iD]
    #This pythoniztion does not work:       
    #masterLams[0: numNow] = [ masterLamsOut[iL] for iL in range(numNow) ]
    #logMasterKaps[0: numNow][:] = [ [ logMasterKapsOut[iL][iD] for iD in range(numDeps) ] for iL in range(numNow) ]

    #print("iLine ", iLine, " gaussLine_ptr ", gaussLine_ptr[iLine])            
  
        #//No! } //ifThisLine strength condition
#//numLines loop
print("End spectrum synthesis")        
#print("logMasterKaps ", logMasterKaps[:][16])
   
#////

if (teff <= jolaTeff):
    #//Begin loop over JOLA bands - isert JOLA oapcity into opacity spectum...
    helpJolaSum = 0.0
  
    if (ifMols == 1):

        for iJola in range(numJola):

            #//Find species in molecule set:

            for iMol in range(gsFirstMol, gsNspec):
                if (gsName[iMol] == jolaSpecies[iJola]):
                    #//System.out.println("mname " + mname[iMol]);
                    #for iTau in range(numDeps):
                    #    logNumJola[iTau] = masterMolPops[iMol][iTau]
                    logNumJola = [ x for x in masterMolPops[iMol-gsFirstMol] ]          
                    #}
                #}
            #}


            
            jolaOmega0 = MolecData.getOrigin(jolaSystem[iJola])  #//band origin ?? //Freq in Hz OR waveno in cm^-1 ??
            jolaB = MolecData.getRotConst(jolaSystem[iJola]) #// B' and b" values of upper and lower vibational state
            jolaLambda = MolecData.getWaveRange(jolaSystem[iJola]) #//approx wavelength range of band
            jolaDeltaLambda = MolecData.getDeltaLambda
            
            jolaLogF = logTiny #Default
            
            if (jolaWhichF[iJola] == "Allen"):
             
                #Band strength: Allen's Astrophysical Quantities approach
                jolaRSqu = MolecData.getSqTransMoment(jolaSystem[iJola]) #//needed for total vibrational band oscillator strength (f_v'v")
                #//Line strength factor from Allen's 4th Ed., p. 88, "script S":
                #This is practically the astrophysical tuning factor:
                jolaQuantumS = MolecData.getQuantumS(jolaSystem[iJola]) 

                #//Compute line strength, S, Allen, p. 88:
                jolaS = jolaRSqu * jolaQuantumS #//may not be this simple (need q?)
                #//Compute logf , Allen, p. 61 Section 4.4.2 - for atoms or molecules - assumes g=1 so logGf = logF:
                #//jolaLogF = logSTofHelp + Math.log(jolaOmega0) + Math.log(jolaS); //if omega0 is a freq in Hz
                #//Gives wrong result?? jolaLogF = logSTofHelp + Useful.logC() + Math.log(jolaOmega0) + Math.log(jolaS); //if omega0 is a waveno in cm^-1 
                checkgf = 303.8*jolaS/(10.0*jolaLambda[0]) #//"Numerical relation", Allen 4th, p. 62 - lambda in A
                jolaLogF = math.log(checkgf) #//better??
                #print("iJola ", iJola, " logF ", 10.0**(logE*jolaLogF+14) )
            
            if (jolaWhichF[iJola] == "Jorgensen"):
                #Band strength: Jorgensen, 1994, A&A, 284, 179 approach - we have the f values directly:
            
                #This is practically the astrophysical tuning factor:
                jolaQuantumS = MolecData.getQuantumS(jolaSystem[iJola])
            
                jolaRawF = MolecData.getFel(jolaSystem[iJola])
                jolaF = jolaRawF * jolaQuantumS
                #print(iJola, " jQS ", jolaQuantumS, " jRF ", jolaRawF, " jF ", jolaF)
                jolaLogF = math.log(jolaF)
                #print("iJola ", iJola, " logF ", 10.0**(logE*jolaLogF+14) )
            
            if (jolaDeltaLambda == 0): 
                jolaAlphP = jolaAlphP_DL0 #// alpha_P - weight of P branch (Delta J = 1)
                jolaAlphR = jolaAlphR_DL0 #// alpha_R - weight of R branch (Delta J = -1)
                jolaAlphQ = jolaAlphQ_DL0 #// alpha_Q - weight of Q branch (Delta J = 0)
        
            if (jolaDeltaLambda != 0): 
                jolaAlphP = jolaAlphP_DL1 #// alpha_P - weight of P branch (Delta J = 1)
                jolaAlphR = jolaAlphR_DL1 #// alpha_R - weight of R branch (Delta J = -1)
                jolaAlphQ = jolaAlphQ_DL1 #// alpha_Q - weight of Q branch (Delta J = 0)
        

            jolaPoints = Jola.jolaGrid(jolaLambda, jolaNumPoints)

            #//This sequence of methods might not be the best way, but it's based on the procedure for atomic lines
            #// Put in JOLA bands:

            #//P & R brnaches in every case:
            dfBydv = Jola.jolaProfilePR(jolaOmega0, jolaLogF, jolaB,
                                     jolaPoints, jolaAlphP, jolaAlphR, numDeps, temp)

            jolaLogKappaL = Jola.jolaKap(logNumJola, dfBydv, jolaPoints, 
                  numDeps, temp, rho)

#////Q branch if DeltaLambda not equal to 0
#//         if (jolaDeltaLambda != 0){ 
#//            dfBydv = Jola.jolaProfileQ(jolaOmega0, jolaLogF, jolaB,
#//                                      jolaPoints, jolaAlphQ, numDeps, temp);
#// //
#//            double[][] jolaLogKappaQL = Jola.jolaKap(logNumJola, dfBydv, jolaPoints, 
#//                   numDeps, temp, rho);
#//            //Now add it to the P & R branch opacity:
#//            for (int iW = 0; iW < jolaNumPoints; iW++){
#//               for (int iD = 0; iD < numDeps; iD++){
#//             //   //  if (iD%10 == 1){
#//              //       //System.out.println("iW " + iW + " iD " + iD + " jolaLogKappaL " + jolaLogKappaL[iW][iD]);
#//               //  // }
#//                   helpJolaSum = Math.exp(jolaLogKappaL[iW][iD]) + Math.exp(jolaLogKappaQL[iW][iD]);
#//                   jolaLogKappaL[iW][iD] = Math.log(helpJolaSum); 
#//               } //iD loop
#//            } //iW loop
#//         } //Q-branch if

            jolaLambdas = [0.0 for i in range(jolaNumPoints)]
            #for il in range(jolaNumPoints):
            #    #// // lineProf[gaussLine_ptr[iLine]][*] is DeltaLambda from line centre in cm
            #    jolaLambdas[il] = nm2cm * jolaPoints[il]
            jolaLambdas = [ nm2cm * x for x in jolaPoints ]
            #print("jolaLambdas[0] ", jolaLambdas[0], " jolaLambdas[jolaNumPoints] ", jolaLambdas[jolaNumPoints-1])
            

            masterLamsOut = SpecSyn.masterLambda(numLams, numMaster, numNow, masterLams, jolaNumPoints, jolaLambdas)
            logMasterKapsOut = SpecSyn2.masterKappa(numDeps, numLams, numMaster, numNow, masterLams, masterLamsOut, \
                                logMasterKaps, jolaNumPoints, jolaLambdas, jolaLogKappaL)
            numNow = numNow + jolaNumPoints
            #numNow = numNow + jolaNumPoints

            #//update masterLams and logMasterKaps:
            for iL in range(numNow):
                masterLams[iL] = masterLamsOut[iL]
                for iD in range(numDeps):
                    #//Still need to put in multi-Gray levels here:
                    logMasterKaps[iL][iD] = logMasterKapsOut[iL][iD]
            #This pythoniztion does not work:
            #masterLams[0: numNow] = [ masterLamsOut[iL] for iL in range(numNow) ]
            #logMasterKaps[0: numNow][:] = [ [ logMasterKapsOut[iL][iD] for iD in range(numDeps) ] for iL in range(numNow) ]
            #plt.xlim(500.0e-7, 820.0e-7)
            #plt.plot([masterLams[i] for i in range(numNow)],\
            #          [logMasterKaps[i][20] for i in range(numNow)] )    

        #} //iJola JOLA band loop

    #} //ifTiO condition

#} //jolaTeff condition
    
#//

#//Sweep the wavelength grid for line-specific wavelength points that are closer together than needed for
#//critical sampling:
#//equivalent spectral resolution of wavelength-dependent critical sampling interval
sweepRes = numpy.double(500000.0) #//equivalent spectral resolution of wavelength-dependent critical sampling interval
#//cm //use shortest wavelength to avoid under-smapling:
sweepDelta = lambdaStart / sweepRes #//cm //use shortest wavelength to avoid under-smapling
sweepHelp = [ numpy.double(0.0) for i in range(numMaster) ] #//to be truncated later
#//Initialize sweepHelp
#for iSweep in range(numMaster):
#    sweepHelp[iSweep] = 0.0
sweepHelp = [ numpy.double(0.0) for iSweep in range(numMaster) ]
   
#//
sweepHelp[0] = masterLams[0] #//An auspicous start :-)
lastLam = 0 #//index of last masterLam wavelength NOT swept out
iSweep = 1 #//current sweepHelp index
#//

for iLam in range(1, numMaster):
    #print ( "In sweeping loop: ", (masterLams[iLam] - masterLams[lastLam]) )
    if ( (masterLams[iLam] - masterLams[lastLam]) >= sweepDelta):
        #//Kept - ie. NOT swept out:
        sweepHelp[iSweep] = masterLams[iLam]
        lastLam = iLam
        iSweep+=1
        #print("Kept condition passed, iSweep ", iSweep)
      

numKept = iSweep-1
#sweptLams = [x for x in sweepHelp]
sweptLams = [numpy.double(0.0) for i in range(numKept)]
#for iKept in range(numKept):
#    sweptLams[iKept] = sweepHelp[iKept]
sweptLams = [ sweepHelp[iKept] for iKept in range(numKept) ]

#stop
#//Interpolate the total extinction array onto the swept wavelength grid:
keptHelp = [numpy.double(0.0) for i in range(numKept)]
logSweptKaps = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(numKept) ]
logMasterKapsId = [numpy.double(0.0) for i in range(numMaster)]
#Not trivially pythonizable:
for iD in range(numDeps):
    #//extract 1D kappa vs lambda at each depth:
    for iL in range(numMaster):
        logMasterKapsId[iL] = logMasterKaps[iL][iD]
      
    #keptHelp = ToolBox.interpolV(logMasterKapsId, masterLams, sweptLams)
    keptHelp = numpy.interp(sweptLams, masterLams, logMasterKapsId)
    for iL in range(numKept):
        logSweptKaps[iL][iD] = keptHelp[iL]

#Won't work logSweptKaps = [ [ ToolBox.interpolV(logMasterKaps[iL][iD], masterLams, sweptLams) for iL in range()] ]

#} //iD loop
    

#Special code to test sweeper by forcing it to NOT sweep anything:
    # - IF this is uncommented, then sweeper above should be commented
"""for iLam in range(1, numMaster):
    #//Kept - ie. NOT swept out:
    sweepHelp[iSweep] = masterLams[iLam]
    iSweep+=1
numKept = iSweep-1
sweptLams = [0.0 for i in range(numKept)]
for iKept in range(numKept):
    sweptLams[iKept] = sweepHelp[iKept]
#//Interpolate the total extinction array onto the swept wavelength grid:
logSweptKaps = [ [ 0.0 for i in range(numDeps) ] for j in range(numKept) ]
for iD in range(numDeps):
    for iL in range(numKept):
        logSweptKaps[iL][iD] = logMasterKaps[iL][iD]
#end special sweeper test block"""
# doesn't work  ipdb.set_trace(pdb debug command  

##Debug:
#print("numLams ", numLams, " numKept ", numKept)
#print("logKappa[:][36]")
#for iL in range(0, numLams, 10):
#    print(lambdaScale[iL], logKappa[iL][36])
#print("logSweptKaps[:][36]")
#for iL in range(0, numKept, 10):
#    print(sweptLams[iL], logSweptKaps[iL][36])
#plt.figure()
#plt.subplot(1,1,1)
#plt.plot(lambdaScale, [logKappa[iL][36] for iL in range(numLams) ], linewidth=3 )
#plt.plot(sweptLams, [logSweptKaps[iL][36] for iL in range(numKept) ], '--' )  

#//
#////
#//Continuum monochromatic optical depth array:
logTauCont = LineTau2.tauLambdaCont(numLams, logKappa,
                 kappa500, numDeps, tauRos, logTotalFudge)



#//Evaluate formal solution of rad trans eq at each lambda 
#// Initial set to put lambda and tau arrays into form that formalsoln expects
#Untransited I_lambda(cosTheta)
contIntens = [ [ numpy.double(0.0) for i in range(numThetas) ] for j in range(numLams) ]
contIntensLam = [numpy.double(0.0) for i in range(numThetas)]

contFlux = [ [ numpy.double(0.0) for i in range(numLams) ] for j in range(2) ]
contFluxLam = [numpy.double(0.0) for i in range(2)]
thisTau = [ [ numpy.double(0.0) for i in range(numDeps) ] for j in range(2) ]
lineMode = False  #//no scattering for overall SED

##For testing:
#thisR = [0.0 for i in range(numThetas)]
#for iT in range(numThetas):
#    thisTheta = math.acos(cosTheta[1][iT])
#    thisR[iT] = math.sin(thisTheta)

for il in range(numLams):

    #for id in range(numDeps):
    #    thisTau[1][id] = logTauCont[il][id]
    #    thisTau[0][id] = math.exp(logTauCont[il][id])
    thisTau[1] = [ numpy.double(x) for x in logTauCont[il] ]
    thisTau[0] = [ numpy.double(math.exp(x)) for x in logTauCont[il] ]
    #} // id loop

    contIntensLam = FormalSoln.formalSoln(numDeps,
                    cosTheta, lambdaScale[il], thisTau, temp, lineMode)
    
#    if (il == 87):
#        print("plot lambda = ", 1.0e7*lambdaScale[il])
#        plt.plot(thisR, contIntensLam/contIntensLam[0])


    contIntens[il] = [ numpy.double(x) for x in contIntensLam ]
    

    #//// Teff test - Also needed for convection module!:
    if (il > 1):
        lambda2 = lambdaScale[il] #// * 1.0E-7;  // convert nm to cm
        lambda1 = lambdaScale[il - 1] #// * 1.0E-7;  // convert nm to cm
        fluxSurfBol = fluxSurfBol + contFluxLam[0] * (lambda2 - lambda1)

#//il loop

#Untransited flux
contFlux = Flux.flux3(contIntens, lambdaScale, cosTheta, phi, cgsRadius, omegaSini, macroVkm)
   
contFluxTrans = [ [ [ numpy.double(0.0) for i in range(numTransThetas) ] for k in range(numLams) ] for j in range(2) ]
contFluxTrans2 = [ [ [ numpy.double(0.0) for i in range(numTransThetas2) ] for k in range(numLams) ] for j in range(2) ]
#fluxTransMA hold the monochromatic "F(z)" lightcurve from Mandel & Agol (2002) for test comparison
#  at arbitrary wavelength of choice
fluxTransMA = [0.0 for i in range(numTransThetas)]
fluxTransMA2 = [0.0 for i in range(numTransThetas2)]
#Index of comparison wavelength
ilMA = ToolBox.lamPoint(numLams, lambdaScale, 5.51e-5)
print("MA lamba ", lambdaScale[ilMA])
#In Mandel & Agol (2002), "I" is intensity relative to disk centre:
relContIntens = [x/contIntens[ilMA][0] for x in contIntens[ilMA]]

if (ifTransit):               
    contFluxTrans = FluxTrans.fluxTrans(contIntens, contFlux, lambdaScale, cosTheta, 
          radius, iFirstTheta, numTransThetas, rPlanet)
    fluxTransMA = TransitLightCurveAnlytc2.transLightAnlytc2(relContIntens, radius, pMA, cosTheta, vTrans, iFirstTheta, numTransThetas, impct)
    #reflect the half-transit profile and add the first and last points for
    #ingress and egress
    for j in range(numLams):
        #lens-shaped occultation area at planetary mid-point contact:
        #Ingress:
        #Subtracting the very small from the very large - let's be sophisticated about it:
        logHelper = math.log(math.pi) + math.log(contIntens[j][numThetas-1]) + logOmegaLens - contFlux[1][j]
        helper = numpy.double(1.0) - math.exp(logHelper)        
        contFluxTrans2[1][j][0] = contFlux[1][j]
        contFluxTrans2[0][j][0] = contFlux[0][j]
        contFluxTrans2[1][j][1] = contFlux[1][j] + math.log(helper)
        contFluxTrans2[0][j][1] = math.exp(contFluxTrans2[1][j][1]) 
        #Full occultation:
        #Ingress to minimum impact parameter          
        for i in range(numTransThetas):
            indx = ( (numTransThetas-1)-i )
            contFluxTrans2[1][j][2+i] = contFluxTrans[1][j][indx]
            contFluxTrans2[0][j][2+i] = contFluxTrans[0][j][indx]
        #Minimum impact parameter to egress
        for i in range(numTransThetas):
            contFluxTrans2[1][j][2+(numTransThetas+i)] = contFluxTrans[1][j][i]
            contFluxTrans2[0][j][2+(numTransThetas+i)] = contFluxTrans[0][j][i]
        #Egress:
        contFluxTrans2[1][j][numTransThetas2-2] = contFlux[1][j] + math.log(helper)
        contFluxTrans2[0][j][numTransThetas2-2] = math.exp(contFluxTrans2[1][j][numTransThetas2-2])
        contFluxTrans2[1][j][numTransThetas2-1] = contFlux[1][j]
        contFluxTrans2[0][j][numTransThetas2-1] = contFlux[0][j]  

#Comparison light curve from Mandel & Agol formula
    #Ingress
    fluxTransMA2[0] = 1.0
    fluxTransMA2[1] = 1.0
    #Full occultation:
    #Ingress to minimum impact parameter          
    for i in range(numTransThetas):
        indx = ( (numTransThetas-1)-i )
        fluxTransMA2[2+i] = fluxTransMA[indx]
        fluxTransMA2[2+i] = fluxTransMA[indx]
        #print("2+i ", 2+i, " fluxTransMA2 ", fluxTransMA2[2+i])
    #Minimum impact parameter to egress
    for i in range(numTransThetas):
        fluxTransMA2[2+(numTransThetas+i)] = fluxTransMA[i]
        fluxTransMA2[2+(numTransThetas+i)] = fluxTransMA[i]
        #print("2+(numTransThetas+i) ", 2+(numTransThetas+i), " fluxTransMA2 ", fluxTransMA2[2+(numTransThetas+i)])
    #Egress        
    fluxTransMA2[numTransThetas2-2] = 1.0
    fluxTransMA2[numTransThetas2-1] = 1.0            
        
logTauMaster = LineTau2.tauLambda(numKept, sweptLams, logSweptKaps,
                numDeps, kappa500, tauRos, logTotalFudge)

#//Line blanketed formal Rad Trans solution:
#//Evaluate formal solution of rad trans eq at each lambda throughout line profile
#// Initial set to put lambda and tau arrays into form that formalsoln expects
#Untransited I_lambda(cosTheta)
masterIntens = [ [ numpy.double(0.0) for i in range(numThetas) ] for j in range(numKept) ] 
#Transited I_lambda(cosTheta)
#masterIntensTrans = [ [ numpy.double(0.0) for i in range(numThetas) ] for j in range(numKept) ] 
masterIntensLam = [numpy.double(0.0) for i in range(numThetas)]

masterFlux = [ [ numpy.double(0.0) for i in range(numKept) ] for j in range(2) ]
masterFluxLam = [numpy.double(0.0) for i in range(2)]

lineMode = False  #//no scattering for overall SED

for il in range(numKept):

#//                        }
    #for id in range(numDeps):
    #    thisTau[1][id] = logTauMaster[il][id]
    #    thisTau[0][id] = math.exp(logTauMaster[il][id])
    #} // id loop
    thisTau[1] = [ numpy.double(x) for x in logTauMaster[il] ]
    thisTau[0] = [ numpy.double(math.exp(x)) for x in logTauMaster[il] ]

    masterIntensLam = FormalSoln.formalSoln(numDeps,
                cosTheta, sweptLams[il], thisTau, temp, lineMode)


    #for it in range(numThetas):
    #    masterIntens[il][it] = masterIntensLam[it]
    masterIntens[il] = [ numpy.double(x) for x in masterIntensLam ]


#} //it loop - thetas


#} //il loop

#Untransited flux
masterFlux = Flux.flux3(masterIntens, sweptLams, cosTheta, phi, cgsRadius, omegaSini, macroVkm)

masterFluxTrans = [ [ [ numpy.double(0.0) for i in range(numTransThetas) ] for k in range(numKept) ] for j in range(2) ]
masterFluxTrans2 = [ [ [ numpy.double(0.0) for i in range(numTransThetas2) ] for k in range(numKept) ] for j in range(2) ]

if (ifTransit):
    masterFluxTrans = FluxTrans.fluxTrans(masterIntens, masterFlux, sweptLams, cosTheta, 
          radius, iFirstTheta, numTransThetas, rPlanet)
    #reflect the half-transit profile and add the first and last points just before
    #ingress and just after egress    
    for j in range(numKept):  
        #lens-shaped occultation area at planetary mid-point contact:
        #Ingress:
        #Subtracting the very small from the very large - let's be sophisticated about it:        
        logHelper = math.log(masterIntens[j][numThetas-1]) + logOmegaLens - masterFlux[1][j]
        helper = numpy.double(1.0) - math.exp(logHelper)                
        masterFluxTrans2[1][j][0] = masterFlux[1][j]
        masterFluxTrans2[0][j][0] = masterFlux[0][j] 
        masterFluxTrans2[1][j][1] = masterFlux[1][j] + math.log(helper)
        masterFluxTrans2[0][j][1] = math.exp(masterFluxTrans2[1][j][1])  
        #Full occultation:
        #Ingress to minimum impact parameter                 
        for i in range(numTransThetas):
            masterFluxTrans2[1][j][2+i] = masterFluxTrans[1][j][(numTransThetas-1)-i]
            masterFluxTrans2[0][j][2+i] = masterFluxTrans[0][j][(numTransThetas-1)-i]
        #Minimum impact parameter to egress
        for i in range(numTransThetas):
            masterFluxTrans2[1][j][2+(numTransThetas+i)] = masterFluxTrans[1][j][i]
            masterFluxTrans2[0][j][2+(numTransThetas+i)] = masterFluxTrans[0][j][i]
        #Egress:
        masterFluxTrans2[1][j][numTransThetas2-2] = masterFlux[1][j] + math.log(helper)
        masterFluxTrans2[0][j][numTransThetas2-2] = math.exp(masterFluxTrans2[1][j][numTransThetas2-2])            
        masterFluxTrans2[1][j][numTransThetas2-1] = masterFlux[1][j]
        masterFluxTrans2[0][j][numTransThetas2-1] = masterFlux[0][j]              
            
#pltb.plot(sweptLams, masterFlux[0])
#plt.plot(sweptLams, masterFlux[0], '.')

#Can we find a pythonic way to accumulate instead of this for loop??
for il in range(numKept):
    #//// Teff test - Also needed for convection module!:
    if (il > 1):
        lambda2 = sweptLams[il] #// * 1.0E-7;  // convert nm to cm
        lambda1 = sweptLams[il - 1] #// * 1.0E-7;  // convert nm to cm
        fluxSurfBol = fluxSurfBol + masterFlux[0][il] * (lambda2 - lambda1)
    #}

logFluxSurfBol = math.log(fluxSurfBol)
logTeffFlux = (logFluxSurfBol - Useful.logSigma()) / 4.0
teffFlux = math.exp(logTeffFlux)

print("Recovered Teff = %9.2f" % (teffFlux))

#//Extract linear monochromatic continuum limb darkening coefficients (LDCs) ("epsilon"s):
ldc = [0.0 for i in range(numLams)]
ldc = LDC.ldc(numLams, lambdaScale, numThetas, cosTheta, contIntens)


#
#
#
#
#   Post-processing
#
# *****   Post-processing ported from ChromaStarServerUI  *****
#
#
#
#
#
#



#logContFluxI = ToolBox.interpolV(contFlux[1], lambdaScale, sweptLams)
logContFluxI = numpy.interp(sweptLams, lambdaScale, contFlux[1])

#//Quality control:

#iStart = ToolBox.lamPoint(numMaster, masterLams, (nm2cm*lambdaStart))
#iStop = ToolBox.lamPoint(numMaster, masterLams, (nm2cm*lambdaStop))
iStart = ToolBox.lamPoint(numKept, sweptLams, lambdaStart);
iStop = ToolBox.lamPoint(numKept, sweptLams, lambdaStop);
   
#//Continuum rectification
numSpecSyn = iStop - iStart + 1
specSynLams = [0.0 for i in range(numSpecSyn)]
specSynFlux = [ [ 0.0 for i in range(numSpecSyn) ] for j in range(2) ]
#js specSynFlux.length = 2;
#specSynFlux[0] = [];
#specSynFlux[1] = [];
#specSynFlux[0].length = numSpecSyn; 
#specSynFlux[1].length = numSpecSyn;
#for iCount in range(numSpecSyn):
#    specSynLams[iCount] = sweptLams[iStart+iCount]
#    specSynFlux[1][iCount] = masterFlux[1][iStart+iCount] - logContFluxI[iStart+iCount]
#   specSynFlux[0][iCount] = math.exp(specSynFlux[1][iCount])
    
specSynLams = [ x for x in sweptLams[iStart: iStart+numSpecSyn] ]
specSynFlux[1] = [ (masterFlux[1][iStart+iCount] - logContFluxI[iStart+iCount]) for iCount in range(numSpecSyn) ]
#print("log masterFlux")
#print([masterFlux[1][iStart+iCount] for iCount in range(numSpecSyn)])
#print("logContFluxI")
#print([logContFluxI[iStart+iCount] for iCount in range(numSpecSyn)])
specSynFlux[0] = [math.exp(x) for x in specSynFlux[1] ]

#//
#// * eqWidthSynth will try to return the equivalenth width of EVERYTHING in the synthesis region
#// * as one value!  Isolate the synthesis region to a single line to a clean result
#// * for that line!
#// *
Wlambda = PostProcess.eqWidthSynth(specSynFlux, specSynLams)

#//
#//Radial velocity correction:
#//We have to correct both masterLams AND specSynLams to correct both the overall SED and the spectrum synthesis region:

masterLams2 = [ 0.0 for i in range(numKept) ]
specSynLams2 = [ 0.0 for i in range(numSpecSyn) ]

#//refresh default each run:
#for i in range(numKept):
#    masterLams2[i] = sweptLams[i]
masterLams2 = [ x for x in sweptLams ]
     
#for i in range(numSpecSyn):
#    specSynLams2[i] = specSynLams[i]
specSynLams2 = [ x for x in specSynLams ] 
    
deltaLam = 0.0
c = 2.9979249E+10 #// light speed in vaccuum in cm/s
RVfac = RV / (1.0e-5*c)
if (RV != 0.0):
    #for i in range(numKept):
    #    deltaLam = RVfac * sweptLams[i]
    #    masterLams2[i] = masterLams2[i] + deltaLam
    masterLams2 = [ masterLams2[i] + (RVfac * sweptLams[i]) for i in range(numKept) ]
      
    #for i in range(numSpecSyn):
    #    deltaLam = RVfac * specSynLams[i]
    #    specSynLams2[i] = specSynLams2[i] + deltaLam 
    specSynLams2 = [ specSynLams2[i] + (RVfac * specSynLams[i])  ]   
     
invnAir = 1.0 / 1.000277 #// reciprocal of refractive index of air at STP 
if (vacAir == "air"):
    #for i in range(numKept):
    #    masterLams2[i] = invnAir * masterLams2[i]
    masterLams2 = [ invnAir * x for x in masterLams2 ]
       
    #for i in range(numSpecSyn):
    #    specSynLams2[i] = invnAir * specSynLams2[i]
    specSynLams2 = [ invnAir * x for x in specSynLams2 ]   
     

bandFlux =  PostProcess.UBVRIraw(masterLams2, masterFlux)
colors =  PostProcess.UBVRI(bandFlux)
#print("U-V: ", colors[0], " B-V: ", colors[1], " V-R ", colors[2], " V-I: ", colors[3],\
#      " R-I ", colors[4], " V- K ", colors[5], " J-K: ", colors[6])
print("U-B: %6.2f B-V: %6.2f V-R: %6.2f V-I: %6.2f R-I: %6.2f V-K: %6.2f J-K: %6.2f" %\
      (colors[0], colors[1], colors[2], colors[3], colors[4], colors[5], colors[6]))
#// UBVRI band intensity annuli - for disk rendering:
bandIntens = PostProcess.iColors(masterLams2, masterIntens, numThetas, numKept) 
    
gaussFilter = PostProcess.gaussian(masterLams2, numKept, diskLambda, diskSigma, lamUV, lamIR) 
#//Use *shifted* wavelength scale (masterLams2) for user-filter integration of spectrum:
tuneBandIntens = PostProcess.tuneColor(masterLams2, masterIntens, numThetas, numKept, \
                                       gaussFilter, lamUV, lamIR) 

    
    
#//Fourier transform of narrow band image:
ft = PostProcess.fourier(numThetas, cosTheta, tuneBandIntens)
numK = len(ft[0])

if ifTransit:
    #Planetary transit light curves as seen through photometric filters:
    numBands = len(bandFlux)
    bandFluxTransit = [[0.0 for i in range(numTransThetas2)] for j in range(numBands)]
    #Sign - I don't know how to directly assign a 2D list column slice (2nd index):
    helpBandFlux = [0.0 for i in range(numBands)]
    helpMasterFlux = [[0.0 for i in range(numKept)] for j in range(2)]

    for iEpoch in range(numTransThetas2):
        for il in range(numKept):
            helpMasterFlux[1][il] = masterFluxTrans2[1][il][iEpoch]
            helpMasterFlux[0][il] = masterFluxTrans2[0][il][iEpoch]
        helpBandFlux = PostProcess.UBVRIraw(masterLams2, helpMasterFlux)
        for iBand in range(numBands):
            bandFluxTransit[iBand][iEpoch] = helpBandFlux[iBand]

    bandFluxTransit2 = [[0.0 for i in range(numEpochs)] for j in range(numBands)]        
    #Interpolate transit light curves onto total duration we are following: 
    for iBand in range(numBands):
        bandFluxTransit2[iBand] = ToolBox.interpolV(bandFluxTransit[iBand], transit2, ephemT) 

    #Interpolate reference light curve from Mandel & Agol (2002) too:

    fluxTransMA2i =  ToolBox.interpolV(fluxTransMA2, transit2, ephemT)

    #for i in range(numEpochs):
    #    print("i ", i, " fluxTransMA2i ", fluxTransMA2i[i])      
        
#
#
# Report 1:
#
#
#Atmospheric structure output: 
#Convert everything to log_10 OR re-scaled units for plotting, printing, etc:
    

log10temp = [0.0 for i in range(numDeps)]
log10rho = [0.0 for i in range(numDeps)]
log10kappaRos = [0.0 for i in range(numDeps)]
log10kappa500 = [0.0 for i in range(numDeps)]
mmwAmu = [0.0 for i in range(numDeps)]
depthsKm = [0.0 for i in range(numDeps)]
#log10mmw = [0.0 for i in range(numDeps)]
#for i in range(numDeps):
#    log10tauRos[i] = log10e * tauRos[1][i]
#    log10temp[i] = log10e * temp[1][i]
#    log10pgas[i] = log10e * pGas[1][i]
#    log10pe[i] = log10e * (newNe[1][i] + Useful.logK() + temp[1][i])
#    log10prad[i] = log10e * pRad[1][i]
#    log10ne[i] = log10e * newNe[1][i]
#    log10rho[i] = log10e * rho[1][i]
#    log10NH[i] = log10e * logNH[i]
#    log10kappaRos[i] = log10e * kappaRos[1][i]
#    log10kappa500[i] = log10e * kappa500[1][i]
#    mmwAmu[i] = mmw[i] / Useful.amu()
#    depthsKm[i] = 1.0e-5 * depths[i]

log10tauRos = [ round(log10e * x, 4) for x in tauRos[1] ]
log10temp = [ round(log10e * x, 4) for x in temp[1] ]
log10pgas = [ round(log10e * x, 4) for x in pGas[1] ]
log10pe = [ round(log10e * (newNe[1][i] + Useful.logK() + temp[1][i]), 4) for i in range(numDeps) ]
log10prad = [ round(log10e * x, 4) for x in pRad[1] ]
log10ne = [ round(log10e * x, 4) for x in newNe[1] ]
log10rho = [ round(log10e * x, 4) for x in rho[1] ]
log10NH = [ round(log10e * x, 4) for x in logNH ]
log10kappaRos = [ round(log10e * x, 4) for x in kappaRos[1] ]
log10kappa500 = [ round(log10e * x, 4) for x in kappa500[1] ]
mmwAmu = [ round(x / Useful.amu(), 4) for x in mmw ]
depthsKm = [ round(1.0e-5 * x, 4) for x in depths ]

#outFile = outPath + strucFile
outFile = outPath + fileStem + ".struc.txt"
#print vertical atmospheric structure
#with open(outFile, 'w', encoding='utf-8') as strucHandle:
with open(outFile, 'w') as strucHandle:
#with open(strucFile, 'w') as strucHandle:    
    strucHandle.write(inputParamString + "\n")
    strucHandle.write("cgs units, unless otherwise noted" + "\n")
    strucHandle.write("logTauRos   depth   temp   logPgas   logPe  logPRad   logNe   logNH   logRho   mu(amu)   logKapRos   logKap500" + "\n")
    #NOt trivially pythonizable - each time through it writes a line to an output file
    for i in range(numDeps):
        outLine = str(log10tauRos[i]) + "   " + str(depthsKm[i]) + "   " + str(round(temp[0][i], 4)) + "   " + str(log10pgas[i]) +\
        "   " + str(log10pe[i]) + "   " + str(log10prad[i]) + "   " + str(log10ne[i]) + "   " + str(log10NH[i]) + "   " + str(log10rho[i]) +\
        "   " + str(mmwAmu[i]) + "   " + str(log10kappaRos[i]) + "   " + str(log10kappa500[i]) + "\n"
        strucHandle.write(outLine)
    #This doesn't work...
    #outLine = ""
    #outLine = [ outLine + str(log10tauRos[i]) + " " + str(depthsKm[i]) + " " + str(temp[0][i]) + " " + str(log10pgas[i]) + " " + str(log10pe[i]) +   \
    #                  " " + str(log10prad[i]) + " " + str(log10ne[i]) + " " + str(log10NH[i]) + " " + str(log10rho[i]) + " " + str(mmwAmu[i]) +   \
    #                  str(log10kappaRos[i]) + " " + str(log10kappa500[i]) + "\n" for i in range(numDeps) ]
    #strucHandle.write(outLine)

if makePlotStruc:
    
    plt.figure()
    plt.subplot(1, 1, 1)

    #Initialplot set-up
    plt.title = "T_kin vs log(tau)"
    plt.xlabel(r'$\log_{10} \tau_{\rm ROs}$')
    plt.ylabel(r'$T_{\rm kin}$ (K)')
    xMin = -6.5
    xMax = 2.5
    plt.xlim(xMin, xMax)
    yMax = max(temp[0]) + 1000.0
    yMin = min(temp[0]) - 500.0
    plt.ylim(yMin, yMax)
    plt.plot(log10tauRos, temp[0])    
    
    


#
#
# Report 2: 
#
#
#Print absolute spectral energy distribution (SED)

    
numWave = numKept
wave = [0.0 for i in range(numWave)]
log10Wave = [0.0 for i in range(numWave)]
log10Flux = [0.0 for i in range(numWave)]
#for i in range(numWave):
#    wave[i] = cm2nm * masterLams2[i]
#    log10Wave[i] = math.log10(masterLams2[i])
#    log10Flux[i] = log10e * masterFlux[1][i]
wave = [ round(cm2nm * x, 4) for x in masterLams2 ]
log10Wave = [ round(math.log10(x), 4) for x in masterLams2 ]
log10Flux = [ round(log10e * x, 4) for x in masterFlux[1] ]
#Debug
#log10WaveC = [ round(math.log10(x), 4) for x in lambdaScale ]
#log10FluxC = [ round(log10e * x, 4) for x in contFlux[1] ]
#log10WaveCI = [ round(math.log10(x), 4) for x in sweptLams ]
#log10FluxCI = [ round(log10e * x, 4) for x in logContFluxI ]


if makePlotSED:

    plt.figure()
    plt.subplot(1, 1, 1)    
    
    #Initial plt plot set-up
    plt.title = "Spectral energy distribution (SED)"
    plt.xlabel(r'$\log_{10} \lambda$ (cm)')
    plt.ylabel(r'$\log_{10} F_\lambda$ (erg s$^{-1}$ cm$^{-2}$ cm$^{-1}$')
    xMin = min(log10Wave) - 0.1
    xMax = max(log10Wave) + 0.1
    plt.xlim(xMin, xMax)
    yMax = max(log10Flux) + 0.5
    yMin = min(log10Flux) - 0.5
    plt.ylim(yMin, yMax)
    plt.plot(log10Wave, log10Flux, linewidth=3)  
    #Debug
    #plt.plot(log10WaveC, log10FluxC, "--", linewidth = 2)
    #plt.plot(log10WaveCI, log10FluxCI, "-.")

#outFile = outPath + sedFile
outFile = outPath + fileStem + ".sed.txt"
#with open(outFile, 'w', encoding='utf-8') as sedHandle:
with open(outFile, 'w') as sedHandle:
#with open(sedFile, 'w') as sedHandle:
    sedHandle.write(inputParamString)
    sedHandle.write("Number of lines treated with Voigt profiles: " + str(numGaussLines) + "\n")
    sedHandle.write("Number of wavelength points: " + str(numKept) + "\n")
    sedHandle.write("wave (nm)    log10(flux) (cgs) \n")
    for i in range(numKept):
        flux = log10Flux[i]
        outLine = str(wave[i]) + "   " + str(flux) + "\n"
        sedHandle.write(outLine)

   

 
#
#
# Report 3:       
#synthetic spectrum quantities
#
#

waveSS = [0.0 for i in range(numSpecSyn)]
#for i in range(numSpecSyn):
#    waveSS[i] = cm2nm * specSynLams2[i]
waveSS = [ round(cm2nm * x, 4) for x in specSynLams2 ]
    
print("Number of lines treated with Voigt profiles: ", numGaussLines)

#Print rectified high resolution spectrum of synthesis region
#outFile = outPath + specFile
outFile = outPath + fileStem + ".spec.txt"
#with open(outFile, 'w', encoding='utf-8') as specHandle:
with open(outFile, 'w') as specHandle:
#with open(specFile, 'w') as specHandle:    
    specHandle.write(inputParamString + "\n")
    specHandle.write("Number of lines treated with Voigt profiles: " + str(numGaussLines) + "\n")
    specHandle.write("Number of wavelength points: " + str(numSpecSyn) + "\n")
    specHandle.write("wave (nm)     normalized flux \n")
    for i in range(numSpecSyn):
        outLine = str(waveSS[i]) + "   " + str(round(specSynFlux[0][i], 4)) + "\n"
        specHandle.write(outLine)
#With line ID labels:
    specHandle.write(" ")
    specHandle.write("lambda_0 species\n")
    for i in range(numGaussLines):
        thisLam = cm2nm * list2Lam0[gaussLine_ptr[i]]
        thisLam = round(thisLam, 2)
        thisLbl = list2Element[gaussLine_ptr[i]] + " " + \
        list2StageRoman[gaussLine_ptr[i]] + " " + str(thisLam)
        outLine = str(thisLam) + "   " + thisLbl + "\n"
        specHandle.write(outLine)    


if makePlotSpec:

    plt.figure()
    plt.subplot(1, 1, 1)    
    
    plt.xlabel(r'$\lambda$ (nm)')
    plt.ylabel(r'$F_\lambda/F^C_\lambda$')
    plt.xlim(-6.5, 2.5)
    plt.title = "Synthetic spectrum"
    xMin = min(waveSS)
    xMax = max(waveSS)
    plt.xlim(xMin, xMax)
    plt.ylim(0.0, 2.0)
    plt.plot(waveSS, specSynFlux[0])
    #Add spectral line labels:
    for i in range(numGaussLines):
        thisLam = cm2nm * list2Lam0[gaussLine_ptr[i]]
        thisLam = round(thisLam, 2)
        thisLbl = list2Element[gaussLine_ptr[i]] + " " + \
        list2StageRoman[gaussLine_ptr[i]] + " " + str(thisLam)
        xPoint = [thisLam, thisLam]
        yPoint = [1.05, 1.1]
        plt.plot(xPoint, yPoint, color='black')
        plt.text(thisLam, 1.7, thisLbl, rotation=270)
    


#
#
# Report 4:
#
#
#Print narrow band Gaussian filter quantities: 
#    limb darkening curve (LDC) and discrete fourier cosine transform of LDC

normTuneBandIntens = [ x / tuneBandIntens[0] for x in tuneBandIntens ] 
#outFile = outPath + ldcFile
outFile = outPath + fileStem + ".ldc.txt"
#with open(outFile, 'w', encoding='utf-8') as ldcHandle:
with open(outFile, 'w') as ldcHandle:
#with open(ldcFile, 'w') as ldcHandle:    
    ldcHandle.write(inputParamString)
    ldcHandle.write("Narrow band limb darkening curve (LDC) \n")
    ldcHandle.write("cos(theta)     I(mu)/I(0) \n")
    for i in range(numThetas):
        outLine = str(round(cosTheta[1][i], 4)) + "   " + str(round(normTuneBandIntens[i], 4)) + "\n" 
        ldcHandle.write(outLine)
    
    ldcHandle.write("\n ")    
    ldcHandle.write("Discrete fourier cosine transform of LDC \n")
    ldcHandle.write("k (RAD/RAD)     I(k) \n")
    for i in range(numK):
        outLine = str(round(ft[0][i], 4)) + "   " + str(round(ft[1][i], 4)) + "\n"
        ldcHandle.write(outLine)
        
    ldcHandle.write("\n ")    
    ldcHandle.write("Monochromatic continuum linear limb darkening coefficients (LDCs) \n")
    ldcHandle.write("Wavelength (nm)     LDC \n")
    for i in range(numK):
        outLine = str(wave[i]) + "   " + str(round(ldc[i], 4)) + "\n"
        ldcHandle.write(outLine)
        


#narrow band limb darkening curve (LDC)

if makePlotLDC:        

    plt.figure()
    plt.subplot(1, 1, 1)    
    
    plt.title = "Narrow band limb darkening"
    plt.xlabel(r'$cos\theta$ (RAD)')
    plt.ylabel(r'$I^{\rm C}_{\rm band}/I^{\rm C}_{\rm band}(0)$')
    plt.xlim(-0.1, 1.1)
    plt.ylim(0, 1.1)
    plt.plot(cosTheta[1], normTuneBandIntens)
    
#discrete fourier cosine transform of LDC

if makePlotFT:
    
    plt.figure()
    plt.subplot(1, 1, 1)    
    
    plt.title = "Fourier cosine transform of I_lambda(theta)"
    plt.xlabel('Angular frequency (RAD/RAD)')
    plt.ylabel(r'$I^{\rm C}_{\rm band}(\theta)$')
    xMin = 0.9 * min(ft[0])
    xMax = 1.1 * max(ft[0])
    plt.xlim(xMin, xMax)
    yMin = 0.9 * min(ft[1])
    yMax = 1.1 * max(ft[1])
    plt.ylim(yMin, yMax)
    plt.plot(ft[0], ft[1])
    
#
#
# Report 6:
#
#   
#//
#//"""
#Print partial pressures of atomic and molecular species
    #Mostly now from Phil Bennett's GAS apckage
#outFile = outPath + lineFile
#print(" **** Report 6!!!! **** ")
outFile = outPath + fileStem + ".ppress.txt"
#with open(outFile, 'w', encoding='utf-8') as tlaHandle:
with open(outFile, 'w') as ppHandle:    
#with open(tlaFile, 'w') as tlaHandle:
    ppHandle.write(inputParamString + "\n")
    ppHandle.write("Log_10 partial pressures every 10th depth: \n")
    for iD in range(0, numDeps): 
        ppHandle.write("log_10(Tau_Ros) " + str(log10tauRos[iD]) + " T_Kin " + str(log10temp[iD]) +\
                               " (K) log_10(P_Gas) " + str(log10pgas[iD]) +\
                               " (dynes/cm^2) log_10(P_e) " + str(log10pe[iD]) + "\n" )
        for iSpec in range(gsNspec):
            ppHandle.write(gsName[iSpec] + " " + \
                               str(round(log10MasterGsPp[iSpec][iD], 4)) + " ")
        ppHandle.write("\n")
        #print("R6 ", (10.0**log10MasterGsPp[0][iD])/(10.0**log10pgas[iD]))
        
        
#spectral line of user-defined 2-level atom

if makePlotPPress:

    plt.figure()
    plt.subplot(1, 1, 1)    
    
    whichSpec = Input.plotSpec
    for thisSpec in range(gsNspec):
        if (gsName[thisSpec].strip() == whichSpec.strip()):
            break;
            
    plt.title = "Log_10 Partial pressure: " + gsName[thisSpec]
    plt.xlabel(r'$\log\tau$')
    plt.ylabel(r'$\log P$ (dynes cm$^{-2}$')
    xMin = logE * min(tauRos[1])
    xMax = logE * max(tauRos[1])
    yMin = min(log10MasterGsPp[thisSpec])
    yMax = max(log10MasterGsPp[thisSpec])
    plt.xlim(xMin, xMax)
    plt.ylim(yMin, yMax)
    plt.plot(log10tauRos, log10MasterGsPp[thisSpec])
    #print(log10tauRos)
    #print(log10MasterGsPp[thisSpec])    
    
#
#
# Report 7:
#
if (ifTransit and makePlotTrans):
    #   
    #//Exo-planet Transit light curves through UBVRIK 
    plt.figure()
    plt.subplot(1, 1, 1)   

    #Initialplot set-up
    plt.title = "Exoplanet transit light curve"
    plt.xlabel(r'Time (hrs)')
    plt.ylabel(r'Relative flux')
    #xMin = 
    #xMax = 
    #plt.xlim(xMin, xMax)
    yMin = 0.0
    yMax = 1.0

    yMinUV = min(bandFluxTransit2[0])/bandFluxTransit2[0][0] #minimum UV flux during transit
    yMinIR = min(bandFluxTransit2[numBands-1])/bandFluxTransit2[numBands-1][0] #minimum IR flux during transit
    yMinMA = min(fluxTransMA2i)
    yMin = min([yMinUV, yMinIR, yMinMA]) # minimum of the two
    yMax = 1.0 + (1.0 - yMin)
    
    textStep = (xMax-xMin)/10.0
    #print("yminUV ", yMinUV, " yminIR ", yMinIR, " ymin ", yMin, " yMax ", yMax, " textStep ", textStep)
    plt.ylim(yMin, yMax)
    
    #transit2Hrs = [x/3600.0 for x in transit2] #s to hours 
    ephemTHrs = [x/3600.0 for x in ephemT] #s to hours    

    whichBands = [0, 1, 3, 4, 5, 8]
    numPlotBands = len(whichBands)
    #numPlotBands = 1
    bandLbls = ["U", "B", "V", "R", "I", "K"]
    transPalette = ['violet', 'blue', 'green', 'red', 'brown', 'black']
    #transPalette = ['violet', 'blue', 'blue', 'green', 'orange', 'red', 'brown', 'gray', 'black', '']
    #normFluxTransit = [[0.0 for i in range(numTransThetas2)] for j in range(numBands)]
    #for iB in range(numBands):
        #for iE in range(numTransThetas2):
            ##Normalize by untransited flux:
            #normFluxTransit[iB][iE] = bandFluxTransit[iB][iE]/bandFluxTransit[iB][0]
            ##plt.plot(transit2, bandFluxTransit[0]/bandFluxTransit[0][0], 'o')
            #plt.plot(transit2Hrs, normFluxTransit[iB], color = transPalette[iB])
    normFluxTransit = [[0.0 for i in range(numEpochs)] for j in range(numPlotBands)]
    for iB in range(numPlotBands):
        for iE in range(numEpochs):
            #Normalize by untransited flux:
            normFluxTransit[iB][iE] = bandFluxTransit2[whichBands[iB]][iE]/bandFluxTransit2[whichBands[iB]][0]
        plt.plot(ephemTHrs, normFluxTransit[iB], color = transPalette[iB])
        plt.text(ephemTHrs[10]+(textStep*iB), 1.0, bandLbls[iB], color = transPalette[iB])
        #plt.plot(ephemTHrs, bandFluxTransit2[whichBands[iB]], color = transPalette[iB])
    #Overplot "F(z)" lightcurve from Mandel & Agol (2002) Section 5 Eq.
    plt.plot(ephemTHrs, fluxTransMA2i, '--', color='black')
    #plt.plot(ephemTHrs, normFluxTransit[0], 'o')
    #for i in range(numEpochs):
        #    print("i ", i, " normFluxTransit[0] ", normFluxTransit[0][i], " fluxTransMA2i ", fluxTransMA2i[i])

if (ifTransit):
    
    outFile = outPath + fileStem + ".trans.txt"
    #print vertical atmospheric structure
    #with open(outFile, 'w', encoding='utf-8') as strucHandle:
    with open(outFile, 'w') as strucHandle:
        #with open(strucFile, 'w') as strucHandle:    
        strucHandle.write(inputParamString + "\n")
        strucHandle.write("numBands " + str(7) + " numEpochs " + str(numEpochs) + "\n")
        strucHandle.write("t (s), F^transit_band(t)/F_band" + "\n")
        #Not trivially pythonizable - each time through it writes a line to an output file
        outLine = "t(s) "\
            + "   " + str(bandLbls[0]) + "   " + str(bandLbls[1])\
            + "   " + str(bandLbls[2]) + "   " + str(bandLbls[3])\
            + "   " + str(bandLbls[4]) + "   " + str(bandLbls[5])\
            + "   " + "M&A02\n"
        strucHandle.write(outLine)
        for iE in range(numEpochs):
            #Transited flux already normalized to untransited flux above
            outLine = str(round(ephemT[iE], 4)) + "   "\
                + str(normFluxTransit[whichBands[0]][iE]) + "   "\
                + str(normFluxTransit[1][iE]) + "   "\
                + str(normFluxTransit[2][iE]) + "   "\
                + str(normFluxTransit[3][iE]) + "   "\
                + str(normFluxTransit[4][iE]) + "   "\
                + str(normFluxTransit[5][iE]) + "   "\
                + str(fluxTransMA2i[iE]) + "\n"
            strucHandle.write(outLine)

#print(" ")       
#print(" ************** ")
#print(" ")
#print("STOP!!!!")
#print(" ")
#print(" ************** ")
#print(" ")                       
#// *****************************
#// 
#//
#//
#// User-defined two-level atom and line profile section:
#//
#//
#//
#//

#    // Set up grid of line lambda points sampling entire profile (cm):
numCore = 5 #//half-core
numWing = 10 #//per wing 
numPoints = 2 * (numCore + numWing) - 1 #// + 1;  //Extra wavelength point at end for monochromatic continuum tau scale
#//linePoints: Row 0 in cm (will need to be in nm for Plack.planck), Row 1 in Doppler widths
species = "Ca"  #Anything but Hydrogen - doesn't matter for now - ??
linePoints = LineGrid.lineGridVoigt(userLam0, userMass, xiT, numDeps, teff, numCore, numWing, species) #//cm

#// Get Einstein coefficient for spontaneous de-excitation from f_ij to compute natural 
#// (radiation) roadening:  Assumes ration of statisitcal weight, g_j/g_i is unity
#logAij = math.log(6.67e13) + math.log(10.0)*userLogF - 2.0*math.log(cm2nm*userLam0)
log10Aij = math.log10(6.67e13) + userLogF - 2.0*math.log10(cm2nm*userLam0)
#////
#//Compute area-normalized depth-independent line profile "phi_lambda(lambda)"
if (ifVoigt == True):
    lineProf = LineProf.voigt2(linePoints, userLam0, log10Aij, userLogGammaCol,
                numDeps, teff, tauRos, temp, pGas, tempSun, pGasSun)
else: 
    lineProf = LineProf.voigt(linePoints, userLam0, log10Aij, userLogGammaCol, \
                      numDeps, teff, tauRos, temp, pGas, tempSun, pGasSun, hjertComp, dbgHandle)
    

#//
#// Level population now computed in LevelPops.levelPops()

#//
#// This holds 2-element temperature-dependent base 10 logarithmic parition fn:

#for k in range(len(thisUwV)):
#    thisUwV[k] = 0.0 #//default initialization
thisUwV = [ 0.0 for i in range(numAtmPrtTmps) ]        

logNums = [ [ 0.0 for i in range(numDeps) ] for j in range(numStages+2) ]

thisLogN = [0.0 for i in range(numDeps)] 
#for i in range(numDeps):
#    thisLogN[i] = logE10*(userA12 - 12.0) + logNH[i]
thisLogN = [ logE10*(userA12 - 12.0) + x for x in logNH ]
   
#//load arrays for stagePops2():
#//Default is to set both temperature-dependent values to to the user-input value:
    
chiIArr[0] = userChiI1
chiIArr[1] = userChiI2
chiIArr[2] = userChiI3
chiIArr[3] = userChiI4
log10UwAArr[0][0] = math.log10(userGw1)
log10UwAArr[0][1] = math.log10(userGw1)
log10UwAArr[1][0] = math.log10(userGw2)
log10UwAArr[1][1] = math.log10(userGw2)
log10UwAArr[2][0] = math.log10(userGw3)
log10UwAArr[2][1] = math.log10(userGw3)
log10UwAArr[3][0] = math.log10(userGw4)
log10UwAArr[3][1] = math.log10(userGw4)

#//One phantom molecule:
fakeNumMols = 1
fakeLogNumB = [ [ 0.0 for i in range(numDeps) ] for j in range(1) ]

#for i in range(numDeps):
#    fakeLogNumB[0][i] = -49.0
fakeLogNumB[0] = [ -49.0 for i in range(numDeps) ] 
    
fakeDissEArr = [ 0.0 for i in range(1) ]
fakeDissEArr[0] = 29.0 #//eV
fakeLog10UwBArr = [ [ 0.0 for i in range(numAtmPrtTmps) ] for j in range(1) ]
#for kk in range(len(fakeLog10UwBArr)):
#    fakeLog10UwBArr[0][kk] = 0.0
fakeLogQwABArr = [ [ 0.0 for i in range(numMolPrtTmps) ] for j in range(fakeNumMols) ]

#for im in range(fakeNumMols):
#    for kk in range(numMolPrtTmps):
#        fakeLogQwABArr[im][kk] = math.log(300.0)
fakeLogQwABArr = [ [ log300 for kk in range(numMolPrtTmps) ] for im in range(fakeNumMols) ]

fakeLogMuABArr = [0.0 for i in range(1)]
fakeLogMuABArr[0] = math.log(2.0) + Useful.logAmu() #//g 
logN = LevelPopsGasServer.stagePops2(thisLogN, newNe, chiIArr, log10UwAArr,   \
                fakeNumMols, fakeLogNumB, fakeDissEArr, fakeLog10UwBArr, fakeLogQwABArr, fakeLogMuABArr, \
                numDeps, temp)

#for iTau in range(numDeps):
#    logNums[0][iTau] = logN[0][iTau]
#    logNums[1][iTau] = logN[1][iTau]
#    logNums[4][iTau] = logN[2][iTau]
#    logNums[5][iTau] = logN[3][iTau]
#    logNums[6][iTau] = logN[4][iTau]
    #//logNums[6][iTau] = logN[4][iTau];
logNums[0] = [ x for x in logN[0] ]
logNums[1] = [ x for x in logN[1] ]
logNums[4] = [ x for x in logN[2] ]
logNums[5] = [ x for x in logN[3] ]
logNums[6] = [ x for x in logN[4] ]  

stage_ptr = 0 #//default initialization is neutral stage
if (userStage == 0):
    stage_ptr = 0
    
if (userStage == 1):
    stage_ptr = 1
    
if (userStage == 2):
    stage_ptr = 4
    
if (userStage == 3):
    stage_ptr = 5
    
numHelp = LevelPopsGasServer.levelPops(userLam0, logN[stage_ptr], userChiL, thisUwV, \
                    userGwL, numDeps, temp);
          
#for iTau in range(numDeps):
#    logNums[2][iTau] = numHelp[iTau]
    #//Log of line-center wavelength in cm
logNums[2] = [ x for x in numHelp ] 
    
logLam0 = math.log(userLam0)
#// energy of b-b transition
logTransE = Useful.logH() + Useful.logC() - logLam0 - Useful.logEv() #// last term converts back to cgs units
#// Energy of upper E-level of b-b transition
chiU = userChiL + math.exp(logTransE)
numHelp = LevelPopsGasServer.levelPops(userLam0, logN[stage_ptr], chiU, thisUwV, userGwL, \
         numDeps, temp)
#for iTau in range(numDeps):
#    logNums[3][iTau] = numHelp[iTau] #//upper E-level - not used - fake for testing with gS3 line treatment
logNums[3] = [ x for x in numHelp ] #//upper E-level - not used - fake for testing with gS3 line treatment   
#//
#//Compute depth-dependent logarithmic monochromatic extinction co-efficient, kappa_lambda(lambda, tauRos):

lineLambdas = [0.0 for i in range(numPoints)]   
#for il in range(numPoints):
#    lineLambdas[il] = linePoints[0][il] + userLam0
lineLambdas = [ x + userLam0 for x in linePoints[0] ]
            
logKappaL = LineKappa.lineKap(userLam0, logNums[2], userLogF, linePoints, lineProf, \
                       numDeps, zScale, tauRos, temp, rho, logFudgeTune)

logTotKappa = LineKappa.lineTotalKap(lineLambdas, logKappaL, numDeps, logKappa, \
             numLams, lambdaScale)
#//
#//Compute monochromatic optical depth scale, Tau_lambda throughout line profile
#//CAUTION: Returns numPoints+1 x numDeps array: the numPoints+1st row holds the line centre continuum tau scale
logTauL = LineTau2.tauLambda(numPoints, lineLambdas, logTotKappa, \
               numDeps, kappa500, tauRos, logTotalFudge)

#//Evaluate formal solution of rad trans eq at each lambda throughout line profile
#// Initial set to put lambda and tau arrays into form that formalsoln expects

lineIntens = [ [ 0.0 for i in range(numThetas) ] for j in range(numPoints) ]

lineIntensLam = [0.0 for i in range(numThetas)]

lineFlux = [ [ 0.0 for i in range(numPoints) ] for j in range(2) ]
lineFluxLam = [0.0 for i in range(2)]

if (ifScatt == True):
    lineMode = True
else:
    lineMode = False
    
for il in range(numPoints):

    #for id in range(numDeps):
    #    thisTau[1][id] = logTauL[il][id]
    #    thisTau[0][id] = math.exp(logTauL[il][id])
        #//console.log("il " + il + " id " + id + " logTauL[il][id] " + logE*logTauL[il][id]);
    thisTau[1] = [ x for x in logTauL[il] ]
    thisTau[0] = [ math.exp(x) for x in logTauL[il] ]    

    lineIntensLam = FormalSoln.formalSoln(numDeps, \
                cosTheta, lineLambdas[il], thisTau, temp, lineMode)
    #//lineFluxLam = flux2(lineIntensLam, cosTheta);
    #for it in range(numThetas):
    #    lineIntens[il][it] = lineIntensLam[it]
    lineIntens[il] = [ x for x in lineIntensLam ]
        #//console.log("il " + il + " it " + it + "lineIntensLam[it] " + lineIntensLam[it]);
    #} //it loop - thetas
#} //il loop
lineFlux = Flux.flux3(lineIntens, lineLambdas, cosTheta, phi, cgsRadius, omegaSini, macroVkm)

#//Continuum rectify line spectrum:
#//
#contFlux2 = ToolBox.interpolV(contFlux[0], lambdaScale, lineLambdas)
contFlux2 = numpy.interp(lineLambdas, lambdaScale, contFlux[0])

lineFlux2 = [ [ 0.0 for i in range(numPoints) ] for j in range(2) ]
#for i in range(numPoints):
#    lineFlux2[0][i] = lineFlux[0][i] / contFlux2[i]
#    lineFlux2[1][i] = math.log(lineFlux2[0][i])
lineFlux2[0] = [ lineFlux[0][i] / contFlux2[i] for i in range(numPoints) ]
lineFlux2[1] = [ math.log(x) for x in lineFlux2[0] ]
   

#//Get equivalent width, W_lambda, in pm - picometers:
#//Wlambda = eqWidth(lineFlux2, linePoints, lam0); //, fluxCont);

WlambdaLine = PostProcess.eqWidthSynth(lineFlux2, lineLambdas) 

#
#
# Report 5:
#
#   
#//
#//"""
#Print rectified high resolution spectrum of synthesis region
lineWave = [0.0 for i in range(numPoints)]
#outFile = outPath + lineFile
outFile = outPath + fileStem + ".tla.txt"
#with open(outFile, 'w', encoding='utf-8') as tlaHandle:
with open(outFile, 'w') as tlaHandle:    
#with open(tlaFile, 'w') as tlaHandle:
    tlaHandle.write(inputParamString + "\n")
    tlaHandle.write("User-defined two-level atom and line: Equivalent width: " + str(WlambdaLine) + " pm \n")
    tlaHandle.write("wave (nm)   normalized flux \n")
    for i in range(numPoints):
        lineWave[i] = cm2nm*lineLambdas[i]
        outLine = str(round(lineWave[i], 4)) + "   " + str(round(lineFlux2[0][i], 4)) + "\n"
        tlaHandle.write(outLine)
    tlaHandle.write("\n")
    tlaHandle.write("log_10 energy level populations (cm^-3) \n")
    tlaHandle.write("tauRos    n_l    n_I    n_II    N_III   N_IV")
    for i in range(numDeps):
        nI = round(log10e * logNums[0][i], 4)
        nII = round(log10e * logNums[1][i], 4)
        nl = round(log10e * logNums[2][i], 4)
        nIII = round(log10e * logNums[4][i], 4)
        nIV = round(log10e * logNums[5][i], 4)
        outLine = str(log10tauRos[i]) + "   " + str(nl) + "   " + str(nI) + "   " + str(nII) + "   " + str(nIII) + "   " + str(nIV) + "\n" 
        tlaHandle.write(outLine)


#spectral line of user-defined 2-level atom

if makePlotTLA:

    plt.figure()
    plt.subplot(1, 1, 1)    
    
    plt.title = "Fourier cosine transform of I_lambda(theta)"
    plt.xlabel(r'$\lambda$ (nm)')
    plt.ylabel(r'$F_\lambda/F^{\rm C}_\lambda$')
    xMin = min(lineWave)
    xMax = max(lineWave)
    plt.xlim(xMin, xMax)
    plt.ylim(0, 1.2)
    plt.plot(lineWave, lineFlux2[0])
    

    
dbgHandle.close()
        
        
    
back to top