def calc_model(pitch_pdf=[1, 2, 3, 4], tank_start=None): """ Calculate tank model for a simulated set of observations that follow the specified pitch probability density function ``pitch_pdf``. This argument corresponds to the fraction of observations in the four PITCH_BINS. This will be normalized to one by the function. """ tank_start = F2C(tank_start) # convert to degC model = xija.ThermalModel('pftank2t', '2013:001', '2013:008', model_spec='pftank2t_spec.json') times = model.times pitches = get_pitches(len(times), pitch_pdf) model.comp['pftank2t'].set_data(tank_start) model.comp['pf0tank2t'].set_data(tank_start) model.comp['pitch'].set_data(pitches, times) model.comp['eclipse'].set_data(False) model.make() model.calc() return model
def calc_model(start, pitch, model_spec): stop = DateTime(start) + 10 model = xija.ThermalModel('pftank2t', start=start, stop=stop, model_spec=model_spec) model.comp['eclipse'].set_data(False) model.comp['pitch'].set_data(pitch) model.comp['pf0tank2t'].set_data(35.0) model.comp['pftank2t'].set_data(35.0) model.make() model.calc() return model
def update_fit_times(self, start=None, stop=None, days=180): """Update model fit times to new values. :param start: Start date for model fit duration :param stop: Stop date for model fit duration :param days: Number of days of data to use to fit the model Either 'start' and 'days', or 'stop' and 'days', or both 'start' and 'stop' must be defined, accounting for the fact that the default value for days is defined above. This re-initializes and runs the Xija model object with new times without changing the parameters. """ if (start is None) and (stop is None): raise ValueError( "Either 'start' and 'days', or 'stop' and 'days', or both 'start' and 'stop' must be defined." ) if start and stop: self.start = DateTime(start).date self.stop = DateTime(stop).date elif stop is None: self.start = DateTime(start).date self.stop = DateTime(DateTime(start).secs + days * 24 * 3600.).date[:8] else: self.start = DateTime(DateTime(start).secs - days * 24 * 3600.).date[:8] self.stop = DateTime(stop).date self.model = xija.ThermalModel(self.model_spec['name'], self.start, self.stop, model_spec=self.model.model_spec) # These solarheat parameters need to be defined to avoid an AttributeError in heat.py. The actual # values don't matter as they are deleted when setting the epoch. for key, value in list(self.model.comp.items()): if 'solarheat' in key: if not hasattr(self.model.comp[key], 't_days'): self.model.comp[key].t_days = -1 if not hasattr(self.model.comp[key], 't_phase'): self.model.comp[key].t_phase = -1 if self.set_data_exprs: self.set_init_data(self.set_data_exprs) if not self.keep_epoch: self.set_epoch() self.model.make() self.model.calc()
def calc_model_pyger(self, states, times, T0s, state_only=False): print 'TANK:', CtoF(T0s) model = xija.ThermalModel('tank', start=states['tstart'][0], stop=states['tstop'][-1], model_spec=self.model_spec) state_times = np.array([states['tstart'], states['tstop']]) model.comp['pitch'].set_data(states['pitch'], state_times) model.comp['eclipse'].set_data(False) model.comp['pf0tank2t'].set_data(T0s[0]) model.comp['pftank2t'].set_data(T0s[0]) model.make() model.calc()
def setup_model(msid, t0, t1, model_spec, init): """ Create Xija model object This function creates a Xija model object with initial parameters, if any. This function is intended to create a streamlined method to creating Xija models that can take both single value data and time defined data (e.g. [pitch1, pitch2, pitch3], [time1, time2, time3]), defined in the `init` dictionary. :param msid: Primary MSID for model; in this case it can be anything as it is only being used to name the model, however keeping the convention to name the model after the primary MSID being predicted reduces confusion :type msid: str :param t0: Start time for model prediction; this can be any format that cxotime.CxoTime accepts :type t0: str or float or int :param t1: End time for model prediction; this can be any format that cxotime.CxoTime accepts :type t1: str or float or int :param model_spec: Dictionary of model parameters or file location where parameters can be imported :type model_spec: dict, str :param init: Dictionary of Xija model initialization parameters, can be empty :type init: dict :rtype: xija.model.XijaModel Example:: model_specs = load_model_specs() init = {'1dpamzt': 35., 'dpa0': 35., 'eclipse': False, 'roll': 0, 'vid_board': True, 'pitch':155, 'clocking': True, 'fep_count': 5, 'ccd_count': 5, 'sim_z': 100000} model = setup_model('1dpamzt', '2019:001:00:00:00', '2019:010:00:00:00', model_specs['1dpamzt'], init) Notes: - This does not run the model, only sets up the model to be run. - Any parameters not specified in `init` will either need to be pulled from telemetry or explicitly defined \ outside of this function before running the model. """ model = xija.ThermalModel(msid, start=t0, stop=t1, model_spec=model_spec) for key, value in init.items(): if isinstance(value, dict): model.comp[key].set_data(value['data'], value['times']) else: model.comp[key].set_data(value) return model
def calc_model(pitch): model = xija.ThermalModel('pftank2t', '2013:001', '2013:040', model_spec='pftank2t_model_spec.json') times = model.times days = (model.times - model.times[0]) / 86400. ok = (days > 10.0) & (days < 30.0) pitches = np.zeros_like(times) + 160.0 pitches[ok] = pitch model.comp['pftank2t'].set_data(22.0) model.comp['pf0tank2t'].set_data(22.0) model.comp['pitch'].set_data(pitches, times) model.comp['eclipse'].set_data(False) model.make() model.calc() return model
# Licensed under a 3-clause BSD style license - see LICENSE.rst """ Replicate (mostly) the minusz TEPHIN node model. (dPs set to zero though). env PYTHONPATH=$PWD python minusz/minusz.py """ import xija import json P_pitches = [45, 60, 90, 120, 145, 170] P_pitches2 = [45, 60, 90, 120, 145, 171] minusz = json.load(open('/proj/sot/ska/share/nmass/minusz/pars_minusz.json')) sigmas = {'tephin': -10} mdl = xija.ThermalModel(name='minusz', start='2010:001', stop='2010:002') nodes = {} pitch = mdl.add(xija.Pitch) eclipse = mdl.add(xija.Eclipse) for msid in minusz: pars = minusz[msid] Ps = [pars['pf_{0:03d}'.format(p)] for p in P_pitches] nodes[msid] = mdl.add(xija.Node, msid, sigma=sigmas.get(msid, -20)) mdl.add(xija.SolarHeat, msid, pitch, eclipse, P_pitches2, Ps, ampl=pars['p_ampl'])
# Licensed under a 3-clause BSD style license - see LICENSE.rst """ Replicate (mostly) the minusz TEPHIN node model. (dPs set to zero though). """ import numpy as np import xija mdl = xija.ThermalModel(start='2010:001', stop='2010:014') tephin = mdl.add(xija.Node, 'tephin') tcylaft6 = mdl.add(xija.Node, 'tcylaft6', predict=False) tmzp_my = mdl.add(xija.Node, 'tmzp_my', predict=False) coup__tephin__tcylaft6 = mdl.add(xija.Coupling, tephin, tcylaft6, tau=130.26) coup__tephin__tmzp_my = mdl.add(xija.Coupling, tephin, tmzp_my, tau=105.91) aosares1 = mdl.add(xija.TelemData, 'aosares1') tephin_solar = mdl.add(xija.SolarHeat, tephin, aosares1, P_pitches=[45, 60, 90, 120, 145, 170], Ps=np.array([0.970, 1.42, 1.91, 1.92, 1.42, 0.69]), ampl=0.0679) tephin_heatsink = mdl.add(xija.HeatSink, tephin, T=0.0, tau=38.0) pars_minusz = """ "tephin": { "T_e": 0.0, "p_ampl": 0.067919468805023628, "pf_045": 0.96976110603706989, "pf_060": 1.4221924089192244,
# Licensed under a 3-clause BSD style license - see LICENSE.rst """ Replicate (mostly) the minusz TEPHIN node model. (dPs set to zero though). """ import json import xija P_pitches=[45, 60, 90, 120, 145, 170] P_pitches2=[45, 60, 90, 120, 145, 171] minusz = json.load(open('nmass/minusz/pars_minusz.json')) mdl = xija.ThermalModel('minusz', start='2010:001', stop='2010:360') nodes = {} pitch = mdl.add(xija.Pitch) eclipse = mdl.add(xija.Eclipse) for msid in minusz: pars = minusz[msid] Ps = [pars['pf_{0:03d}'.format(p)] for p in P_pitches] nodes[msid] = mdl.add(xija.Node, msid) mdl.add(xija.SolarHeat, msid, pitch, eclipse, P_pitches2, Ps, ampl=pars['p_ampl']) mdl.add(xija.HeatSink, msid, T=pars['T_e'], tau=pars['tau_ext']) for msid in minusz: pars = minusz[msid] coupled_nodes = [x for x in pars if x.startswith('tau_t')] for parname in coupled_nodes: mdl.add(xija.Coupling, msid, node2=parname[4:], tau=pars[parname]) mdl.make()
comm.Reduce([semaphore, MPI.DOUBLE], None, op=MPI.SUM, root=0) break elif cmd == 'init': fit_start = DateTime(msg['tstart']).secs fit_stop = DateTime(msg['tstop']).secs dt = (fit_stop - fit_start) / size tstart = fit_start + dt * rank tstop = tstart + dt print 'xija_worker {4} of {5}: Working init {0}:{1} fetching data {2} {3}'.format( rank, procname, DateTime(tstart).date, DateTime(tstop).date, rank, size) src.update((x, msg[x]) for x in ('model', 'outdir', 'pardir')) model_spec = json.load(open(files['model_spec.json'].abs, 'r')) model = xija.ThermalModel(name=msg['model'], start=tstart, stop=tstop, model_spec=model_spec) model.make() elif cmd == 'calc_model': model.parvals[:] = msg['parvals'] elif cmd == 'calc_stat': fit_stat = model.calc_stat() comm.Reduce([fit_stat, MPI.DOUBLE], None, op=MPI.SUM, root=0) elif cmd == 'model': model_func = getattr(model, msg['func']) args = msg.get('args', []) kwargs = msg.get('kwargs', {}) model_func(*args, **kwargs)
# Licensed under a 3-clause BSD style license - see LICENSE.rst import xija import numpy as np import matplotlib.pyplot as plt from Ska.Matplotlib import pointpair start = '2010:001' stop = '2011:345' msid = '1dpamzt' model_spec = 'dpa.json' model = xija.ThermalModel('dpa', start=start, stop=stop, model_spec=model_spec) model.make() model.calc() dpa = model.get_comp(msid) resid = dpa.dvals - dpa.mvals xscatter = np.random.uniform(-0.2, 0.2, size=len(dpa.dvals)) yscatter = np.random.uniform(-0.2, 0.2, size=len(dpa.dvals)) plt.clf() plt.plot(dpa.dvals + xscatter, resid + yscatter, '.', ms=1.0, alpha=1) plt.xlabel('{} telemetry (degC)'.format(msid.upper())) plt.ylabel('Data - Model (degC)') plt.title('Residual vs. Data ({} - {})'.format(start, stop)) bins = np.arange(6, 26.1, 2.0) r1 = [] r99 = [] ns = []
def main(): # Enable fully-randomized evaluation of ACIS-FP model which is desirable # for fitting. taco.set_random_salt(None) opt = get_options() src = pyc.CONTEXT['src'] if 'src' in pyc.CONTEXT else pyc.ContextDict( 'src') files = (pyc.CONTEXT['file'] if 'file' in pyc.CONTEXT else pyc.ContextDict( 'files', basedir=str(Path.cwd()))) files.update(xija.files) sherpa_logger = logging.getLogger("sherpa") loggers = (fit_logger, sherpa_logger) if opt.quiet: for logger in loggers: for h in logger.handlers: logger.removeHandler(h) if opt.filename.endswith(".json"): model_spec = json.load(open(opt.filename, 'r')) elif opt.filename in get_xija_model_names(): model_spec, model_version = get_xija_model_spec(opt.filename) else: raise RuntimeError("'filename' not a valid path to a JSON file " "or a valid model name!") gui_config.update(model_spec.get('gui_config', {})) src['model'] = model_spec['name'] # Use supplied stop time and days OR use model_spec values if stop not supplied if opt.stop: start = CxoTime(CxoTime(opt.stop).secs - opt.days * 86400).date[:8] stop = opt.stop else: start = model_spec['datestart'] stop = model_spec['datestop'] model = xija.ThermalModel(model_spec['name'], start, stop, model_spec=model_spec) set_data_vals = gui_config.get('set_data_vals', {}) for set_data_expr in opt.set_data_exprs: set_data_expr = re.sub('\s', '', set_data_expr) try: comp_name, val = set_data_expr.split('=') except ValueError: raise ValueError( "--set_data must be in form '<comp_name>=<value>'") # Set data to value. ast.literal_eval is a safe way to convert any # string literal into the corresponding Python object. set_data_vals[comp_name] = ast.literal_eval(val) for comp_name, val in set_data_vals.items(): model.comp[comp_name].set_data(val) model.make() if opt.inherit_from: inherit_spec = json.load(open(opt.inherit_from, 'r')) inherit_pars = {par['full_name']: par for par in inherit_spec['pars']} for par in model.pars: if par.full_name in inherit_pars: print("Inheriting par {}".format(par.full_name)) par.val = inherit_pars[par.full_name]['val'] par.min = inherit_pars[par.full_name]['min'] par.max = inherit_pars[par.full_name]['max'] par.frozen = inherit_pars[par.full_name]['frozen'] par.fmt = inherit_pars[par.full_name]['fmt'] filename = Path(opt.filename) if filename.exists(): gui_config['filename'] = str(filename.resolve()) else: gui_config['filename'] = None gui_config['set_data_vals'] = set_data_vals fit_worker = FitWorker(model, opt.maxiter, method=opt.fit_method) model.calc() app = QtWidgets.QApplication(sys.argv) icon_path = str(Path(__file__).parent / "app_icon.png") icon = QtGui.QIcon(icon_path) app.setWindowIcon(icon) MainWindow(model, fit_worker, opt.filename) sys.exit(app.exec_())
# Licensed under a 3-clause BSD style license - see LICENSE.rst import os import json import numpy as np import xija mdl = xija.ThermalModel(start='2010:001', stop='2010:004') tephin = mdl.add(xija.Node, 'tephin') tcylaft6 = mdl.add(xija.Node, 'tcylaft6', predict=False) coup_tephin_tcylaft6 = mdl.add(xija.Coupling, tephin, tcylaft6, tau=20) aosares1 = mdl.add(xija.TelemData, 'aosares1') tephin_solar = mdl.add(xija.SolarHeat, tephin, aosares1, Ps=[0.1, 0.5, 1.0, 1.5, 2.0], dPs=[0.01, 0.02, 0.03, 0.04, 0.05]) tephin_heatsink = mdl.add(xija.HeatSink, tephin, T=0.0, tau=20.0) mdl.make() mdl.write('test_write.json') model_spec = json.load(open('test_write.json')) mdl2 = xija.ThermalModel(start='2010:001', stop='2010:004', model_spec=model_spec) os.unlink('test_write.json')
P_pitches = [50, 90, 150] P_vals = [] for instr in ('hrcs', 'hrci', 'acis'): for pitch in P_pitches: P_vals.append(pars['{0}{1}'.format(instr, pitch)]) P_vals = np.array(P_vals).reshape(3, 3) * u01 / c1 P_vals = P_vals.tolist() tau_e = c1 / u01 T_e = -128.0 * (1. / u01 + 1. / u12) k = 1. / c2 tau12 = c1 / u12 tau21 = c2 / u12 mdl = xija.ThermalModel('psmc', start='2011:103:00:00:00.00', stop='2011:124:00:00:00') pin1at = mdl.add(xija.Node, '1pin1at') pdeaat = mdl.add(xija.Node, '1pdeaat') pitch = mdl.add(xija.Pitch) sim_z = mdl.add(xija.SimZ) coup12 = mdl.add(xija.Coupling, pin1at, pdeaat, tau=tau12) coup21 = mdl.add(xija.Coupling, pdeaat, pin1at, tau=tau21) sol = mdl.add(xija.AcisPsmcSolarHeat, pin1at, pitch, sim_z, P_pitches=P_pitches, P_vals=P_vals)
# Build the core.so module and put into the source directory. # python setup.py build_ext --inplace # Licensed under a 3-clause BSD style license - see LICENSE.rst import xija model = xija.ThermalModel('test', start='2011:001', stop='2011:005') tephin = model.add(xija.Node, 'tephin') model.add(xija.HeatSink, tephin, T=0.0, tau=200.0) tephin.set_data(30.0) model.make() model.calc() # plot(model.times - model.times[0], model.comp['tephin'].mvals) mvals = model.comp['tephin'].mvals assert len(mvals) == 1051 assert mvals[0] == 30.0 assert abs(mvals[500] - 8.75402) < 0.001 assert abs(mvals[1050] - 2.26212) < 0.001
loggers = (fit_logger, sherpa_logger) if opt.quiet: for logger in loggers: for h in logger.handlers: logger.removeHandler(h) # Use supplied stop time or NOW - 7 days (truncated to nearest day) stop = opt.stop or DateTime(DateTime().secs - 7 * 86400).date[:8] start = DateTime(DateTime(stop).secs - opt.days * 86400).date[:8] src['model'] = opt.model src['outdir'] = opt.outdir src['pardir'] = opt.pardir or opt.model model_spec = json.load(open(files['model_spec.json'].abs, 'r')) model = xija.ThermalModel(opt.model, start, stop, model_spec=model_spec) ### UGHH, need to clean this up, probably have model elements accumulate dynamically ### instead of a make step. if not opt.nproc: model.make() model.outdir = src['outdir'].val model.pardir = src['pardir'].val thaw_pars = opt.thaw_pars.split() make_out_dir() hdlr = logging.FileHandler(files['fit_log'].abs, 'w') hdlr.setLevel(logging.INFO)