From 3af0e496cb9399dc778c164104ddb21fc574503e Mon Sep 17 00:00:00 2001 From: Samuel Lopez <85613111+Samuelopez-ansys@users.noreply.github.com> Date: Mon, 7 Oct 2024 09:21:21 +0200 Subject: [PATCH] FEAT: Add SML component in Twin Builder (#5245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: chrpetre <108675940+chrpetre@users.noreply.github.com> Co-authored-by: Sébastien Morais <146729917+SMoraisAnsys@users.noreply.github.com> --- .../example_models/T34/Thermal_ROM_SML.sml | 196 ++++++++++++++++++ _unittest/test_34_TwinBuilder.py | 15 +- .../modeler/circuits/object_3d_circuit.py | 2 +- .../circuits/primitives_twin_builder.py | 113 ++++++++++ 4 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 _unittest/example_models/T34/Thermal_ROM_SML.sml diff --git a/_unittest/example_models/T34/Thermal_ROM_SML.sml b/_unittest/example_models/T34/Thermal_ROM_SML.sml new file mode 100644 index 00000000000..590b51575df --- /dev/null +++ b/_unittest/example_models/T34/Thermal_ROM_SML.sml @@ -0,0 +1,196 @@ +SMLDEF Thermal_ROM_SML +{ + + PORT real in : Input1_InternalHeatGeneration; + PORT real in : Input2_HeatFlow; + + PORT real in : Ref1_Temp1 = 2.951500e+02; + PORT real in : Ref2_Temp2 = 2.951500e+02; + + PORT real out : Output1_Temp1 = sssm.OutVec[0]; + PORT real out : Output2_Temp2 = sssm.OutVec[1]; + + INTERN NCStateSpaceModel sssm + ( + NumOutputs := 2, NumInputs := 4, + InVec[0] := Input1_InternalHeatGeneration , + InVec[1] := Input2_HeatFlow , + InVec[2] := Ref1_Temp1 , + InVec[3] := Ref2_Temp2 , + NumStates := 16 , + Mode := 3 , + A_row := + 0 + 1 + 3 + 5 + 6 + 7 + 9 + 11 + 12 + 13 + 14 + 15 + 16 + 18 + 20 + 21 + , + A_col := + 0 + 1 + 2 + 1 + 2 + 3 + 4 + 5 + 6 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 12 + 13 + 14 + 15 + , + A_NonZeros := 22 + , + MatrixA := + -1.088280e-01 + 0.000000e+00 + 1.000000e+00 + -6.578639e-03 + -6.795586e-03 + -4.334062e-03 + -1.719193e+00 + 0.000000e+00 + 1.000000e+00 + -8.089552e-04 + -3.902651e-03 + -4.524139e-03 + -1.185993e+00 + -9.632427e-02 + -4.795756e-03 + -4.318334e-03 + 0.000000e+00 + 1.000000e+00 + -3.008413e-03 + -1.904252e-03 + -4.033259e-03 + -2.004892e-02 + , + B_row := + 0 + 1 + 1 + 2 + 3 + 4 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 10 + 11 + 12 + , + B_col := + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + , + B_NonZeros := 13 + , + MatrixB := + 1.569859e-08 + 1.569859e-08 + 1.569859e-08 + 5.000000e-01 + 5.000000e-01 + 5.000000e-01 + 1.569859e-08 + 1.569859e-08 + 1.569859e-08 + 1.569859e-08 + 5.000000e-01 + 5.000000e-01 + 5.000000e-01 + , + C_row := + 0 + 8 + , + C_col := + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + , + C_NonZeros := 16 + , + MatrixC := + 1.577107e-02 + -6.230525e-06 + -1.732583e-05 + 5.174927e-03 + 1.763584e+00 + 2.605549e-06 + 5.971550e-05 + 1.493263e-03 + 9.628570e-01 + 1.471336e-02 + 2.037277e-04 + 5.018707e-03 + 2.093970e-06 + 1.080787e-04 + 1.238091e-03 + 9.353277e-04 + , + D_row := + 0 + 1 + , + D_col := + 2 + 3 + , + D_NonZeros := 2 + , + MatrixD := + 1.000000e+00 + 1.000000e+00 + ); +} diff --git a/_unittest/test_34_TwinBuilder.py b/_unittest/test_34_TwinBuilder.py index aedf482dd33..64d92f4009a 100644 --- a/_unittest/test_34_TwinBuilder.py +++ b/_unittest/test_34_TwinBuilder.py @@ -145,7 +145,7 @@ def test_14_set_variable(self): assert "var_test" in self.aedtapp.variable_manager.design_variable_names assert self.aedtapp.variable_manager.design_variables["var_test"].expression == "234" - def test_19_add_dynamic_link(self, add_app): + def test_15_add_dynamic_link(self, add_app): tb = add_app(application=TwinBuilder, project_name=self.dynamic_link, design_name="CableSystem", just_open=True) assert tb.add_q3d_dynamic_component( "Q2D_ArmouredCableExample", "2D_Extractor_Cable", "MySetupAuto", "sweep1", "Original", model_depth="100mm" @@ -203,3 +203,16 @@ def test_19_add_dynamic_link(self, add_app): tb.add_q3d_dynamic_component( "invalid", "2D_Extractor_Cable", "MySetupAuto", "sweep1", "Original", model_depth="100mm" ) + + def test_16_add_sml_component(self, local_scratch): + self.aedtapp.insert_design("SML") + input_file = local_scratch.copyfile( + os.path.join(local_path, "../_unittest/example_models", test_subfolder, "Thermal_ROM_SML.sml") + ) + pins_names = ["Input1_InternalHeatGeneration", "Input2_HeatFlow", "Output1_Temp1,Output2_Temp2"] + assert self.aedtapp.modeler.schematic.create_component_from_sml( + input_file=input_file, model="Thermal_ROM_SML", pins_names=pins_names + ) + rom1 = self.aedtapp.modeler.schematic.create_component("ROM1", "", "Thermal_ROM_SML") + + assert self.aedtapp.modeler.schematic.update_quantity_value(rom1.composed_name, "Input2_HeatFlow", "1") diff --git a/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py b/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py index 1042b54d5d9..268d6eff8eb 100644 --- a/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py +++ b/src/ansys/aedt/core/modeler/circuits/object_3d_circuit.py @@ -624,7 +624,7 @@ def pins(self): elif not pins: return [] for pin in pins: - if self._circuit_components._app.design_type != "Twin Builder": + if self._circuit_components._app.design_type: self._pins.append(CircuitPins(self, pin, idx)) elif pin not in list(self.parameters.keys()): self._pins.append(CircuitPins(self, pin, idx)) diff --git a/src/ansys/aedt/core/modeler/circuits/primitives_twin_builder.py b/src/ansys/aedt/core/modeler/circuits/primitives_twin_builder.py index 7b4f2e5ad14..6cbea886090 100644 --- a/src/ansys/aedt/core/modeler/circuits/primitives_twin_builder.py +++ b/src/ansys/aedt/core/modeler/circuits/primitives_twin_builder.py @@ -475,3 +475,116 @@ def create_periodic_waveform_source( id.set_property("PERIO", 1) return id + + @pyaedt_function_handler() + def create_component_from_sml( + self, + input_file, + model, + pins_names, + ): + """Create and place a new component based on a .sml file. + + Parameters + ---------- + input_file : str + Path to .sml file. + model : str + Model name to import. + pins_names : list + List of model pins names. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + Examples + -------- + >>> from ansys.aedt.core import TwinBuilder + >>> tb = TwinBuilder(version="2025.1") + >>> input_file = os.path.join("Your path", "test.sml") + >>> model = "Thermal_ROM_SML" + >>> pins_names = ["Input1_InternalHeatGeneration", "Input2_HeatFlow", "Output1_Temp1,Output2_Temp2"] + >>> tb.modeler.schematic.create_component_from_sml(input_file=model, model=model, pins_names=pins_names) + >>> tb.release_desktop(False, False) + """ + pins_names_str = ",".join(pins_names) + arg = ["NAME:Options", "Mode:=", 1] + arg2 = ["NAME:Models", model + ":=", [True]] + + arg3 = [ + "NAME:Components", + model + ":=", + [True, True, model, True, pins_names_str.lower(), pins_names_str.lower()], + ] + + arg.append(arg2) + arg.append(arg3) + self.o_component_manager.ImportModelsFromFile(input_file, arg) + return True + + @pyaedt_function_handler() + def update_quantity_value(self, component_name, name, value, netlist_units=""): + """Change the property value of a component. + + Parameters + ---------- + component_name : str + Component name. + name : str + Property name. + value : str + Value of the quantity. + netlist_units : str, optional + Value of the netlist unit. + + Returns + ------- + bool + ``True`` when successful, ``False`` when failed. + + Examples + -------- + >>> from ansys.aedt.core import TwinBuilder + >>> tb = TwinBuilder(version="2025.1") + >>> G = 0.00254 + >>> modelpath = "Simplorer Elements\\Basic Elements\\Tools\\Time Functions:DATAPAIRS" + >>> source1 = tb.modeler.schematic.create_component("source1", "", modelpath, [20 * G, 29 * G]) + >>> tb.modeler.schematic.update_quantity_value(source1.composed_name, "PERIO", "0") + >>> tb.release_desktop(False, False) + """ + try: + self.oeditor.ChangeProperty( + [ + "NAME:AllTabs", + [ + "NAME:Quantities", + ["NAME:PropServers", component_name], + [ + "NAME:ChangedProps", + [ + "NAME:" + name, + "OverridingDef:=", + True, + "Value:=", + value, + "NetlistUnits:=", + netlist_units, + "ShowPin:=", + False, + "Display:=", + False, + "Sweep:=", + False, + "SDB:=", + False, + ], + ], + ], + ] + ) + return True + except Exception: # pragma: no cover + self.logger.warning(f"Property {name} has not been edited. Check if readonly.") + return False