Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use sensor channel instead of file configuration #87

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
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
31 changes: 31 additions & 0 deletions LocalFeeder/FeederSimulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ class OpenDSSState(Enum):
DISABLED = 7


class SensorLocations(BaseModel):
voltage_sensors: List[str]
active_sensors: List[str]
reactive_sensors: List[str]


class FeederSimulator(object):
"""A simple class that handles publishing the solar forecast."""

Expand Down Expand Up @@ -158,6 +164,20 @@ def __init__(self, config: FeederConfig):

if self._sensor_location is None:
self.create_measurement_lists()
else:
sensor_location = os.path.join(
"sensors", os.path.basename(self._sensor_location)
)
if os.path.exists(sensor_location):
with open(sensor_location, "r") as fp:
sensor_config = json.load(fp)
self.voltage_sensors = sensor_config
self.active_sensors = sensor_config
self.reactive_sensors = sensor_config
else:
self.voltage_sensors = []
self.active_sensors = []
self.reactive_sensors = []

self.snapshot_run()
assert self._state == OpenDSSState.SNAPSHOT_RUN, f"{self._state}"
Expand Down Expand Up @@ -282,6 +302,7 @@ def create_measurement_lists(
self._AllNodeNames,
math.floor(len(self._AllNodeNames) * float(percent_voltage) / 100),
)
self.voltage_sensors = voltage_subset
with open(os.path.join("sensors", "voltage_ids.json"), "w") as fp:
json.dump(voltage_subset, fp, indent=4)

Expand All @@ -290,6 +311,7 @@ def create_measurement_lists(
self._AllNodeNames,
math.floor(len(self._AllNodeNames) * float(percent_real) / 100),
)
self.active_sensors = real_subset
with open(os.path.join("sensors", "real_ids.json"), "w") as fp:
json.dump(real_subset, fp, indent=4)

Expand All @@ -298,9 +320,18 @@ def create_measurement_lists(
self._AllNodeNames,
math.floor(len(self._AllNodeNames) * float(percent_voltage) / 100),
)
self.reactive_sensors = reactive_subset
with open(os.path.join("sensors", "reactive_ids.json"), "w") as fp:
json.dump(reactive_subset, fp, indent=4)

def get_sensors(self):
"""Get sensor locations."""
return SensorLocations(
voltage_sensors=self.voltage_sensors,
active_sensors=self.active_sensors,
reactive_sensors=self.reactive_sensors,
)

def get_circuit_name(self):
"""Get name of current opendss circuit."""
return self._circuit.Name()
Expand Down
4 changes: 4 additions & 0 deletions LocalFeeder/component_definition.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@
{
"type": "",
"port_id": "pv_forecast"
},
{
"type": "",
"port_id": "sensors"
}
]
}
20 changes: 14 additions & 6 deletions LocalFeeder/sender_cosim.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ def go_cosim(
pub_pv_forecast = h.helicsFederateRegisterPublication(
vfed, "pv_forecast", h.HELICS_DATA_TYPE_STRING, ""
)
pub_sensors = h.helicsFederateRegisterPublication(
vfed, "sensors", h.HELICS_DATA_TYPE_STRING, ""
)

command_set_key = (
"unused/change_commands"
Expand Down Expand Up @@ -363,15 +366,17 @@ def go_cosim(
# Publish the forecasted PV outputs as a list of MeasurementArray
logger.info("Evaluating the forecasted PV")
forecast_data = sim.forcast_pv(int(config.number_of_timesteps))
PVforecast = [MeasurementArray(**xarray_to_dict(forecast),
units="kW").json() for forecast in forecast_data]
PVforecast = [
MeasurementArray(**xarray_to_dict(forecast), units="kW").json()
for forecast in forecast_data
]
pub_pv_forecast.publish(json.dumps(PVforecast))

pub_sensors.publish(sim.get_sensors().json())

granted_time = -1
request_time = 0
initial_timestamp = datetime.strptime(
config.start_date, "%Y-%m-%d %H:%M:%S"
)
initial_timestamp = datetime.strptime(config.start_date, "%Y-%m-%d %H:%M:%S")

while request_time < int(config.number_of_timesteps):
granted_time = h.helicsFederateRequestTime(vfed, request_time)
Expand Down Expand Up @@ -400,7 +405,10 @@ def go_cosim(
for pv_set in pv_sets:
sim.set_pv_output(pv_set[0].split(".")[1], pv_set[1], pv_set[2])

current_hour = 24*(floored_timestamp.date() - initial_timestamp.date()).days + floored_timestamp.hour
current_hour = (
24 * (floored_timestamp.date() - initial_timestamp.date()).days
+ floored_timestamp.hour
)
logger.info(
f"Solve at hour {current_hour} second "
f"{60*floored_timestamp.minute + floored_timestamp.second}"
Expand Down
8 changes: 8 additions & 0 deletions measuring_federate/component_definition.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
"type": "",
"port_id": "multiplicative_noise_stddev"
},
{
"type": "",
"port_id": "measurement_type"
},
{
"type": "",
"port_id": "measurement_file"
Expand All @@ -19,6 +23,10 @@
{
"type": "MeasurementArray",
"port_id": "subscription"
},
{
"type": "SensorDescription",
"port_id": "sensors"
}
],
"dynamic_outputs": [
Expand Down
21 changes: 17 additions & 4 deletions measuring_federate/measuring_federate.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class MeasurementConfig(BaseModel):
name: str
additive_noise_stddev: float = 0.0
multiplicative_noise_stddev: float = 0.0
measurement_file: str
measurement_type: str | None = None
measurement_file: str | None = None
run_freq_time_step: float = 1.0


Expand Down Expand Up @@ -94,6 +95,10 @@ def __init__(
self.sub_measurement = self.vfed.register_subscription(
input_mapping["subscription"], ""
)
if "sensors" in input_mapping:
self.sub_sensors = self.vfed.register_subscription(
input_mapping["sensors"], ""
)

# TODO: find better way to determine what the name of this federate instance is than looking at the subscription
self.pub_measurement = self.vfed.register_publication(
Expand All @@ -102,6 +107,7 @@ def __init__(

self.additive_noise_stddev = config.additive_noise_stddev
self.multiplicative_noise_stddev = config.multiplicative_noise_stddev
self.measurement_type = config.measurement_type
self.measurement_file = config.measurement_file

def transform(self, measurement_array: MeasurementArray, unique_ids):
Expand All @@ -126,9 +132,16 @@ def run(self):
else:
measurement = MeasurementArray.parse_obj(json_data)

with open(self.measurement_file, "r") as fp:
self.measurement = json.load(fp)
measurement_transformed = self.transform(measurement, self.measurement)
if self.measurement_type is not None:
self.sensors = self.sub_sensors.json
assert self.measurement_type in self.sensors
measurement_transformed = self.transform(
measurement, self.sensors[self.measurement_type]
)
else:
with open(self.measurement_file, "r") as fp:
self.measurement = json.load(fp)
measurement_transformed = self.transform(measurement, self.measurement)
logger.debug("measured transformed")
logger.debug(measurement_transformed)

Expand Down
1 change: 0 additions & 1 deletion recorder/record_subscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import json
import logging
from datetime import datetime
import time

import helics as h
import numpy as np
Expand Down
3 changes: 1 addition & 2 deletions scenarios/omoo_system.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
"use_smartds": false,
"profile_location": "gadal_ieee123/profiles",
"opendss_location": "gadal_ieee123/qsts",
"sensor_location": "gadal_ieee123/sensors.json",
"existing_feeder_file": "opendss/master.dss",
"start_date": "2017-01-01 00:00:00",
"number_of_timesteps": 96,
Expand All @@ -65,7 +64,7 @@
"use_smartds": false,
"profile_location": "gadal_ieee123/profiles",
"opendss_location": "gadal_ieee123/qsts",
"sensor_location": "gadal_ieee123/sensors.json",
"sensor_location": "sensors.json",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this location modified by the opendss and profile names still include the gadal_iee123 name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I figured out what was happening here. The problem is this existing_feeder_file just out of frame.

We use the sensor_location in two different ways right now. In one way, we specify where the sensors are on AWS. In the other way, we use it put it on the channel. I was using it for both, which is why is became a problem.

"existing_feeder_file": "opendss/master.dss",
"start_date": "2017-01-01 00:00:00",
"number_of_timesteps": 96,
Expand Down
Loading
Loading