Beispiel #1
0
    def __init__(self, turbine_positions, wind_angle=0., wind_speed=8.1):
        n_turbines = turbine_positions.shape[0]
        nrel_prop = pickle.load(open('NREL5MWCPCT.p'))
        floris = floris_assembly_opt_AEP(nTurbines=n_turbines,
                                         nDirections=1,
                                         datasize=nrel_prop.CP.size)
        floris.parameters = FLORISParameters()  # use default FLORIS parameters

        # Define site measurements
        floris.windrose_directions = wind_angle * np.ones(
            1)  # incoming wind direction (deg)
        floris.windrose_speeds = wind_speed  # incoming wind speed (m/s)
        floris.air_density = 1.1716
        floris.initVelocitiesTurbines = np.ones_like(
            floris.windrose_directions) * floris.windrose_speeds

        # Define turbine properties
        floris.curve_wind_speed = nrel_prop.wind_speed
        floris.curve_CP = nrel_prop.CP
        floris.curve_CT = nrel_prop.CT
        floris.axialInduction = 1.0 / 3.0 * np.ones(
            n_turbines)  # used only for initialization
        floris.rotorDiameter = 126.4 * np.ones(n_turbines)
        floris.rotorArea = np.pi * floris.rotorDiameter[0]**2 / 4.0 * np.ones(
            n_turbines)
        floris.hubHeight = 90.0 * np.ones(n_turbines)
        floris.generator_efficiency = 0.944 * np.ones(n_turbines)
        floris.turbineX, floris.turbineY = np.array(
            list(zip(*turbine_positions)))

        self.floris = floris
class floris_adjustCtCp(Component):
    """ Adjust Cp and Ct to yaw if they are not already adjusted """

    parameters = VarTree(FLORISParameters(), iotype='in')

    def __init__(self, nTurbines):

        print 'entering adjustCtCp __init__ - analytic'

        super(floris_adjustCtCp, self).__init__()

        # Explicitly size input arrays
        self.add('Ct_in', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                desc='Thrust coefficient for all turbines'))
        self.add('Cp_in', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                desc='power coefficient for all turbines'))
        self.add('generator_efficiency', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                desc='generator efficiency of all turbines'))
        self.add(
            'yaw',
            Array(np.zeros(nTurbines), iotype='in',
                  desc='yaw of each turbine'))

        # Explicitly size output arrays
        self.add('Ct_out', Array(np.zeros(nTurbines), iotype='out', dtype='float', \
                                 desc='Thrust coefficient for all turbines'))
        self.add('Cp_out', Array(np.zeros(nTurbines), iotype='out', dtype='float', \
                                 desc='power coefficient for all turbines'))

    def execute(self):

        print 'entering adjustCtCP - analytic'

        # print 'CTcorrected is', self.parameters.CTcorrected
        # print 'CPcorrected is', self.parameters.CPcorrected

        Ct = self.Ct_in
        Cp = self.Cp_in
        nTurbines = np.size(Ct)
        yaw = self.yaw * np.pi / 180.
        # CTcorrected = self.parameters.CTcorrected
        # CPcorrected = self.parameters.CPcorrected
        # pP = self.parameters.pP

        # print 'before', Ct, Cp
        # print 'yaw in adjust = ', yaw
        # print 'Ct in adjust = ', Ct

        if self.parameters.FLORISoriginal:

            ke = 0.065
            keCorrCT = 0.0
            # ignore these for now
            # keCorrTI = 0.0
            # keCorrHR = 0.0
            # keCorrHRTI = 0.0
            keCorrArray = 0.0

            kd = 0.15
            # kdCorrDirection = 0.0

            me = np.array([-0.5, 0.22, 1.0])
            MU = np.array([0.5, 1.0, 5.5])
            pP = 1.88
            useWakeAngle = False
            initialWakeDisplacement = 4.5
            bd = -0.01
            useaUbU = True
            aU = 5.0
            bU = 1.66
            adjustInitialWakeDiamToYaw = False

        else:
            # rename inputs and outputs
            ke = self.parameters.ke

            keCorrCT = self.parameters.keCorrCT
            keCorrTI = self.parameters.keCorrTI
            keCorrHR = self.parameters.keCorrHR
            keCorrHRTI = self.parameters.keCorrHRTI
            keCorrArray = self.parameters.keCorrArray

            kd = self.parameters.kd
            kdCorrYawDirection = self.parameters.kdCorrYawDirection

            me = self.parameters.me
            MU = self.parameters.MU

            initialWakeDisplacement = self.parameters.initialWakeDisplacement
            useWakeAngle = self.parameters.useWakeAngle
            initialWakeAngle = self.parameters.initialWakeAngle

            bd = self.parameters.bd

            useaUbU = self.parameters.useaUbU
            aU = self.parameters.aU
            bU = self.parameters.bU

            adjustInitialWakeDiamToYaw = self.parameters.adjustInitialWakeDiamToYaw

            pP = self.parameters.pP

        baselineCT = self.parameters.baselineCT
        baselineTI = self.parameters.baselineTI
        keSaturation = self.parameters.keSaturation

        CTcorrected = self.parameters.CTcorrected
        CPcorrected = self.parameters.CPcorrected
        axialIndProvided = self.parameters.axialIndProvided

        if not CTcorrected:
            # print Ct.size, yaw.size
            self.Ct_out = Ct * np.cos(yaw) * np.cos(yaw)
            dCt_dCt = np.eye(nTurbines) * np.cos(yaw) * np.cos(yaw)
            dCt_dyaw = np.eye(nTurbines) * (-2. * Ct * np.sin(yaw) *
                                            np.cos(yaw)) * np.pi / 180.
            dCt_dCp = np.zeros((nTurbines, nTurbines))
            dCt = np.hstack((dCt_dCt, dCt_dCp, dCt_dyaw))

        else:

            self.Ct_out = Ct
            dCt_dCt = np.eye(nTurbines, nTurbines)
            dCt_dCp = np.zeros((nTurbines, nTurbines))
            dCt_dyaw = np.zeros((nTurbines, nTurbines))
            dCt = np.hstack((dCt_dCt, dCt_dCp, dCt_dyaw))

        if not CPcorrected:

            self.Cp_out = Cp * np.cos(yaw)**pP

            dCp_dCp = np.eye(nTurbines, nTurbines) * np.cos(yaw)**pP
            dCp_dyaw = np.eye(
                nTurbines, nTurbines) * (-Cp * pP * np.sin(yaw) * np.cos(yaw)**
                                         (pP - 1.0)) * np.pi / 180.
            dCp_dCt = np.zeros((nTurbines, nTurbines))
            dCp = np.hstack((dCp_dCt, dCp_dCp, dCp_dyaw))

        else:

            self.Cp_out = Cp
            dCp_dCp = np.eye(nTurbines, nTurbines)
            dCp_dCt = np.zeros((nTurbines, nTurbines))
            dCp_dyaw = np.zeros((nTurbines, nTurbines))
            dCp = np.hstack((dCp_dCt, dCp_dCp, dCp_dyaw))

        self.J = np.vstack((dCt, dCp))

    def list_deriv_vars(self):
        return ('Ct_in', 'Cp_in', 'yaw'), ('Ct_out', 'Cp_out')

    def provideJ(self):
        return self.J
class dist_const(Component):

    parameters = VarTree(FLORISParameters(), iotype='in')

    def __init__(self, nTurbines):

        #print 'entering dist_const __init__'

        super(dist_const, self).__init__()

        # Explicitly size input arrays
        self.add('turbineX', Array(np.zeros(nTurbines), iotype='in', \
                                    desc='x coordinates of turbines in wind dir. ref. frame'))
        self.add('turbineY', Array(np.zeros(nTurbines), iotype='in', \
                                    desc='y coordinates of turbines in wind dir. ref. frame'))

        # Explicitly size output array
        self.add('separation', Array(np.zeros(int((nTurbines-1.)*nTurbines/2.)), iotype='out', dtype='float', \
                                        desc='spacing of all turbines in the wind farm'))

    def execute(self):

        #print 'in dist const'

        turbineX = self.turbineX
        turbineY = self.turbineY
        nTurbines = turbineX.size
        separation = np.zeros(int((nTurbines - 1.) * nTurbines / 2.))

        k = 0
        for i in range(0, nTurbines):
            for j in range(i + 1, nTurbines):
                separation[k] = np.sqrt((turbineX[j] - turbineX[i])**2 +
                                        (turbineY[j] - turbineY[i])**2)
                k += 1
        self.separation = separation

    def list_deriv_vars(self):
        return ('turbineX', 'turbineY'), ('separation', )

    def provideJ(self):

        #print 'entering dist const - provideJ'
        tictot = time.time()
        turbineX = self.turbineX
        turbineY = self.turbineY
        nTurbines = turbineX.size
        J = np.zeros(((nTurbines - 1.) * nTurbines / 2., 2 * nTurbines))

        k = 0
        for i in range(0, nTurbines):
            for j in range(i + 1, nTurbines):
                J[k, j] = (turbineX[j] - turbineX[i]) * (
                    (turbineX[j] - turbineX[i])**2 +
                    (turbineY[j] - turbineY[i])**2)**(-0.5)
                J[k, i] = (turbineX[i] - turbineX[j]) * (
                    (turbineX[j] - turbineX[i])**2 +
                    (turbineY[j] - turbineY[i])**2)**(-0.5)
                J[k, j + nTurbines] = (turbineY[j] - turbineY[i]) * (
                    (turbineX[j] - turbineX[i])**2 +
                    (turbineY[j] - turbineY[i])**2)**(-0.5)
                J[k, i + nTurbines] = (turbineY[i] - turbineY[j]) * (
                    (turbineX[j] - turbineX[i])**2 +
                    (turbineY[j] - turbineY[i])**2)**(-0.5)
                k += 1
        toctot = time.time()
        #print 'done %s' % (toctot-tictot)
        return J
class floris_windframe(Component):
    """ Calculates the locations of each turbine in the wind direction reference frame """

    # original variables
    parameters = VarTree(FLORISParameters(), iotype='in')
    verbose = Bool(False,
                   iotype='in',
                   desc='verbosity of FLORIS, False is no output')

    # flow property variables
    wind_speed = Float(iotype='in',
                       units='m/s',
                       desc='free stream wind velocity')
    wind_direction = Float(
        iotype='in',
        units='deg',
        desc='wind direction using direction to, in deg. ccw from east')

    def __init__(self, nTurbines, resolution):

        print 'entering windframe __init__ - analytic'

        super(floris_windframe, self).__init__()

        # Explicitly size input arrays
        self.add('turbineX', Array(np.zeros(nTurbines), iotype='in', \
                                   desc='x positions of turbines in original ref. frame'))
        self.add('turbineY', Array(np.zeros(nTurbines), iotype='in', \
                                   desc='y positions of turbines in original ref. frame'))

        # variables for verbosity
        self.add('Ct', Array(np.zeros(nTurbines), iotype='in'))
        self.add('Cp', Array(np.zeros(nTurbines), iotype='in', \
                             desc='power coefficient for all turbines'))
        self.add('axialInduction', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                         desc='axial induction of all turbines'))
        self.add('yaw', Array(np.zeros(nTurbines), iotype='in', \
                              desc='yaw of each turbine'))

        # variables for testing wind speed at various locations
        self.add('ws_position', Array(np.zeros(resolution*resolution), iotype='in', units='m', \
                                      desc='position of desired measurements in original ref. frame'))

        # Explicitly size output arrays
        self.add('wsw_position', Array(np.zeros(resolution*resolution), iotype='out', units='m', \
                                       desc='position of desired measurements in wind ref. frame'))

        # for testing purposes only
        self.add('turbineXw', Array(np.zeros(nTurbines), iotype='out', units='m', \
                                    desc='x coordinates of turbines in wind dir. ref. frame'))
        self.add('turbineYw', Array(np.zeros(nTurbines), iotype='out', units='m', \
                                    desc='y coordinates of turbines in wind dir. ref. frame'))

    def execute(self):

        print 'entering windframe - analytic'

        if self.parameters.FLORISoriginal:

            ke = 0.065
            keCorrCT = 0.0
            # ignore these for now
            # keCorrTI = 0.0
            # keCorrHR = 0.0
            # keCorrHRTI = 0.0
            keCorrArray = 0.0

            kd = 0.15
            # kdCorrYawDirection = 0.0  # ignored for now

            me = np.array([-0.5, 0.22, 1.0])
            MU = np.array([0.5, 1.0, 5.5])
            pP = 1.88
            useWakeAngle = False
            initialWakeDisplacement = 4.5
            bd = -0.01
            useaUbU = True
            aU = 5.0
            bU = 1.66
            adjustInitialWakeDiamToYaw = False

        else:
            # rename inputs and outputs
            ke = self.parameters.ke

            keCorrCT = self.parameters.keCorrCT
            keCorrTI = self.parameters.keCorrTI
            keCorrHR = self.parameters.keCorrHR
            keCorrHRTI = self.parameters.keCorrHRTI
            keCorrArray = self.parameters.keCorrArray

            kd = self.parameters.kd
            kdCorrYawDirection = self.parameters.kdCorrYawDirection

            me = self.parameters.me
            MU = self.parameters.MU

            initialWakeDisplacement = self.parameters.initialWakeDisplacement
            useWakeAngle = self.parameters.useWakeAngle
            initialWakeAngle = self.parameters.initialWakeAngle

            bd = self.parameters.bd

            useaUbU = self.parameters.useaUbU
            aU = self.parameters.aU
            bU = self.parameters.bU

            adjustInitialWakeDiamToYaw = self.parameters.adjustInitialWakeDiamToYaw

            pP = self.parameters.pP

        baselineCT = self.parameters.baselineCT
        baselineTI = self.parameters.baselineTI
        keSaturation = self.parameters.keSaturation

        CTcorrected = self.parameters.CTcorrected
        CPcorrected = self.parameters.CPcorrected
        axialIndProvided = self.parameters.axialIndProvided

        Vinf = self.wind_speed
        windDirection = self.wind_direction * np.pi / 180.0

        #variables to satisfy verbosity
        axialInd = self.axialInduction
        Cp = self.Cp
        Ct = self.Ct
        yaw = self.yaw * np.pi / 180

        if self.verbose:
            np.set_printoptions(formatter={'float': '{: 0.3f}'.format})
            print "wind direction %s deg" % [windDirection * 180.0 / np.pi]
            print "free-stream wind speed %s" % Vinf
            print "axial induction turbines %s" % axialInd
            print "C_P turbines %s" % Cp
            print "C_T turbines %s" % Ct
            print "yaw turbines %s" % yaw

        # get turbine positions and velocity sampling positions
        # position = self.position
        # turbineX = position[:, 0]
        # turbineY = position[:, 1]
        turbineX = self.turbineX
        turbineY = self.turbineY
        # print turbineX, turbineY

        if self.ws_position.any():
            velX = self.ws_position[:, 0]
            velY = self.ws_position[:, 1]
        else:
            velX = np.zeros([0, 0])
            velY = np.zeros([0, 0])

        # convert to downwind-crosswind coordinates
        rotationMatrix = np.array([
            (np.cos(-windDirection), -np.sin(-windDirection)),
            (np.sin(-windDirection), np.cos(-windDirection))
        ])
        # print 'rotation matrix = ', rotationMatrix
        turbineLocations = np.dot(rotationMatrix,
                                  np.array([turbineX, turbineY]))
        # print turbineLocations
        self.turbineXw = np.zeros(turbineX.size)
        self.turbineYw = np.zeros(turbineX.size)
        # print self.turbineXw
        self.turbineXw = turbineLocations[0]
        self.turbineYw = turbineLocations[1]
        #print 'windframe.turbineX = %s' %self.turbineX
        if velX.size > 0:
            locations = np.dot(rotationMatrix, np.array([velX, velY]))
            velX = locations[0]
            velY = locations[1]

        self.wsw_position = np.array([velX, velY])
        #print 'wsw_position in windframe is:', self.wsw_position
        #print 'ws_position in windframe is:', self.ws_position

        # print self.turbineXw

    def list_deriv_vars(self):
        """specifies the inputs and outputs where derivatives are defined"""

        return ('turbineX', 'turbineY'), ('turbineXw', 'turbineYw')

    def provideJ(self):

        #print 'entering windframe - provideJ'

        n = np.size(self.turbineX)

        windDirection = self.wind_direction * np.pi / 180

        dturbineXw_dturbineX = np.zeros([n, n])
        dturbineXw_dturbineY = np.zeros([n, n])
        dturbineYw_dturbineX = np.zeros([n, n])
        dturbineYw_dturbineY = np.zeros([n, n])

        for i in range(0, n):
            dturbineXw_dturbineX[i, i] = np.cos(-windDirection)
            dturbineXw_dturbineY[i, i] = -np.sin(-windDirection)
            dturbineYw_dturbineX[i, i] = np.sin(-windDirection)
            dturbineYw_dturbineY[i, i] = np.cos(-windDirection)

        JturbineXw = np.concatenate(
            (dturbineXw_dturbineX, dturbineXw_dturbineY), 1)
        JturbineYw = np.concatenate(
            (dturbineYw_dturbineX, dturbineYw_dturbineY), 1)
        J = np.concatenate((JturbineXw, JturbineYw), 0)

        return J
Beispiel #5
0
generator_efficiency = 0.944
hub_height = 90.0
NREL5MWCPCT = pickle.load(open('NREL5MWCPCT.p'))
datasize = NREL5MWCPCT.CP.size
turbineXinit = np.array([1118.1, 1881.9])
turbineYinit = np.array([1279.5, 1720.5])

myFloris = floris_assembly_opt_AEP(nTurbines=2,
                                   nDirections=1,
                                   optimize_yaw=False,
                                   optimize_position=False,
                                   datasize=datasize,
                                   nSamples=resolution * resolution)

# use default FLORIS parameters
myFloris.parameters = FLORISParameters()

# load turbine properties into FLORIS
myFloris.curve_wind_speed = NREL5MWCPCT.wind_speed
myFloris.curve_CP = NREL5MWCPCT.CP
myFloris.curve_CT = NREL5MWCPCT.CT
myFloris.axialInduction = np.array([axialInduction, axialInduction])
myFloris.rotorDiameter = np.array([rotorDiameter, rotorDiameter])
myFloris.rotorArea = np.array([rotorArea, rotorArea])
myFloris.hubHeight = np.array([hub_height, hub_height])
myFloris.generator_efficiency = np.array(
    [generator_efficiency, generator_efficiency])
myFloris.turbineX = turbineXinit
myFloris.turbineY = turbineYinit

# Define site measurements
Beispiel #6
0
class floris_assembly_opt_AEP(Assembly):
    """ Defines the connections between each Component used in the FLORIS model """

    # general input variables
    parameters = VarTree(FLORISParameters(), iotype='in')
    verbose = Bool(False,
                   iotype='in',
                   desc='verbosity of FLORIS, False is no output')
    # Flow property variables
    air_density = Float(iotype='in',
                        units='kg/(m*m*m)',
                        desc='air density in free stream')

    # output
    AEP = Float(iotype='out', units='kW', desc='total windfarm AEP')

    def __init__(self,
                 nTurbines,
                 nDirections,
                 optimize_position=False,
                 nSamples=0,
                 optimize_yaw=False,
                 datasize=0,
                 nSpeeds=False,
                 maxiter=100):

        super(floris_assembly_opt_AEP, self).__init__()

        if nSpeeds == False:
            nSpeeds = nDirections

        self.nTurbines = nTurbines
        self.nSamples = nSamples
        self.nDirections = nDirections
        self.optimize_yaw = optimize_yaw
        self.optimize_position = optimize_position
        self.datasize = datasize
        self.nSpeeds = nSpeeds
        self.maxiter = maxiter

        # wt_layout input variables
        self.add(
            'rotorDiameter',
            Array(np.zeros(nTurbines),
                  dtype='float',
                  iotype='in',
                  units='m',
                  desc='rotor diameters of all turbine'))
        self.add(
            'axialInduction',
            Array(np.zeros(nTurbines),
                  iotype='in',
                  dtype='float',
                  desc='axial induction of all turbines'))
        self.add('hubHeight', Array(np.zeros(nTurbines), dtype='float', iotype='in', units='m', \
                desc='hub heights of all turbines'))

        # turbine properties for ccblade and pre-calculated controller
        self.add(
            'curve_CP',
            Array(np.zeros(datasize), iotype='in', desc='pre-calculated CPCT'))
        self.add(
            'curve_CT',
            Array(np.zeros(datasize), iotype='in', desc='pre-calculated CPCT'))
        self.add(
            'curve_wind_speed',
            Array(np.zeros(datasize), iotype='in', desc='pre-calculated CPCT'))
        self.add('initVelocitiesTurbines',
                 Array(np.zeros(nTurbines), iotype='in', units='m/s'))
        self.add(
            'generator_efficiency',
            Array(np.zeros(nTurbines),
                  iotype='in',
                  dtype='float',
                  desc='generator efficiency of all turbines'))
        self.add(
            'turbineX',
            Array(np.zeros(nTurbines),
                  iotype='in',
                  dtype='float',
                  desc='x positions of turbines in original ref. frame'))
        self.add(
            'turbineY',
            Array(np.zeros(nTurbines),
                  iotype='in',
                  dtype='float',
                  desc='y positions of turbines in original ref. frame'))
        if optimize_yaw:
            for direction in range(0, nDirections):
                self.add('yaw_%d' % direction, Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                         desc='yaw of each turbine for each direction'))
        else:
            self.add('yaw', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                              desc='yaw of each turbine'))

        # windrose input variables
        self.add(
            'windrose_directions',
            Array(np.zeros(nDirections),
                  dtype='float',
                  iotype='in',
                  desc='windrose directions in degrees ccw from east'))
        self.add(
            'windrose_frequencies',
            Array(
                np.ones(nDirections),
                dtype='float',
                iotype='in',
                desc='windrose frequencies corresponding to windrose_directions'
            ))
        if nSpeeds == 1:
            self.add(
                'windrose_speeds',
                Float(
                    iotype='in',
                    units='m/s',
                    desc=
                    'wind speeds for each direction given in windrose_directions'
                ))
        else:
            self.add(
                'windrose_speeds',
                Array(
                    np.zeros(nDirections),
                    dtype='float',
                    iotype='in',
                    units='m/s',
                    desc=
                    'wind speeds for each direction given in windrose_directions'
                ))

        # Explicitly size output arrays

        # variables added to test individual components
        self.add(
            'turbineXw',
            Array(
                np.zeros(nTurbines),
                iotype='out',
                units='m',
                desc=
                'X positions of turbines in the wind direction reference frame'
            ))
        self.add(
            'turbineYw',
            Array(
                np.zeros(nTurbines),
                iotype='out',
                units='m',
                desc=
                'Y positions of turbines in the wind direction reference frame'
            ))
        self.add(
            'wakeCentersYT',
            Array(np.zeros(nTurbines),
                  dtype='float',
                  iotype='out',
                  units='m',
                  desc='centers of the wakes at each turbine'))
        self.add(
            'wakeDiametersT',
            Array(np.zeros(nTurbines),
                  dtype='float',
                  iotype='out',
                  units='m',
                  desc='diameters of each of the wake zones for each of the \
                                         wakes at each turbine'))
        self.add(
            'wakeOverlapTRel',
            Array(np.zeros(nTurbines),
                  dtype='float',
                  iotype='out',
                  units='m',
                  desc='ratio of overlap area of each zone to rotor area'))

        # standard output
        self.add(
            'velocitiesTurbines_directions',
            Array(np.zeros([nDirections, nTurbines]),
                  iotype='out',
                  units='m/s',
                  dtype='float',
                  desc='effective windspeed at each turbine \
                                                        in each direction ccw from east using direction to'
                  ))
        self.add(
            'wt_power_directions',
            Array(np.zeros([nDirections, nTurbines]),
                  iotype='out',
                  units='kW',
                  dtype='float',
                  desc='power of each turbine in each direction ccw from \
                                              east using direction to'))
        self.add(
            'power_directions',
            Array(np.zeros(nDirections),
                  iotype='out',
                  units='kW',
                  desc='total windfarm power \
                                           in each direction ccw from east using direction to'
                  ))

        if nSamples > 0:
            # flow samples
            self.add(
                'ws_positionX',
                Array(np.zeros(nSamples),
                      iotype='in',
                      units='m',
                      desc='X positions of sampling points'))
            self.add(
                'ws_positionY',
                Array(np.zeros(nSamples),
                      iotype='in',
                      units='m',
                      desc='Y position of sampling points'))
            self.add(
                'ws_positionZ',
                Array(np.zeros(nSamples),
                      iotype='in',
                      units='m',
                      desc='Z position of sampling points'))
            for direction in range(0, nDirections):
                self.add(
                    'ws_array_%d' % direction,
                    Array(np.zeros(nSamples),
                          iotype='out',
                          units='m/s',
                          desc='predicted wind speed at sampling points'))

    def configure(self):

        # rename options
        nTurbines = self.nTurbines
        nDirections = self.nDirections
        optimize_position = self.optimize_position
        optimize_yaw = self.optimize_yaw
        datasize = self.datasize
        nSamples = self.nSamples
        nSpeeds = self.nSpeeds
        maxiter = self.maxiter

        # add driver so the workflow is not overwritten later
        if optimize_position or optimize_yaw:
            self.add('driver', SLSQPdriver())

        # add AEP component first so it can be connected to
        F6 = self.add('floris_AEP', AEP(nDirections=nDirections))
        F6.missing_deriv_policy = 'assume_zero'
        self.connect('windrose_frequencies', 'floris_AEP.windrose_frequencies')
        self.connect('floris_AEP.AEP', 'AEP')
        self.connect('floris_AEP.power_directions_out', 'power_directions')

        # set up constraints
        self.add('floris_dist_const', dist_const(nTurbines=nTurbines))
        self.connect('turbineX', 'floris_dist_const.turbineX')
        self.connect('turbineY', 'floris_dist_const.turbineY')

        if nSamples > 0:
            samplingNonSampling = ['', 'Sampling_']
        else:
            samplingNonSampling = ['']

        for i in range(0, nDirections):

            # add fixed point iterator
            self.add('FPIdriver_%d' % i, FixedPointIterator())
            self.add(
                'rotor_CPCT_%d' % i,
                CPCT_Interpolate(nTurbines=self.nTurbines,
                                 datasize=self.datasize))
            CP = 'rotor_CPCT_%d.CP' % i
            CT = 'rotor_CPCT_%d.CT' % i
            CPCT = 'rotor_CPCT_%d' % i

            # add components of floris to assembly
            F2 = self.add('floris_windframe_%d' % i,
                          floris_windframe(nTurbines=nTurbines))
            F2.missing_deriv_policy = 'assume_zero'
            self.add('floris_wcent_wdiam_%d' % i,
                     floris_wcent_wdiam(nTurbines=nTurbines))
            F4 = self.add('floris_overlap_%d' % i,
                          floris_overlap(nTurbines=nTurbines))
            F4.missing_deriv_policy = 'assume_zero'
            self.add('floris_power_%d' % i, floris_power(nTurbines=nTurbines))

            # add visualization components of floris to assembly
            if nSamples > 0:
                self.add(
                    'Sampling_floris_windframe_%d' % i,
                    floris_windframe(nTurbines=nTurbines, nSamples=nSamples))
                self.add(
                    'Sampling_floris_wcent_wdiam_%d' % i,
                    floris_wcent_wdiam(nTurbines=nTurbines, nSamples=nSamples))
                self.add('Sampling_floris_overlap_%d' % i,
                         floris_overlap(nTurbines=nTurbines))
                self.add('Sampling_floris_power_%d' % i,
                         floris_power(nTurbines=nTurbines, nSamples=nSamples))

            # connect inputs to components
            self.connect('curve_CP', 'rotor_CPCT_%d.windSpeedToCPCT.CP' % i)
            self.connect('curve_CT', 'rotor_CPCT_%d.windSpeedToCPCT.CT' % i)
            self.connect('curve_wind_speed',
                         'rotor_CPCT_%d.windSpeedToCPCT.wind_speed' % i)
            self.connect('parameters.pP', 'rotor_CPCT_%d.pP' % i)

            for ssn in samplingNonSampling:
                self.connect('parameters', [
                    '%sfloris_wcent_wdiam_%d.parameters' % (ssn, i),
                    '%sfloris_power_%d.parameters' % (ssn, i)
                ])
                self.connect('verbose', [
                    '%sfloris_windframe_%d.verbose' % (ssn, i),
                    '%sfloris_wcent_wdiam_%d.verbose' % (ssn, i),
                    '%sfloris_power_%d.verbose' % (ssn, i)
                ])
                self.connect('turbineX',
                             '%sfloris_windframe_%d.turbineX' % (ssn, i))
                self.connect('turbineY',
                             '%sfloris_windframe_%d.turbineY' % (ssn, i))
                self.connect('rotorDiameter', [
                    '%sfloris_wcent_wdiam_%d.rotorDiameter' % (ssn, i),
                    '%sfloris_overlap_%d.rotorDiameter' % (ssn, i),
                    '%sfloris_power_%d.rotorDiameter' % (ssn, i)
                ])
                self.connect('axialInduction',
                             '%sfloris_power_%d.axialInduction' % (ssn, i))
                self.connect(
                    'generator_efficiency',
                    '%sfloris_power_%d.generator_efficiency' % (ssn, i))

            if nSamples > 0:
                # connections needed for visualization
                self.connect('ws_positionX',
                             'Sampling_floris_windframe_%d.ws_positionX' % i)
                self.connect('ws_positionY',
                             'Sampling_floris_windframe_%d.ws_positionY' % i)
                self.connect('ws_positionZ',
                             'Sampling_floris_windframe_%d.ws_positionZ' % i)
                self.connect('hubHeight',
                             'Sampling_floris_wcent_wdiam_%d.hubHeight' % i)

            if optimize_yaw:
                yawToConnect = 'yaw_%d' % i
            else:
                yawToConnect = 'yaw'

            self.connect(yawToConnect, '%s.yaw' % CPCT)
            for ssn in samplingNonSampling:
                self.connect(yawToConnect, [
                    '%sfloris_wcent_wdiam_%d.yaw' % (ssn, i),
                    '%sfloris_power_%d.yaw' % (ssn, i)
                ])

            for ssn in samplingNonSampling:
                self.connect('air_density',
                             '%sfloris_power_%d.air_density' % (ssn, i))
                self.connect('windrose_directions[%d]' % i,
                             '%sfloris_windframe_%d.wind_direction' % (ssn, i))

            # for satisfying the verbosity in windframe
            for ssn in samplingNonSampling:
                self.connect(CT, '%sfloris_windframe_%d.Ct' % (ssn, i))
                self.connect(CP, '%sfloris_windframe_%d.Cp' % (ssn, i))
                self.connect(yawToConnect,
                             '%sfloris_windframe_%d.yaw' % (ssn, i))
                self.connect('axialInduction',
                             '%sfloris_windframe_%d.axialInduction' % (ssn, i))

            # ############### Connections between components ##################
            # connections from CtCp calculation to other components
            for ssn in samplingNonSampling:
                self.connect(CT, [
                    '%sfloris_wcent_wdiam_%d.Ct' % (ssn, i),
                    '%sfloris_power_%d.Ct' % (ssn, i)
                ])
                self.connect(CP, '%sfloris_power_%d.Cp' % (ssn, i))

                # connections from floris_windframe to floris_wcent_wdiam
                self.connect('%sfloris_windframe_%d.turbineXw' % (ssn, i),
                             '%sfloris_wcent_wdiam_%d.turbineXw' % (ssn, i))
                self.connect('%sfloris_windframe_%d.turbineYw' % (ssn, i),
                             '%sfloris_wcent_wdiam_%d.turbineYw' % (ssn, i))

                # connections from floris_wcent_wdiam to floris_overlap
                self.connect(
                    '%sfloris_wcent_wdiam_%d.wakeCentersYT' % (ssn, i),
                    '%sfloris_overlap_%d.wakeCentersYT' % (ssn, i))
                self.connect(
                    '%sfloris_wcent_wdiam_%d.wakeDiametersT' % (ssn, i),
                    '%sfloris_overlap_%d.wakeDiametersT' % (ssn, i))

                # connections from floris_windframe to floris_overlap
                self.connect('%sfloris_windframe_%d.turbineXw' % (ssn, i),
                             '%sfloris_overlap_%d.turbineXw' % (ssn, i))
                self.connect('%sfloris_windframe_%d.turbineYw' % (ssn, i),
                             '%sfloris_overlap_%d.turbineYw' % (ssn, i))

                # connections from floris_windframe to floris_power
                self.connect('%sfloris_windframe_%d.turbineXw' % (ssn, i),
                             '%sfloris_power_%d.turbineXw' % (ssn, i))

                # connections from floris_overlap to floris_power
                self.connect('%sfloris_overlap_%d.wakeOverlapTRel' % (ssn, i),
                             '%sfloris_power_%d.wakeOverlapTRel' % (ssn, i))

            # additional connections needed for visualization
            if nSamples > 0:
                self.connect('Sampling_floris_windframe_%d.wsw_position' % i, [
                    'Sampling_floris_wcent_wdiam_%d.wsw_position' % i,
                    'Sampling_floris_power_%d.wsw_position' % i
                ])
                self.connect('Sampling_floris_wcent_wdiam_%d.wakeCentersY' % i,
                             'Sampling_floris_power_%d.wakeCentersY' % i)
                self.connect('Sampling_floris_wcent_wdiam_%d.wakeCentersZ' % i,
                             'Sampling_floris_power_%d.wakeCentersZ' % i)
                self.connect(
                    'Sampling_floris_wcent_wdiam_%d.wakeDiameters' % i,
                    'Sampling_floris_power_%d.wakeDiameters' % i)
                self.connect('Sampling_floris_power_%d.ws_array' % i,
                             'ws_array_%d' % i)

            # connections from floris_power to floris_AEP
            self.connect('floris_power_%d.power' % i,
                         'floris_AEP.power_directions[%d]' % i)
            # #################################################################

            # add to workflow
            exec(
                "self.FPIdriver_%d.workflow.add(['rotor_CPCT_%d', 'floris_windframe_%d', \
                 'floris_wcent_wdiam_%d', 'floris_overlap_%d', 'floris_power_%d'])"
                % (i, i, i, i, i, i))
            exec(
                "self.FPIdriver_%d.add_parameter('rotor_CPCT_%d.wind_speed_hub', low=0., high=100.)"
                % (i, i))
            exec(
                "self.FPIdriver_%d.add_constraint('rotor_CPCT_%d.wind_speed_hub = \
                  floris_power_%d.velocitiesTurbines')" % (i, i, i))
            self.driver.workflow.add('FPIdriver_%d' % i)
            if nSamples > 0:
                self.driver.workflow.add([
                    'Sampling_floris_windframe_%d' % i,
                    'Sampling_floris_wcent_wdiam_%d' % i,
                    'Sampling_floris_overlap_%d' % i,
                    'Sampling_floris_power_%d' % i
                ])

        if nSpeeds > 1:
            for i in range(0, nSpeeds):
                for ssn in samplingNonSampling:
                    self.connect('windrose_speeds[%d]' % i,
                                 '%sfloris_power_%d.wind_speed' % (ssn, i))
                    self.connect('windrose_speeds[%d]' % i,
                                 '%sfloris_windframe_%d.wind_speed' % (ssn, i))
        else:
            for i in range(0, nDirections):
                for ssn in samplingNonSampling:
                    self.connect('windrose_speeds',
                                 '%sfloris_power_%d.wind_speed' % (ssn, i))
                    self.connect('windrose_speeds',
                                 '%sfloris_windframe_%d.wind_speed' % (ssn, i))

        # add AEP calculations to workflow
        self.driver.workflow.add(['floris_AEP', 'floris_dist_const'])
        if optimize_position or optimize_yaw:
            # set up driver
            self.driver.iprint = 3
            self.driver.accuracy = 1.0e-12
            self.driver.maxiter = maxiter
            self.driver.add_objective('-floris_AEP.AEP')
            if optimize_position:
                self.driver.add_parameter('turbineX',
                                          low=7 * 126.4,
                                          high=np.sqrt(self.nTurbines) * 7 *
                                          126.4)
                self.driver.add_parameter('turbineY',
                                          low=7 * 126.4,
                                          high=np.sqrt(self.nTurbines) * 7 *
                                          126.4)
                self.driver.add_constraint(
                    'floris_dist_const.separation > 2*rotorDiameter[0]')
            if optimize_yaw:
                for direction in range(0, self.nDirections):
                    self.driver.add_parameter('yaw_%d' % direction,
                                              low=-30.,
                                              high=30.,
                                              scaler=1.)
class floris_windframe(Component):
    """ Calculates the locations of each turbine in the wind direction reference frame """

    # original variables
    parameters = VarTree(FLORISParameters(), iotype='in')
    verbose = Bool(False,
                   iotype='in',
                   desc='verbosity of FLORIS, False is no output')
    # position = Array(iotype='in', units='m', desc='position of turbines in original ref. frame')

    wind_speed = Float(iotype='in',
                       units='m/s',
                       desc='free stream wind velocity')
    wind_direction = Float(iotype='in',
                           units='deg',
                           desc='overall wind direction for wind farm')

    def __init__(self, nTurbines, nSamples=0):

        super(floris_windframe, self).__init__()

        # Explicitly size input arrays
        self.add('turbineX', Array(np.zeros(nTurbines), iotype='in', \
                                   desc='x positions of turbines in original ref. frame'))
        self.add('turbineY', Array(np.zeros(nTurbines), iotype='in', \
                                   desc='y positions of turbines in original ref. frame'))

        # variables for verbosity
        self.add('Ct', Array(np.zeros(nTurbines), iotype='in'))
        self.add('Cp', Array(np.zeros(nTurbines), iotype='in', \
                             desc='power coefficient for all turbines'))
        self.add('axialInduction', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                         desc='axial induction of all turbines'))
        self.add('yaw', Array(np.zeros(nTurbines), iotype='in', \
                              desc='yaw of each turbine'))

        # for testing purposes only
        self.add('turbineXw', Array(np.zeros(nTurbines), iotype='out', units='m', \
                                    desc='x coordinates of turbines in wind dir. ref. frame'))
        self.add('turbineYw', Array(np.zeros(nTurbines), iotype='out', units='m', \
                                    desc='y coordinates of turbines in wind dir. ref. frame'))

        # variables for testing wind speed at various locations
        self.add(
            'ws_positionX',
            Array(
                np.zeros([nSamples]),
                iotype='in',
                units='m',
                desc='X position of desired measurements in original ref. frame'
            ))
        self.add(
            'ws_positionY',
            Array(
                np.zeros([nSamples]),
                iotype='in',
                units='m',
                desc='Y position of desired measurements in original ref. frame'
            ))
        self.add(
            'ws_positionZ',
            Array(
                np.zeros([nSamples]),
                iotype='in',
                units='m',
                desc='Z position of desired measurements in original ref. frame'
            ))

        # Explicitly size output arrays
        self.add(
            'wsw_position',
            Array(np.zeros([3, nSamples]),
                  iotype='out',
                  units='m',
                  desc='position of desired measurements in wind ref. frame'))

    def execute(self):

        Vinf = self.wind_speed
        windDirection = self.wind_direction * np.pi / 180.0

        #variables to satisfy verbosity
        axialInd = self.axialInduction
        Cp = self.Cp
        Ct = self.Ct
        CTcorrected = self.parameters.CTcorrected
        # yaw = self.yaw*np.pi/180

        # get rotor coefficients, and apply corrections if necesary
        # Cp = np.hstack(self.wt_layout.wt_array(attr='CP'))
        # if CTcorrected == False:
        #     Ct = Ct * (np.cos(yaw)**2)

        if self.verbose:
            np.set_printoptions(formatter={'float': '{: 0.3f}'.format})
            print "wind direction %s deg" % [windDirection * 180.0 / np.pi]
            print "free-stream wind speed %s" % Vinf
            print "axial induction turbines %s" % axialInd
            print "C_P turbines %s" % Cp
            print "C_T turbines %s" % Ct
            # print "yaw turbines %s" % yaw

        # get turbine positions and velocity sampling positions
        turbineX = self.turbineX
        turbineY = self.turbineY

        if len(self.ws_positionX) > 0:
            velX = self.ws_positionX
            velY = self.ws_positionY
            velZ = self.ws_positionZ
        else:
            velX = np.zeros([0, 0])
            velY = np.zeros([0, 0])
            velZ = np.zeros([0, 0])

        # convert to downwind-crosswind coordinates
        rotationMatrix = np.array([
            (np.cos(-windDirection), -np.sin(-windDirection)),
            (np.sin(-windDirection), np.cos(-windDirection))
        ])
        turbineLocations = np.dot(rotationMatrix,
                                  np.array([turbineX, turbineY]))
        # print turbineLocations
        self.turbineXw = np.zeros(turbineX.size)
        self.turbineYw = np.zeros(turbineX.size)
        self.turbineXw = turbineLocations[0]
        self.turbineYw = turbineLocations[1]

        if velX.size > 0:
            locations = np.dot(rotationMatrix, np.array([velX, velY]))
            velX = locations[0]
            velY = locations[1]

        self.wsw_position = np.array([velX, velY, velZ])
class floris_power(Component):
    """ Calculates the turbine power and effective wind speed for each turbine """

    # original variables in Pieter's OpenMDAO stand-alone version of FLORIS
    parameters = VarTree(FLORISParameters(), iotype='in')
    verbose = Bool(False,
                   iotype='in',
                   desc='verbosity of FLORIS, False is no output')

    # Flow property variables
    wind_speed = Float(iotype='in',
                       units='m/s',
                       desc='free stream wind velocity')
    air_density = Float(iotype='in',
                        units='kg/(m*m*m)',
                        desc='air density in free stream')

    # output variables added so I don't have to use WISDEM while developing gradients
    power = Float(iotype='out',
                  units='kW',
                  desc='total power output of the wind farm')

    def __init__(self, nTurbines, nSamples=0):
        super(floris_power, self).__init__()

        # Explicitly size input arrays
        # input variables added so I don't have to use WISDEM while developing gradients
        self.add('rotorDiameter', Array(np.zeros(nTurbines), dtype='float', iotype='in', units='m', \
                                        desc='rotor diameters of all turbines'))
        self.add('axialInduction', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                         desc='axial induction of all turbines'))
        self.add('Ct', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                             desc='Thrust coefficient for all turbines'))
        self.add('Cp', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                             desc='power coefficient for all turbines'))
        self.add('generator_efficiency', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                                               desc='generator efficiency of all turbines'))
        self.add('turbineXw', Array(np.zeros(nTurbines), iotype='in', dtype='float', units='m', \
                                    desc='X positions of turbines in the wind direction reference frame'))
        self.add('wakeCentersYT',  Array(np.zeros([nTurbines, nTurbines]), iotype='in', units='m', \
                                         desc='centers of the wakes at each turbine'))
        self.add('wakeDiametersT', Array(np.zeros([nTurbines, nTurbines, 3]), iotype='in', units='m', \
                                         desc='diameters of each of the wake zones for each of the wakes \
                                         at each turbine'                                                         ))
        self.add('wakeOverlapTRel', Array(np.zeros([nTurbines, nTurbines, 3]), iotype='in', units='m', \
                                          desc='ratios of wake overlap area per zone to rotor area'))
        self.add('yaw', Array(np.zeros([nTurbines]), iotype='in'))
        # input variables added so I don't have to use WISDEM while developing gradients
        self.add(
            'rotorArea',
            Array(np.zeros(nTurbines),
                  iotype='in',
                  dtype='float',
                  units='m*m',
                  desc='rotor area of all turbines'))
        self.add(
            'wsw_position',
            Array(
                np.zeros([3, nSamples]),
                iotype='in',
                units='m',
                desc='positions where measurements are desired in the windframe'
            ))
        self.add(
            'wakeDiameters',
            Array(np.zeros([nSamples, nTurbines, 3]),
                  iotype='in',
                  units='m',
                  desc='diameter of wake zones at measurement points'))
        self.add(
            'wakeCentersY',
            Array(np.zeros([nSamples, nTurbines]),
                  iotype='in',
                  units='m',
                  desc='Y positions of wakes at measurement points'))
        self.add(
            'wakeCentersZ',
            Array(np.zeros([nSamples, nTurbines]),
                  iotype='in',
                  units='m',
                  desc='Z positions of wakes at measurement points'))

        # Explicitly size output arrays
        self.add('velocitiesTurbines',
                 Array(np.zeros(nTurbines), iotype='out', units='m/s'))
        self.add('wt_power',
                 Array(np.zeros(nTurbines), iotype='out', units='kW'))

        self.add(
            'ws_array',
            Array(np.zeros(nSamples),
                  iotype='out',
                  units='m/s',
                  desc='wind speed at measurement locations'))

    def execute(self):

        turbineXw = self.turbineXw
        nTurbines = turbineXw.size

        # wakeOverlapTRel = self.wakeOverlapTRel
        wakeOverlapTRel = np.zeros((nTurbines, nTurbines, 3))

        # convert the input vector to the array used for calculations
        for i in range(0, nTurbines):
            wakeOverlapTRel[i, :,
                            0] = self.wakeOverlapTRel[3 * nTurbines *
                                                      i:3 * nTurbines * i +
                                                      nTurbines]
            wakeOverlapTRel[i, :,
                            1] = self.wakeOverlapTRel[3 * nTurbines * i +
                                                      nTurbines:3 * nTurbines *
                                                      i + 2 * nTurbines]
            wakeOverlapTRel[i, :, 2] = self.wakeOverlapTRel[3 * nTurbines * i +
                                                            2 * nTurbines:3 *
                                                            nTurbines * i +
                                                            3 * nTurbines]

        ke = self.parameters.ke
        keCorrArray = self.parameters.keCorrArray
        keCorrCT = self.parameters.keCorrCT
        baselineCT = self.parameters.baselineCT
        CTcorrected = self.parameters.CTcorrected
        CPcorrected = self.parameters.CPcorrected
        pP = self.parameters.pP
        Ct = self.Ct
        Vinf = self.wind_speed
        turbineXw = self.turbineXw
        axialInduction = self.axialInduction
        rotorDiameter = self.rotorDiameter
        rotorArea = np.pi * self.rotorDiameter**2 / 4.
        rho = self.air_density
        generator_efficiency = self.generator_efficiency
        yaw = self.yaw * np.pi / 180.
        Cp = self.Cp
        MU = self.parameters.MU
        aU = self.parameters.aU
        bU = self.parameters.bU
        useaUbU = self.parameters.useaUbU
        shearCoefficientAlpha = self.parameters.shearCoefficientAlpha
        shearZh = self.parameters.shearZh

        velX = self.wsw_position[0][:]
        velY = self.wsw_position[1][:]
        velZ = self.wsw_position[2][:]
        nSamples = np.size(velX)
        wakeCentersY = self.wakeCentersY
        wakeCentersZ = self.wakeCentersZ
        wakeDiameters = self.wakeDiameters

        axialIndProvided = self.parameters.axialIndProvided

        if CTcorrected == False:
            Ct = Ct * (np.cos(yaw)**2)

        if CPcorrected == False:
            Cp = Cp * np.cos(yaw)**pP

        if axialIndProvided:
            axialInd = axialInduction
        else:
            axialInd = np.array([CTtoAxialInd(ct) for ct in Ct])

        # adjust k_e to C_T, adjusted to yaw
        ke = ke + keCorrCT * (
            Ct - baselineCT
        )  # FT = Ct*0.5*rho*A*(U*cos(yaw))^2, hence, thrust decreases with cos^2
        #   Should ke increase directly with thrust? ==>No - Turbulence characteristics in wind-turbine wakes, A. Crespo"'*, J. Hern'andez b

        # array effects with full or partial wake overlap:
        # use overlap area of zone 1 + 2 of upstream turbines to correct ke
        # Note: array effects only taken into account in calculating
        # velocity deficits, in order not to over-complicate code
        # (avoid loops in calculating overlaps)

        keArray = np.zeros(nTurbines)
        for turb in range(0, nTurbines):
            s = np.sum(wakeOverlapTRel[turb, :, 0] +
                       wakeOverlapTRel[turb, :, 1])
            keArray[turb] = ke[turb] * (1 + s * keCorrArray)

        # calculate velocities in full flow field (optional)
        self.ws_array = np.tile(Vinf, nSamples)

        # apply shear profile
        self.ws_array = self.ws_array * (velZ / shearZh)**shearCoefficientAlpha

        for turb in range(0, nTurbines):
            if useaUbU:
                mU = MU / np.cos(
                    aU * np.pi / 180 + bU * yaw[turb]
                )  # CHANGE: ke now only corrected with CT, which is already corrected with yaw
            else:
                mU = MU

            for loc in range(0, nSamples):
                deltax = velX[loc] - turbineXw[turb]
                deltay = velY[loc] - wakeCentersY[loc, turb]
                deltaz = velZ[loc] - wakeCentersZ[loc, turb]
                radiusLoc = np.sqrt(deltay**2 + deltaz**2)
                axialIndAndNearRotor = 2 * axialInd[turb]

                if deltax > 0 and radiusLoc < wakeDiameters[
                        loc, turb, 0] / 2.0:  # check if in zone 1
                    reductionFactor = axialIndAndNearRotor*\
                                      np.power((rotorDiameter[turb]/(rotorDiameter[turb]+2*keArray[turb]*(mU[0])*np.maximum(0, deltax))), 2)
                elif deltax > 0 and radiusLoc < wakeDiameters[
                        loc, turb, 1] / 2.0:  # check if in zone 2
                    reductionFactor = axialIndAndNearRotor*\
                                      np.power((rotorDiameter[turb]/(rotorDiameter[turb]+2*keArray[turb]*(mU[1])*np.maximum(0, deltax))), 2)
                elif deltax > 0 and radiusLoc < wakeDiameters[
                        loc, turb, 2] / 2.0:  # check if in zone 3
                    reductionFactor = axialIndAndNearRotor*\
                                      np.power((rotorDiameter[turb]/(rotorDiameter[turb]+2*keArray[turb]*(mU[2])*np.maximum(0, deltax))), 2)
                elif deltax <= 0 and radiusLoc < rotorDiameter[
                        turb] / 2.0:  # check if axial induction zone in front of rotor
                    reductionFactor = axialIndAndNearRotor * (
                        0.5 + np.arctan(2.0 * np.minimum(0, deltax) /
                                        (rotorDiameter[turb])) / np.pi)
                else:
                    reductionFactor = 0
                self.ws_array[loc] *= (1 - reductionFactor)
        #print 'ws_array in floris_power is: ', self.ws_array
        # find effective wind speeds at downstream turbines, then predict power downstream turbine
        self.velocitiesTurbines = np.tile(Vinf, nTurbines)

        for turbI in range(0, nTurbines):

            # find overlap-area weighted effect of each wake zone
            wakeEffCoeff = 0
            for turb in range(0, nTurbines):

                wakeEffCoeffPerZone = 0
                deltax = turbineXw[turbI] - turbineXw[turb]

                if deltax > 0:
                    if useaUbU:
                        mU = MU / np.cos(aU * np.pi / 180 + bU * yaw[turb])
                    else:
                        mU = MU
                    for zone in range(0, 3):
                        wakeEffCoeffPerZone = wakeEffCoeffPerZone + np.power(
                            (rotorDiameter[turb]) /
                            (rotorDiameter[turb] +
                             2 * keArray[turb] * mU[zone] * deltax),
                            2.0) * wakeOverlapTRel[turbI, turb, zone]

                    wakeEffCoeff = wakeEffCoeff + np.power(
                        axialInd[turb] * wakeEffCoeffPerZone, 2.0)

            wakeEffCoeff = (1 - 2 * np.sqrt(wakeEffCoeff))

            # multiply the inflow speed with the wake coefficients to find effective wind speed at turbine
            self.velocitiesTurbines[turbI] *= wakeEffCoeff

        if self.verbose:
            print "wind speed at turbines %s [m/s]" % self.velocitiesTurbines
            print "rotor area %s" % rotorArea
            print "rho %s" % rho
            print "generator_efficiency %s" % generator_efficiency

        # find turbine powers
        self.wt_power = np.power(self.velocitiesTurbines, 3.0) * (
            0.5 * rho * rotorArea * Cp) * generator_efficiency
        self.wt_power /= 1000  # in kW

        if self.verbose:
            print "powers turbines %s [kW]" % self.wt_power

        self.power = np.sum(self.wt_power)
class floris_wcent_wdiam(Component):
    """ Calculates the center and diameter of each turbine wake at each other turbine """

    parameters = VarTree(FLORISParameters(), iotype='in')
    verbose = Bool(False,
                   iotype='in',
                   desc='verbosity of FLORIS, False is no output')

    def __init__(self, nTurbines, nSamples=0):
        super(floris_wcent_wdiam, self).__init__()

        # Explicitly size input arrays
        self.add('turbineXw', Array(np.zeros(nTurbines), iotype='in', \
                                    desc='x coordinates of turbines in wind dir. ref. frame'))
        self.add('turbineYw', Array(np.zeros(nTurbines), iotype='in', \
                                    desc='y coordinates of turbines in wind dir. ref. frame'))
        self.add(
            'yaw',
            Array(np.zeros(nTurbines), iotype='in',
                  desc='yaw of each turbine'))
        self.add('rotorDiameter', Array(np.zeros(nTurbines), dtype='float', iotype='in', \
                                        desc='rotor diameter of each turbine'))
        self.add('hubHeight', Array(np.zeros(nTurbines), dtype='float', iotype='in', units='m', \
                desc='hub heights of all turbines'))
        self.add('Ct', Array(np.zeros(nTurbines), iotype='in', dtype='float', \
                             desc='thrust coefficient of each turbine'))

        self.add(
            'wsw_position',
            Array(
                np.zeros([3, nSamples]),
                iotype='in',
                units='m',
                desc='positions where measurements are desired in the windframe'
            ))

        # Explicitly size output arrays
        self.add('wakeCentersYT', Array(np.zeros(nTurbines*nTurbines), iotype='out', dtype='float', \
                                        desc='wake center y position at each turbine'))
        self.add('wakeDiametersT', Array(np.zeros(nTurbines*nTurbines*3), iotype='out', dtype='float', \
                                         desc='wake diameter of each zone of each wake at each turbine'))
        self.add(
            'wakeDiameters',
            Array(
                np.zeros([nSamples, nTurbines, 3]),
                iotype='out',
                dtype='float',
                desc='wake diameter of each zone of each wake at each turbine')
        )
        self.add(
            'wakeCentersY',
            Array(np.zeros([nSamples, nTurbines]),
                  iotype='out',
                  units='m',
                  desc='Y positions of wakes at measurement points'))
        self.add(
            'wakeCentersZ',
            Array(np.zeros([nSamples, nTurbines]),
                  iotype='out',
                  units='m',
                  desc='Z positions of wakes at measurement points'))

    def execute(self):

        # rename inputs and outputs
        # pP = self.parameters.pP
        kd = self.parameters.kd
        ke = self.parameters.ke
        initialWakeDisplacement = self.parameters.initialWakeDisplacement
        initialWakeAngle = self.parameters.initialWakeAngle
        rotorDiameter = self.rotorDiameter
        hubHeight = self.hubHeight
        Ct = self.Ct
        CTcorrected = self.parameters.CTcorrected
        keCorrCT = self.parameters.keCorrCT
        baselineCT = self.parameters.baselineCT
        me = self.parameters.me

        adjustInitialWakeDiamToYaw = self.parameters.adjustInitialWakeDiamToYaw
        useWakeAngle = self.parameters.useWakeAngle

        bd = self.parameters.bd

        turbineXw = self.turbineXw
        turbineYw = self.turbineYw
        yaw = self.yaw * np.pi / 180.0
        nTurbines = turbineXw.size

        velX = self.wsw_position[0][:]
        nSamples = np.size(velX)

        if CTcorrected == False:
            Ct = Ct * (np.cos(yaw * np.pi / 180.)**2)

        # calculate y-location of wake centers
        wakeCentersY = np.zeros((nSamples, nTurbines))
        wakeCentersZ = np.zeros((nSamples, nTurbines))
        wakeCentersYT_mat = np.zeros((nTurbines, nTurbines))
        for turb in range(0, nTurbines):
            wakeAngleInit = 0.5 * np.sin(yaw[turb]) * Ct[turb]
            if useWakeAngle:
                wakeAngleInit += initialWakeAngle * np.pi / 180.0
            for loc in range(0, nSamples):  # at velX-locations
                deltax = np.maximum(velX[loc] - turbineXw[turb], 0)
                factor = (2.0 * kd * deltax / rotorDiameter[turb]) + 1.0
                wakeCentersY[loc, turb] = turbineYw[
                    turb] + initialWakeDisplacement  # initial displacement for no yaw (positive to the left looking downstream)
                displacement = (wakeAngleInit * (15.0 * (factor**4.0) +
                                                 (wakeAngleInit**2.0)) /
                                ((30.0 * kd *
                                  (factor**5.0)) / rotorDiameter[turb])) - (
                                      wakeAngleInit * rotorDiameter[turb] *
                                      (15.0 + (wakeAngleInit**2.0)) /
                                      (30.0 * kd))  # yaw-induced deflection
                if not useWakeAngle:
                    displacement += bd * deltax
                wakeCentersY[loc,
                             turb] = wakeCentersY[loc, turb] + displacement
                wakeCentersZ[loc, turb] = hubHeight[turb]

            for turbI in range(0, nTurbines):  # at turbineX-locations
                deltax = np.maximum(turbineXw[turbI] - turbineXw[turb], 0.0)
                factor = (2.0 * kd * deltax / rotorDiameter[turb]) + 1.0
                wakeCentersYT_mat[turbI, turb] = turbineYw[turb]
                wakeCentersYT_mat[turbI, turb] = wakeCentersYT_mat[
                    turbI,
                    turb] + initialWakeDisplacement  # initial displacement for no yaw (positive to the left looking downstream)

                displacement = (wakeAngleInit*(15.0*(factor**4.0)+(wakeAngleInit**2.0))/
                ((30.0*kd*(factor**5.0))/rotorDiameter[turb]))- \
                (wakeAngleInit*rotorDiameter[turb]*(15.0+(wakeAngleInit**2.0))/(30.0*kd)) # yaw-induced wake center displacement

                wakeCentersYT_mat[
                    turbI,
                    turb] = wakeCentersYT_mat[turbI, turb] + displacement

        # adjust k_e to C_T, adjusted to yaw
        ke = ke + keCorrCT * (
            Ct - baselineCT
        )  # FT = Ct*0.5*rho*A*(U*cos(yaw))^2, hence, thrust decreases with cos^2
        #   Should ke increase directly with thrust? ==>No - Turbulence characteristics in wind-turbine wakes, A. Crespo"'*, J. Hern'andez b

        # calculate wake zone diameters at velX-locations
        wakeDiameters = np.zeros((nSamples, nTurbines, 3))
        wakeDiametersT_mat = np.zeros((nTurbines, nTurbines, 3))
        for turb in range(0, nTurbines):
            if adjustInitialWakeDiamToYaw:
                wakeDiameter0 = rotorDiameter[turb] * np.cos(
                    yaw[turb]
                )  # CHANGE: initial wake diameter at rotor adjusted to yaw
            else:
                wakeDiameter0 = rotorDiameter[turb]
            for loc in range(0, nSamples):  # at velX-locations
                deltax = velX[loc] - turbineXw[turb]
                for zone in range(0, 3):
                    wakeDiameters[loc, turb, zone] = wakeDiameter0 + 2 * ke[
                        turb] * me[zone] * np.maximum(deltax, 0)
            for turbI in range(0, nTurbines):  # at turbineX-locations
                deltax = turbineXw[turbI] - turbineXw[turb]
                for zone in range(0, 3):
                    wakeDiametersT_mat[turbI, turb, zone] = np.maximum(
                        wakeDiameter0 + 2 * ke[turb] * me[zone] * deltax, 0)

        wakeDiametersT_vec = np.zeros(3 * nTurbines * nTurbines)
        for i in range(0, nTurbines):
            wakeDiametersT_vec[(3 * nTurbines *
                                i):(3 * nTurbines * i +
                                    nTurbines)] = wakeDiametersT_mat[i, :, 0]
            wakeDiametersT_vec[3 * nTurbines * i +
                               nTurbines:3 * nTurbines * i +
                               2 * nTurbines] = wakeDiametersT_mat[i, :, 1]
            wakeDiametersT_vec[3 * nTurbines * i +
                               2 * nTurbines:3 * nTurbines * i +
                               3 * nTurbines] = wakeDiametersT_mat[i, :, 2]

        wakeCentersYT_vec = np.zeros(nTurbines * nTurbines)
        for i in range(0, nTurbines):
            wakeCentersYT_vec[(nTurbines *
                               i):(nTurbines * i +
                                   nTurbines)] = wakeCentersYT_mat[i, :]

        self.wakeCentersYT = wakeCentersYT_vec
        self.wakeDiametersT = wakeDiametersT_vec
        self.wakeDiameters = wakeDiameters
        self.wakeCentersY = wakeCentersY
        self.wakeCentersZ = wakeCentersZ