""" Расчёт питательных сред Этот модуль содержит функции для расчёта состава питательных сред на основе процентов, коэффициентов конверсии и разбавления. Основная функция: 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 }