"""Два официальных эталона, повторённых в FEMM5: точный момент и TEAM28.
Используются учебные torque-benchmark-course.fem и team28-course.fem с русскими именами свойств.
Диполь: m=1Ам²,B=1Тл; изменяется внутренний угол AGE без пересоздания сетки.
TEAM28: только установившаяся гармоническая сила при измеренной высоте11.3мм,
не полная переходная задача. Историческую силу автора не используем как ответ.
"""

# Каталог сценария определяется явно: запуск не зависит от чужого CWD.
import os
import sys

os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
exec(open("common.py").read())
folder = result_folder("results-dipole-team28")
data = {"dipole": [], "team28": []}
for angle in [0, 30, 60, 90, 180, 270, 360]:
    opendocument(os.path.abspath("torque-benchmark-course.fem"))
    mi_modifyboundprop("Воздушный зазор AGE", 10, angle)
    solve(folder, "dipole-%d" % angle)
    torque = mo_gapintegral("Воздушный зазор AGE", 0)[0]
    exact = math.sin(angle * math.pi / 180)
    data["dipole"].append(
        {
            "angle_deg": angle,
            "torque_Nm": torque,
            "exact_Nm": exact,
            "absolute_error_Nm": abs(torque - exact),
            "elements": mo_numelements(),
        }
    )
    close_magnetic()
    save_json(folder, data)
for mesh_cm, boundary_name, radius_cm in [
    (0.125, "Asymptotic", 12),
    (0.0625, "Asymptotic", 12),
    (0.0625, "A0", 12),
    (0.0625, "A0", 24),
]:
    opendocument(os.path.abspath("team28-course.fem"))
    if boundary_name == "A0":
        # Меняется только физическое свойство внешней дуги.
        mi_modifyboundprop("Асимптотическая внешняя граница", 9, 0)
    if radius_cm != 12:
        # Увеличиваем только внешнюю дугу и два её осевых узла.
        # Катушки, диск, метки и заданная ближняя плотность сетки не меняются.
        mi_selectarcsegment(12, 0)
        mi_setgroup(99)
        mi_clearselected()
        mi_selectnode(0, -12)
        mi_selectnode(0, 12)
        mi_setgroup(99)
        mi_clearselected()
        mi_selectgroup(99)
        mi_scale(0, 0, radius_cm / 12, 4)
        mi_clearselected()
    # Размеры исходного файла в сантиметрах, ток20А — амплитуда.
    for r, z, name, turns in [
        (0.9, -0.1, "Воздух", 0),
        (4.2, -0.1, "Обмотка", 960),
        (8.8, 0.3, "Обмотка", -576),
        (3.89, 3.92, "Aluminum", 0),
    ]:
        # Имена исходного материала диска читаются непосредственно ниже.
        if name == "Aluminum":
            continue
        mi_selectlabel(r, z)
        mi_setblockprop(name, 0, mesh_cm, "Ток возбуждения" if turns else "<None>", 0, 0, turns)
        mi_clearselected()
    mi_selectlabel(3.89, 3.92)
    mi_setblockprop("Алюминиевый диск", 0, mesh_cm, "<None>", 0, 2, 0)
    mi_clearselected()
    solve(folder, "team28-%s-R%d-mesh-%g" % (boundary_name, radius_cm, mesh_cm))
    mo_selectblock(3.89, 3.92)
    data["team28"].append(
        {
            "mesh_cm": mesh_cm,
            "boundary": boundary_name,
            "outer_radius_cm": radius_cm,
            "Lorentz_Fz_N": mo_blockintegral(12).real,
            "WST_Fz_N": mo_blockintegral(19).real,
            "disc_power_W": mo_blockintegral(4).real,
            "weight_N": 0.107 * 9.80665,
            "elements": mo_numelements(),
        }
    )
    close_magnetic()
    save_json(folder, data)
assert max(x["absolute_error_Nm"] for x in data["dipole"]) < 0.002
print(data)
