Source code for VeraGridEngine.Templates.Emt.nonlinear_resistor_emt_template

from __future__ import annotations

from typing import Sequence

import VeraGridEngine.Utils.Symbolic.symbolic as sym
from VeraGridEngine.Devices.Dynamic.emt_template import EmtModelTemplate
from VeraGridEngine.Devices.Dynamic.var_factory import VarFactory
from VeraGridEngine.Templates.BasicBlockCatalog.lookup_array_runtime_templates import _build_unclipped_lookup_expression
from VeraGridEngine.Templates.BasicBlockCatalog.lookup_array_runtime_templates import _validate_lookup_points
from VeraGridEngine.Templates.Emt.load_RLC_emt_template import _attach_combo_editor_diagram
from VeraGridEngine.Templates.Emt.load_RLC_emt_template import _build_external_mapping
from VeraGridEngine.Templates.Emt.load_RLC_emt_template import get_ground_emt_template
from VeraGridEngine.Utils.Symbolic.block import Block
from VeraGridEngine.Utils.Symbolic.symbolic import CmpOp, Comparison, Const, Expr, Var
from VeraGridEngine.enumerations import DeviceType, VarPowerFlowReferenceType


[docs] def get_nonlinear_resistor_emt_template( vf: VarFactory, voltage_points: Sequence[float], current_points: Sequence[float], name: str = "nonlinear_resistor_emt", ) -> EmtModelTemplate: """Build one ATP-like one-terminal nonlinear resistor EMT block. The block uses an odd-symmetric piecewise-linear `|v| -> |i|` curve and grounds the opposite terminal internally. :param vf: EMT variable factory. :param voltage_points: Non-negative voltage magnitudes. :param current_points: Matching current magnitudes. :param name: Symbolic block name. :return: Materialized EMT template. """ _validate_lookup_points(x_points=voltage_points, y_points=current_points) if float(voltage_points[0]) == 0.0 and float(current_points[0]) == 0.0: pass else: raise ValueError("Nonlinear resistor EMT requires the first V-I point to be (0, 0)") template: EmtModelTemplate = EmtModelTemplate() template.tpe = DeviceType.LoadDevice template.name = name template.block.name = name node_voltage_var: Var = vf.add_var(name=f"v_N_{name}", reference=VarPowerFlowReferenceType.v_N) current_var: Var = vf.add_var(name=f"i_N_{name}", reference=VarPowerFlowReferenceType.i_N) ground_node_var: Var = vf.add_var(name=f"v_gnd_{name}") abs_voltage_var: Var = vf.add_var(name=f"v_abs_{name}") one_const: Const = Const(1.0) zero_const: Const = Const(0.0) ground_template: EmtModelTemplate = get_ground_emt_template(vf=vf, name=name + "_ground") vf.add_connections(ground_template.block.in_vars, [ground_node_var]) ground_current_var: Var = ground_template.block.out_vars[0] voltage_drop: Expr = node_voltage_var - ground_node_var sign_selector: Expr = Comparison(lhs=voltage_drop, op=CmpOp.GE, rhs=zero_const).to_expression() x_vars: list[Var] = list() y_vars: list[Var] = list() point_index: int for point_index in range(len(voltage_points)): x_var = vf.add_var(name=f"arr_v{point_index + 1}_{name}") y_var = vf.add_var(name=f"arr_i{point_index + 1}_{name}") template.block.event_dict[x_var] = vf.add_const(float(voltage_points[point_index]), name=f"arr_v{point_index + 1}") template.block.event_dict[y_var] = vf.add_const(float(current_points[point_index]), name=f"arr_i{point_index + 1}") x_vars.append(x_var) y_vars.append(y_var) magnitude_expr: Expr = _build_unclipped_lookup_expression(yi_var=abs_voltage_var, x_vars=x_vars, y_vars=y_vars) signed_current_expr: Expr = magnitude_expr * (sign_selector - (one_const - sign_selector)) template.block.in_vars = [node_voltage_var] template.block.out_vars = [current_var] template.block.algebraic_vars = [ground_node_var, abs_voltage_var, current_var] template.block.init_eqs[ground_node_var] = zero_const template.block.init_eqs[abs_voltage_var] = sym.abs(voltage_drop) template.block.init_eqs[current_var] = signed_current_expr template.block.algebraic_eqs = [ abs_voltage_var - sym.abs(voltage_drop), current_var - signed_current_expr, ground_current_var + current_var, ] template.block.add(ground_template.block) template.block.external_mapping = _build_external_mapping( voltage_vars=dict(), current_vars=dict(), neutral_voltage_var=node_voltage_var, neutral_current_var=current_var, ) _attach_combo_editor_diagram( root_block=template.block, input_vars=[node_voltage_var], output_vars=[current_var], ground_block=ground_template.block, neutral_input_var=node_voltage_var, ) return template