diff --git a/RATapi/examples/__init__.py b/RATapi/examples/__init__.py index 6d29206f..355de43a 100644 --- a/RATapi/examples/__init__.py +++ b/RATapi/examples/__init__.py @@ -1,10 +1,12 @@ from RATapi.examples.absorption.absorption import absorption -from RATapi.examples.convert_rascal_project import convert_rascal +from RATapi.examples.convert_rascal_project.convert_rascal import convert_rascal from RATapi.examples.domains.domains_custom_layers import domains_custom_layers from RATapi.examples.domains.domains_custom_XY import domains_custom_XY from RATapi.examples.domains.domains_standard_layers import domains_standard_layers from RATapi.examples.non_polarised.DSPC_custom_layers import DSPC_custom_layers from RATapi.examples.non_polarised.DSPC_custom_XY import DSPC_custom_XY +from RATapi.examples.non_polarised.DSPC_data_background import DSPC_data_background +from RATapi.examples.non_polarised.DSPC_function_background import DSPC_function_background from RATapi.examples.non_polarised.DSPC_standard_layers import DSPC_standard_layers __all__ = [ @@ -15,5 +17,7 @@ "DSPC_custom_layers", "DSPC_custom_XY", "DSPC_standard_layers", + "DSPC_data_background", + "DSPC_function_background", "convert_rascal", ] diff --git a/RATapi/examples/data/d2o_background_data.dat b/RATapi/examples/data/d2o_background_data.dat new file mode 100644 index 00000000..93b2fd38 --- /dev/null +++ b/RATapi/examples/data/d2o_background_data.dat @@ -0,0 +1,82 @@ +0.011403 1.90034798968076e-06 -9.65035874608547e-07 +0.011973 1.81361996101478e-06 -4.67852140773275e-09 +0.012572 1.5763144199176e-06 -1.36151693657437e-06 +0.013201 2.66861902156408e-06 5.28737972088124e-07 +0.013861 1.19184137102607e-06 6.5429177234931e-07 +0.014554 1.75409120253422e-06 -4.50039804064594e-07 +0.015281 1.51534921649628e-06 3.54060605152339e-07 +0.016045 1.76294603973655e-06 2.30273872099416e-07 +0.016848 1.66691808740296e-06 1.02729272466451e-06 +0.01769 2.2391873415575e-06 2.02710446930881e-07 +0.018575 1.47947093349392e-06 9.31566506641381e-07 +0.019503 1.58967045467121e-06 6.58308695637623e-09 +0.020479 2.05056480300655e-06 -4.18637528083399e-07 +0.021502 2.54199126843229e-06 6.96150360898885e-08 +0.022578 1.07273638130851e-06 -5.94598550176916e-08 +0.023706 2.89987639289405e-06 8.05335897612554e-07 +0.024892 1.56081284721073e-06 5.50847432744533e-08 +0.026136 2.32386636321661e-06 -5.72991095509919e-07 +0.027443 2.52478251612625e-06 -2.38750704688337e-08 +0.028815 2.66154668842285e-06 1.05087573637142e-06 +0.030256 1.74132051718101e-06 -2.3192582338868e-07 +0.031769 2.01215747485553e-06 -4.26893410009117e-07 +0.033357 1.91881656322323e-06 8.87192534478923e-07 +0.035025 1.69716945696631e-06 1.80981995646851e-07 +0.036777 2.13585488200451e-06 -1.90164659296111e-07 +0.038615 2.17932170608953e-06 -4.91062265460096e-07 +0.040546 1.82384243860966e-06 -1.08387392818395e-06 +0.042573 2.06617996409986e-06 2.22697399577916e-07 +0.044702 3.33679088859971e-06 -1.53613977488785e-07 +0.046937 1.99621696227773e-06 3.55134601922439e-07 +0.049284 2.3551514683307e-06 -1.06523727035749e-06 +0.051748 1.76873031859355e-06 1.15746760150783e-06 +0.054336 1.73606104969994e-06 4.89763150040874e-07 +0.057052 1.82710646654775e-06 -1.15330099931726e-06 +0.059905 2.28227888686718e-06 9.45647703159621e-07 +0.0629 1.59923042799896e-06 -3.70062237263438e-07 +0.066045 1.07352660741589e-06 3.41777294345909e-07 +0.069348 2.02660800872659e-06 2.75569910736786e-07 +0.072815 1.78179239147256e-06 -6.0256088120987e-07 +0.076456 2.14000373613308e-06 -2.18911980741668e-06 +0.080279 2.04230294359047e-06 5.284442372682e-07 +0.084292 2.36455952978407e-06 -1.73629847921614e-07 +0.088507 2.45037654782291e-06 -3.78287083788833e-07 +0.092932 1.33718085273407e-06 4.35130166728242e-07 +0.097579 1.23771058575749e-06 -4.51744576618967e-07 +0.10246 2.25121666653143e-06 6.36952833032752e-07 +0.10758 2.15319571282475e-06 2.20717968415214e-07 +0.11296 1.53041976734067e-06 -6.93055107868105e-07 +0.11861 2.61870106321507e-06 7.69463958198665e-07 +0.12454 2.01650595727752e-06 4.79607176188218e-07 +0.13077 2.06178415911062e-06 1.10173268381594e-06 +0.1373 2.13696968977538e-06 -6.14098124528528e-07 +0.14417 2.3770829041412e-06 -6.16219383494697e-07 +0.15138 2.7622487528669e-06 3.50660742020884e-07 +0.15895 1.86901211887215e-06 6.33626529015099e-07 +0.16689 1.13465824611353e-06 7.62493241842828e-07 +0.17524 2.50673214999504e-06 1.05207422581854e-07 +0.184 1.53613195077685e-06 -8.87137577093779e-08 +0.1932 2.62184014311179e-06 6.22256875962273e-07 +0.20286 1.70525565120706e-06 1.67162600924891e-06 +0.213 2.74574086739327e-06 8.07667338780613e-07 +0.22365 1.59701095264287e-06 1.67629565660922e-07 +0.23484 1.4437004736234e-06 -3.59611249006791e-07 +0.24658 2.47846978404969e-06 4.99800504594724e-07 +0.25891 1.31847420553136e-06 -2.87283586089481e-07 +0.27185 2.34029248136207e-06 2.90756508518823e-07 +0.28544 2.21891181128286e-06 7.22598553179947e-07 +0.29972 1.92836622666398e-06 8.39418345516717e-07 +0.3147 1.82923374769972e-06 5.70510331434857e-07 +0.33044 3.02890531703209e-06 1.20234742176368e-06 +0.34696 1.8127324822871e-06 1.58096394623758e-06 +0.36431 1.90489840127358e-06 -1.41813181395574e-06 +0.38252 1.53063379469415e-06 -1.32294734328625e-06 +0.40165 1.59326881780842e-06 -6.38112989285387e-07 +0.42173 1.7081906242357e-06 -1.49834166690205e-06 +0.44282 2.85476268526193e-06 -1.85680046178151e-07 +0.46496 1.80479009111448e-06 -1.69120607911057e-07 +0.48821 1.6549673183601e-06 3.00340803829798e-07 +0.51262 1.77588964903545e-06 3.28929520936145e-07 +0.53825 2.35718817504981e-06 -4.48934854489947e-07 +0.56516 1.34213437585845e-06 -5.50651590195596e-07 +0.59342 2.31356104763158e-06 7.347220470815e-07 diff --git a/RATapi/examples/non_polarised/DSPC_data_background.py b/RATapi/examples/non_polarised/DSPC_data_background.py new file mode 100644 index 00000000..02987226 --- /dev/null +++ b/RATapi/examples/non_polarised/DSPC_data_background.py @@ -0,0 +1,218 @@ +import pathlib + +import numpy as np + +import RATapi as RAT + + +def DSPC_data_background(): + """Standard Layers fit of a DSPC floating bilayer""" + problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") + + # Set up the relevant parameters + problem.parameters.append(name="Oxide Thickness", min=5.0, value=19.54, max=60.0, fit=True) + problem.parameters.append(name="Oxide SLD", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False) + problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True) + problem.parameters.append(name="SAM Tails SLD", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False) + problem.parameters.append(name="SAM Tails Hydration", min=1.0, value=5.252, max=50.0, fit=True) + problem.parameters.append(name="SAM Roughness", min=1.0, value=5.64, max=15.0, fit=True) + problem.parameters.append(name="CW Thickness", min=10.0, value=17.12, max=28.0, fit=True) + problem.parameters.append(name="CW SLD", min=0.0, value=0.0, max=1e-09, fit=False) + + problem.parameters.append( + name="SAM Heads Thickness", + min=5.0, + value=8.56, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + problem.parameters.append(name="SAM Heads SLD", min=1.0e-07, value=1.75e-06, max=2.0e-06, fit=False) + problem.parameters.append( + name="SAM Heads Hydration", + min=10.0, + value=45.45, + max=50.0, + fit=True, + prior_type="gaussian", + mu=30.0, + sigma=3.0, + ) + problem.parameters.append( + name="Bilayer Heads Thickness", + min=7.0, + value=10.7, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + problem.parameters.append(name="Bilayer Heads SLD", min=5.0e-07, value=1.47e-06, max=1.5e-06, fit=False) + problem.parameters.append(name="Bilayer Roughness", min=2.0, value=6.014, max=15.0, fit=True) + problem.parameters.append(name="Bilayer Tails Thickness", min=14.0, value=17.82, max=22.0, fit=True) + problem.parameters.append(name="Bilayer Tails SLD", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False) + problem.parameters.append(name="Bilayer Tails Hydration", min=10.0, value=17.64, max=50.0, fit=True) + problem.parameters.append(name="Bilayer Heads Hydration", min=10.0, value=36.15, max=50.0, fit=True) + problem.parameters.append(name="CW Hydration", min=99.9, value=100.0, max=100.0, fit=False) + problem.parameters.append(name="Oxide Hydration", min=0.0, value=23.61, max=60.0, fit=True) + + problem.parameters.set_fields(0, max=10) + + # Group these into layers + problem.layers.append( + name="Oxide", + thickness="Oxide Thickness", + SLD="Oxide SLD", + roughness="Substrate Roughness", + hydration="Oxide Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="SAM Tails", + thickness="SAM Tails Thickness", + SLD="SAM Tails SLD", + roughness="SAM Roughness", + hydration="SAM Tails Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="SAM Heads", + thickness="SAM Heads Thickness", + SLD="SAM Heads SLD", + roughness="SAM Roughness", + hydration="SAM Heads Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Central Water", + thickness="CW Thickness", + SLD="CW SLD", + roughness="Bilayer Roughness", + hydration="CW Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Bilayer Heads", + thickness="Bilayer Heads Thickness", + SLD="Bilayer Heads SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Heads Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Bilayer Tails", + thickness="Bilayer Tails Thickness", + SLD="Bilayer Tails SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Tails Hydration", + hydrate_with="bulk out", + ) + + # Make the bulk SLDs + del problem.bulk_in[0] + problem.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) + + del problem.bulk_out[0] + problem.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) + problem.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) + + # Set the scalefactors - use one for each contrast + del problem.scalefactors[0] + problem.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) + problem.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) + + # Now deal with the backgrounds + # SMW has a constant background + del problem.backgrounds[0] + del problem.background_parameters[0] + problem.background_parameters.append( + name="Background parameter SMW", + min=1.0e-10, + value=3.38e-06, + max=4.99e-06, + fit=True, + ) + problem.backgrounds.append(name="SMW Background", type="constant", source="Background parameter SMW") + + data_path = pathlib.Path(__file__).parents[1] / "data" + + # load in background data for D2O + d2o_background = np.loadtxt(data_path / "d2o_background_data.dat") + problem.data.append(name="D2O Background Data", data=d2o_background) + + # add background parameter for the offset + problem.background_parameters.append( + name="D2O Data Offset", + min=-1e-8, + value=0, + max=1e-8, + fit=True, + ) + + # add the background with data and offset + problem.backgrounds.append( + name="D2O Data Background", + type="data", + source="D2O Background Data", + value_1="D2O Data Offset", + ) + + # Now add the data + d2o_dat = np.loadtxt(data_path / "DSPC_D2O.dat", delimiter=",") + problem.data.append(name="dspc_bil_D2O", data=d2o_dat) + + smw_dat = np.loadtxt(data_path / "DSPC_SMW.dat", delimiter=",") + problem.data.append(name="dspc_bil_smw", data=smw_dat) + + # Set the model + stack = [ + "Oxide", + "SAM Tails", + "SAM Heads", + "Central Water", + "Bilayer Heads", + "Bilayer Tails", + "Bilayer Tails", + "Bilayer Heads", + ] + + # Then make the two contrasts + problem.contrasts.append( + name="D2O", + bulk_in="Silicon", + bulk_out="D2O", + background="D2O Data Background", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + data="dspc_bil_D2O", + model=stack, + ) + + problem.contrasts.append( + name="SMW", + bulk_in="Silicon", + bulk_out="SMW", + background="SMW Background", + resolution="Resolution 1", + scalefactor="Scalefactor 2", + data="dspc_bil_smw", + model=stack, + ) + + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + + return problem, results + + +if __name__ == "__main__": + problem, results = DSPC_data_background() + RAT.plotting.plot_ref_sld(problem, results, True) diff --git a/RATapi/examples/non_polarised/DSPC_function_background.py b/RATapi/examples/non_polarised/DSPC_function_background.py new file mode 100644 index 00000000..1ad863fa --- /dev/null +++ b/RATapi/examples/non_polarised/DSPC_function_background.py @@ -0,0 +1,218 @@ +import pathlib + +import numpy as np + +import RATapi as RAT + + +def DSPC_function_background(): + """Standard Layers fit of a DSPC floating bilayer""" + problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") + + # Set up the relevant parameters + problem.parameters.append(name="Oxide Thickness", min=5.0, value=19.54, max=60.0, fit=True) + problem.parameters.append(name="Oxide SLD", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False) + problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True) + problem.parameters.append(name="SAM Tails SLD", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False) + problem.parameters.append(name="SAM Tails Hydration", min=1.0, value=5.252, max=50.0, fit=True) + problem.parameters.append(name="SAM Roughness", min=1.0, value=5.64, max=15.0, fit=True) + problem.parameters.append(name="CW Thickness", min=10.0, value=17.12, max=28.0, fit=True) + problem.parameters.append(name="CW SLD", min=0.0, value=0.0, max=1e-09, fit=False) + + problem.parameters.append( + name="SAM Heads Thickness", + min=5.0, + value=8.56, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + problem.parameters.append(name="SAM Heads SLD", min=1.0e-07, value=1.75e-06, max=2.0e-06, fit=False) + problem.parameters.append( + name="SAM Heads Hydration", + min=10.0, + value=45.45, + max=50.0, + fit=True, + prior_type="gaussian", + mu=30.0, + sigma=3.0, + ) + problem.parameters.append( + name="Bilayer Heads Thickness", + min=7.0, + value=10.7, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + problem.parameters.append(name="Bilayer Heads SLD", min=5.0e-07, value=1.47e-06, max=1.5e-06, fit=False) + problem.parameters.append(name="Bilayer Roughness", min=2.0, value=6.014, max=15.0, fit=True) + problem.parameters.append(name="Bilayer Tails Thickness", min=14.0, value=17.82, max=22.0, fit=True) + problem.parameters.append(name="Bilayer Tails SLD", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False) + problem.parameters.append(name="Bilayer Tails Hydration", min=10.0, value=17.64, max=50.0, fit=True) + problem.parameters.append(name="Bilayer Heads Hydration", min=10.0, value=36.15, max=50.0, fit=True) + problem.parameters.append(name="CW Hydration", min=99.9, value=100.0, max=100.0, fit=False) + problem.parameters.append(name="Oxide Hydration", min=0.0, value=23.61, max=60.0, fit=True) + + problem.parameters.set_fields(0, max=10) + + # Group these into layers + problem.layers.append( + name="Oxide", + thickness="Oxide Thickness", + SLD="Oxide SLD", + roughness="Substrate Roughness", + hydration="Oxide Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="SAM Tails", + thickness="SAM Tails Thickness", + SLD="SAM Tails SLD", + roughness="SAM Roughness", + hydration="SAM Tails Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="SAM Heads", + thickness="SAM Heads Thickness", + SLD="SAM Heads SLD", + roughness="SAM Roughness", + hydration="SAM Heads Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Central Water", + thickness="CW Thickness", + SLD="CW SLD", + roughness="Bilayer Roughness", + hydration="CW Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Bilayer Heads", + thickness="Bilayer Heads Thickness", + SLD="Bilayer Heads SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Heads Hydration", + hydrate_with="bulk out", + ) + + problem.layers.append( + name="Bilayer Tails", + thickness="Bilayer Tails Thickness", + SLD="Bilayer Tails SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Tails Hydration", + hydrate_with="bulk out", + ) + + # Make the bulk SLDs + del problem.bulk_in[0] + problem.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) + + del problem.bulk_out[0] + problem.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) + problem.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) + + # Set the scalefactors - use one for each contrast + del problem.scalefactors[0] + problem.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) + problem.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) + + # Now deal with the backgrounds + # SMW has a constant background + del problem.backgrounds[0] + del problem.background_parameters[0] + problem.background_parameters.append( + name="Background parameter SMW", + min=1.0e-10, + value=3.38e-06, + max=4.99e-06, + fit=True, + ) + problem.backgrounds.append(name="SMW Background", type="constant", source="Background parameter SMW") + + # FIXME: replace this with a Python custom file when Python backgrounds are added! + problem.custom_files.append( + name="D2O Background Function", + filename="backgroundFunction.m", + language="matlab", + path=pathlib.Path(__file__).parent.resolve(), + ) + + problem.background_parameters.append(name="Fn Ao", min=5e-7, value=8e-6, max=5e-5) + problem.background_parameters.append(name="Fn k", min=40, value=70, max=90) + problem.background_parameters.append(name="Fn Const", min=1e-7, value=8e-6, max=1e-5) + + problem.backgrounds.append( + name="D2O Function Background", + type="function", + source="D2O Background Function", + value_1="Fn Ao", + value_2="Fn k", + value_3="Fn Const", + ) + + # Now add the data + data_path = pathlib.Path(__file__).parents[1] / "data" + + d2o_dat = np.loadtxt(data_path / "DSPC_D2O.dat", delimiter=",") + problem.data.append(name="dspc_bil_D2O", data=d2o_dat) + + smw_dat = np.loadtxt(data_path / "DSPC_SMW.dat", delimiter=",") + problem.data.append(name="dspc_bil_smw", data=smw_dat) + + # Set the model + stack = [ + "Oxide", + "SAM Tails", + "SAM Heads", + "Central Water", + "Bilayer Heads", + "Bilayer Tails", + "Bilayer Tails", + "Bilayer Heads", + ] + + # Then make the two contrasts + problem.contrasts.append( + name="D2O", + bulk_in="Silicon", + bulk_out="D2O", + background="D2O Function Background", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + data="dspc_bil_D2O", + model=stack, + ) + + problem.contrasts.append( + name="SMW", + bulk_in="Silicon", + bulk_out="SMW", + background="SMW Background", + resolution="Resolution 1", + scalefactor="Scalefactor 2", + data="dspc_bil_smw", + model=stack, + ) + + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + + return problem, results + + +if __name__ == "__main__": + problem, results = DSPC_function_background() + RAT.plotting.plot_ref_sld(problem, results, True) diff --git a/RATapi/examples/non_polarised/backgroundFunction.m b/RATapi/examples/non_polarised/backgroundFunction.m new file mode 100644 index 00000000..181e0f58 --- /dev/null +++ b/RATapi/examples/non_polarised/backgroundFunction.m @@ -0,0 +1,14 @@ +function background = backgroundFunction(xdata,params) + +% Split up the params array.... +Ao = params(1); +k = params(2); +backConst = params(3); + +% Make an exponential decay background.... +background = zeros(numel(xdata),1); +for i = 1:numel(xdata) + background(i) = Ao*exp(-k*xdata(i)) + backConst; +end + +end diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 00000000..cb5425b5 --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,43 @@ +"""Test the RAT examples.""" + +import importlib + +import pytest + +import RATapi.examples as examples + + +@pytest.mark.parametrize( + "example_name", + [ + "absorption", + "domains_custom_layers", + "domains_custom_XY", + "domains_standard_layers", + "DSPC_custom_layers", + "DSPC_custom_XY", + "DSPC_standard_layers", + "DSPC_data_background", + ], +) +def test_rat_examples(example_name): + """Test that the RAT example projects run successfully.""" + p, r = getattr(examples, example_name)() + assert p is not None + assert r is not None + + +@pytest.mark.parametrize( + "example_name", + [ + "DSPC_function_background", + # FIXME: https://github.com/RascalSoftware/python-RAT/issues/102 + # "convert_rascal", + ], +) +@pytest.mark.skipif(importlib.util.find_spec("matlab") is None, reason="Matlab not installed") +def test_matlab_examples(example_name): + """Test examples which rely on MATLAB engine being installed.""" + p, r = getattr(examples, example_name)() + assert p is not None + assert r is not None