Initial commit: планирование эксперимента и оптимизация смесей
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
# plan.py
|
||||
"""
|
||||
Планирование эксперимента.
|
||||
Позволяет задать шаги для факторов, сгенерировать план различных типов,
|
||||
показать матрицу плана, экспериментальные смеси и сохранить дизайн в проект.
|
||||
"""
|
||||
from core.experiment import ExperimentDesign
|
||||
from core.fs import save_project_partial
|
||||
from core.doe import ze, ccp, fractional_factorial, plackett_burman, box_behnken
|
||||
from core.table_io import handle_table_output
|
||||
|
||||
def plan_menu(mixture, design):
|
||||
if design is None:
|
||||
design = ExperimentDesign()
|
||||
|
||||
while True:
|
||||
print("\n" + "=" * 50)
|
||||
print("ПЛАНИРОВАНИЕ ЭКСПЕРИМЕНТА")
|
||||
print("1. Задать шаги для факторов (ингредиентов, кроме растворителя)")
|
||||
print("2. Сгенерировать план (выбор типа)")
|
||||
print("3. Показать матрицу плана")
|
||||
print("4. Показать экспериментальные смеси (абсолютные значения)")
|
||||
print("5. Сохранить дизайн в проект")
|
||||
print("(Enter - выход в главное меню)")
|
||||
print("=" * 50)
|
||||
choice = input("Выберите пункт: ").strip()
|
||||
|
||||
if choice == "":
|
||||
break
|
||||
|
||||
if choice == "1":
|
||||
num_factors = len(mixture.ings) - 1
|
||||
if num_factors <= 0:
|
||||
print("В смеси нет изменяемых ингредиентов (только растворитель).")
|
||||
continue
|
||||
print(f"Введите шаги для {num_factors} факторов (в %). Введите 0, если фактор не используется:")
|
||||
steps = []
|
||||
for i in range(1, len(mixture.ings)):
|
||||
name = mixture.ings[i].name
|
||||
while True:
|
||||
val = input(f"Шаг для {name} (текущий % = {mixture.ings[i].value:.1f}): ")
|
||||
try:
|
||||
s = float(val)
|
||||
if s < 0:
|
||||
print("Шаг не может быть отрицательным. Введите 0 или положительное число.")
|
||||
continue
|
||||
steps.append(s)
|
||||
break
|
||||
except ValueError:
|
||||
print("Введите число.")
|
||||
design.set_steps(steps)
|
||||
active = design._active_steps()
|
||||
print(f"Шаги установлены. Активных факторов (шаг > 0): {len(active)}")
|
||||
if len(active) < 2:
|
||||
print("Предупреждение: для генерации плана необходимо минимум 2 активных фактора.")
|
||||
|
||||
elif choice == "2":
|
||||
active_steps = design._active_steps()
|
||||
if len(active_steps) < 2:
|
||||
print(f"Недостаточно активных факторов (шаг > 0): {len(active_steps)}. Требуется минимум 2.")
|
||||
continue
|
||||
k = len(active_steps)
|
||||
|
||||
print("\nВыберите тип плана:")
|
||||
print(" 1. Полный факторный план 2^k")
|
||||
print(" 2. Центральный композиционный план (ЦКП)")
|
||||
print(" 3. Дробный факторный план 2^(k-p)")
|
||||
print(" 4. План Плакетта-Бермана")
|
||||
print(" 5. План Бокса-Бенкена")
|
||||
plan_type = input("Ваш выбор (по умолчанию 1): ").strip()
|
||||
if plan_type == "":
|
||||
plan_type = "1"
|
||||
|
||||
if plan_type == "1":
|
||||
print(f"Активных факторов: {k}. Будет сгенерирован план 2^{k} = {2**k} опытов.")
|
||||
try:
|
||||
design.generate_plan()
|
||||
print(f"Основной план сгенерирован: {len(design.plan)} опытов.")
|
||||
except ValueError as e:
|
||||
print(f"Ошибка: {e}")
|
||||
continue
|
||||
|
||||
try:
|
||||
num_center = input("Введите количество дополнительных центральных точек (0, если не нужно): ").strip()
|
||||
if num_center == "":
|
||||
num_center = "0"
|
||||
num_center = int(num_center)
|
||||
if num_center < 0:
|
||||
print("Количество не может быть отрицательным.")
|
||||
elif num_center > 0:
|
||||
center_rows = ze(k, num_center)
|
||||
if center_rows:
|
||||
design.plan.extend(center_rows)
|
||||
print(f"Добавлено {num_center} центральных точек. Всего опытов: {len(design.plan)}")
|
||||
else:
|
||||
print("Ошибка генерации центральных точек.")
|
||||
except ValueError:
|
||||
print("Ошибка: введите целое число.")
|
||||
|
||||
elif plan_type == "2":
|
||||
print("Центральный композиционный план (ЦКП)")
|
||||
try:
|
||||
alpha_input = input("Введите значение альфа (звёздное плечо, по умолчанию 1.0): ").strip()
|
||||
alpha = float(alpha_input) if alpha_input else 1.0
|
||||
except ValueError:
|
||||
print("Ошибка ввода, используется alpha=1.0")
|
||||
alpha = 1.0
|
||||
|
||||
try:
|
||||
center_input = input("Введите количество центральных точек (по умолчанию 1): ").strip()
|
||||
center_points = int(center_input) if center_input else 1
|
||||
if center_points < 0:
|
||||
print("Количество не может быть отрицательным, установлено 1.")
|
||||
center_points = 1
|
||||
except ValueError:
|
||||
print("Ошибка ввода, используется 1 центральная точка.")
|
||||
center_points = 1
|
||||
|
||||
use_fractional = input("Использовать дробное ядро? (y/n, по умолчанию n): ").strip().lower()
|
||||
fractional = None
|
||||
if use_fractional == 'y':
|
||||
try:
|
||||
p = int(input("Введите степень дробления p (1 или больше): ").strip())
|
||||
if 0 < p < k:
|
||||
if k - p < 2:
|
||||
print(f"Ошибка: при k={k} и p={p} ядро будет содержать {k-p} факторов, что меньше 2. Используйте p <= {k-2}.")
|
||||
continue
|
||||
fractional = p
|
||||
print(f"Будет использовано дробное ядро 2^{k-p}.")
|
||||
else:
|
||||
print("Некорректное p, используем полное ядро.")
|
||||
except ValueError:
|
||||
print("Ошибка ввода, используем полное ядро.")
|
||||
|
||||
try:
|
||||
design.plan = ccp(k, alpha, center_points, fractional)
|
||||
if fractional:
|
||||
print(f"ЦКП с дробным ядром 2^{k-fractional} сгенерирован. Опытов: {len(design.plan)}")
|
||||
else:
|
||||
print(f"ЦКП с полным ядром сгенерирован. Опытов: {len(design.plan)}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка генерации ЦКП: {e}")
|
||||
|
||||
elif plan_type == "3":
|
||||
print("Дробный факторный план 2^(k-p)")
|
||||
try:
|
||||
p_input = input("Введите степень дробления p (по умолчанию 1): ").strip()
|
||||
p = int(p_input) if p_input else 1
|
||||
if p <= 0 or p >= k:
|
||||
print("p должно быть от 1 до k-1. Используем p=1.")
|
||||
p = 1
|
||||
if k - p < 2:
|
||||
print(f"Ошибка: при k={k} и p={p} ядро будет содержать {k-p} факторов, что меньше 2. Используйте p <= {k-2}.")
|
||||
continue
|
||||
design.plan = fractional_factorial(k, p)
|
||||
print(f"Дробный факторный план 2^{k-p} сгенерирован. Опытов: {len(design.plan)}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка: {e}")
|
||||
|
||||
elif plan_type == "4":
|
||||
print("План Плакетта-Бермана")
|
||||
try:
|
||||
design.plan = plackett_burman(k)
|
||||
print(f"План Плакетта-Бермана сгенерирован. Опытов: {len(design.plan)}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка: {e}")
|
||||
|
||||
elif plan_type == "5":
|
||||
print("План Бокса-Бенкена")
|
||||
try:
|
||||
if k < 3:
|
||||
print("План Бокса-Бенкена требует минимум 3 фактора.")
|
||||
continue
|
||||
design.plan = box_behnken(k)
|
||||
print(f"План Бокса-Бенкена сгенерирован. Опытов: {len(design.plan)}")
|
||||
except Exception as e:
|
||||
print(f"Ошибка: {e}")
|
||||
|
||||
else:
|
||||
print("Неверный тип плана. План не сгенерирован.")
|
||||
|
||||
elif choice == "3":
|
||||
if not design.plan:
|
||||
print("План не сгенерирован.")
|
||||
continue
|
||||
active_indices = design._active_indices()
|
||||
headers = ["Опыт"] + [mixture.ings[idx+1].name for idx in active_indices]
|
||||
rows = []
|
||||
for i, row in enumerate(design.plan, start=1):
|
||||
rows.append([str(i)] + [str(v) for v in row])
|
||||
handle_table_output(headers, rows, title="Матрица плана")
|
||||
|
||||
elif choice == "4":
|
||||
if not design.plan or not design.steps:
|
||||
print("План или шаги не заданы.")
|
||||
continue
|
||||
try:
|
||||
exp_mixtures = design.get_all_mixtures(mixture)
|
||||
headers = ["Опыт"] + [f"{info.name} ({info.unit})" for info in mixture.ings]
|
||||
rows = []
|
||||
for i, exp_mix in enumerate(exp_mixtures, start=1):
|
||||
abs_ings = exp_mix.get_absolute_ingredients()
|
||||
rows.append([str(i)] + [f"{ing.value:.2f}" for ing in abs_ings])
|
||||
handle_table_output(headers, rows, title="Экспериментальные смеси (абсолютные значения)")
|
||||
except Exception as e:
|
||||
print(f"Ошибка: {e}")
|
||||
|
||||
elif choice == "5":
|
||||
save_project_partial(design=design)
|
||||
print("Дизайн сохранён в проект.")
|
||||
|
||||
else:
|
||||
print("Неверный пункт.")
|
||||
|
||||
return design
|
||||
Reference in New Issue
Block a user