"""Повторные токовые задачи на собственной геометрии; только штатный FEMM API."""
import math
from build import build
from physics import dq0_to_abc,abc_to_dq0

class FieldSession:
    def __init__(self,api,machine,winding,materials,folder,mesh):
        self.api=api;self.machine=machine;self.winding=winding;self.materials=materials
        self.folder=folder;self.mesh=mesh;self.templates={}
    def solve(self,theta,currents,stem):
        api=self.api
        if theta not in self.templates:
            template=self.folder+'/template-%03d.fem'%len(self.templates)
            build(api,self.machine,self.winding,self.materials,template,self.mesh,theta,(0,0,0))
            api['mi_close']();self.templates[theta]=template
        api['opendocument'](self.templates[theta])
        phase=dq0_to_abc([currents[0],currents[1],0],math.radians(theta))
        names=[p+str(b)+' — ветвь статора' for p in 'ABC' for b in (1,2)]+['F — возбуждение ротора']
        expected=[phase[k//2]/2 for k in range(6)]+[currents[2]]
        for name,current in zip(names,expected):api['mi_modifycircprop'](name,1,current)
        path=self.folder+'/'+stem+'.fem';api['mi_saveas'](path)
        # Reopen the exact saved model before solving; current modification never
        # borrows a solution or a geometry builder from the source project.
        api['mi_close']();api['opendocument'](path);api['mi_analyze'](1);api['mi_loadsolution']()
        circuits=[list(api['mo_getcircuitproperties'](n)) for n in names]
        for actual,wanted in zip(circuits,expected):
            if abs(actual[0]-wanted)>1e-7:raise ValueError('Ток сохранённой цепи не совпал')
        abc=[(circuits[2*k][2]+circuits[2*k+1][2])/2 for k in range(3)]
        dq=abc_to_dq0(abc,math.radians(theta))
        api['mo_groupselectblock']();w=api['mo_blockintegral'](2);wc=api['mo_blockintegral'](17);api['mo_clearblock']()
        ilambda=sum(v[0]*v[2] for v in circuits)
        error=abs(w+wc-ilambda)/max(abs(ilambda),1.)
        if error>1e-5:raise ValueError('Нарушен энергетический интеграл')
        api['mo_groupselectblock'](10);api['mo_groupselectblock'](11)
        force=[api['mo_blockintegral'](k) for k in (18,19,22)];api['mo_clearblock']()
        result={'theta_deg':theta,'currents_dqf_A':list(currents),'lambda_dqf_Wb':[dq[0],dq[1],circuits[-1][2]],
                'lambda_abc_Wb':abc,'energy_J':w,'coenergy_J':wc,'energy_identity_relative_error':error,
                'force_torque':force,'elements':api['mo_numelements']()}
        api['mo_close']();api['mi_close']();return result
