diff --git a/.gitignore b/.gitignore index 080f4392b8659a7a20f924541282b5f0ab20c876..84e340c2c3810c7cc7d79a3df9183bc0e6b6cf5c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,37 +1,37 @@ -# ignore results -*.csv -*.mat - -# ignore symbolic links -*.egg-info -*.eggs - -# ignore compiled python files -*.pyc - -# ignore logging files -*.log - -# ignore generated dymola files -buildlog.txt -dsfinal.txt -dsin.txt -dslog.txt -dsmodel* -dymosim* - -# ignore matlab dumping file -*.mdmp - -# ignore spyder project -.spyderproject -.spyproject - -# ignore pycharm files -.idea -__pycache__ - -# ignore jupyter notebook files -.ipynb_checkpoints - +# ignore results +*.csv +*.mat + +# ignore symbolic links +*.egg-info +*.eggs + +# ignore compiled python files +*.pyc + +# ignore logging files +*.log + +# ignore generated dymola files +buildlog.txt +dsfinal.txt +dsin.txt +dslog.txt +dsmodel* +dymosim* + +# ignore matlab dumping file +*.mdmp + +# ignore spyder project +.spyderproject +.spyproject + +# ignore pycharm files +.idea +__pycache__ + +# ignore jupyter notebook files +.ipynb_checkpoints + Test.py \ No newline at end of file diff --git a/README.md b/README.md index c375fe983d27b46cc8766dc899188129e9efcd22..1a98bdfa2da089132b1ae049a95746ef9800f245 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,38 @@ -# Dataprocessing toolkit for RWTH ACS simulators - -## Copyright - -2017, Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University - -## License - -This project is released under the terms of the [GPL version 3](COPYING.md). - -``` -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -``` - -For other licensing options please consult [Prof. Antonello Monti](mailto:amonti@eonerc.rwth-aachen.de). - -## Contact - -[](http://www.acs.eonerc.rwth-aachen.de) - -- Markus Mirz <mmirz@eonerc.rwth-aachen.de> -- Jan Dinkelbach <JDinkelbach@eonerc.rwth-aachen.de> -- Steffen Vogel <stvogel@eonerc.rwth-aachen.de> - -[Institute for Automation of Complex Power Systems (ACS)](http://www.acs.eonerc.rwth-aachen.de) -[EON Energy Research Center (EONERC)](http://www.eonerc.rwth-aachen.de) -[RWTH University Aachen, Germany](http://www.rwth-aachen.de) +# Dataprocessing toolkit for RWTH ACS simulators + +## Copyright + +2017, Institute for Automation of Complex Power Systems, EONERC, RWTH Aachen University + +## License + +This project is released under the terms of the [GPL version 3](COPYING.md). + +``` +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +``` + +For other licensing options please consult [Prof. Antonello Monti](mailto:amonti@eonerc.rwth-aachen.de). + +## Contact + +[](http://www.acs.eonerc.rwth-aachen.de) + +- Markus Mirz <mmirz@eonerc.rwth-aachen.de> +- Jan Dinkelbach <JDinkelbach@eonerc.rwth-aachen.de> +- Steffen Vogel <stvogel@eonerc.rwth-aachen.de> + +[Institute for Automation of Complex Power Systems (ACS)](http://www.acs.eonerc.rwth-aachen.de) +[EON Energy Research Center (EONERC)](http://www.eonerc.rwth-aachen.de) +[RWTH University Aachen, Germany](http://www.rwth-aachen.de) diff --git a/dataprocessing/dpsim.py b/dataprocessing/dpsim.py index 6ba330338348b5d445edf86fd0e3115516283663..7fab233cd103ee08313c1d89c62b4aa78247a0c4 100644 --- a/dataprocessing/dpsim.py +++ b/dataprocessing/dpsim.py @@ -1,30 +1,30 @@ -from dataprocessing.readtools import * -from dataprocessing.timeseries import * - -def get_node_voltage_phasors(dpsim_timeseries_list): - """Calculate voltage phasors of all nodes - :param dpsim_timeseries_list: timeseries list retrieved from dpsim results - :return: - """ - voltage_phasor_list = {} - for ts in dpsim_timeseries_list: - ts_abs = ts.abs(ts.name + '_abs') - ts_phase = ts.phase(ts.name + '_phase') - ts_phasor = {} - ts_phasor['abs'] = ts_abs - ts_phasor['phase'] = ts_phase - voltage_phasor_list[ts.name] = ts_phasor - - return voltage_phasor_list - -def get_node_emt_voltages(timeseries_list, freq): - """Calculate voltage phasors of all nodes - :param timeseries_list: timeseries list retrieved from dpsim results - :return: - """ - voltages_list = {} - for ts in timeseries_list: - ts_emt = ts.dynphasor_shift_to_emt(ts.name, freq) - voltages_list[ts.name] = ts_emt - - return voltages_list +from dataprocessing.readtools import * +from dataprocessing.timeseries import * + +def get_node_voltage_phasors(dpsim_timeseries_list): + """Calculate voltage phasors of all nodes + :param dpsim_timeseries_list: timeseries list retrieved from dpsim results + :return: + """ + voltage_phasor_list = {} + for ts in dpsim_timeseries_list: + ts_abs = ts.abs(ts.name + '_abs') + ts_phase = ts.phase(ts.name + '_phase') + ts_phasor = {} + ts_phasor['abs'] = ts_abs + ts_phasor['phase'] = ts_phase + voltage_phasor_list[ts.name] = ts_phasor + + return voltage_phasor_list + +def get_node_emt_voltages(timeseries_list, freq): + """Calculate voltage phasors of all nodes + :param timeseries_list: timeseries list retrieved from dpsim results + :return: + """ + voltages_list = {} + for ts in timeseries_list: + ts_emt = ts.dynphasor_shift_to_emt(ts.name, freq) + voltages_list[ts.name] = ts_emt + + return voltages_list diff --git a/dataprocessing/plottools.py b/dataprocessing/plottools.py index 768b709ea56c0a4f61c07c7b961c71e7a5fd23e5..61c7b50780547359129ef9c0a4c7a0c97c29b57b 100644 --- a/dataprocessing/plottools.py +++ b/dataprocessing/plottools.py @@ -1,40 +1,40 @@ -import matplotlib.pyplot as plt -import numpy as np -from .timeseries import * - - -def plot_timeseries(figure_id, timeseries, plt_linestyle='-', plt_linewidth=2, plt_color=None, plt_legend_loc='lower right'): - """ - This function plots either a single timeseries or several timeseries in the figure defined by figure_id. - Several timeseries (handed over in a list) are plotted in several subplots. - In order to plot several timeseries in one plot, the function is to be called several times (hold is activated). - """ - plt.figure(figure_id) - if not isinstance(timeseries, list): - if plt_color: - plt.plot(timeseries.time, timeseries.values, linestyle=plt_linestyle, label=timeseries.label, linewidth=plt_linewidth, color=plt_color) - else: - plt.plot(timeseries.time, timeseries.values, linestyle=plt_linestyle, label=timeseries.label, linewidth=plt_linewidth) - plt.gca().autoscale(axis='x', tight=True) - plt.legend(loc=plt_legend_loc) - else: - for ts in timeseries: - plt.subplot(len(timeseries), 1, timeseries.index(ts) + 1) - if plt_color: - plt.plot(ts.time, ts.values, linestyle=plt_linestyle, label=ts.label, linewidth=plt_linewidth, color=plt_color) - else: - plt.plot(ts.time, ts.values, linestyle=plt_linestyle, label=ts.label, linewidth=plt_linewidth) - plt.gca().autoscale(axis='x', tight=True) - plt.legend() - - -def set_timeseries_labels(timeseries, timeseries_labels): - """ - Sets label attribute of timeseries, later used in plotting functions. - Suitable for single timeseries as well as for several timeseries (handed over in a list). - """ - if not isinstance(timeseries, list): - timeseries.label = timeseries_labels - else: - for ts in timeseries: - ts.label = timeseries_labels[timeseries.index(ts)] +import matplotlib.pyplot as plt +import numpy as np +from .timeseries import * + + +def plot_timeseries(figure_id, timeseries, plt_linestyle='-', plt_linewidth=2, plt_color=None, plt_legend_loc='lower right'): + """ + This function plots either a single timeseries or several timeseries in the figure defined by figure_id. + Several timeseries (handed over in a list) are plotted in several subplots. + In order to plot several timeseries in one plot, the function is to be called several times (hold is activated). + """ + plt.figure(figure_id) + if not isinstance(timeseries, list): + if plt_color: + plt.plot(timeseries.time, timeseries.values, linestyle=plt_linestyle, label=timeseries.label, linewidth=plt_linewidth, color=plt_color) + else: + plt.plot(timeseries.time, timeseries.values, linestyle=plt_linestyle, label=timeseries.label, linewidth=plt_linewidth) + plt.gca().autoscale(axis='x', tight=True) + plt.legend(loc=plt_legend_loc) + else: + for ts in timeseries: + plt.subplot(len(timeseries), 1, timeseries.index(ts) + 1) + if plt_color: + plt.plot(ts.time, ts.values, linestyle=plt_linestyle, label=ts.label, linewidth=plt_linewidth, color=plt_color) + else: + plt.plot(ts.time, ts.values, linestyle=plt_linestyle, label=ts.label, linewidth=plt_linewidth) + plt.gca().autoscale(axis='x', tight=True) + plt.legend() + + +def set_timeseries_labels(timeseries, timeseries_labels): + """ + Sets label attribute of timeseries, later used in plotting functions. + Suitable for single timeseries as well as for several timeseries (handed over in a list). + """ + if not isinstance(timeseries, list): + timeseries.label = timeseries_labels + else: + for ts in timeseries: + ts.label = timeseries_labels[timeseries.index(ts)] diff --git a/dataprocessing/readtools.py b/dataprocessing/readtools.py index 5dbdef83614474172a53baa837cf9d3f91f6bddb..c6e1e24a123a83dc551786fd870b726a165cc762 100644 --- a/dataprocessing/readtools.py +++ b/dataprocessing/readtools.py @@ -1,341 +1,341 @@ -#!/usr/bin/python -# coding: utf8 - -import numpy as np -import pandas as pd -from timeseries import * -import re - - - -def read_timeseries_Modelica(filename, timeseries_names=None, is_regex=False): - from modelicares import SimRes - sim = SimRes(filename) - if timeseries_names is None and is_regex is False: - # No trajectory names or regex specified, thus read in all - timeseries = [] - for name in sim.names(): - timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) - timeseries_names = sim.names() - elif is_regex is True: - # Read in variables which match with regex - timeseries = [] - p = re.compile(timeseries_names) - timeseries_names = [name for name in sim.names() if p.search(name)] - timeseries_names.sort() - for name in timeseries_names: - timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) - else: - # Read in specified time series - if not isinstance(timeseries_names, list): - timeseries = TimeSeries(timeseries_names, sim(timeseries_names).times(), sim(timeseries_names).values()) - else: - timeseries = [] - for name in timeseries_names: - timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) - - return timeseries - - -def read_timeseries_PLECS(filename, timeseries_names=None): - pd_df = pd.read_csv(filename) - timeseries_list = [] - if timeseries_names is None: - # No trajectory names specified, thus read in all - timeseries_names = list(pd_df.columns.values) - timeseries_names.remove('Time') - for name in timeseries_names: - timeseries_list.append(TimeSeries(name, pd_df['Time'].values, pd_df[name].values)) - else: - # Read in specified time series - for name in timeseries_names: - timeseries_list.append(TimeSeries(name, pd_df['Time'].values, pd_df[name].values)) - - print('PLECS results column names: ' + str(timeseries_names)) - print('PLECS results number: ' + str(len(timeseries_list))) - - return timeseries_list - -def read_timeseries_simulink(filename, timeseries_names=None): - pd_df = pd.read_csv(filename) - timeseries_list = [] - if timeseries_names is None: - # No trajectory names specified, thus read in all - timeseries_names = list(pd_df.columns.values) - timeseries_names.remove('time') - for name in timeseries_names: - timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values)) - else: - # Read in specified time series - for name in timeseries_names: - timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values)) - - print('Simulink results column names: ' + str(timeseries_names)) - print('Simulink results number: ' + str(len(timeseries_list))) - - return timeseries_list - -def read_timeseries_dpsim_real(filename, timeseries_names=None): - """Reads real time series data from DPsim log file which may have a header. - Timeseries names are assigned according to the header names if available. - :param filename: name of the csv file that has the data - :param timeseries_names: column names which should be read - :return: list of Timeseries objects - """ - timeseries_list = [] - pd_df = pd.read_csv(filename) - - if timeseries_names is None: - # No column names specified, thus read in all and strip spaces - pd_df.rename(columns=lambda x: x.strip(), inplace=True) - column_names = list(pd_df.columns.values) - - # Remove timestamps column name and store separately - column_names.remove('time') - timestamps = pd_df.iloc[:,0] - - for name in column_names: - timeseries_list.append(TimeSeries(name, timestamps, pd_df[name].values)) - else: - # Read in specified time series - print('no column names specified yet') - - print('DPsim results column names: ' + str(column_names)) - print('DPsim results number: ' + str(len(timeseries_list))) - - return timeseries_list - -def read_timeseries_dpsim_cmpl(filename, timeseries_names=None): - """Reads complex time series data from DPsim log file. Real and - imaginary part are stored in one complex variable. - :param filename: name of the csv file that has the data - :param timeseries_names: column name which should be read - :return: list of Timeseries objects - """ - pd_df = pd.read_csv(filename) - timeseries_list = [] - - if timeseries_names is None: - # No column names specified, thus read in all and strip off spaces - pd_df.rename(columns=lambda x: x.strip(), inplace=True) - column_names = list(pd_df.columns.values) - - # Remove timestamps column name and store separately - column_names.remove('time') - timestamps = pd_df.iloc[:,0] - # Calculate number of network nodes since array is [real, imag] - node_number = int(len(column_names) / 2) - node_index = 1 - for column in column_names: - if node_index <= node_number: - ts_name = 'n'+ str(node_index) - timeseries_list.append( - TimeSeries(ts_name, timestamps, np.vectorize(complex)(pd_df.iloc[:,node_index],pd_df.iloc[:,node_index + node_number]))) - else: - break - node_index = node_index + 1 - else: - # Read in specified time series - print('cannot read specified columns yet') - - print('DPsim results column names: ' + str(column_names)) - print('DPsim results number: ' + str(len(timeseries_list))) - - return timeseries_list - -def read_timeseries_dpsim_cmpl_separate(filename, timeseries_names=None): - """Deprecated - Reads complex time series data from DPsim log file. Real and - imaginary part are stored separately. - :param filename: name of the csv file that has the data - :param timeseries_names: column name which should be read - :return: list of Timeseries objects - """ - pd_df = pd.read_csv(filename, header=None) - timeseries_list = [] - - if timeseries_names is None: - # No trajectory names specified, thus read in all - column_names = list(pd_df.columns.values) - # Remove timestamps column name and store separately - column_names.remove(0) - timestamps = pd_df.iloc[:, 0] - # Calculate number of network nodes since array is [real, imag] - node_number = int(len(column_names) / 2) - node_index = 1 - for column in column_names: - if node_index <= node_number: - node_name = 'node '+ str(node_index) +' Re' - timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column])) - else: - node_name = 'node '+ str(node_index - node_number) +' Im' - timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column])) - - node_index = node_index + 1 - else: - # Read in specified time series - print('no column names specified yet') - - print('DPsim results file length:') - print(len(timeseries_list)) - for result in timeseries_list: - print(result.name) - return timeseries_list - - -def read_timeseries_NEPLAN_loadflow(file_name, timeseries_names=None, is_regex=False): - """ - Read in NEPLAN loadflow result from result file, the result is in angle notation, amplitude and angle are stored - separately - To keep consistent with the names of voltage in most cases, the name of voltage variables are changed into '.V*' - instead of '.U*' as in the result file - - :param file_name: name of the mat file for the loadflow result from neplan - :param timeseries_names: column name to be read - :param is_regex: flag for using regular expression - :return: list of Timeseries objects - """ - str_tmp = open(file_name, "r") # Read in files - low = 0 # flag for the start of a new data in str_cmp - high = 0 # flag for the end of this new data in str_cmp - flag = True # To judge if this is the first line of the file, which will be the names for the data type - - # Read in data from result file of neplan - seq = [] # list for data type names - value = [] # list for data - - - namelist = ['U', 'ANGLEU', 'P', 'Q', 'I', 'ANGLEI'] # Suffix of the data name - timeseries = [] - line_del = [] # a list for the value to be deleted - isfloat = re.compile(r'^[-+]?[0-9]+\.[0-9]+$') # regular expression to find float values - - # Transfer ',' in the floats in result file to '.' - for line in str_tmp.readlines(): # Check the data to find out floats with ',' - line = line.replace(",", ".") - high -= high - low -= low - del value[:] - # read in different data and start processing - for letter in line: - if letter == " " or letter == "\n": # different data(separated by ' ') or end(/n) - if low is not high: # if low is equal to high, no data read in - if flag: # first line of the file, list for data-type name - seq.append(line[low:high]) - else: # not first line of the file,list for data - if isfloat.match(line[low:high]): - value.append(float(line[low:high])) - else: - value.append(line[low:high]) - else: # no data for this datatype - value.append(r'#') # No value, set as # - low = high + 1 # refresh low flag - high += 1 - - """ - A typical line current in neplan has two parts from both end, but we doesn't have to calculate them - with the assumption that the topology of the gird should be correct with which we can validate the - current by comparing the voltage of the nodes connected to the ends of the line - """ - if flag is not True: # flag is true when it's the first line - if value[3] is not '#': - for m in range(6): - timeseries.append(TimeSeries(value[3] + '.' + namelist[m], - np.array([0., 1.]), np.array([value[m + 6], value[m + 6]]))) - else: - for m in range(2): - timeseries.append(TimeSeries(value[1] + '.' + namelist[m], - np.array([0., 1.]), np.array([value[m + 6], value[m + 6]]))) - flag = False - str_tmp.close() - - # Read in variables which match with regex - if is_regex is True: - p = re.compile(timeseries_names) - length = len(timeseries) - for rule_check in range(length): - if p.search(timeseries[rule_check].name): - pass - else: - line_del.append(rule_check) - - # Read in specified time series - elif timeseries_names is not None: - length = len(timeseries) - for rule_check in range(length): - if timeseries_names == timeseries[rule_check].name: - pass - else: - line_del.append(rule_check) - - # delete those values that are not needed. - line_del = set(line_del) - line_del = sorted(line_del) - for num_to_del in range(len(line_del)): - del timeseries[line_del[len(line_del) - num_to_del - 1]] - - return timeseries - - -def read_timeseries_simulink_loadflow(file_name, timeseries_names=None, is_regex=False): - """ - Read in simulink load-flow result from result file(.rep), the result is in angle notation, amplitude and angle are stored - separately. - A suffix is used to tag different data for a component: - .Arms/.IDegree for current/current angle, - .Vrms/.VDegree for voltage/voltage angle. - - :param file_name:path of the .rep file for the loadflow result from simulink - :param timeseries_names: specific values to be read - :param is_regex: flag for using regular expression - :return: list of Timeseries objects - """ - str_tmp = open(file_name, 'r', encoding='latin-1') # Read in files, using latin-1 to decode /xb0 - - # Read in data from result file of neplan - name = [] # list for data type names - value = [] # list for data - timeseries = [] - line_del = [] # a list for the value to be deleted - - for line in str_tmp.readlines(): - line = line.replace("°", "") - del value[:] - del name[:] - # read in different data and start processing - if len(line) > 37: - if line[31:35] == '--->': - if line[13:17] == 'Arms': - name = [line[37:len(line)].rstrip() + '.Arms', line[37:len(line)].rstrip() + '.IDegree'] - elif line[13:17] == 'Vrms': - name = [line[37:len(line)].rstrip() + '.Vrms', line[37:len(line)].rstrip() + '.VDegree'] - value = [float(line[0:13]), float(line[18:31])] - timeseries.append(TimeSeries(name[0], - np.array([0., 1.]), np.array([value[0], value[0]]))) - timeseries.append(TimeSeries(name[1], - np.array([0., 1.]), np.array([value[1], value[1]]))) - - # Read in variables which match with regex - if is_regex is True: - p = re.compile(timeseries_names) - length = len(timeseries) - for rule_check in range(length): - if p.search(timeseries[rule_check].name): - pass - else: - line_del.append(rule_check) - - # Read in specified time series - elif timeseries_names is not None: - length = len(timeseries) - for rule_check in range(length): - if timeseries_names == timeseries[rule_check].name: - pass - else: - line_del.append(rule_check) - - # delete those values that are not needed. - line_del = set(line_del) - line_del = sorted(line_del) - for num_to_del in range(len(line_del)): - del timeseries[line_del[len(line_del) - num_to_del - 1]] - return timeseries +#!/usr/bin/python +# coding: utf8 + +import numpy as np +import pandas as pd +from timeseries import * +import re + + + +def read_timeseries_Modelica(filename, timeseries_names=None, is_regex=False): + from modelicares import SimRes + sim = SimRes(filename) + if timeseries_names is None and is_regex is False: + # No trajectory names or regex specified, thus read in all + timeseries = [] + for name in sim.names(): + timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) + timeseries_names = sim.names() + elif is_regex is True: + # Read in variables which match with regex + timeseries = [] + p = re.compile(timeseries_names) + timeseries_names = [name for name in sim.names() if p.search(name)] + timeseries_names.sort() + for name in timeseries_names: + timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) + else: + # Read in specified time series + if not isinstance(timeseries_names, list): + timeseries = TimeSeries(timeseries_names, sim(timeseries_names).times(), sim(timeseries_names).values()) + else: + timeseries = [] + for name in timeseries_names: + timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) + + return timeseries + + +def read_timeseries_PLECS(filename, timeseries_names=None): + pd_df = pd.read_csv(filename) + timeseries_list = [] + if timeseries_names is None: + # No trajectory names specified, thus read in all + timeseries_names = list(pd_df.columns.values) + timeseries_names.remove('Time') + for name in timeseries_names: + timeseries_list.append(TimeSeries(name, pd_df['Time'].values, pd_df[name].values)) + else: + # Read in specified time series + for name in timeseries_names: + timeseries_list.append(TimeSeries(name, pd_df['Time'].values, pd_df[name].values)) + + print('PLECS results column names: ' + str(timeseries_names)) + print('PLECS results number: ' + str(len(timeseries_list))) + + return timeseries_list + +def read_timeseries_simulink(filename, timeseries_names=None): + pd_df = pd.read_csv(filename) + timeseries_list = [] + if timeseries_names is None: + # No trajectory names specified, thus read in all + timeseries_names = list(pd_df.columns.values) + timeseries_names.remove('time') + for name in timeseries_names: + timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values)) + else: + # Read in specified time series + for name in timeseries_names: + timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values)) + + print('Simulink results column names: ' + str(timeseries_names)) + print('Simulink results number: ' + str(len(timeseries_list))) + + return timeseries_list + +def read_timeseries_dpsim_real(filename, timeseries_names=None): + """Reads real time series data from DPsim log file which may have a header. + Timeseries names are assigned according to the header names if available. + :param filename: name of the csv file that has the data + :param timeseries_names: column names which should be read + :return: list of Timeseries objects + """ + timeseries_list = [] + pd_df = pd.read_csv(filename) + + if timeseries_names is None: + # No column names specified, thus read in all and strip spaces + pd_df.rename(columns=lambda x: x.strip(), inplace=True) + column_names = list(pd_df.columns.values) + + # Remove timestamps column name and store separately + column_names.remove('time') + timestamps = pd_df.iloc[:,0] + + for name in column_names: + timeseries_list.append(TimeSeries(name, timestamps, pd_df[name].values)) + else: + # Read in specified time series + print('no column names specified yet') + + print('DPsim results column names: ' + str(column_names)) + print('DPsim results number: ' + str(len(timeseries_list))) + + return timeseries_list + +def read_timeseries_dpsim_cmpl(filename, timeseries_names=None): + """Reads complex time series data from DPsim log file. Real and + imaginary part are stored in one complex variable. + :param filename: name of the csv file that has the data + :param timeseries_names: column name which should be read + :return: list of Timeseries objects + """ + pd_df = pd.read_csv(filename) + timeseries_list = [] + + if timeseries_names is None: + # No column names specified, thus read in all and strip off spaces + pd_df.rename(columns=lambda x: x.strip(), inplace=True) + column_names = list(pd_df.columns.values) + + # Remove timestamps column name and store separately + column_names.remove('time') + timestamps = pd_df.iloc[:,0] + # Calculate number of network nodes since array is [real, imag] + node_number = int(len(column_names) / 2) + node_index = 1 + for column in column_names: + if node_index <= node_number: + ts_name = 'n'+ str(node_index) + timeseries_list.append( + TimeSeries(ts_name, timestamps, np.vectorize(complex)(pd_df.iloc[:,node_index],pd_df.iloc[:,node_index + node_number]))) + else: + break + node_index = node_index + 1 + else: + # Read in specified time series + print('cannot read specified columns yet') + + print('DPsim results column names: ' + str(column_names)) + print('DPsim results number: ' + str(len(timeseries_list))) + + return timeseries_list + +def read_timeseries_dpsim_cmpl_separate(filename, timeseries_names=None): + """Deprecated - Reads complex time series data from DPsim log file. Real and + imaginary part are stored separately. + :param filename: name of the csv file that has the data + :param timeseries_names: column name which should be read + :return: list of Timeseries objects + """ + pd_df = pd.read_csv(filename, header=None) + timeseries_list = [] + + if timeseries_names is None: + # No trajectory names specified, thus read in all + column_names = list(pd_df.columns.values) + # Remove timestamps column name and store separately + column_names.remove(0) + timestamps = pd_df.iloc[:, 0] + # Calculate number of network nodes since array is [real, imag] + node_number = int(len(column_names) / 2) + node_index = 1 + for column in column_names: + if node_index <= node_number: + node_name = 'node '+ str(node_index) +' Re' + timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column])) + else: + node_name = 'node '+ str(node_index - node_number) +' Im' + timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column])) + + node_index = node_index + 1 + else: + # Read in specified time series + print('no column names specified yet') + + print('DPsim results file length:') + print(len(timeseries_list)) + for result in timeseries_list: + print(result.name) + return timeseries_list + + +def read_timeseries_NEPLAN_loadflow(file_name, timeseries_names=None, is_regex=False): + """ + Read in NEPLAN loadflow result from result file, the result is in angle notation, amplitude and angle are stored + separately + To keep consistent with the names of voltage in most cases, the name of voltage variables are changed into '.V*' + instead of '.U*' as in the result file + + :param file_name: name of the mat file for the loadflow result from neplan + :param timeseries_names: column name to be read + :param is_regex: flag for using regular expression + :return: list of Timeseries objects + """ + str_tmp = open(file_name, "r") # Read in files + low = 0 # flag for the start of a new data in str_cmp + high = 0 # flag for the end of this new data in str_cmp + flag = True # To judge if this is the first line of the file, which will be the names for the data type + + # Read in data from result file of neplan + seq = [] # list for data type names + value = [] # list for data + + + namelist = ['U', 'ANGLEU', 'P', 'Q', 'I', 'ANGLEI'] # Suffix of the data name + timeseries = [] + line_del = [] # a list for the value to be deleted + isfloat = re.compile(r'^[-+]?[0-9]+\.[0-9]+$') # regular expression to find float values + + # Transfer ',' in the floats in result file to '.' + for line in str_tmp.readlines(): # Check the data to find out floats with ',' + line = line.replace(",", ".") + high -= high + low -= low + del value[:] + # read in different data and start processing + for letter in line: + if letter == " " or letter == "\n": # different data(separated by ' ') or end(/n) + if low is not high: # if low is equal to high, no data read in + if flag: # first line of the file, list for data-type name + seq.append(line[low:high]) + else: # not first line of the file,list for data + if isfloat.match(line[low:high]): + value.append(float(line[low:high])) + else: + value.append(line[low:high]) + else: # no data for this datatype + value.append(r'#') # No value, set as # + low = high + 1 # refresh low flag + high += 1 + + """ + A typical line current in neplan has two parts from both end, but we doesn't have to calculate them + with the assumption that the topology of the gird should be correct with which we can validate the + current by comparing the voltage of the nodes connected to the ends of the line + """ + if flag is not True: # flag is true when it's the first line + if value[3] is not '#': + for m in range(6): + timeseries.append(TimeSeries(value[3] + '.' + namelist[m], + np.array([0., 1.]), np.array([value[m + 6], value[m + 6]]))) + else: + for m in range(2): + timeseries.append(TimeSeries(value[1] + '.' + namelist[m], + np.array([0., 1.]), np.array([value[m + 6], value[m + 6]]))) + flag = False + str_tmp.close() + + # Read in variables which match with regex + if is_regex is True: + p = re.compile(timeseries_names) + length = len(timeseries) + for rule_check in range(length): + if p.search(timeseries[rule_check].name): + pass + else: + line_del.append(rule_check) + + # Read in specified time series + elif timeseries_names is not None: + length = len(timeseries) + for rule_check in range(length): + if timeseries_names == timeseries[rule_check].name: + pass + else: + line_del.append(rule_check) + + # delete those values that are not needed. + line_del = set(line_del) + line_del = sorted(line_del) + for num_to_del in range(len(line_del)): + del timeseries[line_del[len(line_del) - num_to_del - 1]] + + return timeseries + + +def read_timeseries_simulink_loadflow(file_name, timeseries_names=None, is_regex=False): + """ + Read in simulink load-flow result from result file(.rep), the result is in angle notation, amplitude and angle are stored + separately. + A suffix is used to tag different data for a component: + .Arms/.IDegree for current/current angle, + .Vrms/.VDegree for voltage/voltage angle. + + :param file_name:path of the .rep file for the loadflow result from simulink + :param timeseries_names: specific values to be read + :param is_regex: flag for using regular expression + :return: list of Timeseries objects + """ + str_tmp = open(file_name, 'r', encoding='latin-1') # Read in files, using latin-1 to decode /xb0 + + # Read in data from result file of neplan + name = [] # list for data type names + value = [] # list for data + timeseries = [] + line_del = [] # a list for the value to be deleted + + for line in str_tmp.readlines(): + line = line.replace("°", "") + del value[:] + del name[:] + # read in different data and start processing + if len(line) > 37: + if line[31:35] == '--->': + if line[13:17] == 'Arms': + name = [line[37:len(line)].rstrip() + '.Arms', line[37:len(line)].rstrip() + '.IDegree'] + elif line[13:17] == 'Vrms': + name = [line[37:len(line)].rstrip() + '.Vrms', line[37:len(line)].rstrip() + '.VDegree'] + value = [float(line[0:13]), float(line[18:31])] + timeseries.append(TimeSeries(name[0], + np.array([0., 1.]), np.array([value[0], value[0]]))) + timeseries.append(TimeSeries(name[1], + np.array([0., 1.]), np.array([value[1], value[1]]))) + + # Read in variables which match with regex + if is_regex is True: + p = re.compile(timeseries_names) + length = len(timeseries) + for rule_check in range(length): + if p.search(timeseries[rule_check].name): + pass + else: + line_del.append(rule_check) + + # Read in specified time series + elif timeseries_names is not None: + length = len(timeseries) + for rule_check in range(length): + if timeseries_names == timeseries[rule_check].name: + pass + else: + line_del.append(rule_check) + + # delete those values that are not needed. + line_del = set(line_del) + line_del = sorted(line_del) + for num_to_del in range(len(line_del)): + del timeseries[line_del[len(line_del) - num_to_del - 1]] + return timeseries diff --git a/dataprocessing/timeseries.py b/dataprocessing/timeseries.py index 424e4b0256d65ed71fd7f833cb0dbf7f2915c81b..c1accbb03b96b73ef36d9d211d5e775f5880b3a9 100644 --- a/dataprocessing/timeseries.py +++ b/dataprocessing/timeseries.py @@ -1,136 +1,136 @@ -import numpy as np -import cmath - -class TimeSeries: - """Stores data from different simulation sources. - A TimeSeries object always consists of timestamps and datapoints. - """ - def __init__(self, name, time, values, label=""): - self.time = np.array(time) - self.values = np.array(values) - self.name = name - self.label = name - - def scale(self, name, factor): - """Returns scaled timeseries. - Assumes the same time steps for both timeseries. - """ - ts_scaled = TimeSeries(name, self.time, self.values * factor) - return ts_scaled - - def abs(self, name): - """ Calculate absolute value of complex time series. - """ - abs_values = [] - for value in self.values: - abs_values.append(np.abs(value)) - ts_abs = TimeSeries(name, self.time, abs_values) - return ts_abs - - def phase(self, name): - """ Calculate absolute value of complex time series. - """ - phase_values = [] - for value in self.values: - phase_values.append(np.angle(value, deg=True)) - ts_abs = TimeSeries(name, self.time, phase_values) - ts_phase = TimeSeries(name, self.time, phase_values) - return ts_phase - - @staticmethod - def rmse(ts1, ts2): - """ Calculate root mean square error between two time series - """ - return np.sqrt((TimeSeries.diff('diff', ts1, ts2).values ** 2).mean()) - - @staticmethod - def diff(name, ts1, ts2): - """Returns difference between values of two Timeseries objects. - """ - if len(ts1.time) == len(ts2.time): - ts_diff = TimeSeries(name, ts1.time, (ts1.values - ts2.values)) - else: # different timestamps, common time vector and interpolation required before substraction - time = sorted(set(list(ts1.time) + list(ts2.time))) - interp_vals_ts1 = np.interp(time, ts1.time, ts1.values) - interp_vals_ts2 = np.interp(time, ts2.time, ts2.values) - ts_diff = TimeSeries(name, time, (interp_vals_ts2 - interp_vals_ts1)) - return ts_diff - - def dynphasor_shift_to_emt(self, name, freq): - """ Shift dynamic phasor values to EMT by frequency freq. - Assumes the same time steps for both timeseries. - :param name: name of returned time series - :param freq: shift frequency - :return: new timeseries with shifted time domain values - """ - ts_shift = TimeSeries(name, self.time, self.values.real*np.cos(2*np.pi*freq*self.time) - - self.values.imag*np.sin(2*np.pi*freq*self.time)) - return ts_shift - - def interpolate_cmpl(self, name, timestep): - """ Not tested yet! - Interpolates complex timeseries with timestep - :param name: - :param timestep: - :return: - """ - interpl_time = np.arange(self.time[0], self.time[-1], timestep) - realValues = interp1d(interpl_time, self.values.real) - imagValues = interp1d(interpl_time, self.values.imag) - ts_return = TimeSeries(name, time, np.vectorize(complex)(realValues, imagValues)) - return timeseries - - @staticmethod - def sep_dynphasor_shift_to_emt(name, real, imag, freq): - """ Shift dynamic phasor values to EMT by frequency freq. - Assumes the same time steps for both timeseries. - :param name: name of returned time series - :param real: timeseries with real values - :param imag: timeseries with imaginary values - :param freq: shift frequency - :return: new timeseries with shifted time domain values - """ - ts_shift = TimeSeries(name, real.time, - real.values * np.cos(2 * np.pi * freq * real.time) - imag.values * np.sin( - 2 * np.pi * freq * real.time)) - return ts_shift - - @staticmethod - def check_node_number_comp(ts_list_comp, node): - """ - Check if node number is available in complex time series. - :param ts_comp: complex time series list - :param node: node number to be checked - :return: true if node number is available, false if out of range - """ - ts_comp_length = len(ts_comp) - im_offset = int(ts_comp_length / 2) - if im_offset <= node or node < 0: - print('Complex node not available') - return false - else: - return true - - @staticmethod - def check_node_number(ts_list, node): - """ - Check if node number is available in time series. - :param ts: time series list - :param node: node number to be checked - :return: true if node number is available, false if out of range - """ - ts_length = len(ts) - if ts_length <= node or node < 0: - print('Node not available') - return false - else: - return true - - @staticmethod - def complex_abs(name, ts_real, ts_imag): - """ Calculate absolute value of complex variable. - Assumes the same time steps for both timeseries. - """ - ts_complex = np.vectorize(complex)(ts_real.values, ts_imag.values) - ts_abs = TimeSeries(name, ts_real.time, ts_complex.abs()) +import numpy as np +import cmath + +class TimeSeries: + """Stores data from different simulation sources. + A TimeSeries object always consists of timestamps and datapoints. + """ + def __init__(self, name, time, values, label=""): + self.time = np.array(time) + self.values = np.array(values) + self.name = name + self.label = name + + def scale(self, name, factor): + """Returns scaled timeseries. + Assumes the same time steps for both timeseries. + """ + ts_scaled = TimeSeries(name, self.time, self.values * factor) + return ts_scaled + + def abs(self, name): + """ Calculate absolute value of complex time series. + """ + abs_values = [] + for value in self.values: + abs_values.append(np.abs(value)) + ts_abs = TimeSeries(name, self.time, abs_values) + return ts_abs + + def phase(self, name): + """ Calculate absolute value of complex time series. + """ + phase_values = [] + for value in self.values: + phase_values.append(np.angle(value, deg=True)) + ts_abs = TimeSeries(name, self.time, phase_values) + ts_phase = TimeSeries(name, self.time, phase_values) + return ts_phase + + @staticmethod + def rmse(ts1, ts2): + """ Calculate root mean square error between two time series + """ + return np.sqrt((TimeSeries.diff('diff', ts1, ts2).values ** 2).mean()) + + @staticmethod + def diff(name, ts1, ts2): + """Returns difference between values of two Timeseries objects. + """ + if len(ts1.time) == len(ts2.time): + ts_diff = TimeSeries(name, ts1.time, (ts1.values - ts2.values)) + else: # different timestamps, common time vector and interpolation required before substraction + time = sorted(set(list(ts1.time) + list(ts2.time))) + interp_vals_ts1 = np.interp(time, ts1.time, ts1.values) + interp_vals_ts2 = np.interp(time, ts2.time, ts2.values) + ts_diff = TimeSeries(name, time, (interp_vals_ts2 - interp_vals_ts1)) + return ts_diff + + def dynphasor_shift_to_emt(self, name, freq): + """ Shift dynamic phasor values to EMT by frequency freq. + Assumes the same time steps for both timeseries. + :param name: name of returned time series + :param freq: shift frequency + :return: new timeseries with shifted time domain values + """ + ts_shift = TimeSeries(name, self.time, self.values.real*np.cos(2*np.pi*freq*self.time) + - self.values.imag*np.sin(2*np.pi*freq*self.time)) + return ts_shift + + def interpolate_cmpl(self, name, timestep): + """ Not tested yet! + Interpolates complex timeseries with timestep + :param name: + :param timestep: + :return: + """ + interpl_time = np.arange(self.time[0], self.time[-1], timestep) + realValues = interp1d(interpl_time, self.values.real) + imagValues = interp1d(interpl_time, self.values.imag) + ts_return = TimeSeries(name, time, np.vectorize(complex)(realValues, imagValues)) + return timeseries + + @staticmethod + def sep_dynphasor_shift_to_emt(name, real, imag, freq): + """ Shift dynamic phasor values to EMT by frequency freq. + Assumes the same time steps for both timeseries. + :param name: name of returned time series + :param real: timeseries with real values + :param imag: timeseries with imaginary values + :param freq: shift frequency + :return: new timeseries with shifted time domain values + """ + ts_shift = TimeSeries(name, real.time, + real.values * np.cos(2 * np.pi * freq * real.time) - imag.values * np.sin( + 2 * np.pi * freq * real.time)) + return ts_shift + + @staticmethod + def check_node_number_comp(ts_list_comp, node): + """ + Check if node number is available in complex time series. + :param ts_comp: complex time series list + :param node: node number to be checked + :return: true if node number is available, false if out of range + """ + ts_comp_length = len(ts_comp) + im_offset = int(ts_comp_length / 2) + if im_offset <= node or node < 0: + print('Complex node not available') + return false + else: + return true + + @staticmethod + def check_node_number(ts_list, node): + """ + Check if node number is available in time series. + :param ts: time series list + :param node: node number to be checked + :return: true if node number is available, false if out of range + """ + ts_length = len(ts) + if ts_length <= node or node < 0: + print('Node not available') + return false + else: + return true + + @staticmethod + def complex_abs(name, ts_real, ts_imag): + """ Calculate absolute value of complex variable. + Assumes the same time steps for both timeseries. + """ + ts_complex = np.vectorize(complex)(ts_real.values, ts_imag.values) + ts_abs = TimeSeries(name, ts_real.time, ts_complex.abs()) return ts_abs \ No newline at end of file diff --git a/dataprocessing/validationtools.py b/dataprocessing/validationtools.py index 6bb6e3b710ac2c662a9e1b0bbd29cbd515cda2b8..4bd5401e59dde2a014c365024841577f121166d7 100644 --- a/dataprocessing/validationtools.py +++ b/dataprocessing/validationtools.py @@ -1,154 +1,154 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- - -import os - -from readtools import * - - - -def convert_neplan_to_modelica_timeseries(neplan_timeseries): - """ - Mapping the variable names between modelica and neplan - - Voltage: change *.U and *.ANGLEU to *.V and *.Vangle - - Current: remove unnecessary current variables - :param neplan_timeseries: result of neplan in timeseries - :return: a mapped neplan_timeseries - """ - line_del = [] - # remove all the line current - - # Find current of the same component, which means the current needn't to be validated - for check in range(len(neplan_timeseries)): - if neplan_timeseries[check].values[0] == '#': - line_del.append(check) - if '.P' in neplan_timeseries[check].name: - line_del.append(check) - if '.Q' in neplan_timeseries[check].name: - line_del.append(check) - for i in range(check + 1, len(neplan_timeseries)): - if neplan_timeseries[check].name == neplan_timeseries[i].name: - line_del.append(check) # delete list of the unnecessary data - line_del.append(i) - line_del = sorted(set(line_del)) - for num_to_del in range(len(line_del)): - del neplan_timeseries[line_del[len(line_del) - num_to_del - 1]] - - # Change the unit of variables to keep consistent with those in modelica - for i in range(len(neplan_timeseries)): - if 'ANGLE' in neplan_timeseries[i].name: - neplan_timeseries[i].values = neplan_timeseries[i].values / 180 * cmath.pi # unification of the unit - elif '.U' in neplan_timeseries[i].name or '.I' in neplan_timeseries[i].name: - neplan_timeseries[i].values = neplan_timeseries[i].values * 1000 - - # Change the name of variables to keep consistent with those in modelica - for i in range(len(neplan_timeseries)): - neplan_timeseries[i].name = neplan_timeseries[i].name.replace(' ', '') - neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.ANGLEU', '.Vangle') - neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.U', '.Vpp') - neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.ANGLEI', '.Iangle') - - return neplan_timeseries - -def convert_simulink_to_modelica_timeseries(simseri): - """ - Convert the steady-state results timeseries from simulink to modelica timeseries - :param simseri: simulate timeseries, generated by the result file from simulink - :return: a result timeseries - """ - res = [] - for check in range(len(simseri)): - if 'U AB:' in simseri[check].name: - simseri[check].name = simseri[check].name.replace('U AB:', '') - simseri[check].name = simseri[check].name.replace('Vrms', 'Vpp') - simseri[check].name = simseri[check].name.replace('VDegree', 'Vangle') - simseri[check].name = simseri[check].name.replace(' ', '') - simseri[check].name = simseri[check].name.replace('_', '') - if 'Vangle' in simseri[check].name: - simseri[check].values = (simseri[check].values - 30)/180 * cmath.pi - res.append(simseri[check]) - return res - - -def compare_timeseries(ts1, ts2): - """ - Compare the result from two timeseries. - :param ts1: timeseries - :param ts2: timeseries - :return: an error dic - """ - if len(ts1) > len(ts2): - tmp = ts2 - ts2 = ts1 - ts1 = tmp - for i in range(len(ts1)): - ts1[i].name = ts1[i].name.upper() - for i in range(len(ts2)): - ts2[i].name = ts2[i].name.upper() - - timeseries_names = [] # list for names of components - timeseries_error = [] # list for error - len_ts1 = len(ts1) - len_limit = len(ts2) - - # Match the components in result files, and compare them - for i in range(len_ts1): - flag_not_found = False - for j in range(len_limit): - if ts1[i].name == ts2[j].name: # Find the same variable - timeseries_names.append(ts1[i].name) - if ts1[i].values[0] == 0: - timeseries_error.append(TimeSeries.rmse(ts2[j], ts1[i])) # is it good to do so? - else: - timeseries_error.append(TimeSeries.rmse(ts2[j], ts1[i])/ts1[i].values[0]) - - print(ts1[i].name) - print(timeseries_error[len(timeseries_error) - 1]) - flag_not_found = True - if flag_not_found is False: - # No such variable in Modelica model, set the error to -1 - timeseries_names.append(ts1[i].name) - timeseries_error.append(-1) - return dict(zip(timeseries_names, timeseries_error)) - - -def assert_modelia_results(net_name, error): - """ - assert the result data of a net. - :param net_name: name of the network - :param modelica_res: timeseries of modelica result - :param simulink_res: timeseries of reference result - :return: outputs to command line which are the results of the assert - """ - fail_list = [] # List for all the failed test - # the limitations are set to 0.5 - for name in error.keys(): - if abs(error[name]) > 0.5: - fail_list.append(name) - else: - print("Test on %s Passed" % name) - - # fail_list is 0, which means all the tests are passed - if len(fail_list) is 0: - print("\033[1;36;40mModel %s Passed\033[0m" % net_name) - else: - for name in fail_list: - print("\033[1;31;40mTest on %s of %s Failed\033[0m" % (name, net_name)) - raise ValueError('Test on %s is not passed!' % net_name) - - -def validate_modelica_res(net_name, modelica_res_path, reference_res_path): - """ - Top level function for the validation of modelica, calls all the function needed to execute the validation. - :param modelica_res_path: the path of the modelica result file, whose suffix should be .mat - :param reference_res_path: the path of the reference result file, whose suffix should be .rep(simulink)/.rlf(neplan) - :return: outputs to command line which are the results of the validation. - """ - res_mod = read_timeseries_Modelica (modelica_res_path) - if os.path.splitext(reference_res_path)[1] == '.rep': - res_ref = convert_simulink_to_modelica_timeseries(read_timeseries_simulink_loadflow(reference_res_path)) - elif os.path.splitext(reference_res_path)[1] == '.rlf': - res_ref = convert_neplan_to_modelica_timeseries(read_timeseries_NEPLAN_loadflow(reference_res_path)) - - res_err = compare_timeseries(res_ref, res_mod) - assert_modelia_results(net_name, res_err) +#!/usr/bin/python +# -*- coding: UTF-8 -*- + +import os + +from readtools import * + + + +def convert_neplan_to_modelica_timeseries(neplan_timeseries): + """ + Mapping the variable names between modelica and neplan + - Voltage: change *.U and *.ANGLEU to *.V and *.Vangle + - Current: remove unnecessary current variables + :param neplan_timeseries: result of neplan in timeseries + :return: a mapped neplan_timeseries + """ + line_del = [] + # remove all the line current + + # Find current of the same component, which means the current needn't to be validated + for check in range(len(neplan_timeseries)): + if neplan_timeseries[check].values[0] == '#': + line_del.append(check) + if '.P' in neplan_timeseries[check].name: + line_del.append(check) + if '.Q' in neplan_timeseries[check].name: + line_del.append(check) + for i in range(check + 1, len(neplan_timeseries)): + if neplan_timeseries[check].name == neplan_timeseries[i].name: + line_del.append(check) # delete list of the unnecessary data + line_del.append(i) + line_del = sorted(set(line_del)) + for num_to_del in range(len(line_del)): + del neplan_timeseries[line_del[len(line_del) - num_to_del - 1]] + + # Change the unit of variables to keep consistent with those in modelica + for i in range(len(neplan_timeseries)): + if 'ANGLE' in neplan_timeseries[i].name: + neplan_timeseries[i].values = neplan_timeseries[i].values / 180 * cmath.pi # unification of the unit + elif '.U' in neplan_timeseries[i].name or '.I' in neplan_timeseries[i].name: + neplan_timeseries[i].values = neplan_timeseries[i].values * 1000 + + # Change the name of variables to keep consistent with those in modelica + for i in range(len(neplan_timeseries)): + neplan_timeseries[i].name = neplan_timeseries[i].name.replace(' ', '') + neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.ANGLEU', '.Vangle') + neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.U', '.Vpp') + neplan_timeseries[i].name = neplan_timeseries[i].name.replace('.ANGLEI', '.Iangle') + + return neplan_timeseries + +def convert_simulink_to_modelica_timeseries(simseri): + """ + Convert the steady-state results timeseries from simulink to modelica timeseries + :param simseri: simulate timeseries, generated by the result file from simulink + :return: a result timeseries + """ + res = [] + for check in range(len(simseri)): + if 'U AB:' in simseri[check].name: + simseri[check].name = simseri[check].name.replace('U AB:', '') + simseri[check].name = simseri[check].name.replace('Vrms', 'Vpp') + simseri[check].name = simseri[check].name.replace('VDegree', 'Vangle') + simseri[check].name = simseri[check].name.replace(' ', '') + simseri[check].name = simseri[check].name.replace('_', '') + if 'Vangle' in simseri[check].name: + simseri[check].values = (simseri[check].values - 30)/180 * cmath.pi + res.append(simseri[check]) + return res + + +def compare_timeseries(ts1, ts2): + """ + Compare the result from two timeseries. + :param ts1: timeseries + :param ts2: timeseries + :return: an error dic + """ + if len(ts1) > len(ts2): + tmp = ts2 + ts2 = ts1 + ts1 = tmp + for i in range(len(ts1)): + ts1[i].name = ts1[i].name.upper() + for i in range(len(ts2)): + ts2[i].name = ts2[i].name.upper() + + timeseries_names = [] # list for names of components + timeseries_error = [] # list for error + len_ts1 = len(ts1) + len_limit = len(ts2) + + # Match the components in result files, and compare them + for i in range(len_ts1): + flag_not_found = False + for j in range(len_limit): + if ts1[i].name == ts2[j].name: # Find the same variable + timeseries_names.append(ts1[i].name) + if ts1[i].values[0] == 0: + timeseries_error.append(TimeSeries.rmse(ts2[j], ts1[i])) # is it good to do so? + else: + timeseries_error.append(TimeSeries.rmse(ts2[j], ts1[i])/ts1[i].values[0]) + + print(ts1[i].name) + print(timeseries_error[len(timeseries_error) - 1]) + flag_not_found = True + if flag_not_found is False: + # No such variable in Modelica model, set the error to -1 + timeseries_names.append(ts1[i].name) + timeseries_error.append(-1) + return dict(zip(timeseries_names, timeseries_error)) + + +def assert_modelia_results(net_name, error): + """ + assert the result data of a net. + :param net_name: name of the network + :param modelica_res: timeseries of modelica result + :param simulink_res: timeseries of reference result + :return: outputs to command line which are the results of the assert + """ + fail_list = [] # List for all the failed test + # the limitations are set to 0.5 + for name in error.keys(): + if abs(error[name]) > 0.5: + fail_list.append(name) + else: + print("Test on %s Passed" % name) + + # fail_list is 0, which means all the tests are passed + if len(fail_list) is 0: + print("\033[1;36;40mModel %s Passed\033[0m" % net_name) + else: + for name in fail_list: + print("\033[1;31;40mTest on %s of %s Failed\033[0m" % (name, net_name)) + raise ValueError('Test on %s is not passed!' % net_name) + + +def validate_modelica_res(net_name, modelica_res_path, reference_res_path): + """ + Top level function for the validation of modelica, calls all the function needed to execute the validation. + :param modelica_res_path: the path of the modelica result file, whose suffix should be .mat + :param reference_res_path: the path of the reference result file, whose suffix should be .rep(simulink)/.rlf(neplan) + :return: outputs to command line which are the results of the validation. + """ + res_mod = read_timeseries_Modelica (modelica_res_path) + if os.path.splitext(reference_res_path)[1] == '.rep': + res_ref = convert_simulink_to_modelica_timeseries(read_timeseries_simulink_loadflow(reference_res_path)) + elif os.path.splitext(reference_res_path)[1] == '.rlf': + res_ref = convert_neplan_to_modelica_timeseries(read_timeseries_NEPLAN_loadflow(reference_res_path)) + + res_err = compare_timeseries(res_ref, res_mod) + assert_modelia_results(net_name, res_err) diff --git a/examples/assertresults/assertresults.py b/examples/assertresults/assertresults.py index 871845c20ec8e1c78f455c6fe7f9fe621bd2842b..a3391f251b4738885e13e3bea6b954c6a7d2e036 100644 --- a/examples/assertresults/assertresults.py +++ b/examples/assertresults/assertresults.py @@ -1,45 +1,45 @@ -import re -import os -import sys - -sys.path.append(r"D:\HIWI\Git\data-processing\dataprocessing") -sys.path.append(r"D:\HIWI\Git\python-for-modelica-dev_interface\Py4Mod\py4mod") - -from ModelicaModel import ModelicaModel -from validationtools import * -from readtools import * -os.chdir(r"D:\HIWI\Git") - - -def simulate_modelica(model_name, model_path): - interface = ModelicaModel(model_name, model_path) - - # Initialization - interface.createInterface("OPENMODELICA") - interface.loadFile(model_path + '\ModPowerSystems\package.mo') - - # Redirection - cwd = os.getcwd() - wd = os.path.join(cwd, 'test') - if not os.path.exists(wd): - os.makedirs(wd) - interface.changeWorkingDirectory(wd.replace("\\", "/")) - - # Build & Run - interface.buildModel() - interface.simulate() - - -print("Test Start") -# We need to extract all the result files from git now - -for files in os.listdir( - os.path.abspath("reference-results/Neplan/BasicGrids")): - # Assert the result, model result path read from cmd line - validate_modelica_res(os.path.splitext(files)[0], - os.path.abspath("reference-results/Modelica/BasicGrids/" + - os.path.splitext(files)[0] + ".mat"), - os.path.abspath("reference-results/Neplan/BasicGrids/" + - os.path.splitext(files)[0] + ".rlf")) - -print("Test End") +import re +import os +import sys + +sys.path.append(r".\data-processing\dataprocessing") +sys.path.append(r".\python-for-modelica-dev_interface\Py4Mod\py4mod") + +from ModelicaModel import ModelicaModel +from validationtools import * +from readtools import * +os.chdir(r"D:\HIWI\Git") + + +def simulate_modelica(model_name, model_path): + interface = ModelicaModel(model_name, model_path) + + # Initialization + interface.createInterface("OPENMODELICA") + interface.loadFile(model_path + '\ModPowerSystems\package.mo') + + # Redirection + cwd = os.getcwd() + wd = os.path.join(cwd, 'test') + if not os.path.exists(wd): + os.makedirs(wd) + interface.changeWorkingDirectory(wd.replace("\\", "/")) + + # Build & Run + interface.buildModel() + interface.simulate() + + +print("Test Start") +# We need to extract all the result files from git now + +for files in os.listdir( + os.path.abspath("reference-results/Neplan/BasicGrids")): + # Assert the result, model result path read from cmd line + validate_modelica_res(os.path.splitext(files)[0], + os.path.abspath("reference-results/Modelica/BasicGrids/" + + os.path.splitext(files)[0] + ".mat"), + os.path.abspath("reference-results/Neplan/BasicGrids/" + + os.path.splitext(files)[0] + ".rlf")) + +print("Test End") diff --git a/examples/compareresults/compare_modelica_dpsim.py b/examples/compareresults/compare_modelica_dpsim.py index 28600a13b4a46e5ff8d66694e4a1d57f3edca587..e280c31c0e8fa2cf19c478f00484d546e83e8f39 100644 --- a/examples/compareresults/compare_modelica_dpsim.py +++ b/examples/compareresults/compare_modelica_dpsim.py @@ -1,37 +1,37 @@ -from dataprocessing.readtools import * -from dataprocessing.plottools import * -import matplotlib.pyplot as plt -from plottingtools.config import * - -current_emt_mod = read_timeseries_Modelica(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\EMT\UnitTest_Kundur_FullModel_Euler_1us.mat", ["synchronousGenerator_Park.i[1]"]) # Note: both results include only one damper winding in q axis -current_emt_dpsim = read_timeseries_dpsim_real(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\EMT\DPsim\UnitTest_FullModel_Trap_1us\data_j.csv")[0] -current_emt_dpsim.values = -current_emt_dpsim.values - -# Comparison EMT -figure_id = 1 -plt.figure(figure_id, figsize=(12,8)) -set_timeseries_labels(current_emt_mod, ["EMT Modelica"]) -plot_timeseries(figure_id, current_emt_mod) -set_timeseries_labels(current_emt_dpsim, "EMT DPsim") # TODO: modelica timeseries needs list element, dpsim timeseries needs string -plot_timeseries(figure_id, current_emt_dpsim, plt_linestyle=':') -plt.xlabel('Zeit [s]') -plt.ylabel('Strom [A]') -plt.show(block=False) - -# Comparison DP -current_dp_mod = read_timeseries_Modelica(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\DP\UnitTest_Kundur_FullModel_Euler_1us.mat", ["synchronousGenerator_Park.I[1]"]) # Note: both results include only one damper winding in q axis -current_dp_dpsim = read_timeseries_dpsim_cmpl(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\DP\DPsim\UnitTest_FullModel_Trap_1us\data_j.csv")[0] -current_dp_dpsim.values = -current_dp_dpsim.values -current_dpabs_dpsim = current_dp_dpsim.abs(current_dp_dpsim.name + ' abs') - -figure_id = 2 -plt.figure(figure_id, figsize=(12,8)) -set_timeseries_labels(current_dp_mod, ["DP Modelica"]) -plot_timeseries(figure_id, current_dp_mod) -set_timeseries_labels(current_dpabs_dpsim, "DP DPsim") # TODO: modelica timeseries needs list element, dpsim timeseries needs string -plot_timeseries(figure_id, current_dpabs_dpsim, plt_linestyle=':') -plt.xlabel('Zeit [s]') -plt.ylabel('Strom [A]') -plt.show(block=True) - - +from dataprocessing.readtools import * +from dataprocessing.plottools import * +import matplotlib.pyplot as plt +from plottingtools.config import * + +current_emt_mod = read_timeseries_Modelica(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\EMT\UnitTest_Kundur_FullModel_Euler_1us.mat", ["synchronousGenerator_Park.i[1]"]) # Note: both results include only one damper winding in q axis +current_emt_dpsim = read_timeseries_dpsim_real(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\EMT\DPsim\UnitTest_FullModel_Trap_1us\data_j.csv")[0] +current_emt_dpsim.values = -current_emt_dpsim.values + +# Comparison EMT +figure_id = 1 +plt.figure(figure_id, figsize=(12,8)) +set_timeseries_labels(current_emt_mod, ["EMT Modelica"]) +plot_timeseries(figure_id, current_emt_mod) +set_timeseries_labels(current_emt_dpsim, "EMT DPsim") # TODO: modelica timeseries needs list element, dpsim timeseries needs string +plot_timeseries(figure_id, current_emt_dpsim, plt_linestyle=':') +plt.xlabel('Zeit [s]') +plt.ylabel('Strom [A]') +plt.show(block=False) + +# Comparison DP +current_dp_mod = read_timeseries_Modelica(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\DP\UnitTest_Kundur_FullModel_Euler_1us.mat", ["synchronousGenerator_Park.I[1]"]) # Note: both results include only one damper winding in q axis +current_dp_dpsim = read_timeseries_dpsim_cmpl(r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\DP\DPsim\UnitTest_FullModel_Trap_1us\data_j.csv")[0] +current_dp_dpsim.values = -current_dp_dpsim.values +current_dpabs_dpsim = current_dp_dpsim.abs(current_dp_dpsim.name + ' abs') + +figure_id = 2 +plt.figure(figure_id, figsize=(12,8)) +set_timeseries_labels(current_dp_mod, ["DP Modelica"]) +plot_timeseries(figure_id, current_dp_mod) +set_timeseries_labels(current_dpabs_dpsim, "DP DPsim") # TODO: modelica timeseries needs list element, dpsim timeseries needs string +plot_timeseries(figure_id, current_dpabs_dpsim, plt_linestyle=':') +plt.xlabel('Zeit [s]') +plt.ylabel('Strom [A]') +plt.show(block=True) + + diff --git a/examples/compareresults/compare_modelica_plecs.py b/examples/compareresults/compare_modelica_plecs.py index 369325e132754b16baa57df8dafe0a362bcd9b70..da72501c86fa76df98a96ca47c603e3f26b3bd6c 100644 --- a/examples/compareresults/compare_modelica_plecs.py +++ b/examples/compareresults/compare_modelica_plecs.py @@ -1,55 +1,55 @@ -from dataprocessing.readtools import * -from dataprocessing.plottools import * -import matplotlib.pyplot as plt -import numpy as np - -results_path = r'\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\InductionMachine\results' - -### --- Read in section --- ### -# Stator currents -stator_currents_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.i[1]', 'inductionMachineSquirrelCage.i[2]', 'inductionMachineSquirrelCage.i[3]']) -stator_currents_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineStatorCurrents.csv') - -# Rotor currents -rotor_currents_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.i_qd0r[1]', 'inductionMachineSquirrelCage.i_qd0r[2]']) -rotor_currents_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineRotorCurrentsDqRRFs.csv') -rotor_currents_pls[1].values = -rotor_currents_pls[1].values # transformation DQ0->QD0 - -# Torque and speed -torque_speed_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.T_e', 'inductionMachineSquirrelCage.omega_rm']) -torque_speed_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineTorqueSpeed.csv') -torque_speed_mo[1].values = torque_speed_mo[1].values/2/np.pi*60 # transformation to r/min - -### --- Plot section --- ### -# Stator currents -figure_id = 1 -plt.figure(figure_id) -plt.title("Stator currents") -set_time_series_labels(stator_currents_mo, ['Modelica: Ias [A]', 'Modelica: Ibs [A]', 'Modelica: Ics [A]']) -plot_in_subplots(figure_id, stator_currents_mo) -set_time_series_labels(stator_currents_pls, ['PLECS: Ias [A]', 'PLECS: Ibs [A]', 'PLECS: Ics [A]']) -plot_in_subplots(figure_id, stator_currents_pls, plt_linestyle='--') -plt.xlabel('Time [s]') -plt.show(block=False) - -# Rotor currents -figure_id = 2 -plt.figure(figure_id) -plt.title("Rotor currents (in synchronously rotating reference frame)") -set_time_series_labels(rotor_currents_mo, ['Modelica: Iqr\' [A]', 'Modelica: Idr\' [A]']) -plot_in_subplots(figure_id, rotor_currents_mo) -set_time_series_labels(rotor_currents_pls, ['PLECS: Iqr\' [A]', 'PLECS: Idr\' [A]']) -plot_in_subplots(figure_id, rotor_currents_pls, plt_linestyle='--') -plt.xlabel('Time [s]') -plt.show(block=False) - -# Torque and speed -figure_id = 3 -plt.figure(figure_id) -plt.title("Rotor currents (in synchronously rotating reference frame)") -set_time_series_labels(torque_speed_mo, ['Modelica: Torque [Nm]', 'Modelica: Speed [r/min]']) -plot_in_subplots(figure_id, torque_speed_mo) -set_time_series_labels(torque_speed_pls, ['PLECS: Torque [Nm]', 'PLECS: Speed [r/min]']) -plot_in_subplots(figure_id, torque_speed_pls, plt_linestyle='--') -plt.xlabel('Time [s]') +from dataprocessing.readtools import * +from dataprocessing.plottools import * +import matplotlib.pyplot as plt +import numpy as np + +results_path = r'\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\InductionMachine\results' + +### --- Read in section --- ### +# Stator currents +stator_currents_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.i[1]', 'inductionMachineSquirrelCage.i[2]', 'inductionMachineSquirrelCage.i[3]']) +stator_currents_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineStatorCurrents.csv') + +# Rotor currents +rotor_currents_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.i_qd0r[1]', 'inductionMachineSquirrelCage.i_qd0r[2]']) +rotor_currents_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineRotorCurrentsDqRRFs.csv') +rotor_currents_pls[1].values = -rotor_currents_pls[1].values # transformation DQ0->QD0 + +# Torque and speed +torque_speed_mo = read_time_series_Modelica(results_path + r'\Modelica3hpMachineRRFs.mat', ['inductionMachineSquirrelCage.T_e', 'inductionMachineSquirrelCage.omega_rm']) +torque_speed_pls = read_time_series_PLECS(results_path + r'\PLECS3hpMachineTorqueSpeed.csv') +torque_speed_mo[1].values = torque_speed_mo[1].values/2/np.pi*60 # transformation to r/min + +### --- Plot section --- ### +# Stator currents +figure_id = 1 +plt.figure(figure_id) +plt.title("Stator currents") +set_time_series_labels(stator_currents_mo, ['Modelica: Ias [A]', 'Modelica: Ibs [A]', 'Modelica: Ics [A]']) +plot_in_subplots(figure_id, stator_currents_mo) +set_time_series_labels(stator_currents_pls, ['PLECS: Ias [A]', 'PLECS: Ibs [A]', 'PLECS: Ics [A]']) +plot_in_subplots(figure_id, stator_currents_pls, plt_linestyle='--') +plt.xlabel('Time [s]') +plt.show(block=False) + +# Rotor currents +figure_id = 2 +plt.figure(figure_id) +plt.title("Rotor currents (in synchronously rotating reference frame)") +set_time_series_labels(rotor_currents_mo, ['Modelica: Iqr\' [A]', 'Modelica: Idr\' [A]']) +plot_in_subplots(figure_id, rotor_currents_mo) +set_time_series_labels(rotor_currents_pls, ['PLECS: Iqr\' [A]', 'PLECS: Idr\' [A]']) +plot_in_subplots(figure_id, rotor_currents_pls, plt_linestyle='--') +plt.xlabel('Time [s]') +plt.show(block=False) + +# Torque and speed +figure_id = 3 +plt.figure(figure_id) +plt.title("Rotor currents (in synchronously rotating reference frame)") +set_time_series_labels(torque_speed_mo, ['Modelica: Torque [Nm]', 'Modelica: Speed [r/min]']) +plot_in_subplots(figure_id, torque_speed_mo) +set_time_series_labels(torque_speed_pls, ['PLECS: Torque [Nm]', 'PLECS: Speed [r/min]']) +plot_in_subplots(figure_id, torque_speed_pls, plt_linestyle='--') +plt.xlabel('Time [s]') plt.show() \ No newline at end of file diff --git a/examples/readinresults/DPsim/cim_ieee_9_bus.py b/examples/readinresults/DPsim/cim_ieee_9_bus.py index 55a51defda0466ecbaa70e811ab7b13f10b9bed9..d1f1ff60610e429b9d5e1f218163f4ee3686d85f 100644 --- a/examples/readinresults/DPsim/cim_ieee_9_bus.py +++ b/examples/readinresults/DPsim/cim_ieee_9_bus.py @@ -1,13 +1,13 @@ -from dataprocessing.readtools import * -from dataprocessing.timeseries import * - -path = 'C:\\Users\\mmi\\git\\PowerSystemSimulation\\DPsim\\VisualStudio\\DPsimVS2017\\' -logName = 'lvector-cim'; -dataType = '.csv'; -logFilename = path + logName + dataType; -ts_dpsim = read_timeseries_dpsim_cmpl(logFilename) -for ts in ts_dpsim: - ts_abs = ts.abs(ts.name + ' abs') - ts_phase = ts.phase(ts.name + ' phase') - print(ts.name + ': ' + str(ts_abs.values[0]) + '<' + str(ts_phase.values[0] * 180/np.pi)) - +from dataprocessing.readtools import * +from dataprocessing.timeseries import * + +path = 'C:\\Users\\mmi\\git\\PowerSystemSimulation\\DPsim\\VisualStudio\\DPsimVS2017\\' +logName = 'lvector-cim'; +dataType = '.csv'; +logFilename = path + logName + dataType; +ts_dpsim = read_timeseries_dpsim_cmpl(logFilename) +for ts in ts_dpsim: + ts_abs = ts.abs(ts.name + ' abs') + ts_phase = ts.phase(ts.name + ' phase') + print(ts.name + ': ' + str(ts_abs.values[0]) + '<' + str(ts_phase.values[0] * 180/np.pi)) + diff --git a/examples/readinresults/DPsim/examples_plot.py b/examples/readinresults/DPsim/examples_plot.py index 20da45bfbb4f34eef596bdcb07a214e9126db717..eed141c15d9371231368a69a60d21d3094d74dca 100644 --- a/examples/readinresults/DPsim/examples_plot.py +++ b/examples/readinresults/DPsim/examples_plot.py @@ -1,27 +1,27 @@ -from dataprocessing.dpsim import * -from dataprocessing.plottools import * - -path = 'D:\\path\\to\\logs\\' -logName = 'simulation_name_LeftVector' -logFilename = path + logName + '.csv' - -ts_dpsim = read_timeseries_dpsim_cmpl(logFilename) - -phasors = get_node_voltage_phasors(ts_dpsim) -print('Print phasors for all nodes at first time step:') -for node, phasor in phasors.items(): - print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0])) -print('Print phasors for all nodes at last time step:') -for node, phasor in phasors.items(): - print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1])) - -emt_voltages = get_node_emt_voltages(ts_dpsim, 50) -print('Print EMT voltages for all nodes at last time step:') -for node, voltage in emt_voltages.items(): - print(node + ': ' + str(voltage.values[-1])) - -# Change node number to fit example -#plot_timeseries(1, phasors['n2']['abs']) -plot_timeseries(2, emt_voltages['n2']) -plt.show() - +from dataprocessing.dpsim import * +from dataprocessing.plottools import * + +path = 'D:\\path\\to\\logs\\' +logName = 'simulation_name_LeftVector' +logFilename = path + logName + '.csv' + +ts_dpsim = read_timeseries_dpsim_cmpl(logFilename) + +phasors = get_node_voltage_phasors(ts_dpsim) +print('Print phasors for all nodes at first time step:') +for node, phasor in phasors.items(): + print(node + ': ' + str(phasor['abs'].values[0]) + '<' + str(phasor['phase'].values[0])) +print('Print phasors for all nodes at last time step:') +for node, phasor in phasors.items(): + print(node + ': ' + str(phasor['abs'].values[-1]) + '<' + str(phasor['phase'].values[-1])) + +emt_voltages = get_node_emt_voltages(ts_dpsim, 50) +print('Print EMT voltages for all nodes at last time step:') +for node, voltage in emt_voltages.items(): + print(node + ': ' + str(voltage.values[-1])) + +# Change node number to fit example +#plot_timeseries(1, phasors['n2']['abs']) +plot_timeseries(2, emt_voltages['n2']) +plt.show() + diff --git a/examples/readinresults/Modelica/read_modelica_examples.py b/examples/readinresults/Modelica/read_modelica_examples.py index eab9a32d6f3292e9a4b1c96362c87a97c5cd1636..5e2115571a35337e7cdcf6e719fe65da4df8b6a8 100644 --- a/examples/readinresults/Modelica/read_modelica_examples.py +++ b/examples/readinresults/Modelica/read_modelica_examples.py @@ -1,45 +1,45 @@ -from dataprocessing.readtools import * -from dataprocessing.plottools import * -import matplotlib.pyplot as plt - - -# Example 1: read in single variable included in the Modelica results file -voltage_node126 = read_timeseries_Modelica( - r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", - timeseries_names="N126.Vrel") -plt.figure(1, figsize=(12,8)) -set_timeseries_labels(voltage_node126, "voltage N126") -plt.plot(voltage_node126.time/3600, voltage_node126.values, label=voltage_node126.label) -plt.legend() -plt.show(block=True) - -# Example 2: read in multiple variables defined in a list -voltage_two_nodes = read_timeseries_Modelica( - r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", - timeseries_names=["N127.Vrel", "N128.Vrel"]) -plt.figure(2, figsize=(12,8)) -plt.plot(voltage_two_nodes[0].time/3600, voltage_two_nodes[0].values, label=voltage_two_nodes[0].label) -plt.plot(voltage_two_nodes[1].time/3600, voltage_two_nodes[1].values, label=voltage_two_nodes[1].label) -plt.legend() -plt.show(block=True) - -# Example 3: read in all voltages using regular expressions -voltages_all_nodes = read_timeseries_Modelica( - r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", - timeseries_names='^[^.]*.Vrel$', is_regex=True) -plt.figure(3, figsize=(12, 8)) -for i in range(len(voltages_all_nodes)): - plt.plot(voltages_all_nodes[i].time / 3600, voltages_all_nodes[i].values, label=voltages_all_nodes[i].label) -plt.legend() -plt.show(block=True) - -# Example 4: read in all variables -variables_all = read_timeseries_Modelica( - r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat") -dict_variables_all = {} -for ts in variables_all: - dict_variables_all[ts.name] = ts -plt.figure(4, figsize=(12, 8)) -plt.plot(dict_variables_all["L12.Irel"].time/3600, dict_variables_all["L12.Irel"].values, label=dict_variables_all["L12.Irel"].label) -plt.legend() +from dataprocessing.readtools import * +from dataprocessing.plottools import * +import matplotlib.pyplot as plt + + +# Example 1: read in single variable included in the Modelica results file +voltage_node126 = read_timeseries_Modelica( + r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", + timeseries_names="N126.Vrel") +plt.figure(1, figsize=(12,8)) +set_timeseries_labels(voltage_node126, "voltage N126") +plt.plot(voltage_node126.time/3600, voltage_node126.values, label=voltage_node126.label) +plt.legend() +plt.show(block=True) + +# Example 2: read in multiple variables defined in a list +voltage_two_nodes = read_timeseries_Modelica( + r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", + timeseries_names=["N127.Vrel", "N128.Vrel"]) +plt.figure(2, figsize=(12,8)) +plt.plot(voltage_two_nodes[0].time/3600, voltage_two_nodes[0].values, label=voltage_two_nodes[0].label) +plt.plot(voltage_two_nodes[1].time/3600, voltage_two_nodes[1].values, label=voltage_two_nodes[1].label) +plt.legend() +plt.show(block=True) + +# Example 3: read in all voltages using regular expressions +voltages_all_nodes = read_timeseries_Modelica( + r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat", + timeseries_names='^[^.]*.Vrel$', is_regex=True) +plt.figure(3, figsize=(12, 8)) +for i in range(len(voltages_all_nodes)): + plt.plot(voltages_all_nodes[i].time / 3600, voltages_all_nodes[i].values, label=voltages_all_nodes[i].label) +plt.legend() +plt.show(block=True) + +# Example 4: read in all variables +variables_all = read_timeseries_Modelica( + r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\IEEE European\Single_scenario_fixed_PV\IEEEEuropean_60.mat") +dict_variables_all = {} +for ts in variables_all: + dict_variables_all[ts.name] = ts +plt.figure(4, figsize=(12, 8)) +plt.plot(dict_variables_all["L12.Irel"].time/3600, dict_variables_all["L12.Irel"].values, label=dict_variables_all["L12.Irel"].label) +plt.legend() plt.show(block=True) \ No newline at end of file diff --git a/examples/readinresults/NEPLAN/read_NEPLAN_example.py b/examples/readinresults/NEPLAN/read_NEPLAN_example.py index efc62e2758caa48eacdf2b03e63c027579921e89..3d7e19771a33536bb7d2b54e2416a6a462289954 100644 --- a/examples/readinresults/NEPLAN/read_NEPLAN_example.py +++ b/examples/readinresults/NEPLAN/read_NEPLAN_example.py @@ -1,66 +1,66 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- -import re -from dataprocessing.readtools import * - - -file = r"C:\Users\admin\Desktop\Load_read\Load_flow_WCSS.rlf" - - -# Example 1: Read in all variable -print('************************ Test for read in all variable start ****************') -result_ALL = read_timeseries_NEPLAN_loadflow(file) -for i in range(len(result_ALL)): - print('%s is %s' % (result_ALL[i].name, result_ALL[i].values)) # result as list of TimeSeries -print('************************ Test for read in all variable end ****************') -print('\n') - - -# Example 2: Read in specific variable -print('************************ Test for read in specific variable start ****************') - -print('************************ Read in specific Voltage ****************') -result_U = read_timeseries_NEPLAN_loadflow(file, 'FOUR.U') -for i in range(len(result_U)): - print('%s is %s' % (result_U[i].name, result_U[i].values)) - -print('************************ Read in specific Voltage Angel ****************') -result_ANGELU = read_timeseries_NEPLAN_loadflow(file, 'FOUR.ANGELU') -for i in range(len(result_ANGELU)): - print('%s is %s' % (result_ANGELU[i].name, result_ANGELU[i].values)) - -print('************************ Read in specific Current ****************') -result_I = read_timeseries_NEPLAN_loadflow(file, 'LINE89.I') -for i in range(len(result_I)): - print('%s is %s' % (result_I[i].name, result_I[i].values)) - -print('************************ Read in specific Current Angel ****************') -result_ANGELI = read_timeseries_NEPLAN_loadflow(file, 'LINE89.ANGELI') -for i in range(len(result_ANGELI)): - print('%s is %s' % (result_ANGELI[i].name, result_ANGELI[i].values)) -print('************************ Test for read in specific variable end ****************') -print('\n') - - -# Example 3: Read in using regular expression -print('************************ Test for read in using Regular Expression start ****************') -print('************************ Read in Current using Regular Expression ****************') -result_I_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.I$', True) -for i in range(len(result_I_REG)): - print('%s is %s' % (result_I_REG[i].name, result_I_REG[i].values)) - -print('************************ Read in Current Angel using Regular Expression ****************') -result_ANGERLI_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.ANGELI$', True) -for i in range(len(result_ANGERLI_REG)): - print('%s is %s' % (result_ANGERLI_REG[i].name, result_ANGERLI_REG[i].values)) - -print('************************ Read in Voltage using Regular Expression ****************') -result_U_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.U$', True) -for i in range(len(result_U_REG)): - print('%s is %s' % (result_U_REG[i].name, result_U_REG[i].values)) - -print('************************ Read in Voltage Angel using Regular Expression ****************') -result_ANGELU_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.ANGELU$', True) -for i in range(len(result_ANGELU_REG)): - print('%s is %s' % (result_ANGELU_REG[i].name, result_ANGELU_REG[i].values)) +#!/usr/bin/python +# -*- coding: UTF-8 -*- +import re +from dataprocessing.readtools import * + + +file = r"C:\Users\admin\Desktop\Load_read\Load_flow_WCSS.rlf" + + +# Example 1: Read in all variable +print('************************ Test for read in all variable start ****************') +result_ALL = read_timeseries_NEPLAN_loadflow(file) +for i in range(len(result_ALL)): + print('%s is %s' % (result_ALL[i].name, result_ALL[i].values)) # result as list of TimeSeries +print('************************ Test for read in all variable end ****************') +print('\n') + + +# Example 2: Read in specific variable +print('************************ Test for read in specific variable start ****************') + +print('************************ Read in specific Voltage ****************') +result_U = read_timeseries_NEPLAN_loadflow(file, 'FOUR.U') +for i in range(len(result_U)): + print('%s is %s' % (result_U[i].name, result_U[i].values)) + +print('************************ Read in specific Voltage Angel ****************') +result_ANGELU = read_timeseries_NEPLAN_loadflow(file, 'FOUR.ANGELU') +for i in range(len(result_ANGELU)): + print('%s is %s' % (result_ANGELU[i].name, result_ANGELU[i].values)) + +print('************************ Read in specific Current ****************') +result_I = read_timeseries_NEPLAN_loadflow(file, 'LINE89.I') +for i in range(len(result_I)): + print('%s is %s' % (result_I[i].name, result_I[i].values)) + +print('************************ Read in specific Current Angel ****************') +result_ANGELI = read_timeseries_NEPLAN_loadflow(file, 'LINE89.ANGELI') +for i in range(len(result_ANGELI)): + print('%s is %s' % (result_ANGELI[i].name, result_ANGELI[i].values)) +print('************************ Test for read in specific variable end ****************') +print('\n') + + +# Example 3: Read in using regular expression +print('************************ Test for read in using Regular Expression start ****************') +print('************************ Read in Current using Regular Expression ****************') +result_I_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.I$', True) +for i in range(len(result_I_REG)): + print('%s is %s' % (result_I_REG[i].name, result_I_REG[i].values)) + +print('************************ Read in Current Angel using Regular Expression ****************') +result_ANGERLI_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.ANGELI$', True) +for i in range(len(result_ANGERLI_REG)): + print('%s is %s' % (result_ANGERLI_REG[i].name, result_ANGERLI_REG[i].values)) + +print('************************ Read in Voltage using Regular Expression ****************') +result_U_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.U$', True) +for i in range(len(result_U_REG)): + print('%s is %s' % (result_U_REG[i].name, result_U_REG[i].values)) + +print('************************ Read in Voltage Angel using Regular Expression ****************') +result_ANGELU_REG = read_timeseries_NEPLAN_loadflow(file, '^.*\.ANGELU$', True) +for i in range(len(result_ANGELU_REG)): + print('%s is %s' % (result_ANGELU_REG[i].name, result_ANGELU_REG[i].values)) print('************************ Test for read in using Regular Expression end ****************') \ No newline at end of file diff --git a/setup.py b/setup.py index 950ca8ebb75d4964eb7dc008ac49ec2a85e3fbca..dccce36bccd15723ff6cf8af172396f84a9f9de7 100644 --- a/setup.py +++ b/setup.py @@ -1,45 +1,45 @@ -import os -from setuptools import setup, find_packages - -def read(fname): - dname = os.path.dirname(__file__) - fname = os.path.join(dname, fname) - - try: - import m2r - return m2r.parse_from_file(fname) - except ImportError: - with open(fname) as f: - return f.read() - -setup( - name = "acs-dataprocessing", - version = "0.1.2", - author = "Markus Mirz, Jan Dinkelbach, Steffen Vogel", - author_email = "acs-software@eonerc.rwth-aachen.de", - description = "Several tools for processing simulation results", - license = "GPL-3.0", - keywords = "simulation power system real-time data processing", - url = "https://git.rwth-aachen.de/acs/public/simulation/data-processing", - packages = find_packages(), - long_description = read('README.md'), - classifiers = [ - "Development Status :: 4 - Beta", - "Topic :: Scientific/Engineering", - "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", - "Operating System :: MacOS :: MacOS X", - "Operating System :: Microsoft :: Windows", - "Operating System :: POSIX :: Linux", - "Programming Language :: Python :: 3" - ], - install_requires = [ - "matplotlib", - "numpy", - "pandas" - ], - setup_requires = [ - 'm2r', - 'wheel' - ] -) - +import os +from setuptools import setup, find_packages + +def read(fname): + dname = os.path.dirname(__file__) + fname = os.path.join(dname, fname) + + try: + import m2r + return m2r.parse_from_file(fname) + except ImportError: + with open(fname) as f: + return f.read() + +setup( + name = "acs-dataprocessing", + version = "0.1.2", + author = "Markus Mirz, Jan Dinkelbach, Steffen Vogel", + author_email = "acs-software@eonerc.rwth-aachen.de", + description = "Several tools for processing simulation results", + license = "GPL-3.0", + keywords = "simulation power system real-time data processing", + url = "https://git.rwth-aachen.de/acs/public/simulation/data-processing", + packages = find_packages(), + long_description = read('README.md'), + classifiers = [ + "Development Status :: 4 - Beta", + "Topic :: Scientific/Engineering", + "License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)", + "Operating System :: MacOS :: MacOS X", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3" + ], + install_requires = [ + "matplotlib", + "numpy", + "pandas" + ], + setup_requires = [ + 'm2r', + 'wheel' + ] +) +