def test_resolution_speed_comparator(self): 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) dx = dataset.x_err structure = si | sio2_l | polymer_l | polymer_l | d2o(0, 3) model = ReflectModel(structure, bkg=2e-6, dq_type="constant") objective = Objective(model, dataset, use_weights=False, transform=Transform("logY")) # check that choose_resolution_approach doesn't change state # of model fastest_method = choose_dq_type(objective) assert model.dq_type == "constant" assert_equal(dx, objective.data.x_err) # check that the comparison worked const_time = time.time() for i in range(1000): objective.generative() const_time = time.time() - const_time model.dq_type = "pointwise" point_time = time.time() for i in range(1000): objective.generative() point_time = time.time() - point_time if fastest_method == "pointwise": assert point_time < const_time elif fastest_method == "constant": assert const_time < point_time # check that we could use the function to setup a reflectmodel ReflectModel(structure, bkg=2e-6, dq_type=choose_dq_type(objective))
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 test_multidimensionality(self): # Check that ND data can be used with an objective/model/data # (or at least it doesn't stand in the way) rng = np.random.default_rng() x = rng.uniform(size=100).reshape(50, 2) desired = line_ND(x, self.p) assert desired.shape == (50, 2) data = Data1D((x, desired)) model = Model(self.p, fitfunc=line_ND) y = model(x) assert_allclose(y, desired) objective = Objective(model, data) assert_allclose(objective.chisqr(), 0) assert_allclose(objective.generative(), desired) assert_allclose(objective.residuals(), 0) assert objective.residuals().shape == (50, 2) objective.logl() objective.logpost() covar = objective.covar() assert covar.shape == (2, 2)
class Model(): """The Model class represents a refnx model using predictions made by the classifier and regressors. Class Attributes: roughness (int): the default roughness between each layer in Angstrom. rough_bounds (tuple): the range of values to fit for roughness. si_sld (float): the substrate SLD (silicon). dq (float): the instrument resolution parameter. scale (float): the instrument scale parameter. bkg (float): value for the background parameter. """ roughness = 8 rough_bounds = CurveGenerator.rough_bounds si_sld = NeutronGenerator.substrate_sld dq = CurveGenerator.dq scale = CurveGenerator.scale bkg = 2e-7 def __init__(self, file_path, layers, predicted_slds, predicted_depths, xray): """Initialises the Model class by creating a refnx model with given predicted values. Args: file_path (string): a path to the file with the data to construct the model for. layers (int): the number of layers for the model predicted by the classifier. predicted_slds (ndarray): an array of predicted SLDs for each layer. predicted_depths (ndarray): an array of predicted depths for each layer. xray (Boolean): whether the model should use a neutron or x-ray probe. """ self.structure = SLD(0, name='Air') #Model starts with air. if xray: #Use x-ray probe for i in range(layers): density = predicted_slds[i] / XRayGenerator.density_constant SLD_layer = MaterialSLD(XRayGenerator.material, density, probe='x-ray', wavelength=XRayGenerator.wavelength, name='Layer {}'.format(i+1)) layer = SLD_layer(thick=predicted_depths[i], rough=Model.roughness) layer.density.setp(bounds=XRayGenerator.density_bounds, vary=True) layer.thick.setp(bounds=ImageGenerator.depth_bounds, vary=True) layer.rough.setp(bounds=Model.rough_bounds, vary=True) self.structure = self.structure | layer #Next comes each layer. #Then substrate si_substrate = MaterialSLD(XRayGenerator.material, XRayGenerator.substrate_density, probe='x-ray', name='Si Substrate')(thick=0, rough=Model.roughness) else: #Use neutron probe for i in range(layers): layer = SLD(predicted_slds[i], name='Layer {}'.format(i+1))(thick=predicted_depths[i], rough=Model.roughness) layer.sld.real.setp(bounds=ImageGenerator.sld_neutron_bounds, vary=True) layer.thick.setp(bounds=ImageGenerator.depth_bounds, vary=True) layer.rough.setp(bounds=Model.rough_bounds, vary=True) self.structure = self.structure | layer #Next comes each layer. #Then substrate si_substrate = SLD(Model.si_sld, name='Si Substrate')(thick=0, rough=Model.roughness) si_substrate.rough.setp(bounds=Model.rough_bounds, vary=True) self.structure = self.structure | si_substrate data = self.__load_data(file_path) #Pre-process and load given dataset. self.model = ReflectModel(self.structure, scale=Model.scale, dq=Model.dq, bkg=Model.bkg) self.objective = Objective(self.model, data) def __load_data(self, file_path): """Loads a reflectivity dataset from a given file path and applies scaling. Args: file_path (string): a path to the file with the data to construct the model for. """ data = ReflectDataset(file_path) #Load the data for which the model is designed for. self.filename = os.path.basename(data.filename) data.scale(np.max(data.data[1])) #Normalise Y and Error by dividing by max R point. x, y, y_err = data.x.tolist(), data.y.tolist(), data.y_err.tolist() removed = [] #Remove any points containing 0 values as these cause NaNs when fitting. for i in range(len(x)): if x[i] == 0 or y[i] == 0 or y_err[i] == 0: removed.append(i) #Remove the identified points and return the processed dataset. x = np.delete(np.array(x), removed) y = np.delete(np.array(y), removed) y_err = np.delete(np.array(y_err), removed) data_new = np.array([x, y, y_err]) return ReflectDataset(data_new) def fit(self): """Fits the model to the data using differential evolution.""" fitter = CurveFitter(self.objective) fitter.fit('differential_evolution', verbose=False) def plot_objective(self, prediction=True): """Plots the current objective for the model against given dataset. Args: prediction (Boolean): whether the plot is a prediction or fit. """ if prediction: title='Reflectivity Plot using Predicted Values' label="Predicted" else: title='Reflectivity Plot using Fitted Values' label="Fitted" fig = plt.figure(figsize=[9,7], dpi=600) ax = fig.add_subplot(111) y, y_err, model = self.objective._data_transform(model=self.objective.generative()) # Add the data in a transformed fashion. ax.errorbar(self.objective.data.x, y, y_err, label=self.filename, color="blue", marker="o", ms=3, lw=0, elinewidth=1, capsize=1.5) #Add the prediction/fit ax.plot(self.objective.data.x, model, color="red", label=label, zorder=20) plt.xlabel("$\mathregular{Q\ (Å^{-1})}$", fontsize=11, weight='bold') plt.ylabel('Reflectivity (arb.)', fontsize=11, weight='bold') plt.yscale('log') plt.legend() if title: plt.title(title, fontsize=15, pad=15)