def dummy_wt_list(): wtl = ExtendedWindTurbinePowerCurveVT() nv = 20 wtl.hub_height = 100.0 wtl.rotor_diameter = 90.0 wtl.power_rating = 3.0 wtl.rpm_curve = [[float(i), 10.0] for i in range(nv)] wtl.pitch_curve = [[float(i), 0.0] for i in range(nv)] wtl.c_t_curve = [[float(i), 10.0] for i in range(nv)] wtl.power_curve = [[float(i), 10.0] for i in range(nv)] return wtl
def test_init(self): ewtpc = ExtendedWindTurbinePowerCurveVT()
class openwindAC_assembly(Assembly): # todo: has to be assembly or manipulation and passthrough of aep in execute doesnt work """ Runs OpenWind from OpenMDAO framework """ # Inputs turb_props = VarTree(ExtendedWindTurbinePowerCurveVT(), iotype='in', desc='properties for default turbine') turbine_number = Int(100, iotype='in', desc='plant number of turbines') # TODO: loss inputs # TODO: wake model option selections # Outputs # inherits output vbls net_aep and gross_aep from GenericAEPModel gross_aep = Float(0.0, iotype='out', desc='Gross Output') net_aep = Float(0.0, iotype='out', desc='Net Output') #array_aep = Float(0.0, iotype='out', desc='Gross Annual Energy Production net of array impacts', unit='kWh') total_losses = Float(0.0, iotype='out', desc='Total Losses (gross to net)') capacity_factor = Float(0.0, iotype='out', desc='capacity factor') # ------------------- #def __init__(self, openwind_executable, workbook_path, # try with default values to fix problem with interface.py def __init__(self, openwind_executable=None, workbook_path=None, turbine_name=None, # not used? script_file=None, academic=True, wt_positions=None, machine_rating=None, start_once=False, debug=False): """ Creates a new GenericAEPModel Assembly object for OpenWind Academic """ foundErrors = False if openwind_executable is None: sys.stderr.write('\n*** ERROR: executable not assigned\n\n') foundErrors = True elif not os.path.isfile(openwind_executable): sys.stderr.write('\n*** ERROR: executable {:} not found\n\n'.format(openwind_executable)) foundErrors = True if workbook_path is None: sys.stderr.write('\n*** ERROR: workbook_path not assigned\n\n') foundErrors = True elif not os.path.isfile(workbook_path): sys.stderr.write('\n*** ERROR: workbook {:} not found\n\n'.format(workbook_path)) foundErrors = True if foundErrors: return None # Set the location where new scripts and turbine files will be written self.workDir = os.getcwd() #self.workDir = os.path.dirname(os.path.realpath(__file__)) # location of this source file self.ow = None # the Openwind Component self.openwind_executable = openwind_executable self.workbook_path = workbook_path self.turbine_name = turbine_name self.script_file = script_file self.academic = academic self.debug = debug self.machine_rating = machine_rating self.start_once = start_once if self.debug: sys.stderr.write('\nIn {:}.__init__()\n'.format(self.__class__)) # Set initial positions of turbines self.init_wt_positions = [] if wt_positions is not None: self.init_wt_positions = wt_positions #self.wt_layout.wt_positions = wt_positions # TODO: hack for now assigning turbine #self.turb = GenericWindTurbinePowerCurveVT() self.turb = ExtendedWindTurbinePowerCurveVT() if self.machine_rating is not None: self.turb.power_rating = self.machine_rating #self.turb.hub_height = self.hub_height #self.turb.power_curve = np.copy(self.power_curve) # self.wt_layout is created with a passthrough in configure(), but doesn't exist yet #for i in xrange(0,self.turbine_number): # self.wt_layout.wt_list.append(self.turb) # call to super().__init__ needs to be at the end # - otherwise, self.* declared later will not exist super(openwindAC_assembly, self).__init__() # ------------------- def configure(self): """ make connections """ if self.debug: sys.stderr.write('\nIn {:}.configure()\n'.format(self.__class__)) super(openwindAC_assembly, self).configure() # Create component instances ow = OWACcomp(self.openwind_executable, scriptFile=self.script_file, start_once=self.start_once, debug=self.debug) self.add('ow', ow) # Add components to workflow self.driver.workflow.add(['ow']) # Inputs to OWACcomp self.connect('turb_props.rotor_diameter', 'ow.rotor_diameter') # todo: hack to force external code execution self.create_passthrough('ow.other_losses') self.create_passthrough('ow.availability') self.create_passthrough('ow.wt_layout') self.create_passthrough('ow.dummyVbl') # Outputs from OWACcomp # We can't create passthroughs for gross_aep and net_aep because they're inherited from GenericAEPModel #self.create_passthrough('ow.gross_aep') #self.create_passthrough('ow.net_aep') self.connect('ow.gross_aep', 'gross_aep') self.connect('ow.net_aep', 'net_aep') self.create_passthrough('ow.nTurbs') self.wt_layout.wt_list = [self.turb for i in range(len(self.init_wt_positions))] if self.debug: conns = self.list_connections() sys.stderr.write('Connections\n') for conn in conns: sys.stderr.write(' {:} to {:}\n'.format(conn[0],conn[1])) # ------------------- def execute(self): """ Set up XML and run OpenWind """ if self.debug: sys.stderr.write("\nIn {0}.execute()...\n".format(self.__class__)) # ---- Set up parameters # initial positions are 'connect'ed to OWcomp object with passthrough of wt_layout # set turbine positions # - from initial positions? # - using another component that sets positions? self.wt_layout.wt_positions = self.init_wt_positions # use initial positions # 2014 05 26 - initialize or modify the turbine type here # - read from file # - modify existing turbine type # - add component that returns a new turbine type # trb == ExtendedWindTurbinePowerCurveVT() nt = len(self.wt_layout.wt_positions) # initialize from file #owtg_file = '../test/NREL5MW.owtg' #sys.stderr.write('\n*** WARNING: initializing turbine from {:} - why??\n\n'.format(owtg_file)) #trb = turbfuncs.owtg_to_wtpc(owtg_file) if self.debug: sys.stderr.write('\n*** WARNING: initializing turbine from ExtendedWindTurbinePowerCurveVT\n\n') trb = ExtendedWindTurbinePowerCurveVT() #trb.power_rating = 1000000.0 # watts! trb.power_rating = self.machine_rating for i in range(nt): self.wt_layout.wt_list[i] = trb # show parameters if self.debug: sys.stderr.write('Initial Turbine Positions\n') for i in range(len(self.wt_layout.wt_positions)): sys.stderr.write('{:3d} {:.1f} {:.1f}\n'.format(i, self.wt_layout.wt_positions[i][0],self.wt_layout.wt_positions[i][1])) s = turbfuncs.wtpc_dump(self.wt_layout.wt_list[0]) sys.stderr.write('\n' + s) #report_path = self.workDir + '/' + 'scrtest1.txt' #workbook_path = self.workbook_path # Prepare for next iteration here... # - write new scripts # - write new turbine files # - etc. # owtg_str = turbfuncs.wtpc_to_owtg(self.turb_props) # write new script for execution # newScriptName = 'OpenWind_Script.xml' # self.writeNewScript(newScriptName) # self.command[1] = newScriptName # ---- Run the workflow super(openwindAC_assembly, self).execute() # ---- Process results # calculate capacity factor # - assumes that all turbines have the same power rating # and that self.wt_layout is correct if (self.wt_layout.wt_list[0].power_rating is None or self.wt_layout.wt_list[0].power_rating == 0.0): self.capacity_factor = 0.0 sys.stderr.write('\n*** WARNING: turbine power_rating not set\n\n') else: # power_rating is in W, but net_aep is in kWh #self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating*0.001 * 8760.0 * self.nTurbs)) # 8766 hrs = 365.25 days to agree with OpenWind self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating*0.001 * 8766.0 * self.nTurbs)) self.total_losses = (self.gross_aep - self.net_aep) / self.gross_aep # ------------------- def updateRptPath(self, rptPathName, newScriptName): ''' Updates the output report path by writing a new script file ('newScriptName') that includes the new report path ('rptPathName'), then setting the value of ow.script_file to 'newScriptName' (with proper folder) Writes a new script file and sets self.ow.script_file New script is identical to current script, except that it writes to 'rptPathName' rptPathName should be a full path name (if possible) ''' if self.ow is None: sys.stderr.write('*** WARNING: calling updateRptPath() before ow (OpenWind component) is set\n') return e = rwScriptXML.parseScript(self.ow.script_file) rp = e.find("ReportPath") if rp is None: sys.stderr.write('Can\'t find report path in "{:}"\n'.format(self.ow.script_file)) return if self.debug: sys.stderr.write('Changing report path from "{:}" to "{:}"\n'.format(rp.get('value'),rptPathName)) rp.set('value',rptPathName) rwScriptXML.wrtScript(e, newScriptName) self.ow.script_file = self.workDir + '/' + newScriptName if self.debug: sys.stderr.write('Wrote new script file "{:}"\n'.format(self.ow.script_file)) # ------------------- def updateAssyRptPath(self, rptPathName, newScriptName): ''' Updates the output report path by writing a new script file ('newScriptName') that includes the new report path ('rptPathName'), then setting the value of self.script_file to 'newScriptName' (with proper folder) Similar to updateRptPath() but modifies self.script file, since self.ow may not be set yeet ''' e = rwScriptXML.parseScript(self.script_file) rp = e.find("ReportPath") if rp is None: sys.stderr.write('Can\'t find report path in "{:}"\n'.format(self.ow.script_file)) return if self.debug: sys.stderr.write('Changing report path from "{:}" to "{:}"\n'.format(rp.get('value'),rptPathName)) rp.set('value',rptPathName) rwScriptXML.wrtScript(e, newScriptName) self.script_file = self.workDir + '/' + newScriptName if self.debug: sys.stderr.write('Wrote new script file "{:}"\n'.format(self.script_file))
def __init__(self, openwind_executable=None, workbook_path=None, turbine_name=None, # not used? script_file=None, academic=True, wt_positions=None, machine_rating=None, start_once=False, debug=False): """ Creates a new GenericAEPModel Assembly object for OpenWind Academic """ foundErrors = False if openwind_executable is None: sys.stderr.write('\n*** ERROR: executable not assigned\n\n') foundErrors = True elif not os.path.isfile(openwind_executable): sys.stderr.write('\n*** ERROR: executable {:} not found\n\n'.format(openwind_executable)) foundErrors = True if workbook_path is None: sys.stderr.write('\n*** ERROR: workbook_path not assigned\n\n') foundErrors = True elif not os.path.isfile(workbook_path): sys.stderr.write('\n*** ERROR: workbook {:} not found\n\n'.format(workbook_path)) foundErrors = True if foundErrors: return None # Set the location where new scripts and turbine files will be written self.workDir = os.getcwd() #self.workDir = os.path.dirname(os.path.realpath(__file__)) # location of this source file self.ow = None # the Openwind Component self.openwind_executable = openwind_executable self.workbook_path = workbook_path self.turbine_name = turbine_name self.script_file = script_file self.academic = academic self.debug = debug self.machine_rating = machine_rating self.start_once = start_once if self.debug: sys.stderr.write('\nIn {:}.__init__()\n'.format(self.__class__)) # Set initial positions of turbines self.init_wt_positions = [] if wt_positions is not None: self.init_wt_positions = wt_positions #self.wt_layout.wt_positions = wt_positions # TODO: hack for now assigning turbine #self.turb = GenericWindTurbinePowerCurveVT() self.turb = ExtendedWindTurbinePowerCurveVT() if self.machine_rating is not None: self.turb.power_rating = self.machine_rating #self.turb.hub_height = self.hub_height #self.turb.power_curve = np.copy(self.power_curve) # self.wt_layout is created with a passthrough in configure(), but doesn't exist yet #for i in xrange(0,self.turbine_number): # self.wt_layout.wt_list.append(self.turb) # call to super().__init__ needs to be at the end # - otherwise, self.* declared later will not exist super(openwindAC_assembly, self).__init__()
def execute(self): """ Set up XML and run OpenWind """ if self.debug: sys.stderr.write("\nIn {0}.execute()...\n".format(self.__class__)) # ---- Set up parameters # initial positions are 'connect'ed to OWcomp object with passthrough of wt_layout # set turbine positions # - from initial positions? # - using another component that sets positions? self.wt_layout.wt_positions = self.init_wt_positions # use initial positions # 2014 05 26 - initialize or modify the turbine type here # - read from file # - modify existing turbine type # - add component that returns a new turbine type # trb == ExtendedWindTurbinePowerCurveVT() nt = len(self.wt_layout.wt_positions) # initialize from file #owtg_file = '../test/NREL5MW.owtg' #sys.stderr.write('\n*** WARNING: initializing turbine from {:} - why??\n\n'.format(owtg_file)) #trb = turbfuncs.owtg_to_wtpc(owtg_file) if self.debug: sys.stderr.write('\n*** WARNING: initializing turbine from ExtendedWindTurbinePowerCurveVT\n\n') trb = ExtendedWindTurbinePowerCurveVT() #trb.power_rating = 1000000.0 # watts! trb.power_rating = self.machine_rating for i in range(nt): self.wt_layout.wt_list[i] = trb # show parameters if self.debug: sys.stderr.write('Initial Turbine Positions\n') for i in range(len(self.wt_layout.wt_positions)): sys.stderr.write('{:3d} {:.1f} {:.1f}\n'.format(i, self.wt_layout.wt_positions[i][0],self.wt_layout.wt_positions[i][1])) s = turbfuncs.wtpc_dump(self.wt_layout.wt_list[0]) sys.stderr.write('\n' + s) #report_path = self.workDir + '/' + 'scrtest1.txt' #workbook_path = self.workbook_path # Prepare for next iteration here... # - write new scripts # - write new turbine files # - etc. # owtg_str = turbfuncs.wtpc_to_owtg(self.turb_props) # write new script for execution # newScriptName = 'OpenWind_Script.xml' # self.writeNewScript(newScriptName) # self.command[1] = newScriptName # ---- Run the workflow super(openwindAC_assembly, self).execute() # ---- Process results # calculate capacity factor # - assumes that all turbines have the same power rating # and that self.wt_layout is correct if (self.wt_layout.wt_list[0].power_rating is None or self.wt_layout.wt_list[0].power_rating == 0.0): self.capacity_factor = 0.0 sys.stderr.write('\n*** WARNING: turbine power_rating not set\n\n') else: # power_rating is in W, but net_aep is in kWh #self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating*0.001 * 8760.0 * self.nTurbs)) # 8766 hrs = 365.25 days to agree with OpenWind self.capacity_factor = ((self.net_aep) / (self.wt_layout.wt_list[0].power_rating*0.001 * 8766.0 * self.nTurbs)) self.total_losses = (self.gross_aep - self.net_aep) / self.gross_aep