import json from reagent import Reagent VOLUME_UNITS = { 'нл': 0.001, # 1 нл = 0.001 мкл 'мкл': 1.0, # базовая единица объёма 'мл': 1000.0, # 1 мл = 1000 мкл 'л': 1000000.0 # 1 л = 1 000 000 мкл } MASS_UNITS = { 'нг': 0.000001, # 1 нг = 0.001 мкг 'мкг': 0.001, # базовая единица массы 'мг': 1.0, # 1 мг = 1000 мкг 'г': 1000.0, # 1 г = 1 000 000 мкг 'кг': 1000000.0 # 1 кг = 1 000 000 000 мкг } class Model: def __init__(self): self.total_amount = 100.0 # общее количество среды (по умолчанию — 1000 мл) self.amount_unit = 'мл' # единица измерения общего количества self.solvent = 'Вода' # растворитель по умолчанию self.reagents = [] # список реагентов def convert_amount(self, amount_base: float, target_unit: str, is_volume: bool) -> float: """ Пересчитывает количество из базовых единиц (мкл/мкг) в целевую единицу. """ if is_volume: conversion_factor = VOLUME_UNITS.get(target_unit, 1.0) else: conversion_factor = MASS_UNITS.get(target_unit, 1.0) return amount_base / conversion_factor def calculate_amounts(self) -> tuple: """ Рассчитывает: 1. Исходное количество реагента для неразбавленного состава 2. Количество разбавленного реагента, которое нужно взять 3. Количество растворителя с учётом добавленных разбавленных реагентов Возвращает: (список количеств разбавленных реагентов, количество растворителя, процент растворителя) """ results = [] # Проверяем, есть ли реагенты if not self.reagents: return results, self.total_amount, 100.0 # Суммируем проценты всех реагентов total_percentage = sum(reagent.percentage for reagent in self.reagents) # Проверяем, что сумма процентов не превышает 100 if total_percentage > 100: raise ValueError(f"Сумма процентов реагентов ({total_percentage:.2f}%) превышает 100%") # Шаг 1: Рассчитываем общий объём среды в базовых единицах (мкл) total_in_base = self.total_amount * VOLUME_UNITS[self.amount_unit] # Шаг 2: Рассчитываем количество каждого реагента для неразбавленного состава undiluted_amounts = [] for reagent in self.reagents: # Расчёт количества реагента в базовых единицах amount_in_base = (reagent.percentage / 100) * total_in_base # Определение типа единицы измерения реагента is_volume = reagent.unit in VOLUME_UNITS # Применение коэффициента пересчёта adjusted_amount = amount_in_base * reagent.conversion_factor # Пересчёт в целевую единицу измерения final_amount = self.convert_amount(adjusted_amount, reagent.unit, is_volume) undiluted_amounts.append(final_amount) # Шаг 3: Рассчитываем количество разбавленного реагента, которое нужно взять # и общий объём вносимых разбавленных реагентов (в базовых единицах) diluted_amounts = [] total_diluted_volume_base = 0 for i, reagent in enumerate(self.reagents): dilution_factor = getattr(reagent, 'dilution_factor', 1.0) if dilution_factor <= 0: dilution_factor = 1.0 # Количество разбавленного реагента = исходное количество / фактор разбавления diluted_amount = undiluted_amounts[i] * dilution_factor diluted_amounts.append(diluted_amount) # Вычисляем объём разбавленного реагента в базовых единицах (мкл) is_volume = reagent.unit in VOLUME_UNITS if is_volume: # Если реагент в объёмных единицах, его объём = diluted_amount reagent_volume_base = diluted_amount * VOLUME_UNITS[reagent.unit] else: # Если реагент в массовых единицах, считаем, что он вносит пренебрежимый объём # или можно добавить коэффициент плотности, пока игнорируем reagent_volume_base = 0 total_diluted_volume_base += reagent_volume_base # Шаг 4: Рассчитываем количество растворителя # Растворитель = общий объём - объём всех разбавленных реагентов solvent_volume_base = total_in_base - total_diluted_volume_base # Переводим количество растворителя в целевую единицу измерения solvent_amount = solvent_volume_base / VOLUME_UNITS[self.amount_unit] # Если объём реагентов превышает общий объём, корректируем if solvent_amount < 0: solvent_amount = 0 # Процент растворителя в неразбавленном составе solvent_percentage = 100 - total_percentage return diluted_amounts, solvent_amount, solvent_percentage def save_to_file(self, filename: str): """Сохраняет модель в JSON-файл""" data = { 'total_amount': self.total_amount, 'amount_unit': self.amount_unit, 'solvent': self.solvent, 'reagents': [ { 'name': r.name, 'percentage': r.percentage, 'unit': r.unit, 'conversion_factor': r.conversion_factor, 'dilution_factor': getattr(r, 'dilution_factor', 1.0) } for r in self.reagents ] } with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False, indent=4) def load_from_file(self, filename: str): """Загружает модель из JSON-файла""" with open(filename, 'r', encoding='utf-8') as f: data = json.load(f) self.total_amount = data['total_amount'] self.amount_unit = data['amount_unit'] self.solvent = data['solvent'] self.reagents.clear() for r_data in data['reagents']: reagent = Reagent( name=r_data['name'], percentage=r_data['percentage'], unit=r_data['unit'], conversion_factor=r_data.get('conversion_factor', 1.0) ) # Добавляем коэффициент разбавления reagent.dilution_factor = r_data.get('dilution_factor', 1.0) self.reagents.append(reagent) def add_reagent(self, name: str, percentage: float, unit: str, conversion_factor: float = 1.0, dilution_factor: float = 1.0): """Добавляет новый реагент в модель""" reagent = Reagent(name, percentage, unit, conversion_factor) reagent.dilution_factor = dilution_factor self.reagents.append(reagent) def remove_reagent(self, index: int): """Удаляет реагент по индексу""" if 0 <= index < len(self.reagents): del self.reagents[index] def clear_reagents(self): """Очищает список реагентов""" self.reagents.clear() def get_reagent_count(self) -> int: """Возвращает количество реагентов в модели""" return len(self.reagents) def set_total_amount(self, amount: float, unit: str): """Устанавливает общее количество среды и единицу измерения""" self.total_amount = amount self.amount_unit = unit def set_solvent(self, solvent_name: str): """Устанавливает название растворителя""" self.solvent = solvent_name