import numpy as np
import platform
import os, sys, subprocess, glob, datetime
import colorama
colorama.init()
from .process_raw import *
from .find_solstice import *
from .cal_sun import *
def yellow(text):
return colorama.Fore.YELLOW + colorama.Style.BRIGHT + text + colorama.Style.RESET_ALL
def green(text):
return colorama.Fore.GREEN + colorama.Style.BRIGHT + text + colorama.Style.RESET_ALL
def SPROG(name):
return find_prog(name)
def run_prog(name,args,output_file=None,verbose=True):
prog = SPROG(name)
args1 = [str(a) for a in args]
if verbose:
sys.stderr.write("Running '%s' with args: %s\n" % (name," ".join(args1)))
if output_file is not None:
# any error will cause an exception (and we capture the output to a file)
res = subprocess.run([prog]+args1,check=True,stdout=subprocess.PIPE)
with open(output_file,'w') as f:
f.write(res.stdout.decode('utf-8'))
else:
# any error will cause an exception...
subprocess.run([prog]+args1,check=True)
[docs]class Master:
def __init__(self, casedir='.', nproc=None):
"""Set up the Solstice simulation, i.e. establishing the case folder, calling the Solstice program and post-processing the results
``Argument``
* casedir (str): the case directory
* nproc (int): number of processors, e.g. nproc=1 will run in serial mode,
nproc=4 will run with 4 processors in parallel
nproc=None will run with any number of processors that are available
"""
self.casedir=os.path.abspath(casedir)
self.nproc=nproc
if not os.path.exists(self.casedir):
os.makedirs(self.casedir)
assert os.path.isdir(casedir)
sys.stderr.write("Case directory is '%s'\n" % (yellow(self.casedir),))
[docs] def in_case(self, folder, fn):
"""Joining a file name with the case directory
``Argument``
* fn (str): file name
``Return``
* a joining directory of the file in the case directory
"""
if not os.path.exists(folder):
os.makedirs(folder)
assert os.path.isdir(folder)
return os.path.join(folder,fn)
[docs] def run(self, azimuth, elevation, num_rays, rho_mirror, dni, folder, gen_vtk=False, printresult=False, verbose=False, system='crs'):
"""Run an optical simulation (one sun position) using Solstice
* `azimuth` (float): the azimuth angle of the ray-tracing simulation in Solstice, counted from East towards to North
* `elevation` (float): the elevation angle of the ray-tracing simulation in Solstice
* `num_rays` (int): number of rays to be cast in the ray-tracing simulation
* `rho_mirror`(float): reflectivity of mirrors, required for results post-processing
* `dni` (float): the direct normal irradiance (W/m2), required to obtain performance of individual heliostat
* `gen_vtk` (boolean): if True, generate .vtk files for rendering in Paraview
* `system` (str): 'crs' for a central receiver system, or 'dish' for a parabolic dish system
Returns: no return value (results files are created and written)
"""
YAML_IN = self.in_case(self.casedir, 'input.yaml')
RECV_IN = self.in_case(self.casedir, 'input-rcv.yaml')
# main raytrace
if self.nproc==None:
run_prog("solstice",['-D%s,%s'%(azimuth,elevation),'-v','-n',num_rays,'-R',RECV_IN,'-fo',self.in_case(folder, 'simul'),YAML_IN])
else:
run_prog("solstice",['-D%s,%s'%(azimuth,elevation),'-v', '-t', self.nproc, '-n',num_rays,'-R',RECV_IN,'-fo',self.in_case(folder, 'simul'),YAML_IN])
folder=os.path.abspath(folder)
if gen_vtk and verbose:
dirn = os.getcwd()
try:
os.chdir(folder)
# Read "simul" results and produce a text file with the raw results
run_prog('solppraw',[self.in_case(folder, 'simul')])
# post processing
run_prog("solstice",['-D%s,%s'%(azimuth,elevation),'-g','format=obj:split=geometry','-fo',self.in_case(folder, 'geom'),YAML_IN])
# run a short raytrace to produce some ray paths
run_prog("solstice",['-D%s,%s'%(azimuth,elevation),'-q','-n','100','-R',RECV_IN,'-p','default',YAML_IN], output_file=self.in_case(folder, 'solpaths'))
# Read "simul" results and produce receiver files (.vtk) of incoming and/or absorbed solar flux per-primitive
run_prog('solmaps',[self.in_case(folder, 'simul')])
# Read "geom" and "simul" file results and produce primaries and receivers files (.vtk), and .obj geometry files
run_prog('solpp',[self.in_case(folder, 'geom'),self.in_case(folder, 'simul')])
# Read "solpaths" file and produce readable file (.vtk) by paraview to visualize the ray paths
run_prog('solpaths',[self.in_case(folder, 'solpaths')])
finally:
os.chdir(dirn)
if system=='dish':
eta=process_raw_results_dish(self.in_case(folder, 'simul'), folder, rho_mirror, dni, verbose=verbose)
if printresult:
sys.stderr.write('\n' + yellow("Total efficiency: {:f}\n".format(eta)))
sys.stderr.write(green("Completed successfully.\n"))
return eta
else:
if system=='multi-aperture':
eta, performance_hst=process_raw_results_multi_aperture(self.in_case(folder, 'simul'), folder,rho_mirror, dni, verbose=verbose)
else:
eta, performance_hst=process_raw_results(self.in_case(folder, 'simul'), folder,rho_mirror, dni, verbose=verbose)
if printresult:
sys.stderr.write('\n' + yellow("Total efficiency: {:f}\n".format(eta)))
sys.stderr.write(green("Completed successfully.\n"))
return eta, performance_hst
[docs] def run_annual(self, nd, nh, latitude, num_rays, num_hst,rho_mirror,dni, gen_vtk=False,verbose=False):
"""Run a list of optical simulations to obtain annual performance (lookup table) using Solstice
``Arguments``
* nd (int): number of rows in the lookup table (discretisation of the declination angle)
* nh (int): number of columns in the lookup table (discretisation of the solar hour angle)
* latitude (float): the latitude angle of the plan location (deg)
* num_rays (int): number of rays to be cast in the ray-tracing simulation
* num_hst (int): number of heliostats
* nproc (int): number of processors, e.g. nproc=1 will run in serial mode,
nproc=4 will run with 4 processors in parallel
nproc=None will run with any number of processors that are available
* rho_mirror (float): reflectivity of mirrors, required for results post-processing
* dni (float): the direct normal irradiance (W/m2), required to obtain performance of individual heliostat
* gen_vtk (bool): True - perform postprocessing for visualisation of each individual ray-tracing scene (each sun position), False - no postprocessing for visualisation
``Return``
* table (numpy array), the annual optical efficiency lookup table
* ANNUAL (numpy array), the annual output of each heliostat
"""
YAML_IN = self.in_case(self.casedir, 'input.yaml')
RECV_IN = self.in_case(self.casedir, 'input-rcv.yaml')
sun=SunPosition()
AZI, ZENITH,table,case_list=sun.annual_angles(latitude, casefolder=self.casedir, nd=nd, nh=nh)
case_list=case_list[1:]
SOLSTICE_AZI, SOLSTICE_ELE=sun.convert_convention('solstice', AZI, ZENITH)
# performance of individual heliostat is recorded
# TODO note, DNI is not varied in the simulation,
# i.e. performance is not dni-weighted
ANNUAL=np.zeros((num_hst, 9))
run=np.r_[0]
for i in range(len(case_list)):
c=int(case_list[i,0].astype(float))
if c not in run:
azimuth=SOLSTICE_AZI[c-1]
elevation=SOLSTICE_ELE[c-1]
#if np.sin(elevation*np.pi/180.)>=1.e-5:
# dni=1618.*np.exp(-0.606/(np.sin(elevation*np.pi/180.)**0.491))
#else:
# dni=0.
sys.stderr.write("\n"+green('Sun position: %s \n'%c))
print('azimuth: %.2f'% azimuth, ', elevation: %.2f'%elevation)
onesunfolder=os.path.join(self.casedir,'sunpos_%s'%(c))
# run solstice
if elevation<1.: # 1 degree
efficiency_total=ufloat(0,0)
performance_hst=np.zeros((num_hst, 9))
else:
efficiency_total, performance_hst=self.run(azimuth, elevation, num_rays, rho_mirror, dni, folder=onesunfolder, gen_vtk=gen_vtk, printresult=False, verbose=verbose)
sys.stderr.write(yellow("Total efficiency: {:f}\n".format(efficiency_total)))
ANNUAL+=performance_hst
else:
ANNUAL+=performance_hst
for a in range(len(table[3:])):
for b in range(len(table[0,3:])):
val=re.findall(r'\d+', table[a+3,b+3])
if val==[]:
table[a+3,b+3]=0
else:
if c==float(val[0]):
table[a+3,b+3]=efficiency_total.nominal_value
run=np.append(run,c)
annual_title=np.array(['Q_solar','Q_cosine', 'Q_shade', 'Q_hst_abs', 'Q_block', 'Q_atm', 'Q_spil', 'Q_refl', 'Q_rcv_abs'])
ANNUAL=np.vstack((annual_title, ANNUAL))
if verbose:
np.savetxt(self.casedir+'/lookup_table.csv', table, fmt='%s', delimiter=',')
np.savetxt(self.casedir+'/result-heliostats-annual-performance.csv', ANNUAL, fmt='%s', delimiter=',')
sys.stderr.write("\n"+green("Lookup table saved.\n"))
sys.stderr.write(green("Completed successfully.\n"+"\n"))
return table, ANNUAL