Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/docker-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ jobs:
shell: bash -l {0}
run: |
pip install matplotlib pyarrow numpy matplotlib pandas
pip install oedisi==1.2.1
pip install 'oedisi>=2,<3'

oedisi evaluate-estimate --metric MAAE --path outputs
oedisi evaluate-estimate --metric MARE --path outputs

python post_analysis.py outputs_build
- name: Archive logs
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: always()
with:
name: docker_logs
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
oedisi run
python post_analysis.py
- name: Archive logs
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: always()
with:
name: test_logs
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-dopf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
oedisi run
python opf_analysis.py
- name: Archive logs
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
if: always()
with:
name: test_logs
Expand Down
5 changes: 4 additions & 1 deletion measuring_federate/measuring_federate.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ def __init__(
logger.debug(config.name)

h.helicsFederateInfoSetTimeProperty(
fedinfo, h.helics_property_time_delta, config.run_freq_time_step
fedinfo, h.helics_property_time_period, config.run_freq_time_step
)
h.helicsFederateInfoSetTimeProperty(
fedinfo, h.helics_property_time_offset, 0.03
)

self.vfed = h.helicsCreateValueFederate(config.name, fedinfo)
Expand Down
2 changes: 0 additions & 2 deletions recorder/record_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,6 @@ def run(self):
logger.info("start time: " + str(datetime.now()))
logger.debug(granted_time)
# Check that the data is a MeasurementArray type
json_data = self.sub.json
json_data["time"] = granted_time
measurement = MeasurementArray(**self.sub.json)
measurement_dict = {
key: value
Expand Down
2 changes: 1 addition & 1 deletion scenarios/large_aws_feeder.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,4 @@
"target_port": "subscription"
}
]
}
}
5 changes: 2 additions & 3 deletions scenarios/medium_aws_feeder.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,7 @@
"start_date": "2017-05-01 00:00:00",
"number_of_timesteps": 96,
"run_freq_sec": 900,
"topology_output": "../../outputs/topology.json",
"use_sparse_admittance": true
"topology_output": "../../outputs/topology.json"
}
},
{
Expand Down Expand Up @@ -149,4 +148,4 @@
"target_port": "subscription"
}
]
}
}
44 changes: 43 additions & 1 deletion scenarios/small_aws_feeder.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,30 @@
"csv_filename": "../../outputs/voltage_angle.csv"
}
},
{
"name": "recorder_measured_voltage_magnitude",
"type": "Recorder",
"parameters": {
"feather_filename": "../../outputs/measured_voltage_magnitude.feather",
"csv_filename": "../../outputs/measured_voltage_magnitude.csv"
}
},
{
"name": "recorder_measured_power_real",
"type": "Recorder",
"parameters": {
"feather_filename": "../../outputs/measured_power_real.feather",
"csv_filename": "../../outputs/measured_power_real.csv"
}
},
{
"name": "recorder_measured_power_imag",
"type": "Recorder",
"parameters": {
"feather_filename": "../../outputs/measured_power_imag.feather",
"csv_filename": "../../outputs/measured_power_imag.csv"
}
},
{
"name": "state_estimator",
"type": "StateEstimatorComponent",
Expand Down Expand Up @@ -147,6 +171,24 @@
"source_port": "voltage_mag",
"target": "recorder_voltage_mag",
"target_port": "subscription"
},
{
"source": "sensor_voltage_magnitude",
"source_port": "publication",
"target": "recorder_measured_voltage_magnitude",
"target_port": "subscription"
},
{
"source": "sensor_power_real",
"source_port": "publication",
"target": "recorder_measured_power_real",
"target_port": "subscription"
},
{
"source": "sensor_power_imaginary",
"source_port": "publication",
"target": "recorder_measured_power_imag",
"target_port": "subscription"
}
]
}
}
1 change: 1 addition & 0 deletions wls_federate/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
base_*.csv
base_*.npz
*.png
opendss
profiles

Expand Down
52 changes: 39 additions & 13 deletions wls_federate/state_estimator_federate.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,24 @@ def matrix_to_numpy(admittance: List[List[Complex]]):
return np.array([[x[0] + 1j * x[1] for x in row] for row in admittance])


def get_indices(topology, measurement):
def get_indices(topology: Topology, measurement, extra_nodes=set()):
"Get list of indices in the topology for each index of the input measurement"
inv_map = {v: i for i, v in enumerate(topology.base_voltage_magnitudes.ids)}
return [inv_map[v] for v in measurement.ids]
ordinary_indices = [inv_map[v] for v in measurement.ids]
extra_indices = [inv_map[v] for v in extra_nodes.difference(measurement.ids)]
return ordinary_indices + extra_indices


def get_zero_injection_indices(topology: Topology):
zero_nodes = set(topology.base_voltage_magnitudes.ids)
zero_nodes = zero_nodes.difference(topology.injections.power_real.ids)
zero_nodes = zero_nodes.difference(topology.injections.power_imaginary.ids)
zero_nodes = zero_nodes.difference(topology.injections.current_real.ids)
zero_nodes = zero_nodes.difference(topology.injections.current_imaginary.ids)
zero_nodes = zero_nodes.difference(topology.injections.impedance_real.ids)
zero_nodes = zero_nodes.difference(topology.injections.impedance_imaginary.ids)
zero_nodes = zero_nodes.difference(topology.slack_bus)
return zero_nodes


class AlgorithmParameters(BaseModel):
Expand Down Expand Up @@ -164,19 +178,23 @@ def state_estimator(
logging.debug("Number of Nodes")
logging.debug(num_node)

knownP = get_indices(topology, P)
knownQ = get_indices(topology, Q)
zero_power_nodes = get_zero_injection_indices(topology)
knownP = get_indices(topology, P, extra_nodes=zero_power_nodes)
knownQ = get_indices(topology, Q, extra_nodes=zero_power_nodes)
knownV = get_indices(topology, V)

P_array = np.zeros(len(knownP))
P_array[: len(P.values)] = P.values
Q_array = np.zeros(len(knownQ))
Q_array[: len(Q.values)] = Q.values
z = np.concatenate(
(
V.values / base_voltages[knownV],
-np.array(P.values) / parameters.base_power,
-np.array(Q.values) / parameters.base_power,
-P_array / parameters.base_power,
-Q_array / parameters.base_power,
),
axis=0,
)

Y = get_y(topology.admittance, topology.base_voltage_magnitudes.ids)
# Hand-crafted unit conversion (check it, it works)
Y = (
Expand Down Expand Up @@ -318,12 +336,20 @@ def run(self):
knownV = get_indices(topology, voltages)

if self.initial_V is None:
# Flat start or using average measurements
if (
len(power_P.ids) + len(voltages.ids) + len(power_Q.ids)
> len(ids) * 2
):
self.initial_V = 1.0
voltage_inv_map = {v: i for i, v in enumerate(voltages.ids)}
topology_inv_map = {
v: i for i, v in enumerate(topology.base_voltage_magnitudes.ids)
}
if all(map(lambda x: x in voltage_inv_map, topology.slack_bus)):
self.initial_V = np.mean(
[
voltages.values[voltage_inv_map[slack_bus]]
/ topology.base_voltage_magnitudes.values[
topology_inv_map[slack_bus]
]
for slack_bus in topology.slack_bus
]
)
else:
self.initial_V = np.mean(
np.array(voltages.values)
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_no_noise_3/topology.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_no_noise_40/topology.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_3/power_imag.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_3/power_real.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_3/topology.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_3/voltage_real.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_40/power_imag.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_40/power_real.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions wls_federate/tests/large_smartds_noise_40/topology.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading