Skip to content

Commit

Permalink
Finalize the ZeroMQ format
Browse files Browse the repository at this point in the history
  • Loading branch information
abhineet-gupta committed Nov 14, 2023
1 parent cbe2a68 commit 3750a7e
Show file tree
Hide file tree
Showing 5 changed files with 344 additions and 306 deletions.
166 changes: 73 additions & 93 deletions Examples/17b_zeromq_multi_openfast.py
Original file line number Diff line number Diff line change
@@ -1,121 +1,101 @@
import platform
import os
import matplotlib.pyplot as plt
from ROSCO_toolbox.inputs.validation import load_rosco_yaml
from ROSCO_toolbox.utilities import write_DISCON
from ROSCO_toolbox import control_interface as ROSCO_ci
import multiprocessing as mp
from ROSCO_toolbox.control_interface import wfc_zmq_server
from ROSCO_toolbox import sim as ROSCO_sim
from ROSCO_toolbox import turbine as ROSCO_turbine
from ROSCO_toolbox import controller as ROSCO_controller
from ROSCO_toolbox.ofTools.case_gen import CaseLibrary as cl
import numpy as np
import multiprocessing as mp
from ROSCO_toolbox.ofTools.case_gen.run_FAST import run_FAST_ROSCO

this_dir = os.path.dirname(os.path.abspath(__file__))
example_out_dir = os.path.join(this_dir,'examples_out')
os.makedirs(example_out_dir,exist_ok=True)

this_dir = os.path.dirname(os.path.abspath(__file__))
example_out_dir = os.path.join(this_dir, "examples_out")
os.makedirs(example_out_dir, exist_ok=True)


def run_zmq():
connect_zmq = True
s = wfc_zmq_server(network_address="tcp://*:5555", timeout=10000.0, verbose=False, n_turbines = 2)
while connect_zmq:
# Get latest measurements from ROSCO
measurements = s.get_measurements()
identifier = measurements['ZMQ_ID']

# somewhere in the server code, we need to save the ID to setpoints
# otherwise, it's initialized as 0 like everything else
# do this here for now until the server code moves somewhere else

# I think we need to build out this part of the code, next
id = int(identifier)

s.setpoints[id-1]['ZMQ_ID'] = measurements['ZMQ_ID']

# Maybe measurements needs to be a dict so we don't have this id-1 business
s.measurements[id-1] = measurements

# Decide new control input based on measurements
current_time = measurements['Time']
if current_time <= 10.0:
yaw_setpoint = 0.0
"""Start the ZeroMQ server for wind farm control"""

# Start the server at the following address
network_address = "tcp://*:5555"
server = wfc_zmq_server(network_address, timeout=60.0, verbose=True)

# Provide the wind farm control algorithm as the wfc_controller method of the server
server.wfc_controller = wfc_controller

# Run the server to receive measurements and send setpoints
server.runserver()


def wfc_controller(id, current_time, measurements):
"""
Users needs to define this function to implement wind farm controller.
The user defined function should take as argument the turbine id, the
current time and current measurements and return the setpoints
for the particular turbine for the current time. It should ouput the
setpoints as a dictionary whose keys should be as defined in
wfc_zmq_server.wfc_interface. The wfc_controller method of the wfc_zmq_server
should be overwriten with this fuction, otherwise, an exception is raised and
the simulation stops.
"""
if current_time <= 10.0:
YawOffset = 0.0
else:
if id == 1:
YawOffset = -10.0
else:
if identifier >= 1.5:
yaw_setpoint = -10.0
else:
yaw_setpoint = 10.0

# current_time1 = measurements1['Time']
# if current_time1 <= 10.0:
# yaw_setpoint1 = 0.0
# else:
# yaw_setpoint1 = -20.0

# Send new setpoints back to ROSCO
s.setpoints[id-1]['ZMQ_YawOffset'] = yaw_setpoint
s.send_setpoints(id)
# s1.send_setpoints(nacelleHeading=yaw_setpoint1)

if measurements['iStatus'] == -1:
connect_zmq = False
s._disconnect()
print('Done with run_zmq')
YawOffset = 10
setpoints = {}
setpoints["ZMQ_YawOffset"] = YawOffset
return setpoints


def sim_openfast_1():
# fstfile = '/Users/agupta/Projects/Tools/AG_ROSCO/Examples/IEA-3.4-130-RWT/openfast/IEA-3.4-130-RWT.fst'
# of_exec = '/Users/agupta/Projects/Tools/AG_openfast/build_v3p5p0/glue-codes/openfast/openfast'
# os.system(of_exec + ' ' + fstfile)
# pass
"""Run the first OpenFAST simulation with ZeroMQ enabled"""
r = run_FAST_ROSCO()
r.tuning_yaml = 'NREL5MW.yaml'
r.tuning_yaml = "NREL5MW.yaml"
r.wind_case_fcn = cl.power_curve
r.wind_case_opts = {
'U': [8],
'TMax': 100,
}
run_dir = os.path.join(example_out_dir,'17b_zeromq_OF1')
r.wind_case_opts = {
"U": [8],
"TMax": 100,
}
run_dir = os.path.join(example_out_dir, "17b_zeromq_OF1")
r.controller_params = {}
r.controller_params['LoggingLevel'] = 2
r.controller_params['DISCON'] = {}
r.controller_params['DISCON']['ZMQ_Mode'] = 1
r.controller_params['DISCON']['ZMQ_ID'] = 1
r.save_dir = run_dir
r.controller_params["LoggingLevel"] = 2
r.controller_params["DISCON"] = {}
r.controller_params["DISCON"]["ZMQ_Mode"] = 1
r.controller_params["DISCON"]["ZMQ_ID"] = 1
r.save_dir = run_dir
r.run_FAST()



def sim_openfast_2():
"""Run the second OpenFAST simulation with ZeroMQ enabled"""
r = run_FAST_ROSCO()
r.tuning_yaml = 'NREL5MW.yaml'
r.tuning_yaml = "NREL5MW.yaml"
r.wind_case_fcn = cl.power_curve
r.wind_case_opts = {
'U': [8],
'TMax': 100,
}
run_dir = os.path.join(example_out_dir,'17b_zeromq_OF2')
r.save_dir = run_dir
r.wind_case_opts = {
"U": [8],
"TMax": 100,
}
run_dir = os.path.join(example_out_dir, "17b_zeromq_OF2")
r.save_dir = run_dir
r.controller_params = {}
r.controller_params['DISCON'] = {}
r.controller_params['LoggingLevel'] = 2
r.controller_params['DISCON']['ZMQ_Mode'] = 1
r.controller_params['DISCON']['ZMQ_ID'] = 2
r.controller_params["DISCON"] = {}
r.controller_params["LoggingLevel"] = 2
r.controller_params["DISCON"]["ZMQ_Mode"] = 1
r.controller_params["DISCON"]["ZMQ_ID"] = 2
r.run_FAST()


if __name__ == "__main__":
# sim_rosco()
# run_zmq()
# sim_openfast()
p1 = mp.Process(target=run_zmq)
# Start wind farm control server and two openfast simulation
# as separate processes
p0 = mp.Process(target=run_zmq)
p1 = mp.Process(target=sim_openfast_1)
p2 = mp.Process(target=sim_openfast_2)

p0.start()
p1.start()
p2 = mp.Process(target=sim_openfast_1)
p2.start()
p3 = mp.Process(target=sim_openfast_2)
p3.start()

p0.join()
p1.join()
p2.join()
p3.join()


1 change: 0 additions & 1 deletion ROSCO/rosco_registry/wfc_interface.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ measurements: [
]

setpoints: [
ZMQ_ID,
ZMQ_TorqueOffset,
ZMQ_YawOffset,
ZMQ_PitOffset(1),
Expand Down
15 changes: 7 additions & 8 deletions ROSCO/src/ZeroMQInterface.f90
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SUBROUTINE UpdateZeroMQ(LocalVar, CntrPar, ErrVar)
TYPE(ErrorVariables), INTENT(INOUT) :: ErrVar

character(256) :: zmq_address
real(C_DOUBLE) :: setpoints(6)
real(C_DOUBLE) :: setpoints(5)
real(C_DOUBLE) :: turbine_measurements(17)
CHARACTER(*), PARAMETER :: RoutineName = 'UpdateZeroMQ'

Expand All @@ -24,7 +24,7 @@ subroutine zmq_client(zmq_address, measurements, setpoints) bind(C, name='zmq_cl
implicit none
character(C_CHAR), intent(out) :: zmq_address(*)
real(C_DOUBLE) :: measurements(17)
real(C_DOUBLE) :: setpoints(6)
real(C_DOUBLE) :: setpoints(5)
end subroutine zmq_client
end interface
#endif
Expand Down Expand Up @@ -68,12 +68,11 @@ end subroutine zmq_client
! write (*,*) 'ZeroMQInterface: pitch 1 setpoint from ssc: ', setpoints(3)
! write (*,*) 'ZeroMQInterface: pitch 2 setpoint from ssc: ', setpoints(4)
! write (*,*) 'ZeroMQInterface: pitch 3 setpoint from ssc: ', setpoints(5)
LocalVar%ZMQ_ID = setpoints(1)
LocalVar%ZMQ_TorqueOffset = setpoints(2)
LocalVar%ZMQ_YawOffset = setpoints(3)
LocalVar%ZMQ_PitOffset(1) = setpoints(4)
LocalVar%ZMQ_PitOffset(2) = setpoints(5)
LocalVar%ZMQ_PitOffset(3) = setpoints(6)
LocalVar%ZMQ_TorqueOffset = setpoints(1)
LocalVar%ZMQ_YawOffset = setpoints(2)
LocalVar%ZMQ_PitOffset(1) = setpoints(3)
LocalVar%ZMQ_PitOffset(2) = setpoints(4)
LocalVar%ZMQ_PitOffset(3) = setpoints(5)

ENDIF

Expand Down
2 changes: 1 addition & 1 deletion ROSCO/src/zmq_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ void delete_blank_spaces_in_string(char *s)
int zmq_client (
char *zmq_address,
double measurements[17],
double setpoints[6]
double setpoints[5]
)
{
int num_measurements = 17; // Number of setpoints and measurements, respectively, and float precision (character length)
Expand Down
Loading

0 comments on commit 3750a7e

Please sign in to comment.