From ea76d71b8d08eb3c06c3602b7108eb648e728feb Mon Sep 17 00:00:00 2001 From: Nathan Moore Date: Mon, 4 Dec 2023 09:55:46 -0700 Subject: [PATCH 1/5] fix: pd.read_csv not formatted correctly --- ditto/writers/opendss/write.py | 102 ++++++++++++++++----------------- 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/ditto/writers/opendss/write.py b/ditto/writers/opendss/write.py index 119422f4..9c45a0d3 100644 --- a/ditto/writers/opendss/write.py +++ b/ditto/writers/opendss/write.py @@ -146,7 +146,7 @@ def float_to_str(self, f): def write(self, model, separate_feeders = False, separate_substations = False, write_taps=False, verbose=False): """General writing function responsible for calling the sub-functions. - Note: re.sub('[^0-9a-zA-Z]+', '_', object_name) is used to fix node/bus names for OpenDSS, + Note: re.sub('[^0-9a-zA-Z]+', '_', object_name) is used to fix node/bus names for OpenDSS, which uses dots for phase designation and spaces for paramater delimiters. :param model: DiTTo model @@ -1047,8 +1047,8 @@ def write_storages(self, model): # Phases if hasattr(i, "phase_storages") and i.phase_storages is not None: - if i.nominal_voltage < 300: # Line-Neutral voltage for 120 V - txt += " phases=1" + if i.nominal_voltage < 300: # Line-Neutral voltage for 120 V + txt += " phases=1" else: txt += " phases={N_phases}".format(N_phases=len(i.phase_storages)) @@ -1069,7 +1069,7 @@ def write_storages(self, model): hasattr(i, "connecting_element") and i.connecting_element is not None ): - if i.nominal_voltage is None: + if i.nominal_voltage is None: i.nominal_voltage = model[i.connecting_element].nominal_voltage txt += " bus1={elt}".format(elt=re.sub('[^0-9a-zA-Z]+', '_', i.connecting_element)) if ( @@ -1173,7 +1173,7 @@ def write_storages(self, model): # Yearly/Daily/Duty/Charge trigger/Discharge trigger # - # TODO + # TODO txt += "\n" feeder_text_map[substation_name + "_" + feeder_name] = txt @@ -1460,12 +1460,12 @@ def write_PVs(self, model): voltvar_nodes.add(i.name) if ( - hasattr(i, "control_type") - and i.control_type is not None - and i.control_type == "voltwatt_voltvar" - ): - txt += " Model=1" - voltwatt_voltvar_nodes.add(i.name) + hasattr(i, "control_type") + and i.control_type is not None + and i.control_type == "voltwatt_voltvar" + ): + txt += " Model=1" + voltwatt_voltvar_nodes.add(i.name) if ( hasattr(i, "timeseries") @@ -1539,13 +1539,13 @@ def write_PVs(self, model): inv_txt = inv_txt.strip(",") inv_txt += "]" - - if len(voltwatt_voltvar_nodes) > 0: - if not len(voltvar_nodes) > 0: - inv_txt += "New XYCurve.VoltVarCurve_{loc} npts=6 Yarray=(1.0,1.0,0.0,0.0,-1.0,-1.0) Xarray=(0.5,0.92,0.98,1.02,1.08,1.5)\n\n".format( loc=substation_name + "_" + feeder_name) # Default voltvar curve used is 1547 Cat-B - if not len(voltwatt_nodes) > 0: - inv_txt += "New XYCurve.VoltWattCurve_{loc} npts=4 Yarray=(1.0,1.0,0.0,0.0) XArray=(0.5,1.06,1.1,1.5)\n\n".format( loc=substation_name + "_" + feeder_name) # Default volt-watt curve used - for node in voltwatt_voltvar_nodes: + + if len(voltwatt_voltvar_nodes) > 0: + if not len(voltvar_nodes) > 0: + inv_txt += "New XYCurve.VoltVarCurve_{loc} npts=6 Yarray=(1.0,1.0,0.0,0.0,-1.0,-1.0) Xarray=(0.5,0.92,0.98,1.02,1.08,1.5)\n\n".format( loc=substation_name + "_" + feeder_name) # Default voltvar curve used is 1547 Cat-B + if not len(voltwatt_nodes) > 0: + inv_txt += "New XYCurve.VoltWattCurve_{loc} npts=4 Yarray=(1.0,1.0,0.0,0.0) XArray=(0.5,1.06,1.1,1.5)\n\n".format( loc=substation_name + "_" + feeder_name) # Default volt-watt curve used + for node in voltwatt_voltvar_nodes: inv_txt += "New InvControl.InvPVCtrVW_{node} Combimode=VV_VW voltage_curvex_ref=rated vvc_curve1=VoltVarCurve_{loc} VV_RefReactivePower=VARMAX_VARS VoltwattYAxis=PAVAILABLEPU voltwatt_curve=VoltWattCurve_{loc} eventlog=yes DeltaQ_factor = 0.25 DeltaP_factor=0.25 PVSystemlist=[{node}]\n\n".format( loc=substation_name + "_" + feeder_name, node=node) if txt != "": @@ -1660,7 +1660,7 @@ def write_timeseries(self, model): continue # WARNING - this step can be slow for big systems with lots of data npoints = len( - pd.read_csv(os.path.join(self.output_path, i.data_location)),header=None + pd.read_csv(os.path.join(self.output_path, i.data_location),header=None) ) if self.timeseries_iternumber is None: @@ -2058,7 +2058,7 @@ def write_loads(self, model): txt += "\n\n" feeder_text_map[substation_name + "_" + feeder_name] = txt - + for substation_name in substation_text_map: for feeder_name in substation_text_map[substation_name]: txt = feeder_text_map[substation_name + "_" + feeder_name] @@ -2327,7 +2327,7 @@ def write_regulators(self, model): pass # XLT: try: # probably an index error b/c cyme reader only has api_transformer.reactances = [float(xhl)] - if isinstance(i.reactances[1], (int, float)): + if isinstance(i.reactances[1], (int, float)): transfo_creation_string += " XLT={}".format( i.reactances[1] ) @@ -2904,11 +2904,11 @@ def write_lines(self, model): else: continue - if hasattr(i,'positions') and i.positions is not None and len(i.positions) > 0: + if hasattr(i,'positions') and i.positions is not None and len(i.positions) > 0: intermediate_txt += i.name - for position in i.positions: - intermediate_txt +=f';({position.long},{position.lat})' - intermediate_txt+='\n\n' + for position in i.positions: + intermediate_txt +=f';({position.long},{position.lat})' + intermediate_txt+='\n\n' # Set the units in miles for comparison (IEEE 13 nodes feeder) # TODO: Let the user specify the export units @@ -3066,28 +3066,28 @@ def write_lines(self, model): self.files_to_redirect.append( os.path.join(output_redirect, self.output_filenames["lines"]) ) - if intermediate_txt != "": - output_folder = None - output_redirect = None - if self.separate_substations: - output_folder = os.path.join(self.output_path, substation_name) - output_redirect = substation_name - if not os.path.exists(output_folder): - os.makedirs(output_folder) - else: - output_folder = os.path.join(self.output_path) - output_redirect = "" - if not os.path.exists(output_folder): - os.makedirs(output_folder) - if self.separate_feeders: - output_folder = os.path.join(output_folder, feeder_name) - output_redirect = os.path.join(output_redirect, feeder_name) - if not os.path.exists(output_folder): - os.makedirs(output_folder) - with open( - os.path.join(output_folder, self.output_filenames["intermediates"]), "w" - ) as fp: - fp.write(intermediate_txt) + if intermediate_txt != "": + output_folder = None + output_redirect = None + if self.separate_substations: + output_folder = os.path.join(self.output_path, substation_name) + output_redirect = substation_name + if not os.path.exists(output_folder): + os.makedirs(output_folder) + else: + output_folder = os.path.join(self.output_path) + output_redirect = "" + if not os.path.exists(output_folder): + os.makedirs(output_folder) + if self.separate_feeders: + output_folder = os.path.join(output_folder, feeder_name) + output_redirect = os.path.join(output_redirect, feeder_name) + if not os.path.exists(output_folder): + os.makedirs(output_folder) + with open( + os.path.join(output_folder, self.output_filenames["intermediates"]), "w" + ) as fp: + fp.write(intermediate_txt) # Just write the file - don't redirect it return 1 @@ -3992,7 +3992,7 @@ def write_master_file(self, model): "Buscoords {f}\n".format(f=self.output_filenames["buses"]) ) # The buscoords are also written to base folder as well as the subfolders - fp.write("set maxcontroliter=50\n") # for volt-var convergence if needed + fp.write("set maxcontroliter=50\n") # for volt-var convergence if needed if self.has_timeseries: fp.write("\nSolve mode={timestep} number={iternumber}\n".format(timestep=self.timeseries_solve_format,iternumber=self.timeseries_iternumber)) #Run for first day of year @@ -4088,11 +4088,9 @@ def write_master_file(self, model): "Buscoords {f}\n".format(f=self.output_filenames["buses"]) ) # The buscoords are also written to base folder as well as the subfolders - fp.write("set maxcontroliter=50\n") # for volt-var convergence if needed + fp.write("set maxcontroliter=50\n") # for volt-var convergence if needed if self.has_timeseries: fp.write("\nSolve mode={timestep} number={iternumber}\n".format(timestep=self.timeseries_solve_format,iternumber=self.timeseries_iternumber)) #Run for first day of year - + else: fp.write("\nSolve\n") - - From de823d7fb3395f3a12679ee1b207ae4f2a5dc4c7 Mon Sep 17 00:00:00 2001 From: Nathan Moore Date: Mon, 4 Dec 2023 11:45:39 -0700 Subject: [PATCH 2/5] only support python >=3.8, which allows newer pandas versions --- setup.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 2812d9c9..799e3056 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ extras_requires = [ "lxml~=4.9", - "pandas~=1.3.5", # Pyton 3.7 does not support pandas 1.4 + "pandas~=2.0", "scipy~=1.7", numpy_dependency, "XlsxWriter~=3.0", @@ -111,9 +111,11 @@ def run(self): "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Natural Language :: English", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], test_suite="tests", install_requires=[ @@ -123,7 +125,7 @@ def run(self): "six~=1.16", "traitlets~=5.1", "json_tricks~=3.16", - "pandas~=1.3.5", + "pandas~=2.0", numpy_dependency, ], extras_require={ From 77ba46ab6f31d636ae64d3c08bc796e71e8beb24 Mon Sep 17 00:00:00 2001 From: Nathan Moore Date: Mon, 4 Dec 2023 11:46:11 -0700 Subject: [PATCH 3/5] run ci tests on python 3.8 & 3.12, and remove duplicate ci run --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5287cde..3423f54e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: CI -on: [push, pull_request] +on: [push] jobs: build: @@ -10,9 +10,9 @@ jobs: os: - ubuntu-latest - windows-latest - python-version: [ '3.7', '3.8', '3.9' ] + python-version: ['3.8', '3.12'] - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - name: Set up Python From 38da4f73c2a3237818a71d9fc4b59dcbaf5e779c Mon Sep 17 00:00:00 2001 From: Nathan Moore Date: Mon, 4 Dec 2023 11:46:20 -0700 Subject: [PATCH 4/5] bump to version 0.2.4 --- ditto/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ditto/version.py b/ditto/version.py index 930d0ece..3961bad3 100644 --- a/ditto/version.py +++ b/ditto/version.py @@ -1,2 +1,2 @@ # -*- coding: utf-8 -*- -__version__ = "0.2.3" +__version__ = "0.2.4" From fa57a4f0ecce811cf51f10ea2042305608a43fb7 Mon Sep 17 00:00:00 2001 From: Nathan Moore Date: Mon, 4 Dec 2023 14:35:25 -0700 Subject: [PATCH 5/5] also run CI on pull_request --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3423f54e..831f51c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,6 @@ name: CI -on: [push] +on: [push, pull_request] jobs: build: