From 3f16e7c18538f662f18e3f9a890796b920cf763e Mon Sep 17 00:00:00 2001 From: "Michele.Maris" <michele.maris@inaf.it> Date: Tue, 11 Jun 2024 20:20:58 +0200 Subject: [PATCH] u --- src/yapsut/__init__.py | 1 + src/yapsut/montecarlo_fitting.py | 187 +++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 src/yapsut/montecarlo_fitting.py diff --git a/src/yapsut/__init__.py b/src/yapsut/__init__.py index 4e2fca0..86a86b4 100644 --- a/src/yapsut/__init__.py +++ b/src/yapsut/__init__.py @@ -18,6 +18,7 @@ from .template_subs import discoverKeys, templateFiller from .periodic_stats import periodic_stats, periodic_centroid from .stats import CumulativeOfData from .colored_noise import gaussian_colored_noise +from .montecarlo_fitting import EnsembleFitting_Base # planck legacy is under editing #from .planck_legacy import cosmological_dipole diff --git a/src/yapsut/montecarlo_fitting.py b/src/yapsut/montecarlo_fitting.py new file mode 100644 index 0000000..f975a60 --- /dev/null +++ b/src/yapsut/montecarlo_fitting.py @@ -0,0 +1,187 @@ +import numpy as np +import pandas as pd + +class EnsembleFitting_Base : + """This class implements Ensemble fitting with curve_fit for (a,b,c,Rdark) out of the input curve. + """ + @property + def initial_values(self) : + """return the initial values""" + return self._initial_values + # + @initial_values.setter + def initial_values(self,this) : + """return the initial values""" + self._initial_values=this + # + @property + def param_names(self) : + return self._param_names + # + @property + def Model(self) : + return self._Model + # + @Model.setter + def Model(self,Model,param_names) : + self._param_names=param_names + self._Model=this + # + @property + def fit_success(self) : + return self._success + # + @property + def size(self) : + return self._size + # + @property + def fit(self) : + return self._fit + # + def copy(self) : + from copy import deepcopy + return copy(self) + # + def __len__(self) : + return self._size + # + def __init__(self,X,Xerr,Y,Yerr) : + """It takes in input X, Y and their errors""" + self._X=X + self._Xerr=Xerr if not Xerr is None else X*0 + # + self._Y=Y + self._Yerr=Yerr if not Yerr is None else Y*0 + # + self._size=len(X) + # + self._fitting_clean() + # + def _fitting_clean(self) : + self._mc=None + self._initial_values=None + self._Model=None + self._param_names=None + self._success=False + self._fit=None + self._fitting_kargs={} + # + @property + def fitting_kargs(self) : + """access to the fitting arguments dictionary""" + return self._fitting_kargs + # + @property + def fitting_result(self) : + """returns the whole last fitting result""" + return self._fitting_result + # + def fitting_bounds(self) : + """returns fitting bounds""" + return self._fitting_args['bounds'] + # + @property + def residuals(self) : + if not self.fit_success : + return np.nan*self._X + return self._Y-self._Model(self._X,*self._fit) + # + @property + def chisq(self) : + if not self.fit_success : + return np.nan + r=(self.residuals/self._Yerr)**2 + return r.sum() + # + def mc_shot(self) : + """creates a montecarlo realization of the I,P data. + Assumes uniform error for I and gaussian error for P + """ + n=self._size + X=np.random.uniform(low=-0.5,high=0.5,size=n)*self._Xerr+self._X + Y=np.random.normal(size=n)*self._Yerr+self._Y + return X,Y + # + def montecarlo(self,nmc,force_positive=True,as_pandas=True,max_nmc=-3) : + """creates a montecarlo serie of parameters + output: mc realization of parameters + """ + out=[] + n=len(self) + imc=nmc + mcount=abs(max_nmc)*nmc if max_nmc < 0 else max_nmc + if nmc == 0 : mcount = nmc + while imc > 0 and mcount > 0: + mcount-=1 + # + X,Y=self.mc_shot() + fit,fit_success=self.fitting(X,Y,self._Yerr) + # + if fit_success : + if self.valid_fit(fit) : + imc+=-1 + out.append(fit) + self._mc=np.array(out) + if as_pandas : + out=pd.DataFrame(self._mc,columns=self._param_names) + return out + # + @property + def montecarlo_ensemble_averages(self) : + """returns the ensemble averaged values from the montecarlo simulation""" + try : + return np.array([np.median(k) for k in self._mc.T]) + except : + return np.ones(len(self._param_names))+np.nan + # + def fitting(self,X,Y,sgm) : + """ + the fitter function, must be specialized according to the this template + +def fitting(self,X,Y,sgm) : + from scipy.optimize import curve_fit + # + # resets all the variables to be generated + self._success=False + self._fit=None + self._fitting_result=None + # + # perfom the fit + try : + self._fitting_result=curve_fit(self.Model,X,Y,sigma=sgm,p0=self._initial_values,full_output=True,**self._fitting_kargs) + # + # saves the fit result and the flags success + self._fit=self._fitting_result[0] + self._success=self._fitting_result[-1] in [1,2,3,4] + except : + self._success=False + # + # returns the result + return self._fit,self._success + + """ + from scipy.optimize import curve_fit + # + # resets all the variables to be generated + self._success=False + self._fit=None + self._fitting_result=None + # + # perfom the fit + try : + self._fitting_result=curve_fit(self.Model,X,Y,sigma=sgm,p0=self._initial_values,full_output=True,**self._fitting_kargs) + # + # saves the fit result and the flags success + self._fit=self._fitting_result[0] + self._success=self._fitting_result[-1] in [1,2,3,4] + except : + self._success=False + # + # returns the result + return self._fit,self._success + # + def valid_fit(self,fit) : + """test wether the fit is valid: a specialized function for the application""" + #return True or False + return True -- GitLab