# Built-in modules
import numpy as np
import sys as sy
import copy as cp
import os
# BoloCalc modules
import src.experiment as ex
import src.unit as un
class Vary:
"""
Vary object takes a simulation object, which has information about
the experiment, and an input parameter vary file and calculates
sensitivity for a user-defined set of parameters
Args:
sim (src.Simulation): parent Simulation object
param_file (str): parameter vary input filename
vary_name (str): name to which to save vary outputs
vary_tog (bool): whether or not to vary input parameter arrays together
Parents:
sim (src.Simulation): parent Simulation object
"""
def __init__(self, sim, param_file, vary_name, vary_tog=False):
# Store passed parameters
self._sim = sim
self._sns = self._sim.sns
self._exp = self._sim.exp
self._log = self._sim.log
self._ph = self._sim.phys
self._param_file = param_file
self._vary_name = vary_name
self._vary_tog = vary_tog
self._units = self._sim.output_units
self._nexp = self._sim.param("nexp")
# Status bar length
self._bar_len = 100
# Scope (exp, tel, cam, or ch) of the parameter setx
self._scope = ''
self._scope_enums = {
'exp': 3, 'tel': 2, 'cam': 1, 'ch': 0,
'opt': 0, 'pix': 0}
# Name of parameter vary directory
self._param_dir = "paramVary"
self._input_param_dir = os.path.split(self._param_file)[0]
self._cust_dir = os.path.join(self._input_param_dir, "customVary")
self._cust_str = "CUST"
# Load parameters to vary
self._load_params()
# **** Public methods ****
def vary(self):
""" Run parmaeter vary simulation """
# Start by generating "fiducial" experiments
tot_sims = (self._sim.param("nexp") * self._sim.param("ndet") *
self._sim.param("nobs"))
self._log.out((
"Simulting %d experiment realizations each with "
"%d detector realizations and %d sky realizations. "
"Total sims = %d"
% (self._sim.param("nexp"), self._sim.param("ndet"),
self._sim.param("nobs"), tot_sims)))
self._exps = []
self._sens = []
for n in range(self._nexp):
self._status(n, self._nexp)
exp = ex.Experiment(self._sim)
exp.evaluate()
sns = self._sim.sns.sensitivity(exp)
self._exps.append(exp)
self._sens.append(sns)
self._done()
# Loop over parameter set and adjust sensitivities
adj_sns = []
tot_adjs = self._nexp * len(self._set_arr)
self._log.out((
"Looping over %d parameter sets for %d realizations. "
"Number of experiment realizations to adjust = %d"
% (len(self._set_arr), self._sim.param("nexp"),
tot_adjs)))
for n, (exp, sens) in enumerate(zip(self._exps, self._sens)):
adj_sns.append(self._vary_exp(exp, sens, n, tot_adjs))
self._done()
# Combine and save experiment realizations
self.adj_sns = np.concatenate(adj_sns, axis=-1)
self._save()
return
# ***** Helper methods *****
def _save(self):
""" Save simulation outputs to files """
# Write parameter by parameter
tot_writes = len(self.adj_sns)
self._log.out((
"Writing outputs for %d parameters" % (tot_writes)))
for i in range(tot_writes):
self._status(i, tot_writes)
self._save_param_iter(i)
self._done()
return
def _adjust_sens(self, exp, sns, tel='', cam='', ch='', opt=''):
""" Calculate new sensitivity array where needed """
tel = self._cap(tel)
cam = self._cap(cam)
ch = self._cap(ch)
opt = self._cap(opt)
# Change channel parameter
if str(tel) != '' and str(cam) != '' and str(ch) != '':
tel_ind = list(exp.tels.keys()).index(tel)
cam_ind = list(exp.tels[tel].cams.keys()).index(cam)
ch_ind = list(exp.tels[tel].cams[cam].chs.keys()).index(ch)
channel = exp.tels[tel].cams[cam].chs[ch]
channel.evaluate()
sns[tel_ind][cam_ind][ch_ind] = self._sns.ch_sensitivity(
channel)
# Change optics parameter for both channels
elif (str(tel) != '' and str(cam) != '' and
str(ch) == '' and str(opt) != ''):
tel_ind = list(exp.tels.keys()).index(tel)
cam_ind = list(exp.tels[tel].cams.keys()).index(cam)
# Evaluate all channels in this camera
for ch in exp.tels[tel].cams[cam].chs:
ch_ind = list(exp.tels[tel].cams[cam].chs.keys()).index(ch)
channel = exp.tels[tel].cams[cam].chs[ch]
channel.evaluate()
sns[tel_ind][cam_ind][ch_ind] = self._sns.ch_sensitivity(
channel)
# Change camera parameter
elif str(tel) != '' and str(cam) != '':
tel_ind = list(exp.tels.keys()).index(tel)
cam_ind = list(exp.tels[tel].cams.keys()).index(cam)
# Evaluate camera
exp.tels[tel].cams[cam].evaluate()
# Store new sensitivity values
for ch_ind, channel in enumerate(
exp.tels[tel].cams[cam].chs.values()):
# channel.evaluate()
sns[tel_ind][cam_ind][ch_ind] = self._sns.ch_sensitivity(
channel)
# Change telescope parameter
elif str(tel) != '':
tel_ind = list(exp.tels.keys()).index(tel)
# Evaluate telescope
exp.tels[tel].evaluate()
for cam_ind, camera in enumerate(
exp.tels[tel].cams.values()):
for ch_ind, channel in enumerate(
camera.chs.values()):
# channel.evaluate()
sns[tel_ind][cam_ind][ch_ind] = (
self._sns.ch_sensitivity(channel))
# Change experiment parameter
else:
for tel_ind, telescope in enumerate(
exp.tels.values()):
for cam_ind, camera in enumerate(
telescope.cams.values()):
for ch_ind, channel in enumerate(
camera.chs.values()):
channel.evaluate()
sns[tel_ind][cam_ind][ch_ind] = (
self._sns.ch_sensitivity(channel))
return cp.deepcopy(sns)
def _set_new_pix_sz(self, cam, ch, tup):
""" Set new pixel size for given camera and channel """
i = tup[0]
j = tup[1]
# Check that the f-number is defined
f_num = cam.get_param('fnum')
if str(f_num) == 'NA':
self._log.err("Cannot set 'Pixel Size**' as a "
"parameter to vary without 'F Number' "
"also defined for this camera")
# Check that the band center is defined
bc = ch.get_param('bc')
if str(bc) == 'NA':
self._log.err("Cannot set 'Pixel Size**' as a "
"parameter to vary without "
"'Band Center' also defined for this "
"channel")
# Check that the waist factor is defined
wf = ch.get_param('wf')
if str(wf) == 'NA':
self._log.err("Cannot set 'Pixel Size**' as a "
"parameter to vary without "
"'Waist Factor' also defined for this "
"channel")
# Check that the aperture defined
opt_keys = list(cam.opt_chn.optics.keys())
# opt_keys_upper = [opt.replace(" ", "").upper() for opt in opt_keys]
if 'APERTURE' in opt_keys:
ap_name = 'APERTURE'
elif 'LYOT' in opt_keys:
ap_name = 'LYOT'
elif 'STOP' in opt_keys:
ap_name = 'STOP'
else:
self._log.err("Cannot pass 'Pixel Size**' as a "
"parameter to vary when neither "
"'Aperture' nor 'Lyot' nor 'Stop' "
"is defined in the camera's optical "
"chain")
ap = cam.opt_chn.optics[ap_name]
# Store current values for detector number, aperture
# efficiency, and pixel size
curr_pix_sz = ch.get_param('pix_sz')
curr_ndet = ch.get_param('det_per_waf')
curr_ap = ap.get_param(
'abs', band_ind=ch.band_ind) # median value
if curr_ap == 'NA':
curr_ap = None
# Calculate new values for detector number,
# aperture efficiency, and pixel size
new_pix_sz_mm = self._set_arr[i][j]
new_pix_sz = un.Unit('mm').to_SI(new_pix_sz_mm)
new_ndet = curr_ndet * np.power(
(curr_pix_sz / new_pix_sz), 2.)
if curr_ap is not None: # scale the median value
curr_eff = self._ph.spill_eff(
bc, curr_pix_sz, f_num, wf)
new_eff = self._ph.spill_eff(
bc, new_pix_sz, f_num, wf)
apAbs_new = 1. - (1. - curr_ap) * np.mean(new_eff / curr_eff)
else: # use band-averaged value
apAbs_new = 1. - self._ph.spill_eff(
bc, new_pix_sz, f_num, wf)
# Define new values
changed = []
changed.append(ch.change_param(
'pix_sz', new_pix_sz_mm))
changed.append(ch.change_param(
'det_per_waf', new_ndet))
changed.append(ap.change_param(
'abs', apAbs_new,
band_ind=ch.band_ind, num_bands=len(ch.cam.chs)))
return np.any(changed)
def _set_new_param(self, exp, tup):
""" Set new parameter value for given experiment """
i = tup[0]
j = tup[1]
scope = self._vary_scope(j)
# Change experiment parameter
if str(scope) == 'exp':
changed = exp.change_param(
self._params[j], self._set_arr[i][j])
# Change telescope parameter
elif str(scope) == 'tel':
tel = exp.tels[self._cap(self._tels[j])]
changed = tel.change_param(
self._params[j], self._set_arr[i][j])
# Change camera parameter
elif str(scope) == 'cam':
tel = exp.tels[self._cap(self._tels[j])]
cam = tel.cams[self._cap(self._cams[j])]
changed = cam.change_param(
self._params[j], self._set_arr[i][j])
# Change channel parameter
elif str(scope) == 'ch':
tel = exp.tels[self._cap(self._tels[j])]
cam = tel.cams[self._cap(self._cams[j])]
ch = cam.chs[self._cap(self._chs[j])]
changed = ch.change_param(
self._params[j], self._set_arr[i][j])
# Change optic parameter
elif str(scope) == 'opt':
tel = exp.tels[self._cap(self._tels[j])]
cam = tel.cams[self._cap(self._cams[j])]
opt = cam.opt_chn.optics[self._cap(self._opts[j])]
if self._chs[j] != '':
ch = cam.chs[self._cap(self._chs[j])]
changed = opt.change_param(
self._params[j], self._set_arr[i][j],
band_ind=ch.band_ind,
num_bands=len(cam.chs))
else:
changed = opt.change_param(
self._params[j], self._set_arr[i][j],
band_ind=None,
num_bands=len(cam.chs))
# Change the pixel size,
# varying detector number also
elif str(scope) == 'pix':
tel = exp.tels[self._cap(self._tels[j])]
cam = tel.cams[self._cap(self._cams[j])]
ch = cam.chs[self._cap(self._chs[j])]
changed = self._set_new_pix_sz(cam, ch, (i, j))
return changed
def _vary_exp(self, exp, sns, n, ntot):
""" Set new parameter combinations for defined experiment """
# Sensitivity for every parameter combination
sns_arr = []
# Loop over long-form data
for i in range(len(self._set_arr)):
self._status((n * len(self._set_arr) + i), ntot)
changes = []
# First adjust parameters
for j in range(len(self._set_arr[i])):
changed = self._set_new_param(exp, (i, j))
changes.append(changed)
# Where changes happened
changed_args = np.argwhere(changes).flatten()
chg_tels = self._tels[changed_args]
chg_cams = self._cams[changed_args]
chg_chs = self._chs[changed_args]
chg_opts = self._opts[changed_args]
# Only account for unique changes
chgs = np.array([chg_tels, chg_cams, chg_chs, chg_opts]).T
# If no changes occurred, move to the next parameter step
if len(chgs) == 0:
sns_arr.append(cp.deepcopy(sns))
continue
unique_chgs = np.unique(chgs, axis=0)
# Store new sensitivity values
for unique_chg in unique_chgs:
out_sns = self._adjust_sens(exp, sns, *unique_chg)
sns_arr.append(out_sns)
return sns_arr
def _save_param_iter(self, it):
""" Save sensitiviy for this parameter iteration """
exp = self._exps[0] # Just for retrieving names
sns = self.adj_sns[it]
# Write output files for every channel
if str(self._scope) != 'exp': # Overall scope of vary
tel_names = list(set(self._tels)) # unique tels
tels = [exp.tels[self._cap(tel_name)]
for tel_name in tel_names]
tel_inds = [list(exp.tels.keys()).index(self._cap(tel_name))
for tel_name in tel_names]
tel_iter = range(len(tels))
else: # Loop over all telescopes
tel_names = list(exp.tels.keys())
tels = exp.tels.values()
tel_inds = range(len(tels))
tel_iter = tel_inds
for i, tel, a in zip(tel_inds, tels, tel_iter):
if (str(self._scope) == 'cam' or str(self._scope) == 'ch'):
valid_inds = np.argwhere(
self._tels == tel_names[a]).flatten()
cam_names = list(set(self._cams[valid_inds]))
cams = [tel.cams[self._cap(cam_name)]
for cam_name in cam_names]
cam_inds = [list(tel.cams.keys()).index(self._cap(cam_name))
for cam_name in cam_names]
cam_iter = range(len(cams))
else: # Loop over all cameras
cam_names = list(tel.cams.keys())
cams = list(tel.cams.values())
cam_inds = range(len(cams))
cam_iter = cam_inds
for j, cam, b in zip(cam_inds, cams, cam_iter):
param_dir = self._check_dir(
os.path.join(cam.dir, self._param_dir))
vary_dir = os.path.join(param_dir, self._vary_name)
if it == 0:
if not os.path.isdir(vary_dir):
os.mkdir(vary_dir)
if (str(self._scope) == 'ch' or str(self._scope) == 'pix'):
valid_inds = np.argwhere(
(self._tels == tel_names[a]) *
(self._cams == cam_names[b])).flatten()
ch_names = list(set(self._chs[valid_inds])) # uniqee chs
chs = [cam.chs[self._cap(ch_name)]
for ch_name in ch_names]
ch_inds = [list(cam.chs.keys()).index(self._cap(ch_name))
for ch_name in ch_names]
else: # Loop over all channels
ch_names = list(cam.chs.keys())
chs = cam.chs.values()
ch_inds = range(len(chs))
for k, ch in zip(ch_inds, chs):
fch = os.path.join(
vary_dir, "%s.txt" % (ch.param("ch_name")))
if it == 0:
self._init_vary_file(fch)
ch_dir = self._check_dir(
os.path.join(vary_dir, ch.param("ch_name")))
fout = os.path.join(ch_dir, "output_%03d.txt" % (it))
# Convert from SI
sns_in = [list(
self._units.values())[m].from_SI(
np.array(sns[i][j][k][m]))
for m in range(len(sns[i][j][k]))]
# Write to files
self._write_output(sns_in, fout)
self._write_vary_row(it, sns_in, fch)
return
def _init_vary_file(self, fvary):
""" Initiate and format the output file """
# Add a left-most column for the parameter index
# Build formatting string using efficient spacer
fmt_str = ""
fmt_unit = ""
for spc in self._param_widths:
fmt_str += "%-" + str(int(spc)) + "s | "
fmt_unit += "%-" + str(int(spc)) + "s | "
ind_str = "%5s | " % ("")
# Formatting strings to be used when writing
self._fmt_str = fmt_str.replace("s", ".3f")
self._fmt_ind = " %03d | " # for writing index values
with open(fvary, 'w') as f:
f.write(ind_str + (fmt_str % (*self._tels,) + "\n"))
f.write(ind_str + (fmt_str % (*self._cams,) + "\n"))
f.write(ind_str + (fmt_str % (*self._chs,) + "\n"))
f.write(ind_str + (fmt_str % (*self._opts,) + "\n"))
f.write(ind_str + (fmt_str % (*self._params,)))
self._write_vary_header_params(f)
f.write(("Index | " + (fmt_unit % (*self._unit_strs,))))
self._write_vary_header_units(f)
self._horiz_line(f)
return
def _write_vary_header_params(self, f):
""" Write header for vary params output file """
title = ("%-23s | %-23s | %-23s | %-23s | "
"%-23s | %-23s | %-23s | %-23s | %-26s | %-26s | "
"%-23s | %-23s | %-23s | %-23s | %-23s\n"
% ("Optical Throughput", "Optical Power",
"Telescope Temp", "Sky Temp",
"Photon NEP", "Bolometer NEP", "Readout NEP",
"Detector NEP", "Detector NET_CMB",
"Detector NET_RJ", "Array NET_CMB",
"Array NET_RJ", "Correlation Factor",
"CMB Map Depth", "RJ Map Depth"))
f.write(title)
return
def _write_vary_header_units(self, f):
""" Write header units for output vary file """
unit = ("%-23s | %-23s | %-23s | %-23s | "
"%-23s | %-23s | %-23s | %-23s | %-26s | %-26s | "
"%-23s | %-23s | %-23s | %-23s | %-23s\n"
% ("", "[pW]", "[K_RJ]", "[K_RJ]",
"[aW/rtHz]", "[aW/rtHz]", "[aW/rtHz]",
"[aW/rtHz]", "[uK_CMB-rts]", "[uK_RJ-rts]",
"[uK_CMB-rts]", "[uK_RJ-rts]", "",
"[uK_CMB-amin]", "[uK_RJ-amin]"))
f.write(unit)
return
def _horiz_line(self, f):
""" Draw a horizontal line in the output file """
width = int(405 + sum(self._param_widths) + len(self._params))
f.write(("-" * width + "\n"))
return
def _write_output(self, data, fout):
""" Write formatted output to output file """
with open(fout, 'w') as fwrite:
data_write = np.transpose(data)
for row in data_write: # params
wrstr = ""
for val in row:
wrstr += ("%-9.4f " % (val))
fwrite.write(wrstr)
fwrite.write("\n")
return
def _write_vary_row(self, it, data, fch):
""" Write row of data to the output file """
with open(fch, 'a') as f:
f.write(self._fmt_ind % (int(it)))
f.write(self._fmt_str % (*self._set_arr[it],))
spreads = [self._spread(dat) for dat in data]
wstr = ("%-5.3f +/- (%-5.3f,%5.3f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-6.1f +/- (%-6.1f,%6.1f) | "
"%-6.1f +/- (%-6.2f,%6.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.3f,%5.3f) | "
"%-5.2f +/- (%-5.2f,%5.2f) | "
"%-5.2f +/- (%-5.2f,%5.2f)\n"
% (*np.array(spreads).flatten(),))
f.write(wstr)
return
def _check_dir(self, dir_val):
""" Check that the output directory exists, or make it """
if not os.path.isdir(dir_val):
os.mkdir(dir_val)
return dir_val
def _status(self, n, ntot):
""" Print status bar """
frac = float(n)/float(ntot)
sy.stdout.write('\r')
sy.stdout.write("[%-*s] %02.1f%%" % (int(self._bar_len),
'=' * int(self._bar_len * frac), frac * 100.))
sy.stdout.flush()
def _done(self):
""" Print filled status bar """
sy.stdout.write('\r')
sy.stdout.write(
"[%-*s] %.1f%%" % (self._bar_len, '=' * self._bar_len, 100.))
sy.stdout.write('\n')
sy.stdout.flush()
return
def _load_params(self):
""" Load parameters to vary from input file """
self._log.log(
"Loading parameters to vary from %s" % (self._param_file))
# Converted loaded paraemters to strings with whitespace stripped
convs = {i: lambda s: s.strip() for i in range(8)}
# Load data from vary file
data = np.loadtxt(self._param_file, delimiter='|', dtype=str,
unpack=True, ndmin=2, converters=convs)
# Skip the first line if it wasn't commented out
if data[5][0].upper() == "MINIMUM":
data = [d[1:] for d in data]
self._tels, self._cams, self._chs, self._opts = data[:4]
self._params, mins, maxs, stps = data[4:]
params_upper = [param.replace(" ", "").strip().upper()
for param in self._params]
# Store the units associated with the loaded parameters
self._unit_strs = ["[" + self._sim.std_params[
param.replace(" ", "").upper()].unit.name + "]"
for param in self._params]
# Array to manage table spacing - don't waste space!
param_widths = [len(max(
[self._tels[i], self._cams[i], self._chs[i],
self._opts[i], self._params[i]], key=len))
for i in range(len(self._params))]
self._param_widths = [width if width > 10 else 10
for width in param_widths]
# Check for consistency of number of parameters varied
if len(set([len(d) for d in data])) == 1:
self._num_params = len(self._params)
else:
self._log.err("Number of telescopes, parameters, mins, maxes, and "
"steps must match for parameters to be varied "
"in %s" % (self._param_file))
# Check if any parameters use custom-defined inputs
min_empty = (np.char.upper(mins) == self._cust_str)
max_empty = (np.char.upper(maxs) == self._cust_str)
stp_empty = (np.char.upper(stps) == self._cust_str)
if np.any(min_empty) or np.any(max_empty) or np.any(stp_empty):
if not np.any(np.logical_and(
np.logical_and(min_empty, max_empty),
np.logical_and(max_empty, stp_empty))):
self._log.err(
"Either all of or none of (min, max, step) must be "
"defined as 'CUST' for each parameter to be varied "
"in %s" % (self._param_file))
else:
cust_inds = min_empty
else:
cust_inds = None
# If min, max, and step is not defined, check for a custom file
cust_params = [[] for n in range(self._num_params)]
if cust_inds is not None:
existing_files = os.listdir(self._cust_dir)
existing_files_upper = np.char.upper(existing_files)
cust_labels = np.array(
[self._tels[cust_inds], self._cams[cust_inds],
self._chs[cust_inds], self._opts[cust_inds],
self._params[cust_inds]]).T
for ii, cust_label in enumerate(cust_labels):
lab_arr = [("%s" % (lab)).replace(" ", "").strip()
for lab in cust_label if lab != ""]
fname = "%s.txt" % ("_".join(lab_arr))
fname_upper = fname.upper()
select_ind = np.argwhere(
fname_upper == existing_files_upper).flatten()
if len(select_ind) == 1:
fload = np.take(existing_files, select_ind)[0]
fload_path = os.path.join(self._cust_dir, fload)
cust_param_arr = np.loadtxt(
fload_path, unpack=True, dtype=np.float)
cust_params[ii] = cust_param_arr.tolist()
elif len(select_ind) > 1:
self._log.err("Duplicate custom parameter vary file %s detected"
% (existing_files[select_ind].flatten()[0]))
else:
fload = os.path.join(self._cust_dir, fname)
self._log.err("Could not locate custom parameter vary file %s"
% (fload))
# Store the parameter arrays
set_arr = []
for ii in range(self._num_params):
min_val = mins[ii]
max_val = maxs[ii]
stp_val = stps[ii]
if min_val.upper() == self._cust_str:
set_arr.append(cust_params[ii])
elif (float(max_val) - float(min_val)) < float(stp_val):
self._log.err(
"Step value cannot be larger than max value minus min "
"value for parameters to be varied in %s"
% (self._param_file))
else:
set_arr.append(np.arange(
float(min_val), float(max_val)+float(stp_val),
float(stp_val)).tolist())
# If vary together flag is set, move the parameters together
# Transpose parameter arrays from wide-form to long-form
if self._vary_tog:
# Check that the parameter arrays are the same length
arr_lens = [len(arr) for arr in set_arr]
if not len(set(arr_lens)) == 1:
self._log.err(
"Cannot vary parameters in '%s' together because array "
"because array lengths are different" % (self._param_file))
self._set_arr = np.array(set_arr).T
else:
self._set_arr = self._wide_to_long(set_arr)
# Special joint consideration of pixel size, spill efficiency,
# and detector number
if 'PIXELSIZE**' in params_upper:
if not np.any(np.isin(
params_upper, ['WAISTFACTOR', 'APERTURE', 'LYOT',
'STOP', 'NUMDETPERWAFER'])):
self._pix_size_special = True
else:
self._log.err("Cannot pass 'Pixel Size**' as a parameter to "
"'%s' when 'Aperture', 'Lyot', 'Stop', or "
"'Num Det per Wafer' is also passed"
% (self._param_file))
else:
self._pix_size_special = False
return
def _vary_scope(self, ind):
""" Find scope of the parameter vary """
scope = ''
ret_val = ''
if self._tels[ind] != '':
scope = 'tel'
if self._cams[ind] != '':
scope = 'cam'
if str(self._chs[ind]) != '':
scope = 'ch'
if self._opts[ind] != '':
ret_val = 'opt'
elif ('PIXELSIZE' in
self._params[ind].replace(" ", "").upper() and
self._pix_size_special):
ret_val = 'pix'
else:
ret_val = 'ch'
else:
if self._opts[ind] != '':
ret_val = 'opt'
else:
ret_val = 'cam'
else:
ret_val = 'tel'
else:
scope = 'exp'
ret_val = 'exp'
# Set a new global scope
if scope == 'exp':
self._scope == 'exp'
elif (scope == 'tel' and (
self._scope == '' or self._scope == 'cam' or
self._scope == 'ch')):
self._scope = 'tel'
elif (scope == 'cam' and (
self._scope == '' or self._scope == 'ch')):
self._scope = 'cam'
elif (scope == 'ch' and self._scope == ''):
self._scope = 'ch'
else:
pass
# Return scope for this parameter
return ret_val
def _wide_to_long(self, inp_arr):
""" Convert wide-form data to long-form data """
len_arr = [len(inp) for inp in inp_arr]
ret_arr = []
for i in range(len(inp_arr)):
inner_arr = []
if i < len(inp_arr) - 1:
for j in range(len_arr[i]):
inner_arr += (
[inp_arr[i][j]] * np.prod(len_arr[i+1:]))
else:
inner_arr += inp_arr[i]
if i > 0:
ret_arr.append(inner_arr * np.prod(len_arr[:i]))
else:
ret_arr.append(inner_arr)
return np.transpose(ret_arr)
def _spread(self, inp, unit=None):
""" Calculate parameter output distribution spread """
pct_lo, pct_hi = self._sim.param("pct")
if unit is None:
unit = un.Unit("NA")
lo, med, hi = unit.from_SI(np.percentile(
inp, (float(pct_lo), 50.0, float(pct_hi))))
return [med, abs(hi-med), abs(med-lo)]
def _cap(self, inp):
""" Captialize a string and strip spaces """
return str(inp).replace(" ", "").strip().upper()