Investigation of a surfactant monolayer#

A common system that is studied with neutron and X-ray reflectometry are surfactant monolayers. In this tutorial, we will look at how the EasyReflectometry assembly SurfactantLayer (detailed here) can be used to model a phospholipid bilayer. First, we will import the relevant packages and functions.

First configure matplotlib to place figures in notebook and import needed modules

[1]:
%matplotlib inline

import refnx

import EasyReflectometry
from EasyReflectometry.calculators import CalculatorFactory
from EasyReflectometry.data import load
from EasyReflectometry.plot import plot
from EasyReflectometry.sample import Material
from EasyReflectometry.sample import SurfactantLayer
from EasyReflectometry.sample import Layer
from EasyReflectometry.sample import Sample
from EasyReflectometry.experiment.model import Model
from EasyReflectometry.fitting import Fitter
from EasyReflectometry.plot import plot


Next, as usual we print the versions of the software packages.

[2]:
print(f'EasyReflectometry: {EasyReflectometry.__version__}')
print(f'refnx: {refnx.__version__}')
EasyReflectometry: 0.0.0
refnx: 0.1.43

Reading in experimental data#

As has been shown previously, we use the load function to read in our experimental data. For this tutorial we will be looking at DSPC, a phospholipid molecule that will self-assemble into a monolayer at the air-water interface. The data being used has kindly been shared by the authors of previous work on the system.

[3]:
data = load('_static/d70d2o.ort')
plot(data)
../_images/tutorials_monolayer_6_0.png

Building the model#

The study of surfactant monolayers is very popular in the literature, including the models based on functional descriptions, slab models, and molecular dynamics simulations. In EasyReflectometry, we use a slab model description taht has become particularly commonplace. A graphical representation of the slab model for a phosphoplipid monolayer is shown below.

A slab model description for a phospholipid monolayer.

A slab model description for a phospholipid monolayer, showing the head and tail layers.

The slab model for a phospholipid monolayer involves describing the system as consisting of two components, that for the hydrophilic head group layer and that for the hydrophobic tail group layer. Each of these layers have some thickness that can be estimated by considering the size of the head and tail groups. The scattering length density (\rho) for the layers is then defined based on the layer thickness (d), the scattering length for the lipid head or tail molecule (b), the surface number density of the monolayer (defined by the area per molecule, \mathrm{APM}) and the presence of solvent in the head or tail molecules (\phi solvation), where the solvent has a known scattering length density (\rho_{\mathrm{solvent}}), \n”,

\rho = \frac{b}{d\mathrm{APM}}(1-\phi) + \rho_{\mathrm{solvent}}\phi.

This approach has two benefits: 1. By constraining the area per molecule of the head and tail groups to be the same, the analysis can ensure that the number density of the two components is equal (i.e. for every head group there is a tail group), as would be expected given the chemical bonding. 2. The area per molecule is a parameter that can be measured using complementary methods, such as surface-pressure isotherm, to help define the value.

Finally, we can constrain the roughness between head-tail and tail-superphase layers to be the same value, as it is unlikely that it would be different.

Before we create the SurfactantLayer object, we will create simple Material objects for the sub- and super-phase.

[4]:
d2o = Material.from_pars(6.36, 0, 'D2O')
air = Material.from_pars(0, 0, 'Air')

Building the surfactant monolayer#

Now we can create the SurfactantLayer object, this takes a large number of parameters, that we will introduce gradually.

The chemical structure for the DSPC molecule.

The chemical structure for the DSPC molecule. By Graeme Bartlett - Self Drawn, CC0

The chemical structure for the DSPC molecule is shown above, where the head group is everything to the right of (and including) the ester group as this is the hydrophilic component. While, everything to the left hand side is the tail group (both chains are included). We want to define the chemical formula for each of these subunits.

[5]:
head_formula = 'C10H18NO8P'
tail_formula = 'C34D70'

Next we define estimates for the thickness of each layer, for this we will use values from a previous work, as we will not be varying these parameters.

[6]:
head_thickness = 12.9
tail_thickness = 17.6

We expect the head layer to be solvated with some of the D2O present, however it is unlikely that there will be any solvent surface coverage (by D2O or air) in the tighly packed tails.

[7]:
head_solvent_fraction = 0.5
tail_solvent_fraction = 0.0

Finally, we define the values for the area per molecule and roughness for the whole surfactant layer.

[8]:
area_per_molecule = 45
roughness = 3

Having created the necessary initial values, we can use these to create a SurfactantLayer object. Note that the area per molecule and roughness for both layers are the same. We can also print information about our surfactant system.

[9]:
dspc = SurfactantLayer.from_pars(
    tail_layer_molecular_formula=tail_formula,
    tail_layer_thickness=tail_thickness,
    tail_layer_solvent=air,
    tail_layer_solvent_fraction=tail_solvent_fraction,
    tail_layer_area_per_molecule=area_per_molecule,
    tail_layer_roughness=roughness,
    head_layer_molecular_formula=head_formula,
    head_layer_thickness=head_thickness,
    head_layer_solvent=d2o,
    head_layer_solvent_fraction=head_solvent_fraction,
    head_layer_area_per_molecule=area_per_molecule,
    head_layer_roughness=roughness
)
dspc.constrain_area_per_molecule = True
dspc.conformal_roughness = True
dspc
[9]:
head_layer:
  EasySurfactantLayer Head Layer:
    material:
      C10H18NO8P in D2O:
        solvent_fraction: 0.5
        sld: 3.697e-6 1 / angstrom ** 2
        isld: 0.000e-6 1 / angstrom ** 2
        material:
          C10H18NO8P:
            sld: 1.035e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
        solvent:
          D2O:
            sld: 6.360e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
    thickness: 12.900 angstrom
    roughness: 3.000 angstrom
  molecular_formula: C10H18NO8P
  area_per_molecule: 45.00 angstrom ** 2
tail_layer:
  EasySurfactantLayer Tail Layer:
    material:
      C34D70 in Air:
        solvent_fraction: 0.0
        sld: 8.753e-6 1 / angstrom ** 2
        isld: 0.000e-6 1 / angstrom ** 2
        material:
          C34D70:
            sld: 8.753e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
        solvent:
          Air:
            sld: 0.000e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
    thickness: 17.600 angstrom
    roughness: 3.000 angstrom
  molecular_formula: C34D70
  area_per_molecule: 45.00 angstrom ** 2
area per molecule constrained: true
conformal roughness: true

The layers for the sub- and super-phase are then created.

[10]:
d2o_layer = Layer.from_pars(d2o, 0, 3, 'D2O Subphase')
air_layer = Layer.from_pars(air, 0, 0, 'Air Superphase')

For the surfactant layer, the roughness is typically defined by the roughness between the water-head layers. Therefore, it is desirable to add this constraint to our model.

[11]:
dspc.constrain_solvent_roughness(d2o_layer.roughness)

Now that the surfactant layer and sub- and super-phases are available and the necessary constraints present, we construct our Sample and Model objects.

[12]:
sample = Sample.from_pars(air_layer, dspc, d2o_layer)
model = Model.from_pars(sample, 1, data['data']['R_0'].values.min(), 5)

For the model we set the background initially as the minimum value observed in the experimental data.

Defining bounds and performing the optimisation#

The varying parameters can then be defined, in this case we will let the scale factor, the background, the surfactant area per molecule, and head layer solvent surface coverage vary with the bounds shown below.

[13]:
model.scale.bounds = (0.05, 1.5)
model.background.bounds = (4e-7, 1e-6)

dspc.tail_layer.area_per_molecule.bounds = (30, 60)
dspc.head_layer.solvent_fraction.bounds = (0.4, 0.7)

Finally, as with other tutorials, we create the CalculatorFactory (and connect this to our model) and Fitter objects and perform the fit.

[14]:
calculator = CalculatorFactory()
model.interface = calculator
fitter = Fitter(model)
analysed = fitter.fit(data, method='differential_evolution')

The result can then be plotted, before we investigate the results.

[15]:
plot(analysed)
../_images/tutorials_monolayer_30_0.png
[16]:
model
[16]:
EasyModel:
  scale: 0.14026181781909397
  background: 8.871220729512246e-07
  resolution: 5.0 %
  sample:
    EasyStructure:
    - Air Superphase:
        material:
          Air:
            sld: 0.000e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
        thickness: 0.000 angstrom
        roughness: 0.000 angstrom
    - head_layer:
        EasySurfactantLayer Head Layer:
          material:
            C10H18NO8P in D2O:
              solvent_fraction: 0.631168085674412
              sld: 4.306e-6 1 / angstrom ** 2
              isld: 0.000e-6 1 / angstrom ** 2
              material:
                C10H18NO8P:
                  sld: 0.792e-6 1 / angstrom ** 2
                  isld: 0.000e-6 1 / angstrom ** 2
              solvent:
                D2O:
                  sld: 6.360e-6 1 / angstrom ** 2
                  isld: 0.000e-6 1 / angstrom ** 2
          thickness: 12.900 angstrom
          roughness: 3.000 angstrom
        molecular_formula: C10H18NO8P
        area_per_molecule: 58.81 angstrom ** 2
      tail_layer:
        EasySurfactantLayer Tail Layer:
          material:
            C34D70 in Air:
              solvent_fraction: 0.0
              sld: 8.753e-6 1 / angstrom ** 2
              isld: 0.000e-6 1 / angstrom ** 2
              material:
                C34D70:
                  sld: 8.753e-6 1 / angstrom ** 2
                  isld: 0.000e-6 1 / angstrom ** 2
              solvent:
                Air:
                  sld: 0.000e-6 1 / angstrom ** 2
                  isld: 0.000e-6 1 / angstrom ** 2
          thickness: 17.600 angstrom
          roughness: 3.000 angstrom
        molecular_formula: C34D70
        area_per_molecule: 58.81 angstrom ** 2
      area per molecule constrained: true
      conformal roughness: true
    - D2O Subphase:
        material:
          D2O:
            sld: 6.360e-6 1 / angstrom ** 2
            isld: 0.000e-6 1 / angstrom ** 2
        thickness: 0.000 angstrom
        roughness: 3.000 angstrom

We can see above that the solvent surface coverage of the surfactant was found to be around 60 % and the area per molecule around 50 Å2, in agreement with previous investigations.

References#

Hollinshead, C. M., Harvey, R. D., Barlow, D. J., Webster, J. R. P., Hughes, A. V., Weston, A., Lawrence, M. J., 2009, Effects of Surface Pressure on the Structure of Distearoylphosphatidylcholine Monolayers Formed at the Air/Water Interface, Langmuir, 25, 4070-4077

Campbell, R. A., Saaka, Y., Shao, Y., Gerelli, Y., Cubitt, R., Nazaruk, E., Matyszewska, D. Lawrence, M. J., 2018, Structure of surfactant and phospholipid monolayers at the air/water interface modeled from neutron reflectivity data, Journal of Colloid and Interface Science, 531, 98-108

McCluskey, A. R., Grant, J., Smith, A. J., Rawle, J. L., Barlow, D. J., Lawrence, M. J., Parker, S. C., Edler, K. J., 2019, Assessing molecular simulation for the analysis of lipid monolayer reflectometry, Journal of Physics Communications, 3, 075001

McCluskey, A. R., Cooper, J. F. K., Arnold, T., Snow, T., 2020, A general approach to maximise information density in neutron reflectometry analysis, Machine Learning: Science and Technology, 1, 035002