Ejemplo n.º 1
0
 def __init__(self, cost_comp, turbineTypes, lower, upper, turbineXYZ, boundary_comp, min_spacing=None,
              driver=EasyRandomSearchDriver(random_search_driver.RandomizeTurbineTypeAndPosition()), plot_comp=None, record_id=None, expected_cost=1):
     sys.stderr.write("%s is deprecated. Use TopFarmProblem instead\n" % self.__class__.__name__)
     TopFarmProblem.__init__(self, cost_comp, driver, plot_comp, record_id, expected_cost)
     TurbineTypeOptimizationProblem.initialize(self, turbineTypes, lower, upper)
     TurbineXYZOptimizationProblem.initialize(self, turbineXYZ, boundary_comp, min_spacing)
     self.setup(check=True, mode=self.mode)
Ejemplo n.º 2
0
def main():
    if __name__ == '__main__':
        try:
            import matplotlib.pyplot as plt
            plt.gcf()
            plot_comp = XYPlotComp()
            plot = True
        except RuntimeError:
            plot_comp = NoPlot()
            plot = False

        n_wt = 16
        site = IEA37Site(n_wt)
        windTurbines = IEA37_WindTurbines()
        wake_model = IEA37SimpleBastankhahGaussian(site, windTurbines)
        Drotor_vector = [windTurbines.diameter()] * n_wt
        power_rated_vector = [float(windTurbines.power(20) / 1000)] * n_wt
        hub_height_vector = [windTurbines.hub_height()] * n_wt
        AEPCalc = AEPCalculator(wake_model)

        def aep_func(x, y, **kwargs):
            return AEPCalc.calculate_AEP(x_i=x, y_i=y).sum(-1).sum(-1) * 10**6

        def irr_func(aep, **kwargs):
            my_irr = economic_evaluation(Drotor_vector, power_rated_vector,
                                         hub_height_vector,
                                         aep).calculate_irr()
            print(my_irr)
            return my_irr

        aep_comp = CostModelComponent(input_keys=['x', 'y'],
                                      n_wt=n_wt,
                                      cost_function=aep_func,
                                      output_key="aep",
                                      output_unit="GWh",
                                      objective=False,
                                      output_val=np.zeros(n_wt))
        irr_comp = CostModelComponent(input_keys=['aep'],
                                      n_wt=n_wt,
                                      cost_function=irr_func,
                                      output_key="irr",
                                      output_unit="%",
                                      objective=True,
                                      income_model=True)
        group = TopFarmGroup([aep_comp, irr_comp])
        problem = TopFarmProblem(
            design_vars=dict(zip('xy', site.initial_position.T)),
            cost_comp=group,
            driver=EasyRandomSearchDriver(
                randomize_func=RandomizeTurbinePosition_Circle(), max_iter=50),
            constraints=[
                SpacingConstraint(200),
                CircleBoundaryConstraint([0, 0], 1300.1)
            ],
            plot_comp=plot_comp)
        cost, state, recorder = problem.optimize()
Ejemplo n.º 3
0
def test_random_search_driver_position(topfarm_generator, randomize_func):
    np.random.seed(1)
    driver = EasyRandomSearchDriver(randomize_func, max_iter=1000)
    tf = topfarm_generator(driver, spacing=1)
    tf.optimize()
    tb_pos = tf.turbine_positions[:, :2]
    tol = 1e-1
    assert tb_pos[1][0] < 6 + tol  # check within border
    np.testing.assert_array_almost_equal(tb_pos, [[3, -3], [6, -7], [4, -3]],
                                         -int(np.log10(tol)))
Ejemplo n.º 4
0
def test_TopFarmProblemXYBoundaryPenalty():
    tf = xy3tb.get_tf(design_vars={'x': [3, 7, 4], 'y': [-3, -7, -3]},
                      driver=EasyRandomSearchDriver(RandomizeTurbinePosition(1), 10),
                      constraints=[XYBoundaryConstraint(xy3tb.boundary)])
    # spacing violated
    cost, _ = tf.evaluate({'x': xy3tb.desired[:, 0], 'y': xy3tb.desired[:, 1]})
    npt.assert_array_less(1e10, cost)

    # spacing satisfied
    cost, _ = tf.evaluate({'x': xy3tb.optimal[:, 0], 'y': xy3tb.optimal[:, 1]})
    npt.assert_equal(1.5, cost)
Ejemplo n.º 5
0
def test_TopFarmProblemXYBoundaryPenaltyAndLimits():
    tf = xy3tb.get_tf(design_vars={'x': ([3, 7, 4], -1, 5), 'y': ([-3, -7, -3], -9, -1)},
                      driver=EasyRandomSearchDriver(RandomizeTurbinePosition(1), 10),
                      constraints=[XYBoundaryConstraint(xy3tb.boundary)])
    tf.evaluate({'x': xy3tb.desired[:, 0], 'y': xy3tb.desired[:, 1]})
    npt.assert_equal(tf['boundaryDistances'][1, 3], -1)

    desvars = tf.driver._designvars
    npt.assert_equal(desvars['indeps.x']['lower'], 0)
    npt.assert_equal(desvars['indeps.x']['upper'], 5)
    npt.assert_array_equal(desvars['indeps.y']['lower'], -9)
    npt.assert_array_equal(desvars['indeps.y']['upper'], -1)
Ejemplo n.º 6
0
def test_TopFarmProblemLimits():

    tf = xy3tb.get_tf(design_vars={'x': (xy3tb.initial[:, 0], -3, 3),
                                   'y': (xy3tb.initial[:, 1], [-4, -3, -2], [2, 3, 4])},
                      driver=EasyRandomSearchDriver(RandomizeTurbinePosition(1), max_iter=100),
                      constraints=[])
    tf.evaluate()
    desvars = tf.driver._designvars
    npt.assert_equal(desvars['indeps.x']['lower'], -3)
    npt.assert_equal(desvars['indeps.x']['upper'], 3)
    npt.assert_array_equal(desvars['indeps.y']['lower'], [-4, -3, -2])
    npt.assert_array_equal(desvars['indeps.y']['upper'], [2, 3, 4])
Ejemplo n.º 7
0
def main():
    if __name__ == '__main__':
        n_wt = 16
        site = IEA37Site(n_wt)
        windTurbines = IEA37_WindTurbines()
        windFarmModel = IEA37SimpleBastankhahGaussian(site, windTurbines)
        tf = TopFarmProblem(
            design_vars=dict(zip('xy', site.initial_position.T)),
            cost_comp=PyWakeAEPCostModelComponent(windFarmModel, n_wt),
            driver=EasyRandomSearchDriver(
                randomize_func=RandomizeTurbinePosition_Circle(), max_iter=5),
            constraints=[CircleBoundaryConstraint([0, 0], 1300.1)],
            plot_comp=XYPlotComp())
        tf.optimize()
        tf.plot_comp.show()
def main():
    if __name__ == '__main__':
        plot_comp = XYPlotComp()
        site = get_site()
        n_wt = len(site.initial_position)
        windTurbines = DTU10MW()
        min_spacing = 2 * windTurbines.diameter(0)
        windFarmModel = IEA37SimpleBastankhahGaussian(site, windTurbines)
        Drotor_vector = [windTurbines.diameter()] * n_wt
        power_rated_vector = [float(windTurbines.power(20) / 1000)] * n_wt
        hub_height_vector = [windTurbines.hub_height()] * n_wt

        def aep_func(x, y, **_):
            sim_res = windFarmModel(x, y)
            aep = sim_res.aep()
            return aep.sum(['wd', 'ws']).values * 10**6

        def irr_func(aep, **_):
            return economic_evaluation(Drotor_vector, power_rated_vector,
                                       hub_height_vector, aep).calculate_irr()

        aep_comp = CostModelComponent(input_keys=['x', 'y'],
                                      n_wt=n_wt,
                                      cost_function=aep_func,
                                      output_key="aep",
                                      output_unit="GWh",
                                      objective=False,
                                      output_val=np.zeros(n_wt))
        irr_comp = CostModelComponent(input_keys=['aep'],
                                      n_wt=n_wt,
                                      cost_function=irr_func,
                                      output_key="irr",
                                      output_unit="%",
                                      objective=True,
                                      income_model=True)
        group = TopFarmGroup([aep_comp, irr_comp])
        problem = TopFarmProblem(
            design_vars=dict(zip('xy', site.initial_position.T)),
            cost_comp=group,
            driver=EasyRandomSearchDriver(
                randomize_func=RandomizeTurbinePosition_Circle(), max_iter=10),
            constraints=[
                SpacingConstraint(min_spacing),
                XYBoundaryConstraint(site.boundary),
            ],
            plot_comp=plot_comp)
        cost, state, recorder = problem.optimize()
        problem.plot_comp.show()
Ejemplo n.º 9
0
def main():
    if __name__ == '__main__':
        site = IEA37Site(16)
        windTurbines = IEA37_WindTurbines()
        wake_model = IEA37SimpleBastankhahGaussian(windTurbines)
        aep_calc = PyWakeAEP(site, windTurbines, wake_model)
        tf = TopFarmProblem(
            design_vars=dict(zip('xy', site.initial_position.T)),
            cost_comp=aep_calc.get_TopFarm_cost_component(16),
            driver=EasyRandomSearchDriver(
                randomize_func=RandomizeTurbinePosition_Circle(), max_iter=5),
            constraints=[CircleBoundaryConstraint([0, 0], 1300.1)],
            plot_comp=XYPlotComp())
        # tf.evaluate()
        tf.optimize()
        tf.plot_comp.show()
Ejemplo n.º 10
0
def test_random_search_driver_randomize_all_uniform():
    np.random.seed(1)

    class Cost():
        i = 0

        def __call__(self, *args, **kwargs):
            self.i += 1
            return self.i

    cost_comp = CostModelComponent(input_keys=['x', 'y', 'type'],
                                   n_wt=2,
                                   cost_function=Cost(),
                                   income_model=True)

    tf = TopFarmProblem(
        {
            'x': ([1, 6], [0, 1], [5, 6]),
            'y': ([-1., 0], -6, 0),
            'type': ([3, 3], 3, 8)
        },
        cost_comp=cost_comp,
        constraints=[],
        driver=EasyRandomSearchDriver(randomize_func=RandomizeAllUniform(
            ['x', 'type']),
                                      max_iter=600,
                                      disp=False),
    )
    _, state, recorder = tf.optimize()

    # check that integer design variables are somewhat evenly distributed
    x, y, t = recorder['x'], recorder['y'], recorder['type']
    for arr, l, u in [(x[:, 0], 0, 5), (x[:, 1], 1, 6), (t[:, 0], 3, 8)]:
        count = [(arr == i).sum() for i in range(l, u + 1)]
        npt.assert_equal(601, sum(count))
        npt.assert_array_less(600 / len(count) * .70, count)

    count, _ = np.histogram(y[:, 0], np.arange(-6, 1))
    npt.assert_equal(y.shape[0], sum(count))
    npt.assert_array_less(600 / len(count) * .70, count)
Ejemplo n.º 11
0
def test_random_search_driver_type_and_position(topfarm_generator):
    np.random.seed(1)

    tf = TopFarmProblem(
        {
            'x': [1, 6, 6],
            'y': [1, 0, -8],
            'type': ([0, 0, 0], 0, 3)
        },
        cost_comp=DummyCost(desired, ['x', 'y', 'type']),
        constraints=[SpacingConstraint(1),
                     XYBoundaryConstraint(boundary)],
        driver=EasyRandomSearchDriver(
            randomize_func=RandomizeTurbineTypeAndPosition(1), max_iter=2000),
    )
    _, state, _ = tf.optimize()
    tb_pos = tf.turbine_positions[:, :2]
    tol = 1e-1
    assert tb_pos[1][0] < 6 + tol  # check within border

    np.testing.assert_array_almost_equal(tb_pos, [[3, -3], [6, -7], [4, -3]],
                                         -int(np.log10(tol)))
    np.testing.assert_array_equal(state['type'], [1, 2, 3])
def main(obj=False, max_con_on=True):
    if __name__ == '__main__':
        start = time.time()
        try:
            import matplotlib.pyplot as plt
            plt.gcf()
            plot = True
        except RuntimeError:
            plot = False

        # ------ DEFINE WIND TURBINE TYPES, LOCATIONS & STORE METADATA -------
        windTurbines = WindTurbines(
            names=['Ghost_T1', 'T2'],
            diameters=[40, 84],
            hub_heights=[70, hornsrev1.HornsrevV80().hub_height()],
            ct_funcs=[dummy_thrust(ct_rated=0),
                      hornsrev1.HornsrevV80().ct],
            power_funcs=[
                cube_power(power_rated=0),
                cube_power(power_rated=3000)
            ],
            # hornsrev1.HornsrevV80()._power],
            power_unit='kW')
        Drotor_vector = windTurbines._diameters
        power_rated_vec = np.array(
            [pcurv(25) / 1000 for pcurv in windTurbines._power_funcs])
        hub_height_vector = windTurbines._hub_heights

        x, y = np.meshgrid(range(-840, 840, 420), range(-840, 840, 420))
        n_wt = len(x.flatten())
        # initial turbine positions and other independent variables
        ext_vars = {'x': x.flatten(), 'y': y.flatten(), 'obj': obj * 1}

        capconst = []
        if max_con_on:
            capconst = [
                CapacityConstraint(max_capacity=30.01,
                                   rated_power_array=power_rated_vec)
            ]

        # ---------------- DEFINE SITE & SELECT WAKE MODEL -------------------
    #        site = UniformWeibullSite(p_wd=[50, 50], a=[9, 9], k=[2.3, 2.3], ti=.1, alpha=0, h_ref=100)
        site = UniformWeibullSite(p_wd=[100], a=[9], k=[2.3], ti=.1)
        site.default_ws = [9]  # reduce the number of calculations
        site.default_wd = [0]  # reduce the number of calculations

        wake_model = NOJ(site, windTurbines)

        AEPCalc = AEPCalculator(wake_model)

        # ------------- OUTPUTS AEP PER TURBINE & FARM IRR -------------------
        def aep_func(x, y, type, obj, **kwargs
                     ):  # TODO fix type as input change to topfarm turbinetype
            out = AEPCalc.calculate_AEP(x_i=x, y_i=y,
                                        type_i=type.astype(int)).sum((1, 2))
            if obj:  # if objective is AEP; output the total Farm_AEP
                out = np.sum(out)
            return out * 10**6

        def irr_func(aep, type, **kwargs):
            idx = type.astype(int)
            return economic_evaluation(Drotor_vector[idx],
                                       power_rated_vec[idx],
                                       hub_height_vector[idx],
                                       aep).calculate_irr()

        # ----- WRAP AEP AND IRR INTO TOPFARM COMPONENTS AND THEN GROUP  -----
        aep_comp = CostModelComponent(input_keys=[
            topfarm.x_key, topfarm.y_key, topfarm.type_key, ('obj', obj)
        ],
                                      n_wt=n_wt,
                                      cost_function=aep_func,
                                      output_key="aep",
                                      output_unit="GWh",
                                      objective=obj,
                                      output_val=np.zeros(n_wt),
                                      income_model=True)
        comps = [aep_comp]  # AEP component is always in the group
        if not obj:  # if objective is IRR initiate/add irr_comp
            irr_comp = CostModelComponent(input_keys=[topfarm.type_key, 'aep'],
                                          n_wt=n_wt,
                                          cost_function=irr_func,
                                          output_key="irr",
                                          output_unit="%",
                                          objective=True)
            comps.append(irr_comp)

        group = TopFarmGroup(comps)

        # - INITIATE THE PROBLEM WITH ONLY TURBINE TYPE AS DESIGN VARIABLES -
        tf = TopFarmProblem(
            design_vars={
                topfarm.type_key: ([0] * n_wt, 0, len(windTurbines._names) - 1)
            },
            cost_comp=group,
            driver=EasyRandomSearchDriver(randomize_func=RandomizeAllUniform(
                [topfarm.type_key]),
                                          max_iter=1),
            # driver=EasySimpleGADriver(max_gen=2, random_state=1),
            constraints=capconst,
            # plot_comp=TurbineTypePlotComponent(windTurbines._names),
            plot_comp=NoPlot(),
            ext_vars=ext_vars)

        cost, state, rec = tf.optimize()
        # view_model(problem, outfile='ex5_n2.html', show_browser=False)
        end = time.time()
        print(end - start)
        # %%
        # ------------------- OPTIONAL VISUALIZATION OF WAKES ----------------
        post_visual, save = False, False
        if post_visual:
            #        import matplotlib.pyplot as plt
            for cou, (i, j, k, co, ae) in enumerate(
                    zip(rec['x'], rec['y'], rec['type'], rec['cost'],
                        rec['aep'])):
                AEPCalc.calculate_AEP(x_i=i, y_i=j, type_i=k)
                AEPCalc.plot_wake_map(wt_x=i,
                                      wt_y=j,
                                      wt_type=k,
                                      wd=site.default_wd[0],
                                      ws=site.default_ws[0],
                                      levels=np.arange(2.5, 12, .1))
                windTurbines.plot(i, j, types=k)
                title = f'IRR: {-np.round(co,2)} %, AEP :  {round(np.sum(ae))} GWh, '
                if "totalcapacity" in rec.keys():
                    title += f'Total Capacity: {rec["totalcapacity"][cou]} MW'
                plt.title(title)
                if save:
                    plt.savefig(
                        r'..\..\..\ima2\obj_AEP_{}_MaxConstraint_{}_{}.png'.
                        format(obj, max_con_on, cou))
                plt.show()
def main():
    if __name__ == '__main__':
        try:
            import matplotlib.pyplot as plt
            plt.gcf()
            plot_comp = XYPlotComp()
            plot = True
        except RuntimeError:
            plot_comp = NoPlot()
            plot = False

        n_wt = 16
        site = IEA37Site(n_wt)
        windTurbines = IEA37_WindTurbines()
        windFarmModel = IEA37SimpleBastankhahGaussian(site, windTurbines)
        Drotor_vector = [windTurbines.diameter()] * n_wt
        power_rated_vector = [float(windTurbines.power(20)) * 1e-6] * n_wt
        hub_height_vector = [windTurbines.hub_height()] * n_wt
        distance_from_shore = 10         # [km]
        energy_price = 0.1              # [Euro/kWh] What we get per kWh
        project_duration = 20            # [years]
        rated_rpm_array = [12] * n_wt    # [rpm]
        water_depth_array = [15] * n_wt  # [m]

        eco_eval = economic_evaluation(distance_from_shore, energy_price, project_duration)

        def irr_func(aep, **kwargs):
            eco_eval.calculate_irr(
                rated_rpm_array,
                Drotor_vector,
                power_rated_vector,
                hub_height_vector,
                water_depth_array,
                aep)
            print(eco_eval.IRR)
            return eco_eval.IRR

        aep_comp = CostModelComponent(
            input_keys=['x', 'y'],
            n_wt=n_wt,
            cost_function=lambda x, y, **_: windFarmModel(x=x, y=y).aep().sum(['wd', 'ws']) * 10**6,
            output_key="aep",
            output_unit="kWh",
            objective=False,
            output_val=np.zeros(n_wt))
        irr_comp = CostModelComponent(
            input_keys=['aep'],
            n_wt=n_wt,
            cost_function=irr_func,
            output_key="irr",
            output_unit="%",
            objective=True,
            income_model=True)
        group = TopFarmGroup([aep_comp, irr_comp])
        problem = TopFarmProblem(
            design_vars=dict(zip('xy', site.initial_position.T)),
            cost_comp=group,
            driver=EasyRandomSearchDriver(randomize_func=RandomizeTurbinePosition_Circle(), max_iter=5),
            constraints=[SpacingConstraint(200),
                         CircleBoundaryConstraint([0, 0], 1300.1)],
            plot_comp=plot_comp)
        cost, state, recorder = problem.optimize()
Ejemplo n.º 14
0
                def setup_prob(differentiable):

                    #####################################
                    ## Setup Floris run with gradients ##
                    #####################################
                    topfarm.x_key = 'turbineX'
                    topfarm.y_key = 'turbineY'
                    turbineX = np.array(
                        [1164.7, 947.2, 1682.4, 1464.9, 1982.6, 2200.1])
                    turbineY = np.array(
                        [1024.7, 1335.3, 1387.2, 1697.8, 2060.3, 1749.7])
                    f = np.array([
                        3.597152, 3.948682, 5.167395, 7.000154, 8.364547,
                        6.43485, 8.643194, 11.77051, 15.15757, 14.73792,
                        10.01205, 5.165975
                    ])
                    wind_speed = 8
                    site = Amalia1Site(f, mean_wsp=wind_speed)
                    site.initial_position = np.array([turbineX, turbineY]).T
                    wt = NREL5MWREF()
                    wake_model = NOJ(site, wt)
                    aep_calculator = AEPCalculator(wake_model)
                    n_wt = len(turbineX)
                    differentiable = differentiable
                    wake_model_options = {
                        'nSamples': 0,
                        'nRotorPoints': 1,
                        'use_ct_curve': True,
                        'ct_curve': ct_curve,
                        'interp_type': 1,
                        'differentiable': differentiable,
                        'use_rotor_components': False
                    }

                    aep_comp = AEPGroup(
                        n_wt,
                        differentiable=differentiable,
                        use_rotor_components=False,
                        wake_model=floris_wrapper,
                        params_IdepVar_func=add_floris_params_IndepVarComps,
                        wake_model_options=wake_model_options,
                        datasize=len(power_curve),
                        nDirections=len(f),
                        cp_points=len(power_curve))  # , cp_curve_spline=None)

                    def cost_func(AEP, **kwargs):
                        return AEP

                    cost_comp = CostModelComponent(input_keys=[('AEP', [0])],
                                                   n_wt=n_wt,
                                                   cost_function=cost_func,
                                                   output_key="aep",
                                                   output_unit="kWh",
                                                   objective=True,
                                                   income_model=True,
                                                   input_units=['kW*h'])
                    group = TopFarmGroup([aep_comp, cost_comp])
                    boundary = np.array([(900, 1000), (2300, 1000),
                                         (2300, 2100),
                                         (900, 2100)])  # turbine boundaries
                    prob = TopFarmProblem(
                        design_vars={
                            'turbineX': (turbineX, 'm'),
                            'turbineY': (turbineY, 'm')
                        },
                        cost_comp=group,
                        driver=EasyRandomSearchDriver(
                            randomize_func=RandomizeTurbinePosition_Square(),
                            max_iter=500),
                        #                        driver=EasyScipyOptimizeDriver(optimizer='SLSQP',tol=10**-12),
                        #                        driver=EasyScipyOptimizeDriver(optimizer='COBYLA'),
                        constraints=[
                            SpacingConstraint(200, units='m'),
                            XYBoundaryConstraint(boundary, units='m')
                        ],
                        plot_comp=plot_comp,
                        expected_cost=-100e2,
                    )
                    turbineZ = np.array([90.0, 100.0, 90.0, 80.0, 70.0, 90.0])
                    air_density = 1.1716  # kg/m^3
                    rotorDiameter = np.zeros(n_wt)
                    hubHeight = np.zeros(n_wt)
                    axialInduction = np.zeros(n_wt)
                    generatorEfficiency = np.zeros(n_wt)
                    yaw = np.zeros(n_wt)
                    for turbI in range(0, n_wt):
                        rotorDiameter[turbI] = wt.diameter()  # m
                        hubHeight[turbI] = wt.hub_height()  # m
                        axialInduction[turbI] = 1.0 / 3.0
                        generatorEfficiency[turbI] = 1.0  # 0.944
                        yaw[turbI] = 0.  # deg.
                    prob['turbineX'] = turbineX
                    prob['turbineY'] = turbineY
                    prob['hubHeight'] = turbineZ
                    prob['yaw0'] = yaw
                    prob['rotorDiameter'] = rotorDiameter
                    prob['hubHeight'] = hubHeight
                    prob['axialInduction'] = axialInduction
                    prob['generatorEfficiency'] = generatorEfficiency
                    prob['windSpeeds'] = np.ones(len(f)) * wind_speed
                    prob['air_density'] = air_density

                    prob['windDirections'] = np.arange(0, 360, 360 / len(f))
                    prob['windFrequencies'] = f / 100
                    # turns off cosine spread (just needs to be very large)
                    prob['model_params:cos_spread'] = 1E12
                    prob['model_params:shearExp'] = 0.25
                    prob['model_params:z_ref'] = 80.
                    prob['model_params:z0'] = 0.
                    prob['rated_power'] = np.ones(n_wt) * 5000.
                    prob['cut_in_speed'] = np.ones(n_wt) * 3
                    prob['cp_curve_wind_speed'] = cp_curve[:, 0]
                    prob['cp_curve_cp'] = cp_curve[:, 1]
                    prob['rated_wind_speed'] = np.ones(n_wt) * 11.4
                    prob['cut_out_speed'] = np.ones(n_wt) * 25.0
                    # if 0:
                    # prob.check_partials(compact_print=True,includes='*direction_group0*')
                    # else:
                    return prob