from typing import List
from decimal import Decimal
import sqlalchemy as sql
from sqlalchemy.orm import (
mapped_column,
relationship,
Mapped,
)
from app.model.orm.orm_base import OrmBase
[docs]
PROPERTY_NAMES = {
'volume': 'volume',
'pressure': 'pressure',
'stirringMode': 'stirring mode',
'stirringSpeed': 'stirring speed',
'dilutionRate': 'dilution rate',
'O2': 'O<sub>2</sub>',
'CO2': 'CO<sub>2</sub>',
'H2': 'H<sub>2</sub>',
'N2': 'N<sub>2</sub>',
'inoculumConcentration': 'inoculum concentration',
'inoculumVolume': 'inoculum volume',
'initialPh': 'initial pH',
'initialTemperature': 'initial temperature',
}
"The human-readable names of the properties of a Compartment"
[docs]
PROPERTY_UNITS = {
'volume': 'mL',
'pressure': 'atm',
'stirringMode': '',
'stirringSpeed': 'rpm',
'dilutionRate': 'h<sup>-1</sup>',
'O2': '%',
'CO2': '%',
'H2': '%',
'N2': '%',
'inoculumConcentration': ' Cells/mL',
'inoculumVolume': 'mL',
'initialPh': '',
'initialTemperature': '°C',
}
"The units that properties of a Compartment are measured in"
[docs]
class Compartment(OrmBase):
"""
The environment of a particular bioreplicate.
There could be multiple of these within the same bioreplicate that form a
single biological system, but can be measured separately.
One compartment may change to a different compartment due to a
``Perturbation``.
In the future, this entity may be broken down into a separate "compartment"
and "environment".
"""
[docs]
__tablename__ = "Compartments"
[docs]
id: Mapped[int] = mapped_column(primary_key=True)
[docs]
name: Mapped[str] = mapped_column(sql.String(100), nullable=False)
# Note: convert to studyUniqueID or delete
[docs]
studyId: Mapped[str] = mapped_column(sql.ForeignKey('Studies.publicId'), nullable=False)
[docs]
study: Mapped['Study'] = relationship(back_populates='compartments')
[docs]
volume: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
pressure: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
stirringSpeed: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
stirringMode: Mapped[str] = mapped_column(sql.String(50), nullable=True)
[docs]
O2: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
CO2: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
H2: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
N2: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
inoculumConcentration: Mapped[Decimal] = mapped_column(sql.Numeric(20, 3), nullable=True)
[docs]
inoculumVolume: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
initialPh: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
initialTemperature: Mapped[Decimal] = mapped_column(sql.Numeric(7, 2), nullable=True)
[docs]
dilutionRate: Mapped[Decimal] = mapped_column(sql.Numeric(7, 3), nullable=True)
[docs]
mediumName: Mapped[str] = mapped_column(sql.String(100), nullable=True)
[docs]
mediumUrl: Mapped[str] = mapped_column(sql.String(100), nullable=True)
[docs]
experimentCompartments: Mapped[List['ExperimentCompartment']] = relationship(back_populates='compartment')
[docs]
experiments: Mapped[List['Experiment']] = relationship(
secondary="ExperimentCompartments",
viewonly=True
)
[docs]
measurementContexts: Mapped[List['MeasurementContext']] = relationship(back_populates='compartment')
[docs]
measurements: Mapped[List['Measurement']] = relationship(
order_by='Measurement.timeInSeconds',
secondary='MeasurementContexts',
viewonly=True,
)
@property
[docs]
def properties_description(self):
formatted_properties = []
for prop, name in PROPERTY_NAMES.items():
units = PROPERTY_UNITS[prop]
value = getattr(self, prop)
if value is None or value == '':
continue
formatted_properties.append(f"<strong>{value}{units}</strong> {name}")
return ', '.join(formatted_properties)
[docs]
def diff(self, other):
changes = []
for prop in PROPERTY_NAMES.keys():
value = getattr(self, prop)
other_value = getattr(other, prop)
if value != other_value:
changes.append((PROPERTY_NAMES[prop], value, other_value))
return changes