Skip to content

Commit

Permalink
improve dtrans
Browse files Browse the repository at this point in the history
  • Loading branch information
wwang2 committed Aug 5, 2024
1 parent f34c764 commit 40b0c30
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 69 deletions.
5 changes: 5 additions & 0 deletions ditto/modify/system_structure.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ def set_nominal_voltages_recur(self, *args):
]
)
num_phases = len(self.model[trans_name].windings[0].phase_windings)
if self.model[trans_name].is_threephaseunit == 0:
new_value = new_value *1.732
if num_phases!=3:
new_value = new_value *1.732
print(f"1num_phases={num_phases}")
Expand All @@ -255,6 +257,9 @@ def set_nominal_voltages_recur(self, *args):
]
)
num_phases = len(self.model[trans_name].windings[0].phase_windings)
if self.model[trans_name].is_threephaseunit == 0: # wenbo added this because naming convention in synergi warehouse.mdb
new_value = new_value *1.732

if num_phases!=3:
new_value = new_value *1.732
print(f"2trans_name={trans_name}")
Expand Down
48 changes: 27 additions & 21 deletions ditto/readers/synergi/read.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ def parse(self, model):
NodeID = self.get_data("Node", "NodeId")
NodeX = self.get_data("Node", "X")
NodeY = self.get_data("Node", "Y")


NodeX = self.get_data("Node", "Latitude") # lat
NodeY = self.get_data("Node", "Longitude") # lon




## Preferences ########
LengthUnits = self.get_data("SAI_Equ_Control", "LengthUnits")
Expand Down Expand Up @@ -1990,16 +1997,19 @@ def parse(self, model):
print("--> Parsing Loads...")

load_bus_map = {}
bus_load_map = {}

previous_load = None # this line is to check dubplicated load from previous load
previous_downstream_load = None
for i, obj in enumerate(LoadName):
# Create a Load DiTTo object
api_load = Load(model)
# if obj.replace(" ", "_").lower() == '230632.0DF0'.lower():
# breakpoint()
# if obj.replace(" ", "_").lower() == '440723.1df0'.lower():
# print('hold')
# Set the name
api_load.name = "Load_" + obj.replace(" ", "_").lower()
if api_load.name == previous_load:
#continue
api_load.name = "Load_" + obj.replace(" ", "_").lower() + '_dup'

#print(f'load_name = {api_load.name}')
Expand Down Expand Up @@ -2122,6 +2132,15 @@ def parse(self, model):

if api_load.name not in load_bus_map:
load_bus_map[obj.replace(" ", "_").lower()] = [api_load.connecting_element, api_load.phase_loads]

downstream_load = [load.p for load in api_load.phase_loads]

if 'dup' in api_load.name:
bus_load_map[api_load.connecting_element] += np.array(downstream_load)
else:
bus_load_map[api_load.connecting_element] = downstream_load

#previous_downstream_load = downstream_load

# else: # wenbo edit: kva is not read in synergi
# # Create the PhaseLoad DiTTo object
Expand Down Expand Up @@ -2217,24 +2236,6 @@ def parse(self, model):
api_load.vmin = 0.65
api_load.vmax = 1.1

# print('phase_load.phase={}, phase_load.p={}, phase_load.q={}'.format(phase_load.phase, phase_load.p, phase_load.q))

# else:
#
# # if there is no load information, place a small load instead of writing zero to the load
# phase_load = PhaseLoad(model)
#
# # Set the Phase
# phase_load.phase = phase
#
# # Set P
# phase_load.p = 0.01
#
# # Set Q
# phase_load.q = 0.01
#
# # Add the PhaseLoad to the list
# api_load.phase_loads.append(phase_load)



Expand Down Expand Up @@ -2280,7 +2281,12 @@ def parse(self, model):
api_transformer.conn = ['wye' , 'wye']
api_transformer.kvas = api_transformer.ConnKvaPh


# check if kvas and ConnKvaPh is enough to carry the load, then update it if needed
bus_loads = bus_load_map[api_transformer.connecting_element]
need_kvas = bus_loads
if sum(api_transformer.kvas)<sum(need_kvas):
new_kvas = [float((int(str(int(num))[0]) + 1) * 10 ** (len(str(int(num))) - 1)) for num in need_kvas]
api_transformer.kvas = new_kvas
####################################################################################
# #
# CAPACITORS #
Expand Down
127 changes: 79 additions & 48 deletions ditto/writers/opendss/write.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def __init__(self, **kwargs):
self.feeders_redirect = {}
self.mv_load_voltage_dict = {}
self.feeder_head_line = None
self.model_dtrans = False
self.model_dtrans = True # this will decide if model secondary / dtrans

self.write_distribution_transformers = True
self.write_taps = False
Expand Down Expand Up @@ -372,8 +372,8 @@ def write_bus_coordinates(self, model, delimiter=","):

txt += "{name}{delimiter}{X}{delimiter}{Y}\n".format(
name=re.sub("[^0-9a-zA-Z]+", "_", i.name.lower()),
X=i.positions[0].long,
Y=i.positions[0].lat,
X=i.positions[0].lat,
Y=i.positions[0].long,
delimiter=delimiter,
)
feeder_text_map[substation_name + "_" + feeder_name] = txt
Expand Down Expand Up @@ -1141,23 +1141,28 @@ def write_dtransformers(self, model):
# if hasattr(i, "bus2") and i.bus2 is not None:
# txt += i.bus2 + ")"
if hasattr(i, "conn") and i.conn is not None:
txt += f" conn = ({i.conn[0]}, {i.conn[1]})"
txt += f" conns = ({i.conn[0]}, {i.conn[1]})"

if hasattr(i, "nominal_voltage") and i.nominal_voltage is not None:
#txt += f" kvs = ({i.nominal_voltage/1000}, 0.24)"
if hasattr(i, "phase_loads") and i.phase_loads is not None and len(i.phase_loads)==1:
try:
kv1 = self.mv_load_voltage_dict[i.name.split('DTran_')[1]]
kv1 = self.mv_load_voltage_dict[i.name.split('_')[1]]
except:

kv1 = 0

logger.warning('WARNING: There is kv1=0 in dtrans object!')


txt += f" kvs = ({kv1}, 0.24)"
else:
try:
kv1 = self.mv_load_voltage_dict[i.name.split('DTran_')[1]]
kv1 = self.mv_load_voltage_dict[i.name.split('_')[1]]
except:
kv1 = 0
txt += f" kvs = ({kv1}, 0.208)"
kv1 = 0
logger.warning('WARNING: There is kv1=0 in dtrans object!')

txt += f" kvs = ({kv1}, 0.416)"


if hasattr(i, "kvas") and i.kvas is not None:
Expand Down Expand Up @@ -1495,35 +1500,50 @@ def write_PVs(self, model):

# nominal voltage
if hasattr(i, "nominal_voltage") and i.nominal_voltage is not None:
if i.nominal_voltage < 300:
if hasattr(i, "phases") and i.phases is not None:
txt += " phases=1"
txt += " kV={kV}".format(
kV=i.nominal_voltage * 10**-3
) # DiTTo in volts
else:
if hasattr(i, "phases") and i.phases is not None:
txt += " phases=3"
txt += " kV={kV}".format(
kV=i.nominal_voltage * 10**-3
) # DiTTo in volts
if hasattr(i, "phases") and i.phases is not None:
txt += f" phases={len(i.phases)}"
if len(i.phases) == 1:
txt +=f" kV={round(i.nominal_voltage * 10**-3/1.732,2)}"
else:
txt += f" kV={i.nominal_voltage * 10**-3}" # DiTTo in volts

# if i.nominal_voltage < 300:
# if hasattr(i, "phases") and i.phases is not None:
# txt += " phases=1"
# txt += " kV={kV}".format(
# kV=i.nominal_voltage * 10**-3
# ) # DiTTo in volts
# else:
# if hasattr(i, "phases") and i.phases is not None:
# txt += " phases=3"
# txt += " kV={kV}".format(
# kV=i.nominal_voltage * 10**-3
# ) # DiTTo in volts
if not substation_name + "_" + feeder_name in self._baseKV_feeders_:
self._baseKV_feeders_[
substation_name + "_" + feeder_name
] = set()
if (
i.nominal_voltage < 300
): # Line-Neutral voltage for 120 V (i.e. 240V)
self._baseKV_.add(i.nominal_voltage * 10**-3)
self._baseKV_feeders_[substation_name + "_" + feeder_name].add(
i.nominal_voltage * 2 * 10**-3
)
else:
self._baseKV_.add(i.nominal_voltage * 10**-3)
self._baseKV_feeders_[substation_name + "_" + feeder_name].add(
i.nominal_voltage * 10**-3
)
# if (
# i.nominal_voltage < 300
# ): # Line-Neutral voltage for 120 V (i.e. 240V)
# self._baseKV_.add(i.nominal_voltage * 10**-3)
# self._baseKV_feeders_[substation_name + "_" + feeder_name].add(
# i.nominal_voltage * 2 * 10**-3
# )
# else:
# self._baseKV_.add(i.nominal_voltage * 10**-3)
# self._baseKV_feeders_[substation_name + "_" + feeder_name].add(
# i.nominal_voltage * 10**-3
# )
self._baseKV_.add(i.nominal_voltage * 10**-3)
self._baseKV_feeders_[substation_name + "_" + feeder_name].add(
i.nominal_voltage * 10**-3
)

else:
logger.warning(
"Warning - check PV definition, possible no kv defined."
)
parent = model[i.connecting_element]
if (
hasattr(parent, "nominal_voltage")
Expand Down Expand Up @@ -1563,7 +1583,7 @@ def write_PVs(self, model):

if hasattr(i, "active_rating") and i.active_rating is not None:
pf_local = 1.0
if i.power_factor is not None:
if i.power_factor is not None and i.power_factor > 0:
pf_local = abs(i.power_factor)
txt += " kVA={kva}".format(
kva=i.active_rating / pf_local * 10**-3
Expand All @@ -1578,23 +1598,30 @@ def write_PVs(self, model):
** -3 # Set the inverter to be oversized by 10% if active rating not specified
) # DiTTo in watts

else:
# wenbo note: if no active rating, kva need to be defined still.
pf_local = 1.0
txt += " kVA={kva}".format(
kva=i.rated_power / pf_local * 10**-3
) # DiTTo in watts

if hasattr(i, "rated_power") and i.rated_power is not None:
txt += " Pmpp={kw}".format(
kw=i.rated_power
* 10
** -3 # Set the inverter to be oversized by 10% if active rating not specified
) # DiTTo in watts

if hasattr(i, "reactive_rating") and i.reactive_rating is not None:
if self.opendss_version >= 9:
kvarlimit_key = " kvarMax="
else:
kvarlimit_key = " kvarlimit="
txt += kvarlimit_key + "{kvar}".format(
kvar=i.reactive_rating
* 10
** -3 # Set the inverter to be oversized by 10% if active rating not specified
) # DiTTo in watts
# if hasattr(i, "reactive_rating") and i.reactive_rating is not None:
# if self.opendss_version >= 9:
# kvarlimit_key = " kvarMax="
# else:
# kvarlimit_key = " kvarlimit="
# txt += kvarlimit_key + "{kvar}".format(
# kvar=i.reactive_rating
# * 10
# ** -3 # Set the inverter to be oversized by 10% if active rating not specified
# ) # DiTTo in watts

# connection type
if hasattr(i, "connection_type") and i.connection_type is not None:
Expand Down Expand Up @@ -1636,7 +1663,7 @@ def write_PVs(self, model):
if hasattr(i, "control_type") and (
i.control_type is None or i.control_type == "powerfactor"
): # use powerfactor as default mode
if hasattr(i, "power_factor") and i.power_factor is not None:
if hasattr(i, "power_factor") and i.power_factor is not None and i.power_factor>0:
txt += " Model=1 pf={power_factor}".format(
power_factor=i.power_factor
)
Expand Down Expand Up @@ -2086,11 +2113,14 @@ def write_loads(self, model):

# Name
if hasattr(i, "name") and i.name is not None:


if i.name not in load_list:

txt += "New Load." + i.name
load_list.append(i.name)
else:
continue
txt += "New Load." + i.name + '_dup'
#print(f"i.name = {i.name}")
else:
Expand Down Expand Up @@ -2145,22 +2175,23 @@ def write_loads(self, model):
#print(f"i.phase_loads length = {len(i.phase_loads)}")
if self.model_dtrans:
if i.nominal_voltage < 300:

txt += " kV={volt}".format(volt=i.nominal_voltage * 10**-3)
# Wenbo: This is added because single phase load should be L-N, not L-L
elif hasattr(i, "phase_loads") and i.phase_loads is not None and len(i.phase_loads)==1:
#txt += " kV={volt}".format(volt=round(i.nominal_voltage * 10**-3/math.sqrt(3),2))
txt += " kV=0.24"
self.mv_load_voltage_dict[i.name.split('Load_')[1]] = round(i.nominal_voltage * 10**-3/1.732,2)
elif hasattr(i, "phase_loads") and i.phase_loads is not None and len(i.phase_loads)>1:
txt += " kV=0.208"
txt += " kV=0.416"
self.mv_load_voltage_dict[i.name.split('Load_')[1]] = round(i.nominal_voltage * 10**-3,2)
#txt += " kV={volt}".format(volt=i.nominal_voltage * 10**-3)
else:
if i.nominal_voltage < 300:
txt += " kV={volt}".format(volt=i.nominal_voltage * 10**-3)
# Wenbo: This is added because single phase load should be L-N, not L-L
elif hasattr(i, "phase_loads") and i.phase_loads is not None and len(i.phase_loads)==1:
txt += " kV={volt}".format(volt=round(i.nominal_voltage * 10**-3/math.sqrt(3),2))
txt += " kV={volt}".format(volt=round(i.nominal_voltage * 10**-3/math.sqrt(3),2))
else:
txt += " kV={volt}".format(volt=i.nominal_voltage * 10**-3)

Expand Down Expand Up @@ -4277,7 +4308,7 @@ def write_master_file(self, model):
):
fp.write("Redirect {file}\n".format(file=file))

_baseKV_list_ = list(self._baseKV_) + [0.208, 0.416]
_baseKV_list_ = list(self._baseKV_) + [0.24, 0.416]
_baseKV_list_ = sorted(_baseKV_list_)
fp.write("\nSet Voltagebases={}\n".format(_baseKV_list_))

Expand Down

0 comments on commit 40b0c30

Please sign in to comment.