From de5ddfd37141c7138f7aea1583894de704c369ad Mon Sep 17 00:00:00 2001 From: "Alex H. Room" <69592136+alexhroom@users.noreply.github.com> Date: Wed, 19 Feb 2025 10:31:00 +0000 Subject: [PATCH] Adds Jupyter notebooks and MATLAB live scripts to the examples (#30) * rearranged examples to make way for python * script for getting tutorials * fixed matlab images and made setup tutorial simpler * split tutorials folder into two * split tutorials folder into two * added livescripts to matlab examples * added nbsphinx to requirements and install pandoc in CI * removed python-rat data from repo * made notebooks part of build process * fix ci * added prolog to notebooks * matlab live scripts now have outputs * updated readme, fixed typo, added examples to header * update notebooks readme * tidied up header * complete rebase (whoops!) * review fixes --- .github/workflows/build_docs.yml | 9 ++ .gitignore | 4 + README.md | 2 + requirements.txt | 2 + source/conf.py | 76 ++++++++++++++++- source/examples.rst | 21 +++++ source/examples/DSPC_custom_XY.rst | 79 ------------------ source/examples/DSPC_custom_layers.rst | 67 --------------- source/examples/DSPC_standard_layers.rst | 55 ------------ source/examples/convert_r1_project.rst | 52 ------------ source/examples/custom_model_languages.rst | 56 ------------- source/examples/domains_custom_XY.rst | 60 ------------- source/examples/domains_custom_layers.rst | 60 ------------- source/examples/domains_standard_layers.rst | 64 -------------- source/guide.rst | 3 +- source/index.rst | 9 +- source/matlab_examples.pdf | Bin 0 -> 45874 bytes source/matlab_examples/DSPC_custom_XY.rst | 49 +++++++++++ source/matlab_examples/DSPC_custom_layers.rst | 41 +++++++++ .../matlab_examples/DSPC_standard_layers.rst | 30 +++++++ source/matlab_examples/convert_r1_project.rst | 23 +++++ .../custom_model_languages.rst | 36 ++++++++ source/matlab_examples/domains_custom_XY.rst | 33 ++++++++ .../matlab_examples/domains_custom_layers.rst | 33 ++++++++ .../domains_standard_layers.rst | 39 +++++++++ .../imaginary.rst | 0 .../{examples => matlab_examples}/index.rst | 10 +-- source/python_examples/index.rst | 37 ++++++++ source/python_examples/notebooks/README.md | 5 ++ source/reference/index.rst | 24 ++++++ 30 files changed, 474 insertions(+), 505 deletions(-) create mode 100644 source/examples.rst delete mode 100644 source/examples/DSPC_custom_XY.rst delete mode 100644 source/examples/DSPC_custom_layers.rst delete mode 100644 source/examples/DSPC_standard_layers.rst delete mode 100644 source/examples/convert_r1_project.rst delete mode 100644 source/examples/custom_model_languages.rst delete mode 100644 source/examples/domains_custom_XY.rst delete mode 100644 source/examples/domains_custom_layers.rst delete mode 100644 source/examples/domains_standard_layers.rst create mode 100644 source/matlab_examples.pdf create mode 100644 source/matlab_examples/DSPC_custom_XY.rst create mode 100644 source/matlab_examples/DSPC_custom_layers.rst create mode 100644 source/matlab_examples/DSPC_standard_layers.rst create mode 100644 source/matlab_examples/convert_r1_project.rst create mode 100644 source/matlab_examples/custom_model_languages.rst create mode 100644 source/matlab_examples/domains_custom_XY.rst create mode 100644 source/matlab_examples/domains_custom_layers.rst create mode 100644 source/matlab_examples/domains_standard_layers.rst rename source/{examples => matlab_examples}/imaginary.rst (100%) rename source/{examples => matlab_examples}/index.rst (82%) create mode 100644 source/python_examples/index.rst create mode 100644 source/python_examples/notebooks/README.md create mode 100644 source/reference/index.rst diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 4ee01d69..815f8ba0 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -21,8 +21,17 @@ jobs: python-version: '3.11' - name: Build docs run: | + # create an x11 display because otherwise MATLAB refuses to export live scripts... + sudo apt install -y xvfb + export DISPLAY=':99.0' + Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & + wget https://github.com/RascalSoftware/RAT/releases/download/nightly/Linux.zip unzip Linux.zip -d API/ + + # we get pandoc from web as apt version is outdated + wget https://github.com/jgm/pandoc/releases/download/3.6.2/pandoc-3.6.2-1-amd64.deb + sudo apt install -y ./pandoc-3.6.2-1-amd64.deb python -m pip install --upgrade pip pip install matlabengine==24.1.* pip install -r requirements.txt diff --git a/.gitignore b/.gitignore index c7c5425b..73092706 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ source/_outputs/ # autogenerated documentation source/reference/python/RATapi.* +source/python_examples/data/ +source/matlab_examples/*.html +source/python_examples/notebooks/* +!source/python_examples/notebooks/README.md diff --git a/README.md b/README.md index 3c88d0ee..c8fe400a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ Download the appropriate version of RAT from the GitHub [release](https://github wget https://github.com/RascalSoftware/RAT/releases/download/nightly/Linux.zip unzip Linux.zip -d API/ +You also must have `pandoc` installed to build the Python example Jupyter notebooks. See the installation instructions [here](https://pandoc.org/installing.html). + To build the HTML docs, type the following into a terminal with access to the Python executable: diff --git a/requirements.txt b/requirements.txt index 540e74f2..49410a82 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,6 +3,8 @@ sphinxcontrib-matlabdomain==0.18 pydata-sphinx-theme==0.15.2 sphinx_design==0.6.0 sphinx-copybutton==0.5.2 +jupyter==1.0.0 +nbsphinx==0.9.6 RATapi==0.0.0.dev4 autodoc_pydantic==2.2.0 enum-tools[sphinx]==0.12.0 diff --git a/source/conf.py b/source/conf.py index 29dd9e11..6d05b51f 100644 --- a/source/conf.py +++ b/source/conf.py @@ -7,8 +7,13 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. import os import sys +import shutil import datetime +import zipfile +from importlib import metadata from urllib.parse import urljoin +from urllib.request import urlretrieve +from pathlib import Path # -- Project information ----------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -33,17 +38,60 @@ sys.path.insert(0, os.path.dirname(os.path.abspath(".."))) from version import get_doc_version doc_version = get_doc_version() - + # -- General configuration --------------------------------------------------- # add extensions path for snippets sys.path.append(os.path.abspath("./_ext")) -extensions = ['sphinxcontrib.matlab', 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinxcontrib.autodoc_pydantic', 'sphinx_design', 'sphinx_copybutton', 'snippets', 'enum_tools.autoenum'] +extensions = ['sphinxcontrib.matlab', 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'sphinx.ext.autosummary', 'sphinxcontrib.autodoc_pydantic', 'sphinx_design', 'sphinx_copybutton', 'snippets', 'enum_tools.autoenum', 'nbsphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +# -- Setup example files ----------------------------------------------------- +PYTHON_RAT_RELEASE = metadata.version("RATapi") + +if not os.path.isdir("./python_examples/data"): + zip_dir, headers = urlretrieve(f"https://github.com/RascalSoftware/python-RAT/archive/refs/tags/{PYTHON_RAT_RELEASE}.zip") + with zipfile.ZipFile(zip_dir) as zf: + zf.extractall() + print("Copying Jupyter notebooks...") + for directory in ['normal_reflectivity', 'domains', 'absorption']: + for file in Path(f"./python-RAT-{PYTHON_RAT_RELEASE}/RATapi/examples/{directory}/").glob('*'): + shutil.copy(file, "./python_examples/notebooks/") + + shutil.copytree(f"./python-RAT-{PYTHON_RAT_RELEASE}/RATapi/examples/data", "./python_examples/data", dirs_exist_ok=True) + + shutil.rmtree(f"./python-RAT-{PYTHON_RAT_RELEASE}") + +if not os.path.isfile("./matlab_examples/standardLayersDSPCSheet.html"): + try: + from matlab.engine import start_matlab + except ImportError: + print("Could not copy MATLAB live scripts as MATLAB is not installed.") + else: + print("Starting MATLAB Engine...") + eng = start_matlab() + matlab_examples_path = Path("./matlab_examples").resolve() + eng.eval("cd('../API'); addPaths;", nargout=0) + for sheet in ['normalReflectivity/standardLayers/standardLayersDSPCSheet', + 'normalReflectivity/customLayers/customLayersDSPCSheet', + 'normalReflectivity/customXY/customXYDSPCSheet', + 'domains/standardLayers/domainsStandardLayersSheet', + 'domains/customLayers/domainsCustomLayersSheet', + 'domains/customXY/domainsCustomXYSheet', + 'miscellaneous/convertRascal1Project/convertRascal', + 'miscellaneous/alternativeLanguages/customModelLanguagesSheet',]: + filename = Path(sheet).name + folder = str(Path(sheet).parent) + print(f"exporting {sheet}") + eng.cd(f"examples/{folder}", nargout=0) + eng.matlab.internal.liveeditor.executeAndSave(str(Path(f"../API/examples/{sheet}.mlx").resolve()), nargout=0) + eng.export(f"{filename}.mlx", str(matlab_examples_path / f"{filename}.html"), nargout=0) + eng.cd("../../../", nargout=0) + + # -- Options for HTML output ------------------------------------------------- #set primary_domain = 'matlab' primary_domain = None @@ -84,6 +132,30 @@ autodoc_typehints = "description" +nbsphinx_prolog = r""" +{% set docname = 'doc/' + env.doc2path(env.docname, base=None)|string %} + +.. raw:: html + +
+ This page was generated from the notebook {{ env.docname.split('/')|last|e + '.ipynb' }} found in + the Python-RAT repository. + Download notebook. +
+ +.. note:: + + To get the output project and results from this example in your Python session, run: + + .. code-block:: python + + from RATapi.examples import {{ env.docname.split('/')|last|e }} + project, results = {{ env.docname.split('/')|last|e }}() + +------------------------------------------------------------------------------------- + +""" + ### autodoc_pydantic settings # hide JSON schemas by default autodoc_pydantic_model_show_json = False diff --git a/source/examples.rst b/source/examples.rst new file mode 100644 index 00000000..151df19b --- /dev/null +++ b/source/examples.rst @@ -0,0 +1,21 @@ +Examples +======== + +Several examples are provided for RAT in both Python and MATLAB: + + +Matlab +------ + +.. toctree:: + :maxdepth: 3 + + matlab_examples/index + +Python +------ + +.. toctree:: + :maxdepth: 3 + + python_examples/index diff --git a/source/examples/DSPC_custom_XY.rst b/source/examples/DSPC_custom_XY.rst deleted file mode 100644 index 0697c2a8..00000000 --- a/source/examples/DSPC_custom_XY.rst +++ /dev/null @@ -1,79 +0,0 @@ -============== -DSPC Custom XY -============== - -This shows an example of using a :ref:`custom XY` model to analyse reflectivity from a supported bilayer of DSPC. - -Similar to :ref:`DSPC_Custom_Layers`, we can make use of the fact that the volumes, and of course the atomistic composition are known. So, -for lipid tails for example, then we can take a literature value for the tails volume, have a fittable parameter for the lipid area per molecule, and then the tail thickness will simply be - -.. math:: \text{Tail Thick} = \frac{\text{Tail Volume}}{\text{Lipid APM}}. - -Since the volume is known, then the SLD of the tails is also obviously easily calculable. - -In this model, we make distributions to represent the volume fractions of each of the components in the sample, the convert these to SLD's, as described in :ref:`[1] `. - -We also make our volume fractions as optional outputted parameters from our file. The optional nature of this output means we can suppress it to run the model, then -activate it to make final output plots of our analysis. - -.. image:: ../images/examples/volumeFractions.png - :align: center - :alt: Volume fractions - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom model used is a MATLAB model - **examples/normalReflectivity/customXY/customXYDSPC.m**. - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'customXY')); - customXYDSPCScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'customXY')); - edit customXYDSPCSheet - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom model used is a Python model - **RATapi.examples.normal_reflectivity.custom_XY_DSPC.py**. - - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.normal_reflectivity.DSPC_custom_XY.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.normal_reflectivity.DSPC_custom_XY() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.normal_reflectivity.DSPC_custom_XY.ipynb - - -.. _ref_1: - -[1] Sheker et al, J. Appl. Phys, 100, 102216 (2011) [`DOI 10.1063/1.3661986 `_] - diff --git a/source/examples/DSPC_custom_layers.rst b/source/examples/DSPC_custom_layers.rst deleted file mode 100644 index 4496f214..00000000 --- a/source/examples/DSPC_custom_layers.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. _DSPC_Custom_Layers: - -================== -DSPC Custom Layers -================== - -This shows an example of using a :ref:`custom layers` model to analyse reflectivity from a supported bilayer of DSPC. - -In this example, we can make use of the fact that the volumes, and of course the atomistic composition are known. So, for lipid tails for example, then we can -take a literature value for the tails volume, have a fittable parameter for the lipid area per molecule, and then the tail thickness will simply be - -.. math:: Tail Thick = Tail Volume / Lipid APM. - -Since the volume is known, then the SLD of the tails is also obviously easily calculable. - -In addition, the datasets for this example, have a resolution (per point) in their fourth column. We use this resolution in our analysis, rather than declaring a constant, fittable one. - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom model used is a MATLAB model - **examples/normalReflectivity/customLayers/customBilayerDSPC.m**. - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'customLayers')); - customLayersDSPCScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'customLayers')); - edit customLayersDSPCSheet.mlx - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom model used is a Python model - **RATapi.examples.normal_reflectivity.custom_bilayer_DSPC.py**. - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.normal_reflectivity.DSPC_custom_layers.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.normal_reflectivity.DSPC_custom_layers() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.normal_reflectivity.DSPC_custom_layers.ipynb diff --git a/source/examples/DSPC_standard_layers.rst b/source/examples/DSPC_standard_layers.rst deleted file mode 100644 index 7c906e53..00000000 --- a/source/examples/DSPC_standard_layers.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. _DSPC_Standard_Layers: - -==================== -DSPC Standard Layers -==================== -This shows an example of using a :ref:`standard layers` model to analyse reflectivity from a floating bilayer of DSPC. - -The model is set up in the script, we set Gaussian priors on some of the parameters, build the two contrasts, run the calculation and plot the results. - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'standardLayers')); - standardLayersDSPCScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'normalReflectivity', 'standardLayers')); - edit standardLayersDSPCSheet.mlx - - - .. tab-item:: Python - :sync: Python - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.normal_reflectivity.DSPC_standard_layers.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.normal_reflectivity.DSPC_standard_layers() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.normal_reflectivity.DSPC_standard_layers.ipynb diff --git a/source/examples/convert_r1_project.rst b/source/examples/convert_r1_project.rst deleted file mode 100644 index 38dc9145..00000000 --- a/source/examples/convert_r1_project.rst +++ /dev/null @@ -1,52 +0,0 @@ -============================= -Converting a RasCAL-1 Project -============================= - -If you have projects from RasCAL1, there is a simple utility supplied with the toolbox that makes converting between formats easy as explained in :ref:`conversionFuncs`. - -This example shows the conversion of a RasCAL-1 custom layers project into a RAT project and vice versa, because this is a custom layers project, the custom model -function **Model_IIb.m** which in the example directory is required to run the converted RAT project successfully. - -This example can be run using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom model used is a MATLAB model - **examples/miscellaneous/convertRascal1Project/Model_IIb.m**. - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'miscellaneous', 'convertRascal1Project')); - edit convertRascal.mlx - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom model used is a MATLAB model - **RATapi.examples.convert_rascal_project.Model_IIb.m**. - A python version is provided for the jupyter notebook - **RATapi.examples.convert_rascal_project.Model_IIb.py** - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.convert_rascal_project.convert_rascal.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.convert_rascal_project.convert_rascal() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.convert_rascal_project.convert_rascal.ipynb diff --git a/source/examples/custom_model_languages.rst b/source/examples/custom_model_languages.rst deleted file mode 100644 index 80583b4d..00000000 --- a/source/examples/custom_model_languages.rst +++ /dev/null @@ -1,56 +0,0 @@ -================================== -Alternative Custom Model Languages -================================== - -In this example, we setup a :ref:`custom layers` problem using three different programming language (MATLAB, Python, and C++) to write the custom model function. -The provided C++ function needs to be compiled into a dynamic library using instructions given in :ref:`customLanguages` or instructions specific to your compiler. - - -This example can be run using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom models used are - - **examples/miscellaneous/languages/alloyDomains.m**, - **examples/miscellaneous/languages/alloyDomains.m**, - **examples/miscellaneous/languages/alloyDomains.m**. - - .. warning:: For Python custom functions, you will need to setup the python environment for MATLAB, see `Setup MATLAB to use Python `_ - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'miscellaneous', 'alternativeLanguages')); - customModelLanguagesScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'miscellaneous', 'alternativeLanguages')); - edit customModelLanguagesSheet.mlx - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom models used are - - **RATapi.examples.languages.custom_bilayer.cpp**, - **RATapi.examples.languages.custom_bilayer.py**, - **RATapi.examples.languages.custom_bilayer.m**. - - .. warning:: For MATLAB custom functions, ensure MATLAB and matlabengine are installed :ref:`install`. - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.languages.run_custom_file_languages.py - diff --git a/source/examples/domains_custom_XY.rst b/source/examples/domains_custom_XY.rst deleted file mode 100644 index 7f9bef42..00000000 --- a/source/examples/domains_custom_XY.rst +++ /dev/null @@ -1,60 +0,0 @@ -================================= -Incoherent Summing with Custom XY -================================= - -This is an example of using incoherent summing ('domains') from custom XY models. - -The domain custom XY model is similar to a normal custom models, except that the input (function arguments) of the custom function contains an additional 'domains' parameter as described in :ref:`domainsCustomModels`. - -This parameter tells the function which is the current domain, so the appropriate layer stack can be generated. - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom model used is a MATLAB model - **examples/domains/customXY/domainsXY.m**. - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'customXY')); - domainsCustomXYScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'customXY')); - edit domainsCustomXYSheet.mlx - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom model used is a Python model - **RATapi.examples.domains.domains_XY_model.py**. - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.domains.domains_custom_XY.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.domains.domains_custom_XY() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.domains.domains_custom_XY.ipynb diff --git a/source/examples/domains_custom_layers.rst b/source/examples/domains_custom_layers.rst deleted file mode 100644 index 64f39d95..00000000 --- a/source/examples/domains_custom_layers.rst +++ /dev/null @@ -1,60 +0,0 @@ -===================================== -Incoherent Summing with Custom Layers -===================================== - -This is an example of using incoherent summing ('domains') from custom layers models. The sample is a simple two layer of permalloy/gold, with up/down domains - -The domain custom model is similar to a normal custom models, except that the input (function arguments) of the custom function contains an additional 'domains' parameter as described in :ref:`domainsCustomModels`. - -This parameter tells the function which is the current domain, so the appropriate layer stack can be generated. - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - .. note:: The custom model used is a MATLAB model - **examples/domains/customLayers/alloyDomains.m**. - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'customLayers')); - domainsCustomXYScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'customLayers')); - edit domainsCustomXYSheet.mlx - - - .. tab-item:: Python - :sync: Python - - .. note:: The custom model used is a Python model - **RATapi.examples.domains.alloy_domains.py**. - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.domains.domains_custom_layers.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.domains.domains_custom_layers() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.domains.domains_custom_layers.ipynb diff --git a/source/examples/domains_standard_layers.rst b/source/examples/domains_standard_layers.rst deleted file mode 100644 index ece6061a..00000000 --- a/source/examples/domains_standard_layers.rst +++ /dev/null @@ -1,64 +0,0 @@ -======================================= -Incoherent Summing with Standard Layers -======================================= - -Analysing data containing domains using standard layers models is done in a similar way to a normal standard layers model, but with a couple of -additional steps. - -A normal standard layers model defines parameters, which are grouped into layers, and then these are arranged into contrasts. For sample containing domains, the -layers are first grouped into domain 'contrasts', which are just groupings of layers with none of the additional parameters of a contrast (such as resolutions -etc). Then, the actual experimental contrasts are built in the usual way, but with the model set as any two of the domains. - -.. image:: ../images/domainsGraph.png - :align: center - :alt: Domains graph - -To control the ratio between the domains, we can add domain ratios as described in :ref:`domainsStanlay`. And each contrast has an additional field -for domain ratios which is set as one of the values from this block. - -This example can be run as a script or interactively using the instructions below. - -.. tab-set:: - :sync-group: code - - .. tab-item:: Matlab - :sync: Matlab - - **Run Script**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'standardLayers')); - domainsStandardLayersScript - - **Run Interactively**: - - .. code-block:: Matlab - - root = getappdata(0, 'root'); - cd(fullfile(root, 'examples', 'domains', 'standardLayers')); - edit domainsStandardLayersSheet.mlx - - - .. tab-item:: Python - :sync: Python - - **Run Script**: - - .. code-block:: console - - python RATapi.examples.domains.domains_standard_layers.py - - **Run as Function**: - - .. code-block:: Python - - import RATapi as RAT - problem, results = RAT.examples.domains.domains_standard_layers() - - **Run Interactively**: - - .. code-block:: console - - jupyter notebook RATapi.examples.domains.domains_standard_layers.ipynb diff --git a/source/guide.rst b/source/guide.rst index 3c7c607c..502c74e5 100644 --- a/source/guide.rst +++ b/source/guide.rst @@ -8,7 +8,8 @@ User Guide :maxdepth: 2 tutorial/index - examples/index + matlab_examples/index + python_examples/index algorithms/index advanced/index calcTypes/index diff --git a/source/index.rst b/source/index.rst index 0b05b0f4..fc8000fa 100644 --- a/source/index.rst +++ b/source/index.rst @@ -45,7 +45,9 @@ RAT contains a number of improvements over legacy RasCAL, including: * :ref:`guide`: Learn the core principles of RAT with code snippets. - * :ref:`examples`: Jump into some practical examples. + * :ref:`matlabExamples`: Jump into some practical examples for the MATLAB interface. + + * :ref:`pythonExamples`: Explore some practical examples for the Python interface. .. grid-item-card:: @@ -77,6 +79,5 @@ RAT contains a number of improvements over legacy RasCAL, including: install guide - reference/matlab/index - reference/python/index - + examples + reference/index diff --git a/source/matlab_examples.pdf b/source/matlab_examples.pdf new file mode 100644 index 0000000000000000000000000000000000000000..086835e9f9ae59c142ee4839e263afbea4c65a10 GIT binary patch literal 45874 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 YA(F^MtOE!khd|1JfH#(nw3tBu1u~}c)&Kwi literal 0 HcmV?d00001 diff --git a/source/matlab_examples/DSPC_custom_XY.rst b/source/matlab_examples/DSPC_custom_XY.rst new file mode 100644 index 00000000..21fab247 --- /dev/null +++ b/source/matlab_examples/DSPC_custom_XY.rst @@ -0,0 +1,49 @@ +============== +DSPC Custom XY +============== + +This shows an example of using a :ref:`custom XY` model to analyse reflectivity from a supported bilayer of DSPC. + +Similar to :ref:`DSPC_Custom_Layers`, we can make use of the fact that the volumes, and of course the atomistic composition are known. So, +for lipid tails for example, then we can take a literature value for the tails volume, have a fittable parameter for the lipid area per molecule, and then the tail thickness will simply be + +.. math:: \text{Tail Thick} = \frac{\text{Tail Volume}}{\text{Lipid APM}}. + +Since the volume is known, then the SLD of the tails is also obviously easily calculable. + +In this model, we make distributions to represent the volume fractions of each of the components in the sample, the convert these to SLD's, as described in :ref:`[1] `. + +We also make our volume fractions as optional outputted parameters from our file. The optional nature of this output means we can suppress it to run the model, then +activate it to make final output plots of our analysis. + +.. image:: ../images/examples/volumeFractions.png + :align: center + :alt: Volume fractions + +This example can be run as a script or interactively using the instructions below. + + +.. note:: The custom model used is a MATLAB model - **examples/normalReflectivity/customXY/customXYDSPC.m**. + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'customXY')); + customXYDSPCScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'customXY')); + edit customXYDSPCSheet.mlx + +.. _ref_1: + +[1] Shekhar et al, J. Appl. Phys, 100, 102216 (2011) [`DOI 10.1063/1.3661986 `_] + +.. raw:: html + :file: customXYDSPCSheet.html diff --git a/source/matlab_examples/DSPC_custom_layers.rst b/source/matlab_examples/DSPC_custom_layers.rst new file mode 100644 index 00000000..b72f0320 --- /dev/null +++ b/source/matlab_examples/DSPC_custom_layers.rst @@ -0,0 +1,41 @@ +.. _DSPC_Custom_Layers: + +================== +DSPC Custom Layers +================== + +This shows an example of using a :ref:`custom layers` model to analyse reflectivity from a supported bilayer of DSPC. + +In this example, we can make use of the fact that the volumes, and of course the atomistic composition are known. So, for lipid tails for example, then we can +take a literature value for the tails volume, have a fittable parameter for the lipid area per molecule, and then the tail thickness will simply be + +.. math:: Tail Thick = Tail Volume / Lipid APM. + +Since the volume is known, then the SLD of the tails is also obviously easily calculable. + +In addition, the datasets for this example, have a resolution (per point) in their fourth column. We use this resolution in our analysis, rather than declaring a constant, fittable one. + +This example can be run as a script or interactively using the instructions below. + + +.. note:: The custom model used is a MATLAB model - **examples/normalReflectivity/customLayers/customBilayerDSPC.m**. + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'customLayers')); + customLayersDSPCScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'customLayers')); + edit customLayersDSPCSheet.mlx + + +.. raw:: html + :file: customLayersDSPCSheet.html diff --git a/source/matlab_examples/DSPC_standard_layers.rst b/source/matlab_examples/DSPC_standard_layers.rst new file mode 100644 index 00000000..c4568c74 --- /dev/null +++ b/source/matlab_examples/DSPC_standard_layers.rst @@ -0,0 +1,30 @@ +.. _DSPC_Standard_Layers: + +==================== +DSPC Standard Layers +==================== +This shows an example of using a :ref:`standard layers` model to analyse reflectivity from a floating bilayer of DSPC. + +The model is set up in the script, we set Gaussian priors on some of the parameters, build the two contrasts, run the calculation and plot the results. + +This example can be run as a script or interactively using the instructions below. + + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'standardLayers')); + standardLayersDSPCScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'normalReflectivity', 'standardLayers')); + edit standardLayersDSPCSheet.mlx + +.. raw:: html + :file: standardLayersDSPCSheet.html diff --git a/source/matlab_examples/convert_r1_project.rst b/source/matlab_examples/convert_r1_project.rst new file mode 100644 index 00000000..32ef7d4f --- /dev/null +++ b/source/matlab_examples/convert_r1_project.rst @@ -0,0 +1,23 @@ +============================= +Converting a RasCAL-1 Project +============================= + +If you have projects from RasCAL1, there is a simple utility supplied with the toolbox that makes converting between formats easy as explained in :ref:`conversionFuncs`. + +This example shows the conversion of a RasCAL-1 custom layers project into a RAT project and vice versa, because this is a custom layers project, the custom model +function **Model_IIb.m** which in the example directory is required to run the converted RAT project successfully. + +This example can be run using the instructions below. + +.. note:: The custom model used is a MATLAB model - **examples/miscellaneous/convertRascal1Project/Model_IIb.m**. + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'miscellaneous', 'convertRascal1Project')); + edit convertRascal.mlx + +.. raw:: html + :file: convertRascal.html diff --git a/source/matlab_examples/custom_model_languages.rst b/source/matlab_examples/custom_model_languages.rst new file mode 100644 index 00000000..e4a06985 --- /dev/null +++ b/source/matlab_examples/custom_model_languages.rst @@ -0,0 +1,36 @@ +================================== +Alternative Custom Model Languages +================================== + +In this example, we setup a :ref:`custom layers` problem using three different programming language (MATLAB, Python, and C++) to write the custom model function. +The provided C++ function needs to be compiled into a dynamic library using instructions given in :ref:`customLanguages` or instructions specific to your compiler. + + +This example can be run using the instructions below. + + +.. note:: The custom models used are - + **examples/miscellaneous/languages/alloyDomains.m**, + **examples/miscellaneous/languages/alloyDomains.m**, + **examples/miscellaneous/languages/alloyDomains.m**. + +.. warning:: For Python custom functions, you will need to setup the python environment for MATLAB, see `Setup MATLAB to use Python `_ + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'miscellaneous', 'alternativeLanguages')); + customModelLanguagesScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'miscellaneous', 'alternativeLanguages')); + edit customModelLanguagesSheet.mlx + +.. raw:: html + :file: customModelLanguagesSheet.html diff --git a/source/matlab_examples/domains_custom_XY.rst b/source/matlab_examples/domains_custom_XY.rst new file mode 100644 index 00000000..bf6080fb --- /dev/null +++ b/source/matlab_examples/domains_custom_XY.rst @@ -0,0 +1,33 @@ +================================= +Incoherent Summing with Custom XY +================================= + +This is an example of using incoherent summing ('domains') from custom XY models. + +The domain custom XY model is similar to a normal custom models, except that the input (function arguments) of the custom function contains an additional 'domains' parameter as described in :ref:`domainsCustomModels`. + +This parameter tells the function which is the current domain, so the appropriate layer stack can be generated. + +This example can be run as a script or interactively using the instructions below. + + +.. note:: The custom model used is a MATLAB model - **examples/domains/customXY/domainsXY.m**. + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'customXY')); + domainsCustomXYScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'customXY')); + edit domainsCustomXYSheet.mlx + +.. raw:: html + :file: domainsCustomXYSheet.html diff --git a/source/matlab_examples/domains_custom_layers.rst b/source/matlab_examples/domains_custom_layers.rst new file mode 100644 index 00000000..b23d161e --- /dev/null +++ b/source/matlab_examples/domains_custom_layers.rst @@ -0,0 +1,33 @@ +===================================== +Incoherent Summing with Custom Layers +===================================== + +This is an example of using incoherent summing ('domains') from custom layers models. The sample is a simple two layer of permalloy/gold, with up/down domains + +The domain custom model is similar to a normal custom models, except that the input (function arguments) of the custom function contains an additional 'domains' parameter as described in :ref:`domainsCustomModels`. + +This parameter tells the function which is the current domain, so the appropriate layer stack can be generated. + +This example can be run as a script or interactively using the instructions below. + + +.. note:: The custom model used is a MATLAB model - **examples/domains/customLayers/alloyDomains.m**. + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'customLayers')); + domainsCustomLayersScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'customLayers')); + edit domainsCustomLayersSheet.mlx + +.. raw:: html + :file: domainsCustomLayersSheet.html diff --git a/source/matlab_examples/domains_standard_layers.rst b/source/matlab_examples/domains_standard_layers.rst new file mode 100644 index 00000000..435b88bc --- /dev/null +++ b/source/matlab_examples/domains_standard_layers.rst @@ -0,0 +1,39 @@ +======================================= +Incoherent Summing with Standard Layers +======================================= + +Analysing data containing domains using standard layers models is done in a similar way to a normal standard layers model, but with a couple of +additional steps. + +A normal standard layers model defines parameters, which are grouped into layers, and then these are arranged into contrasts. For sample containing domains, the +layers are first grouped into domain 'contrasts', which are just groupings of layers with none of the additional parameters of a contrast (such as resolutions +etc). Then, the actual experimental contrasts are built in the usual way, but with the model set as any two of the domains. + +.. image:: ../images/domainsGraph.png + :align: center + :alt: Domains graph + +To control the ratio between the domains, we can add domain ratios as described in :ref:`domainsStanlay`. And each contrast has an additional field +for domain ratios which is set as one of the values from this block. + +This example can be run as a script or interactively using the instructions below. + +**Run Script**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'standardLayers')); + domainsStandardLayersScript + +**Run Interactively**: + +.. code-block:: Matlab + + root = getappdata(0, 'root'); + cd(fullfile(root, 'examples', 'domains', 'standardLayers')); + edit domainsStandardLayersSheet.mlx + + +.. raw:: html + :file: domainsStandardLayersSheet.html diff --git a/source/examples/imaginary.rst b/source/matlab_examples/imaginary.rst similarity index 100% rename from source/examples/imaginary.rst rename to source/matlab_examples/imaginary.rst diff --git a/source/examples/index.rst b/source/matlab_examples/index.rst similarity index 82% rename from source/examples/index.rst rename to source/matlab_examples/index.rst index 339f8b56..c8612d7e 100644 --- a/source/examples/index.rst +++ b/source/matlab_examples/index.rst @@ -1,9 +1,9 @@ -.. _examples: +.. _matlabExamples: -======== -Examples -======== -A number of examples are provided to demonstrate the functionality available in the MATLAB and Python interface of RAT. +=============== +MATLAB Examples +=============== +A number of examples are provided to demonstrate the functionality available in the MATLAB interface of RAT. ****************** Normal Calculation diff --git a/source/python_examples/index.rst b/source/python_examples/index.rst new file mode 100644 index 00000000..b0342dcc --- /dev/null +++ b/source/python_examples/index.rst @@ -0,0 +1,37 @@ +.. _pythonExamples: + +=============== +Python Examples +=============== +A number of examples are provided to demonstrate the functionality available in the Python interface of RAT. + +****************** +Normal Calculation +****************** + +.. toctree:: + :maxdepth: 1 + + notebooks/DSPC_standard_layers + notebooks/DSPC_custom_layers + notebooks/DSPC_custom_xy + +****************** +Domain Calculation +****************** + +.. toctree:: + :maxdepth: 1 + + notebooks/domains_standard_layers + notebooks/domains_custom_layers + notebooks/domains_custom_XY + +************* +Miscellaneous +************* + +.. toctree:: + :maxdepth: 1 + + notebooks/absorption diff --git a/source/python_examples/notebooks/README.md b/source/python_examples/notebooks/README.md new file mode 100644 index 00000000..9048a0c5 --- /dev/null +++ b/source/python_examples/notebooks/README.md @@ -0,0 +1,5 @@ +## Notebooks folder + +This folder contains the notebooks so they can be built by Sphinx. + +It is populated with notebooks by `sphinx build` (see `conf.py`) diff --git a/source/reference/index.rst b/source/reference/index.rst new file mode 100644 index 00000000..383aeae5 --- /dev/null +++ b/source/reference/index.rst @@ -0,0 +1,24 @@ +API Reference +============= + +This section of the documentation contains API reference information for the +Python and MATLAB versions of RAT. + +MATLAB Reference +---------------- + +.. toctree:: + :maxdepth: 3 + + matlab/index + + +Python Reference +---------------- + +.. toctree:: + :maxdepth: 3 + + python/index + +