diff --git a/ditto/constant.py b/ditto/constant.py new file mode 100644 index 00000000..e2848a3a --- /dev/null +++ b/ditto/constant.py @@ -0,0 +1,64 @@ + +# Units +# The associated string must be Pint-parsable: +# >>> 1.0 * ureg.parse_expression(KVA) +# 1 kilowatt +# +# Power +VA = "watt" # Pint uses watts +KVA = "kilowatt" +W = "watt" +KW = "kilowatt" + +# Voltage +V = "volt" +KV = "kilovolt" + +# Current +A = "amps" +OHM = "ohm" +KOHM = "kiloohm" + +# Capacitance +F = "farad" +NF = "nanofarad" + +# Susceptance +SIEMENS = "siemens" + +# Energy +J = "joule" +KJ = "kilojoule" +WH = "watthour" +KWH = "kilowatthour" + +# Distances +M = "meter" +CM = "centimeter" +MM = "milimeter" +KM = "kilometer" +FT = "feet" +KFT = "kilofeet" +MI = "mile" +IN = "inch" + +# Mass +KG = "kilogram" +G = "gram" +MG = "milligram" + +# Angles +DEG = "degree" +RAD = "radian" + +# Temperature +K = "kelvin" + +# Time +MS = "millisecond" +S = "second" +MIN = "minute" +H = "hour" +DAY = "day" +MONTH = "month" +YEAR = "year" diff --git a/ditto/metrics/network_analysis.py b/ditto/metrics/network_analysis.py index cf9ea6e1..252354c7 100644 --- a/ditto/metrics/network_analysis.py +++ b/ditto/metrics/network_analysis.py @@ -771,8 +771,8 @@ def analyze_object(self, obj, feeder_name): # then we add the points to the list of points for the feeder if hasattr(obj, "positions") and obj.positions is not None: for position in obj.positions: - X = position.long - Y = position.lat + X = position.longitude + Y = position.latitude if X is not None and Y is not None: if feeder_name in self.points: self.points[feeder_name].append([X, Y]) @@ -1330,9 +1330,7 @@ def analyze_object(self, obj, feeder_name): ): self.results[feeder_name][ "sum_distribution_transformer_mva" - ] += ( - obj.windings[0].rated_power * 10 ** -6 - ) # DiTTo in va + ] += (obj.windings[0].rated_power * 10 ** -6) # DiTTo in va if ( hasattr(obj.windings[0], "phase_windings") diff --git a/ditto/models/capacitor.py b/ditto/models/capacitor.py index 3ba5daa1..78a2e932 100644 --- a/ditto/models/capacitor.py +++ b/ditto/models/capacitor.py @@ -6,85 +6,111 @@ from .position import Position from .phase_capacitor import PhaseCapacitor +from ..constant import V, S, OHM, SIEMENS + class Capacitor(DiTToHasTraits): - name = Unicode(help="""Name of the capacitor object""", default_value="") + name = Unicode(help="""Name of the capacitor object""", default_value="", unit=None) nominal_voltage = Float( - help="""The nominal voltage of the capacitor""", default_value=None + help="""The nominal voltage of the capacitor""", default_value=None, unit=V ) connection_type = Unicode( help="""This is the type of connection that the capacitor connects to on the high side. The strings may be one of the following Delta (D), Wye (Y), Zigzap (Z) or autotransformer (A).""", default_value=None, + unit=None, ) delay = Float( help="""The time that the capacitor need to connect or disconnect by automatic voltage regulation""", default_value=None, + unit=S, ) mode = Unicode( help="""What control mode is used. A string from one of the options: {voltage, activePower, reactivePower, currentFlow, admittance, timeScheduled, none}""", default_value=None, + unit=None, ) low = Float( help="""This is the low value of the range that is being controlled by the capacitor (e.g. voltage).""", default_value=None, + unit=None, # PROBLEM HERE.... ) high = Float( help="""This is the high value of the range that is being controlled by the capacitor (e.g. voltage).""", default_value=None, + unit=None, # PROBLEM HERE... ) resistance = Float( - help="""The total series resistance of the capacitor""", default_value=None + help="""The total series resistance of the capacitor""", + default_value=None, + unit=OHM, ) resistance0 = Float( help="""The total series zero-sequence resistance of the capacitor""", default_value=None, + unit=OHM, ) reactance = Float( - help="""The total series reactance of the capacitor""", default_value=None + help="""The total series reactance of the capacitor""", + default_value=None, + unit=OHM, ) reactance0 = Float( help="""The total series zero-sereactance of the capacitor""", default_value=None, + unit=OHM, ) susceptance = Float( help="""The total shunt susceptance of the capacitor section. Note that if the var value of the capacitor is provided this should follow the formula susceptance = -1*p.var/(nominal_voltage)**2""", default_value=None, + unit=SIEMENS, ) susceptance0 = Float( help="""The total zero sequence shunt susceptance of the capacitor""", default_value=None, + unit=SIEMENS, ) conductance = Float( - help="""This is the shunt conductance of the capacitor """, default_value=None + help="""This is the shunt conductance of the capacitor """, + default_value=None, + unit=SIEMENS, ) conductance0 = Float( help="""This is the zero sequence shunt conductance of the capacitor per section""", default_value=None, + unit=SIEMENS, ) pt_ratio = Float( help="""The voltage (potential) transformer ratio used to step down the voltage for controller.""", default_value=None, + unit=None, ) ct_ratio = Float( help="""The current transformer ratio used to define the current ratio for a controller.""", default_value=None, + unit=None, ) pt_phase = Unicode( - help="""The phase that the controller is connected to.""", default_value=None + help="""The phase that the controller is connected to.""", + default_value=None, + unit=None, ) connecting_element = Unicode( - help="""The bus which the capacitor is connected to""", default_value=None + help="""The bus which the capacitor is connected to""", + default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the capacitor (typically just one). The positions are objects containing elements of long, lat and elevation (See Position object documentation).""", default_value=None, + unit=None, ) phase_capacitors = List( Instance(PhaseCapacitor), help="""A list of phase capacitors which contain phase, var and switch values. The total var of the capacitor is defined through the phasecapacitors.""", default_value=None, + unit=None, ) # Modification: Nicolas (August 2017) @@ -93,6 +119,7 @@ class Capacitor(DiTToHasTraits): measuring_element = Unicode( help="""Name of the circuit element, typically a line or transformer, to which the capacitor control's PT and/or CT are connected""", default_value=None, + unit=None, ) # Modification: Nicolas (December 2017) @@ -102,15 +129,17 @@ class Capacitor(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default=None + help="""The name of the feeder the object is on.""", default=None, unit=None ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) def build(self, model): diff --git a/ditto/models/feeder_metadata.py b/ditto/models/feeder_metadata.py index 8efec7b4..7b33cedb 100644 --- a/ditto/models/feeder_metadata.py +++ b/ditto/models/feeder_metadata.py @@ -13,53 +13,65 @@ Instance, ) +from ..constant import V, DEG, OHM + class Feeder_metadata(DiTToHasTraits): """TODO """ - name = Unicode(help="""Name of the feeder object""") + name = Unicode(help="""Name of the feeder object""", unit=None) nominal_voltage = Float( - help="""Nominal voltage at the feeder head.""", default_value=None + help="""Nominal voltage at the feeder head.""", default_value=None, unit=V + ) + headnode = Unicode( + help="""Name of the headnode/FEEDERHEAD.""", default_value=None, unit=None ) - headnode = Unicode(help="""Name of the headnode/FEEDERHEAD.""", default_value=None) transformer = Unicode( help="""Name of the transformer representing the substation.""", default_value=None, + unit=None, ) substation = Unicode( help="""Name of the object representing the substation in the feeder files (often a bus downstream of the transformer).""", default_value=None, + unit=None, ) operating_voltage = Float( - help="""Operating voltage at the feeder head.""", default_value=None + help="""Operating voltage at the feeder head.""", default_value=None, unit=V ) - operating_angle1 = Float(help="""Angle 1.""", default_value=None) - operating_angle2 = Float(help="""Angle 2.""", default_value=None) - operating_angle3 = Float(help="""Angle 3.""", default_value=None) + operating_angle1 = Float(help="""Angle 1.""", default_value=None, unit=DEG) + operating_angle2 = Float(help="""Angle 2.""", default_value=None, unit=DEG) + operating_angle3 = Float(help="""Angle 3.""", default_value=None, unit=DEG) positive_sequence_resistance = Float( help="""Positive sequence resistance for the source equivalent.""", default_value=None, + unit=OHM, ) positive_sequence_reactance = Float( help="""Positive sequence reactance for the source equivalent.""", default_value=None, + unit=OHM, ) zero_sequence_resistance = Float( help="""Zero sequence resistance for the source equivalent.""", default_value=None, + unit=OHM, ) zero_sequence_reactance = Float( help="""Zero sequence reactance for the source equivalent.""", default_value=None, + unit=OHM, ) negative_sequence_resistance = Float( help="""Negative sequence resistance for the source equivalent.""", default_value=None, + unit=OHM, ) negative_sequence_reactance = Float( help="""Negative sequence reactance for the source equivalent.""", default_value=None, + unit=OHM, ) def build(self, model, Asset=None, ConnectivityNode=None, Location=None): diff --git a/ditto/models/line.py b/ditto/models/line.py index c9da237b..fa5b1e1b 100644 --- a/ditto/models/line.py +++ b/ditto/models/line.py @@ -1,6 +1,8 @@ from __future__ import absolute_import, division, print_function from builtins import super, range, zip, round, map +from ..constant import V, M, OHM, NF + from .base import ( DiTToHasTraits, Float, @@ -31,57 +33,71 @@ class Line(DiTToHasTraits): """ - name = Unicode(help="""Name of the line object""") + name = Unicode(help="""Name of the line object""", unit=None) nominal_voltage = Float( help="""This parameter defines the base voltage of the wire.""", default_value=None, + unit=V, ) line_type = Unicode( - help="""Whether the line is overhead or underground""", default_value="overhead" + help="""Whether the line is overhead or underground""", + default_value="overhead", + unit=None, ) length = Float( - help="""This parameter is the length of the Line.""", default_value=0 + help="""This parameter is the length of the Line.""", default_value=0, unit=M ) from_element = Any( help="""Name of the node which connects to the 'from' end of the line""", default_value=None, + unit=None, ) to_element = Any( help="""'Name of the node which connects to the 'to' end of the line""", default_value=None, + unit=None, ) is_fuse = Int( help="""This flag indicates whether or not the line is also a fuse""", default_value=None, + unit=None, ) is_switch = Int( help="""This flag indicates whether or not the line is also a switch""", default_value=None, + unit=None, ) is_banked = Int( help="""This flag indicates whether or not the switch is banked. If this is true, the switch objects are controlled together""", default_value=None, + unit=None, ) faultrate = Float( - help="""The number of faults that occur per year""", default_value=None + help="""The number of faults that occur per year""", + default_value=None, + unit=None, ) wires = List( Instance(Wire), help="""This parameter is a list of all the wires included on the line. The wires are objects containing elements of phase, X and Y. """, default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the line. The positions are objects containing elements of long, lat and elevation. The points can be used to map the position of the line. """, default_value=None, + unit=None, ) impedance_matrix = List( List(Complex), help="""This provides the matrix representation of the line impedance in complex form. Computed from the values of GMR and distances of individual wires. Kron reduction is applied to make this a 3x3 matrix.""", + unit=OHM + "/" + M, ) capacitance_matrix = List( List(Complex), help="""This provides the matrix representation of the line capacitance in complex form. Computed from the values of diameters and distances of individual wires. Kron reduction is applied to make this a 3x3 matrix.""", + unit=NF + "/" + M, ) # Modification: Nicolas (December 2017) @@ -91,9 +107,12 @@ class Line(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default_value=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default_value=None + help="""The name of the feeder the object is on.""", + default_value=None, + unit=None, ) # Modification: Nicolas (December 2017) @@ -101,33 +120,40 @@ class Line(DiTToHasTraits): is_recloser = Int( help="""This flag indicates whether or not the line is also a recloser""", default_value=None, + unit=None, ) # Modification: Nicolas (January 2018) is_breaker = Int( help="""This flag indicates whether or not the line is also a breaker""", default_value=None, + unit=None, ) # Modification: Nicolas (March 2018) is_sectionalizer = Int( help="""This flag indicates whether or not the line is also a sectionalizer""", default_value=None, + unit=None, ) # Modification: Nicolas (March 2018) - nameclass = Unicode(help="""Nameclass of the line object.""", default_value=None) + nameclass = Unicode( + help="""Nameclass of the line object.""", default_value=None, unit=None + ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) # Modification: Nicolas (June 2018) is_network_protector = Int( help="""This flag indicates whether or not the line is also a network protector.""", default_value=None, + unit=None, ) def build( diff --git a/ditto/models/load.py b/ditto/models/load.py index af3d09d7..aa19dc83 100644 --- a/ditto/models/load.py +++ b/ditto/models/load.py @@ -7,80 +7,97 @@ from .phase_load import PhaseLoad from .timeseries import Timeseries +from ..constant import V, M, W, VA, KWH, KVA + class Load(DiTToHasTraits): - name = Unicode(help="""Name of the load object""", default_value="") + name = Unicode(help="""Name of the load object""", default_value="", unit=None) nominal_voltage = Float( - help="""This is the nominal voltage of the load.""", default_value=None + help="""This is the nominal voltage of the load.""", default_value=None, unit=V ) connection_type = Unicode( help="""The connection type (D, Y, Z, A) for Delta, Wye, Zigzag or autotransformer.""", default_value=None, + unit=None, ) vmin = Float( help="""The minimum per-unit voltage value. Going below this implies constant impedance.""", default_value=None, + unit=None, ) vmax = Float( help="""The maximum per-unit voltage value. Going below this implies constant impedance.""", default_value=None, + unit=None, ) phase_loads = List( Instance(PhaseLoad), help="""A list of the different phase loads connected to the load. This contains information about the phase as well as the p&q or zip load data.""", default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the load- it should only contain one. The positions are objects containing elements of long, lat and elevation.""", default_value=None, + unit=None, ) timeseries = List( Instance(Timeseries), help="""A list of all the timeseries elements used to represent the loads""", default_value=None, + unit=None, ) # Modification: Nicolas (August 2017) # OpenDSS needs the name of the bus to which the load is connected, because it does not # represent the load as a bus with a connection line to another bus in the feeder. connecting_element = Unicode( - help="""Name of the bus to which the load is connected""", default_value=None + help="""Name of the bus to which the load is connected""", + default_value=None, + unit=None, ) # Modification: Claudio (August 2017) rooftop_area = Float( help="""This parameter is the rooftop area for all phases of the load""", default_value=None, + unit=M + "*" + M, ) peak_p = Float( help="""This parameter is the annual peak p value of all combined phases of the load""", default_value=None, + unit=W, ) peak_q = Float( help="""This parameter is the annual peak q value of all combined phases of the load""", default_value=None, + unit=VA, ) peak_coincident_p = Float( help="""This parameter is the annual coincident peak p value of all combined phases of the load""", default_value=None, + unit=W, ) peak_coincident_q = Float( help="""This parameter is the annual coincident peak q value of all combined phases of the load""", default_value=None, + unit=VA, ) yearly_energy = Float( help="""This is the total energy used by the load across all phases over a typical year""", default_value=None, + unit=KWH, ) num_levels = Float( help="""The number of floors (levels) that the building load has""", default_value=None, + unit=None, ) num_users = Float( - help="""The number of users at the loadpoint""", default_value=None + help="""The number of users at the loadpoint""", default_value=None, unit=None ) # Modification: Nicolas (December 2017) @@ -90,45 +107,55 @@ class Load(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default_value=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default_value=None + help="""The name of the feeder the object is on.""", + default_value=None, + unit=None, ) # Modification: Nicolas (December 2017) upstream_transformer_name = Unicode( help="""The name of the distribution transformer which serves this load""", default_value=None, + unit=None, ) # Modification: Nicolas (May 2018) transformer_connected_kva = Float( help="""KVA of the distribution transformer which serves this load.""", default_value=None, + unit=KVA, ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) # Modification: Nicolas (July 2018) is_center_tap = Int( help="""Flag that indicates whether the element is a center tap load or not.""", default_value=None, + unit=None, ) center_tap_perct_1_N = Float( help="""Percentage of the load between active 1 and neutral. Should be a float between 0 and 1.""", default_value=None, + unit=None, ) center_tap_perct_N_2 = Float( help="""Percentage of the load between neutal and active 2. Should be a float between 0 and 1.""", default_value=None, + unit=None, ) center_tap_perct_1_2 = Float( help="""Percentage of the load between active 1 and active 2. Should be a float between 0 and 1.""", default_value=None, + unit=None, ) def build(self, model): diff --git a/ditto/models/load_layer.py b/ditto/models/load_layer.py index 912d8df3..9678b65c 100644 --- a/ditto/models/load_layer.py +++ b/ditto/models/load_layer.py @@ -5,19 +5,26 @@ from .position import Position +from ..constant import S, A, OHM, W + class LoadLayer(DiTToHasTraits): - name = Unicode(help="""Name of the load object""") + name = Unicode(help="""Name of the load object""", unit=None) interval = Integer( - help="""The time resolution (in seconds) for the measured data""" + help="""The time resolution (in seconds) for the measured data""", unit=S + ) + current = Any( + help="""The input data for the ZIP current measurements""", unit=A + ) # TODO: Check that + impedance = Any( + help="""The input data for the ZIP imedance measurements""", unit=OHM ) - current = Any(help="""The input data for the ZIP current measurements""") - impedance = Any(help="""The input data for the ZIP imedance measurements""") - power = Any(help="""The input data for the ZIP power measurements""") + power = Any(help="""The input data for the ZIP power measurements""", unit=W) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the load data. The positions are objects containing elements of long, lat and elevation (See Position object documentation).""", + unit=None, ) def build(self, model): diff --git a/ditto/models/meter.py b/ditto/models/meter.py index 6538bcbc..506a8c5f 100644 --- a/ditto/models/meter.py +++ b/ditto/models/meter.py @@ -5,20 +5,26 @@ from .position import Position +from ..constant import V + class Meter(DiTToHasTraits): - name = Unicode(help="""Name of the meter object""") - nominal_voltage = Float(help="""The nominal voltage of the meter""") + name = Unicode(help="""Name of the meter object""", unit=None) + nominal_voltage = Float( + help="""The nominal voltage of the meter""", default_value=None, unit=V + ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the line. The positions are objects containing elements of long, lat and elevation (See Position object documentation). The points can be used to map the position of the line. """, + unit=None, ) # NOT YET CIM COMPATIBLE phases = List( Instance(Unicode), help="""This parameter is a list of all the phases at the node. The Phases are Strings of 'A', 'B', 'C', 'N', 's1' or 's2' (for secondaries).""", + unit=None, ) def build(self, model): diff --git a/ditto/models/node.py b/ditto/models/node.py index ded1a7a5..0f81a2a4 100644 --- a/ditto/models/node.py +++ b/ditto/models/node.py @@ -5,6 +5,8 @@ from .position import Position +from ..constant import V + class Node(DiTToHasTraits): """Inheritance: @@ -14,19 +16,22 @@ class Node(DiTToHasTraits): ConnectivityNode (self._cn) """ - name = Unicode(help="""Name of the node object""") + name = Unicode(help="""Name of the node object""", unit=None) nominal_voltage = Float( help="""This parameter defines the base voltage at the node.""", default_value=None, + unit=V, ) phases = List( Instance(Unicode), help="""This parameter is a list of all the phases at the node.""", + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the node - it should only contain one. The positions are objects containing elements of long, lat and elevation.""", + unit=None, ) # Modification: Nicolas (December 2017) @@ -36,9 +41,10 @@ class Node(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default=None + help="""The name of the feeder the object is on.""", default=None, unit=None ) # Modification: Tarek (April 2018) @@ -46,12 +52,14 @@ class Node(DiTToHasTraits): is_substation_connection = Int( help="""1 if the node connects from inside a substation to outside, 0 otherwise.""", default=None, + unit=None, ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) def build(self, model, Asset=None, ConnectivityNode=None, Location=None): diff --git a/ditto/models/phase_capacitor.py b/ditto/models/phase_capacitor.py index c569f8e6..996c7a3f 100644 --- a/ditto/models/phase_capacitor.py +++ b/ditto/models/phase_capacitor.py @@ -5,25 +5,33 @@ from .position import Position +from ..constant import VA + class PhaseCapacitor(DiTToHasTraits): phase = Unicode( help="""The phase (A, B, C, N, s1, s2) of the capacitor section""", default_value=None, + unit=None, + ) + var = Float( + help="""The var rating of the capacitor phase""", default_value=None, unit=VA ) - var = Float(help="""The var rating of the capacitor phase""", default_value=None) switch = Int( help="""A boolean value to denote whether or not the capacitor is switched in. 1 means it's switched in, 0 means that it's not""", default_value=None, + unit=None, ) sections = Int( help="""The maximum number of sections connected to this phase""", default_value=None, + unit=None, ) normalsections = Int( help="""The normal number of sections connected to this phase""", default_value=None, + unit=None, ) def build(self, model): diff --git a/ditto/models/phase_load.py b/ditto/models/phase_load.py index 102e32fa..3cb48afe 100644 --- a/ditto/models/phase_load.py +++ b/ditto/models/phase_load.py @@ -5,30 +5,37 @@ from .position import Position +from ..constant import W, VA + class PhaseLoad(DiTToHasTraits): phase = Unicode( - help="""The phase (A, B, C, N, s1, s2) of the load""", default_value=None + help="""The phase (A, B, C, N, s1, s2) of the load""", + default_value=None, + unit=None, ) p = Float( help="""The active power of the load which is fixed. Positive values represent flow out of the node.""", default_value=None, + unit=W, ) q = Float( help="""The reactive power of the load which is fixed. Positive values represent flow out of the node.""", default_value=None, + unit=VA, ) # Modification: Nicolas (August 2017) # OpenDSS has 8 different load models. Without this field there is no way to capture # this information in DiTTo ==> Only constant P&Q and Zipload would be considered # Note: use_zip can probably be removed since it is equivalent to model=8 - model = Int(help="""OpenDSS Load Model number.""", default_value=1) + model = Int(help="""OpenDSS Load Model number.""", default_value=1, unit=None) # TO REMOVE?? use_zip = Int( help="""Describes whether the load is reprsented as a zipload or not. 1 represents zipload with fractions taken from the p and q values above. 0 represents a load defined by p & q alone.""", default_value=0, + unit=None, ) # Modification: Nicolas Gensollen (December 2017) @@ -37,29 +44,36 @@ class PhaseLoad(DiTToHasTraits): drop = Int( help="""Set to 1 if the object should be dropped in the writing process. Otherwise leave 0.""", default_value=0, + unit=None, ) ppercentcurrent = Float( help="""This is the portion of active power load modeled as constant current. Active portions of current, power and impedance should all add to 1. Used for ZIP models.""", default_value=None, + unit=None, ) qpercentcurrent = Float( help=""" This is the portion of active power load modeled as constant impedance. Reactive portions of current, power and impedance should all add to 1. Used for ZIP models.""", default_value=None, + unit=None, ) ppercentpower = Float( - help="""This is the portion of active power load modeled as constant power. Active portions of current, power and impedance should all add to 1. Used for ZIP models.""" + help="""This is the portion of active power load modeled as constant power. Active portions of current, power and impedance should all add to 1. Used for ZIP models.""", + unit=None, ) qpercentpower = Float( - help="""This is the portion of reactive power load modeled as constant current. Reactive portions of current, power and impedance should all add to 1. Used for ZIP models.""" + help="""This is the portion of reactive power load modeled as constant current. Reactive portions of current, power and impedance should all add to 1. Used for ZIP models.""", + unit=None, ) ppercentimpedance = Float( help="""This is the portion of reactive power load modeled as Active portions of current, power and impedance should all add to 1. constant impedance. Used for ZIP models.""", default_value=None, + unit=None, ) qpercentimpedance = Float( help="""This is the portion of reactive power load modeled as constant impedance. Reactive portions of current, power and impedance should all add to 1. Used for ZIP models.""", default_value=None, + unit=None, ) def build(self, model): diff --git a/ditto/models/phase_reactor.py b/ditto/models/phase_reactor.py index 72246538..15f22d74 100644 --- a/ditto/models/phase_reactor.py +++ b/ditto/models/phase_reactor.py @@ -16,6 +16,8 @@ from .position import Position from .wire import Wire +from ..constant import A, W, OHM + class PhaseReactor(DiTToHasTraits): """ @@ -24,23 +26,30 @@ class PhaseReactor(DiTToHasTraits): phase = Unicode( help="""The phase (A, B, C, N, s1, s2) of the phase reactor""", default_value=None, + unit=None, ) ampacity = Float( help="""The ampacity rating for the phase reactor under nomal conditions""", default_value=None, + unit=A, ) emergency_ampacity = Float( help="""The ampacity rating for the phase reactor under emergency conditions""", default_value=None, + unit=A, ) rated_power = Float( - help="""The rated power of the phase reactor""", default_value=None + help="""The rated power of the phase reactor""", default_value=None, unit=W ) resistance = Float( - help="""The total resistance of the phase reactor.""", default_value=None + help="""The total resistance of the phase reactor.""", + default_value=None, + unit=OHM, ) reactance = Float( - help="""The total reactance of the phase reactor.""", default_value=None + help="""The total reactance of the phase reactor.""", + default_value=None, + unit=OHM, ) def build(self, model): diff --git a/ditto/models/phase_storage.py b/ditto/models/phase_storage.py index 389cfa7d..99578a4f 100644 --- a/ditto/models/phase_storage.py +++ b/ditto/models/phase_storage.py @@ -2,15 +2,20 @@ from .position import Position +from ..constant import W, VA + class PhaseStorage(DiTToHasTraits): - phase = Unicode(help="""The phases the device is on.""", default_value=None) + phase = Unicode( + help="""The phases the device is on.""", default_value=None, unit=None + ) p = Float( help="""Present Watt value (positive denotes power coming out, and negative is charging). In watts.""", default_value=None, + unit=W, ) - q = Float(help="""Present var value. In vars.""", default_value=None) + q = Float(help="""Present var value. In vars.""", default_value=None, unit=VA) def build(self, model): """ diff --git a/ditto/models/phase_winding.py b/ditto/models/phase_winding.py index 17103087..8ff89e39 100644 --- a/ditto/models/phase_winding.py +++ b/ditto/models/phase_winding.py @@ -5,21 +5,29 @@ from .position import Position +from ..constant import OHM + class PhaseWinding(DiTToHasTraits): tap_position = Float( help="""The initial tap position of the phase on the winding. It should be in the range [lowstep,highstep] provided by the transformer or regulator""", default_value=None, + unit=None, ) phase = Unicode( help="""The phase for this componant of the winding (A,B,C, N,s1,s2)""", default_value=None, + unit=None, ) compensator_r = Float( - help="""The compensator resistance value for the phase""", default_value=None + help="""The compensator resistance value for the phase""", + default_value=None, + unit=OHM, ) compensator_x = Float( - help="""The compensator reactance value for the phase""", default_value=None + help="""The compensator reactance value for the phase""", + default_value=None, + unit=OHM, ) def build(self, model): diff --git a/ditto/models/photovoltaic.py b/ditto/models/photovoltaic.py index 8d6c8533..2eef5d45 100644 --- a/ditto/models/photovoltaic.py +++ b/ditto/models/photovoltaic.py @@ -17,100 +17,127 @@ from .position import Position from .timeseries import Timeseries +from ..constant import V, VA, OHM, K + class Photovoltaic(DiTToHasTraits): - name = Unicode(help="""Name of the PV object""") + name = Unicode(help="""Name of the PV object""", unit=None) nominal_voltage = Float( help="""This parameter defines the base voltage at the power source.""", default_value=None, + unit=V, ) phases = List( Instance(Unicode), help="""This parameter is a list of all the phases at the power source.""", + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the power source - it should only contain one. The positions are objects containing elements of long, lat and elevation.""", + unit=None, ) rated_power = Float( - help="""The rated power of the source node""", default_value=None + help="""The rated power of the source node""", default_value=None, unit=VA ) control_type = Unicode( help="""The control scheme (voltvar_vars_over_watts, voltvar_watts_over_vars, voltvar_fixed_vars, voltvar_novars, voltwatt, watt_powerfactor, powerfactor, none) being used""", default_value=None, + unit=None, ) active_rating = Float( - help="""The active rating of the inverter""", default_value=None + help="""The active rating of the inverter""", + default_value=None, + unit=OHM, # TODO: CHECK THAT ) reactive_rating = Float( - help="""The reactive rating of the inverter""", default_value=None + help="""The reactive rating of the inverter""", + default_value=None, + unit=OHM, # TODO: CHECK THAT ) connecting_element = Unicode( help="""Name of the bus to which the power source is connected. This can be interpreted as "from" at a feeder head and "to" for a PV inverter""", default_value=None, + unit=None, ) min_power_factor = Float( - help="""The minimum power factor for the inverter""", default_value=None + help="""The minimum power factor for the inverter""", + default_value=None, + unit=None, ) cutout_percent = Float( help="""The cutout percentage. If the per-unit power drops below this value the power source turns off""", default_value=None, + unit=None, ) cutin_percent = Float( help="""The cutin percentage. If the per-unit power rises above this value the power source turns on""", default_value=None, + unit=None, ) resistance = Float( help="""The per-unit internal resistance of the power source""", default_value=None, + unit=OHM, # TODO: Check that.... ) reactance = Float( help="""The per-unit internal reactance of the power source""", default_value=None, + unit=OHM, # TODO: Check that ) v_max_pu = Float( help="""The per-unit maximum voltage. Beyond this constant impedance model is applied""", default_value=None, + unit=None, ) v_min_pu = Float( help="""The per-unit minimum voltage. Below this, constant impedance model is applied""", default_value=None, + unit=None, ) - rise_limit = Float(help="""The % rise per minute""", default_value=None) - fall_limit = Float(help="""The % fall per minute""", default_value=None) + rise_limit = Float(help="""The % rise per minute""", default_value=None, unit=None) + fall_limit = Float(help="""The % fall per minute""", default_value=None, unit=None) power_factor = Float( help="""The powerfactor used when using powerfactor control setting""", default_value=1, + unit=None, ) voltvar_curve = Unicode( help="""The voltvar curve being used. Use CYME's default volt-var curve""", default_value="DEFAULT VOLT-VAR", + unit=None, ) wattpowerfactor_curve = Unicode( help="""The watt-powerfactor curve being used. Use CYME's default volt-var curve""", default_value="DEFAULT WATT-PF", + unit=None, ) voltwatt_curve = Unicode( help="""The volt-watt curve being used. Use CYME's default volt-var curve""", default_value="DEFAULT VOLT-WATT", + unit=None, ) var_injection = Float( help="""The percentage of available reacive power injected to the system""", default_value=100, + unit=None, ) temperature = Float( - help="""The ambinent temperature in degrees celcius""", default_value=None + help="""The ambinent temperature in degrees kelvin""", + default_value=None, + unit=K, ) timeseries = List( Instance(Timeseries), help="""A list of all the timeseries elements used to represent the Solar Irradiance""", default_value=None, + unit=None, ) # Modification: Tarek (August 2018) # Multiple feeder support. Each element keeps track of the name of the substation it is connected to, as well as the name of the feeder. diff --git a/ditto/models/position.py b/ditto/models/position.py index 3efc17ec..f8c914db 100644 --- a/ditto/models/position.py +++ b/ditto/models/position.py @@ -3,11 +3,15 @@ from .base import DiTToHasTraits, Float, Unicode, Any, Int, List, observe, Instance +from ..constant import M + class Position(DiTToHasTraits): - long = Float(help="""Decimal Longitude""") - lat = Float(help="""Decimal Latitude""") - elevation = Float(help="""Decimal elevation (meters)""") + # NOTE: We are not really using lat/long I believe, but mostly coordinates in various format + # TODO: Build the conversion to parse to lat/long from given inputs... + longitude = Float(help="""Decimal Longitude""", unit=M) + latitude = Float(help="""Decimal Latitude""", unit=M) + elevation = Float(help="""Decimal elevation (meters)""", unit=M) def build(self, model): self._model = model diff --git a/ditto/models/power_source.py b/ditto/models/power_source.py index 820fde5d..5522c62d 100644 --- a/ditto/models/power_source.py +++ b/ditto/models/power_source.py @@ -15,84 +15,105 @@ from .position import Position +from ..constant import V, M, VA, OHM, DEG + class PowerSource(DiTToHasTraits): - name = Unicode(help="""Name of the power source object""") + name = Unicode(help="""Name of the power source object""", unit=None) nominal_voltage = Float( help="""This parameter defines the base voltage at the power source.""", default_value=None, + unit=V, ) per_unit = Float( help="""This parameter defines the per unit voltage at the source.""", default_value=1.0, + unit=None, ) phases = List( Instance(Unicode), help="""This parameter is a list of all the phases at the power source.""", + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the power source - it should only contain one. The positions are objects containing elements of long, lat and elevation.""", + unit=None, ) is_sourcebus = Int( - help="""A Boolean flag which is 1 if the PowerSource object is an external power source at the distribution system head""" + help="""A Boolean flag which is 1 if the PowerSource object is an external power source at the distribution system head""", + unit=None, ) rated_power = Float( - help="""The rated power of the source node""", default_value=None + help="""The rated power of the source node""", default_value=None, unit=VA ) emergency_power = Float( - help="""The emergency power of the source node""", default_value=None + help="""The emergency power of the source node""", default_value=None, unit=VA ) connection_type = Unicode( help="""The connection type (D, Y, Z, A) for Delta, Wye, Zigzag or autotransformer.""", default_value=None, + unit=None, ) cutout_percent = Float( help="""The cutout percentage. If the per-unit power drops below this value the power source turns off""", default_value=None, + unit=None, ) cutin_percent = Float( help="""The cutin percentage. If the per-unit power rises above this value the power source turns on""", default_value=None, + unit=None, ) resistance = Float( help="""The per-unit internal resistance of the power source""", default_value=None, + unit=OHM, # Not sure, to confirm... ) reactance = Float( help="""The per-unit internal reactance of the power source""", default_value=None, + unit=OHM, # Not sure, to confirm... ) v_max_pu = Float( help="""The per-unit maximum voltage. Beyond this constant impedance model is applied""", default_value=None, + unit=None, ) v_min_pu = Float( help="""The per-unit minimum voltage. Below this, constant impedance model is applied""", default_value=None, + unit=None, ) power_factor = Float( - help="""The power factor for the power source object""", default_value=None + help="""The power factor for the power source object""", + default_value=None, + unit=None, ) connecting_element = Unicode( help="""Name of the bus to which the power source is connected. This can be interpreted as "from" at a feeder head and "to" for a PV inverter""", default_value=None, + unit=None, ) # Addition Nicolas November 2017: phase_angle = Float( - help="""Base angle, degree of the first phase.""", default_value=0 + help="""Base angle, degree of the first phase.""", default_value=0, unit=DEG ) positive_sequence_impedance = Complex( - help="""Positive-sequence impedance of the source.""", default_value=None + help="""Positive-sequence impedance of the source.""", + default_value=None, + unit=OHM + "/" + M, ) zero_sequence_impedance = Complex( - help="""Zero-sequence impedance of the source.""", default_value=None + help="""Zero-sequence impedance of the source.""", + default_value=None, + unit=OHM + "/" + M, ) def build(self, model): diff --git a/ditto/models/powertransformer.py b/ditto/models/powertransformer.py index ff95e86f..45dc9147 100644 --- a/ditto/models/powertransformer.py +++ b/ditto/models/powertransformer.py @@ -6,10 +6,14 @@ from .position import Position from .winding import Winding +from ..constant import DEG, OHM, VA + class PowerTransformer(DiTToHasTraits): - name = Unicode(help="""Name of the transformer object""", default_value="") + name = Unicode( + help="""Name of the transformer object""", default_value="", unit=None + ) # Modification: Nicolas (August 2017) # Moved the rated_power from the transformer down to the windings @@ -18,54 +22,67 @@ class PowerTransformer(DiTToHasTraits): install_type = Unicode( help="""The mounting type of the transformer: one of {POLETOP, PADMOUNT, VAULT}""", default_value=None, + unit=None, ) noload_loss = Float( help="""The no-load loss for a zero sequence short-circuit test on the entire transformer""", default_value=None, + unit=None, ) phase_shift = Float( help="""The degree phase shift that the transformer causes.""", default_value=None, + unit=DEG, ) from_element = Any( help="""Name of the node which connects to the 'from' end of the transformer""", default_value=None, + unit=None, ) to_element = Any( help="""'Name of the node which connects to the 'to' end of the transformer""", default_value=None, + unit=None, ) reactances = List( Float(), help="""Reactances are described between all the windings. There are n*(n-1)/2 reactances (where n is the number of windings). For two a winding transformer this gives one value, and for a 3 winding transformer it gives 3.""", default_value=None, + unit=OHM, ) windings = List( Instance(Winding), help="""A list of the windings that the transformer contains. Most will have two windings but center tap transformers have three.""", default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the transformer - it should contain just one. The positions are objects containing elements of long, lat and elevation.""", default_value=None, + unit=None, ) # Modification: Nicolas (August 2017) - loadloss = Float(help="Percent Losses at rated load", default_value=None) - normhkva = Float(help="Normal maximum kVA rating for H winding", default_value=None) + loadloss = Float(help="Percent Losses at rated load", default_value=None, unit=None) + normhkva = Float( + help="Normal maximum kVA rating for H winding", default_value=None, unit=VA + ) # Modification: Nicolas (November 2017) is_center_tap = Int( - help="""Set to 1 if the transformer is a center tap transformer""", default=0 + help="""Set to 1 if the transformer is a center tap transformer""", + default=0, + unit=None, ) # Modification: Nicolas (December 2017) is_substation = Int( help="""Set to 1 if the transformer is a substation or is inside a substation""", default=0, + unit=None, ) # Modification: Nicolas (December 2017) @@ -75,9 +92,10 @@ class PowerTransformer(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default=None + help="""The name of the feeder the object is on.""", default=None, unit=None ) def build(self, model): diff --git a/ditto/models/reactor.py b/ditto/models/reactor.py index 00735a21..f5248862 100644 --- a/ditto/models/reactor.py +++ b/ditto/models/reactor.py @@ -16,53 +16,67 @@ from .position import Position from .phase_reactor import PhaseReactor +from ..constant import V + class Reactor(DiTToHasTraits): """ TODO """ - name = Unicode(help="""Name of the Reactor object""") + name = Unicode(help="""Name of the Reactor object""", unit=None) nominal_voltage = Float( help="""This parameter defines the base voltage of the reactor.""", default_value=None, + unit=V, ) from_element = Any( help="""Name of the node which connects to the 'from' end of the reactor""", default_value=None, + unit=None, ) to_element = Any( help="""'Name of the node which connects to the 'to' end of the reactor. If set to None, shunt reactor is assumed.""", default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the line. The positions are objects containing elements of long, lat and elevation. The points can be used to map the position of the line. """, default_value=None, + unit=None, ) connection_type = Unicode( help="""The connection type (D, Y, Z, A) for Delta, Wye, Zigzag.""", default_value=None, + unit=None, ) substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default_value=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default_value=None + help="""The name of the feeder the object is on.""", + default_value=None, + unit=None, ) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) faultrate = Float( - help="""The number of faults that occur per year""", default_value=None + help="""The number of faults that occur per year""", + default_value=None, + unit=None, ) phase_reactors = List( Instance(PhaseReactor), help="""This parameter is a list of all the phase reactors composing the reactor.""", default_value=None, + unit=None, ) # NOT SURE ABOUT IMPEDANCE MATRIX.... diff --git a/ditto/models/regulator.py b/ditto/models/regulator.py index 9c8d95fb..f8588173 100644 --- a/ditto/models/regulator.py +++ b/ditto/models/regulator.py @@ -6,87 +6,111 @@ from .position import Position from .winding import Winding +from ..constant import S, DEG, V, OHM, A + class Regulator(DiTToHasTraits): - name = Unicode(help="""Name of the regulator object""", default_value="") + name = Unicode(help="""Name of the regulator object""", default_value="", unit=None) delay = Float( - help="""The delay for first tap change operation""", default_value=None + help="""The delay for first tap change operation""", default_value=None, unit=S ) highstep = Int( help="""The hightest possible tap step position from neutral""", default_value=None, + unit=None, ) lowstep = Int( help="""The lowest possible tap step position from neutral""", default_value=None, + unit=None, ) pt_ratio = Float( help="""The turns ratio used for the power transducer with a line-drop compensator.""", default_value=None, + unit=None, ) ct_ratio = Float( help="""The turns ratio used for the current transducer with a line-drop compensator.""", default_value=None, + unit=None, ) phase_shift = Float( - help="""The degree phase shift that the regulator causes.""", default_value=None + help="""The degree phase shift that the regulator causes.""", + default_value=None, + unit=DEG, ) ltc = Int( help="""1 if this regulator is a load tap changer, 0 otherwise.""", default_value=None, + unit=None, ) bandwidth = Float( - help="""The band before a change occurs in the regulator""", default_value=None + help="""The band before a change occurs in the regulator""", + default_value=None, + unit=V, ) bandcenter = Float( help="""This is the target value for the regulator. Should often be the nominal voltage""", default_value=None, + unit=V, ) voltage_limit = Float( - help="""The maximum voltage allowed on the PT secondary""", default_value=None + help="""The maximum voltage allowed on the PT secondary""", + default_value=None, + unit=V, ) from_element = Any( help="""The node which connects to the 'from' end of the regulator""", default_value=None, + unit=None, ) to_element = Any( help="""'The node which connects to the 'to' end of the regulator""", default_value=None, + unit=None, ) connected_transformer = Unicode( help="""The name of the transformer that the voltage regulator is attached to""", default_value=None, + unit=None, ) pt_phase = Unicode( - help="""The phase being used to monitor the voltage""", default_value=None + help="""The phase being used to monitor the voltage""", + default_value=None, + unit=None, ) positions = List( Instance(Position), help="""This parameter is a list of positional points describing the regulator (typically just one). The positions are objects containing elements of long, lat and elevation (See Position object documentation).""", default_value=None, + unit=None, ) reactances = List( (Int(), Int(), Float()), help="""Reactances are described between all the windings. There are n*(n-1)/2 reactances (where n is the number of windings). For two a winding transformer this gives one value, and for a 3 winding transformer it gives 3. The list elements have (from_winding, to_winding, reactance) where from_winding and to_winding are the 1-based indices of the windings list.""", default_value=None, + unit=OHM, ) windings = List( Instance(Winding), help=""" This is a list containing one element for each winding in the voltage regulator. It describes attributes of the winding. This paramter is required to describe many compontants of the regulator. The simplest versions have two windings representing a high and low voltage.""", default_value=None, + unit=None, ) # Added by Nicolas (August 2017) winding = Int( help="""Number of the winding of the transformer element that the RegControl is monitoring.""", default_value=None, + unit=None, ) ct_prim = Float( help="""Rating, in Amperes, of the primary CT rating for converting the line amps to control amps""", default_value=None, + unit=A, ) # Added by Tarek (September 26) @@ -94,6 +118,7 @@ class Regulator(DiTToHasTraits): noload_loss = Float( help="""The no-load loss for a zero sequence short-circuit test on the regulator""", default_value=None, + unit=None, ) # Modification: Nicolas (December 2017) @@ -103,21 +128,24 @@ class Regulator(DiTToHasTraits): substation_name = Unicode( help="""The name of the substation to which the object is connected.""", default=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default=None + help="""The name of the feeder the object is on.""", default=None, unit=None ) # Modification: Tarek (April 2018) setpoint = Float( help="""The percentage p.u. voltage setpoint of the regulator""", default_value=None, + unit=None, ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", default_value=0, + unit=None, ) def build(self, model): diff --git a/ditto/models/storage.py b/ditto/models/storage.py index 0648bd4b..9dc03d1f 100644 --- a/ditto/models/storage.py +++ b/ditto/models/storage.py @@ -3,18 +3,22 @@ from .position import Position from .phase_storage import PhaseStorage +from ..constant import V, W, KWH, OHM + class Storage(DiTToHasTraits): - name = Unicode(help="""Name of the storage object.""", default_value="") + name = Unicode(help="""Name of the storage object.""", default_value="", unit=None) connecting_element = Unicode( - help="""Name of the bus the storage is connected to.""", default_value=None + help="""Name of the bus the storage is connected to.""", + default_value=None, + unit=None, ) nominal_voltage = Float( - help="""Nominal voltage for the storage element.""", default_value=None + help="""Nominal voltage for the storage element.""", default_value=None, unit=V ) rated_power = Float( - help="""Rated power of the device. In watts.""", default_value=None + help="""Rated power of the device. In watts.""", default_value=None, unit=W ) reactive_rating = Float( help="""Rated reactive power of the device. In watts.""", default_value=None @@ -23,72 +27,99 @@ class Storage(DiTToHasTraits): help="""Minimum power factor of the device""", default_value=None ) rated_kWh = Float( - help="""Rated storage capacity. In kilo-watt-hours.""", default_value=None + help="""Rated storage capacity. In kilo-watt-hours.""", + default_value=None, + unit=KWH, ) stored_kWh = Float( help="""Present amount of energy stored. In kilo-watt-hours.""", default_value=None, + unit=KWH, ) reserve = Float( help="""Percent of rated_kWh storage capacity to be held in reserve for normal operation.""", default_value=None, + unit=None, ) state = Unicode( help="""Present state of the device: {IDLING,CHARGING,DISCHARGING}.""", default_value=None, + unit=None, ) discharge_rate = Float( - help="""Discharge rate in percent of rated power.""", default_value=None + help="""Discharge rate in percent of rated power.""", default=0, unit=None + ) + charge_rate = Float( + help="""Charging rate in percent of rated power.""", default=0, unit=None ) - charge_rate = Float(help="""Charging rate in percent of rated power.""", default_value=None) charging_efficiency = Float( - help="""Percent efficiency for charging the storage element.""", default_value=None + help="""Percent efficiency for charging the storage element.""", + default=None, + unit=None, ) discharging_efficiency = Float( - help="""Percent efficiency for discharging the storage element.""", default_value=None + help="""Percent efficiency for discharging the storage element.""", + default=None, + unit=None, ) resistance = Float( - help="""Equivalent percent internal resistance. In ohms.""", default_value=None + help="""Equivalent percent internal resistance. In ohms.""", + default=None, + unit=OHM, ) reactance = Float( - help="""Equivalent percent internal reactance. In ohms.""", default_value=None + help="""Equivalent percent internal reactance. In ohms.""", + default=None, + unit=OHM, ) model_ = Int( help="""Model to use for power output with voltage. 1=constant P at specified pf. 2=constant admittance. 3=User-written model.""", - default_value=None, + default=None, + unit=None, ) yearly = Unicode( - help="""Dispatch shape to use for yearly simulations.""", default_value=None + help="""Dispatch shape to use for yearly simulations.""", + default=None, + unit=None, ) daily = Unicode( - help="""Dispatch shape to use for daily simulations.""", default_value=None + help="""Dispatch shape to use for daily simulations.""", default=None, unit=None ) duty = Unicode( - help="""Load shape to use for duty cycle dispatch simulations.""", default_value=None + help="""Load shape to use for duty cycle dispatch simulations.""", + default=None, + unit=None, ) discharge_trigger = Float( - help="""Dispatch trigger value for discharging the storage.""", default_value=None + help="""Dispatch trigger value for discharging the storage.""", + default=None, + unit=None, ) charge_trigger = Float( - help="""Dispatch trigger value for charging the storage.""", default_value=None + help="""Dispatch trigger value for charging the storage.""", + default=None, + unit=None, ) phase_storages = List( Instance(PhaseStorage), help="""A list of the phase storage that the storage contains.""", - default_value=None, + default=None, + unit=None, ) substation_name = Unicode( help="""The name of the substation to which the object is connected.""", - default_value=None, + default=None, + unit=None, ) feeder_name = Unicode( - help="""The name of the feeder the object is on.""", default_value=None + help="""The name of the feeder the object is on.""", default=None, unit=None ) # Modification: Nicolas (May 2018) is_substation = Int( help="""Flag that indicates wheter the element is inside a substation or not.""", - default_value=None, + default_value=0, + unit=None, ) def build(self, model): diff --git a/ditto/models/timeseries.py b/ditto/models/timeseries.py index 3a6f6584..d5769359 100644 --- a/ditto/models/timeseries.py +++ b/ditto/models/timeseries.py @@ -12,32 +12,40 @@ class Timeseries(DiTToHasTraits): "pandas.DataFrame", help="""This is the data that is stored in the timeseries object.""", default_value=None, + unit=None, ) data_label = Unicode( help="The label assigned to the dataset. This describes what the name should be when it is outputted to through the writers" "", default_value=None, + unit=None, ) interval = Float( help="""This is the interval in the default units that the timeseries data is recorded at. E.g. minute data would have an interval of 60 for a unit of seconds""", default=None, + unit=None, # PROBLEM HERE ) data_location = Unicode( - help="""The absolute location on disk of the data""", default_value=None + help="""The absolute location on disk of the data""", + default_value=None, + unit=None, ) data_type = Unicode( help="""This is the python datatype of the timeseries e.g. float, complex etc.""", default_value=None, + unit=None, ) loaded = Int( help="""A boolean describing whether the data is in memory or on disk. If this is 1, the data is loaded into the data field. Otherwise it is not in memory and is on disk at data_location""", default=None, + unit=None, ) scale_factor = Float( help="""A number to multiply the entire timeseries by for scaling purposes""", default_value=1, + unit=None, ) def build(self, model): diff --git a/ditto/models/weather_layer.py b/ditto/models/weather_layer.py index 15f9fb41..f6e17e5e 100644 --- a/ditto/models/weather_layer.py +++ b/ditto/models/weather_layer.py @@ -5,20 +5,25 @@ from .position import Position +from ..constant import K, S, M + class WeatherLayer(DiTToHasTraits): - name = Unicode(help="""Name of the weather object""") + name = Unicode(help="""Name of the weather object""", unit=None) interval = Integer( - help="""The time resolution (in seconds) for the measured data""" + help="""The time resolution (in seconds) for the measured data""", unit=S + ) + ghi = Any(help="""The input data for global horizontal irradiance""", unit=None) + temperature = Any(help="""The input data for temperature""", unit=K) + relative_humitidy = Any(help="""The input data for relative humidity""", unit=None) + surface_windspeed = Any( + help="""The input data for surface windspeed""", unit=M + "/" + S ) - ghi = Any(help="""The input data for global horizontal irradiance""") - temperature = Any(help="""The input data for temperature""") - relative_humitidy = Any(help="""The input data for relative humidity""") - surface_windspeed = Any(help="""The input data for surface windspeed""") positions = List( Instance(Position), help="""This parameter is a list of positional points describing the weather data. The positions are objects containing elements of long, lat and elevation (See Position object documentation).""", + unit=None, ) def build(self, model): diff --git a/ditto/models/winding.py b/ditto/models/winding.py index a73e723a..3e160b2f 100644 --- a/ditto/models/winding.py +++ b/ditto/models/winding.py @@ -6,42 +6,55 @@ from .position import Position from .phase_winding import PhaseWinding +from ..constant import V, OHM, VA + class Winding(DiTToHasTraits): connection_type = Unicode( help="""The connection type (D, Y, Z, A) for Delta, Wye, Zigzag or autotransformer.""", default_value=None, + unit=None, ) voltage_type = Int( help="""0 for a high voltage connection, 2 for a low voltage connection, and 1 for an intermediary connection.""", default_value=None, + unit=None, ) nominal_voltage = Float( - help="""The nominal voltage of the transformer winding""", default_value=None + help="""The nominal voltage of the transformer winding""", + default_value=None, + unit=V, ) voltage_limit = Float( - help="""The maximum voltage allowed on the PT secondary.""", default_value=None + help="""The maximum voltage allowed on the PT secondary.""", + default_value=None, + unit=V, ) resistance = Float( help="""The per unit resistance of the winding. For a representation with only one resistance for the entire transformer, this is split equally between the windings.""", default_value=None, + unit=OHM, # NOT SURE.... ) reverse_resistance = Float( help="""The per unit resistance of the winding with reverse powerflow. For a representation with only one resistance for the entire transformer, this is split equally between the windings.""", default_value=None, + unit=OHM, # NOT SURE... ) phase_windings = List( Instance(PhaseWinding), help="""A list of phasewinding objects which contain the phase, tap position and compensator settings""", default_value=None, + unit=None, ) # Added by Nicolas (August 2017) # Better results are obtained if the rated power is specified at the windings rather # than for the whole transformer - rated_power = Float(help="""The rated power of the winding""", default_value=None) + rated_power = Float( + help="""The rated power of the winding""", default_value=None, unit=VA + ) emergency_power = Float( - help="""The emergency power of the winding""", default_value=None + help="""The emergency power of the winding""", default_value=None, unit=VA ) def build(self, model): diff --git a/ditto/models/wire.py b/ditto/models/wire.py index 2994d545..5d771bdf 100644 --- a/ditto/models/wire.py +++ b/ditto/models/wire.py @@ -5,66 +5,84 @@ from .position import Position +from ..constant import M, CM, MM, A, OHM + class Wire(DiTToHasTraits): phase = Unicode( - help="""The phase (A, B, C, N, s1, s2) of the wire""", default_value=None + help="""The phase (A, B, C, N, s1, s2) of the wire""", + default_value=None, + unit=None, ) nameclass = Unicode( - help="""The nameclass (e.g. 1/0_ACSR) of the wire""", default_value=None + help="""The nameclass (e.g. 1/0_ACSR) of the wire""", + default_value=None, + unit=None, ) X = Float( help="""The horizontal placement of the wire on a cross section of the line w.r.t. some point of reference (typically one wire on the configuration)""", default_value=None, + unit=M, ) Y = Float( help="""The vertical placement above (or below) ground of the wire on a cross section of the line w.r.t. some point of reference (typically one wire on the configuration)""", default_value=None, + unit=M, ) diameter = Float( help="""The diameter of the conductor. If the wire is a concentric neutral cable, this is the diameter of the phase conductor.""", default_value=None, + unit=MM, ) gmr = Float( help="""The geometric mean radius of the wire. If the wire is a concentric neutral cable, this is the GMR of the phase conductor.""", default_value=None, + unit=CM, ) ampacity = Float( help="""The ampacity rating for the wire under nomal conditions""", default_value=None, + unit=A, ) emergency_ampacity = Float( help="""The ampacity rating for the wire under emergency conditions""", default_value=None, + unit=A, ) resistance = Float( help="""The total resistance of the wire. If the wire is a concentric neutral cable, this is the per-unit resistance of the phase conductor""", default_value=None, - ) + unit=OHM, + ) # I'm putting ohm for consistency but we have to change that to be per unit length insulation_thickness = Float( help="""Thickness of the insulation around the secondary live conductors""", default=None, + unit=MM, ) is_fuse = Int( help="""This flag indicates whether or not this wire is also a fuse""", default_value=None, + unit=None, ) is_switch = Int( help="""This flag indicates whether or not this wire is also a switch""", default_value=None, + unit=None, ) is_open = Int( help="""This flag indicates whether or not the line is open (if it is a switch/fuse/breaker/recloser/sectionalizer/network protector).""", default_value=None, + unit=None, ) # Modification: Nicolas Gensollen (June 2018) # fuse_limit --> interrupting_rating (more generic) interrupting_rating = Float( help="""The maximum current that can pass through the wire before the equipment disconnects.""", default_value=None, + unit=A, ) # Concentric Neutral Specific @@ -74,22 +92,27 @@ class Wire(DiTToHasTraits): concentric_neutral_gmr = Float( help="""The geometric mean radius of the neutral strand for a concentric neutral cable.""", default_value=None, + unit=CM, ) concentric_neutral_resistance = Float( help="""The per-unit length resistance of the neutral strand for a concentric neutral cable.""", default_value=None, + unit=OHM, # Again, putting ohm but have to change to be per unit ) concentric_neutral_diameter = Float( help="""The diameter of the neutral strand of the concentric neutral cable.""", default_value=None, + unit=MM, ) concentric_neutral_outside_diameter = Float( help="""The outside diameter of the concentric neutral cable.""", default_value=None, + unit=MM, ) concentric_neutral_nstrand = Int( help="""The number of strands for the concentric neutral cable.""", default_value=None, + unit=None, ) ############################################################### @@ -99,6 +122,7 @@ class Wire(DiTToHasTraits): drop = Int( help="""Set to 1 if the object should be dropped in the writing process. Otherwise leave 0.""", default_value=0, + unit=None, ) # Modification: Nicolas (December 2017) @@ -106,24 +130,28 @@ class Wire(DiTToHasTraits): is_recloser = Int( help="""This flag indicates whether or not this wire is also a recloser""", default_value=None, + unit=None, ) # Modification: Nicolas (January 2018) is_breaker = Int( help="""This flag indicates whether or not this wire is also a recloser""", default_value=None, + unit=None, ) # Modification: Nicolas (June 2018) is_network_protector = Int( help="""This flag indicates whether or not this wire is also a network protector.""", default_value=None, + unit=None, ) # Modification: Nicolas (August 2018) is_sectionalizer = Int( help="""This flag indicates whether or not this wire is also a sectionalizer.""", default_value=None, + unit=None, ) def build(self, model): diff --git a/ditto/modify/system_structure.py b/ditto/modify/system_structure.py index 5ec1f79b..05c34610 100644 --- a/ditto/modify/system_structure.py +++ b/ditto/modify/system_structure.py @@ -114,8 +114,8 @@ def set_missing_coords_recur(self): and ( i.positions is None or len(i.positions) == 0 - or i.positions[0].lat == 0 - or i.positions[0].long == 0 + or i.positions[0].latitude == 0 + or i.positions[0].longitude == 0 ) and (hasattr(i, "name") and i.name is not None) ): @@ -136,10 +136,12 @@ def set_missing_coords_recur(self): hasattr(j, "positions") and j.positions is not None and len(j.positions) != 0 - and j.positions[0].lat != 0 - and j.positions[0].long != 0 + and j.positions[0].latitude != 0 + and j.positions[0].longitude != 0 ): - adj_lats_longs.append((j.positions[0].lat, j.positions[0].long)) + adj_lats_longs.append( + (j.positions[0].latitude, j.positions[0].longitude) + ) if len(adj_lats_longs) == 0: next_recur.append(i) @@ -154,8 +156,8 @@ def set_missing_coords_recur(self): av_lat = av_lat / float(num) av_long = av_long / float(num) computed_pos = Position(self.model) - computed_pos.lat = av_lat - computed_pos.long = av_long + computed_pos.latitude = av_lat + computed_pos.longitude = av_long self.model[i].positions = [computed_pos] if len(next_recur) == len(recur_nodes): for i in recur_nodes: @@ -327,13 +329,13 @@ def set_load_coordinates(self, **kwargs): position_obj = self.model[obj.connecting_element].positions obj.positions = [] for po in position_obj: - _long = po.long - _lat = po.lat + _long = po.longitude + _lat = po.latitude _elev = po.elevation load_position = Position() - load_position.long = _long + delta_longitude - load_position.lat = _lat + delta_latitude + load_position.longitude = _long + delta_longitude + load_position.latitude = _lat + delta_latitude load_position.elevation = _elev + delta_elevation obj.positions.append(load_position) diff --git a/ditto/readers/cyme/read.py b/ditto/readers/cyme/read.py index 35c0ce2b..2acb44c6 100644 --- a/ditto/readers/cyme/read.py +++ b/ditto/readers/cyme/read.py @@ -1270,8 +1270,8 @@ def parse_nodes(self, model): # Set the coordinates try: position = Position(model) - position.long = float(node["coordx"]) - position.lat = float(node["coordy"]) + position.longitude = float(node["coordx"]) + position.latitude = float(node["coordy"]) position.elevation = 0 api_node.positions.append(position) except: @@ -2294,8 +2294,8 @@ def parse_lines(self, model): # Set the position try: position = Position(model) - position.long = float(settings["coordx"]) - position.lat = float(settings["coordy"]) + position.longitude = float(settings["coordx"]) + position.latitude = float(settings["coordy"]) position.elevation = 0 new_line["position"] = position except: @@ -3806,8 +3806,8 @@ def parse_capacitors(self, model): # Position try: position = Position(model) - position.long = float(settings["coordx"]) - position.lat = float(settings["coordy"]) + position.longitude = float(settings["coordx"]) + position.latitude = float(settings["coordy"]) position.elevation = 0 api_capacitor.position.append(position) except: @@ -4422,8 +4422,8 @@ def parse_transformers(self, model): # Set the position try: position = Position(model) - position.long = float(settings["coordx"]) - position.lat = float(settings["coordy"]) + position.longitude = float(settings["coordx"]) + position.latitude = float(settings["coordy"]) position.elevation = 0 api_transformer.positions.append(position) except: @@ -4940,8 +4940,8 @@ def parse_regulators(self, model): try: position = Position(model) - position.long = float(reg_set["coordx"]) - position.lat = float(reg_set["coordy"]) + position.longitude = float(reg_set["coordx"]) + position.latitude = float(reg_set["coordy"]) position.elevation = 0 api_regulator.positions.append(position) except: diff --git a/ditto/readers/dew/read.py b/ditto/readers/dew/read.py index fbc6bb48..e336df34 100644 --- a/ditto/readers/dew/read.py +++ b/ditto/readers/dew/read.py @@ -145,8 +145,12 @@ def parse(self, model, **kwargs): # Posiiton information can be used if required (not stored and not included in ditto) try: position = Position(model) - position.lat = float(entries[13][:-1]) # X position in EDD DEW - position.long = float(entries[14][:-1]) # Y posiiton in EDD + position.latitude = float( + entries[13][:-1] + ) # X position in EDD DEW + position.longitude = float( + entries[14][:-1] + ) # Y posiiton in EDD position.elevation = 0 api_node.positions.append(position) except AttributeError: diff --git a/ditto/readers/dew/read_new.py b/ditto/readers/dew/read_new.py index e11208f2..4a43dd16 100644 --- a/ditto/readers/dew/read_new.py +++ b/ditto/readers/dew/read_new.py @@ -126,8 +126,12 @@ def parse(self, model, inputfile, databasepath): # Posiiton information can be used if required (not stored and not included in ditto) try: position = Position(model) - position.lat = float(entries[13][:-1]) # X position in EDD DEW - position.long = float(entries[14][:-1]) # Y posiiton in EDD + position.latitude = float( + entries[13][:-1] + ) # X position in EDD DEW + position.longitude = float( + entries[14][:-1] + ) # Y posiiton in EDD position.elevation = 0 api_node.positions.append(position) except AttributeError: diff --git a/ditto/readers/opendss/read.py b/ditto/readers/opendss/read.py index 25431163..63be11de 100644 --- a/ditto/readers/opendss/read.py +++ b/ditto/readers/opendss/read.py @@ -664,8 +664,8 @@ def parse_nodes(self, model, **kwargs): try: node_pos = Position(model) - node_pos.long = data["positions"][0] - node_pos.lat = data["positions"][1] + node_pos.longitude = data["positions"][0] + node_pos.latitude = data["positions"][1] api_node.positions.append(node_pos) except: pass diff --git a/ditto/readers/synergi/read.py b/ditto/readers/synergi/read.py index 9bd18024..a696fad2 100644 --- a/ditto/readers/synergi/read.py +++ b/ditto/readers/synergi/read.py @@ -590,8 +590,8 @@ def parse(self, model): pos = Position(model) # Set the coordinates - pos.long = NodeY[i] - pos.lat = NodeX[i] + pos.longitude = NodeY[i] + pos.latitude = NodeX[i] # Add the Position to the node's positions api_node.positions.append(pos) diff --git a/ditto/writers/cyme/write.py b/ditto/writers/cyme/write.py index b18025db..1f8c0e2b 100644 --- a/ditto/writers/cyme/write.py +++ b/ditto/writers/cyme/write.py @@ -444,13 +444,13 @@ def write_network_file(self, model, **kwargs): # CoordX and CoordY if hasattr(i, "positions") and i.positions is not None: try: - new_node_string += "," + str(i.positions[0].long) + new_node_string += "," + str(i.positions[0].longitude) except: new_node_string += ",0" pass try: - new_node_string += "," + str(i.positions[0].lat) + new_node_string += "," + str(i.positions[0].latitude) except: new_node_string += ",0" pass @@ -578,8 +578,8 @@ def write_network_file(self, model, **kwargs): [ new_sectionID, seg_number, - position.long, - position.lat, + position.longitude, + position.latitude, ] ) @@ -1588,8 +1588,8 @@ def write_network_file(self, model, **kwargs): if i.name not in self.nodeID_list: if hasattr(i, "positions") and i.positions is not None: try: - X = i.positions[0].long - Y = i.positions[0].lat + X = i.positions[0].longitude + Y = i.positions[0].latitude except: X = 0 Y = 0 @@ -1911,10 +1911,10 @@ def write_network_file(self, model, **kwargs): if hasattr(i, "positions") and i.positions is not None: try: new_transformer_line += "," + str( - i.positions[0].long + i.positions[0].longitude ) new_transformer_line += "," + str( - i.positions[0].lat + i.positions[0].latitude ) except: new_transformer_line += ",," @@ -2133,8 +2133,8 @@ def write_network_file(self, model, **kwargs): # CoordX and CoordY if hasattr(i, "positions") and i.positions is not None: try: - new_regulator_string += "," + str(i.positions[0].long) - new_regulator_string += "," + str(i.positions[0].lat) + new_regulator_string += "," + str(i.positions[0].longitude) + new_regulator_string += "," + str(i.positions[0].latitude) except: new_regulator_string += ",," pass @@ -2469,10 +2469,10 @@ def write_network_file(self, model, **kwargs): ): try: new_transformer_line += "," + str( - transformer_object.positions[0].long + transformer_object.positions[0].longitude ) new_transformer_line += "," + str( - transformer_object.positions[0].lat + transformer_object.positions[0].latitude ) except: new_transformer_line += ",," @@ -2833,10 +2833,10 @@ def write_network_file(self, model, **kwargs): ): try: new_transformer_line += "," + str( - transformer_object.positions[0].long + transformer_object.positions[0].longitude ) new_transformer_line += "," + str( - transformer_object.positions[0].lat + transformer_object.positions[0].latitude ) except: new_transformer_line += ",," @@ -3333,11 +3333,11 @@ def write_network_file(self, model, **kwargs): isinstance(obj, Node) and len(obj.positions) > 0 and obj.positions[0] is not None - and obj.positions[0].lat is not None - and obj.positions[0].long is not None + and obj.positions[0].latitude is not None + and obj.positions[0].longitude is not None ): - all_coordsX.append(obj.positions[0].long) - all_coordsY.append(obj.positions[0].lat) + all_coordsX.append(obj.positions[0].longitude) + all_coordsY.append(obj.positions[0].latitude) # (CASE 1) - Since we don't know what the LV value is beforehand, we store all coordinates by nominal voltage # in the dictionaries by_nominal_voltage_X and by_nominal_voltage_Y. if ( @@ -3351,8 +3351,8 @@ def write_network_file(self, model, **kwargs): and obj.positions[0] is not None ): if ( - obj.positions[0].lat is not None - and obj.positions[0].long is not None + obj.positions[0].latitude is not None + and obj.positions[0].longitude is not None ): if ( obj.nominal_voltage @@ -3362,17 +3362,17 @@ def write_network_file(self, model, **kwargs): ): by_nominal_voltage_X[ obj.nominal_voltage - ].append(obj.positions[0].long) + ].append(obj.positions[0].longitude) by_nominal_voltage_Y[ obj.nominal_voltage - ].append(obj.positions[0].lat) + ].append(obj.positions[0].latitude) else: by_nominal_voltage_X[ obj.nominal_voltage - ] = [obj.positions[0].long] + ] = [obj.positions[0].longitude] by_nominal_voltage_Y[ obj.nominal_voltage - ] = [obj.positions[0].lat] + ] = [obj.positions[0].latitude] # (CASE 2) - If the nominal voltage was None, then add the coordinates to the default list else: if ( @@ -3380,11 +3380,11 @@ def write_network_file(self, model, **kwargs): and obj.positions[0] is not None ): if ( - obj.positions[0].lat is not None - and obj.positions[0].long is not None + obj.positions[0].latitude is not None + and obj.positions[0].longitude is not None ): - defaultX.append(obj.positions[0].long) - defaultY.append(obj.positions[0].lat) + defaultX.append(obj.positions[0].longitude) + defaultY.append(obj.positions[0].latitude) # (CASE 1) if len(list(by_nominal_voltage_X.keys())) > 0: low_voltage = min(list(by_nominal_voltage_X.keys())) @@ -3445,8 +3445,8 @@ def write_network_file(self, model, **kwargs): # We also need the coordinates of this connection. # Use the coordinates of the Node if obj.positions is not None and len(obj.positions) > 0: - X = obj.positions[0].long - Y = obj.positions[0].lat + X = obj.positions[0].longitude + Y = obj.positions[0].latitude # If we don't have coordinates, then set to (0,0).... else: X = 0 @@ -3980,8 +3980,8 @@ def write_load_file(self, model, **kwargs): self.nodeID_list.append(i.name) if hasattr(i, "positions") and i.positions is not None: try: - X = i.positions[0].long - Y = i.positions[0].lat + X = i.positions[0].longitude + Y = i.positions[0].latitude except: X = 0 Y = 0 diff --git a/ditto/writers/ephasor/write.py b/ditto/writers/ephasor/write.py index f300c487..1e43868d 100644 --- a/ditto/writers/ephasor/write.py +++ b/ditto/writers/ephasor/write.py @@ -125,8 +125,8 @@ def write_bus_coordinates(self, **kwargs): logger.debug( "{name} {X} {Y}\n".format( name=i.name.lower(), - X=i.positions[0].lat, - Y=i.positions[0].long, + X=i.positions[0].latitude, + Y=i.positions[0].longitude, ) ) diff --git a/ditto/writers/opendss/write.py b/ditto/writers/opendss/write.py index 8fbf6a67..2a73434f 100644 --- a/ditto/writers/opendss/write.py +++ b/ditto/writers/opendss/write.py @@ -342,7 +342,9 @@ def write_bus_coordinates(self, model): txt = feeder_text_map[substation_name + "_" + feeder_name] txt += "{name} {X} {Y}\n".format( - name=i.name.lower(), X=i.positions[0].lat, Y=i.positions[0].long + name=i.name.lower(), + X=i.positions[0].latitude, + Y=i.positions[0].longitude, ) feeder_text_map[substation_name + "_" + feeder_name] = txt