def test_ND_model(self): # Check that ND data can be passed to/from a model # Here we see if x can be multidimensional, and that y can return # multidimensional data. # It should be up to the user to ensure that the Data/Model/Objective # stack is returning something consistent with each other. # e.g. the Model output should return something with the same shape as # Data.y. rng = np.random.default_rng() x = rng.uniform(size=100).reshape(2, 50) c = Parameter(1.0, name="c") m = Parameter(2.0, name="m") p = c | m # check that the function is returning what it's supposed to before # we test Model y0 = line(x[0], p) y1 = line(x[1], p) desired = np.vstack((y0, y1)) assert_allclose(line_ND(x, p), desired) fit_model = Model(p, fitfunc=line_ND) y = fit_model(x) assert_allclose(y, desired)
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 test_evaluation(self): c = Parameter(1.0, name="c") m = Parameter(2.0, name="m") p = c | m fit_model = Model(p, fitfunc=line) x = np.linspace(0, 100.0, 20) y = 2.0 * x + 1.0 # different ways of getting the model instance to evaluate assert_equal(fit_model.model(x, p), y) assert_equal(fit_model(x, p), y) assert_equal(fit_model.model(x), y) assert_equal(fit_model(x), y) # can we pickle the model object pkl = pickle.dumps(fit_model) unpkl = pickle.loads(pkl) assert_equal(unpkl(x), y) # you should be able to use a lambda fit_model = Model(p, fitfunc=line2) assert_equal(fit_model(x, p), y) # and swap the order of parameters - retrieve by key p = m | c fit_model = Model(p, fitfunc=line2) assert_equal(fit_model(x, p), y)
def create_structures(self): structures = [] self.distribution_params = [] COI = self.master_structure[self.loc_in_struct] for i in range(self.num_structs): new_COI = copy(COI) if self.param_name == 'thickness': new_COI.thick = Parameter(name='%d - Thick' % i, value=new_COI.thick.value, vary=False) self.distribution_params.append(new_COI.thick) elif self.param_name == 'adsorbed amount': new_COI.adsorbed_amount = Parameter(name='%d - Ads. amnt.' % i, value=new_COI.adsorbed_amount.value, vary=False) self.distribution_params.append(new_COI.adsorbed_amount) else: print('param_name not recognized') struct = self.master_structure[0] for component in self.master_structure[1:]: if component is not COI: struct = struct | component else: struct = struct | new_COI struct.solvent = self.master_structure.solvent structures.append(struct) return structures
def __init__(self, extent, vf, dz, polymer_sld, name='', gamma=None, left_slabs=(), right_slabs=(), interpolator=Pchip, zgrad=True, monotonic_penalty=0, microslab_max_thickness=1): self.name = name if isinstance(polymer_sld, SLD): self.polymer_sld = polymer_sld else: self.polymer_sld = SLD(polymer_sld) # left and right slabs are other areas where the same polymer can # reside self.left_slabs = [slab for slab in left_slabs if isinstance(slab, Slab)] self.right_slabs = [slab for slab in right_slabs if isinstance(slab, Slab)] self.microslab_max_thickness = microslab_max_thickness self.extent = ( possibly_create_parameter(extent, name='%s - spline extent' % name)) # dz are the spatial spacings of the spline knots self.dz = Parameters(name='dz - spline') for i, z in enumerate(dz): p = possibly_create_parameter( z, name='%s - spline dz[%d]' % (name, i)) p.range(0, 1) self.dz.append(p) # vf are the volume fraction values of each of the spline knots self.vf = Parameters(name='vf - spline') for i, v in enumerate(vf): p = possibly_create_parameter( v, name='%s - spline vf[%d]' % (name, i)) p.range(0, 1) self.vf.append(p) if len(self.vf) != len(self.dz): raise ValueError("dz and vs must have same number of entries") self.monotonic_penalty = monotonic_penalty self.zgrad = zgrad self.interpolator = interpolator if gamma is not None: self.gamma = possibly_create_parameter(gamma, 'gamma') else: self.gamma = Parameter(0, 'gamma') self.__cached_interpolator = {'zeds': np.array([]), 'vf': np.array([]), 'interp': None, 'extent': -1}
def test_remove_constraint(self): x = Parameter(5.) y = Parameter(1.) y.constraint = x * 2. y.constraint = None assert_(y.vary is False) assert_equal(y.value, 10) assert_(y._constraint is None)
def test_range(self): x = Parameter(0.) x.range(-1, 1.) assert_equal(x.bounds.lb, -1) assert_equal(x.bounds.ub, 1.) vals = x.valid(np.linspace(-100, 100, 10000)) assert_(np.min(vals) >= -1) assert_(np.max(vals) <= 1)
def test_xerr(self): c = Parameter(1.0, name='c') m = Parameter(2.0, name='m') p = c | m fit_model = Model(p, fitfunc=line3) assert_(fit_model._fitfunc_has_xerr is True) fit_model = Model(p, fitfunc=line2) assert_(fit_model._fitfunc_has_xerr is False)
def test_xerr(self): c = Parameter(1.0, name="c") m = Parameter(2.0, name="m") p = c | m fit_model = Model(p, fitfunc=line3) assert fit_model._fitfunc_has_xerr is True fit_model = Model(p, fitfunc=line2) assert fit_model._fitfunc_has_xerr is False
def __init__(self, solvent_sld, name="POPG"): # super(Popg, self).__init__() d2o = (2 * 0.6671e-4 + 0.5843e-4) + 0j h2o = (2 * -0.3739e-4 + 0.5843e-4) + 0j self.s_sld = Parameter( value=solvent_sld.real, name="{} Solvent SLD".format(name), vary=False, ) d2o_molfr = (1 / d2o.real - h2o.real) * ( (self.s_sld * 1e-6 / 0.036182336306) - h2o.real) wmol_real = (d2o_molfr * d2o.real) + ((1 - d2o_molfr) * h2o.real) wmol_imag = (d2o_molfr * d2o.imag) + ((1 - d2o_molfr) * h2o.imag) self.water_per_lipid_head = Parameter( value=2.8, name="{} Waters Per Head".format(name), vary=True, bounds=(0, 5), ) self.water_per_lipid_tail = Parameter( value=0., name="{} Waters Per Tail".format(name), vary=False, ) self.b_heads_real = Parameter( constraint=get_scattering_length(POPG_H).real + self.water_per_lipid_head * wmol_real, name="{} Head Scattering Length A^-1".format(name), ) self.b_heads_imag = Parameter( value=get_scattering_length(POPG_H).imag + self.water_per_lipid_head * wmol_imag, name="{} Head Imaginary Scattering Length A^-1".format(name), ) self.b_tails_real = Parameter( value=get_scattering_length(POPG_T).real + self.water_per_lipid_tail * wmol_real, name="{} Tail Scattering Length A^-1".format(name), vary=False, ) self.b_tails_imag = Parameter( value=get_scattering_length(POPG_T).imag + self.water_per_lipid_tail * wmol_imag, name="{} Tail Imaginary Scattering Length A^-1".format(name), vary=False, ) self.vm_heads = Parameter( value=214, name="{} Volume of Solvated Heads A^-3".format(name), vary=False, ) self.vm_tails = Parameter( value=886.4, name="{} Volume of Tails A^-3".format(name), vary=False, )
def setup_method(self, tmpdir): self.path = os.path.dirname(os.path.abspath(__file__)) self.tmpdir = tmpdir.strpath theoretical = np.loadtxt(os.path.join(self.path, "gauss_data.txt")) xvals, yvals, evals = np.hsplit(theoretical, 3) xvals = xvals.flatten() yvals = yvals.flatten() evals = evals.flatten() # these best weighted values and uncertainties obtained with Igor self.best_weighted = [-0.00246095, 19.5299, -8.28446e-2, 1.24692] self.best_weighted_errors = [ 0.0220313708486, 1.12879436221, 0.0447659158681, 0.0412022938883, ] self.best_weighted_chisqr = 77.6040960351 self.best_unweighted = [ -0.10584111872702096, 19.240347049328989, 0.0092623066070940396, 1.501362314145845, ] self.best_unweighted_errors = [ 0.34246565477, 0.689820935208, 0.0411243173041, 0.0693429375282, ] self.best_unweighted_chisqr = 497.102084956 self.p0 = np.array([0.1, 20.0, 0.1, 0.1]) self.names = ["bkg", "A", "x0", "width"] self.bounds = [(-1, 1), (0, 30), (-5.0, 5.0), (0.001, 2)] self.params = Parameters(name="gauss_params") for p, name, bound in zip(self.p0, self.names, self.bounds): param = Parameter(p, name=name) param.range(*bound) param.vary = True self.params.append(param) self.model = Model(self.params, fitfunc=gauss) self.data = Data1D((xvals, yvals, evals)) self.objective = Objective(self.model, self.data) return 0
def __init__(self, value, name=''): self.name = name if isinstance(value, complex): self.real = Parameter(value.real, name='%s - sld' % name) self.imag = Parameter(value.imag, name='%s - isld' % name) elif isinstance(value, SLD): self.real = value.real self.imag = value.imag else: self.real = Parameter(value, name='%s - sld' % name) self.imag = Parameter(0, name='%s - isld' % name) self._parameters = Parameters(name=name) self._parameters.extend([self.real, self.imag])
def test_model_subclass(self): class Line(Model): def __init__(self, parameters): super(Line, self).__init__(parameters) def model(self, x, p=None, x_err=None): if p is not None: self._parameters = p a, b = self._parameters return a.value + x * b.value a = Parameter(1.1) b = Parameter(2.2) p = Parameters([a, b]) Line(p)
def test_repr(self): p = Parameter(value=5, name='pop', vary=True) q = eval(repr(p)) assert (q.name == 'pop') assert_allclose(q.value, p.value) p.bounds.lb = -5 q = eval(repr(p)) assert_allclose(q.bounds.lb, -5) assert_allclose(q.bounds.ub, np.inf) p = Parameter(value=5, vary=True) q = eval(repr(p)) assert_allclose(q.value, p.value) assert_allclose(q.vary, p.vary)
def test_sld(self): p = SLD(5 + 1j, name='pop') assert_equal(float(p.real), 5) assert_equal(float(p.imag), 1) # test that we can cast to complex assert_equal(complex(p), 5 + 1j) p = SLD(5) assert_equal(float(p.real), 5) q = Parameter(5) r = Parameter(1) p = SLD([q, r]) assert_equal(float(p.real), 5) assert_equal(float(p.imag), 1)
def test_lnsigma(self): # check that lnsigma works correctly, by using the emcee line fit # example def logp(theta, x, y, yerr): m, b, lnf = theta if -5.0 < m < 0.5 and 0.0 < b < 10.0 and -10.0 < lnf < 1.0: return 0.0 return -np.inf def logl(theta, x, y, yerr): m, b, lnf = theta model = m * x + b inv_sigma2 = 1.0 / (yerr**2 + model**2 * np.exp(2 * lnf)) print(inv_sigma2) return -0.5 * (np.sum((y - model)**2 * inv_sigma2 - np.log(inv_sigma2))) x, y, yerr, _ = self.data.data theta = [self.m_true, self.b_true, np.log(self.f_true)] bo = BaseObjective(theta, logl, logp=logp, fcn_args=(x, y, yerr)) lnsigma = Parameter(np.log(self.f_true), 'lnsigma', bounds=(-10, 1), vary=True) self.objective.setp(np.array([self.b_true, self.m_true])) self.objective.lnsigma = lnsigma # amendment factor because dfm emcee example does not include 2pi amend = 0.5 * self.objective.npoints * np.log(2 * np.pi) assert_allclose(self.objective.logl() + amend, bo.logl())
def test_lnsigma(self): # check that lnsigma works correctly def lnprior(theta, x, y, yerr): m, b, lnf = theta if -5.0 < m < 0.5 and 0.0 < b < 10.0 and -10.0 < lnf < 1.0: return 0.0 return -np.inf def lnlike(theta, x, y, yerr): m, b, lnf = theta model = m * x + b inv_sigma2 = 1.0 / (yerr**2 + model**2 * np.exp(2 * lnf)) print(inv_sigma2) return -0.5 * (np.sum((y - model)**2 * inv_sigma2 - np.log(inv_sigma2))) x, y, yerr, _ = self.data.data theta = [self.m_true, self.b_true, np.log(self.f_true)] bo = BaseObjective(theta, lnlike, lnprior=lnprior, fcn_args=(x, y, yerr)) lnsigma = Parameter(np.log(self.f_true), 'lnsigma', bounds=(-10, 1), vary=True) self.objective.setp(np.array([self.b_true, self.m_true])) self.objective.lnsigma = lnsigma assert_allclose(self.objective.lnlike(), bo.lnlike())
def test_or(self): # concatenation of Parameter instances a = Parameter(1, name='a') b = Parameter(2, name='b') c = Parameters(name='c') c.append(a) c.append(b) # concatenate Parameter instances d = a | b assert_(is_parameters(d)) # concatenate Parameter with Parameters d = a | c assert_(is_parameters(d)) assert_equal(len(d), 2) # a, a, b assert_equal(len(d.flattened()), 3)
def setup_method(self): # Choose the "true" parameters. # 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') | Parameter(self.m_ls, 'm') self.model = Model(self.p, fitfunc=line) self.objective = Objective(self.model, self.data) # want b and m self.p[0].vary = True self.p[1].vary = True 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
def test_set_by_name(self): c = Parameter(3.) self.m['a'] = c assert_(self.m[0] is c) # can't set an entry by name, if there isn't an existing name in this # Parameters instance. from pytest import raises with raises(ValueError): self.m['abc'] = c
def imag(self, wavelength=None): """Extinction coefficent, k.""" if self.model is not None: wavelength = self.model.wav elif self.set_wav is not None: wavelength = self.set_wav else: wavelength = self._default_wav warnings.warn("Using default wavelength (model not linked)") if np.any(self._wav): # TODO - raise a warning if the wavelength supplied is outside the # wavelength range covered by the data file. return Parameter(np.interp(wavelength, self._wav, self._EC)) elif self.A is not None: return Parameter(0) else: return Parameter(value=self._EC)
def test_possibly_create_parameter(self): p = Parameter(10, bounds=(1.0, 2.0)) q = possibly_create_parameter(p, vary=True, bounds=(-1.0, 2.0)) assert q is p assert_allclose(p.bounds.lb, 1) assert_allclose(p.bounds.ub, 2) q = possibly_create_parameter(10, vary=True, bounds=(-1.0, 2.0)) assert_allclose(q.value, 10) assert_allclose(q.bounds.lb, -1) assert_allclose(q.bounds.ub, 2.0) assert q.vary
def test_repr(self): p = Parameter(value=5, vary=False, name="test") g = Parameters(name="name") f = Parameters() f.append(p) f.append(g) q = eval(repr(f)) assert q.name is None assert_equal(q[0].value, 5) assert q[0].vary is False assert isinstance(q[1], Parameters)
def __init__(self, value, name=''): self.name = name self.imag = Parameter(0, name='%s - isld' % name) if isinstance(value, numbers.Real): self.real = Parameter(value.real, name='%s - sld' % name) elif isinstance(value, numbers.Complex): self.real = Parameter(value.real, name='%s - sld' % name) self.imag = Parameter(value.imag, name='%s - isld' % name) elif isinstance(value, SLD): self.real = value.real self.imag = value.imag elif isinstance(value, Parameter): self.real = value elif (hasattr(value, '__len__') and isinstance(value[0], Parameter) and isinstance(value[1], Parameter)): self.real = value[0] self.imag = value[1] self._parameters = Parameters(name=name) self._parameters.extend([self.real, self.imag])
def test_repr(self): p = Parameter(value=5, vary=False, name='test') g = Parameters(name='name') f = Parameters() f.append(p) f.append(g) q = eval(repr(f)) assert (q.name is None) assert_equal(q[0].value, 5) assert (q[0].vary is False) assert (isinstance(q[1], Parameters))
def test_pickle(self): # a parameter and a constrained parameter should be pickleable bounds = PDF(norm(1., 2.)) x = Parameter(1, bounds=bounds) pkl = pickle.dumps(x) unpkl = pickle.loads(pkl) # test pickling on a constrained parameter system a = Parameter(1.) b = Parameter(2.) b.constraint = np.sin(a) assert_(hasattr(a, 'sin')) c = [a, b] pkl = pickle.dumps(c) unpkl = pickle.loads(pkl) d, e = unpkl d.value = 2. assert_equal(e.value, np.sin(2.)) # should still have all math functions assert_(hasattr(d, 'sin'))
def test_logp(self): self.p[0].range(0, 10) assert_almost_equal(self.objective.logp(), np.log(0.1)) # logp should set parameters self.objective.logp([8, 2]) assert_equal(np.array(self.objective.parameters), [8, 2]) # if we supply a value outside the range it should return -inf assert_equal(self.objective.logp([-1, 2]), -np.inf) # are auxiliary parameters included in log? assert_almost_equal(self.objective.logp([8, 2]), np.log(0.1)) p = Parameter(2.0, bounds=(1.0, 3.0)) self.objective.auxiliary_params = Parameters([p]) assert len(self.objective.varying_parameters()) == 2 assert_equal(self.objective.logp(), np.log(0.1)) assert p in self.objective.parameters.flattened() p.vary = True assert len(self.objective.varying_parameters()) == 3 assert_equal(self.objective.logp(), np.log(0.1) + np.log(0.5)) assert p in self.objective.varying_parameters().flattened()
def real(self): """Refractive index, n.""" if self.model is not None: wavelength = self.model.wav elif self.set_wav is not None: wavelength = self.set_wav else: wavelength = self._default_wav warnings.warn("Using default wavelength (model not linked)") if np.any(self._wav): # TODO - raise a warning if the wavelength supplied is outside the # wavelength range covered by the data file. return Parameter(np.interp(wavelength, self._wav, self._RI)) elif self.A is not None: return Parameter(self.A.value + (self.B.value * 1000**2) / (wavelength**2) + (self.C.value**1000**4) / (wavelength**4)) else: return Parameter(value=self._RI)
def test_sld(self): p = SLD(5 + 1j, name="pop") assert_equal(float(p.real), 5) assert_equal(float(p.imag), 1) # test that we can cast to complex assert_equal(complex(p), 5 + 1j) p = SLD(5) assert_equal(float(p.real), 5) q = Parameter(5) r = Parameter(1) p = SLD([q, r]) assert_equal(float(p.real), 5) assert_equal(float(p.imag), 1) # use SLD to make a Slab thickness = Parameter(100) roughness = Parameter(3.0) vfsolv = Parameter(0.2) s = p(thickness, roughness) assert_equal(s.thick.value, thickness.value) assert_equal(s.rough.value, roughness.value) assert_equal(s.vfsolv.value, 0) s = p(thickness, roughness, vfsolv) assert_equal(s.thick.value, thickness.value) assert_equal(s.rough.value, roughness.value) assert_equal(s.vfsolv.value, vfsolv.value) # check that we can construct SLDs from a constrained par deut_par = Parameter(6.36) h2o_solvent = SLD(-0.56) ms_val = 0.6 * deut_par + 0.4 * h2o_solvent.real mixed_solvent = SLD(ms_val) assert isinstance(mixed_solvent.real, _BinaryOp) sld = complex(mixed_solvent) assert_allclose(sld.real, 0.6 * 6.36 + 0.4 * -0.56) deut_par.value = 5.0 sld = complex(mixed_solvent) assert_allclose(sld.real, 0.6 * 5.0 + 0.4 * -0.56)
def test_parameter_bounds(self): x = Parameter(4, bounds=Interval(-4, 4)) assert_equal(x.logp(), uniform.logpdf(0, -4, 8)) x.bounds = None assert_(isinstance(x._bounds, Interval)) assert_equal(x.bounds.lb, -np.inf) assert_equal(x.bounds.ub, np.inf) assert_equal(x.logp(), 0) x.setp(bounds=norm(0, 1)) assert_almost_equal(x.logp(1), norm.logpdf(1, 0, 1)) # all created parameters were mistakenly being given the same # default bounds instance! x = Parameter(4) y = Parameter(5) assert_(id(x.bounds) != id(y.bounds))