Files
help_lab/calculations/medium.py
T

212 lines
9.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Расчёт питательных сред
Этот модуль содержит функции для расчёта состава питательных сред
на основе процентов, коэффициентов конверсии и разбавления.
Основная функция: 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
}