def test_asdict(flow_field_fixture: FlowField,
                turbine_grid_fixture: TurbineGrid):

    flow_field_fixture.initialize_velocity_field(turbine_grid_fixture)
    dict1 = flow_field_fixture.as_dict()

    new_ff = FlowField.from_dict(dict1)
    new_ff.initialize_velocity_field(turbine_grid_fixture)
    dict2 = new_ff.as_dict()

    assert dict1 == dict2
예제 #2
0
 def _build_instance(self):
     return FlowField(
         self.input_dict["wind_speed"], self.input_dict["wind_direction"],
         self.input_dict["wind_shear"], self.input_dict["wind_veer"],
         self.input_dict["turbulence_intensity"],
         self.input_dict["air_density"], self.input_dict["wake"],
         self.input_dict["turbine_map"])
예제 #3
0
def flow_field_fixture(sample_inputs_fixture):
    wake = Wake(sample_inputs_fixture.wake)
    turbine = Turbine(sample_inputs_fixture.turbine)
    turbine_map = TurbineMap(
        [0.0, 100.0], [0.0, 0.0], [copy.deepcopy(turbine), copy.deepcopy(turbine)]
    )
    farm_prop = sample_inputs_fixture.farm["properties"]
    wind_map = WindMap(
        wind_speed=farm_prop["wind_speed"],
        layout_array=(farm_prop["layout_x"], farm_prop["layout_y"]),
        wind_layout=(farm_prop["wind_x"], farm_prop["wind_y"]),
        turbulence_intensity=farm_prop["turbulence_intensity"],
        wind_direction=farm_prop["wind_direction"],
    )
    return FlowField(
        farm_prop["wind_shear"],
        farm_prop["wind_veer"],
        farm_prop["air_density"],
        wake,
        turbine_map,
        wind_map,
        farm_prop["specified_wind_height"],
    )
예제 #4
0
def full_flow_cc_solver(farm: Farm, flow_field: FlowField, flow_field_grid: FlowFieldGrid, model_manager: WakeModelManager) -> None:
    # Get the flow quantities and turbine performance
    turbine_grid_farm = copy.deepcopy(farm)
    turbine_grid_flow_field = copy.deepcopy(flow_field)

    turbine_grid_farm.construct_turbine_map()
    turbine_grid_farm.construct_turbine_fCts()
    turbine_grid_farm.construct_turbine_fCps()
    turbine_grid_farm.construct_turbine_power_interps()
    turbine_grid_farm.construct_hub_heights()
    turbine_grid_farm.construct_rotor_diameters()
    turbine_grid_farm.construct_turbine_TSRs()
    turbine_grid_farm.construc_turbine_pPs()
    turbine_grid_farm.construct_coordinates()

    turbine_grid = TurbineGrid(
        turbine_coordinates=turbine_grid_farm.coordinates,
        reference_turbine_diameter=turbine_grid_farm.rotor_diameters_sorted,
        wind_directions=turbine_grid_flow_field.wind_directions,
        wind_speeds=turbine_grid_flow_field.wind_speeds,
        grid_resolution=3,
    )
    turbine_grid_farm.expand_farm_properties(
        turbine_grid_flow_field.n_wind_directions, turbine_grid_flow_field.n_wind_speeds, turbine_grid.sorted_coord_indices
    )
    turbine_grid_flow_field.initialize_velocity_field(turbine_grid)
    turbine_grid_farm.initialize(turbine_grid.sorted_indices)
    cc_solver(turbine_grid_farm, turbine_grid_flow_field, turbine_grid, model_manager)

    ### Referring to the quantities from above, calculate the wake in the full grid

    # Use full flow_field here to use the full grid in the wake models
    deflection_model_args = model_manager.deflection_model.prepare_function(flow_field_grid, flow_field)
    deficit_model_args = model_manager.velocity_model.prepare_function(flow_field_grid, flow_field)

    v_wake = np.zeros_like(flow_field.v_initial_sorted)
    w_wake = np.zeros_like(flow_field.w_initial_sorted)
    turb_u_wake = np.zeros_like(flow_field.u_initial_sorted)

    shape = (farm.n_turbines,) + np.shape(flow_field.u_initial_sorted)
    Ctmp = np.zeros((shape))

    # Calculate the velocity deficit sequentially from upstream to downstream turbines
    for i in range(flow_field_grid.n_turbines):

        # Get the current turbine quantities
        x_i = np.mean(turbine_grid.x_sorted[:, :, i:i+1], axis=(3, 4))
        x_i = x_i[:, :, :, None, None]
        y_i = np.mean(turbine_grid.y_sorted[:, :, i:i+1], axis=(3, 4))        
        y_i = y_i[:, :, :, None, None]
        z_i = np.mean(turbine_grid.z_sorted[:, :, i:i+1], axis=(3, 4))
        z_i = z_i[:, :, :, None, None]

        u_i = turbine_grid_flow_field.u_sorted[:, :, i:i+1]
        v_i = turbine_grid_flow_field.v_sorted[:, :, i:i+1]

        turb_avg_vels = average_velocity(turbine_grid_flow_field.u_sorted)
        turb_Cts = Ct(
            velocities=turb_avg_vels,
            yaw_angle=turbine_grid_farm.yaw_angles_sorted,
            fCt=turbine_grid_farm.turbine_fCts,
            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,
        )
        turb_Cts = turb_Cts[:, :, :, None, None]

        axial_induction_i = axial_induction(
            velocities=turbine_grid_flow_field.u_sorted,
            yaw_angle=turbine_grid_farm.yaw_angles_sorted,
            fCt=turbine_grid_farm.turbine_fCts,
            turbine_type_map=turbine_grid_farm.turbine_type_map_sorted,
            ix_filter=[i],
        )
        axial_induction_i = axial_induction_i[:, :, :, None, None]

        turbulence_intensity_i = turbine_grid_flow_field.turbulence_intensity_field[:, :, i:i+1]
        yaw_angle_i = turbine_grid_farm.yaw_angles_sorted[:, :, i:i+1, None, None]
        hub_height_i = turbine_grid_farm.hub_heights_sorted[: ,:, i:i+1, None, None]
        rotor_diameter_i = turbine_grid_farm.rotor_diameters_sorted[: ,:, i:i+1, None, None]
        TSR_i = turbine_grid_farm.TSRs_sorted[: ,:, i:i+1, None, None]

        effective_yaw_i = np.zeros_like(yaw_angle_i)
        effective_yaw_i += yaw_angle_i

        if model_manager.enable_secondary_steering:
            added_yaw = wake_added_yaw(
                u_i,
                v_i,
                turbine_grid_flow_field.u_initial_sorted,
                turbine_grid.y_sorted[:, :, i:i+1] - y_i,
                turbine_grid.z_sorted[:, :, i:i+1],
                rotor_diameter_i,
                hub_height_i,
                turb_Cts[:, :, i:i+1],
                TSR_i,
                axial_induction_i,
                scale=2.0
            )
            effective_yaw_i += added_yaw

        # Model calculations
        # NOTE: exponential
        deflection_field = model_manager.deflection_model.function(
            x_i,
            y_i,
            effective_yaw_i,
            turbulence_intensity_i,
            turb_Cts[:, :, i:i+1],
            rotor_diameter_i,
            **deflection_model_args
        )

        if model_manager.enable_transverse_velocities:
            v_wake, w_wake = calculate_transverse_velocity(
                u_i,
                flow_field.u_initial_sorted,
                flow_field_grid.x_sorted - x_i,
                flow_field_grid.y_sorted - y_i,
                flow_field_grid.z_sorted,
                rotor_diameter_i,
                hub_height_i,
                yaw_angle_i,
                turb_Cts[:, :, i:i+1],
                TSR_i,
                axial_induction_i,
                scale=2.0
            )

        # NOTE: exponential
        turb_u_wake, Ctmp = model_manager.velocity_model.function(
            i,
            x_i,
            y_i,
            z_i,
            u_i,
            deflection_field,
            yaw_angle_i,
            turbine_grid_flow_field.turbulence_intensity_field,
            turb_Cts,
            turbine_grid_farm.rotor_diameters_sorted[:, :, :, None, None],
            turb_u_wake,
            Ctmp,
            **deficit_model_args
        )

        flow_field.v_sorted += v_wake
        flow_field.w_sorted += w_wake
    flow_field.u_sorted = flow_field.u_initial_sorted - turb_u_wake
예제 #5
0
def sequential_solver(farm: Farm, flow_field: FlowField, grid: TurbineGrid, model_manager: WakeModelManager) -> None:
    # Algorithm
    # For each turbine, calculate its effect on every downstream turbine.
    # For the current turbine, we are calculating the deficit that it adds to downstream turbines.
    # Integrate this into the main data structure.
    # Move on to the next turbine.

    # <<interface>>
    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)
    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)

    # This is u_wake
    wake_field = np.zeros_like(flow_field.u_initial_sorted)
    v_wake = np.zeros_like(flow_field.v_initial_sorted)
    w_wake = np.zeros_like(flow_field.w_initial_sorted)

    turbine_turbulence_intensity = flow_field.turbulence_intensity * np.ones((flow_field.n_wind_directions, flow_field.n_wind_speeds, farm.n_turbines, 1, 1))
    ambient_turbulence_intensity = flow_field.turbulence_intensity

    # Calculate the velocity deficit sequentially from upstream to downstream turbines
    for i in range(grid.n_turbines):

        # Get the current turbine quantities
        x_i = np.mean(grid.x_sorted[:, :, i:i+1], axis=(3, 4))
        x_i = x_i[:, :, :, None, None]
        y_i = np.mean(grid.y_sorted[:, :, i:i+1], axis=(3, 4))        
        y_i = y_i[:, :, :, None, None]
        z_i = np.mean(grid.z_sorted[:, :, i:i+1], axis=(3, 4))
        z_i = z_i[:, :, :, None, None]

        u_i = flow_field.u_sorted[:, :, i:i+1]
        v_i = flow_field.v_sorted[:, :, i:i+1]

        ct_i = Ct(
            velocities=flow_field.u_sorted,
            yaw_angle=farm.yaw_angles_sorted,
            fCt=farm.turbine_fCts,
            turbine_type_map=farm.turbine_type_map_sorted,
            ix_filter=[i],
        )
        ct_i = ct_i[:, :, 0:1, None, None]  # Since we are filtering for the i'th turbine in the Ct function, get the first index here (0:1)
        axial_induction_i = axial_induction(
            velocities=flow_field.u_sorted,
            yaw_angle=farm.yaw_angles_sorted,
            fCt=farm.turbine_fCts,
            turbine_type_map=farm.turbine_type_map_sorted,
            ix_filter=[i],
        )
        axial_induction_i = axial_induction_i[:, :, 0:1, None, None]    # Since we are filtering for the i'th turbine in the axial induction function, get the first index here (0:1)
        turbulence_intensity_i = turbine_turbulence_intensity[:, :, i:i+1]
        yaw_angle_i = farm.yaw_angles_sorted[:, :, i:i+1, None, None]
        hub_height_i = farm.hub_heights_sorted[: ,:, i:i+1, None, None]
        rotor_diameter_i = farm.rotor_diameters_sorted[: ,:, i:i+1, None, None]
        TSR_i = farm.TSRs_sorted[: ,:, i:i+1, None, None]

        effective_yaw_i = np.zeros_like(yaw_angle_i)
        effective_yaw_i += yaw_angle_i

        if model_manager.enable_secondary_steering:
            added_yaw = wake_added_yaw(
                u_i,
                v_i,
                flow_field.u_initial_sorted,
                grid.y_sorted[:, :, i:i+1] - y_i,
                grid.z_sorted[:, :, i:i+1],
                rotor_diameter_i,
                hub_height_i,
                ct_i,
                TSR_i,
                axial_induction_i
            )
            effective_yaw_i += added_yaw

        # Model calculations
        # NOTE: exponential
        deflection_field = model_manager.deflection_model.function(
            x_i,
            y_i,
            effective_yaw_i,
            turbulence_intensity_i,
            ct_i,
            rotor_diameter_i,
            **deflection_model_args
        )

        if model_manager.enable_transverse_velocities:
            v_wake, w_wake = calculate_transverse_velocity(
                u_i,
                flow_field.u_initial_sorted,
                grid.x_sorted - x_i,
                grid.y_sorted - y_i,
                grid.z_sorted,
                rotor_diameter_i,
                hub_height_i,
                yaw_angle_i,
                ct_i,
                TSR_i,
                axial_induction_i
            )

        if model_manager.enable_yaw_added_recovery:
            I_mixing = yaw_added_turbulence_mixing(
                u_i,
                turbulence_intensity_i,
                v_i,
                flow_field.w_sorted[:, :, i:i+1],
                v_wake[:, :, i:i+1],
                w_wake[:, :, i:i+1],
            )
            gch_gain = 2
            turbine_turbulence_intensity[:, :, i:i+1] = turbulence_intensity_i + gch_gain * I_mixing

        # NOTE: exponential
        velocity_deficit = model_manager.velocity_model.function(
            x_i,
            y_i,
            z_i,
            axial_induction_i,
            deflection_field,
            yaw_angle_i,
            turbulence_intensity_i,
            ct_i,
            hub_height_i,
            rotor_diameter_i,
            **deficit_model_args
        )

        wake_field = model_manager.combination_model.function(
            wake_field,
            velocity_deficit * flow_field.u_initial_sorted
        )

        wake_added_turbulence_intensity = model_manager.turbulence_model.function(
            ambient_turbulence_intensity,
            grid.x_sorted,
            x_i,
            rotor_diameter_i,
            axial_induction_i
        )

        # Calculate wake overlap for wake-added turbulence (WAT)
        area_overlap = np.sum(velocity_deficit * flow_field.u_initial_sorted > 0.05, axis=(3, 4)) / (grid.grid_resolution * grid.grid_resolution)
        area_overlap = area_overlap[:, :, :, None, None]

        # Modify wake added turbulence by wake area overlap
        downstream_influence_length = 15 * rotor_diameter_i
        ti_added = (
            area_overlap
            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)
            * np.array(grid.x_sorted > x_i)
            * np.array(np.abs(y_i - grid.y_sorted) < 2 * rotor_diameter_i)
            * np.array(grid.x_sorted <= downstream_influence_length + x_i)
        )

        # Combine turbine TIs with WAT
        turbine_turbulence_intensity = np.maximum( np.sqrt( ti_added ** 2 + ambient_turbulence_intensity ** 2 ) , turbine_turbulence_intensity )

        flow_field.u_sorted = flow_field.u_initial_sorted - wake_field
        flow_field.v_sorted += v_wake
        flow_field.w_sorted += w_wake

    flow_field.turbulence_intensity_field = np.mean(turbine_turbulence_intensity, axis=(3,4))
    flow_field.turbulence_intensity_field = flow_field.turbulence_intensity_field[:,:,:,None,None]
예제 #6
0
def cc_solver(farm: Farm, flow_field: FlowField, grid: TurbineGrid, model_manager: WakeModelManager) -> None:

    # <<interface>>
    deflection_model_args = model_manager.deflection_model.prepare_function(grid, flow_field)
    deficit_model_args = model_manager.velocity_model.prepare_function(grid, flow_field)

    # This is u_wake
    v_wake = np.zeros_like(flow_field.v_initial_sorted)
    w_wake = np.zeros_like(flow_field.w_initial_sorted)
    turb_u_wake = np.zeros_like(flow_field.u_initial_sorted)
    turb_inflow_field = copy.deepcopy(flow_field.u_initial_sorted)

    turbine_turbulence_intensity = flow_field.turbulence_intensity * np.ones((flow_field.n_wind_directions, flow_field.n_wind_speeds, farm.n_turbines, 1, 1))
    ambient_turbulence_intensity = flow_field.turbulence_intensity

    shape = (farm.n_turbines,) + np.shape(flow_field.u_initial_sorted)
    Ctmp = np.zeros((shape))
    # Ctmp = np.zeros((len(x_coord), len(wd), len(ws), len(x_coord), y_ngrid, z_ngrid))
    
    sigma_i = np.zeros((shape))
    # sigma_i = np.zeros((len(x_coord), len(wd), len(ws), len(x_coord), y_ngrid, z_ngrid))

    # Calculate the velocity deficit sequentially from upstream to downstream turbines
    for i in range(grid.n_turbines):

        # Get the current turbine quantities
        x_i = np.mean(grid.x_sorted[:, :, i:i+1], axis=(3, 4))
        x_i = x_i[:, :, :, None, None]
        y_i = np.mean(grid.y_sorted[:, :, i:i+1], axis=(3, 4))        
        y_i = y_i[:, :, :, None, None]
        z_i = np.mean(grid.z_sorted[:, :, i:i+1], axis=(3, 4))
        z_i = z_i[:, :, :, None, None]

        mask2 = np.array(grid.x_sorted < x_i + 0.01) * np.array(grid.x_sorted > x_i - 0.01) * np.array(grid.y_sorted < y_i + 0.51*126.0) * np.array(grid.y_sorted > y_i - 0.51*126.0)
        # mask2 = np.logical_and(np.logical_and(np.logical_and(grid.x_sorted < x_i + 0.01, grid.x_sorted > x_i - 0.01), grid.y_sorted < y_i + 0.51*126.0), grid.y_sorted > y_i - 0.51*126.0)
        turb_inflow_field = turb_inflow_field * ~mask2 + (flow_field.u_initial_sorted - turb_u_wake) * mask2

        turb_avg_vels = average_velocity(turb_inflow_field)
        turb_Cts = Ct(
            turb_avg_vels,
            farm.yaw_angles_sorted,
            farm.turbine_fCts,
            turbine_type_map=farm.turbine_type_map_sorted,
        )
        turb_Cts = turb_Cts[:, :, :, None, None]     
        turb_aIs = axial_induction(
            turb_avg_vels,
            farm.yaw_angles_sorted,
            farm.turbine_fCts,
            turbine_type_map=farm.turbine_type_map_sorted,
            ix_filter=[i],
        )
        turb_aIs = turb_aIs[:, :, :, None, None]

        u_i = turb_inflow_field[:, :, i:i+1]
        v_i = flow_field.v_sorted[:, :, i:i+1]

        axial_induction_i = axial_induction(
            velocities=flow_field.u_sorted,
            yaw_angle=farm.yaw_angles_sorted,
            fCt=farm.turbine_fCts,
            turbine_type_map=farm.turbine_type_map_sorted,
            ix_filter=[i],
        )

        axial_induction_i = axial_induction_i[:, :, :, None, None]

        turbulence_intensity_i = turbine_turbulence_intensity[:, :, i:i+1]
        yaw_angle_i = farm.yaw_angles_sorted[:, :, i:i+1, None, None]
        hub_height_i = farm.hub_heights_sorted[: ,:, i:i+1, None, None]
        rotor_diameter_i = farm.rotor_diameters_sorted[: ,:, i:i+1, None, None]
        TSR_i = farm.TSRs_sorted[: ,:, i:i+1, None, None]

        effective_yaw_i = np.zeros_like(yaw_angle_i)
        effective_yaw_i += yaw_angle_i

        if model_manager.enable_secondary_steering:
            added_yaw = wake_added_yaw(
                u_i,
                v_i,
                flow_field.u_initial_sorted,
                grid.y_sorted[:, :, i:i+1] - y_i,
                grid.z_sorted[:, :, i:i+1],
                rotor_diameter_i,
                hub_height_i,
                turb_Cts[:, :, i:i+1],
                TSR_i,
                axial_induction_i,
                scale=2.0,
            )
            effective_yaw_i += added_yaw

        # Model calculations
        # NOTE: exponential
        deflection_field = model_manager.deflection_model.function(
            x_i,
            y_i,
            effective_yaw_i,
            turbulence_intensity_i,
            turb_Cts[:, :, i:i+1],
            rotor_diameter_i,
            **deflection_model_args
        )

        if model_manager.enable_transverse_velocities:
            v_wake, w_wake = calculate_transverse_velocity(
                u_i,
                flow_field.u_initial_sorted,
                grid.x_sorted - x_i,
                grid.y_sorted - y_i,
                grid.z_sorted,
                rotor_diameter_i,
                hub_height_i,
                yaw_angle_i,
                turb_Cts[:, :, i:i+1],
                TSR_i,
                axial_induction_i,
                scale=2.0
            )

        if model_manager.enable_yaw_added_recovery:
            I_mixing = yaw_added_turbulence_mixing(
                u_i,
                turbulence_intensity_i,
                v_i,
                flow_field.w_sorted[:, :, i:i+1],
                v_wake[:, :, i:i+1],
                w_wake[:, :, i:i+1],
            )
            gch_gain = 1.0
            turbine_turbulence_intensity[:, :, i:i+1] = turbulence_intensity_i + gch_gain * I_mixing

        turb_u_wake, Ctmp = model_manager.velocity_model.function(
            i,
            x_i,
            y_i,
            z_i,
            u_i,
            deflection_field,
            yaw_angle_i,
            turbine_turbulence_intensity,
            turb_Cts,
            farm.rotor_diameters_sorted[:, :, :, None, None],
            turb_u_wake,
            Ctmp,
            **deficit_model_args
        )

        wake_added_turbulence_intensity = model_manager.turbulence_model.function(
            ambient_turbulence_intensity,
            grid.x_sorted,
            x_i,
            rotor_diameter_i,
            turb_aIs
        )

        # Calculate wake overlap for wake-added turbulence (WAT)
        area_overlap = 1 - np.sum(turb_u_wake <= 0.05, axis=(3, 4)) / (grid.grid_resolution * grid.grid_resolution)
        area_overlap = area_overlap[:, :, :, None, None]

        # Modify wake added turbulence by wake area overlap
        downstream_influence_length = 15 * rotor_diameter_i
        ti_added = (
            area_overlap
            * np.nan_to_num(wake_added_turbulence_intensity, posinf=0.0)
            * np.array(grid.x_sorted > x_i)
            * np.array(np.abs(y_i - grid.y_sorted) < 2 * rotor_diameter_i)
            * np.array(grid.x_sorted <= downstream_influence_length + x_i)
        )

        # Combine turbine TIs with WAT
        turbine_turbulence_intensity = np.maximum( np.sqrt( ti_added ** 2 + ambient_turbulence_intensity ** 2 ) , turbine_turbulence_intensity )

        flow_field.v_sorted += v_wake
        flow_field.w_sorted += w_wake
    flow_field.u_sorted = turb_inflow_field

    flow_field.turbulence_intensity_field = np.mean(turbine_turbulence_intensity, axis=(3,4))
    flow_field.turbulence_intensity_field = flow_field.turbulence_intensity_field[:,:,:,None,None]
예제 #7
0
def flow_field_fixture(sample_inputs_fixture):
    flow_field_dict = sample_inputs_fixture.flow_field
    return FlowField.from_dict(flow_field_dict)