193 lines
9.0 KiB
Python
193 lines
9.0 KiB
Python
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
|