212 lines
9.2 KiB
Python
212 lines
9.2 KiB
Python
"""
|
||
Расчёт питательных сред
|
||
|
||
Этот модуль содержит функции для расчёта состава питательных сред
|
||
на основе процентов, коэффициентов конверсии и разбавления.
|
||
|
||
Основная функция: calculate_medium_composition()
|
||
"""
|
||
|
||
from typing import List, Dict, Tuple
|
||
|
||
# Константы для конверсии единиц измерения
|
||
# Базовые единицы: мкл для объёма, мг для массы
|
||
VOLUME_UNITS = {
|
||
'нл': 0.001, # нанолитры -> микролитры
|
||
'мкл': 1.0, # микролитры (база)
|
||
'мл': 1000.0, # миллилитры -> микролитры
|
||
'л': 1000000.0, # литры -> микролитры
|
||
}
|
||
|
||
MASS_UNITS = {
|
||
'нг': 0.000001, # нанограммы -> миллиграммы
|
||
'мкг': 0.001, # микрограммы -> миллиграммы
|
||
'мг': 1.0, # миллиграммы (база)
|
||
'г': 1000.0, # граммы -> миллиграммы
|
||
'кг': 1000000.0, # килограммы -> миллиграммы
|
||
}
|
||
|
||
|
||
def convert_units(value: float, from_unit: str, to_unit: str = None) -> float:
|
||
"""
|
||
Конвертирует значение между единицами объёма или массы
|
||
|
||
Параметры:
|
||
value: числовое значение
|
||
from_unit: исходная единица (например "мл" или "мг")
|
||
to_unit: целевая единица (если None, конвертирует в базовую)
|
||
|
||
Возвращает:
|
||
float: сконвертированное значение
|
||
|
||
Пример:
|
||
>>> convert_units(100, 'мл') # конвертирует в базовую (мкл)
|
||
100000.0
|
||
>>> convert_units(500, 'мкл', 'мл')
|
||
0.5
|
||
"""
|
||
# Определяем тип единицы (объём или масса)
|
||
if from_unit in VOLUME_UNITS:
|
||
units_map = VOLUME_UNITS
|
||
elif from_unit in MASS_UNITS:
|
||
units_map = MASS_UNITS
|
||
else:
|
||
raise ValueError(f"Неизвестная единица измерения: {from_unit}")
|
||
|
||
# Конвертируем в базовую единицу (мкл для объёма, мг для массы)
|
||
value_in_base = value * units_map[from_unit]
|
||
|
||
# Если нужна конвертация в другую единицу
|
||
if to_unit and to_unit in units_map:
|
||
return value_in_base / units_map[to_unit]
|
||
|
||
return value_in_base
|
||
|
||
|
||
def calculate_medium_composition(
|
||
total_volume: float,
|
||
volume_unit: str,
|
||
reagents: List[Dict],
|
||
solvent_name: str = "Вода"
|
||
) -> Dict:
|
||
"""
|
||
РАССЧИТЫВАЕТ СОСТАВ ПИТАТЕЛЬНОЙ СРЕДЫ
|
||
|
||
Эта функция является основной для расчёта питательных сред.
|
||
|
||
ВХОДНЫЕ ПАРАМЕТРЫ:
|
||
---------------
|
||
total_volume : float
|
||
Общий объём/количество среды (например 1000)
|
||
|
||
volume_unit : str
|
||
Единица измерения общего объёма: "нл", "мкл", "мл", "л"
|
||
|
||
reagents : List[Dict]
|
||
Список реагентов. Каждый реагент - словарь с ключами:
|
||
- name (str): название реагента
|
||
- percentage (float): процентное содержание в среде (0-100)
|
||
- unit (str): единица измерения реагента (нг, мкг, мг, г, кг, нл, мкл, мл, л)
|
||
- dilution_factor (float): фактор разбавления (необяз., по умолч. 1.0)
|
||
|
||
Пример реагента:
|
||
{
|
||
'name': 'Глюкоза',
|
||
'percentage': 2.5,
|
||
'unit': 'г',
|
||
'dilution_factor': 1.0
|
||
}
|
||
|
||
solvent_name : str, optional
|
||
Название растворителя (по умолчанию "Вода")
|
||
|
||
ВОЗВРАЩАЕМЫЙ СЛОВАРЬ:
|
||
--------------------
|
||
{
|
||
'total_volume': float, # Исходный объём
|
||
'total_unit': str, # Единица измерения
|
||
'solvent_name': str, # Название растворителя
|
||
'solvent_volume': float, # Объём растворителя
|
||
'solvent_percentage': float, # Процент растворителя
|
||
'reagents': List[Dict] # Список реагентов с рассчитанными количествами
|
||
}
|
||
|
||
Каждый реагент в возвращаемом списке содержит:
|
||
- все исходные поля
|
||
- calculated_amount (float): рассчитанное количество реагента
|
||
- undiluted_amount (float): количество до разбавления
|
||
- amount_unit (str): единица измерения (скопирована из unit)
|
||
|
||
ПРИМЕР ИСПОЛЬЗОВАНИЯ (в CLI):
|
||
-----------------------------
|
||
>>> reagents = [
|
||
... {'name': 'Глюкоза', 'percentage': 2.0, 'unit': 'г', 'conversion_factor': 1.0},
|
||
... {'name': 'Пептон', 'percentage': 1.0, 'unit': 'г', 'conversion_factor': 1.0}
|
||
... ]
|
||
>>> result = calculate_medium_composition(1000, 'мл', reagents)
|
||
>>> print(f"Растворитель: {result['solvent_volume']} мл")
|
||
Растворитель: 970.0 мл
|
||
>>> for r in result['reagents']:
|
||
... print(f"{r['name']}: {r['calculated_amount']} {r['unit']}")
|
||
Глюкоза: 20.0 г
|
||
Пептон: 10.0 г
|
||
"""
|
||
|
||
# Проверка входных данных
|
||
|
||
if total_volume <= 0:
|
||
raise ValueError(f"Общий объём должен быть положительным: {total_volume}")
|
||
|
||
if volume_unit not in VOLUME_UNITS:
|
||
raise ValueError(f"Неизвестная единица объёма: {volume_unit}")
|
||
|
||
# Суммируем проценты всех реагентов
|
||
total_percentage = sum(r.get('percentage', 0) for r in reagents)
|
||
|
||
if total_percentage > 100:
|
||
raise ValueError(
|
||
f"Сумма процентов ({total_percentage:.2f}%) превышает 100%"
|
||
)
|
||
|
||
# Конвертируем общий объём в базовую единицу (мкл)
|
||
total_base = convert_units(total_volume, volume_unit)
|
||
|
||
results = []
|
||
total_diluted_volume_base = 0 # объём разбавленных реагентов в мкл
|
||
|
||
for reagent in reagents:
|
||
# Извлекаем параметры с значениями по умолчанию
|
||
percentage = reagent.get('percentage', 0)
|
||
unit = reagent.get('unit', 'мг')
|
||
# print ("unit = ",unit)
|
||
# conversion_factor = reagent.get('conversion_factor', 1.0)
|
||
dilution_factor = reagent.get('dilution_factor', 1.0)
|
||
|
||
# Проверяем, является ли реагент жидкостью (объём) или твёрдым веществом (масса)
|
||
is_volume = unit in VOLUME_UNITS
|
||
|
||
# 1. Объём реагента в среде (исходя из процента)
|
||
amount_in_base = (percentage / 100) * total_base
|
||
# print ("amount_in_base = ",amount_in_base)
|
||
# 2. Применяем коэффициент конверсии
|
||
# adjusted_amount_base = amount_in_base * conversion_factor
|
||
|
||
# 3. Конвертируем в нужную единицу (без учёта разбавления)
|
||
# undiluted_amount = convert_units(adjusted_amount_base, volume_unit, unit)
|
||
undiluted_amount = convert_units(amount_in_base, 'мкл', unit)
|
||
# print ("volume_unit = ",volume_unit)
|
||
|
||
# 4. Применяем разбавление
|
||
if dilution_factor <= 0:
|
||
dilution_factor = 1.0
|
||
diluted_amount = undiluted_amount * dilution_factor
|
||
# print ("diluted_amount = ", diluted_amount)
|
||
# 5. Для объёмных реагентов учитываем в расчёте растворителя
|
||
if is_volume:
|
||
reagent_volume_base = convert_units(diluted_amount, unit)
|
||
total_diluted_volume_base += reagent_volume_base
|
||
|
||
# Сохраняем результат
|
||
reagent_result = reagent.copy()
|
||
reagent_result['calculated_amount'] = diluted_amount
|
||
reagent_result['undiluted_amount'] = undiluted_amount
|
||
reagent_result['amount_unit'] = unit
|
||
results.append(reagent_result)
|
||
|
||
# Рассчитываем объём растворителя
|
||
solvent_volume_base = total_base - total_diluted_volume_base
|
||
if solvent_volume_base < 0:
|
||
solvent_volume_base = 0
|
||
|
||
solvent_volume = convert_units(solvent_volume_base, 'мкл', volume_unit)
|
||
solvent_percentage = 100 - total_percentage
|
||
|
||
return {
|
||
'total_volume': total_volume,
|
||
'total_unit': volume_unit,
|
||
'solvent_name': solvent_name,
|
||
'solvent_volume': solvent_volume,
|
||
'solvent_percentage': solvent_percentage,
|
||
'reagents': results
|
||
}
|