{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2025-04-03T12:16:07.011990Z", "iopub.status.busy": "2025-04-03T12:16:07.011808Z", "iopub.status.idle": "2025-04-03T12:16:09.006578Z", "shell.execute_reply": "2025-04-03T12:16:09.005855Z" } }, "outputs": [], "source": [ "import pathlib\n", "from IPython.display import Code\n", "\n", "import RATapi as RAT\n", "from RATapi.models import Parameter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Simple example of a layer containing domains using a custom XY model\n", "\n", "Domains custom XY models operate in the same way as domains custom layer models, in that there is an additional input to the custom model specifying the domain to be calculated:\n", "\n", "This is then used within the function to calculate the correct SLD profile for each contrast and domain. In this example, we simulate a hydrogenated layer on a silicon substrate, containing domains of a larger SLD, against D2O, SMW and water.\n", "\n", "Start by making the project and adding the parameters:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2025-04-03T12:16:09.010565Z", "iopub.status.busy": "2025-04-03T12:16:09.010228Z", "iopub.status.idle": "2025-04-03T12:16:09.018629Z", "shell.execute_reply": "2025-04-03T12:16:09.017968Z" } }, "outputs": [], "source": [ "problem = RAT.Project(calculation=\"domains\", model=\"custom xy\", geometry=\"substrate/liquid\")\n", "\n", "parameter_list = [\n", " Parameter(name=\"Oxide Thickness\", min=10.0, value=20.0, max=50.0, fit=True),\n", " Parameter(name=\"Layer Thickness\", min=1.0, value=30.0, max=500.0, fit=True),\n", " Parameter(name=\"Layer SLD\", min=-0.5e-6, value=-0.5e-6, max=0.0, fit=True),\n", " Parameter(name=\"Layer Roughness\", min=2.0, value=5.0, max=7.0, fit=True),\n", " Parameter(name=\"Domain SLD\", min=1.0e-6, value=1.0e-6, max=5.0e-6, fit=True)\n", "]\n", "\n", "problem.parameters.extend(parameter_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now set the SLDs of the bulk phases for our samples." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2025-04-03T12:16:09.020843Z", "iopub.status.busy": "2025-04-03T12:16:09.020644Z", "iopub.status.idle": "2025-04-03T12:16:09.026941Z", "shell.execute_reply": "2025-04-03T12:16:09.026314Z" } }, "outputs": [], "source": [ "problem.bulk_in.set_fields(0, name=\"Silicon\", value=2.073e-6, max=1.0, fit=False)\n", "\n", "problem.bulk_out.append(name=\"SLD SMW\", min=2.0e-6, value=2.073e-6, max=2.1e-6)\n", "problem.bulk_out.append(name=\"SLD H2O\", min=-0.6e-6, value=-0.56e-6, max=-0.5e-6)\n", "\n", "problem.scalefactors.set_fields(0, min=0.8, value=1.0, max=1.1, fit=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The custom file takes the parameters and build the model as usual, changing the SLD of the layer depending on whether we are calculating the layer (domain = 0), or the domain (domain = 1)." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2025-04-03T12:16:09.029109Z", "iopub.status.busy": "2025-04-03T12:16:09.028902Z", "iopub.status.idle": "2025-04-03T12:16:09.220946Z", "shell.execute_reply": "2025-04-03T12:16:09.220221Z" } }, "outputs": [ { "data": { "text/html": [ "
import math\n",
"\n",
"import numpy as np\n",
"\n",
"\n",
"def domains_XY_model(params, bulk_in, bulk_out, contrast, domain):\n",
" # Split up the parameters for convenience\n",
" subRough = params[0]\n",
" oxideThick = params[1]\n",
" layerThick = params[2]\n",
" layerSLD = params[3]\n",
" layerRough = params[4]\n",
" domainSLD = params[5]\n",
"\n",
" # Make an array of z values for our model\n",
" z = np.arange(0, 141)\n",
"\n",
" # Make the volume fraction distribution for our Silicon substrate\n",
" [vfSilicon, siSurf] = makeLayer(z, -25, 50, 1, subRough, subRough)\n",
"\n",
" # ... and the Oxide ...\n",
" [vfOxide, oxSurface] = makeLayer(z, siSurf, oxideThick, 1, subRough, subRough)\n",
"\n",
" # ... and also our layer.\n",
" [vfLayer, laySurface] = makeLayer(z, oxSurface, layerThick, 1, subRough, layerRough)\n",
"\n",
" # Everything that is not already occupied will be filled will water\n",
" totalVF = vfSilicon + vfOxide + vfLayer\n",
" vfWater = 1 - totalVF\n",
"\n",
" # Now convert the Volume Fractions to SLDs\n",
" siSLD = vfSilicon * bulk_in\n",
" oxSLD = vfOxide * 3.41e-6\n",
"\n",
" # Layer SLD depends on whether we are calculating the domain or not\n",
" if domain == 0:\n",
" laySLD = vfLayer * layerSLD\n",
" else:\n",
" laySLD = vfLayer * domainSLD\n",
"\n",
" # ... and finally the water SLD.\n",
" waterSLD = vfWater * bulk_out[contrast]\n",
"\n",
" # Make the total SLD by just adding them all up\n",
" totalSLD = siSLD + oxSLD + laySLD + waterSLD\n",
"\n",
" # The output is just a [n x 2] array of z against SLD\n",
" SLD = np.column_stack([z, totalSLD])\n",
"\n",
" return SLD, subRough\n",
"\n",
"\n",
"def makeLayer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R):\n",
" """This produces a layer, with a defined thickness, height and roughness.\n",
" Each side of the layer has its own roughness value.\n",
" """\n",
" # Find the edges\n",
" left = prevLaySurf\n",
" right = prevLaySurf + thickness\n",
"\n",
" # Make our heaviside\n",
" a = (z - left) / ((2**0.5) * Sigma_L)\n",
" b = (z - right) / ((2**0.5) * Sigma_R)\n",
"\n",
" erf_a = np.array([math.erf(value) for value in a])\n",
" erf_b = np.array([math.erf(value) for value in b])\n",
"\n",
" VF = np.array((height / 2) * (erf_a - erf_b))\n",
"\n",
" return VF, right\n",
"