Skip to content
Snippets Groups Projects
Commit 0e497c78 authored by Wuttke, Joachim's avatar Wuttke, Joachim
Browse files

[doc1] Use std_samples and std_simulations in Examples and web doc ()

Merging branch 'doc1'  into 'main'.

See merge request !728
parents 8b37f2f2 99473ea6
No related branches found
No related tags found
1 merge request!728Use std_samples and std_simulations in Examples and web doc
Pipeline #59117 passed
Showing
with 280 additions and 222 deletions
......@@ -3,41 +3,14 @@
Basic example of specular reflectometry simulation with BornAgain.
The sample consists of 20 alternating Ti and Ni layers.
"""
import bornagain as ba
from bornagain import deg, angstrom
def get_sample():
# Define materials
m_ambient = ba.MaterialBySLD("Vacuum", 0, 0)
m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)
# Define layers
ambient_layer = ba.Layer(m_ambient)
ti_layer = ba.Layer(m_ti, 30*angstrom)
ni_layer = ba.Layer(m_ni, 70*angstrom)
substrate_layer = ba.Layer(m_substrate)
# Define sample
sample = ba.MultiLayer()
sample.addLayer(ambient_layer)
for _ in range(10):
sample.addLayer(ti_layer)
sample.addLayer(ni_layer)
sample.addLayer(substrate_layer)
return sample
from bornagain import std_samples
return std_samples.alternating_layers()
def get_simulation(sample, scan_size=500):
simulation = ba.SpecularSimulation()
scan = ba.AlphaScan(1.54*angstrom, scan_size, 0, 2*deg)
simulation.setScan(scan)
simulation.setSample(sample)
return simulation
from bornagain import std_simulations
return std_simulations.specular(sample, scan_size)
if __name__ == '__main__':
from bornagain import ba_plot
......
#!/usr/bin/env python3
"""
Basic example of specular reflectometry simulation with BornAgain.
The sample consists of 20 alternating Ti and Ni layers.
Explicit variant without using std_samples and std_simulation.
"""
import bornagain as ba
from bornagain import deg, angstrom
def get_sample():
"""
Sample consisting of 20 alternating Ti and Ni layers.
"""
# Define materials
m_ambient = ba.MaterialBySLD("Vacuum", 0, 0)
m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)
# Define layers
ambient_layer = ba.Layer(m_ambient)
ti_layer = ba.Layer(m_ti, 30*angstrom)
ni_layer = ba.Layer(m_ni, 70*angstrom)
substrate_layer = ba.Layer(m_substrate)
# Define sample
sample = ba.MultiLayer()
sample.addLayer(ambient_layer)
for _ in range(10):
sample.addLayer(ti_layer)
sample.addLayer(ni_layer)
sample.addLayer(substrate_layer)
return sample
def get_simulation(sample, scan_size=500):
"""
A standard specular simulation setup.
"""
simulation = ba.SpecularSimulation()
scan = ba.AlphaScan(1.54*angstrom, scan_size, 0, 2*deg)
simulation.setScan(scan)
simulation.setSample(sample)
return simulation
if __name__ == '__main__':
from bornagain import ba_plot
sample = get_sample()
simulation = get_simulation(sample)
ba_plot.run_and_plot(simulation)
#!/usr/bin/env python3
"""
Basic example of specular reflectometry simulation with BornAgain.
The sample consists of 20 alternating Ti and Ni layers.
Variant with explicit function get_simulation.
"""
import bornagain as ba
from bornagain import deg, angstrom
def get_sample():
from bornagain import std_samples
return std_samples.alternating_layers()
def get_simulation(sample, scan_size=500):
"""
A standard specular simulation setup.
"""
simulation = ba.SpecularSimulation()
scan = ba.AlphaScan(1.54*angstrom, scan_size, 0, 2*deg)
simulation.setScan(scan)
simulation.setSample(sample)
return simulation
if __name__ == '__main__':
from bornagain import ba_plot
sample = get_sample()
simulation = get_simulation(sample)
ba_plot.run_and_plot(simulation)
......@@ -16,31 +16,8 @@ from bornagain import angstrom
def get_sample():
"""
Defines sample and returns it. Note that SLD-based materials are used.
"""
# creating materials
m_ambient = ba.MaterialBySLD("Ambient", 0, 0)
m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)
# creating layers
ambient_layer = ba.Layer(m_ambient)
ti_layer = ba.Layer(m_ti, 30*angstrom)
ni_layer = ba.Layer(m_ni, 70*angstrom)
substrate_layer = ba.Layer(m_substrate)
# creating multilayer
multi_layer = ba.MultiLayer()
multi_layer.addLayer(ambient_layer)
for _ in range(10):
multi_layer.addLayer(ti_layer)
multi_layer.addLayer(ni_layer)
multi_layer.addLayer(substrate_layer)
return multi_layer
from bornagain import std_samples
return std_samples.alternating_layers()
def get_simulation(sample, scan_size=500):
......
......@@ -14,31 +14,8 @@ from bornagain import angstrom
def get_sample():
"""
Defines sample and returns it. Note that SLD-based materials are used.
"""
# creating materials
m_ambient = ba.MaterialBySLD("Ambient", 0, 0)
m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)
# creating layers
ambient_layer = ba.Layer(m_ambient)
ti_layer = ba.Layer(m_ti, 30*angstrom)
ni_layer = ba.Layer(m_ni, 70*angstrom)
substrate_layer = ba.Layer(m_substrate)
# creating multilayer
multi_layer = ba.MultiLayer()
multi_layer.addLayer(ambient_layer)
for _ in range(10):
multi_layer.addLayer(ti_layer)
multi_layer.addLayer(ni_layer)
multi_layer.addLayer(substrate_layer)
return multi_layer
from bornagain import std_samples
return std_samples.alternating_layers()
def get_simulation(sample, scan_size=500):
......
......@@ -39,11 +39,12 @@ function(run_noplot example)
${Python3_EXECUTABLE} ${script_path} ${TEST_OUTPUT_DIR_PY_EXAMPLES})
endfunction()
# Python persistence test: run modified example, and compare with reference data.
function(test_example example tolerance)
# Python equality test: run modified example, and compare with reference data of another example
function(test_equality example reference tolerance)
set(script_path ${EXAMPLES_DIR}/${example}.py)
get_filename_component(EXAMPLE_NAME ${script_path} NAME_WE)
get_filename_component(EXAMPLE_DIR ${script_path} DIRECTORY)
get_filename_component(REFERENCE_NAME ${reference} NAME_WE)
set(test_name Example.persist.${EXAMPLE_NAME})
set(PYPERSIST_TOLERANCE ${tolerance})
......@@ -54,6 +55,11 @@ function(test_example example tolerance)
add_test(NAME ${test_name} COMMAND ${Python3_EXECUTABLE} -B ${example_mod})
endfunction()
# Python persistence test: run modified example, and compare with reference data.
function(test_example example tolerance)
test_equality(${example} ${example} ${tolerance})
endfunction()
####################################################################################################
# Persistence tests
####################################################################################################
......@@ -99,7 +105,9 @@ test_example(scatter2d/SpheresAtHexLattice 2e-10)
test_example(scatter2d/TriangularRipple 2e-10)
# test_example(scatter2d/TwoTypesOfCylindersWithSizeDistribution 2e-10)
test_example(specular/AlternatingLayers 2e-10)
test_example(specular/AlternatingLayers 2e-13)
test_equality(specular/AlternatingLayers1 specular/AlternatingLayers 2e-13)
test_equality(specular/AlternatingLayers2 specular/AlternatingLayers 2e-13)
test_example(specular/BeamAngularDivergence 2e-10)
test_example(specular/BeamFullDivergence 2e-10)
test_example(specular/TOFRWithResolution 2e-10)
......
......@@ -14,6 +14,7 @@ import bornagain as ba
REFERENCE_DIR = "@TEST_REFERENCE_DIR_EXAMPLES_MINI@"
EXAMPLE_DIR = "@EXAMPLE_DIR@"
EXAMPLE_NAME = "@EXAMPLE_NAME@"
REFERENCE_NAME = "@REFERENCE_NAME@"
OUTPUT_DIR = "@TEST_OUTPUT_DIR_PY_PERSIST@"
TOLERANCE = @PYPERSIST_TOLERANCE@
......@@ -147,9 +148,9 @@ def process_example():
nfailures = 0
if type(result) is dict:
for dict_key, subresult in result.items():
nfailures += check_result(subresult, EXAMPLE_NAME + "." + str(dict_key))
nfailures += check_result(subresult, REFERENCE_NAME + "." + str(dict_key))
else:
nfailures += check_result(result, EXAMPLE_NAME)
nfailures += check_result(result, REFERENCE_NAME)
return nfailures
......
No preview for this file type
"""
BornAgain collection of standard sample.
"""
import bornagain as ba
from bornagain import deg, angstrom
def alternating_layers():
"""
Consists of 20 alternating Ti and Ni layers.
"""
# Define materials
m_ambient = ba.MaterialBySLD("Vacuum", 0, 0)
m_ti = ba.MaterialBySLD("Ti", -1.9493e-06, 0)
m_ni = ba.MaterialBySLD("Ni", 9.4245e-06, 0)
m_substrate = ba.MaterialBySLD("SiSubstrate", 2.0704e-06, 0)
# Define layers
ambient_layer = ba.Layer(m_ambient)
ti_layer = ba.Layer(m_ti, 30*angstrom)
ni_layer = ba.Layer(m_ni, 70*angstrom)
substrate_layer = ba.Layer(m_substrate)
# Define sample
sample = ba.MultiLayer()
sample.addLayer(ambient_layer)
for _ in range(10):
sample.addLayer(ti_layer)
sample.addLayer(ni_layer)
sample.addLayer(substrate_layer)
return sample
"""
BornAgain collection of standard simulation setups.
"""
import bornagain as ba
from bornagain import deg, angstrom
def specular(sample, scan_size=500):
"""
A standard specular simulation.
"""
simulation = ba.SpecularSimulation()
scan = ba.AlphaScan(1.54*angstrom, scan_size, 0, 2*deg)
simulation.setScan(scan)
simulation.setSample(sample)
return simulation
......@@ -16,8 +16,12 @@ endif()
configure_file(${WRAP_DIR}/Python/__init__.py.in
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/bornagain/__init__.py @ONLY)
foreach(mod ba_plot.py ba_fitmonitor.py)
configure_file(${WRAP_DIR}/Python/${mod} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/bornagain/${mod} COPYONLY)
file(GLOB py_files ${WRAP_DIR}/Python/*.py)
foreach(py_file ${py_files})
get_filename_component(out_file ${py_file} NAME)
configure_file(${py_file}
${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/bornagain/${out_file} COPYONLY)
endforeach()
if(CONFIGURE_BINDINGS)
......
+++
title = "Multilayer"
weight = 35
+++
## TODO: Integrate content from reflectometry tutorial
The ***Define materials*** stance defines four materials in terms
of their scattering length density (SLD).
The arguments of the constructor-like global function
[MaterialBySLD]({{% ref-api "group__materials" %}})
are `name`, `real_sld`, `imag_sld`.
Both `real_sld` and `imag_sld` are in units of inverse square angstroms.
SLD values for a wide variety of materials can be found on https://sld-calculator.appspot.com
and https://www.ncnr.nist.gov/resources/activation.
By convention, `imag_sld` is treated as negative,
which corresponds to attenuation of the signal.
In this example, all imaginary parts are zero.
The ***Define layers*** stance defines four types of layers.
The arguments of the constructor
{{% api-class "Layer" %}}
are `material` and `thickness` in nanometer.
If no thickness is provided, then the layer is semi-infinite.
The ***Define sample*** stance constructs a sample by pilig up the above defined layers
from top (vacuum) to bottom (substrate).
Samples are always of type
{{% api-class "MultiLayer" %}}.
......@@ -21,35 +21,11 @@ To generate this image
run this script:
{{< highlightfile file="Examples/specular/AlternatingLayers.py">}}
{{< highlightfile file="Examples/specular/AlternatingLayers2.py">}}
### Explanation
The ***Define materials*** stance defines four materials in terms
of their scattering length density (SLD).
The arguments of the constructor-like global function
[MaterialBySLD]({{% ref-api "group__materials" %}})
are `name`, `real_sld`, `imag_sld`.
Both `real_sld` and `imag_sld` are in units of inverse square angstroms.
SLD values for a wide variety of materials can be found on https://sld-calculator.appspot.com
and https://www.ncnr.nist.gov/resources/activation.
By convention, `imag_sld` is treated as negative,
which corresponds to attenuation of the signal.
In this example, all imaginary parts are zero.
The ***Define layers*** stance defines four types of layers.
The arguments of the constructor
{{% api-class "Layer" %}}
are `material` and `thickness` in nanometer.
If no thickness is provided, then the layer is semi-infinite.
The ***Define sample*** stance constructs a sample by pilig up the above defined layers
from top (vacuum) to bottom (substrate).
Samples are always of type
{{% api-class "MultiLayer" %}}.
The function ***get_simulation*** constructs a
{{% api-class "SpecularSimulation" %}}.
The constructor
......
+++
title = "Modify the script"
weight = 40
+++
## Expanded simulation script
As a first step towards writing sample and simulation specifications
of your own, let us expand the simulation script
[AlternatingLayers.py]({{% ref-src "Examples/specular/AlternatingLayers.py" %}})
from the preceding pages.
Instead of the shorthand calls to modules
[std_samples]({{% ref-src "Wrap/Python/std_samples.py" %}}) and
[std_simulations]({{% ref-src "Wrap/Python/std_simulations.py" %}}),
we provide explicit code for the functions `get_sample` and `get_simulation`:
{{< highlightfile file="Examples/specular/AlternatingLayers1.py">}}
<p>
### Sample
`get_sample` is a function without arguments.
It returns an object of type [MultiLayer]({{% ref-api "classMultiLayer" %}}).
The return statement is preceded by three stances.
Each stance starts with a comment line,
{{< highlight python >}}
# comment extends from hash character to end of line
{{< /highlight >}}
BornAgain functions that start with a capital letter,
like `MaterialBySLD` or `Layer` are _constructors_ or
constructor-like global functions.
They return new _objects_. An object is an instance of a _class_.
The function `MaterialBySLD` instantiates an object of type
[Material]({{% ref-api "classMaterial" %}})
the function `Layer` an object of type
[Layer]({{% ref-api "classLayer" %}}).
Function like `addLayer` is a member function of class
[MultiLayer]({{% ref-api "classMultiLayer" %}}).
This can be seen from the two lines
{{< highlight python >}}
sample = ba.MultiLayer()
sample.addLayer(ambient_layer)
{{< /highlight >}}
where `sample` is created as a new instance of class `MultiLayer`.
### Simulation
`get_simulation(sample, scan_size=500)` is a function with one
required argument (`sample`) and one optional keyword argument
(`scan_size`). If the function is called with only one argument,
then `scan_size` is assigned the default value 500.
`angstrom` and `deg` are numeric constants. They are used to
convert physical quantities to internal units nanometer and radian.
The function returns an object of type
[SpecularSimulation]({{% ref-api "classSpecularSimulation" %}}).
......@@ -12,35 +12,14 @@ We assume that BornAgain and Python are
and that you verified that the Python interpreter can
[find]({{% ref-py "start/find.md" %}}) the module `bornagain`.
Download the following example script, and save it under the name `AlternatingLayers.py`.
We shall now run a first example script.
This and all other example scripts can also be found in the BornAgain distribution,
in directory `Examples`.
Alternatively, all example scripts can also be found in the BornAgain distribution:
Download the following example script,
using the link just below the code frame.
Save the script under the name `AlternatingLayers.py`.
<!-- Nav tabs -->
<ul class="nav nav-tabs" id="OperationSystemTab" role="tablist">
<li class="nav-item">
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#Windows" role="tab" aria-controls="windows" aria-selected="true">Windows</a>
</li>
<li class="nav-item">
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#MacOS" role="tab" aria-controls="macos" aria-selected="false">MacOS</a>
</li>
<li class="nav-item">
<a class="nav-link" id="messages-tab" data-toggle="tab" href="#Linux" role="tab" aria-controls="linux" aria-selected="false">Linux</a>
</li>
</ul>
<!-- Tab panes -->
<div class="tab-content id="OperationSystemTabContent">
<div class="tab-pane active" id="Windows" role="tabpanel" aria-labelledby="windows-tab">
<p><pre><code>C:\BornAgain-{{< release-string >}}\Examples\python</code></pre></p>
</div>
<div class="tab-pane" id="MacOS" role="tabpanel" aria-labelledby="macos-tab">
<p><pre><code>/Applications/BornAgain.app/Contents/share/BornAgain-{{< release-string-short >}}/Examples/python</code></pre></p>
</div>
<div class="tab-pane" id="Linux" role="tabpanel" aria-labelledby="linux-tab">
<p><pre><code>install_dir/share/BornAgain-{{< release-string-short >}}/Examples/python</code></pre></p>
</div>
</div>
{{< highlightfile file="Examples/specular/AlternatingLayers.py">}}
<p>
......@@ -60,9 +39,9 @@ As result, a MatPlotLib window should pop up, and display this reflectometry cur
{{< figscg src="/files/simulated/AlternatingLayers.png" width="500" class="center">}}
#### Short call (*nix)
#### Short call (Linux, Mac)
Under *nix (Linux, MacOS),
Under a Unix shell,
the script can also be launched without typing `python` at the command prompt:
```bash
AlternatingLayers.py
......
+++
title = "Syntax"
title = "Understand the syntax"
weight = 30
+++
......@@ -14,9 +14,7 @@ For easy reference, here again the full script:
{{< highlightfile file="Examples/specular/AlternatingLayers.py">}}
<p>
We shall now explain the code section by section.
### Front matter
We shall now explain the code.
The [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) line
{{< highlight python >}}
......@@ -34,92 +32,39 @@ Text, text, text
{{< /highlight >}}
are comments.
The line
{{< highlight python >}}
import bornagain as ba
{{< /highlight >}}
imports the Python module `bornagain` (small caps, see chapter on
[how to find]({{% ref-py "start/find.md" %}}) BornAgain),
and assigns it the alias `ba` for brevity.
Classes and functions from the BornAgain API are
now available with the prefix `ba.`.
The line
{{< highlight python >}}
from bornagain import deg, angstrom
{{< /highlight >}}
makes a few frequently used symbols, namely the unit multipliers for
degree and angstrom, available without prefix.
### Sample
`get_sample` is a function without arguments.
It returns an object of type [MultiLayer]({{% ref-api "classMultiLayer" %}}).
The return statement is preceded by three stances.
Each stance starts with a comment line,
The block
{{< highlight python >}}
# comment extends from hash character to end of line
def get_sample():
from bornagain import std_samples
return std_samples.alternating_layers()
{{< /highlight >}}
defines the function `get_sample` that
imports the BornAgain submodule [std_samples]({{% ref-src "Wrap/Python/std_samples.py" %}}),
and returns the alternating layers sample model.
BornAgain functions that start with a capital letter,
like `MaterialBySLD` or `Layer` are _constructors_ or
constructor-like global functions.
They return new _objects_. An object is an instance of a _class_.
The function `MaterialBySLD` instantiates an object of type
[Material]({{% ref-api "classMaterial" %}})
the function `Layer` an object of type
[Layer]({{% ref-api "classLayer" %}}).
Function like `addLayer` is a member function of class
[MultiLayer]({{% ref-api "classMultiLayer" %}}).
This can be seen from the two lines
Similarly, the next block
{{< highlight python >}}
sample = ba.MultiLayer()
sample.addLayer(ambient_layer)
def get_simulation(sample, scan_size=500):
from bornagain import std_simulations
return std_simulations.specular(sample, scan_size)
{{< /highlight >}}
where `sample` is created as a new instance of class `MultiLayer`.
### Simulation
`get_simulation(sample, scan_size=500)` is a function with one
required argument (`sample`) and one optional keyword argument
(`scan_size`). If the function is called with only one argument,
then `scan_size` is assigned the default value 500.
`angstrom` and `deg` are numeric constants. They are used to
convert physical quantities to internal units nanometer and radian.
The function returns an object of type
[SpecularSimulation]({{% ref-api "classSpecularSimulation" %}}).
defines the function `get_simulation` that)
imports the BornAgain submodule [std_simulations]({{% ref-src "Wrap/Python/std_simulations.py" %}}),
and returns a standard setup to simulate a specular reflectivity scan.
### Main program
The line
The clause
{{< highlight python >}}
if __name__ == '__main__':
{{< /highlight >}}
is standard Python idiom.
It ensures that the following is executed if and only if this script
is executed directly, as a _main program_,
but not if this script is included as a submodule in some other code.
The lines
{{< highlight python >}}
sample = get_sample()
simulation = get_simulation(sample)
{{< /highlight >}}
call the two functions defined above
in order to obtain the sample model
and then the full simulation setup, comprising sample and instrument model.
ensures that the following statements are only executed
if the script is called directly, as a "main" program.
This precaution is required by the GUI, where scripts can be imported without
being immediately executed.
Finally, the single line
In the main block, the statement
{{< highlight python >}}
ba_plot.run_and_plot(simulation)
{{< /highlight >}}
runs the simulation and plots the result, using MatPlotLib.
It uses the module
[ba_plot]({{% ref-src "Wrap/Python/ba_plot.py" %}}),
imported a few lines before.
See section [Plot and export]({{% ref-py "result/_index.md" %}})
for other ways of running simulations and plotting or exporting results.
runs the previously defined simulation, and calls MatPlotLib to display the results.
The function `run_and_plot` is implemented in the module
[ba_plot]({{% ref-src "Wrap/Python/ba_plot.py" %}}).
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment