### Install ExoPlaSim via pip Source: https://exoplasim.readthedocs.io/en/latest/_sources/index.rst.txt Standard installation command for the ExoPlaSim package. ```bash pip install exoplasim ``` -------------------------------- ### Install ExoPlaSim in a Conda environment Source: https://exoplasim.readthedocs.io/en/latest/_sources/index.rst.txt Recommended installation workflow using conda-forge for compiler dependencies and OpenMPI. ```bash conda install -c conda-forge gcc gxx gfortran "openmpi<5.0.1" python pip install exoplasim python -c "import exoplasim; exoplasim.sysconfigure()" ``` -------------------------------- ### Install ExoPlaSim with netCDF and HDF5 support Source: https://exoplasim.readthedocs.io/en/latest/postprocessor.html Use this command to ensure the necessary dependencies for netCDF and HDF5 output formats are installed. ```bash pip install exoplasim[netCDF4,HDF5] ``` -------------------------------- ### Configure and Initialize ExoPlaSim Environment Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html Handles system-level configuration, including Python version-specific setup and marking the first run of the application. ```python sysconfigure() #compile_pyfft() #This will be called from sysconfigure() os.system(f"touch {sourcedir}/firstrun") ``` -------------------------------- ### Instantiate an ExoPlaSim Model Source: https://exoplasim.readthedocs.io/en/latest/_sources/tutorial.rst.txt Initialize the model instance with a working directory, resolution, and output format. Ensure the specified output format dependencies like netCDF4 or h5py are installed if using formats other than .npz. ```python import exoplasim as exo toi700d = exo.Model(workdir="toi700d_run",modelname="TOI-700d", ncpus=4,resolution="T21",outputtype=".npz") ``` -------------------------------- ### exoplasim.printsysconfig Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Prints the system configuration file generated on the first installation of ExoPlaSim. ```APIDOC ## exoplasim.printsysconfig(ncpus=4) ### Description Print the system configuration file ExoPlaSim generated on its first installation. ### Parameters - **ncpus** (int, optional) - Number of cores you want to use. The configuration differs for single-core vs parallel execution. ### Returns - **dict** - The contents of the configuration file as a dictionary. ``` -------------------------------- ### Test NetCDF library installation Source: https://exoplasim.readthedocs.io/en/latest/_sources/index.rst.txt Run this command in the run folder to check for missing linked objects related to NetCDF. ```bash ./burn7.x -nburnout MOST.00000 MOST.00000.nc ``` -------------------------------- ### Print System Configuration Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html Retrieves and displays the system configuration file generated during installation. Requires specifying the number of CPUs to select between single-core and parallel configurations. ```python def printsysconfig(ncpus=4): '''Print the system configuration file ExoPlaSim generated on its first installation. Parameters ---------- ncpus : int, optional Number of cores you want to use. The configuration differs for single-core vs parallel execution, so make sure you are checking the correct configuration. Returns ------- dict The contents of the configuration file as a dictionary ''' sourcedir = "/".join(__file__.split("/")[:-1]) #Get the absolute path for the module if ncpus==1: if not os.path.exists(sourcedir+"/most_compiler"): raise Exception("""ExoPlaSim has not yet been configured. Please configure it by instantiating a Model or running exoplasim.sysconfigure().""") with open(sourcedir+"/most_compiler") as f: result = f.read() else: if not os.path.exists(sourcedir+"/most_compiler_mpi"): raise Exception("""ExoPlaSim has not yet been configured. Please configure it by instantiating a Model or running exoplasim.sysconfigure().""") with open(sourcedir+"/most_compiler_mpi") as f: result = f.read() print(result) config = {} result = result.split('\n') for line in result: if '=' in line: setting = line.split('=') config[setting[0]] = setting[1] return config ``` -------------------------------- ### Initialize and run an ExoPlaSim model Source: https://exoplasim.readthedocs.io/en/latest/_sources/index.rst.txt Demonstrates the standard workflow of creating a model instance, configuring it, exporting settings, running the simulation, and finalizing output. ```python import exoplasim as exo mymodel = exo.Model(workdir="mymodel_testrun",modelname="mymodel",resolution="T21",layers=10,ncpus=8) mymodel.configure() mymodel.exportcfg() mymodel.run(years=100,crashifbroken=True) mymodel.finalize("mymodel_output") ``` -------------------------------- ### Configure physics filters Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Examples of specifying physics filters using the physicsfilter parameter. ```python physicsfilter="gp|exp|sp" ``` ```python physicsfilter="gp|cesaro" ``` -------------------------------- ### Define Other Arguments Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Example format for passing custom namelist parameters via the otherargs dictionary. ```python otherargs={"N_RUN_MONTHS@plasim_namelist":'4',"NGUI@plasim_namelist:'1'} ``` -------------------------------- ### get(year, snapshot=False, highcadence=False) Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Retrieves an open NetCDF data object for a specific year. ```APIDOC ## get(year, snapshot=False, highcadence=False) ### Description Return an open NetCDF data object for the given year. Defaults to returning time-averaged output. ### Parameters - **year** (int) - Required - Integer year of output to return. - **snapshot** (bool) - Optional - If True, return the snapshot version. - **highcadence** (bool) - Optional - If True, return the high-cadence version. ### Returns - **netCDF4.Dataset** - An open netCDF4 data object. ``` -------------------------------- ### Initialize pRT Atmosphere and Configure Simulation Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/pRT.html Sets up the Radtrans object with species, opacities, and scattering parameters, and performs initial physical constant and stellar spectrum calculations. ```python _log(logfile,"===================================") _log(logfile,"| ExoPlaSim->petitRADTRANS Engine |") _log(logfile,"| v1.0, Adiv Paradise (c) 2021 |") _log(logfile,"===================================") _log(logfile," ") _log(logfile,"-------------Direct Imager----------") _log(logfile," ") #Compute zenith angle from czen #Figure out how to output spectra #Get surface type from model output #Turn off reflection for night-time grid cells gravity *= 100.0 #SI->CGS atmosphere = Radtrans(line_species = ['H2O_'+h2o_lines, 'CO2', 'O3'], rayleigh_species = ['N2', 'O2', 'CO2', 'H2', 'He'], continuum_opacities = ['N2-N2', 'N2-O2','O2-O2', 'CO2-CO2','H2-H2','H2-He'], wlen_bords_micron = [0.3, 20], do_scat_emis = True, cloud_species = ['H2O(c)_cd'],) if cloudfunc is None: cloudfunc = basicclouds planckh = 6.62607015e-34 boltzk = 1.380649e-23 cc = 2.99792458e8 if stellarspec is None: SIwvl = spec.wvl*1.0e-6 #um->m stellarspec = 1.0e-6 * 2*planckh*cc**2/SIwvl**5 \ /(np.exp(planckh*cc/(SIwvl*boltzk*Tstar))-1) # W sr-1 m-2 um-1 ``` -------------------------------- ### Verify system configuration Source: https://exoplasim.readthedocs.io/en/latest/_sources/index.rst.txt Use these commands to print and return the execution configuration files for single-core and parallel runs. ```python exoplasim.printsysconfig(ncpus=1) exoplasim.printsysconfig(ncpus=2) ``` -------------------------------- ### exoplasim.compile_pyfft() Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Compiles or recompiles the pyfft libraries required for ExoPlaSim. This operation requires meson, ninja, gfortran, and gcc to be installed on the system. ```APIDOC ## exoplasim.compile_pyfft() ### Description Compile or recompile the pyfft libraries. Requires meson, ninja, gfortran, and gcc. ``` -------------------------------- ### Initialize ExoPlaSim Model Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html The __init__ method configures the model environment, including resolution, hardware settings, and compilation flags. ```python """ def __init__(self,resolution="T21",layers=10,ncpus=4,precision=8,debug=False,inityear=0, recompile=False,optimization=None,mars=False,workdir="most",source=None,force991=False, modelname="MOST_EXP",outputtype=".npz",crashtolerant=False,outputfaulttolerant=False, hyperthreading=True,mpi_opts=None): global sourcedir #self.burn7 = burn7 self.mars = mars self.extension = outputtype self.extensions = {"regular" : self.extension, "snapshot" : self.extension, "highcadence" : self.extension} self._configuredpostprocessor = {"regular":False,"snapshot":False,"highcadence":False} self.postprocessordefaults = {"regular" : {}, "snapshot" : {"times":None,"timeaverage":False,"stdev":False}, "highcadence" : {"times":None,"timeaverage":False,"stdev":False}} self.postprocessorcfgs = {"regular":{},"snapshot":{},"highcadence":{}} self.pRTopts = {} for ftype in ['regular','snapshot','highcadence']: self.pRTopts[ftype] = {"transit":False, "image":False, "h2o_linelist" : 'Exomol', "cloudfunc":None, "smooth":False, "smoothweight": 0.95} self.crashtolerant = crashtolerant self.outputfaulttolerant = outputfaulttolerant if self.extension not in pyburn.SUPPORTED: raise Exception("Unsupported output format detected. Supported formats are:\n\t\n\t%s"%("\n\t".join(pyburn.SUPPORTED))) sourcedir = "/".join(__file__.split("/")[:-1]) #Get the absolute path for the module if not os.path.isfile(sourcedir+"/firstrun") or not os.path.isfile(sourcedir+"/most_compiler")\ or not os.path.isfile(sourcedir+"/most_compiler_mpi"): #This means we haven't run yet, and have some post-install work to do recompile=True #os.system('spth=$(python%s -c "import exoplasim as exo; print(exo.__path__)") && echo $spth>sourcepath'%sys.version[0]) #with open("sourcepath","r") as spf: #sourcedir = spf.read().strip() #if sourcedir[0]=="[": #sourcedir=sourcedir[1:] #if sourcedir[-1]=="]": #sourcedir=sourcedir[:-1] #if sourcedir[0]=="'": #sourcedir=sourcedir[1:] #if sourcedir[-1]=="'": #sourcedir=sourcedir[:-1] #os.system("rm sourcepath") #with open("%s/__init__.py"%sourcedir,"r") as sourcef: #sourcecode = sourcef.read().split('\n') #sourcecode[2] = 'sourcedir = "%s"'%sourcedir #sourcecode = '\n'.join(sourcecode) #os.system("cp %s/__init__.py %s/preinit.py"%(sourcedir,sourcedir)) #try: ##with open("%s/__init__.py"%sourcedir,"w") as sourcef: ##sourcef.write(sourcecode) #cwd = os.getcwd() #os.chdir(sourcedir) #pyversion = ".".join(sys.version.split(".")[:2]) #for pyfftfile in glob.glob(os.path.join(sourcedir,"pyfft*.so")): #os.remove(pyfftfile) ``` -------------------------------- ### exoplasim.Earthlike.__init__ Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Initializes a new Earth-like model instance with specified resolution, layers, and performance settings. ```APIDOC ## class exoplasim.Earthlike ### Description Creates an Earth-like model instance. This class inherits from Model and provides default configurations suitable for Earth-like simulations. ### Parameters - **resolution** (str) - Optional - Model resolution (default 'T21'). - **layers** (int) - Optional - Number of vertical layers (default 10). - **ncpus** (int) - Optional - Number of CPUs to use (default 4). - **precision** (int) - Optional - Precision setting (default 8). - **debug** (bool) - Optional - Enable debug mode (default False). - **inityear** (int) - Optional - Initial year (default 0). - **recompile** (bool) - Optional - Force recompile (default False). - **optimization** (str) - Optional - Optimization level. - **mars** (bool) - Optional - Enable Mars-like configuration (default False). - **workdir** (str) - Optional - Working directory (default 'most'). - **source** (str) - Optional - Source path. - **force991** (bool) - Optional - Force 991 compatibility (default False). - **modelname** (str) - Optional - Name of the model (default 'MOST_EXP'). - **outputtype** (str) - Optional - Output file format (default '.npz'). - **crashtolerant** (bool) - Optional - Enable crash tolerance (default False). - **outputfaulttolerant** (bool) - Optional - Enable output fault tolerance (default False). - **hyperthreading** (bool) - Optional - Enable hyperthreading (default True). - **mpi_opts** (str) - Optional - MPI options. ``` -------------------------------- ### Parse Configuration and Initialize Dataset Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/pyburn.html Parses input arguments to configure physical parameters like radius, gravity, and gas constants before initializing the dataset object. ```python elif int(arg)==2: stdev = True elif int(arg)==3: timeaverage=True stdev = True elif key=="radius" or key=="RADIUS": radius = float(arg)/6371220.0 #Radii in the namelist are given in metres elif key=="gravity" or key=="GRAVITY": gravity = float(arg) elif (key=="mars" or key=="MARS") and int(arg)==1: gravity = MARS_GRAV radius = MARS_RADIUS/6371220.0 #We want to start off with radii in Earth radii gascon = MARS_RD #This is called RD in burn7, not gascon data = dataset(rawfile, variables, mode=mode,radius=radius,gravity=gravity,gascon=gascon, zonal=zonal, substellarlon=substellarlon, physfilter=physfilter,logfile=logfile) ``` -------------------------------- ### Rerun ExoPlaSim system configuration Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html Use this function to re-run the configuration script if compilers or libraries have changed, or if the initial setup failed. ```python def sysconfigure(): '''Rerun the ExoPlaSim system configuration script. If compilers/libraries have changed since you first configured ExoPlaSim, or the initial configuration failed, you should call this function. ''' sourcedir = "/".join(__file__.split("/")[:-1]) #Get the absolute path for the module try: cwd = os.getcwd() os.chdir(sourcedir) pyversion = ".".join(sys.version.split(".")[:2]) #for pyfftfile in glob.glob(os.path.join(sourcedir,"pyfft*.so")): #os.remove(pyfftfile) if float(pyversion)>=3.5 and float(pyversion)<3.7: print("./configure -v %s"%(pyversion)) result = subprocess.run(["./configure.sh -v %s"%(pyversion)],shell=True,check=True, stdout=subprocess.PIPE,stderr=subprocess.PIPE, universal_newlines=True) print(result.stdout) print(result.stderr) elif float(pyversion)>=3.7: print("./configure -v %s"%(pyversion)) result = subprocess.run(["./configure.sh -v %s"%(pyversion)],shell=True,check=True, capture_output=True,universal_newlines=True) print(result.stdout) print(result.stderr) elif float(pyversion)<3.5 and float(pyversion)>=3.0: print("./configure -v %s"%(pyversion)) os.system("./configure.sh -v %s"%(pyversion)) result="" else: print("./configure -v 3") os.system("./configure.sh -v 3") result="" if not os.path.isfile(sourcedir+"/firstrun") : os.system(f"touch {sourcedir}/firstrun") compile_pyfft() #import numpy.f2py #with open("pyfft.f90","r") as pyfft_file: #pyfft_source = pyfft_file.read() #failed = pyburn.f2py_compile(pyfft_source,modulename='pyfft', #extra_args='--f90exec=gfortran --f77exec=gfortran --f90flags="-O3"', #extension='.f90') #if failed!=0: #print(failed) ##raise Exception("Encountered an error in pyfft compilation with f2py.... please ensure gfortran is installed and configured correctly.") #with open("pyfft991.f90","r") as pyfft991_file: #pyfft991_source = pyfft991_file.read() #failed = pyburn.f2py_compile(pyfft991_source,modulename='pyfft991', #extra_args='--f90exec=gfortran --f77exec=gfortran --f90flags="-O3"', #extension='.f90') #if failed!=0: #print(failed) #raise Exception("Encountered an error in pyfft991 compilation with f2py.... please ensure gfortran is installed and configured correctly.") #if self.burn7: #os.system("nc-config --version > ncversion.tmp") #with open("ncversion.tmp","r") as ncftmpf: #version = float('.'.join(ncftmpf.read().split()[1].split('.')[:2])) #if version>4.2: #os.system("cd postprocessor && ./build_init.sh || ./build_init_compatibility.sh") #else: #os.system("cd postprocessor && rm burn7.x && make") #os.chdir(cwd) #os.system("touch %s/postprocessor/netcdfbuilt"%sourcedir) os.chdir(cwd) except PermissionError: raise PermissionError("\nHi! Welcome to ExoPlaSim. It looks like this is the first "+ "time you're using this program since installing, and you "+ "may have installed it to a location that needs root "+ "privileges to modify. This is not ideal! If you want to "+ "use the program this way, you will need to run python code"+ " that uses ExoPlaSim with sudo privileges; i.e. sudo "+ "python3 myscript.py. If you did this because pip install "+ "breaks without sudo privileges, then try using \n\n\tpip "+ "install --user exoplasim \n\ninstead. It is generally a "+ "very bad idea to install things with sudo pip install.") except Exception as e: print(result.stderr) raise e ``` -------------------------------- ### Configure Atmospheric and Simulation Parameters Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html This block manages the initialization of atmospheric gas pressures, calculates the mean molecular weight, and updates the corresponding Fortran namelists for the simulation. ```python self._edit_namelist("aero_namelist","l_aerorad",str(self.aerorad*1)) self._edit_namelist("aero_namelist","aerofile","'%s.dat'"%aerofile) aerofile+=".dat" self.aerofile = aerofile if pH2: self.pgases["pH2"]=pH2 if pHe: self.pgases["pHe"]=pHe if pN2: self.pgases["pN2"]=pN2 if pO2: self.pgases["pO2"]=pO2 if pCO2: self.pgases["pCO2"]=pCO2 if pAr: self.pgases["pAr"]=pAr if pNe: self.pgases["pNe"]=pNe if pKr: self.pgases["pKr"]=pKr if pH2O: self.pgases["pH2O"]=pH2O if pCH4: self.pgases["pCH4"]=pCH4 if len(self.pgases)==0: if not pressure: #self.pgases=gases_default #self.pressure=0.0 #for gas in self.pgases: #self.pressure+=self.pgases[gas] #in bars if self.mars: self.pressure = 6.36e-3 else: self.pressure = 1.011 else: self.pressure = pressure else: self.pressure=0.0 for gas in self.pgases: self.pressure+=self.pgases[gas] gasesvx = {} for gas in self.pgases: gasesvx[gas[1:]] = self.pgases[gas]/self.pressure self.mmw = 0 for gas in gasesvx: self.mmw += gasesvx[gas]*smws['m'+gas] if self.mmw==0: if self.mars: self.mmw = MARS_MMW #43.991866 else: self.mmw = 28.970253 self.gascon = 8314.46261815324 / self.mmw if gascon: self.gascon=gascon self.mmw = 8314.46261815324/self.gascon print('Mean Molecular Weight set to %1.4f g/mol'%self.mmw) if pressure: if pressure != self.pressure: #User has specified a different pressure than sum of gas pressures self.pressure = pressure self.CO2ppmv = 300.0 if 'pCO2' in self.pgases: self.CO2ppmv = self.pgases['pCO2']/self.pressure * 1.0e6 #ppmv self._edit_namelist("radmod_namelist","CO2",str(self.CO2ppmv)) self._edit_namelist("plasim_namelist","PSURF",str(self.pressure*1.0e5)) #Pa self._edit_namelist("planet_namelist","GASCON",str(self.gascon)) self._edit_namelist("radmod_namelist","NPBROADEN",str(pressurebroaden*1)) self.pressurebroaden=pressurebroaden self._edit_namelist("plasim_namelist","NEQSIG",str(vtype)) self.vtype=vtype self._edit_namelist("plasim_namelist","MPSTEP",str(timestep)) self._edit_namelist("plasim_namelist","NSTPW",str(int(7200//int(timestep)))) self.timestep=timestep if year: self._edit_namelist("plasim_namelist","N_DAYS_PER_YEAR",str(int(year))) self._edit_namelist("planet_namelist","SIDEREAL_YEAR",str(year*86400.0)) self.stepsperyear=float(year)*1440.0/self.timestep else: self.stepsperyear=360.*1440.0/self.timestep self.sidyear=year if rotationperiod!=1.0: self._edit_namelist("planet_namelist","ROTSPD",str(1.0/float(rotationperiod))) self._edit_namelist("plasim_namelist","N_DAYS_PER_YEAR", str(max(int(360.0/float(rotationperiod)/12+0.5),1)*12)) #if rotationperiod>80.0 and type(top_restoretime)==type(None): #top_restoretime = 1.0 #If we have a long rotation period, apply top-layer forcing nsteps = max(1,int(round(360.0*1440.0/self.timestep+0.49999))) self._edit_namelist("plasim_namelist","N_RUN_STEPS",str(nsteps)) if runsteps is not None: self._edit_namelist("plasim_namelist","N_RUN_STEPS",str(runsteps)) self.runsteps = runsteps self.rotationperiod=rotationperiod if synchronous: self._edit_namelist("radmod_namelist","NFIXED","1") self._edit_namelist("plasim_namelist","FIXEDLON",str(substellarlon)) self.synchronous=synchronous self.substellarlon=substellarlon self._edit_namelist("radmod_namelist","DESYNC",str(desync)) self.desync=desync self._edit_namelist("plasim_namelist","DTTL",str(tlcontrast)) self.tlcontrast=tlcontrast if top_restoretime: #self._edit_namelist("plasim_namelist","RESTIM","%f,%d*0.0"%(top_restoretime,self.layers-1)) self._edit_namelist("plasim_namelist","NSPONGE","1") self._edit_namelist("plasim_namelist","DAMPSP","%f"%top_restoretime) self.top_restoretime = top_restoretime if restartfile: os.system("cp %s %s/plasim_restart"%(restartfile,self.workdir)) ``` -------------------------------- ### Compute transit spectrum for a single column Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/pRT.html Calculates the transmission radius for a single atmospheric column, including vertical profile setup and ozone parameterization. ```python def _transitcolumn(atmosphere, pressures, psurf, temperature, humidity, clouds, gases_vmr, gascon, gravity, rplanet, h2o_lines,cloudfunc,smooth,smoothweight,ozone,ozoneheight,ozonespread,num): '''Compute the transit spectrum through a single column. Parameters ---------- atmosphere : Radtrans.Atmosphere Initialized Atmosphere object pressures : numpy.ndarray Pressure array in hPa, with the surface at the end of the array psurf : float Surface pressure in hPa temperature : numpy.ndarray Array of air temperatures, with the surface at the end of the array humidity : numpy.ndarray Specific humidity in the column [kg/kg] clouds : numpy.ndarray Cloud water mass fraction in each cell [kg/kg] gases_vmr : dict Dictionary of component gases and their volume mixing ratios gascon : float Specific gas constant gravity : float Surface gravity in SI units rplanet : float Planet radius in kilometers h2o_lines : {'HITEMP', 'EXOMOL'} Line list to use for H2O absorption. Options are 'HITEMP' or 'EXOMOL'. cloudfunc : function A routine which takes pressure, temperature, and cloud water content as arguments, and returns keyword arguments to be unpacked into calc_flux_transm. smooth : bool Whether or not to smooth humidity and cloud columns. As of Nov 12, 2021, it is recommended that you use smooth=True for well-behaved spectra. This is a conservative smoothing operation, meaning the water and cloud column mass should be conserved--what this does is move some water from the water-rich layers into the layers directly above and below. smoothweight : float The fraction of the water in a layer that should be retained during smoothing. A higher value means the smoothing is less severe. 0.95 is probably the upper limit for well-behaved spectra. ozone : float Ozone column amount [cm-STP] ozoneheight : float Altitude of maximum ozone concentration [m] ozonespread : float Width of the ozone gaussian distribution [m] num : int, float Which number column this is (used for reporting) Returns ------- numpy.ndarray Transmission radius in kilometers ''' print("Doing column %d"%num) temperature = temperature[0] pressures = pressures[0] humidity = humidity[0] clouds = clouds[0] #Define vertical profiles with ghost stratosphere extp = np.append(np.geomspace(1.0e-6,0.5*pressures[0],num=20),pressures) try: extta = np.append(np.ones(20)*temperature[0],temperature) except: print(temperature.shape) raise exthus = np.append(np.zeros(20),humidity) extcl = np.append(np.zeros(20),clouds) if smooth: exthus = _smooth(exthus,xcoords=extp,xN=psurf,centerweight=smoothweight) extcl = _smooth(extcl,xcoords=extp,xN=psurf,centerweight=smoothweight) #Set up atmosphere atmosphere.setup_opa_structure(extp*1.0e-3) MMW = 8.31446261815324/gascon*1.0e3*np.ones_like(extp) #grams per mole #Set absorber fractions mass_fractions = {} for gas in gases_vmr: mmass = smws['m'+gas] mass_fractions[gas] = gases_vmr[gas] * mmass/MMW * (1-exthus-extcl) mass_fractions['H2O_'+h2o_lines] = exthus*(1-extcl) mass_fractions['H2O(c)'] = extcl kwargs = cloudfunc(extp,extta,extcl) #Compute ozone from parameterization mass_fractions['O3'] = np.zeros_like(extp) zfo3 = 100./2.14 zo3t = ozone bo3 = ozoneheight co3 = ozonespread zh = 0.0 zconst = np.exp(-bo3/co3) ga = gravity*0.01 #SI units extdp = np.gradient(extp)*1e2 for k in range(len(extp)-1,0,-1): zh -= extta[k]*gascon/ga*np.log(extp[k-1]/extp[k]) zo3 = -(ozone + ozone*zconst)/(1.+np.exp((zh-bo3)/co3))+zo3t mass_fractions['O3'][k]=zo3*ga/(zfo3*extdp[k]) zo3t -= zo3 mass_fractions['O3'][0] = zo3t * ga / (zfo3 * extdp[0]) if smooth: mass_fractions['O3'] = _smooth(mass_fractions['O3'],xcoords=extp,xN=psurf,centerweight=smoothweight) #Compute flux atmosphere.calc_transm(extta, mass_fractions, gravity, MMW, \ P0_bar=psurf*1.0e-3, R_pl=rplanet*1e5,**kwargs) return atmosphere.transm_rad*1e-5 #kilometers ``` -------------------------------- ### exoplasim.sysconfigure Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Reruns the ExoPlaSim system configuration script. ```APIDOC ## exoplasim.sysconfigure() ### Description Rerun the ExoPlaSim system configuration script. Call this if compilers/libraries have changed or the initial configuration failed. ``` -------------------------------- ### Initialize Dataset Processing Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/pyburn.html Sets up the dataset object based on provided variables or namelist configuration. ```python if namelist is None: if variables is None: variables = list(ilibrary.keys()) if mars: radius = MARS_RADIUS/6371220.0 gascon = MARS_RD gravity = MARS_GRAV if type(variables)==tuple or type(variables)==list: data = dataset(rawfile, variables, mode=mode,radius=radius,gravity=gravity,gascon=gascon, zonal=zonal, substellarlon=substellarlon, physfilter=physfilter,logfile=logfile) elif type(variables)==dict: #for advancedDataset data = advancedDataset(rawfile, variables, mode=mode,radius=radius,gravity=gravity, gascon=gascon, zonal=zonal, substellarlon=substellarlon, physfilter=physfilter, logfile=logfile) ``` -------------------------------- ### Importing exoplasim.gcmt dependencies Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/gcmt.html Initializes the module by importing necessary libraries and file support utilities. ```python import numpy as np import exoplasim.filesupport from exoplasim.filesupport import SUPPORTED import os, glob ``` -------------------------------- ### Configure ExoPlaSim simulation parameters Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim.html Logic for updating namelist files and managing simulation resources based on input keys. ```python str(self.highcadence["start"])) self._edit_namelist("plasim_namelist","HCENDSTEP", str(self.highcadence["end"])) self._edit_namelist("plasim_namelist","HCINTERVAL", str(self.highcadence["interval"])) if key=="snapshots": self.snapshots=value if self.snapshots: self._edit_namelist("plasim_namelist","NSNAPSHOT","1") self._edit_namelist("plasim_namelist","NSTPS",str(self.snapshots)) else: self._rm_namelist_param("plasim_namelist","NSTPS") self._edit_namelist("plasim_namelist","NSNAPSHOT","0") if key=="resources": self.resources=value if len(self.resources)>0: for res in self.resources: os.system("cp %s %s/"%(res,self.workdir)) if key=="landmap": self.landmap=value changeland=True if key=="topomap": self.topomap=value changeland=True if key=="stormclim": self.stormclim=value if self.stormclim: self._edit_namelist("hurricane_namelist","NSTORMDIAG","1") self._add_postcodes("example.nl",[322,323,324,325,326,327,328,329]) self._add_postcodes("snapshot.nl",[322,323,324,325,326,327,328,329]) else: self._edit_namelist("hurricane_namelist","NSTORMDIAG","0") self._rm_postcodes("example.nl",[322,323,324,325,326,327,328,329]) self._rm_postcodes("snapshot.nl",[322,323,324,325,326,327,328,329]) if key=="nstorms": self.nstorms=value self._edit_namelist("hurricane_namelist","NSTORMS",str(self.int(nstorms))) if key=="stormcapture": self.stormcapture=value if self.stormcapture["toggle"]: self._edit_namelist("hurricane_namelist","HC_CAPTURE","1") for param in self.stormcapture: if param!="toggle": self._edit_namelist("hurricane_namelist",param, str(self.stormcapture[param])) else: self._edit_namelist("hurricane_namelist","HC_CAPTURE","0") if key=="threshold": self.threshold = value if key=="aerosol": self.aerosol = value self._edit_namelist("plasim_namelist","L_AERO",str(self.aerosol*1)) if key=="asource": self.asource = value self._edit_namelist("aero_namelist","l_source",str(self.asource)) if key=="apart": self.apart = value self._edit_namelist("aero_namelist","apart",str(self.apart)) if key=="rhop": self.rhop = value self._edit_namelist("aero_namelist","rhop",str(self.rhop)) if key=="fcoeff": self.fcoeff = value self._edit_namelist("aero_namelist","fcoeff",str(self.fcoeff)) if key=="aerobulk": self.aerobulk = value self._edit_namelist("aero_namelist","l_source",str(self.aerobulk)) if key=="aerorad": self.aerorad = value if "aerofile" not in kwargs and self.aerorad: self.aerofile = "gj667_constants_500.dat" elif "aerofile" in kwargs and self.aerorad: self.aerofile = kwargs["aerofile"] if self.aerofile is None: self.aerofile = "gj667_constants_500.dat" if self.aerorad: if f"{sourcedir}/hazeconstants/{self.aerofile}" in glob.glob(f"{sourcedir}/hazeconstants/*.dat"): os.system(f"cp {sourcedir}/hazeconstants/{self.aerofile} {self.workdir}/") elif f"{sourcedir}/hazeconstants/{self.aerofile}.dat" in glob.glob(f"{sourcedir}/hazeconstants/*.dat"): os.system(f"cp {sourcedir}/hazeconstants/{self.aerofile}.dat {self.workdir}/") if self.aerofile[-4:]==".dat": self.aerofile=aerofile[:-4] self.aerorad=True self._edit_namelist("aero_namelist","l_aerorad",str(self.aerorad*1)) self._edit_namelist("aero_namelist","aerofile","'%s.dat'"%self.aerofile) self.aerofile+=".dat" ``` -------------------------------- ### Configure Ozone and Surface Albedo Source: https://exoplasim.readthedocs.io/en/latest/_modules/exoplasim/pRT.html Sets ozone parameters and calculates surface albedo based on ice, snow, and vegetation coverage. ```python try: starseparation = orbdistances[idx] except: starseparation = orbdistances if ozone is False: a0o3 = 0. a1o3 = 0. aco3 = 0. bo3 = 20000. co3 = 5000. toffo3 = 0.0 elif ozone is True: a0o3 = 0.25 a1o3 = 0.11 aco3 = 0.08 bo3 = 20000. co3 = 5000. toffo3 = 0.25 else: a0o3 = ozone["amount"] a1o3 = ozone["varlat"] aco3 = ozone["varseason"] toffo3 = ozone["seasonoffset"] bo3 = ozone["height"] co3 = ozone["spread"] dt = output.variables['time'][0] / stepsperyear rlats = ilats*np.pi/180. o3 = a0o3+a1o3*abs(np.sin(rlats))+aco3*np.sin(rlats)*np.cos(2*np.pi*(dt-toffo3)) albedo = output.variables['alb'][0,...].flatten() ice = output.variables['sit'][0,...]+output.variables['snd'][0,...] ice = ice.flatten() #icemap = 2.0*(ice>0.001) #1 mm probably not enough to make everything white ice = np.minimum(ice/0.02,1.0) #0-1 with a cap at 2 cm of snow snow = 1.0*(output.variables['snd'][0,...].flatten()>0.02) #absorbed by vegetation forest = np.zeros_like(ice) desertf = np.zeros_like(ice) mntf = np.zeros_like(ice) ice[forest>0] *= 1 - 0.82*forest[forest>0] forest[ice>0] *= 0.82*forest[ice>0] bare = 1-(ice+forest) #sfctype = np.maximum(sea,icemap).astype(int) # Sea with no ice: 1 # Sea with ice: 2 # Land with no ice: 0 (since both are 0) # Land with ice: 2 #surfaces = [] #for n in range(len(sfctype)): # surfaces.append({'type':sfctype[n],'albedo':albedo[n]}) surfspecs = (sfcalbedo*(1-output.variables['sic'][0,...].flatten())[:,np.newaxis]+ surfaces[2][np.newaxis,:]*(output.variables['sic'][0,...].flatten())[:,np.newaxis]) surfspecs = (surfspecs*bare[:,np.newaxis] + surfaces[2][np.newaxis,:]*ice[:,np.newaxis]+ surfaces[3][np.newaxis,:]*forest[:,np.newaxis]) clt = output.variables['clt'][0,...].flatten() for n in range(len(albedo)): bol_alb = np.trapz(stellarspec*surfspecs[n,:],x=spec.wvl)/ \ ``` -------------------------------- ### exoplasim.Model Source: https://exoplasim.readthedocs.io/en/latest/source/exoplasim.html Initializes an ExoPlaSim model in a specified directory, compiling the executable if it does not exist. ```APIDOC ## class exoplasim.Model ### Description Create and initialize an ExoPlaSim model in a particular directory. If the necessary executable does not yet exist, it will be compiled. ### Parameters - **resolution** (str) - Optional - Model resolution (default 'T21') - **layers** (int) - Optional - Number of vertical layers (default 10) - **ncpus** (int) - Optional - Number of CPUs to use (default 4) - **precision** (int) - Optional - Precision (default 8) - **debug** (bool) - Optional - Enable debug mode (default False) - **inityear** (int) - Optional - Initial year (default 0) - **recompile** (bool) - Optional - Force recompile (default False) - **optimization** (str) - Optional - Optimization level - **mars** (bool) - Optional - Enable Mars mode (default False) - **workdir** (str) - Optional - Working directory (default 'most') - **source** (str) - Optional - Source path - **force991** (bool) - Optional - Force 991 (default False) - **modelname** (str) - Optional - Model name (default 'MOST_EXP') - **outputtype** (str) - Optional - Output file type (default '.npz') - **crashtolerant** (bool) - Optional - Enable crash tolerance (default False) - **outputfaulttolerant** (bool) - Optional - Enable output fault tolerance (default False) - **hyperthreading** (bool) - Optional - Enable hyperthreading (default True) - **mpi_opts** (str) - Optional - MPI options ```