From a9f1b6f5c6529d0ab196d33677d65a1c0f7b0b3c Mon Sep 17 00:00:00 2001 From: Mike Harms Date: Sat, 10 Jun 2017 08:47:02 -0700 Subject: [PATCH 1/2] few tweaks for integration with gui --- pytc/experiments/base.py | 32 +++++++++++++++++++++++++------- pytc/experiments/chooser.py | 4 ++-- pytc/fit_param.py | 19 ++++++++++++++++--- pytc/fitters/base.py | 3 --- pytc/fitters/bayesian.py | 2 ++ pytc/fitters/bootstrap.py | 2 ++ pytc/fitters/ml.py | 2 ++ pytc/global_fit.py | 33 +++++++++++++++++++++++++++++---- 8 files changed, 78 insertions(+), 19 deletions(-) diff --git a/pytc/experiments/base.py b/pytc/experiments/base.py index b0673fd..41f76b2 100644 --- a/pytc/experiments/base.py +++ b/pytc/experiments/base.py @@ -22,13 +22,13 @@ class BaseITCExperiment: Class that holds an experimental ITC measurement and a model that describes it. """ - AVAIL_UNITS = {"cal":1.9872036, - "kcal":0.0019872036, - "J":8.3144598, - "kJ":0.0083144598} + AVAIL_UNITS = {"cal/mol":1.9872036, + "kcal/mol":0.0019872036, + "J/mol":8.3144598, + "kJ/mol":0.0083144598} - def __init__(self,dh_file,model,shot_start=1,units="cal",uncertainty=0.1, - **model_kwargs): + def __init__(self,dh_file,model,shot_start=1,units="cal/mol", + uncertainty=0.1,**model_kwargs): """ Parameters @@ -42,7 +42,7 @@ def __init__(self,dh_file,model,shot_start=1,units="cal",uncertainty=0.1, what shot to use as the first real point. Shots start at 0, so default=1 discards first point. units : string - file units ("cal","kcal","J","kJ") + file units ("cal/mol","kcal/mol","J/mol","kJ/mol") uncertainty : float > 0.0 uncertainty in integrated heats (set to same for all shots, unless specified in something like NITPIC output file). @@ -219,6 +219,24 @@ def units(self): return self._units + @units.setter + def units(self,units): + """ + Change the units. + """ + + # Deal with units + self._units = units + try: + self._R = self.AVAIL_UNITS[self._units] + except KeyError: + err = "units must be one of:\n" + for k in self.AVAIL_UNITS.keys(): + err += " {}\n".format(k) + err += "\n" + + raise ValueError(err) + @property def R(self): """ diff --git a/pytc/experiments/chooser.py b/pytc/experiments/chooser.py index c1cfb8b..f85cebe 100644 --- a/pytc/experiments/chooser.py +++ b/pytc/experiments/chooser.py @@ -1,7 +1,7 @@ from . import OriginExperiment, NitpicExperiment -def ITCExperiment(dh_file,model,shot_start=1,units="cal",uncertainty=0.1, +def ITCExperiment(dh_file,model,shot_start=1,units="cal/mol",uncertainty=0.1, **model_kwargs): """ Wrapper that creates a BaseITCExperiment instance that that holds an ITC @@ -19,7 +19,7 @@ def ITCExperiment(dh_file,model,shot_start=1,units="cal",uncertainty=0.1, what shot to use as the first real point. Shots start at 0, so default=1 discards first point. units : string - file units ("cal","kcal","J","kJ") + file units ("cal/mol","kcal/mol","J/mol","kJ/mol") uncertainty : float > 0.0 uncertainty in integrated heats (set to same for all shots, unless specified in something like NITPIC output file). diff --git a/pytc/fit_param.py b/pytc/fit_param.py index c09d1bb..2d4ae22 100644 --- a/pytc/fit_param.py +++ b/pytc/fit_param.py @@ -39,10 +39,15 @@ def __init__(self,name,guess=None,guess_range=None,fixed=False,bounds=None, self.fixed = fixed self.bounds = bounds self.alias = alias - - self.value = self.guess + + self._initialize_fit_results() - # These will be filled in by the fitter + def _initialize_fit_results(self): + """ + Set fit results to start (stdev, ninetyfive, value to guess). + """ + + self.value = self.guess self._stdev = np.inf self._ninetyfive = [-np.inf,np.inf] @@ -158,6 +163,7 @@ def guess(self,g): self._guess = 1.0 self._value = self._guess + self._initialize_fit_results() #-------------------------------------------------------------------------- # parameter guess_range @@ -196,6 +202,8 @@ def guess_range(self,g): else: self._guess_range = [-10000.0,10000.0] + self._initialize_fit_results() + #-------------------------------------------------------------------------- # parameter fixed-ness. @@ -214,6 +222,7 @@ def fixed(self,bool_value): """ self._fixed = bool(bool_value) + self._initialize_fit_results() #-------------------------------------------------------------------------- # bounds for fit. @@ -245,6 +254,8 @@ def bounds(self,b): else: self._bounds = (-np.inf,np.inf) + self._initialize_fit_results() + #-------------------------------------------------------------------------- # parameter alias @@ -270,3 +281,5 @@ def alias(self,a): pass self._alias = a + + self._initialize_fit_results() diff --git a/pytc/fitters/base.py b/pytc/fitters/base.py index 1b26c98..d55f701 100644 --- a/pytc/fitters/base.py +++ b/pytc/fitters/base.py @@ -172,8 +172,6 @@ def corner_plot(self,filter_params=(),*args,**kwargs): return fig - return fig - @property def samples(self): """ @@ -184,4 +182,3 @@ def samples(self): return self._samples except AttributeError: return [] - diff --git a/pytc/fitters/bayesian.py b/pytc/fitters/bayesian.py index 1fcb99a..3f464d4 100644 --- a/pytc/fitters/bayesian.py +++ b/pytc/fitters/bayesian.py @@ -62,6 +62,8 @@ def __init__(self,num_walkers=100,initial_walker_spread=1e-4,ml_guess=True, err = "multithreading has not yet been (fully) implemented.\n" raise NotImplementedError(err) + self._success = None + self.fit_type = "bayesian" def ln_prior(self,param): diff --git a/pytc/fitters/bootstrap.py b/pytc/fitters/bootstrap.py index be09dd3..a454382 100644 --- a/pytc/fitters/bootstrap.py +++ b/pytc/fitters/bootstrap.py @@ -73,6 +73,8 @@ def fit(self,model,parameters,bounds,y_obs,y_err=None,param_names=None): self._bounds= bounds self._y_obs = y_obs self._y_err = y_err + + self._success = None if y_err is None or self._exp_err == False: self._y_err = np.array([self._perturb_size diff --git a/pytc/fitters/ml.py b/pytc/fitters/ml.py index f844930..f913240 100644 --- a/pytc/fitters/ml.py +++ b/pytc/fitters/ml.py @@ -58,6 +58,8 @@ def fit(self,model,parameters,bounds,y_obs,y_err,param_names=None): self._y_obs = y_obs self._y_err = y_err + self._success = None + # If no error is specified, assign the error as 1/N, identical for all # points self._y_err = y_err diff --git a/pytc/global_fit.py b/pytc/global_fit.py index 5d79305..73fcd0e 100644 --- a/pytc/global_fit.py +++ b/pytc/global_fit.py @@ -63,6 +63,10 @@ def add_experiment(self,experiment): self._expt_dict[name] = experiment self._expt_list_stable_order.append(name) + # Delete the fitter if we remove an experiment. It is no longer valid + self.delete_current_fit() + + def remove_experiment(self,experiment): """ Remove an experiment from the analysis. @@ -89,6 +93,9 @@ def remove_experiment(self,experiment): self._expt_dict.pop(expt_name) self._expt_list_stable_order.remove(expt_name) + # Delete the fitter if we remove an experiment. It is no longer valid + self.delete_current_fit() + def link_to_global(self,expt,expt_param,global_param_name): """ Link a local experimental fitting parameter to a global fitting @@ -450,6 +457,15 @@ def _parse_fit(self): err = "Paramter type {} not recognized.\n".format(self._flat_param_type[i]) raise ValueError(err) + def delete_current_fit(self): + """ + Delete the current experiment (if it exists). + """ + + try: + del self._fitter + except AttributeError: + pass def plot(self,correct_molar_ratio=False,subtract_dilution=False, color_list=None,data_symbol="o",linewidth=1.5,num_samples=100): @@ -493,9 +509,13 @@ def plot(self,correct_molar_ratio=False,subtract_dilution=False, ax[i].yaxis.set_ticks_position('left') ax[i].xaxis.set_ticks_position('bottom') + # Nothing to plot + if len(self._expt_list_stable_order) < 1: + return fig, ax + # Add labels to top plot and remove x-axis u = self._expt_dict[self._expt_list_stable_order[0]].units - ax[0].set_ylabel("heat per shot ({}/mol)".format(u)) + ax[0].set_ylabel("heat per shot ({})".format(u)) plt.setp(ax[0].get_xticklabels(), visible=False) # Add labels to the residuals plot @@ -586,7 +606,9 @@ def corner_plot(self,filter_params=("competent","dilution","intercept","heat")): try: return self._fitter.corner_plot(filter_params) except AttributeError: - raise FitNotRunError("Fit has not been run yet\n") + # If the fit has not been done, return an empty plot + dummy_fig = plt.figure(figsize=(5.5,6)) + return dummy_fig # ------------------------------------------------------------------------- # Properties describing fit results @@ -597,11 +619,14 @@ def fit_as_csv(self): Return a csv-style string of the fit. """ + if len(self._expt_list_stable_order) < 1: + return "# No experiments loaded." + out = ["# Fit successful? {}\n".format(self.fit_success)] out.append("# {}\n".format(datetime.datetime.now())) - + u = self._expt_dict[self._expt_list_stable_order[0]].units - out.append("# Units: {}/mol\n".format(u)) + out.append("# Units: {}\n".format(u)) fit_stats_keys = list(self.fit_stats.keys()) fit_stats_keys.sort() From 6ee49bd29b609157bcda472935b2d9919f6baf87 Mon Sep 17 00:00:00 2001 From: Mike Harms Date: Sat, 10 Jun 2017 08:51:59 -0700 Subject: [PATCH 2/2] prepping for next release --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..b88034e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[metadata] +description-file = README.md