def test_constraints(self): # constraints should work during fitting self.p[0].value = 5.4 self.p[1].constraint = -0.203 * self.p[0] assert_equal(self.p[1].value, self.p[0].value * -0.203) res = self.mcfitter.fit() assert_(res.success) assert_equal(len(self.objective.varying_parameters()), 1) # lnsigma is parameters[0] assert_(self.p[0] is self.objective.parameters.flattened()[0]) assert_(self.p[1] is self.objective.parameters.flattened()[1]) assert_almost_equal(self.p[0].value, res.x[0]) assert_almost_equal(self.p[1].value, self.p[0].value * -0.203) # check that constraints work during sampling # the CurveFitter has to be set up again if you change how the # parameters are being fitted. mcfitter = CurveFitter(self.objective) assert_(mcfitter.nvary == 1) mcfitter.sample(5) assert_equal(self.p[1].value, self.p[0].value * -0.203) # the constrained parameters should have a chain assert_(self.p[0].chain is not None) assert_(self.p[1].chain is not None) assert_allclose(self.p[1].chain, self.p[0].chain * -0.203)
def setup(self): pth = os.path.dirname(os.path.abspath(refnx.reflect.__file__)) e361 = RD(os.path.join(pth, 'test', 'e361r.txt')) sio2 = SLD(3.47, name='SiO2') si = SLD(2.07, name='Si') d2o = SLD(6.36, name='D2O') polymer = SLD(1, name='polymer') # e361 is an older dataset, but well characterised structure361 = si | sio2(10, 4) | polymer(200, 3) | d2o(0, 3) model361 = ReflectModel(structure361, bkg=2e-5) model361.scale.vary = True model361.bkg.vary = True model361.scale.range(0.1, 2) model361.bkg.range(0, 5e-5) model361.dq = 5. # d2o structure361[-1].sld.real.vary = True structure361[-1].sld.real.range(6, 6.36) structure361[1].thick.vary = True structure361[1].thick.range(5, 20) structure361[2].thick.vary = True structure361[2].thick.range(100, 220) structure361[2].sld.real.vary = True structure361[2].sld.real.range(0.2, 1.5) e361.x_err = None objective = Objective(model361, e361) self.fitter = CurveFitter(objective, nwalkers=200) self.fitter.initialise('jitter')
class curvefitter(Benchmark): repeat = 3 def setup(self): # Reproducible results! np.random.seed(123) m_true = -0.9594 b_true = 4.294 f_true = 0.534 m_ls = -1.1040757010910947 b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = m_true * x + b_true y += np.abs(f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) data = Data1D(data=(x, y, y_err)) p = Parameter(b_ls, 'b', vary=True, bounds=(-100, 100)) p |= Parameter(m_ls, 'm', vary=True, bounds=(-100, 100)) model = Model(p, fitfunc=line) objective = Objective(model, data) self.mcfitter = CurveFitter(objective) self.mcfitter.initialise('prior') def time_sampler(self): # to get an idea of how fast the actual sampling is. # i.e. the overhead of objective.lnprob, objective.lnprior, etc self.mcfitter.sampler.run_mcmc(self.mcfitter._state, 100)
def NIST_runner( dataset, method="least_squares", chi_atol=1e-5, val_rtol=1e-2, err_rtol=6e-3, ): NIST_dataset = ReadNistData(dataset) x, y = (NIST_dataset["x"], NIST_dataset["y"]) if dataset == "Nelson": y = np.log(y) params = NIST_dataset["start"] fitfunc = NIST_Models[dataset][0] model = Model(params, fitfunc) objective = Objective(model, (x, y)) fitter = CurveFitter(objective) result = fitter.fit(method=method) assert_allclose(objective.chisqr(), NIST_dataset["sum_squares"], atol=chi_atol) certval = NIST_dataset["cert_values"] assert_allclose(result.x, certval, rtol=val_rtol) if "stderr" in result: certerr = NIST_dataset["cert_stderr"] assert_allclose(result.stderr, certerr, rtol=err_rtol)
def test_mcmc(self): self.mcfitter.sample(steps=50, nthin=1, verbose=False) assert_equal(self.mcfitter.nvary, 2) # smoke test for corner plot self.mcfitter.objective.corner() # we're not doing Parallel Tempering here. assert_(self.mcfitter._ntemps == -1) assert_(isinstance(self.mcfitter.sampler, emcee.EnsembleSampler)) # should be able to multithread mcfitter = CurveFitter(self.objective, nwalkers=50) res = mcfitter.sample(steps=33, nthin=2, verbose=False, pool=2) # check that the autocorrelation function at least runs acfs = mcfitter.acf(nburn=10) assert_equal(acfs.shape[-1], mcfitter.nvary) # check chain shape assert_equal(mcfitter.chain.shape, (33, 50, 2)) # assert_equal(mcfitter._lastpos, mcfitter.chain[:, -1, :]) assert_equal(res[0].chain.shape, (33, 50)) # if the number of parameters changes there should be an Exception # raised from pytest import raises with raises(RuntimeError): self.p[0].vary = False self.mcfitter.sample(1) # can fix by making the sampler again self.mcfitter.make_sampler() self.mcfitter.sample(1)
def NIST_runner(dataset, method='leastsq', chi_atol=1e-5, val_rtol=1e-2, err_rtol=0.01): NIST_dataset = ReadNistData(dataset) x, y = (NIST_dataset['x'], NIST_dataset['y']) if dataset == 'Nelson': y = np.log(y) params = NIST_dataset['start'] fitfunc = Models[dataset][0] fitter = CurveFitter(fitfunc, (x, y), params) result = fitter.fit(method, params) assert_allclose(result.chisqr, NIST_dataset['sum_squares'], atol=chi_atol) thisval = values(result.params) certval = NIST_dataset['cert_values'] assert_allclose(thisval, certval, rtol=val_rtol) if result.errorbars: thiserr = np.array([result.params[par].stderr for par in result.params]) certerr = NIST_dataset['cert_stderr'] assert_allclose(thiserr, certerr, rtol=err_rtol)
def setup(self): # Reproducible results! np.random.seed(123) m_true = -0.9594 b_true = 4.294 f_true = 0.534 m_ls = -1.1040757010910947 b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = m_true * x + b_true y += np.abs(f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) data = Data1D(data=(x, y, y_err)) p = Parameter(b_ls, 'b', vary=True, bounds=(-100, 100)) p |= Parameter(m_ls, 'm', vary=True, bounds=(-100, 100)) model = Model(p, fitfunc=line) self.objective = Objective(model, data) self.mcfitter = CurveFitter(self.objective) self.mcfitter_t = CurveFitter(self.objective, ntemps=20) self.mcfitter.initialise('prior') self.mcfitter_t.initialise('prior')
def NIST_runner(dataset, method='least_squares', chi_atol=1e-5, val_rtol=1e-2, err_rtol=5e-3): NIST_dataset = ReadNistData(dataset) x, y = (NIST_dataset['x'], NIST_dataset['y']) if dataset == 'Nelson': y = np.log(y) params = NIST_dataset['start'] fitfunc = NIST_Models[dataset][0] model = Model(params, fitfunc) objective = Objective(model, (x, y)) fitter = CurveFitter(objective) result = fitter.fit(method=method) assert_allclose(objective.chisqr(), NIST_dataset['sum_squares'], atol=chi_atol) certval = NIST_dataset['cert_values'] assert_allclose(result.x, certval, rtol=val_rtol) if 'stderr' in result: certerr = NIST_dataset['cert_stderr'] assert_allclose(result.stderr, certerr, rtol=err_rtol)
def test_all_minimisers(self): """test minimisers against the Gaussian fit""" f = CurveFitter(self.objective) methods = [ "differential_evolution", "L-BFGS-B", "least_squares", "shgo", "dual_annealing", ] for method in methods: self.objective.setp(self.p0) opts = {} if method in ["differential_evolution", "dual_annealing"]: opts = {"seed": 1} res = f.fit(method=method, **opts) assert_allclose(res.x, self.best_weighted, rtol=0.005) # smoke test to check that we can use nlpost self.objective.setp(self.p0) logp0 = self.objective.logp() # check that probabilities are calculated correctly assert_allclose( self.objective.logpost(), self.objective.logp() + self.objective.logl(), ) assert_allclose(self.objective.nlpost(), -self.objective.logpost()) assert_allclose(self.objective.nlpost(self.p0), -self.objective.logpost(self.p0)) # if the priors are all uniform then the only difference between # logpost and logl is a constant. A minimiser should converge on the # same answer. The following tests examine that. # The test works for dual_annealing, but not for differential # evolution, not sure why that is. self.objective.setp(self.p0) res1 = f.fit(method="dual_annealing", seed=1) assert_almost_equal(res1.x, self.best_weighted, 3) nll1 = self.objective.nll() nlpost1 = self.objective.nlpost() self.objective.setp(self.p0) res2 = f.fit(method="dual_annealing", target="nlpost", seed=1) assert_almost_equal(res2.x, self.best_weighted, 3) nll2 = self.objective.nll() nlpost2 = self.objective.nlpost() assert_allclose(nlpost1, nlpost2, atol=0.001) assert_allclose(nll1, nll2, atol=0.001) # these two priors are calculated for different parameter values # (before and after the fit) they should be the same because all # the parameters have uniform priors. assert_almost_equal(self.objective.logp(), logp0)
def test_reflectivity_fit(self): # a smoke test to make sure the reflectivity fit proceeds model = self.model361 objective = Objective(model, (self.qvals361, self.rvals361, self.evals361), transform=Transform('logY')) fitter = CurveFitter(objective) with np.errstate(invalid='raise'): fitter.fit('differential_evolution')
def test_mcmc_pt(self): if not _HAVE_PTSAMPLER: return # smoke test for parallel tempering mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) assert_equal(mcfitter.sampler.ntemps, 10) res = mcfitter.sample(steps=30, nthin=2, verbose=False, pool=0) assert_equal(mcfitter.chain.shape, (30, 10, 50, 2)) assert_equal(res[0].chain.shape, (30, 50)) assert_equal(mcfitter.chain[:, 0, :, 0], res[0].chain) assert_equal(mcfitter.chain[:, 0, :, 1], res[1].chain)
def test_run(): print("\n\n\n") from refnx.dataset import Data1D from refnx.dataset import ReflectDataset import refnx import data_in data = data_in.data_in('d2o/29553_54.dat') # dataset = data # ... data = Data1D(data) from make_egg import bsla_thesis # air = SLD(0) # air = air(0,0) bt = bsla_thesis() bt.interface_protein_solvent.setp(vary=True, bounds=(11, 40)) bt.protein_length.setp(vary=True, bounds=(25, 55)) bt.number_of_water_molecules.setp(vary=True, bounds=(1, 10000)) bt.interface_width_air_solvent.setp(vary=True, bounds=(0.001, 30)) #bt.interface_width_protein_solvent.setp(vary=True, bounds=(0, 5)) bt.sld_of_protein.setp(vary=True, bounds=(1.92, 6.21)) # *(10**(-6)) bt.d2o_to_h2o_ratio.setp(vary=True, bounds=(0, 1)) # if isinstance(bt, Component): # print("it is comp") # if isinstance(bt, Structure): # print("it is") #print(bt.parameters) # d2o = 1.9185/0.3 # h2o = -0.1635/0.3 # solvent = SLD((bt.d2o_to_h2o_ratio.value*d2o + (1-bt.d2o_to_h2o_ratio.value)*h2o)) # solvent = solvent(0,0) # from refnx.reflect import Structure # structure = air|bt|solvent # structure.name = "bsla" from refnx.reflect import ReflectModel model = ReflectModel(bt) #structure) from refnx.analysis import Transform, CurveFitter, Objective objective = Objective(model, data) fitter = CurveFitter(objective) fitter.fit('differential_evolution') import matplotlib.pyplot as plt #%matplotlib notebook # plt.plot(*bt.sld_profile()) objective.plot() plt.yscale('log') plt.xscale('log') plt.xlabel('Q') plt.ylabel('Reflectivity') plt.legend() print(bt) plt.show()
def test_all_minimisers(self): """test minimisers against the Gaussian fit""" f = CurveFitter(self.objective) methods = ['differential_evolution', 'L-BFGS-B', 'least_squares'] if hasattr(sciopt, 'shgo'): methods.append('shgo') if hasattr(sciopt, 'dual_annealing'): methods.append('dual_annealing') for method in methods: self.objective.setp(self.p0) res = f.fit(method=method) assert_almost_equal(res.x, self.best_weighted, 3) # smoke test to check that we can use nlpost self.objective.setp(self.p0) logp0 = self.objective.logp() # check that probabilities are calculated correctly assert_allclose(self.objective.logpost(), self.objective.logp() + self.objective.logl()) assert_allclose(self.objective.nlpost(), -self.objective.logpost()) # if the priors are all uniform then the only difference between # logpost and logl is a constant. A minimiser should converge on the # same answer. The following tests examine that. # The test works for dual_annealing, but not for differential # evolution, not sure why that is. self.objective.setp(self.p0) res1 = f.fit(method='dual_annealing', seed=1) assert_almost_equal(res1.x, self.best_weighted, 3) nll1 = self.objective.nll() nlpost1 = self.objective.nlpost() self.objective.setp(self.p0) res2 = f.fit(method='dual_annealing', target='nlpost', seed=1) assert_almost_equal(res2.x, self.best_weighted, 3) nll2 = self.objective.nll() nlpost2 = self.objective.nlpost() assert_allclose(nlpost1, nlpost2, atol=0.001) assert_allclose(nll1, nll2, atol=0.001) # these two priors are calculated for different parameter values # (before and after the fit) they should be the same because all # the parameters have uniform priors. assert_almost_equal(self.objective.logp(), logp0)
def test_best_unweighted(self): self.objective.weighted = False f = CurveFitter(self.objective, nwalkers=100) res = f.fit() output = res.x assert_almost_equal(self.objective.chisqr(), self.best_unweighted_chisqr) assert_almost_equal(output, self.best_unweighted, 5) # compare the residuals res = self.data.y - self.model(self.data.x) assert_equal(self.objective.residuals(), res) # compare objective._covar to the best_unweighted_errors uncertainties = np.array([param.stderr for param in self.params]) assert_almost_equal(uncertainties, self.best_unweighted_errors, 3)
def test_reflectivity_emcee(self): model = self.model361 model.dq = 5. objective = Objective(model, (self.qvals361, self.rvals361, self.evals361), transform=Transform('logY')) fitter = CurveFitter(objective, nwalkers=100) assert_(len(objective.generative().shape) == 1) assert_(len(objective.residuals().shape) == 1) res = fitter.fit('least_squares') res_mcmc = fitter.sample(steps=5, nthin=10, random_state=1, verbose=False) mcmc_val = [mcmc_result.median for mcmc_result in res_mcmc] assert_allclose(mcmc_val, res.x, rtol=0.05)
def curvefitter(self): """ class:`CurveFitter` : Object for fitting the data based on the objective. """ if self.objective is not None and self._curvefitter is None: self._curvefitter = CurveFitter(self.objective) return self._curvefitter
def setup_method(self): # Reproducible results! np.random.seed(123) self.m_true = -0.9594 self.b_true = 4.294 self.f_true = 0.534 self.m_ls = -1.1040757010910947 self.b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = self.m_true * x + self.b_true y += np.abs(self.f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) self.data = Data1D(data=(x, y, y_err)) self.p = Parameter(self.b_ls, 'b', vary=True, bounds=(-100, 100)) self.p |= Parameter(self.m_ls, 'm', vary=True, bounds=(-100, 100)) self.model = Model(self.p, fitfunc=line) self.objective = Objective(self.model, self.data) assert_(len(self.objective.varying_parameters()) == 2) mod = np.array([4.78166609, 4.42364699, 4.16404064, 3.50343504, 3.4257084, 2.93594347, 2.92035638, 2.67533842, 2.28136038, 2.19772983, 1.99295496, 1.93748334, 1.87484436, 1.65161016, 1.44613461, 1.11128101, 1.04584535, 0.86055984, 0.76913963, 0.73906649, 0.73331407, 0.68350418, 0.65216599, 0.59838566, 0.13070299, 0.10749131, -0.01010195, -0.10010155, -0.29495372, -0.42817431, -0.43122391, -0.64637715, -1.30560686, -1.32626428, -1.44835768, -1.52589881, -1.56371158, -2.12048349, -2.24899179, -2.50292682, -2.53576659, -2.55797996, -2.60870542, -2.7074727, -3.93781479, -4.12415366, -4.42313742, -4.98368609, -5.38782395, -5.44077086]) self.mod = mod self.mcfitter = CurveFitter(self.objective)
def test_mcmc(self): self.mcfitter.sample(steps=50, nthin=1, verbose=False) # we're not doing Parallel Tempering here. assert_(self.mcfitter._ntemps == -1) assert_(isinstance(self.mcfitter.sampler, emcee.EnsembleSampler)) # should be able to multithread mcfitter = CurveFitter(self.objective, nwalkers=50) res = mcfitter.sample(steps=33, nthin=2, verbose=False, pool=2) # check that the autocorrelation function at least runs acfs = mcfitter.acf(nburn=10) assert_equal(acfs.shape[-1], mcfitter.nvary) # check chain shape assert_equal(mcfitter.chain.shape, (33, 50, 2)) # assert_equal(mcfitter._lastpos, mcfitter.chain[:, -1, :]) assert_equal(res[0].chain.shape, (33, 50))
def test_modelvals_degenerate_layers(self): # try fitting dataset with a deposited layer split into two degenerate # layers fname = os.path.join(self.pth, "c_PLP0011859_q.txt") dataset = ReflectDataset(fname) sio2 = SLD(3.47, name="SiO2") si = SLD(2.07, name="Si") d2o = SLD(6.36, name="D2O") polymer = SLD(2.0, name="polymer") sio2_l = sio2(30, 3) polymer_l = polymer(125, 3) structure = si | sio2_l | polymer_l | polymer_l | d2o(0, 3) polymer_l.thick.setp(value=125, vary=True, bounds=(0, 250)) polymer_l.rough.setp(value=4, vary=True, bounds=(0, 8)) structure[-1].rough.setp(vary=True, bounds=(0, 6)) sio2_l.rough.setp(value=3.16, vary=True, bounds=(0, 8)) model = ReflectModel(structure, bkg=2e-6) objective = Objective(model, dataset, use_weights=False, transform=Transform("logY")) model.scale.setp(vary=True, bounds=(0, 2)) model.bkg.setp(vary=True, bounds=(0, 8e-6)) slabs = structure.slabs() assert_equal(slabs[2, 0:2], slabs[3, 0:2]) assert_equal(slabs[2, 3], slabs[3, 3]) assert_equal(slabs[1, 3], sio2_l.rough.value) f = CurveFitter(objective) f.fit(method="differential_evolution", seed=1, maxiter=3) slabs = structure.slabs() assert_equal(slabs[2, 0:2], slabs[3, 0:2]) assert_equal(slabs[2, 3], slabs[3, 3])
def test_globalfitting(self): # smoke test for can the global fitting run? # also tests that global fitting gives same output as # normal fitting (for a single dataset) self.model.scale.setp(vary=True, bounds=(0.1, 2)) self.model.bkg.setp(vary=True, bounds=(1e-10, 8e-6)) self.structure[-1].rough.setp(vary=True, bounds=(0.2, 6)) self.sio2_l.thick.setp(vary=True, bounds=(0.2, 80)) self.polymer_l.thick.setp(bounds=(0.01, 400), vary=True) self.polymer_l.sld.real.setp(vary=True, bounds=(0.01, 4)) self.objective.transform = Transform('logY') starting = np.array(self.objective.parameters) with np.errstate(invalid='raise'): g = CurveFitter(self.global_objective) res_g = g.fit() # need the same starting point self.objective.setp(starting) f = CurveFitter(self.objective) res_f = f.fit() # individual and global should give the same fit. assert_almost_equal(res_g.x, res_f.x)
def make_model(names, bs, thicks, roughs, fig_i, data, show=False, mcmc=False): extent = sum( thicks[:, 0]) # (float or Parameter) – Total extent of spline region vs = array( bs )[:, 0] #(Sequence of float/Parameter) – the real part of the SLD values of each of the knots. dz = cum_sum( array(thicks[:, 0]) ) #(Sequence of float/Parameter) – the lateral offset between successive knots. print(dz) name = "number of nots " + str(len(names)) #(str) – Name of component component = Spline(extent, vs, dz, name) front = SLD(0) front = front(0, 0) back = SLD(0) back = back(0, 0) structure = front | component | back model = ReflectModel(structure, bkg=3e-6, dq=5.0) objective = Objective(model, data, transform=Transform('logY')) fitter = CurveFitter(objective) fitter.fit('differential_evolution') return structure, fitter, objective, fig_i + 1
def test_best_weighted(self): assert_equal(len(self.objective.varying_parameters()), 4) self.objective.setp(self.p0) f = CurveFitter(self.objective, nwalkers=100) res = f.fit('least_squares', jac='3-point') output = res.x assert_almost_equal(output, self.best_weighted, 3) assert_almost_equal(self.objective.chisqr(), self.best_weighted_chisqr, 5) # compare the residuals res = (self.data.y - self.model(self.data.x)) / self.data.y_err assert_equal(self.objective.residuals(), res) # compare objective.covar to the best_weighted_errors uncertainties = [param.stderr for param in self.params] assert_allclose(uncertainties, self.best_weighted_errors, rtol=0.005) # we're also going to try the checkpointing here. checkpoint = os.path.join(self.tmpdir, 'checkpoint.txt') # compare samples to best_weighted_errors np.random.seed(1) f.sample(steps=101, random_state=1, verbose=False, f=checkpoint) process_chain(self.objective, f.chain, nburn=50, nthin=10) uncertainties = [param.stderr for param in self.params] assert_allclose(uncertainties, self.best_weighted_errors, rtol=0.07) # test that the checkpoint worked check_array = np.loadtxt(checkpoint) check_array = check_array.reshape(101, f._nwalkers, f.nvary) assert_allclose(check_array, f.chain) # test loading the checkpoint chain = load_chain(checkpoint) assert_allclose(chain, f.chain) f.initialise('jitter') f.sample(steps=2, nthin=4, f=checkpoint, verbose=False) assert_equal(f.chain.shape[0], 2)
def make_model(names, bs, thicks, roughs, fig_i, data, show=False, mcmc=False): no_layers = len(bs) layers = [] for i in range(no_layers): names.append('layer' + str(i)) for i in range(no_layers): sld = SLD(bs[i], name=names[i]) layers.append(sld(thicks[i], roughs[i])) layers[0].thick.setp(vary=True, bounds=(thicks[i] - 1, thicks[i] + 1)) layers[0].sld.real.setp(vary=True, bounds=(bs[i] - 1, bs[i] + 1)) for layer in layers[1:]: layer.thick.setp(vary=True, bounds=(thicks[i] - 1, thicks[i] + 1)) layer.sld.real.setp(vary=True, bounds=(bs[i] - 1, bs[i] + 1)) layer.rough.setp(vary=True, bounds=(0, 5)) structure = layers[0] for layer in layers[1:]: structure |= layer print(structure) model = ReflectModel(structure, bkg=3e-6, dq=5.0) #model.scale.setp(bounds=(0.6, 1.2), vary=True) #model.bkg.setp(bounds=(1e-9, 9e-6), vary=True) objective = Objective(model, data, transform=Transform('logY')) fitter = CurveFitter(objective) if mcmc: fitter.sample(1000) process_chain(objective, fitter.chain, nburn=300, nthin=100) else: fitter.fit('differential_evolution') print(objective.parameters) if show: plt.figure(fig_i) plt.plot(*structure.sld_profile()) plt.ylabel('SLD /$10^{-6} \AA^{-2}$') plt.xlabel('distance / $\AA$') return structure, fitter, objective, fig_i + 1
def test_globalfitting(self): # smoke test for can the global fitting run? # also tests that global fitting gives same output as # normal fitting (for a single dataset) self.model.scale.setp(vary=True, bounds=(0.1, 2)) self.model.bkg.setp(vary=True, bounds=(1e-10, 8e-6)) self.structure[-1].rough.setp(vary=True, bounds=(0.2, 6)) self.sio2_l.thick.setp(vary=True, bounds=(0.2, 80)) self.polymer_l.thick.setp(bounds=(0.01, 400), vary=True) self.polymer_l.sld.real.setp(vary=True, bounds=(0.01, 4)) self.objective.transform = Transform('logY') with np.errstate(invalid='raise'): g = CurveFitter(self.global_objective) res_g = g.fit(method='differential_evolution', seed=1, maxiter=10) f = CurveFitter(self.objective) res_f = f.fit(method='differential_evolution', seed=1, maxiter=10) # individual and global should give the same fit. Because we use DE # there is no dependence on starting point, so long as we set a # seed. assert_almost_equal(res_g.x, res_f.x)
def test_mcmc_pt(self): # smoke test for parallel tempering x = np.array(self.objective.parameters) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) assert_equal(mcfitter.sampler.ntemps, 10) # check that the parallel sampling works # and that chain shape is correct res = mcfitter.sample(steps=5, nthin=2, verbose=False, pool=-1) assert_equal(mcfitter.chain.shape, (5, 10, 50, 2)) assert_equal(res[0].chain.shape, (5, 50)) assert_equal(mcfitter.chain[:, 0, :, 0], res[0].chain) assert_equal(mcfitter.chain[:, 0, :, 1], res[1].chain) chain = np.copy(mcfitter.chain) # the sampler should store the probability assert_equal(mcfitter.logpost.shape, (5, 10, 50)) assert_allclose(mcfitter.logpost, mcfitter.sampler._ptchain.logP) logprobs = mcfitter.logpost highest_prob_loc = np.argmax(logprobs[:, 0]) idx = np.unravel_index(highest_prob_loc, logprobs[:, 0].shape) idx = list(idx) idx.insert(1, 0) idx = tuple(idx) assert_equal(idx, mcfitter.index_max_prob) pvals = mcfitter.chain[idx] assert_allclose(logprobs[idx], self.objective.logpost(pvals)) # try resetting the chain mcfitter.reset() # test for reproducible operation self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain = np.copy(mcfitter.chain) self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain2 = np.copy(mcfitter.chain) assert_allclose(chain2, chain)
n = l.reshape(timesteps, sim.layers.shape[1]-layers_to_cut, sim.layers.shape[2]) data_dir = '../data/reflectometry2/dspc_{}/'.format(surface_pressure) dataset = ReflectDataset(os.path.join(data_dir, '{}{}.dat'.format(contrast, surface_pressure))) refy = np.zeros((n.shape[0], dataset.x.size)) sldy = [] chi = np.zeros((n.shape[0])) print(n.shape[0]) for i in range(n.shape[0]): sim.av_layers = n[i, :, :] model = ReflectModel(sim) model.scale.setp(1, vary=True, bounds=(0.00000001, np.inf)) model.bkg.setp(dataset.y[-1], vary=False) objective = Objective(model, dataset, transform=Transform('YX4')) fitter = CurveFitter(objective) res = fitter.fit() refy[i] = model(dataset.x, x_err=dataset.x_err)*(dataset.x)**4 sldy.append(sim.sld_profile()[1]) chi[i] = objective.chisqr() all_chi = np.append(all_chi, objective.chisqr()) if i == 0: ax1.errorbar(dataset.x, dataset.y*(dataset.x)**4 * 10**(ci-1), yerr=dataset.y_err*( dataset.x)**4 * 10**(ci-1), linestyle='', marker='o', color=sns.color_palette()[ci]) if i % 5 == 0: ax1.plot(dataset.x, model(dataset.x,
def test_multipledataset_corefinement(self): # test corefinement of three datasets data361 = ReflectDataset(os.path.join(self.pth, 'e361r.txt')) data365 = ReflectDataset(os.path.join(self.pth, 'e365r.txt')) data366 = ReflectDataset(os.path.join(self.pth, 'e366r.txt')) si = SLD(2.07, name='Si') sio2 = SLD(3.47, name='SiO2') d2o = SLD(6.36, name='d2o') h2o = SLD(-0.56, name='h2o') cm3 = SLD(3.47, name='cm3') polymer = SLD(1, name='polymer') structure361 = si | sio2(10, 4) | polymer(200, 3) | d2o(0, 3) structure365 = si | structure361[1] | structure361[2] | cm3(0, 3) structure366 = si | structure361[1] | structure361[2] | h2o(0, 3) structure365[-1].rough = structure361[-1].rough structure366[-1].rough = structure361[-1].rough structure361[1].thick.setp(vary=True, bounds=(0, 20)) structure361[2].thick.setp(value=200., bounds=(200., 250.), vary=True) structure361[2].sld.real.setp(vary=True, bounds=(0, 2)) structure361[2].vfsolv.setp(value=5., bounds=(0., 100.), vary=True) model361 = ReflectModel(structure361, bkg=2e-5) model365 = ReflectModel(structure365, bkg=2e-5) model366 = ReflectModel(structure366, bkg=2e-5) model361.bkg.setp(vary=True, bounds=(1e-6, 5e-5)) model365.bkg.setp(vary=True, bounds=(1e-6, 5e-5)) model366.bkg.setp(vary=True, bounds=(1e-6, 5e-5)) objective361 = Objective(model361, data361) objective365 = Objective(model365, data365) objective366 = Objective(model366, data366) global_objective = GlobalObjective( [objective361, objective365, objective366]) # are the right numbers of parameters varying? assert_equal(len(global_objective.varying_parameters()), 7) # can we set the parameters? global_objective.setp(np.array([1e-5, 10, 212, 1, 10, 1e-5, 1e-5])) f = CurveFitter(global_objective) f.fit() indiv_chisqr = np.sum( [objective.chisqr() for objective in global_objective.objectives]) # the overall chi2 should be sum of individual chi2 global_chisqr = global_objective.chisqr() assert_almost_equal(global_chisqr, indiv_chisqr) # now check that the parameters were held in common correctly. slabs361 = structure361.slabs() slabs365 = structure365.slabs() slabs366 = structure366.slabs() assert_equal(slabs365[0:2, 0:5], slabs361[0:2, 0:5]) assert_equal(slabs366[0:2, 0:5], slabs361[0:2, 0:5]) assert_equal(slabs365[-1, 3], slabs361[-1, 3]) assert_equal(slabs366[-1, 3], slabs361[-1, 3]) # check that the residuals are the correct lengths res361 = objective361.residuals() res365 = objective365.residuals() res366 = objective366.residuals() res_global = global_objective.residuals() assert_allclose(res_global[0:len(res361)], res361, rtol=1e-5) assert_allclose(res_global[len(res361):len(res361) + len(res365)], res365, rtol=1e-5) assert_allclose(res_global[len(res361) + len(res365):], res366, rtol=1e-5) repr(global_objective)
def test_mcmc_init(self): # smoke test for sampler initialisation # TODO check that the initialisation worked. # reproducible initialisation with random_state dependents self.mcfitter.initialise("prior", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("prior", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) self.mcfitter.initialise("jitter", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("jitter", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=chain) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise(chain) # initialise for Parallel tempering mcfitter = CurveFitter(self.objective, ntemps=20, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=np.copy(chain)) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100, ntemps=20) mcfitter.initialise(chain)
def test_best_weighted(self): assert_equal(len(self.objective.varying_parameters()), 4) self.objective.setp(self.p0) f = CurveFitter(self.objective, nwalkers=100) res = f.fit("least_squares", jac="3-point") output = res.x assert_almost_equal(output, self.best_weighted, 3) assert_almost_equal(self.objective.chisqr(), self.best_weighted_chisqr, 5) # compare the residuals res = (self.data.y - self.model(self.data.x)) / self.data.y_err assert_equal(self.objective.residuals(), res) # compare objective.covar to the best_weighted_errors uncertainties = [param.stderr for param in self.params] assert_allclose(uncertainties, self.best_weighted_errors, rtol=0.005) # we're also going to try the checkpointing here. checkpoint = os.path.join(self.tmpdir, "checkpoint.txt") # compare samples to best_weighted_errors np.random.seed(1) f.sample(steps=201, random_state=1, verbose=False, f=checkpoint) process_chain(self.objective, f.chain, nburn=50, nthin=10) uncertainties = [param.stderr for param in self.params] assert_allclose(uncertainties, self.best_weighted_errors, rtol=0.07) # test that the checkpoint worked check_array = np.loadtxt(checkpoint) check_array = check_array.reshape(201, f._nwalkers, f.nvary) assert_allclose(check_array, f.chain) # test loading the checkpoint chain = load_chain(checkpoint) assert_allclose(chain, f.chain) f.initialise("jitter") f.sample(steps=2, nthin=4, f=checkpoint, verbose=False) assert_equal(f.chain.shape[0], 2) # we should be able to produce 2 * 100 steps from the generator g = self.objective.pgen(ngen=20000000000) s = [i for i, a in enumerate(g)] assert_equal(np.max(s), 200 - 1) g = self.objective.pgen(ngen=200) pvec = next(g) assert_equal(pvec.size, len(self.objective.parameters.flattened())) # check that all the parameters are returned via pgen, not only those # being varied. self.params[0].vary = False f = CurveFitter(self.objective, nwalkers=100) f.initialise("jitter") f.sample(steps=2, nthin=4, f=checkpoint, verbose=False) g = self.objective.pgen(ngen=100) pvec = next(g) assert_equal(pvec.size, len(self.objective.parameters.flattened())) # the following test won't work because of emcee/gh226. # chain = load_chain(checkpoint) # assert_(chain.shape == f.chain.shape) # assert_allclose(chain, f.chain) # try reproducing best fit with parallel tempering self.params[0].vary = True f = CurveFitter(self.objective, nwalkers=100, ntemps=10) f.fit("differential_evolution", seed=1) f.sample(steps=201, random_state=1, verbose=False) process_chain(self.objective, f.chain, nburn=50, nthin=15) print(self.params[0].chain.shape, self.params[0].chain) uncertainties = [param.stderr for param in self.params] assert_allclose(uncertainties, self.best_weighted_errors, rtol=0.07)
def test_pickle(self): # tests if a CurveFitter can be pickled/unpickled. f = CurveFitter(self.objective) pkl = pickle.dumps(f) g = pickle.loads(pkl) g._check_vars_unchanged()
class TestCurveFitter(object): def setup_method(self): # Reproducible results! np.random.seed(123) self.m_true = -0.9594 self.b_true = 4.294 self.f_true = 0.534 self.m_ls = -1.1040757010910947 self.b_ls = 5.4405552502319505 # Generate some synthetic data from the model. N = 50 x = np.sort(10 * np.random.rand(N)) y_err = 0.1 + 0.5 * np.random.rand(N) y = self.m_true * x + self.b_true y += np.abs(self.f_true * y) * np.random.randn(N) y += y_err * np.random.randn(N) self.data = Data1D(data=(x, y, y_err)) self.p = Parameter(self.b_ls, "b", vary=True, bounds=(-100, 100)) self.p |= Parameter(self.m_ls, "m", vary=True, bounds=(-100, 100)) self.model = Model(self.p, fitfunc=line) self.objective = Objective(self.model, self.data) assert_(len(self.objective.varying_parameters()) == 2) mod = np.array([ 4.78166609, 4.42364699, 4.16404064, 3.50343504, 3.4257084, 2.93594347, 2.92035638, 2.67533842, 2.28136038, 2.19772983, 1.99295496, 1.93748334, 1.87484436, 1.65161016, 1.44613461, 1.11128101, 1.04584535, 0.86055984, 0.76913963, 0.73906649, 0.73331407, 0.68350418, 0.65216599, 0.59838566, 0.13070299, 0.10749131, -0.01010195, -0.10010155, -0.29495372, -0.42817431, -0.43122391, -0.64637715, -1.30560686, -1.32626428, -1.44835768, -1.52589881, -1.56371158, -2.12048349, -2.24899179, -2.50292682, -2.53576659, -2.55797996, -2.60870542, -2.7074727, -3.93781479, -4.12415366, -4.42313742, -4.98368609, -5.38782395, -5.44077086, ]) self.mod = mod self.mcfitter = CurveFitter(self.objective) def test_bounds_list(self): bnds = bounds_list(self.p) assert_allclose(bnds, [(-100, 100), (-100, 100)]) # try making a Parameter bound a normal distribution, then get an # approximation to box bounds self.p[0].bounds = PDF(norm(0, 1)) assert_allclose(bounds_list(self.p), [norm(0, 1).ppf([0.005, 0.995]), (-100, 100)]) def test_constraints(self): # constraints should work during fitting self.p[0].value = 5.4 self.p[1].constraint = -0.203 * self.p[0] assert_equal(self.p[1].value, self.p[0].value * -0.203) res = self.mcfitter.fit() assert_(res.success) assert_equal(len(self.objective.varying_parameters()), 1) # lnsigma is parameters[0] assert_(self.p[0] is self.objective.parameters.flattened()[0]) assert_(self.p[1] is self.objective.parameters.flattened()[1]) assert_almost_equal(self.p[0].value, res.x[0]) assert_almost_equal(self.p[1].value, self.p[0].value * -0.203) # check that constraints work during sampling # the CurveFitter has to be set up again if you change how the # parameters are being fitted. mcfitter = CurveFitter(self.objective) assert_(mcfitter.nvary == 1) mcfitter.sample(5) assert_equal(self.p[1].value, self.p[0].value * -0.203) # the constrained parameters should have a chain assert_(self.p[0].chain is not None) assert_(self.p[1].chain is not None) assert_allclose(self.p[1].chain, self.p[0].chain * -0.203) def test_mcmc(self): self.mcfitter.sample(steps=50, nthin=1, verbose=False) assert_equal(self.mcfitter.nvary, 2) # smoke test for corner plot self.mcfitter.objective.corner() # we're not doing Parallel Tempering here. assert_(self.mcfitter._ntemps == -1) assert_(isinstance(self.mcfitter.sampler, emcee.EnsembleSampler)) # should be able to multithread mcfitter = CurveFitter(self.objective, nwalkers=50) res = mcfitter.sample(steps=33, nthin=2, verbose=False, pool=2) # check that the autocorrelation function at least runs acfs = mcfitter.acf(nburn=10) assert_equal(acfs.shape[-1], mcfitter.nvary) # check the standalone autocorrelation calculator acfs2 = autocorrelation_chain(mcfitter.chain, nburn=10) assert_equal(acfs, acfs2) # check integrated_time integrated_time(acfs2, tol=5) # check chain shape assert_equal(mcfitter.chain.shape, (33, 50, 2)) # assert_equal(mcfitter._lastpos, mcfitter.chain[:, -1, :]) assert_equal(res[0].chain.shape, (33, 50)) # if the number of parameters changes there should be an Exception # raised from pytest import raises with raises(RuntimeError): self.p[0].vary = False self.mcfitter.sample(1) # can fix by making the sampler again self.mcfitter.make_sampler() self.mcfitter.sample(1) def test_random_seed(self): # check that MCMC sampling is reproducible self.mcfitter.sample(steps=2, random_state=1) # get a starting pos starting_pos = self.mcfitter._state.coords # is sampling reproducible self.mcfitter.reset() self.mcfitter.initialise(pos=starting_pos) self.mcfitter.sample(3, random_state=1, pool=1) chain1 = np.copy(self.mcfitter.chain) self.mcfitter.reset() self.mcfitter.initialise(pos=starting_pos) self.mcfitter.sample(3, random_state=1, pool=1) chain2 = np.copy(self.mcfitter.chain) assert_equal(chain1, chain2) def test_mcmc_pt(self): # smoke test for parallel tempering x = np.array(self.objective.parameters) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) assert_equal(mcfitter.sampler.ntemps, 10) # check that the parallel sampling works # and that chain shape is correct res = mcfitter.sample(steps=5, nthin=2, verbose=False, pool=-1) assert_equal(mcfitter.chain.shape, (5, 10, 50, 2)) assert_equal(res[0].chain.shape, (5, 50)) assert_equal(mcfitter.chain[:, 0, :, 0], res[0].chain) assert_equal(mcfitter.chain[:, 0, :, 1], res[1].chain) chain = np.copy(mcfitter.chain) # the sampler should store the probability assert_equal(mcfitter.logpost.shape, (5, 10, 50)) assert_allclose(mcfitter.logpost, mcfitter.sampler._ptchain.logP) logprobs = mcfitter.logpost highest_prob_loc = np.argmax(logprobs[:, 0]) idx = np.unravel_index(highest_prob_loc, logprobs[:, 0].shape) idx = list(idx) idx.insert(1, 0) idx = tuple(idx) assert_equal(idx, mcfitter.index_max_prob) pvals = mcfitter.chain[idx] assert_allclose(logprobs[idx], self.objective.logpost(pvals)) # try resetting the chain mcfitter.reset() # test for reproducible operation self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain = np.copy(mcfitter.chain) self.objective.setp(x) mcfitter = CurveFitter(self.objective, ntemps=10, nwalkers=50) mcfitter.initialise("jitter", random_state=1) mcfitter.sample(steps=5, nthin=2, verbose=False, random_state=2) chain2 = np.copy(mcfitter.chain) assert_allclose(chain2, chain) def test_mcmc_init(self): # smoke test for sampler initialisation # TODO check that the initialisation worked. # reproducible initialisation with random_state dependents self.mcfitter.initialise("prior", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("prior", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) self.mcfitter.initialise("jitter", random_state=1) starting_pos = np.copy(self.mcfitter._state.coords) self.mcfitter.initialise("jitter", random_state=1) starting_pos2 = self.mcfitter._state.coords assert_equal(starting_pos, starting_pos2) mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=chain) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100) mcfitter.initialise(chain) # initialise for Parallel tempering mcfitter = CurveFitter(self.objective, ntemps=20, nwalkers=100) mcfitter.initialise("covar") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("prior") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) mcfitter.initialise("jitter") assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with last position mcfitter.sample(steps=1) chain = mcfitter.chain mcfitter.initialise(pos=chain[-1]) assert_equal(mcfitter._state.coords.shape, (20, 100, 2)) # initialise with chain mcfitter.sample(steps=2) chain = mcfitter.chain mcfitter.initialise(pos=np.copy(chain)) assert_equal(mcfitter._state.coords, chain[-1]) # initialise with chain if it's never been run before mcfitter = CurveFitter(self.objective, nwalkers=100, ntemps=20) mcfitter.initialise(chain) def test_fit_smoke(self): # smoke tests to check that fit runs def callback(xk): return def callback2(xk, **kws): return # L-BFGS-B res0 = self.mcfitter.fit(callback=callback) assert_almost_equal(res0.x, [self.b_ls, self.m_ls], 6) res0 = self.mcfitter.fit() res0 = self.mcfitter.fit(verbose=False) res0 = self.mcfitter.fit(verbose=False, callback=callback) # least_squares res1 = self.mcfitter.fit(method="least_squares") assert_almost_equal(res1.x, [self.b_ls, self.m_ls], 6) # least_squares doesn't accept a callback. As well as testing that # least_squares works, it checks that providing a callback doesn't # trip the fitter up. res1 = self.mcfitter.fit(method="least_squares", callback=callback) assert_almost_equal(res1.x, [self.b_ls, self.m_ls], 6) # need full bounds for differential_evolution self.p[0].range(3, 7) self.p[1].range(-2, 0) res2 = self.mcfitter.fit( method="differential_evolution", seed=1, popsize=10, maxiter=100, callback=callback2, ) assert_almost_equal(res2.x, [self.b_ls, self.m_ls], 6) # check that the res object has covar and stderr assert_("covar" in res0) assert_("stderr" in res0) def test_NIST(self): # Run all the NIST standard tests with leastsq for model in NIST_Models: try: NIST_runner(model) except Exception: print(model) raise