From 2ca40633fa4342cec10192bec0ba19862307153d Mon Sep 17 00:00:00 2001 From: "Zink, Zephyr" Date: Thu, 15 Jan 2026 14:45:21 -0700 Subject: [PATCH 1/5] voltage type comprehension, safe naming for opendss, recloser addition, floating point symmetry issue --- src/ditto/writers/opendss/__init__.py | 7 +++++ .../opendss/components/distribution_branch.py | 6 ++-- .../opendss/components/distribution_bus.py | 2 +- .../components/distribution_capacitor.py | 4 +-- .../opendss/components/distribution_load.py | 4 +-- .../components/distribution_regulator.py | 8 ++--- .../opendss/components/distribution_solar.py | 4 +-- .../components/distribution_transformer.py | 8 ++--- .../components/distribution_vsource.py | 19 +++++++++--- .../opendss/components/geometry_branch.py | 4 ++- .../components/matrix_impedance_branch.py | 4 ++- .../components/matrix_impedance_fuse.py | 7 ++++- .../components/matrix_impedance_recloser.py | 30 +++++++++++++++++++ .../components/matrix_impedance_switch.py | 4 ++- .../components/sequence_impedance_branch.py | 4 ++- .../distribution_regulator_controller.py | 6 ++-- .../equipment/bare_conductor_equipment.py | 2 +- .../distribution_transformer_equipment.py | 4 ++- .../equipment/geometry_branch_equipment.py | 6 ++-- .../matrix_impedance_branch_equipment.py | 20 ++++++++++--- .../matrix_impedance_recloser_equipment.py | 21 +++++++++++++ .../sequence_impedance_branch_equipment.py | 2 +- src/ditto/writers/opendss/write.py | 6 +++- 23 files changed, 142 insertions(+), 40 deletions(-) create mode 100644 src/ditto/writers/opendss/components/matrix_impedance_recloser.py create mode 100644 src/ditto/writers/opendss/equipment/matrix_impedance_recloser_equipment.py diff --git a/src/ditto/writers/opendss/__init__.py b/src/ditto/writers/opendss/__init__.py index b22cfbc..ee0c28a 100644 --- a/src/ditto/writers/opendss/__init__.py +++ b/src/ditto/writers/opendss/__init__.py @@ -34,3 +34,10 @@ ) from ditto.writers.opendss.profile import ProfileMapper from ditto.writers.opendss.components.distribution_solar import DistributionSolarMapper + +from ditto.writers.opendss.components.matrix_impedance_recloser import ( + MatrixImpedanceRecloserMapper, +) +from ditto.writers.opendss.equipment.matrix_impedance_recloser_equipment import ( + MatrixImpedanceRecloserEquipmentMapper, +) diff --git a/src/ditto/writers/opendss/components/distribution_branch.py b/src/ditto/writers/opendss/components/distribution_branch.py index 1e0a2ca..e3baac4 100644 --- a/src/ditto/writers/opendss/components/distribution_branch.py +++ b/src/ditto/writers/opendss/components/distribution_branch.py @@ -16,11 +16,11 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_buses(self): - self.opendss_dict["Bus1"] = self.model.buses[0].name - self.opendss_dict["Bus2"] = self.model.buses[1].name + self.opendss_dict["Bus1"] = self.model.buses[0].name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus2"] = self.model.buses[1].name.replace(" ", "_").replace(".", "_") for phase in self.model.phases: if phase != Phase.N: self.opendss_dict["Bus1"] += self.phase_map[phase] diff --git a/src/ditto/writers/opendss/components/distribution_bus.py b/src/ditto/writers/opendss/components/distribution_bus.py index 5c32a55..d77ea9b 100644 --- a/src/ditto/writers/opendss/components/distribution_bus.py +++ b/src/ditto/writers/opendss/components/distribution_bus.py @@ -14,7 +14,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.COORDINATE_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_coordinate(self): if hasattr(self.model.coordinate, "x"): diff --git a/src/ditto/writers/opendss/components/distribution_capacitor.py b/src/ditto/writers/opendss/components/distribution_capacitor.py index 2e76933..d8e832e 100644 --- a/src/ditto/writers/opendss/components/distribution_capacitor.py +++ b/src/ditto/writers/opendss/components/distribution_capacitor.py @@ -19,10 +19,10 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_bus(self): - self.opendss_dict["Bus1"] = self.model.bus.name + self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") num_phases = len(self.model.phases) for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] diff --git a/src/ditto/writers/opendss/components/distribution_load.py b/src/ditto/writers/opendss/components/distribution_load.py index 49ae2fa..73567f4 100644 --- a/src/ditto/writers/opendss/components/distribution_load.py +++ b/src/ditto/writers/opendss/components/distribution_load.py @@ -20,7 +20,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") profile_name = self.get_profile_name(self.model) if profile_name: @@ -28,7 +28,7 @@ def map_name(self): def map_bus(self): num_phases = len(self.model.phases) - self.opendss_dict["Bus1"] = self.model.bus.name + self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] # TODO: Should we include the phases its connected to here? diff --git a/src/ditto/writers/opendss/components/distribution_regulator.py b/src/ditto/writers/opendss/components/distribution_regulator.py index f5e81dd..b7ad15b 100644 --- a/src/ditto/writers/opendss/components/distribution_regulator.py +++ b/src/ditto/writers/opendss/components/distribution_regulator.py @@ -17,7 +17,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_buses(self): buses = [] @@ -27,7 +27,7 @@ def map_buses(self): if is_center_tapped: for i in range(len(self.model.buses)): bus = self.model.buses[i] - buses.append(bus.name) + buses.append(bus.name.replace(" ", "_").replace(".", "_")) dss_phases = "" for phase in self.model.winding_phases[0]: dss_phases += self.phase_map[phase] @@ -37,7 +37,7 @@ def map_buses(self): else: for bus in self.model.buses: - buses.append(bus.name) + buses.append(bus.name.replace(" ", "_").replace(".", "_")) for winding_phases in self.model.winding_phases: dss_phases = "" for phase in winding_phases: @@ -54,7 +54,7 @@ def map_winding_phases(self): def map_equipment(self): equipment = self.model.equipment - self.opendss_dict["XfmrCode"] = equipment.name + self.opendss_dict["XfmrCode"] = equipment.name.replace(" ", "_").replace(".", "_") def map_controllers(self): ... diff --git a/src/ditto/writers/opendss/components/distribution_solar.py b/src/ditto/writers/opendss/components/distribution_solar.py index 1ade817..f999efa 100644 --- a/src/ditto/writers/opendss/components/distribution_solar.py +++ b/src/ditto/writers/opendss/components/distribution_solar.py @@ -18,7 +18,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") profile_name = self.get_profile_name(self.model) if profile_name: @@ -26,7 +26,7 @@ def map_name(self): def map_bus(self): num_phases = len(self.model.phases) - self.opendss_dict["Bus1"] = self.model.bus.name + self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] # TODO: Should we include the phases its connected to here? diff --git a/src/ditto/writers/opendss/components/distribution_transformer.py b/src/ditto/writers/opendss/components/distribution_transformer.py index f860599..7ad5443 100644 --- a/src/ditto/writers/opendss/components/distribution_transformer.py +++ b/src/ditto/writers/opendss/components/distribution_transformer.py @@ -18,7 +18,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_buses(self): buses = [] @@ -28,7 +28,7 @@ def map_buses(self): if is_center_tapped: for i in range(len(self.model.buses)): bus = self.model.buses[i] - buses.append(bus.name) + buses.append(bus.name.replace(" ", "_").replace(".", "_")) dss_phases = "" for phase in self.model.winding_phases[0]: dss_phases += self.phase_map[phase] @@ -38,7 +38,7 @@ def map_buses(self): else: for bus in self.model.buses: - buses.append(bus.name) + buses.append(bus.name.replace(" ", "_").replace(".", "_")) for winding_phases in self.model.winding_phases: dss_phases = "" for phase in winding_phases: @@ -55,4 +55,4 @@ def map_winding_phases(self): def map_equipment(self): equipment = self.model.equipment - self.opendss_dict["XfmrCode"] = equipment.name + self.opendss_dict["XfmrCode"] = equipment.name.replace(" ", "_").replace(".", "_") diff --git a/src/ditto/writers/opendss/components/distribution_vsource.py b/src/ditto/writers/opendss/components/distribution_vsource.py index 1dddd56..65ca05a 100644 --- a/src/ditto/writers/opendss/components/distribution_vsource.py +++ b/src/ditto/writers/opendss/components/distribution_vsource.py @@ -19,14 +19,14 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") profile_name = self.get_profile_name(self.model) if profile_name: self.opendss_dict["Yearly"] = profile_name def map_bus(self): - self.opendss_dict["Bus1"] = self.model.bus.name + self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] @@ -59,7 +59,7 @@ def map_equipment(self): voltage = voltage.to("kilovolt") rated_voltage = rated_voltage.to("kilovolt") angle = angle.to("degree") - + print(voltage.magnitude, rated_voltage.magnitude, self.model.bus.voltage_type) if self.model.equipment.sources[0].voltage_type == VoltageTypes.LINE_TO_GROUND: if num_phases == 1: v_mag = voltage.magnitude @@ -71,9 +71,20 @@ def map_equipment(self): else: v_mag = voltage.magnitude - v_nom = rated_voltage.magnitude if num_phases == 1 else rated_voltage.magnitude * 1.732 + if self.model.bus.voltage_type == VoltageTypes.LINE_TO_GROUND: + if num_phases == 1: + v_nom = rated_voltage.magnitude + else: + v_nom = rated_voltage.magnitude * 1.732 + else: + if num_phases == 1: + v_nom = rated_voltage.magnitude / 1.732 + else: + v_nom = rated_voltage.magnitude + self.opendss_dict["Angle"] = angle.magnitude self.opendss_dict["pu"] = v_mag / v_nom + print(v_nom) self.opendss_dict["BasekV"] = v_nom self.opendss_dict["Z0"] = complex(r0.magnitude, x0.magnitude) self.opendss_dict["Z1"] = complex(r1.magnitude, x1.magnitude) diff --git a/src/ditto/writers/opendss/components/geometry_branch.py b/src/ditto/writers/opendss/components/geometry_branch.py index 606c8fe..a87795a 100644 --- a/src/ditto/writers/opendss/components/geometry_branch.py +++ b/src/ditto/writers/opendss/components/geometry_branch.py @@ -15,7 +15,9 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["Geometry"] = self.model.equipment.name + self.opendss_dict["Geometry"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/components/matrix_impedance_branch.py b/src/ditto/writers/opendss/components/matrix_impedance_branch.py index 0a09e60..f80a738 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_branch.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_branch.py @@ -14,7 +14,9 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name + self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/components/matrix_impedance_fuse.py b/src/ditto/writers/opendss/components/matrix_impedance_fuse.py index ffcfe03..4c5a3c2 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_fuse.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_fuse.py @@ -15,8 +15,13 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.FUSE_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name + self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) def map_is_closed(self): # Require every phase to be enabled for the OpenDSS line to be enabled. self.opendss_dict["Switch"] = "true" + + def map_in_service(self): + self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/components/matrix_impedance_recloser.py b/src/ditto/writers/opendss/components/matrix_impedance_recloser.py new file mode 100644 index 0000000..3630d3d --- /dev/null +++ b/src/ditto/writers/opendss/components/matrix_impedance_recloser.py @@ -0,0 +1,30 @@ +from gdm.distribution import DistributionSystem +from infrasys import Component + + +from ditto.writers.opendss.components.distribution_branch import DistributionBranchMapper +from ditto.enumerations import OpenDSSFileTypes + + +class MatrixImpedanceRecloserMapper(DistributionBranchMapper): + def __init__(self, model: Component, system: DistributionSystem): + super().__init__(model, system) + + altdss_name = "Line_LineCode" + altdss_composition_name = "Line" + opendss_file = OpenDSSFileTypes.SWITCH_FILE.value + + def map_equipment(self): + self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) + + def map_is_closed(self): + # Require every phase to be enabled for the OpenDSS line to be enabled. + self.opendss_dict["Switch"] = "true" + + def map_in_service(self): + self.opendss_dict["enabled"] = self.model.in_service + + def map_controller(self): + pass diff --git a/src/ditto/writers/opendss/components/matrix_impedance_switch.py b/src/ditto/writers/opendss/components/matrix_impedance_switch.py index 1b0737f..45721e0 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_switch.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_switch.py @@ -15,7 +15,9 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.SWITCH_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name + self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) def map_is_closed(self): # Require every phase to be enabled for the OpenDSS line to be enabled. diff --git a/src/ditto/writers/opendss/components/sequence_impedance_branch.py b/src/ditto/writers/opendss/components/sequence_impedance_branch.py index 47647a9..f19afd6 100644 --- a/src/ditto/writers/opendss/components/sequence_impedance_branch.py +++ b/src/ditto/writers/opendss/components/sequence_impedance_branch.py @@ -15,7 +15,9 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name + self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( + ".", "_" + ) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py b/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py index 77fb371..e0b6831 100644 --- a/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py +++ b/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py @@ -17,8 +17,8 @@ def __init__(self, model: RegulatorController, xfmr_name: str, system: Distribut self.xfmr_name = xfmr_name def map_name(self): - self.opendss_dict["Name"] = self.model.name - self.opendss_dict["Transformer"] = self.xfmr_name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Transformer"] = self.xfmr_name.replace(" ", "_").replace(".", "_") def map_delay(self): self.opendss_dict["TapDelay"] = self.model.delay.to("s").magnitude @@ -59,7 +59,7 @@ def map_bandwidth(self): def map_controlled_bus(self): self.opendss_dict[ "Bus" - ] = f"{self.model.controlled_bus.name}{self.phase_map[self.model.controlled_phase]}" + ] = f"{self.model.controlled_bus.name.replace(' ', '_').replace('.', '_')}{self.phase_map[self.model.controlled_phase]}" def map_controlled_phase(self): ... diff --git a/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py b/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py index d42f874..7d459da 100644 --- a/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py +++ b/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py @@ -14,7 +14,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.WIRES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_conductor_diameter(self): self.opendss_dict["Radius"] = self.model.conductor_diameter.magnitude / 2 diff --git a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py index fdf154a..9e28236 100644 --- a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py +++ b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py @@ -15,7 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.TRANSFORMERS_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_pct_no_load_loss(self): self.opendss_dict["pctNoLoadLoss"] = self.model.pct_no_load_loss @@ -44,6 +44,8 @@ def map_windings(self): num_phases = winding.num_phases # rated_voltage nom_voltage = winding.rated_voltage.to("kV").magnitude + voltage_type = winding.voltage_type + nom_voltage = nom_voltage if voltage_type == "line-to-ground" else nom_voltage / 1.732 kvs.append(nom_voltage if num_phases == 1 else nom_voltage * 1.732) # resistance pctRs.append(winding.resistance) diff --git a/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py b/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py index 40c2e1c..dc00204 100644 --- a/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py @@ -17,7 +17,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINECODES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_common(self): units = [] @@ -58,7 +58,9 @@ def map_conductors(self): # conductor_type = 'tsdata' else: raise ValueError(f"Unknown conductor type {conductor}") - all_conductors.append(f"{conductor_type}.{conductor.name}") + all_conductors.append( + f"{conductor_type}.{conductor.name.replace(' ', '_').replace('.', '_')}" + ) self.opendss_dict["Conductors"] = all_conductors def map_insulation(self): diff --git a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py index eec6e8f..4534da3 100644 --- a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py @@ -22,19 +22,31 @@ def map_common(self): self.opendss_dict["Units"] = "km" def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_r_matrix(self): r_matrix_ohms = self.model.r_matrix.to("ohm/km") - self.opendss_dict["RMatrix"] = r_matrix_ohms.magnitude + assert ( + r_matrix_ohms.magnitude - r_matrix_ohms.T.magnitude + ).max() < 1e-6, "RMatrix must be symmetric" + r_matrix_ohms = (r_matrix_ohms.magnitude + r_matrix_ohms.T.magnitude) / 2 + self.opendss_dict["RMatrix"] = r_matrix_ohms def map_x_matrix(self): x_matrix_ohms = self.model.x_matrix.to("ohm/km") - self.opendss_dict["XMatrix"] = x_matrix_ohms.magnitude + assert ( + x_matrix_ohms.magnitude - x_matrix_ohms.T.magnitude + ).max() < 1e-6, "XMatrix must be symmetric" + x_matrix_ohms = (x_matrix_ohms.magnitude + x_matrix_ohms.T.magnitude) / 2 + self.opendss_dict["XMatrix"] = x_matrix_ohms def map_c_matrix(self): c_matrix_nf = self.model.c_matrix.to("nanofarad/km") - self.opendss_dict["CMatrix"] = c_matrix_nf.magnitude + assert ( + c_matrix_nf.magnitude - c_matrix_nf.T.magnitude + ).max() < 1e-6, "CMatrix must be symmetric" + c_matrix_nf = (c_matrix_nf.magnitude + c_matrix_nf.T.magnitude) / 2 + self.opendss_dict["CMatrix"] = c_matrix_nf def map_ampacity(self): ampacity_amps = self.model.ampacity.to("ampere") diff --git a/src/ditto/writers/opendss/equipment/matrix_impedance_recloser_equipment.py b/src/ditto/writers/opendss/equipment/matrix_impedance_recloser_equipment.py new file mode 100644 index 0000000..f7a2977 --- /dev/null +++ b/src/ditto/writers/opendss/equipment/matrix_impedance_recloser_equipment.py @@ -0,0 +1,21 @@ +from gdm.distribution import DistributionSystem +from infrasys import Component + + +from ditto.writers.opendss.equipment.matrix_impedance_branch_equipment import ( + MatrixImpedanceBranchEquipmentMapper, +) +from ditto.enumerations import OpenDSSFileTypes + + +class MatrixImpedanceRecloserEquipmentMapper(MatrixImpedanceBranchEquipmentMapper): + def __init__(self, model: Component, system: DistributionSystem): + super().__init__(model, system) + + altdss_name = "LineCode_ZMatrixCMatrix" + altdss_composition_name = "LineCode" + opendss_file = OpenDSSFileTypes.SWITCH_CODES_FILE.value + + def map_controller(self): + # Not mapped in OpenDSS + pass diff --git a/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py b/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py index c830c7d..7b6e089 100644 --- a/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py @@ -15,7 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINECODES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name + self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") def map_common(self): self.opendss_dict["Units"] = "km" diff --git a/src/ditto/writers/opendss/write.py b/src/ditto/writers/opendss/write.py index f2a55b8..ae2188c 100644 --- a/src/ditto/writers/opendss/write.py +++ b/src/ditto/writers/opendss/write.py @@ -52,7 +52,11 @@ def _get_voltage_bases(self) -> list[float]: voltage_bases = [] buses: list[DistributionBus] = list(self.system.get_components(DistributionBus)) for bus in buses: - voltage_bases.append(bus.rated_voltage.to("kilovolt").magnitude * 1.732) + voltage_bases.append( + bus.rated_voltage.to("kilovolt").magnitude + if bus.voltage_type == "line-to-line" + else bus.rated_voltage.to("kilovolt").magnitude * 1.732 + ) return list(set(voltage_bases)) def write( # noqa From ba3873f6b31b4363f54f7d03cbdee3be48b97ab7 Mon Sep 17 00:00:00 2001 From: "Zink, Zephyr" Date: Thu, 15 Jan 2026 15:20:25 -0700 Subject: [PATCH 2/5] clean up prints --- src/ditto/writers/opendss/components/distribution_vsource.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ditto/writers/opendss/components/distribution_vsource.py b/src/ditto/writers/opendss/components/distribution_vsource.py index 65ca05a..dbefcd8 100644 --- a/src/ditto/writers/opendss/components/distribution_vsource.py +++ b/src/ditto/writers/opendss/components/distribution_vsource.py @@ -59,7 +59,7 @@ def map_equipment(self): voltage = voltage.to("kilovolt") rated_voltage = rated_voltage.to("kilovolt") angle = angle.to("degree") - print(voltage.magnitude, rated_voltage.magnitude, self.model.bus.voltage_type) + if self.model.equipment.sources[0].voltage_type == VoltageTypes.LINE_TO_GROUND: if num_phases == 1: v_mag = voltage.magnitude @@ -84,7 +84,6 @@ def map_equipment(self): self.opendss_dict["Angle"] = angle.magnitude self.opendss_dict["pu"] = v_mag / v_nom - print(v_nom) self.opendss_dict["BasekV"] = v_nom self.opendss_dict["Z0"] = complex(r0.magnitude, x0.magnitude) self.opendss_dict["Z1"] = complex(r1.magnitude, x1.magnitude) From 9dd6e3db75a4db2ae3e86f7af1bb673baa96eb49 Mon Sep 17 00:00:00 2001 From: "Zink, Zephyr" Date: Fri, 16 Jan 2026 09:05:04 -0700 Subject: [PATCH 3/5] fix symmetry assert --- .../equipment/matrix_impedance_branch_equipment.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py index 4534da3..033326a 100644 --- a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py @@ -27,24 +27,24 @@ def map_name(self): def map_r_matrix(self): r_matrix_ohms = self.model.r_matrix.to("ohm/km") assert ( - r_matrix_ohms.magnitude - r_matrix_ohms.T.magnitude - ).max() < 1e-6, "RMatrix must be symmetric" + abs(r_matrix_ohms.magnitude - r_matrix_ohms.T.magnitude).max() < 1e-6 + ), "RMatrix must be symmetric" r_matrix_ohms = (r_matrix_ohms.magnitude + r_matrix_ohms.T.magnitude) / 2 self.opendss_dict["RMatrix"] = r_matrix_ohms def map_x_matrix(self): x_matrix_ohms = self.model.x_matrix.to("ohm/km") assert ( - x_matrix_ohms.magnitude - x_matrix_ohms.T.magnitude - ).max() < 1e-6, "XMatrix must be symmetric" + abs(x_matrix_ohms.magnitude - x_matrix_ohms.T.magnitude).max() < 1e-6 + ), "XMatrix must be symmetric" x_matrix_ohms = (x_matrix_ohms.magnitude + x_matrix_ohms.T.magnitude) / 2 self.opendss_dict["XMatrix"] = x_matrix_ohms def map_c_matrix(self): c_matrix_nf = self.model.c_matrix.to("nanofarad/km") assert ( - c_matrix_nf.magnitude - c_matrix_nf.T.magnitude - ).max() < 1e-6, "CMatrix must be symmetric" + abs(c_matrix_nf.magnitude - c_matrix_nf.T.magnitude).max() < 1e-6 + ), "CMatrix must be symmetric" c_matrix_nf = (c_matrix_nf.magnitude + c_matrix_nf.T.magnitude) / 2 self.opendss_dict["CMatrix"] = c_matrix_nf From a0747d0cd8d1fb36fc290cd4778ba5eef9e27d13 Mon Sep 17 00:00:00 2001 From: "Zink, Zephyr" Date: Wed, 21 Jan 2026 17:15:33 -0700 Subject: [PATCH 4/5] single phase delta consideration --- .../equipment/distribution_transformer_equipment.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py index 9e28236..3d089ac 100644 --- a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py +++ b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py @@ -45,14 +45,19 @@ def map_windings(self): # rated_voltage nom_voltage = winding.rated_voltage.to("kV").magnitude voltage_type = winding.voltage_type + connection_type = winding.connection_type nom_voltage = nom_voltage if voltage_type == "line-to-ground" else nom_voltage / 1.732 - kvs.append(nom_voltage if num_phases == 1 else nom_voltage * 1.732) + kvs.append( + nom_voltage + if num_phases == 1 and connection_type != "DELTA" + else nom_voltage * 1.732 + ) # resistance pctRs.append(winding.resistance) # rated_power kVAs.append(winding.rated_power.to("kva").magnitude) # connection_type - conns.append(self.connection_map[winding.connection_type]) + conns.append(self.connection_map[connection_type]) # TODO: num_phases and is_grounded aren't included if self.model.is_center_tapped and i == len(self.model.windings): kvs.append(nom_voltage) From 95f7812031aa32c84dc8847ed1160637956a56c4 Mon Sep 17 00:00:00 2001 From: "Zink, Zephyr" Date: Fri, 30 Jan 2026 10:57:29 -0700 Subject: [PATCH 5/5] move fixing name for opendss to class function --- .../writers/opendss/components/distribution_branch.py | 6 +++--- src/ditto/writers/opendss/components/distribution_bus.py | 2 +- .../writers/opendss/components/distribution_capacitor.py | 4 ++-- src/ditto/writers/opendss/components/distribution_load.py | 4 ++-- .../writers/opendss/components/distribution_regulator.py | 8 ++++---- .../writers/opendss/components/distribution_solar.py | 4 ++-- .../opendss/components/distribution_transformer.py | 8 ++++---- .../writers/opendss/components/distribution_vsource.py | 4 ++-- src/ditto/writers/opendss/components/geometry_branch.py | 4 +--- .../writers/opendss/components/matrix_impedance_branch.py | 4 +--- .../writers/opendss/components/matrix_impedance_fuse.py | 4 +--- .../opendss/components/matrix_impedance_recloser.py | 4 +--- .../writers/opendss/components/matrix_impedance_switch.py | 4 +--- .../opendss/components/sequence_impedance_branch.py | 4 +--- .../controllers/distribution_regulator_controller.py | 6 +++--- .../writers/opendss/equipment/bare_conductor_equipment.py | 2 +- .../equipment/distribution_transformer_equipment.py | 2 +- .../opendss/equipment/geometry_branch_equipment.py | 6 ++---- .../equipment/matrix_impedance_branch_equipment.py | 2 +- .../equipment/sequence_impedance_branch_equipment.py | 2 +- src/ditto/writers/opendss/opendss_mapper.py | 4 ++++ 21 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/ditto/writers/opendss/components/distribution_branch.py b/src/ditto/writers/opendss/components/distribution_branch.py index e3baac4..a9fd852 100644 --- a/src/ditto/writers/opendss/components/distribution_branch.py +++ b/src/ditto/writers/opendss/components/distribution_branch.py @@ -16,11 +16,11 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_buses(self): - self.opendss_dict["Bus1"] = self.model.buses[0].name.replace(" ", "_").replace(".", "_") - self.opendss_dict["Bus2"] = self.model.buses[1].name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus1"] = self.get_opendss_safe_name(self.model.buses[0].name) + self.opendss_dict["Bus2"] = self.get_opendss_safe_name(self.model.buses[1].name) for phase in self.model.phases: if phase != Phase.N: self.opendss_dict["Bus1"] += self.phase_map[phase] diff --git a/src/ditto/writers/opendss/components/distribution_bus.py b/src/ditto/writers/opendss/components/distribution_bus.py index d77ea9b..f7e6858 100644 --- a/src/ditto/writers/opendss/components/distribution_bus.py +++ b/src/ditto/writers/opendss/components/distribution_bus.py @@ -14,7 +14,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.COORDINATE_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_coordinate(self): if hasattr(self.model.coordinate, "x"): diff --git a/src/ditto/writers/opendss/components/distribution_capacitor.py b/src/ditto/writers/opendss/components/distribution_capacitor.py index d8e832e..318f1bf 100644 --- a/src/ditto/writers/opendss/components/distribution_capacitor.py +++ b/src/ditto/writers/opendss/components/distribution_capacitor.py @@ -19,10 +19,10 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_bus(self): - self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus1"] = self.get_opendss_safe_name(self.model.bus.name) num_phases = len(self.model.phases) for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] diff --git a/src/ditto/writers/opendss/components/distribution_load.py b/src/ditto/writers/opendss/components/distribution_load.py index 73567f4..3d9a0bf 100644 --- a/src/ditto/writers/opendss/components/distribution_load.py +++ b/src/ditto/writers/opendss/components/distribution_load.py @@ -20,7 +20,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) profile_name = self.get_profile_name(self.model) if profile_name: @@ -28,7 +28,7 @@ def map_name(self): def map_bus(self): num_phases = len(self.model.phases) - self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus1"] = self.get_opendss_safe_name(self.model.bus.name) for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] # TODO: Should we include the phases its connected to here? diff --git a/src/ditto/writers/opendss/components/distribution_regulator.py b/src/ditto/writers/opendss/components/distribution_regulator.py index b7ad15b..cfd9098 100644 --- a/src/ditto/writers/opendss/components/distribution_regulator.py +++ b/src/ditto/writers/opendss/components/distribution_regulator.py @@ -17,7 +17,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_buses(self): buses = [] @@ -27,7 +27,7 @@ def map_buses(self): if is_center_tapped: for i in range(len(self.model.buses)): bus = self.model.buses[i] - buses.append(bus.name.replace(" ", "_").replace(".", "_")) + buses.append(self.get_opendss_safe_name(bus.name)) dss_phases = "" for phase in self.model.winding_phases[0]: dss_phases += self.phase_map[phase] @@ -37,7 +37,7 @@ def map_buses(self): else: for bus in self.model.buses: - buses.append(bus.name.replace(" ", "_").replace(".", "_")) + buses.append(self.get_opendss_safe_name(bus.name)) for winding_phases in self.model.winding_phases: dss_phases = "" for phase in winding_phases: @@ -54,7 +54,7 @@ def map_winding_phases(self): def map_equipment(self): equipment = self.model.equipment - self.opendss_dict["XfmrCode"] = equipment.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["XfmrCode"] = self.get_opendss_safe_name(equipment.name) def map_controllers(self): ... diff --git a/src/ditto/writers/opendss/components/distribution_solar.py b/src/ditto/writers/opendss/components/distribution_solar.py index f999efa..f626c46 100644 --- a/src/ditto/writers/opendss/components/distribution_solar.py +++ b/src/ditto/writers/opendss/components/distribution_solar.py @@ -18,7 +18,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) profile_name = self.get_profile_name(self.model) if profile_name: @@ -26,7 +26,7 @@ def map_name(self): def map_bus(self): num_phases = len(self.model.phases) - self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus1"] = self.get_opendss_safe_name(self.model.bus.name) for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] # TODO: Should we include the phases its connected to here? diff --git a/src/ditto/writers/opendss/components/distribution_transformer.py b/src/ditto/writers/opendss/components/distribution_transformer.py index 7ad5443..1809d97 100644 --- a/src/ditto/writers/opendss/components/distribution_transformer.py +++ b/src/ditto/writers/opendss/components/distribution_transformer.py @@ -18,7 +18,7 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_buses(self): buses = [] @@ -28,7 +28,7 @@ def map_buses(self): if is_center_tapped: for i in range(len(self.model.buses)): bus = self.model.buses[i] - buses.append(bus.name.replace(" ", "_").replace(".", "_")) + buses.append(self.get_opendss_safe_name(bus.name)) dss_phases = "" for phase in self.model.winding_phases[0]: dss_phases += self.phase_map[phase] @@ -38,7 +38,7 @@ def map_buses(self): else: for bus in self.model.buses: - buses.append(bus.name.replace(" ", "_").replace(".", "_")) + buses.append(self.get_opendss_safe_name(bus.name)) for winding_phases in self.model.winding_phases: dss_phases = "" for phase in winding_phases: @@ -55,4 +55,4 @@ def map_winding_phases(self): def map_equipment(self): equipment = self.model.equipment - self.opendss_dict["XfmrCode"] = equipment.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["XfmrCode"] = self.get_opendss_safe_name(equipment.name) diff --git a/src/ditto/writers/opendss/components/distribution_vsource.py b/src/ditto/writers/opendss/components/distribution_vsource.py index dbefcd8..d1d7326 100644 --- a/src/ditto/writers/opendss/components/distribution_vsource.py +++ b/src/ditto/writers/opendss/components/distribution_vsource.py @@ -19,14 +19,14 @@ def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) profile_name = self.get_profile_name(self.model) if profile_name: self.opendss_dict["Yearly"] = profile_name def map_bus(self): - self.opendss_dict["Bus1"] = self.model.bus.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Bus1"] = self.get_opendss_safe_name(self.model.bus.name) for phase in self.model.phases: self.opendss_dict["Bus1"] += self.phase_map[phase] diff --git a/src/ditto/writers/opendss/components/geometry_branch.py b/src/ditto/writers/opendss/components/geometry_branch.py index a87795a..3b6a3af 100644 --- a/src/ditto/writers/opendss/components/geometry_branch.py +++ b/src/ditto/writers/opendss/components/geometry_branch.py @@ -15,9 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["Geometry"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["Geometry"] = self.get_opendss_safe_name(self.model.equipment.name) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/components/matrix_impedance_branch.py b/src/ditto/writers/opendss/components/matrix_impedance_branch.py index f80a738..ee1ebf0 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_branch.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_branch.py @@ -14,9 +14,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["LineCode"] = self.get_opendss_safe_name(self.model.equipment.name) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/components/matrix_impedance_fuse.py b/src/ditto/writers/opendss/components/matrix_impedance_fuse.py index 4c5a3c2..5d0274b 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_fuse.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_fuse.py @@ -15,9 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.FUSE_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["LineCode"] = self.get_opendss_safe_name(self.model.equipment.name) def map_is_closed(self): # Require every phase to be enabled for the OpenDSS line to be enabled. diff --git a/src/ditto/writers/opendss/components/matrix_impedance_recloser.py b/src/ditto/writers/opendss/components/matrix_impedance_recloser.py index 3630d3d..19cb40e 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_recloser.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_recloser.py @@ -15,9 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.SWITCH_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["LineCode"] = self.get_opendss_safe_name(self.model.equipment.name) def map_is_closed(self): # Require every phase to be enabled for the OpenDSS line to be enabled. diff --git a/src/ditto/writers/opendss/components/matrix_impedance_switch.py b/src/ditto/writers/opendss/components/matrix_impedance_switch.py index 45721e0..7d01b25 100644 --- a/src/ditto/writers/opendss/components/matrix_impedance_switch.py +++ b/src/ditto/writers/opendss/components/matrix_impedance_switch.py @@ -15,9 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.SWITCH_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["LineCode"] = self.get_opendss_safe_name(self.model.equipment.name) def map_is_closed(self): # Require every phase to be enabled for the OpenDSS line to be enabled. diff --git a/src/ditto/writers/opendss/components/sequence_impedance_branch.py b/src/ditto/writers/opendss/components/sequence_impedance_branch.py index f19afd6..09d08df 100644 --- a/src/ditto/writers/opendss/components/sequence_impedance_branch.py +++ b/src/ditto/writers/opendss/components/sequence_impedance_branch.py @@ -15,9 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINES_FILE.value def map_equipment(self): - self.opendss_dict["LineCode"] = self.model.equipment.name.replace(" ", "_").replace( - ".", "_" - ) + self.opendss_dict["LineCode"] = self.get_opendss_safe_name(self.model.equipment.name) def map_in_service(self): self.opendss_dict["enabled"] = self.model.in_service diff --git a/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py b/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py index e0b6831..cd99164 100644 --- a/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py +++ b/src/ditto/writers/opendss/controllers/distribution_regulator_controller.py @@ -17,8 +17,8 @@ def __init__(self, model: RegulatorController, xfmr_name: str, system: Distribut self.xfmr_name = xfmr_name def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") - self.opendss_dict["Transformer"] = self.xfmr_name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) + self.opendss_dict["Transformer"] = self.get_opendss_safe_name(self.xfmr_name) def map_delay(self): self.opendss_dict["TapDelay"] = self.model.delay.to("s").magnitude @@ -59,7 +59,7 @@ def map_bandwidth(self): def map_controlled_bus(self): self.opendss_dict[ "Bus" - ] = f"{self.model.controlled_bus.name.replace(' ', '_').replace('.', '_')}{self.phase_map[self.model.controlled_phase]}" + ] = f"{self.get_opendss_safe_name(self.model.controlled_bus.name)}{self.phase_map[self.model.controlled_phase]}" def map_controlled_phase(self): ... diff --git a/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py b/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py index 7d459da..e4c0067 100644 --- a/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py +++ b/src/ditto/writers/opendss/equipment/bare_conductor_equipment.py @@ -14,7 +14,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.WIRES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_conductor_diameter(self): self.opendss_dict["Radius"] = self.model.conductor_diameter.magnitude / 2 diff --git a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py index 3d089ac..f51adf2 100644 --- a/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py +++ b/src/ditto/writers/opendss/equipment/distribution_transformer_equipment.py @@ -15,7 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.TRANSFORMERS_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_pct_no_load_loss(self): self.opendss_dict["pctNoLoadLoss"] = self.model.pct_no_load_loss diff --git a/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py b/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py index dc00204..e0f0bb6 100644 --- a/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/geometry_branch_equipment.py @@ -17,7 +17,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINECODES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_common(self): units = [] @@ -58,9 +58,7 @@ def map_conductors(self): # conductor_type = 'tsdata' else: raise ValueError(f"Unknown conductor type {conductor}") - all_conductors.append( - f"{conductor_type}.{conductor.name.replace(' ', '_').replace('.', '_')}" - ) + all_conductors.append(f"{conductor_type}.{self.get_opendss_safe_name(conductor.name)}") self.opendss_dict["Conductors"] = all_conductors def map_insulation(self): diff --git a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py index 033326a..d48b113 100644 --- a/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/matrix_impedance_branch_equipment.py @@ -22,7 +22,7 @@ def map_common(self): self.opendss_dict["Units"] = "km" def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_r_matrix(self): r_matrix_ohms = self.model.r_matrix.to("ohm/km") diff --git a/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py b/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py index 7b6e089..0eef05a 100644 --- a/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py +++ b/src/ditto/writers/opendss/equipment/sequence_impedance_branch_equipment.py @@ -15,7 +15,7 @@ def __init__(self, model: Component, system: DistributionSystem): opendss_file = OpenDSSFileTypes.LINECODES_FILE.value def map_name(self): - self.opendss_dict["Name"] = self.model.name.replace(" ", "_").replace(".", "_") + self.opendss_dict["Name"] = self.get_opendss_safe_name(self.model.name) def map_common(self): self.opendss_dict["Units"] = "km" diff --git a/src/ditto/writers/opendss/opendss_mapper.py b/src/ditto/writers/opendss/opendss_mapper.py index fb83e1d..30b337e 100644 --- a/src/ditto/writers/opendss/opendss_mapper.py +++ b/src/ditto/writers/opendss/opendss_mapper.py @@ -87,3 +87,7 @@ def get_profile_name(self, component): profile_name = str(self.model.uuid) return profile_name + + def get_opendss_safe_name(self, name: str) -> str: + """Fix the name to be compatible with OpenDSS by replacing spaces and periods with underscores.""" + return name.replace(" ", "_").replace(".", "_")