Skip to content

Commit f296ae4

Browse files
committed
ENH: add absolute_phi to LipidLeafletGuest
1 parent e2da5f5 commit f296ae4

File tree

2 files changed

+112
-15
lines changed

2 files changed

+112
-15
lines changed

CHANGELOG.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,3 +700,7 @@ in 0.1.13.
700700

701701
0.1.61
702702
------
703+
- Added absolute_phi keyword to LipidLeafletGuest. This allows one to
704+
parameterise the volume fraction of guest present in a layer in terms
705+
of an absolute volume fraction. This is useful when attempting to constrain
706+
the volume fraction of guest in the head and tail regions to be the same.

refnx/reflect/_lipid.py

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,12 @@ class LipidLeafletGuest(LipidLeaflet):
404404
phi_guest_h: float or refnx.analysis.Parameter
405405
Guest lying in the head layer. This is a fractional
406406
value representing how much of the space **not** taken up by the lipid
407-
is occupied by the guest molecule. The absolute volume fraction is
408-
available from the `LipidLeafletGuest.volfrac_guest` property.
407+
is occupied by the guest molecule.
408+
If, however, `absolute_phi` is set to True, then this parameter
409+
represents the absolute value of the guest molecule in the head region.
410+
The absolute volume fraction is always available from the
411+
`LipidLeafletGuest.volfrac_guest_h` property.
412+
Please see the notes section for further details.
409413
410414
.. warning::
411415
This parameter may not be determinable with low uncertainty if the lipid
@@ -415,8 +419,12 @@ class LipidLeafletGuest(LipidLeaflet):
415419
phi_guest_t: float or refnx.analysis.Parameter
416420
Guest lying in the tail layer. This is a fractional
417421
value representing how much of the space **not** taken up by the lipid
418-
is occupied by the guest molecule. The absolute volume fraction is
419-
available from the `LipidLeafletGuest.volfrac_guest` property.
422+
is occupied by the guest molecule.
423+
If, however, `absolute_phi` is set to True, then this parameter
424+
represents the absolute value of the guest molecule in the tail region.
425+
The absolute volume fraction is always
426+
available from the `LipidLeafletGuest.volfrac_guest_t` property.
427+
Please see the notes section for further details.
420428
421429
.. warning::
422430
This parameter may not be determinable with low uncertainty if the lipid
@@ -444,13 +452,45 @@ class LipidLeafletGuest(LipidLeaflet):
444452
closer to the backing medium.
445453
name: str, optional
446454
The name for the component
455+
absolute_phi: bool, optional
456+
Specifies whether `phi_guest_h` and `phi_guest_t` represent fractional
457+
or absolute volume fractions.
458+
Please see the notes section for further details.
447459
448460
Notes
449461
-----
450462
The sum of coherent scattering lengths must be in Angstroms, the volume
451463
must be in cubic Angstroms. This is because the SLD of a tail group is
452-
calculated as `b_tails / vm_tails * 1e6` to achieve the units
464+
calculated as ``b_tails / vm_tails * 1e6`` to achieve the units
453465
10**6 Angstrom**-2.
466+
467+
`phi_guest_t` and `phi_guest_h` represent either a fractional (what
468+
fraction not occupied by lipid is occupied by guest) or absolute
469+
volume fraction of guest in a layer. If ``absolute_phi is False`` then
470+
the absolute volume fraction of guest in a layer is calculated as::
471+
472+
volfrac_guest_x = (1 - volfrac_x) * phi_guest_x
473+
474+
where ``volfrac_x`` is the absolute volume fraction of lipid in the head
475+
group region (x representing either the head (h) or tail region (t)).
476+
The amount of solvent in that layer is then calculated as::
477+
478+
vfsolv = 1 - volfrac_guest_x - volfrac_x
479+
480+
If ``absolute_phi is `True`` then `phi_guest_x` is regarded as an
481+
absolute volume fraction (not relative) and
482+
``volfrac_guest_x == phi_guest_x``. ``absolute_phi`` is useful when
483+
one wants to constrain the volume fraction of guest in the head and
484+
tail layers to be the same. Otherwise, setting `absolute_phi` to be
485+
False is preferred, as each layer is less likely to be overfilled.
486+
Appropriate constraints and bounds must be used during the modelling
487+
process to ensure ``volfrac_guest_x + volfrac_x <=1``.
488+
For optimisation using `differential_evolution` this entails
489+
using the :meth:`LipidLeafletGuest.make_constraints` method to create
490+
those constraints. Please see `using constraints`_ for an example.
491+
With MCMC the log-prior term becomes `-np.inf` (i.e. impossible).
492+
493+
.. _using constraints: https://refnx.readthedocs.io/en/latest/inequality_constraints.html#inequality-constraints-with-differential-evolution
454494
"""
455495

456496
def __init__(
@@ -471,6 +511,7 @@ def __init__(
471511
tail_solvent=None,
472512
reverse_monolayer=False,
473513
name="",
514+
absolute_phi=False,
474515
):
475516
super().__init__(
476517
apm,
@@ -501,6 +542,7 @@ def __init__(
501542
self.phi_guest_t.bounds.lb = 0
502543
self.phi_guest_t.bounds.ub = 1
503544
self.sld_guest = possibly_create_scatterer(sld_guest)
545+
self.absolute_phi = absolute_phi
504546

505547
def __repr__(self):
506548
sld_bh = SLD([self.b_heads_real, self.b_heads_imag])
@@ -522,7 +564,8 @@ def __repr__(self):
522564
f"head_solvent={self.head_solvent!r}, "
523565
f"tail_solvent={self.tail_solvent!r}, "
524566
f"reverse_monolayer={self.reverse_monolayer}, "
525-
f"name={self.name!r})"
567+
f"name={self.name!r}, "
568+
f"absolute_phi={self.absolute_phi!r})"
526569
)
527570
return s
528571

@@ -628,23 +671,73 @@ def parameters(self):
628671
def logp(self):
629672
# penalise unphysical volume fractions.
630673
if (
631-
self.volfrac_h > 1
632-
or self.volfrac_t > 1
633-
or self.phi_guest_h.value > 1
674+
self.phi_guest_h.value > 1
634675
or self.phi_guest_t.value > 1
676+
or self.volfrac_t + self.volfrac_guest_t > 1
677+
or self.volfrac_h + self.volfrac_guest_h > 1
635678
):
636679
return -np.inf
637680

638681
return 0
639682

683+
def make_constraint(self, objective):
684+
"""
685+
Creates a NonlinearConstraint for a LipidLeafletGuest, ensuring that
686+
volume fraction of material in the head+tail regions lies in [0, 1].
687+
Suitable for use by differential_evolution.
688+
689+
Parameters
690+
----------
691+
objective: refnx.analysis.Objective
692+
Objective containing the LipidLeafletGuest. Must be the Objective
693+
that is being minimised by differential_evolution.
694+
695+
Returns
696+
-------
697+
nlc: NonlinearConstraint
698+
699+
Notes
700+
-----
701+
You must create separate constraints for each LipidLeafletGuest object
702+
in your system.
703+
The Objective you supply must be for the overall curve fitting system.
704+
i.e. possibly a GlobalObjective.
705+
706+
Examples
707+
--------
708+
>>> # leaflet is a LipidLeafletGuest, used in an Objective, obj
709+
>>> con = leaflet.make_constraint(obj)
710+
>>> fitter = CurveFitter(obj)
711+
>>> fitter.fit("differential_evolution", constraints=(con,))
712+
"""
713+
714+
def con(x):
715+
objective.setp(x)
716+
return (
717+
self.volfrac_h + self.volfrac_guest_h,
718+
self.volfrac_t + self.volfrac_guest_t,
719+
)
720+
721+
return NonlinearConstraint(con, 0, 1)
722+
640723
@property
641724
def volfrac_guest_h(self):
642-
# Absolute volume fraction of guest in the head group region.
643-
vfh = self.volfrac_h
644-
return (1.0 - vfh) * self.phi_guest_h.value
725+
"""
726+
Absolute volume fraction of guest in the head group region.
727+
"""
728+
if self.absolute_phi:
729+
return self.phi_guest_h.value
730+
else:
731+
vfh = self.volfrac_h
732+
return (1.0 - vfh) * self.phi_guest_h.value
645733

646734
@property
647735
def volfrac_guest_t(self):
648-
# Absolute volume fraction of guest in the tail group region.
649-
vft = self.volfrac_t
650-
return (1.0 - vft) * self.phi_guest_t.value
736+
"""
737+
Absolute volume fraction of guest in the tail group region.
738+
"""
739+
if self.absolute_phi:
740+
return self.phi_guest_t.value
741+
else:
742+
vft = self.volfrac_t
743+
return (1.0 - vft) * self.phi_guest_t.value

0 commit comments

Comments
 (0)