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
Beispiel #2
0
def owtg_to_wtpc(owtg_file):
    ''' convert OWTG turbine definition file for openWind to FUSED-Wind ExtendedWindTurbinePowerCurveVT '''
    
    wtpc = ExtendedWindTurbinePowerCurveVT()
    tree = rwTurbXML.parseOWTG(owtg_file)
    
    if tree is None:
        sys.stderr.write('\n*** ERROR: could not parse turbine file "{:}"\n\n"'.format(owtg_file))
        return None
    
    vels, pwrs = rwTurbXML.getPwrTbls(tree)
    wtpc.power_curve = np.array([vels, pwrs]).transpose()
    
    vels, thrusts = rwTurbXML.getThrustTbls(tree)
    wtpc.c_t_curve = np.array([vels, thrusts]).transpose()
    
    vels, rpms = rwTurbXML.getRPMTbls(tree)
    wtpc.rpm_curve = np.array([vels, rpms]).transpose()
    
    name, capKW, hubHt, rtrDiam = rwTurbXML.getTurbParams(tree)
    wtpc.hub_height = hubHt
    wtpc.rotor_diameter = rtrDiam
    wtpc.power_rating = 1000.0 * capKW
    
    return wtpc
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()
    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__()
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 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