コード例 #1
0
    def test_constructor_defaults(self):

        self.hobj.add('arr_nodefault3', Array(iotype='in', units='kg'))
        self.assertTrue(all(array([]) == self.hobj.arr_nodefault3))

        self.hobj.add('arr_nounits', Array(iotype='in'))
        if hasattr(self.hobj.arr_nounits, 'units'):
            self.fail("Unitless Array should not have units")
コード例 #2
0
    def setUp(self):
        """this setup function will be called before each test in this class"""
        self.hobj = Component()
        self.hobj.add('arr1', Array(array([98.9]), iotype='in', units='ft'))
        self.hobj.add('arr2', Array(array([13.2]), iotype='out', units='inch'))
        self.hobj.add('arr3', Array(iotype='in', units='kg', desc='stuff'))

        self.hobj.arr1 = [1.0, 2.0, 3.0]
        self.hobj.arr2 = [[1., 2.], [3., 4.]]
        self.hobj.arr3 = [1.1]
コード例 #3
0
ファイル: fusedwasp.py プロジェクト: dykesk/FUSED-Wake
class PlantFromWWF(Component):
    """Create a Plant information from a .wwf WAsP file"""
    # Inputs
    filename = Str(iotype='in', desc='The .wwf file name')
    wt_desc = VarTree(GenericWindTurbinePowerCurveVT(),
                      iotype='in',
                      desc='The wind turbine power curve')

    # Outputs
    wt_layout = VarTree(GenericWindFarmTurbineLayout(),
                        iotype='out',
                        desc='wind turbine properties and layout')
    wind_rose_array = Array(
        iotype='out',
        units='m/s',
        desc='Windrose array [wind_directions, frequency, weibull_A, weibull_k]'
    )

    def execute(self):
        # Reading the .wwf file
        wwf = WWF(self.filename)
        self.wt_layout.wt_list.append(self.wt_desc)
        # self.wt_layout.wt_wind_roses.frequency_array =
        self.wt_layout.configure_single()

        for wt, wr in self.wwf.windroses.iteritems():
            self.wt_layout.wt_positions[i, :] = self.wwf.data[wt][:2]
            self.wt_layout.wt_wind_roses.append(wr)
            i += 1

        self.wt_layout.configure_single()
        # For practical reason we also output the first wind rose array outside
        # the wt_layout
        self.wind_rose_array = self.wt_layout.wt_wind_roses[0]
コード例 #4
0
class AEPM(AEPMultipleWindRoses):
    """
    Calculate the AEP of a wind farm. Provide the standard AEPMultipleWindRoses interfaces, with in addition the
    possibility to change the layout of the windfarm using wt_positions as an interface.
    """
    wt_positions = Array(
        [],
        unit='m',
        iotype='in',
        desc='Array of wind turbines attached to particular positions')

    def __init__(self, wake_model=TopFGCLarsen(), **kwargs):
        """
        :param wake_model: A GenericWindFarm compatible model
        """
        self.wake_model = wake_model
        super(TopAEP, self).__init__(**kwargs)

    def configure(self):
        """
        Configure the assembly.
        :param wake_model: The wake model
        :return:
        """
        self.add('wf', self.wake_model)
        super(TopAEP, self).configure()
        self.connect('wt_positions', 'wf.wt_positions')
コード例 #5
0
 def test_default_value_type(self):
     try:
         self.hobj.add('bad_default', Array('bad'))
     except TypeError, err:
         self.assertEqual(
             str(err),
             "Default value should be an array-like object, not a <type 'str'>."
         )
コード例 #6
0
class A(Component):
    f = Float(iotype='in')
    a1d = Array(array([1.0, 1.0, 2.0, 3.0]), iotype='in')
    a2d = Array(array([[1.0, 1.0], [2.0, 3.0]]), iotype='in')
    b1d = Array(array([1.0, 1.0, 2.0, 3.0]), iotype='out')
    b2d = Array(array([[1.0, 1.0], [2.0, 3.0]]), iotype='out')
    c1d = Array(array([0.0, 1.0, 2.0, 3.0]), iotype='in')
    c2d = Array(array([[0.0, 1.0], [2.0, 3.0]]), iotype='in')

    ext1 = Array(array([eye(3), eye(3), eye(3)]))

    def execute(self):
        pass

    def some_funct(self, a, b, op='add'):
        if op == 'add':
            return a + b
        elif op == 'mult':
            return a * b
        elif op == 'sub':
            return a - b
        raise RuntimeError("bad input to some_funct")

    @property
    def some_prop(self):
        return 7
コード例 #7
0
    def test_shapes(self):

        self.hobj.add(
            'sh1',
            Array(array([[2.0, 4.5], [3.14, 2.5]]),
                  iotype='in',
                  units='kg',
                  shape=(2, 2)))
        self.assertEqual(self.hobj.sh1[1][1], 2.5)

        try:
            self.hobj.add(
                'sh1',
                Array(array([2.0, 2.5]), iotype='in', units='kg',
                      shape=(2, 2)))
        except ValueError, err:
            msg = "Shape of the default value does not match the shape attribute."
            self.assertEqual(str(err), msg)
コード例 #8
0
class GeomData(VariableTree):

    points = Array([], desc='nx3 array of point (x,y,z) locations.')

    facets = Array([],
                   desc='nx3 (or nx4) integer array of triangle or quad' +
                   'connectivities.',
                   dtype='int')

    def __init__(self, n_point, n_facet, facet_size=3):
        super(GeomData, self).__init__()

        if facet_size not in [3, 4]:
            msg = "facet size must be either 3 or 4"
            raise ValueError(msg)

        self.points = np.zeros((n_point, 3))
        self.facets = np.zeros((n_facet, facet_size), dtype='int')
コード例 #9
0
    def test_set_to_default(self):
        self.hobj.add('arr4', Array(iotype='in', units='kg'))
        self.assertTrue(all(array([]) == self.hobj.arr4))
        self.hobj.arr4 = [6.5]
        self.assertEqual(6.5, self.hobj.arr4[0])

        self.hobj.revert_to_defaults()

        self.assertTrue(all(array([98.9]) == self.hobj.arr1))
        self.assertTrue(all(array([]) == self.hobj.arr4))
コード例 #10
0
ファイル: aep.py プロジェクト: styxmshy/TOPFARM
class TopFGCLarsen(FGCLarsen):
    """
    Calculate the wind turbine power using the GCLarsen model.
    This version gives the standard FGCLarsen interfaces, but replace the wt_layout.wt_positions by the input
    wt_positions. This is done to speed-up the variable copy in openMDAO. The idea is that at each iteration, it's not
    necessary to copy arround wt_layout.
    """
    wt_positions = Array([], unit='m', iotype='in', desc='Array of wind turbines attached to particular positions')

    def execute(self):
        self.wt_layout.wt_positions = self.wt_positions
        super(TopFGCLarsen, self).execute()
コード例 #11
0
    def test_unit_conversion(self):
        self.hobj.arr1 = [1., 2., 3.]
        self.hobj.arr2 = self.hobj.get_wrapped_attr('arr1')
        self.assertAlmostEqual(12., self.hobj.arr2[0])
        self.assertAlmostEqual(24., self.hobj.arr2[1])
        self.assertAlmostEqual(36., self.hobj.arr2[2])

        # unit to unitless
        self.hobj.add('arr5', Array(iotype='in'))
        self.hobj.arr5 = [1., 2., 4.]
        self.hobj.arr2 = self.hobj.get_wrapped_attr('arr5')
        self.assertAlmostEqual(1., self.hobj.arr2[0])
        self.assertAlmostEqual(2., self.hobj.arr2[1])
        self.assertAlmostEqual(4., self.hobj.arr2[2])
コード例 #12
0
ファイル: foundation.py プロジェクト: yimei-wang/TOPFARM
class FoundationLength(TopfarmComponent):
    wt_positions = Array(
        [],
        unit='m',
        iotype='in',
        desc='Array of wind turbines attached to particular positions')
    ##wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='in', desc='wind turbine properties and layout')
    borders = Array(iotype='in',
                    desc='The polygon defining the borders ndarray([n_bor,2])',
                    unit='m')
    depth = Array(iotype='in',
                  desc='An array of depth ndarray([n_d, 2])',
                  unit='m')
    foundation_length = Float(
        iotype='out', desc='The total foundation length of the wind farm')
    foundations = Array(iotype='out',
                        desc='The foundation length ofeach wind turbine')
    scaling = Float(1.0, iotype='in', desc='scaling of the foundation')
    inc = 0

    def execute(self):
        foundation_func = LinearNDInterpolator(self.depth[:, 0:2],
                                               self.depth[:, 2])
        self.foundations = array([
            foundation_func(self.wt_positions[i, 0], self.wt_positions[i, 1])
            for i in range(self.wt_positions.shape[0])
        ])
        #dist = DistFromBorders()(wt_positions=self.wt_positions, borders=self.borders).dist
        min_depth = self.depth[:, 2].min()
        self.foundations[isnan(self.foundations)] = min_depth

        if self.scaling == 0.0:
            # Using the baseline for scaling
            self.scaling = sum(self.foundations)

        self.foundation_length = sum(self.foundations) / self.scaling
コード例 #13
0
class ElNetLayout(TopfarmComponent):
    wt_positions = Array(
        [],
        unit='m',
        iotype='in',
        desc='Array of wind turbines attached to particular positions')
    ##wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='in', desc='wind turbine properties and layout')
    #elnet_layout = VarTree(GenericWindTurbineCableLayout(), iotype='out')

    elnet_layout = Dict(
        iotype='out',
        desc=
        'The keys are tuples of connected wind turbine indices, the values are the cable length'
    )

    def execute(self):
        self.elnet_layout = elnet(self.wt_positions)
コード例 #14
0
class Simple(Component):
    a = Float(iotype='in')
    b = Float(iotype='in')
    c = Float(iotype='out')
    d = Float(iotype='out')
    x_array = Array([0, 0, 0], iotype='in')

    def __init__(self):
        super(Simple, self).__init__()
        self.a = 4.
        self.b = 5.
        self.c = 7.
        self.d = 1.5

    def execute(self):
        self.c = self.a + self.b
        self.d = self.a - self.b

        self.x_array[1] = self.a * self.b
コード例 #15
0
class ElNetLength(TopfarmComponent):
    wt_positions = Array(
        [],
        unit='m',
        iotype='in',
        desc='Array of wind turbines attached to particular positions')
    #wt_layout = VarTree(GenericWindFarmTurbineLayout(), iotype='in', desc='wind turbine properties and layout')
    elnet_layout = Dict(
        iotype='out')  #VarTree(GenericWindTurbineCableLayout(), iotype='out')
    elnet_length = Float(iotype='out',
                         desc='The total inner cable length',
                         unit='m')
    scaling = Float(1.0, iotype='in', desc='')

    def execute(self):
        elnet_layout = elnet(self.wt_positions)
        if self.scaling == 0.0:
            #using the first run as a baseline for scaling:
            self.scaling = sum(elnet_layout.values())
        self.elnet_length = sum(elnet_layout.values()) / self.scaling
        self.elnet_layout = elnet_layout
コード例 #16
0
ファイル: aep.py プロジェクト: styxmshy/TOPFARM
class AEP(TopfarmComponent):

    # Inputs
    wind_speeds = List([], iotype='in', units='m/s',
        desc='The different wind speeds to run [nWS]')

    wind_directions = List([], iotype='in', units='deg',
        desc='The different wind directions to run [nWD]')

    wt_positions = Array(iotype='in')

    scaling = Float(1.0, iotype='in', desc='Scaling of the AEP')

    # Outputs
    array_aep = Array([], iotype='out', units='kW*h',
        desc='The energy production per sector [nWD, nWS]')

    gross_aep = Float(iotype='out', units='kW*h',
        desc='Gross Annual Energy Production before availability and loss impacts')

    net_aep = Float(iotype='out', units='kW*h',
        desc='Net Annual Energy Production after availability and loss impacts')

    capacity_factor = Float(0.0, iotype='out',
        desc='Capacity factor for wind plant')


    def __init__(self, wt_layout, wind_rose, wf, **kwargs):
        """

        :param wt_layout: GenericWindFarmTurbineLayout()
        :param wind_rose: WeibullWindRoseVT()
        :param wf: GenericWindFarm()
        :param scaling: float [default = 1.0]
                        The scaling used to calculate the net_aep. If it is set to 0.0, the scaling
                        will be set to the net_aep the first time the simulation is run.
        """
        self.wf = wf
        self.wf.wt_layout = wt_layout
        self.wind_rose = wind_rose
        super(AEP, self).__init__(**kwargs)

    def execute(self):

        # build the cdf vector of the wind speed for each wind rose wind direction sector
        cdfw = []
        for iwd, wd in enumerate(self.wind_rose.wind_directions):
            cdfw.append(weibullCDF(self.wind_speeds, self.wind_rose.A[iwd], self.wind_rose.k[iwd]))

        # calculate the probability in each wind direction sector, using the CDF of the wind rose wind direction
        cdfd0 = [sum(self.wind_rose.frequency[:i]) for i in range(len(self.wind_rose.frequency)+1)]
        wd = np.hstack([self.wind_rose.wind_directions, [360]])
        cdfd1 = interp1d(wd, cdfd0)(self.wind_directions)

        net_aep = 0.0
        gross_aep = 0.0
        cwd = 0
        net_aeps = np.zeros([len(self.wind_directions)])
        gross_aeps = np.zeros([len(self.wind_directions)])
        self.powers = np.zeros([len(self.wind_directions), len(self.wind_speeds)])
        for iwd, wd in enumerate(self.wind_directions):
            if cwd < len(self.wind_rose.wind_directions):
                while wd >= self.wind_rose.wind_directions[cwd+1] and cwd < len(self.wind_rose.wind_directions)-2:
                    # switching wind rose wind direction sector
                    cwd += 1
            powers = np.zeros([len(self.wind_speeds)])
            for iws, ws in enumerate(self.wind_speeds):
                self.wf.wt_layout.wt_positions=self.wt_positions
                self.wf.wind_speed=ws
                self.wf.wind_direction=wd
                self.wf.run()
                powers[iws] = self.wf.power
            self.powers[iwd,:] = powers
            # Integrating over the wind speed CDF
            net_aeps[iwd] = np.trapz(powers, cdfw[cwd]) * 365.0 * 24.0
            for i in range(self.wt_positions.shape[0]):
                power_curve = interp1d(self.wf.wt_layout.wt_list[i].power_curve[:,0],
                                       self.wf.wt_layout.wt_list[i].power_curve[:,1])(self.wind_speeds)
                gross_aeps[iwd] += np.trapz(power_curve, cdfw[cwd]) * 365.0 * 24.0

        # Integrating over the wind direction CDF
        net_aep = np.trapz(net_aeps, cdfd1)
        gross_aep = np.trapz(gross_aeps, cdfd1)

        self.capacity_factor = net_aep / gross_aep

        if self.scaling == 0.0:
            # The scaling has to be calculated
            self.scaling = net_aep

        self.net_aep = net_aep / self.scaling
        self.gross_aep = gross_aep
コード例 #17
0
 def test_intvalues(self):
     f1 = Array([3.])
     d1 = f1.default_value / 2
     self.assertAlmostEqual(d1[0], 1.5, places=4)
コード例 #18
0
 def test_bogus_units(self):
     try:
         uf = Array([0.], iotype='in', units='bogus')
     except ValueError, err:
         self.assertEqual(str(err), "Units of 'bogus' are invalid")
コード例 #19
0
ファイル: aep.py プロジェクト: styxmshy/TOPFARM
class TopFortranGCLarsen(FGCL):
    wt_positions = Array([], unit='m', iotype='in', desc='Array of wind turbines attached to particular positions')

    def execute(self):
        self.wt_layout.wt_positions = self.wt_positions
        super(TopFGCLarsen, self).execute()
コード例 #20
0
class NEWSUMTdriver(DriverUsesDerivatives):
    """ Driver wrapper of Fortran version of NEWSUMT. 
        
    
.. todo:: Check to see if this itmax variable is needed.
            NEWSUMT might handle it for us.
            
    """

    implements(IHasParameters, IHasIneqConstraints, IHasObjective)

    itmax = Int(10,
                iotype='in',
                desc='Maximum number of iterations before \
                    termination.')

    default_fd_stepsize = Float(0.01, iotype='in', desc='Default finite ' \
                                'difference stepsize. Parameters with ' \
                                'specified values override this.')

    ilin = Array(dtype=numpy_int,
                 default_value=zeros(0, 'i4'),
                 iotype='in',
                 desc='Array designating whether each constraint is linear.')

    # Control parameters for NEWSUMT.
    # NEWSUMT has quite a few parameters to give the user control over aspects
    # of the solution.
    epsgsn = Float(0.001,
                   iotype='in',
                   desc='Convergence criteria \
                      of the golden section algorithm used for the \
                      one dimensional minimization.')
    epsodm = Float(0.001,
                   iotype='in',
                   desc='Convergence criteria \
                      of the unconstrained minimization.')
    epsrsf = Float(0.001,
                   iotype='in',
                   desc='Convergence criteria \
                      for the overall process.')
    g0 = Float(0.1,
               iotype='in',
               desc='Initial value of the transition \
                      parameter.')
    ra = Float(1.0,
               iotype='in',
               desc='Penalty multiplier. Required if mflag=1')
    racut = Float(0.1,
                  iotype='in',
                  desc='Penalty multiplier decrease ratio. \
                      Required if mflag=1.')
    ramin = Float(1.0e-13,
                  iotype='in',
                  desc='Lower bound of \
                      penalty multiplier. \
                      Required if mflag=1.')
    stepmx = Float(2.0,
                   iotype='in',
                   desc='Maximum bound imposed on the \
                      initial step size of the one-dimensional \
                      minimization.')

    jprint = Int(0,
                 iotype='in',
                 desc='Print information during NEWSUMT \
                    solution. Higher values are more verbose. If 0,\
                    print initial and final designs only.',
                 high=3,
                 low=-1)
    lobj = Int(0, iotype='in', desc='Set to 1 if linear objective function.')
    maxgsn = Int(20,
                 iotype='in',
                 desc='Maximum allowable number of golden \
                    section iterations used for 1D minimization.')
    maxodm = Int(6,
                 iotype='in',
                 desc='Maximum allowable number of one \
                    dimensional minimizations.')
    maxrsf = Int(15,
                 iotype='in',
                 desc='Maximum allowable number of \
                     unconstrained minimizations.')
    mflag = Int(0,
                iotype='in',
                desc='Flag for penalty multiplier. \
                     If 0, initial value computed by NEWSUMT. \
                     If 1, initial value set by ra.')

    def __init__(self, *args, **kwargs):
        super(NEWSUMTdriver, self).__init__(*args, **kwargs)

        self.iter_count = 0

        # Save data from common blocks into the driver
        self.contrl = _contrl()
        self.countr = _countr()

        # define the NEWSUMTdriver's private variables
        # note, these are all resized in config_newsumt

        # basic stuff
        self.design_vals = zeros(0, 'd')
        self.constraint_vals = []

        # temp storage
        self.__design_vals_tmp = zeros(0, 'd')
        self._ddobj = zeros(0)
        self._dg = zeros(0)
        self._dh = zeros(0)
        self._dobj = zeros(0)
        self._g = zeros(0)
        self._gb = zeros(0)
        self._g1 = zeros(0)
        self._g2 = zeros(0)
        self._g3 = zeros(0)
        self._s = zeros(0)
        self._sn = zeros(0)
        self._x = zeros(0)
        self._iik = zeros(0, dtype=int)

        self._lower_bounds = zeros(0)
        self._upper_bounds = zeros(0)
        self._iside = zeros(0)
        self.fdcv = zeros(0)

        # Just defined here. Set elsewhere
        self.n1 = self.n2 = self.n3 = self.n4 = 0

        # Ready inputs for NEWSUMT
        self._obj = 0.0
        self._objmin = 0.0

        self.isdone = False
        self.resume = False
        self.uses_Hessians = False

    def start_iteration(self):
        """Perform the optimization."""

        # Flag used to figure out if we are starting a new finite difference
        self.baseline_point = True

        # set newsumt array sizes and more...
        self._config_newsumt()

        self.iter_count = 0

        # get the values of the parameters
        # check if any min/max constraints are violated by initial values
        for i, val in enumerate(self.get_parameters().values()):

            value = val.evaluate(self.parent)
            self.design_vals[i] = value
            # next line is specific to NEWSUMT
            self.__design_vals_tmp[i] = value

        # Call the interruptible version of SUMT in a loop that we manage
        self.isdone = False
        self.resume = False

    def continue_iteration(self):
        """Returns True if iteration should continue."""

        return not self.isdone and self.iter_count < self.itmax

    def pre_iteration(self):
        """Checks or RunStopped and evaluates objective."""

        super(NEWSUMTdriver, self).pre_iteration()
        if self._stop:
            self.raise_exception('Stop requested', RunStopped)

    def run_iteration(self):
        """ The NEWSUMT driver iteration."""

        self._load_common_blocks()

        try:
            ( fmin, self._obj, self._objmin, self.design_vals,
              self.__design_vals_tmp, self.isdone, self.resume) = \
              newsumtinterruptible.newsuminterruptible(user_function,
                   self._lower_bounds, self._upper_bounds,
                   self._ddobj, self._dg, self._dh, self._dobj,
                   self.fdcv, self._g,
                   self._gb, self._g1, self._g2, self._g3,
                   self._obj, self._objmin,
                   self._s, self._sn, self.design_vals, self.__design_vals_tmp,
                   self._iik, self.ilin, self._iside,
                   self.n1, self.n2, self.n3, self.n4,
                   self.isdone, self.resume, analys_extra_args = (self,))

        except Exception, err:
            self._logger.error(str(err))
            raise

        self._save_common_blocks()

        self.iter_count += 1

        # Update the parameters and run one final time with what it gave us.
        # This update is needed because I obeserved that the last callback to
        # user_function is the final leg of a finite difference, so the model
        # is not in sync with the final design variables.
        if not self.continue_iteration():
            dvals = [float(val) for val in self.design_vals]
            self.set_parameters(dvals)

            super(NEWSUMTdriver, self).run_iteration()
コード例 #21
0
ファイル: aep.py プロジェクト: styxmshy/TOPFARM
class AEPFortranMultipleWindRoses(TopfarmComponent):

    # Inputs
    wind_speeds = List([], iotype='in', units='m/s',
        desc='The different wind speeds to run [nWS]')

    wind_directions = List([], iotype='in', units='deg',
        desc='The different wind directions to run [nWD]')

    turbulence_intensity = Float(0.1, iotype='in',
        desc='The turbulence intensity at the site')

    wt_positions = Array(iotype='in')

    wind_roses = List(iotype='in', desc='List of weibull wind_rose arrays')

    scaling = Float(1.0, iotype='in', desc='Scaling of the AEP')

    # Outputs
    array_aep = Array([], iotype='out', units='kW*h',
        desc='The energy production per sector [nWD, nWS]')

    gross_aep = Float(iotype='out', units='kW*h',
        desc='Gross Annual Energy Production before availability and loss impacts')

    net_aep = Float(iotype='out', units='kW*h',
        desc='Net Annual Energy Production after availability and loss impacts')

    capacity_factor = Float(0.0, iotype='out',
        desc='Capacity factor for wind plant')


    def __init__(self, wt_layout, wf, **kwargs):
        """

        :param wt_layout: GenericWindFarmTurbineLayout()
        :param wf: GenericWindFarm()
        :param scaling: float [default = 1.0]
                        The scaling used to calculate the net_aep. If it is set to 0.0, the scaling
                        will be set to the net_aep the first time the simulation is run.
        """
        self.wf = wf
        self.wf.wt_layout = wt_layout
        #self.wind_rose = wind_rose
        super(AEPFortranMultipleWindRoses, self).__init__(**kwargs)

    def execute(self):
        wt_net_aep = np.zeros([self.wt_positions.shape[0]])
        wt_gross_aep = np.zeros([self.wt_positions.shape[0]])
        cwd = 0
        wind_speeds, wind_directions = np.meshgrid(self.wind_speeds, self.wind_directions)

        # Runnning all the wind speeds and wind directions at the same time
        self.wf.wt_layout.wt_positions=self.wt_positions
        self.wf.wind_speeds = wind_speeds.flatten()
        self.wf.wind_directions = wind_directions.flatten()
        self.wf.turbulence_intensities = self.turbulence_intensity * ones_like(self.wf.wind_directions)
        self.wf.run()
        powers = self.wf.wt_power.reshape([len(self.wind_directions),
                                           len(self.wind_speeds),
                                           self.wt_positions.shape[0]])
        self.powers = powers

        for iwt, wt in enumerate(self.wf.wt_layout.wt_list):
            net_aeps = np.zeros([len(self.wind_directions)])
            gross_aeps = np.zeros([len(self.wind_directions)])

            # build the cdf vector of the wind speed for each wind rose wind direction sector
            cdfw = []
            for iwd, wd in enumerate(self.wind_roses[iwt].wind_directions):
                cdfw.append(weibullCDF(self.wind_speeds, self.wind_roses[iwt].A[iwd], self.wind_roses[iwt].k[iwd]))

            # calculate the probability in each wind direction sector, using the CDF of the wind rose wind direction
            cdfd0 = [sum(self.wind_roses[iwt].frequency[:i]) for i in range(len(self.wind_roses[iwt].frequency)+1)]
            wd = np.hstack([self.wind_roses[iwt].wind_directions, [360]])
            cdfd1 = interp1d(wd, cdfd0)(self.wind_directions)
            cwd = 0
            for iwd, wd in enumerate(self.wind_directions):
                # self.wind_directions is not the same as self.wind_roses[iwt].wind_directions, so we have to match both sectors
                if cwd < len(self.wind_roses[iwt].wind_directions):
                    while wd >= self.wind_roses[iwt].wind_directions[cwd+1] and \
                          cwd < len(self.wind_roses[iwt].wind_directions)-2:
                        # switching wind rose wind direction sector
                        cwd += 1
                # Integrating over the wind speed CDF
                net_aeps[iwd] = np.trapz(powers[iwd,:,iwt], cdfw[cwd]) * 365.0 * 24.0
                for i in range(self.wt_positions.shape[0]):
                    power_curve = interp1d(wt.power_curve[:,0],
                                           wt.power_curve[:,1])(self.wind_speeds)
                    gross_aeps[iwd] += np.trapz(power_curve, cdfw[cwd]) * 365.0 * 24.0

            # Integrating over the wind direction CDF
            wt_net_aep[iwt] = np.trapz(net_aeps, cdfd1)
            wt_gross_aep[iwt] = np.trapz(gross_aeps, cdfd1)

        net_aep = wt_net_aep.sum()
        gross_aep = wt_gross_aep.sum()

        self.capacity_factor = net_aep / gross_aep

        if self.scaling == 0.0:
            # The scaling has to be calculated
            self.scaling = net_aep

        self.net_aep = net_aep / self.scaling
        self.gross_aep = gross_aep