From 46ba7e667c45dc7a57c5adbca6d45f594f399986 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Thu, 23 Jan 2025 14:25:10 +0000 Subject: [PATCH 1/7] Add _to_default_unit method to GeneralUnit class. [closes #381] --- .../Sandpit/Exscientia/Types/_general_unit.py | 21 +++++++++++++++++++ python/BioSimSpace/Types/_general_unit.py | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py b/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py index d87cd279..9cb7a158 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/_general_unit.py @@ -817,3 +817,24 @@ def _from_string(cls, string): else: raise TypeError("'string' must be of type 'str'") + + def _to_default_unit(self, mag=None): + """ + Internal method to return an object of the same type in the default unit. + + Parameters + ---------- + + mag : float + The value (optional). + + Returns + ------- + + length : :class:`Length ` + The length in the default unit of Angstrom. + """ + if mag is None: + return self + else: + return mag * self diff --git a/python/BioSimSpace/Types/_general_unit.py b/python/BioSimSpace/Types/_general_unit.py index d87cd279..9cb7a158 100644 --- a/python/BioSimSpace/Types/_general_unit.py +++ b/python/BioSimSpace/Types/_general_unit.py @@ -817,3 +817,24 @@ def _from_string(cls, string): else: raise TypeError("'string' must be of type 'str'") + + def _to_default_unit(self, mag=None): + """ + Internal method to return an object of the same type in the default unit. + + Parameters + ---------- + + mag : float + The value (optional). + + Returns + ------- + + length : :class:`Length ` + The length in the default unit of Angstrom. + """ + if mag is None: + return self + else: + return mag * self From 5e338eb0510edf112e5f4c51388b93a340f9a595 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Thu, 23 Jan 2025 16:06:45 +0000 Subject: [PATCH 2/7] Add mass type. --- .../Sandpit/Exscientia/Types/__init__.py | 2 + .../Sandpit/Exscientia/Types/_mass.py | 402 ++++++++++++++++++ python/BioSimSpace/Types/__init__.py | 2 + python/BioSimSpace/Types/_mass.py | 402 ++++++++++++++++++ 4 files changed, 808 insertions(+) create mode 100644 python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py create mode 100644 python/BioSimSpace/Types/_mass.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py b/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py index cecb5ec8..3cba4fd4 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/__init__.py @@ -34,6 +34,7 @@ Coordinate Energy Length + Mass Pressure Temperature Time @@ -47,6 +48,7 @@ from ._coordinate import * from ._energy import * from ._length import * +from ._mass import * from ._pressure import * from ._temperature import * from ._time import * diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py new file mode 100644 index 00000000..c7f775cd --- /dev/null +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py @@ -0,0 +1,402 @@ +###################################################################### +# BioSimSpace: Making biomolecular simulation a breeze! +# +# Copyright: 2017-2025 +# +# Authors: Lester Hedges +# +# BioSimSpace is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BioSimSpace is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BioSimSpace. If not, see . +##################################################################### + +"""A mass type.""" + +__author__ = "Lester Hedges" +__email__ = "lester.hedges@gmail.com" + +__all__ = ["Mass"] + +from sire.legacy import Units as _SireUnits + +from ._type import Type as _Type + + +class Mass(_Type): + """A mass type.""" + + # A list of the supported Sire unit names. + _sire_units = [ + "kilogram", + "gram", + "milligram", + "microgram", + "nanogram", + "picogram", + "femtogram", + ] + + # Dictionary of allowed units. + _supported_units = { + "KILOGRAM": _SireUnits.kilogram, + "GRAM": _SireUnits.gram, + "MILLIGRAM": _SireUnits.milligram, + "MICROGRAM": _SireUnits.microgram, + "NANOGRAM": _SireUnits.nanogram, + "PICOGRAM": _SireUnits.picogram, + "FEMTOGRAM": _SireUnits.femtogram, + } + + # Map unit abbreviations to the full name. + _abbreviations = { + "KG": "KILOGRAM", + "G": "GRAM", + "MG": "MILLIGRAM", + "UG": "MICROGRAM", + "NG": "NANOGRAM", + "PG": "PICOGRAM", + "FG": "FEMTOGRAM", + } + + # Print format. + _print_format = { + "GRAM": "g", + "MILLIGRAM": "mg", + "MICROGRAM": "ug", + "NANOGRAM": "ng", + "PICOGRAM": "pg", + "FEMTOGRAM": "fg", + } + + # Documentation strings. + _doc_strings = { + "KILOGRAM": "A mass in kilogram.", + "GRAM": "A mass in gram.", + "MILLIGRAM": "A mass in milligram.", + "MICROGRAM": "A mass in microgram.", + "NANOGRAM": "A mass in nanogram.", + "PICOGRAM": "A mass in picogram.", + "FEMTOGRAM": "A mass in femtogram.", + } + + # Null type unit for avoiding issue printing configargparse help. + _default_unit = "GRAM" + + # The dimension mask. + _dimensions = tuple(list(_supported_units.values())[0].dimensions()) + + def __init__(self, *args): + """ + Constructor. + + ``*args`` can be a value and unit, or a string representation + of the length, e.g. "12 grams". + + Parameters + ---------- + + value : float + The value. + + unit : str + The unit. + + string : str + A string representation of the mass. + + Examples + -------- + + Create an object representing a mass of 12 grams then + print the mass in kilograms. + + >>> import BioSimSpace as BSS + >>> length = BSS.Types.Length(12, "G") + >>> print(length.kilograms()) + + The same as above, except passing a string representation of the + length to the constructor. + + >>> import BioSimSpace as BSS + >>> length = BSS.Types.Length("12 G") + >>> print(length.kilograms()) + + The string matching is extremeley flexible, so all of the following + would be valid arguments: "12 G", "12 grams", "1.2e1 grams". + """ + + # Call the base class constructor. + super().__init__(*args) + + def __mul__(self, other): + """Multiplication operator.""" + + # Handle containers by converting each item in the container to + # this type. + if isinstance(other, list): + return [self.__mul__(item) for item in other] + if isinstance(other, tuple): + return tuple([self.__mul__(item) for item in other]) + + # Convert int to float. + if type(other) is int: + other = float(other) + + # Multiplication by float. + if isinstance(other, float): + mag = self._value * other + return Mass(mag, self._unit) + + # Multiplication by another type. + elif isinstance(other, _Type): + from ._general_unit import GeneralUnit as _GeneralUnit + + return _GeneralUnit(self._to_sire_unit() * other._to_sire_unit()) + + # Multiplication by a string. + elif isinstance(other, str): + try: + mass = Mass(other) + return self * length + except: + raise ValueError( + "Could not convert the string to a 'BioSimSpace.Mass' type." + ) + else: + raise TypeError( + "unsupported operand type(s) for *: '%s' and '%s'" + % (type(self), type(other)) + ) + + def __rmul__(self, other): + """Multiplication operator.""" + + # Multiplication is commutative: a*b = b*a + return self.__mul__(other) + + def kilogram(self): + """ + Return the mass in kilograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in kilograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.kilogram), + "KILOGRAM", + ) + + def gram(self): + """ + Return the mass in grams. + + Returns + ------- + + mass : :class:`Mass ` + The mass in grams. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.gram), + "GRAM", + ) + + def milligram(self): + """ + Return the mass in milligrams. + + Returns + ------- + + mass : :class:`Mass ` + The mass in milligrams. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.milligram), + "MILLIGRAM", + ) + + def microgram(self): + """ + Return the mass in micrograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in micrograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.microgram), + "MICROGRAM", + ) + + def nanogram(self): + """ + Return the mass in nanograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in nanograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.nanogram), + "NANOGRAM", + ) + + def picogram(self): + """ + Return the mass in picograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in picograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.picogram), + "PICOGRAM", + ) + + def femtogram(self): + """ + Return the mass in femtograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in femtograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.femtogram), + "FEMTOGRAM", + ) + + def _to_default_unit(self, mag=None): + """ + Internal method to return an object of the same type in the default unit. + + Parameters + ---------- + + mag : float + The value (optional). + + Returns + ------- + + length : :class:`Mass ` + The mass in the default unit of grams. + """ + if mag is None: + return self.gram() + else: + return Mass(mag, "GRAM") + + def _convert_to(self, unit): + """ + Return the mass in a different unit. + + Parameters + ---------- + + unit : str + The unit to convert to. + + Returns + ------- + + length : :class:`Mass ` + The mass in the specified unit. + """ + if unit == "KILOGRAM": + return self.kilogram() + elif unit == "GRAM": + return self.gram() + elif unit == "MILLIGRAM": + return self.milligram() + elif unit == "MICROGRAM": + return self.microgram() + elif unit == "NANOGRAM": + return self.nanogram() + elif unit == "PICOGRAM": + return self.picogram() + elif unit == "FEMTOGRAM": + return self.femtogram() + else: + raise ValueError( + "Supported units are: '%s'" % list(self._supported_units.keys()) + ) + + @classmethod + def _validate_unit(cls, unit): + """Validate that the unit are supported.""" + + # Strip whitespace and convert to upper case. + unit = unit.replace(" ", "").upper() + + # Strip any "S" characters. + unit = unit.replace("S", "") + + # Check that the unit is supported. + if unit in cls._supported_units: + return unit + elif unit in cls._abbreviations: + return cls._abbreviations[unit] + else: + raise ValueError( + "Supported units are: '%s'" % list(cls._supported_units.keys()) + ) + + @staticmethod + def _to_sire_format(unit): + """ + Reformat the unit string so it adheres to the Sire unit formatting. + + Parameters + ---------- + + unit : str + A string representation of the unit. + + Returns + ------- + + sire_unit : str + The unit string in Sire compatible format. + """ + + unit = unit.replace("kg", "kilogram") + unit = unit.replace("ug", "microgram") + unit = unit.replace("mg", "milligram") + unit = unit.replace("ng", "nanogram") + unit = unit.replace("pg", "picogram") + unit = unit.replace("fg", "femtogram") + unit = unit.replace("g", "gram") + + # Convert powers. + unit = unit.replace("kilogram-1", "(1/kilogram)") + unit = unit.replace("gram-1", "(1/gram)") + unit = unit.replace("milligram-1", "(1/milligram)") + unit = unit.replace("microgram-1", "(1/microgram)") + unit = unit.replace("nanogram-1", "(1/nanogram)") + unit = unit.replace("picogram-1", "(1/picogram)") + unit = unit.replace("femtogram-1", "(1/femtogram)") + + return unit diff --git a/python/BioSimSpace/Types/__init__.py b/python/BioSimSpace/Types/__init__.py index cecb5ec8..3cba4fd4 100644 --- a/python/BioSimSpace/Types/__init__.py +++ b/python/BioSimSpace/Types/__init__.py @@ -34,6 +34,7 @@ Coordinate Energy Length + Mass Pressure Temperature Time @@ -47,6 +48,7 @@ from ._coordinate import * from ._energy import * from ._length import * +from ._mass import * from ._pressure import * from ._temperature import * from ._time import * diff --git a/python/BioSimSpace/Types/_mass.py b/python/BioSimSpace/Types/_mass.py new file mode 100644 index 00000000..c7f775cd --- /dev/null +++ b/python/BioSimSpace/Types/_mass.py @@ -0,0 +1,402 @@ +###################################################################### +# BioSimSpace: Making biomolecular simulation a breeze! +# +# Copyright: 2017-2025 +# +# Authors: Lester Hedges +# +# BioSimSpace is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BioSimSpace is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BioSimSpace. If not, see . +##################################################################### + +"""A mass type.""" + +__author__ = "Lester Hedges" +__email__ = "lester.hedges@gmail.com" + +__all__ = ["Mass"] + +from sire.legacy import Units as _SireUnits + +from ._type import Type as _Type + + +class Mass(_Type): + """A mass type.""" + + # A list of the supported Sire unit names. + _sire_units = [ + "kilogram", + "gram", + "milligram", + "microgram", + "nanogram", + "picogram", + "femtogram", + ] + + # Dictionary of allowed units. + _supported_units = { + "KILOGRAM": _SireUnits.kilogram, + "GRAM": _SireUnits.gram, + "MILLIGRAM": _SireUnits.milligram, + "MICROGRAM": _SireUnits.microgram, + "NANOGRAM": _SireUnits.nanogram, + "PICOGRAM": _SireUnits.picogram, + "FEMTOGRAM": _SireUnits.femtogram, + } + + # Map unit abbreviations to the full name. + _abbreviations = { + "KG": "KILOGRAM", + "G": "GRAM", + "MG": "MILLIGRAM", + "UG": "MICROGRAM", + "NG": "NANOGRAM", + "PG": "PICOGRAM", + "FG": "FEMTOGRAM", + } + + # Print format. + _print_format = { + "GRAM": "g", + "MILLIGRAM": "mg", + "MICROGRAM": "ug", + "NANOGRAM": "ng", + "PICOGRAM": "pg", + "FEMTOGRAM": "fg", + } + + # Documentation strings. + _doc_strings = { + "KILOGRAM": "A mass in kilogram.", + "GRAM": "A mass in gram.", + "MILLIGRAM": "A mass in milligram.", + "MICROGRAM": "A mass in microgram.", + "NANOGRAM": "A mass in nanogram.", + "PICOGRAM": "A mass in picogram.", + "FEMTOGRAM": "A mass in femtogram.", + } + + # Null type unit for avoiding issue printing configargparse help. + _default_unit = "GRAM" + + # The dimension mask. + _dimensions = tuple(list(_supported_units.values())[0].dimensions()) + + def __init__(self, *args): + """ + Constructor. + + ``*args`` can be a value and unit, or a string representation + of the length, e.g. "12 grams". + + Parameters + ---------- + + value : float + The value. + + unit : str + The unit. + + string : str + A string representation of the mass. + + Examples + -------- + + Create an object representing a mass of 12 grams then + print the mass in kilograms. + + >>> import BioSimSpace as BSS + >>> length = BSS.Types.Length(12, "G") + >>> print(length.kilograms()) + + The same as above, except passing a string representation of the + length to the constructor. + + >>> import BioSimSpace as BSS + >>> length = BSS.Types.Length("12 G") + >>> print(length.kilograms()) + + The string matching is extremeley flexible, so all of the following + would be valid arguments: "12 G", "12 grams", "1.2e1 grams". + """ + + # Call the base class constructor. + super().__init__(*args) + + def __mul__(self, other): + """Multiplication operator.""" + + # Handle containers by converting each item in the container to + # this type. + if isinstance(other, list): + return [self.__mul__(item) for item in other] + if isinstance(other, tuple): + return tuple([self.__mul__(item) for item in other]) + + # Convert int to float. + if type(other) is int: + other = float(other) + + # Multiplication by float. + if isinstance(other, float): + mag = self._value * other + return Mass(mag, self._unit) + + # Multiplication by another type. + elif isinstance(other, _Type): + from ._general_unit import GeneralUnit as _GeneralUnit + + return _GeneralUnit(self._to_sire_unit() * other._to_sire_unit()) + + # Multiplication by a string. + elif isinstance(other, str): + try: + mass = Mass(other) + return self * length + except: + raise ValueError( + "Could not convert the string to a 'BioSimSpace.Mass' type." + ) + else: + raise TypeError( + "unsupported operand type(s) for *: '%s' and '%s'" + % (type(self), type(other)) + ) + + def __rmul__(self, other): + """Multiplication operator.""" + + # Multiplication is commutative: a*b = b*a + return self.__mul__(other) + + def kilogram(self): + """ + Return the mass in kilograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in kilograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.kilogram), + "KILOGRAM", + ) + + def gram(self): + """ + Return the mass in grams. + + Returns + ------- + + mass : :class:`Mass ` + The mass in grams. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.gram), + "GRAM", + ) + + def milligram(self): + """ + Return the mass in milligrams. + + Returns + ------- + + mass : :class:`Mass ` + The mass in milligrams. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.milligram), + "MILLIGRAM", + ) + + def microgram(self): + """ + Return the mass in micrograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in micrograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.microgram), + "MICROGRAM", + ) + + def nanogram(self): + """ + Return the mass in nanograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in nanograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.nanogram), + "NANOGRAM", + ) + + def picogram(self): + """ + Return the mass in picograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in picograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.picogram), + "PICOGRAM", + ) + + def femtogram(self): + """ + Return the mass in femtograms. + + Returns + ------- + + mass : :class:`Mass ` + The mass in femtograms. + """ + return Mass( + (self._value * self._supported_units[self._unit]).to(_SireUnits.femtogram), + "FEMTOGRAM", + ) + + def _to_default_unit(self, mag=None): + """ + Internal method to return an object of the same type in the default unit. + + Parameters + ---------- + + mag : float + The value (optional). + + Returns + ------- + + length : :class:`Mass ` + The mass in the default unit of grams. + """ + if mag is None: + return self.gram() + else: + return Mass(mag, "GRAM") + + def _convert_to(self, unit): + """ + Return the mass in a different unit. + + Parameters + ---------- + + unit : str + The unit to convert to. + + Returns + ------- + + length : :class:`Mass ` + The mass in the specified unit. + """ + if unit == "KILOGRAM": + return self.kilogram() + elif unit == "GRAM": + return self.gram() + elif unit == "MILLIGRAM": + return self.milligram() + elif unit == "MICROGRAM": + return self.microgram() + elif unit == "NANOGRAM": + return self.nanogram() + elif unit == "PICOGRAM": + return self.picogram() + elif unit == "FEMTOGRAM": + return self.femtogram() + else: + raise ValueError( + "Supported units are: '%s'" % list(self._supported_units.keys()) + ) + + @classmethod + def _validate_unit(cls, unit): + """Validate that the unit are supported.""" + + # Strip whitespace and convert to upper case. + unit = unit.replace(" ", "").upper() + + # Strip any "S" characters. + unit = unit.replace("S", "") + + # Check that the unit is supported. + if unit in cls._supported_units: + return unit + elif unit in cls._abbreviations: + return cls._abbreviations[unit] + else: + raise ValueError( + "Supported units are: '%s'" % list(cls._supported_units.keys()) + ) + + @staticmethod + def _to_sire_format(unit): + """ + Reformat the unit string so it adheres to the Sire unit formatting. + + Parameters + ---------- + + unit : str + A string representation of the unit. + + Returns + ------- + + sire_unit : str + The unit string in Sire compatible format. + """ + + unit = unit.replace("kg", "kilogram") + unit = unit.replace("ug", "microgram") + unit = unit.replace("mg", "milligram") + unit = unit.replace("ng", "nanogram") + unit = unit.replace("pg", "picogram") + unit = unit.replace("fg", "femtogram") + unit = unit.replace("g", "gram") + + # Convert powers. + unit = unit.replace("kilogram-1", "(1/kilogram)") + unit = unit.replace("gram-1", "(1/gram)") + unit = unit.replace("milligram-1", "(1/milligram)") + unit = unit.replace("microgram-1", "(1/microgram)") + unit = unit.replace("nanogram-1", "(1/nanogram)") + unit = unit.replace("picogram-1", "(1/picogram)") + unit = unit.replace("femtogram-1", "(1/femtogram)") + + return unit From 8888e353ac28fa2a28aab5ef390b40c17a36a8a0 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Mon, 27 Jan 2025 16:21:22 +0000 Subject: [PATCH 3/7] Add mass requirement. --- python/BioSimSpace/Gateway/_node.py | 3 + python/BioSimSpace/Gateway/_requirements.py | 201 ++++++++++++++--- .../Sandpit/Exscientia/Gateway/_node.py | 3 + .../Exscientia/Gateway/_requirements.py | 204 +++++++++++++++--- 4 files changed, 346 insertions(+), 65 deletions(-) diff --git a/python/BioSimSpace/Gateway/_node.py b/python/BioSimSpace/Gateway/_node.py index 62197497..9d7bd231 100644 --- a/python/BioSimSpace/Gateway/_node.py +++ b/python/BioSimSpace/Gateway/_node.py @@ -60,6 +60,7 @@ from ._requirements import Energy as _Energy from ._requirements import Integer as _Integer from ._requirements import Length as _Length +from ._requirements import Mass as _Mass from ._requirements import Pressure as _Pressure from ._requirements import Requirement as _Requirement from ._requirements import String as _String @@ -74,6 +75,7 @@ _Energy, _Pressure, _Length, + _Mass, _Area, _Volume, _Temperature, @@ -86,6 +88,7 @@ _Energy, _Pressure, _Length, + _Mass, _Area, _Volume, _Temperature, diff --git a/python/BioSimSpace/Gateway/_requirements.py b/python/BioSimSpace/Gateway/_requirements.py index b761f9b3..ae30e499 100644 --- a/python/BioSimSpace/Gateway/_requirements.py +++ b/python/BioSimSpace/Gateway/_requirements.py @@ -31,15 +31,16 @@ "Boolean", "Integer", "Float", - "String", # Regular types. + "String", "File", - "FileSet", # File types. + "FileSet", "Length", "Area", - "Volume", # Length types. + "Volume", "Angle", "Charge", "Energy", + "Mass", "Pressure", "Temperature", "Time", @@ -744,16 +745,20 @@ class Length(Requirement): for the default. >>> import BioSimSpace as BSS - >>> my_length = BSS.Gateway.Length(help="A length requirement", - ... default=10*BSS.Units.Length.angstrom) + >>> my_length = BSS.Gateway.Length( + ... help="A length requirement", + ... default=10*BSS.Units.Length.angstrom + ... ) Create a length requirement with a default of 10 Angstrom and a maximum of 50 nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_length = BSS.Gateway.Length(help="A length requirement", - ... default=10*BSS.Units.Length.angstrom, - ... maximum=50*BSS.Units.Length.nanometer) + >>> my_length = BSS.Gateway.Length( + ... help="A length requirement", + ... default=10*BSS.Units.Length.angstrom, + ... maximum=50*BSS.Units.Length.nanometer + ... ) """ # Set the argparse argument type. @@ -866,9 +871,11 @@ class Area(Requirement): of 50 square nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_area = BSS.Gateway.Area(help="An area requirement", - ... default=100*BSS.Units.Area.angstrom2, - ... maximum=50*BSS.Units.Area.nanometer2) + >>> my_area = BSS.Gateway.Area( + ... help="An area requirement", + ... default=100*BSS.Units.Area.angstrom2, + ... maximum=50*BSS.Units.Area.nanometer2 + ... ) """ # Set the argparse argument type. @@ -981,9 +988,11 @@ class Volume(Requirement): of 50 cubed nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_volume = BSS.Gateway.Volume(help="A volume requirement", - ... default=10*BSS.Units.Volume.angstrom3, - ... maximum=50*BSS.Units.Volume.nanometer3) + >>> my_volume = BSS.Gateway.Volume( + ... help="A volume requirement", + ... default=10*BSS.Units.Volume.angstrom3, + ... maximum=50*BSS.Units.Volume.nanometer3 + ... ) """ # Set the argparse argument type. @@ -1096,9 +1105,11 @@ class Angle(Requirement): of 360 degrees. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_angle = BSS.Gateway.Angle(help="An angle requirement", - ... default=3.14*BSS.Units.Angle.radian, - ... maximum=360*BSS.Units.Angle.degree) + >>> my_angle = BSS.Gateway.Angle( + ... help="An angle requirement", + ... default=3.14*BSS.Units.Angle.radian, + ... maximum=360*BSS.Units.Angle.degree + ... ) """ # Set the argparse argument type. @@ -1211,9 +1222,11 @@ class Charge(Requirement): maximum of -10 Coulomb. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_charge = BSS.Gateway.Charge(help="A charge requirement", - ... default=3*BSS.Units.Charge.electron_charge, - ... maximum=10*BSS.Units.Charge.coulomb) + >>> my_charge = BSS.Gateway.Charge( + ... help="A charge requirement", + ... default=3*BSS.Units.Charge.electron_charge, + ... maximum=10*BSS.Units.Charge.coulomb + ... ) """ # Set the argparse argument type. @@ -1326,9 +1339,11 @@ class Energy(Requirement): maximum of 50 kJ per mol. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_energy = BSS.Gateway.Energy(help="An energy requirement", - ... default=3*BSS.Units.Energy.kcal_per_mol, - ... maximum=50*BSS.Units.Energy.kj_per_mol) + >>> my_energy = BSS.Gateway.Energy( + ... help="An energy requirement", + ... default=3*BSS.Units.Energy.kcal_per_mol, + ... maximum=50*BSS.Units.Energy.kj_per_mol + ... ) """ # Set the argparse argument type. @@ -1419,6 +1434,122 @@ def _validate(self, value): return _Types.Energy(value, unit)._convert_to(self._unit) +class Mass(Requirement): + """A mass requirement. + + Examples + -------- + + Create a mass requirement with a default of 10 grams. + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass(help="A mass requirement with a default of 10 grams", default=10, unit="gram") + + The same, but explicitly passing a :class:`Mass ` + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass(help="A mass requirement with a default of 10 grams", default=10*BSS.Units.Mass.gram) + + Create a mass requirement with a default of 10 grams and a maximum of 10 kilograms. + Note that the unit is taken from the default value. + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass( + ... help="A mass requirement with a default of 10 grams", + ... default=10*BSS.Units.Mass.gram, + ... maximum=10*BSS.Units.Mass.kilogram + ... ) + """ + + # Set the argparse argument type. + _arg_type = str + + def __init__( + self, + help=None, + default=None, + unit=None, + minimum=None, + maximum=None, + allowed=None, + ): + """ + Constructor. + + Parameters + ---------- + + help : str + The help string. + + default : :class:`Mass ` + The default value. + + unit : str + The unit. + + minimum : :class:`Mass ` + The minimum allowed value. + + maximum : :class:`Mass ` + The maximum allowed value. + + allowed : [:class:`Mass `] + A list of allowed values. + """ + + # Validate the unit. + if unit is not None: + mass = _Types.Mass("1 %s" % unit) + self._unit = mass.unit() + self._print_unit = mass._print_format[mass.unit()] + else: + try: + self._unit = default.unit() + except: + raise ValueError("No unit or default value has been specified!") + + # Call the base class constructor. + super().__init__( + help=help, + default=default, + unit=self._unit, + minimum=minimum, + maximum=maximum, + allowed=allowed, + ) + + def getValue(self): + """ + Return the value. + + Returns + ------- + + value : :class:`Mass ` + The value of the requirement. + """ + if self._value is None: + return None + else: + return _copy.deepcopy(self._value) + + def _validate(self, value): + """Validate that the value is of the correct type.""" + + if isinstance(value, _Types.Mass): + return value._convert_to(self._unit) + + else: + # Extract the value and unit from the argument string. + value, unit = _validate_unit_requirement(value, "pressure") + + if unit is None: + return _Types.Mass(value, self._unit) + else: + return _Types.Mass(value, unit)._convert_to(self._unit) + + class Pressure(Requirement): """A pressure requirement. @@ -1440,9 +1571,11 @@ class Pressure(Requirement): maximum of 10 bar. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_pressure = BSS.Gateway.Pressure(help="A pressure requirement", - ... default=BSS.Units.Pressure.atm, - ... maximum=10*BSS.Units.Pressure.bar) + >>> my_pressure = BSS.Gateway.Pressure( + ... help="A pressure requirement", + ... default=BSS.Units.Pressure.atm, + ... maximum=10*BSS.Units.Pressure.bar + ... ) """ # Set the argparse argument type. @@ -1555,9 +1688,11 @@ class Temperature(Requirement): maximum of 100 Celsius. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_temperature = BSS.Gateway.Temperature(help="A temperature requirement", - ... default=300*BSS.Units.Temperature.kelvin, - ... maximum=100*BSS.Units.Temperature.celsius) + >>> my_temperature = BSS.Gateway.Temperature( + ... help="A temperature requirement", + ... default=300*BSS.Units.Temperature.kelvin, + ... maximum=100*BSS.Units.Temperature.celsius + ... ) """ # Set the argparse argument type. @@ -1670,9 +1805,11 @@ class Time(Requirement): of 5 hours. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_time = BSS.Gateway.Time(help="A time requirement", - ... default=35*BSS.Units.Time.minute, - ... maximum=5*BSS.Units.Time.hour) + >>> my_time = BSS.Gateway.Time( + ... help="A time requirement", + ... default=35*BSS.Units.Time.minute, + ... maximum=5*BSS.Units.Time.hour + ... ) """ # Set the argparse argument type. diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py b/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py index 62197497..9d7bd231 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Gateway/_node.py @@ -60,6 +60,7 @@ from ._requirements import Energy as _Energy from ._requirements import Integer as _Integer from ._requirements import Length as _Length +from ._requirements import Mass as _Mass from ._requirements import Pressure as _Pressure from ._requirements import Requirement as _Requirement from ._requirements import String as _String @@ -74,6 +75,7 @@ _Energy, _Pressure, _Length, + _Mass, _Area, _Volume, _Temperature, @@ -86,6 +88,7 @@ _Energy, _Pressure, _Length, + _Mass, _Area, _Volume, _Temperature, diff --git a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py b/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py index 0d346428..ae30e499 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Gateway/_requirements.py @@ -31,15 +31,16 @@ "Boolean", "Integer", "Float", - "String", # Regular types. + "String", "File", - "FileSet", # File types. + "FileSet", "Length", "Area", - "Volume", # Length types. + "Volume", "Angle", "Charge", "Energy", + "Mass", "Pressure", "Temperature", "Time", @@ -744,16 +745,20 @@ class Length(Requirement): for the default. >>> import BioSimSpace as BSS - >>> my_length = BSS.Gateway.Length(help="A length requirement", - ... default=10*BSS.Units.Length.angstrom) + >>> my_length = BSS.Gateway.Length( + ... help="A length requirement", + ... default=10*BSS.Units.Length.angstrom + ... ) Create a length requirement with a default of 10 Angstrom and a maximum of 50 nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_length = BSS.Gateway.Length(help="A length requirement", - ... default=10*BSS.Units.Length.angstrom, - ... maximum=50*BSS.Units.Length.nanometer) + >>> my_length = BSS.Gateway.Length( + ... help="A length requirement", + ... default=10*BSS.Units.Length.angstrom, + ... maximum=50*BSS.Units.Length.nanometer + ... ) """ # Set the argparse argument type. @@ -866,9 +871,11 @@ class Area(Requirement): of 50 square nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_area = BSS.Gateway.Area(help="An area requirement", - ... default=100*BSS.Units.Area.angstrom2, - ... maximum=50*BSS.Units.Area.nanometer2) + >>> my_area = BSS.Gateway.Area( + ... help="An area requirement", + ... default=100*BSS.Units.Area.angstrom2, + ... maximum=50*BSS.Units.Area.nanometer2 + ... ) """ # Set the argparse argument type. @@ -981,9 +988,11 @@ class Volume(Requirement): of 50 cubed nanometers. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_volume = BSS.Gateway.Volume(help="A volume requirement", - ... default=10*BSS.Units.Volume.angstrom3, - ... maximum=50*BSS.Units.Volume.nanometer3) + >>> my_volume = BSS.Gateway.Volume( + ... help="A volume requirement", + ... default=10*BSS.Units.Volume.angstrom3, + ... maximum=50*BSS.Units.Volume.nanometer3 + ... ) """ # Set the argparse argument type. @@ -1096,9 +1105,11 @@ class Angle(Requirement): of 360 degrees. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_angle = BSS.Gateway.Angle(help="An angle requirement", - ... default=3.14*BSS.Units.Angle.radian, - ... maximum=360*BSS.Units.Angle.degree) + >>> my_angle = BSS.Gateway.Angle( + ... help="An angle requirement", + ... default=3.14*BSS.Units.Angle.radian, + ... maximum=360*BSS.Units.Angle.degree + ... ) """ # Set the argparse argument type. @@ -1211,9 +1222,11 @@ class Charge(Requirement): maximum of -10 Coulomb. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_charge = BSS.Gateway.Charge(help="A charge requirement", - ... default=3*BSS.Units.Charge.electron_charge, - ... maximum=10*BSS.Units.Charge.coulomb) + >>> my_charge = BSS.Gateway.Charge( + ... help="A charge requirement", + ... default=3*BSS.Units.Charge.electron_charge, + ... maximum=10*BSS.Units.Charge.coulomb + ... ) """ # Set the argparse argument type. @@ -1326,9 +1339,11 @@ class Energy(Requirement): maximum of 50 kJ per mol. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_energy = BSS.Gateway.Energy(help="An energy requirement", - ... default=3*BSS.Units.Energy.kcal_per_mol, - ... maximum=50*BSS.Units.Energy.kj_per_mol) + >>> my_energy = BSS.Gateway.Energy( + ... help="An energy requirement", + ... default=3*BSS.Units.Energy.kcal_per_mol, + ... maximum=50*BSS.Units.Energy.kj_per_mol + ... ) """ # Set the argparse argument type. @@ -1419,6 +1434,122 @@ def _validate(self, value): return _Types.Energy(value, unit)._convert_to(self._unit) +class Mass(Requirement): + """A mass requirement. + + Examples + -------- + + Create a mass requirement with a default of 10 grams. + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass(help="A mass requirement with a default of 10 grams", default=10, unit="gram") + + The same, but explicitly passing a :class:`Mass ` + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass(help="A mass requirement with a default of 10 grams", default=10*BSS.Units.Mass.gram) + + Create a mass requirement with a default of 10 grams and a maximum of 10 kilograms. + Note that the unit is taken from the default value. + + >>> import BioSimSpace as BSS + >>> my_mass = BSS.Gateway.Mass( + ... help="A mass requirement with a default of 10 grams", + ... default=10*BSS.Units.Mass.gram, + ... maximum=10*BSS.Units.Mass.kilogram + ... ) + """ + + # Set the argparse argument type. + _arg_type = str + + def __init__( + self, + help=None, + default=None, + unit=None, + minimum=None, + maximum=None, + allowed=None, + ): + """ + Constructor. + + Parameters + ---------- + + help : str + The help string. + + default : :class:`Mass ` + The default value. + + unit : str + The unit. + + minimum : :class:`Mass ` + The minimum allowed value. + + maximum : :class:`Mass ` + The maximum allowed value. + + allowed : [:class:`Mass `] + A list of allowed values. + """ + + # Validate the unit. + if unit is not None: + mass = _Types.Mass("1 %s" % unit) + self._unit = mass.unit() + self._print_unit = mass._print_format[mass.unit()] + else: + try: + self._unit = default.unit() + except: + raise ValueError("No unit or default value has been specified!") + + # Call the base class constructor. + super().__init__( + help=help, + default=default, + unit=self._unit, + minimum=minimum, + maximum=maximum, + allowed=allowed, + ) + + def getValue(self): + """ + Return the value. + + Returns + ------- + + value : :class:`Mass ` + The value of the requirement. + """ + if self._value is None: + return None + else: + return _copy.deepcopy(self._value) + + def _validate(self, value): + """Validate that the value is of the correct type.""" + + if isinstance(value, _Types.Mass): + return value._convert_to(self._unit) + + else: + # Extract the value and unit from the argument string. + value, unit = _validate_unit_requirement(value, "pressure") + + if unit is None: + return _Types.Mass(value, self._unit) + else: + return _Types.Mass(value, unit)._convert_to(self._unit) + + class Pressure(Requirement): """A pressure requirement. @@ -1440,9 +1571,11 @@ class Pressure(Requirement): maximum of 10 bar. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_pressure = BSS.Gateway.Pressure(help="A pressure requirement", - ... default=BSS.Units.Pressure.atm, - ... maximum=10*BSS.Units.Pressure.bar) + >>> my_pressure = BSS.Gateway.Pressure( + ... help="A pressure requirement", + ... default=BSS.Units.Pressure.atm, + ... maximum=10*BSS.Units.Pressure.bar + ... ) """ # Set the argparse argument type. @@ -1555,9 +1688,11 @@ class Temperature(Requirement): maximum of 100 Celsius. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_temperature = BSS.Gateway.Temperature(help="A temperature requirement", - ... default=300*BSS.Units.Temperature.kelvin, - ... maximum=100*BSS.Units.Temperature.celsius) + >>> my_temperature = BSS.Gateway.Temperature( + ... help="A temperature requirement", + ... default=300*BSS.Units.Temperature.kelvin, + ... maximum=100*BSS.Units.Temperature.celsius + ... ) """ # Set the argparse argument type. @@ -1670,9 +1805,11 @@ class Time(Requirement): of 5 hours. Note that the unit is taken from the default value. >>> import BioSimSpace as BSS - >>> my_time = BSS.Gateway.Time(help="A time requirement", - ... default=35*BSS.Units.Time.minute, - ... maximum=5*BSS.Units.Time.hour) + >>> my_time = BSS.Gateway.Time( + ... help="A time requirement", + ... default=35*BSS.Units.Time.minute, + ... maximum=5*BSS.Units.Time.hour + ... ) """ # Set the argparse argument type. @@ -1764,7 +1901,8 @@ def _validate(self, value): def _validate_unit_requirement(value, unit_type): - """Helper function to validate input requirements with units. + """ + Helper function to validate input requirements with units. Parameters ---------- From f9497f04e8385776d78b620d67f7f1ace6d73e88 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Mon, 27 Jan 2025 16:27:13 +0000 Subject: [PATCH 4/7] Document use of explicit_dummies kwarg. [closes #382] --- python/BioSimSpace/Process/_amber.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/BioSimSpace/Process/_amber.py b/python/BioSimSpace/Process/_amber.py index 51a35aff..c585c670 100644 --- a/python/BioSimSpace/Process/_amber.py +++ b/python/BioSimSpace/Process/_amber.py @@ -102,6 +102,9 @@ def __init__( explicit_dummies : bool Whether to keep dummy atoms explicit at alchemical end states, or remove them. + This option is provided for legacy support of alchemical free energy calculations + using the old PMEMD CPU implementation. The default is False, which should be + used for any recent AMBER version or for GPU accelerated PMEMD. exe : str The full path to the AMBER executable. From 72d6e1ea5e6f8d009536a4acb89211eed6d075a5 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Mon, 27 Jan 2025 16:38:30 +0000 Subject: [PATCH 5/7] Add mass unit convenience classes. --- .../Sandpit/Exscientia/Types/_mass.py | 1 + .../Sandpit/Exscientia/Units/Mass/__init__.py | 46 +++++++++++++++++++ .../Sandpit/Exscientia/Units/__init__.py | 15 ++++++ python/BioSimSpace/Types/_mass.py | 1 + python/BioSimSpace/Units/Mass/__init__.py | 46 +++++++++++++++++++ python/BioSimSpace/Units/__init__.py | 15 ++++++ 6 files changed, 124 insertions(+) create mode 100644 python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py create mode 100644 python/BioSimSpace/Units/Mass/__init__.py diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py index c7f775cd..d3d1e917 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py @@ -69,6 +69,7 @@ class Mass(_Type): # Print format. _print_format = { + "KILOGRAM": "kg", "GRAM": "g", "MILLIGRAM": "mg", "MICROGRAM": "ug", diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py b/python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py new file mode 100644 index 00000000..0d201699 --- /dev/null +++ b/python/BioSimSpace/Sandpit/Exscientia/Units/Mass/__init__.py @@ -0,0 +1,46 @@ +###################################################################### +# BioSimSpace: Making biomolecular simulation a breeze! +# +# Copyright: 2017-2025 +# +# Authors: Lester Hedges +# +# BioSimSpace is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BioSimSpace is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BioSimSpace. If not, see . +##################################################################### + +"""Mass units.""" + +__author__ = "Lester Hedges" +__email__ = "lester.hedges@gmail.com" + +__all__ = [ + "kilogram", + "gram", + "milligram", + "microgram", + "nanogram", + "picogram", + "femtogram", +] + + +from ...Types import Mass as _Mass + +kilogram = _Mass(1, "kilogram") +gram = _Mass(1, "gram") +milligram = _Mass(1, "milligram") +microgram = _Mass(1, "microgram") +nanogram = _Mass(1, "nanogram") +picogram = _Mass(1, "picogram") +femtogram = _Mass(1, "femtogram") diff --git a/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py b/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py index 6b454831..55b41476 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Units/__init__.py @@ -73,6 +73,20 @@ Charge.electron_charge Charge.coulomb +Mass units +========== + +.. autosummary:: + :toctree: generated/ + + Mass.kilogram + Mass.gram + Mass.milligram + Mass.microgram + Mass.nanogram + Mass.picogram + Mass.femtogram + Energy units ============ @@ -123,6 +137,7 @@ from . import Charge from . import Energy from . import Length +from . import Mass from . import Pressure from . import Temperature from . import Time diff --git a/python/BioSimSpace/Types/_mass.py b/python/BioSimSpace/Types/_mass.py index c7f775cd..d3d1e917 100644 --- a/python/BioSimSpace/Types/_mass.py +++ b/python/BioSimSpace/Types/_mass.py @@ -69,6 +69,7 @@ class Mass(_Type): # Print format. _print_format = { + "KILOGRAM": "kg", "GRAM": "g", "MILLIGRAM": "mg", "MICROGRAM": "ug", diff --git a/python/BioSimSpace/Units/Mass/__init__.py b/python/BioSimSpace/Units/Mass/__init__.py new file mode 100644 index 00000000..0d201699 --- /dev/null +++ b/python/BioSimSpace/Units/Mass/__init__.py @@ -0,0 +1,46 @@ +###################################################################### +# BioSimSpace: Making biomolecular simulation a breeze! +# +# Copyright: 2017-2025 +# +# Authors: Lester Hedges +# +# BioSimSpace is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# BioSimSpace is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with BioSimSpace. If not, see . +##################################################################### + +"""Mass units.""" + +__author__ = "Lester Hedges" +__email__ = "lester.hedges@gmail.com" + +__all__ = [ + "kilogram", + "gram", + "milligram", + "microgram", + "nanogram", + "picogram", + "femtogram", +] + + +from ...Types import Mass as _Mass + +kilogram = _Mass(1, "kilogram") +gram = _Mass(1, "gram") +milligram = _Mass(1, "milligram") +microgram = _Mass(1, "microgram") +nanogram = _Mass(1, "nanogram") +picogram = _Mass(1, "picogram") +femtogram = _Mass(1, "femtogram") diff --git a/python/BioSimSpace/Units/__init__.py b/python/BioSimSpace/Units/__init__.py index 6b454831..55b41476 100644 --- a/python/BioSimSpace/Units/__init__.py +++ b/python/BioSimSpace/Units/__init__.py @@ -73,6 +73,20 @@ Charge.electron_charge Charge.coulomb +Mass units +========== + +.. autosummary:: + :toctree: generated/ + + Mass.kilogram + Mass.gram + Mass.milligram + Mass.microgram + Mass.nanogram + Mass.picogram + Mass.femtogram + Energy units ============ @@ -123,6 +137,7 @@ from . import Charge from . import Energy from . import Length +from . import Mass from . import Pressure from . import Temperature from . import Time From 2668680ce90e1cbdb2a5d8e06dffe00d1cedd869 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Wed, 29 Jan 2025 11:30:09 +0000 Subject: [PATCH 6/7] Fix docstrings. [ci skip] --- python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py | 8 ++++---- python/BioSimSpace/Types/_mass.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py index d3d1e917..90e6cfc7 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py @@ -121,15 +121,15 @@ def __init__(self, *args): print the mass in kilograms. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Length(12, "G") - >>> print(length.kilograms()) + >>> length = BSS.Types.Mass(12, "G") + >>> print(length.kilogram()) The same as above, except passing a string representation of the length to the constructor. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Length("12 G") - >>> print(length.kilograms()) + >>> length = BSS.Types.Mass("12 G") + >>> print(length.kilogram()) The string matching is extremeley flexible, so all of the following would be valid arguments: "12 G", "12 grams", "1.2e1 grams". diff --git a/python/BioSimSpace/Types/_mass.py b/python/BioSimSpace/Types/_mass.py index d3d1e917..90e6cfc7 100644 --- a/python/BioSimSpace/Types/_mass.py +++ b/python/BioSimSpace/Types/_mass.py @@ -121,15 +121,15 @@ def __init__(self, *args): print the mass in kilograms. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Length(12, "G") - >>> print(length.kilograms()) + >>> length = BSS.Types.Mass(12, "G") + >>> print(length.kilogram()) The same as above, except passing a string representation of the length to the constructor. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Length("12 G") - >>> print(length.kilograms()) + >>> length = BSS.Types.Mass("12 G") + >>> print(length.kilogram()) The string matching is extremeley flexible, so all of the following would be valid arguments: "12 G", "12 grams", "1.2e1 grams". From 08697f4b03c94d107eb8137540ab210b1c988b52 Mon Sep 17 00:00:00 2001 From: Lester Hedges Date: Wed, 29 Jan 2025 11:35:44 +0000 Subject: [PATCH 7/7] Replace all mentions of length and Length. [ci skip] --- .../Sandpit/Exscientia/Types/_mass.py | 18 +++++++++--------- python/BioSimSpace/Types/_mass.py | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py index 90e6cfc7..ecb76a75 100644 --- a/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py +++ b/python/BioSimSpace/Sandpit/Exscientia/Types/_mass.py @@ -100,7 +100,7 @@ def __init__(self, *args): Constructor. ``*args`` can be a value and unit, or a string representation - of the length, e.g. "12 grams". + of the mass, e.g. "12 grams". Parameters ---------- @@ -121,15 +121,15 @@ def __init__(self, *args): print the mass in kilograms. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Mass(12, "G") - >>> print(length.kilogram()) + >>> mass = BSS.Types.Mass(12, "G") + >>> print(mass.kilogram()) The same as above, except passing a string representation of the - length to the constructor. + mass to the constructor. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Mass("12 G") - >>> print(length.kilogram()) + >>> mass = BSS.Types.Mass("12 G") + >>> print(mass.kilogram()) The string matching is extremeley flexible, so all of the following would be valid arguments: "12 G", "12 grams", "1.2e1 grams". @@ -167,7 +167,7 @@ def __mul__(self, other): elif isinstance(other, str): try: mass = Mass(other) - return self * length + return self * mass except: raise ValueError( "Could not convert the string to a 'BioSimSpace.Mass' type." @@ -302,7 +302,7 @@ def _to_default_unit(self, mag=None): Returns ------- - length : :class:`Mass ` + mass : :class:`Mass ` The mass in the default unit of grams. """ if mag is None: @@ -323,7 +323,7 @@ def _convert_to(self, unit): Returns ------- - length : :class:`Mass ` + mass : :class:`Mass ` The mass in the specified unit. """ if unit == "KILOGRAM": diff --git a/python/BioSimSpace/Types/_mass.py b/python/BioSimSpace/Types/_mass.py index 90e6cfc7..ecb76a75 100644 --- a/python/BioSimSpace/Types/_mass.py +++ b/python/BioSimSpace/Types/_mass.py @@ -100,7 +100,7 @@ def __init__(self, *args): Constructor. ``*args`` can be a value and unit, or a string representation - of the length, e.g. "12 grams". + of the mass, e.g. "12 grams". Parameters ---------- @@ -121,15 +121,15 @@ def __init__(self, *args): print the mass in kilograms. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Mass(12, "G") - >>> print(length.kilogram()) + >>> mass = BSS.Types.Mass(12, "G") + >>> print(mass.kilogram()) The same as above, except passing a string representation of the - length to the constructor. + mass to the constructor. >>> import BioSimSpace as BSS - >>> length = BSS.Types.Mass("12 G") - >>> print(length.kilogram()) + >>> mass = BSS.Types.Mass("12 G") + >>> print(mass.kilogram()) The string matching is extremeley flexible, so all of the following would be valid arguments: "12 G", "12 grams", "1.2e1 grams". @@ -167,7 +167,7 @@ def __mul__(self, other): elif isinstance(other, str): try: mass = Mass(other) - return self * length + return self * mass except: raise ValueError( "Could not convert the string to a 'BioSimSpace.Mass' type." @@ -302,7 +302,7 @@ def _to_default_unit(self, mag=None): Returns ------- - length : :class:`Mass ` + mass : :class:`Mass ` The mass in the default unit of grams. """ if mag is None: @@ -323,7 +323,7 @@ def _convert_to(self, unit): Returns ------- - length : :class:`Mass ` + mass : :class:`Mass ` The mass in the specified unit. """ if unit == "KILOGRAM":