def test_rotation_off_origin(vec3_fixture): """ A vector rotation by pi on the 3rd (z) axis about a center of rotation located midway between the vector and the origin should result in a vector located at the origin. Similarly, a vector rotation by pi on the 3rd (z) axis about a center of rotation located and 1.5x the vector should result in a vector located at 2x the original value. """ from floris.utilities import Vec3 center_of_rotation = Vec3(vec3_fixture.x1 / 2.0, vec3_fixture.x2 / 2.0, 0.0) vec3_fixture.rotate_on_x3(180, center_of_rotation) assert pytest.approx(vec3_fixture.x1prime) == 0.0 assert pytest.approx(vec3_fixture.x2prime) == 0.0 assert pytest.approx(vec3_fixture.x3prime) == 0.0 center_of_rotation = Vec3(1.5 * vec3_fixture.x1, 1.5 * vec3_fixture.x2, 0.0) vec3_fixture.rotate_on_x3(180, center_of_rotation) assert pytest.approx(vec3_fixture.x1prime) == 2 * vec3_fixture.x1 assert pytest.approx(vec3_fixture.x2prime) == 2 * vec3_fixture.x2 assert pytest.approx(vec3_fixture.x3prime) == 0.0
def test_rotated(): """ The class should rotate a turbine when given an angle and center of rotation The resulting map should contain turbines at (0, 0) and (-100, 0) when the sample map is rotated by pi about (0, 0). """ test_class = TurbineMapTest() rotated_map = test_class.instance.rotated(180, Vec3(0, 0, 0)) baseline_coordinates = [Vec3(0.0, 0.0, 0.0), Vec3(-100.0, 0.0, 0.0)] for i, coordinate in enumerate(rotated_map.coords): assert pytest.approx(coordinate == baseline_coordinates[i])
def test_sorted_in_x_as_list(): """ The class should sort its Turbines in ascending order based on the x-component of their associated Vec3. The returned object should be [(Vec3, Turbine)]. The resulting list should be ordered as [(0.0, 0.0, 0.0), (100.0, 0.0, 0.0)] when the sample data is sorted. """ test_class = TurbineMapTest() sorted_map = test_class.instance.sorted_in_x_as_list() baseline_coordinates = [Vec3(0.0, 0.0, 0.0), Vec3(-100.0, 0.0, 0.0)] for i, element in enumerate(sorted_map): coordinate = element[0] assert pytest.approx(coordinate == baseline_coordinates[i])
def test_rotation_on_origin(): """ The class should rotate by 180 on the 3rd (z) axis at the origin like so: < 1, 2, 3 > becomes < -1, -2, ,3 > """ test_class = Vec3Test() baseline = Vec3(-1, -2, 3) vec3 = Vec3(test_class.x, test_class.y, test_class.z) vec3.rotate_on_x3(180) assert \ vec3.x1prime == pytest.approx(baseline.x1) and \ vec3.x2prime == pytest.approx(baseline.x2) and \ vec3.x3prime == pytest.approx(baseline.x3)
def test_rotation_off_origin(): """ The class should rotate by 180 on the 3rd (z) axis about center of rotation at <0, 10, 0> like so: < 1, 2, 3 > becomes < -1, -2, ,3 > """ test_class = Vec3Test() baseline = Vec3(5, 4, 3) center_of_rotation = Vec3(3, 3, 0) vec3 = Vec3(test_class.x, test_class.y, test_class.z) vec3.rotate_on_x3(180, center_of_rotation) assert \ vec3.x1prime == pytest.approx(baseline.x1) and \ vec3.x2prime == pytest.approx(baseline.x2) and \ vec3.x3prime == pytest.approx(baseline.x3)
def test_instantiation_with_list(): """ The class should initialize with a list of length 3. The class should raise an exception if the length of points is not 3. """ vec3 = Vec3([1, 2, 3]) assert vec3.x1 == 1.0 assert vec3.x2 == 2.0 assert vec3.x3 == 3.0 with pytest.raises(Exception): vec3 = Vec3([1, 2, 3, 4]) with pytest.raises(Exception): vec3 = Vec3([1, 2])
def test_farm_init_homogenous_turbines(): farm_data = SampleInputs().farm turbine_data = SampleInputs().turbine layout_x = farm_data["layout_x"] layout_y = farm_data["layout_y"] coordinates = np.array([ Vec3([x, y, turbine_data["hub_height"]]) for x, y in zip(layout_x, layout_y) ]) farm = Farm(layout_x=layout_x, layout_y=layout_y, turbine_type=[turbine_data]) # TODO: these all pass on mac and fail on linux # turbine_type=[turbine_data] # turbine_type=[turbine_data["turbine_type"]] farm.construct_hub_heights() farm.construct_coordinates() farm.set_yaw_angles(N_WIND_DIRECTIONS, N_WIND_SPEEDS) # Check initial values np.testing.assert_array_equal(farm.coordinates, coordinates) assert isinstance(farm.layout_x, np.ndarray) assert isinstance(farm.layout_y, np.ndarray)
def test_equality(vec3_fixture): """ The overloaded equality operator should compare each component to the same components of the right-hand-side value. """ rhs = Vec3([vec3_fixture.x1, vec3_fixture.x2, vec3_fixture.x3]) assert vec3_fixture == rhs rhs = Vec3([vec3_fixture.x1 + 1, vec3_fixture.x2, vec3_fixture.x3]) assert vec3_fixture != rhs rhs = Vec3([vec3_fixture.x1, vec3_fixture.x2 + 1, vec3_fixture.x3]) assert vec3_fixture != rhs rhs = Vec3([vec3_fixture.x1, vec3_fixture.x2, vec3_fixture.x3 + 1]) assert vec3_fixture != rhs
def test_string_formatting(): """ The class has a default string representation and allows for custom string formatting. """ from floris.utilities import Vec3 vec3 = Vec3([1, 2, 3], string_format="{:6.2f}") assert str(vec3) == " 1.00 2.00 3.00"
def test_equality(vec3_fixture): """ The overloaded equality operator should compare each component to the same components of the right-hand-side value. """ from floris.utilities import Vec3 rhs = Vec3(vec3_fixture.x1, vec3_fixture.x2, vec3_fixture.x3) assert vec3_fixture == rhs rhs = Vec3(vec3_fixture.x1 + 1, vec3_fixture.x2, vec3_fixture.x3) assert vec3_fixture != rhs rhs = Vec3(vec3_fixture.x1, vec3_fixture.x2 + 1, vec3_fixture.x3) assert vec3_fixture != rhs rhs = Vec3(vec3_fixture.x1, vec3_fixture.x2, vec3_fixture.x3 + 1) assert vec3_fixture != rhs
def test_instantiation_with_list(): """ The class should initialize with a list of length 3. """ from floris.utilities import Vec3 vec3 = Vec3([1, 2, 3]) assert vec3 is not None assert vec3.x1 == 1 assert vec3.x2 == 2 assert vec3.x3 == 3
def test_instantiation_with_args(): """ The class should initialize with three positional arguments. """ from floris.utilities import Vec3 vec3 = Vec3(1, 2, 3) assert vec3 is not None assert vec3.x1 == 1 assert vec3.x2 == 2 assert vec3.x3 == 3
def test_instantiation_with_list(): """ The class should initialize with a list of length 3. """ test_class = Vec3Test() vec3 = Vec3(test_class.list) assert vec3 is not None and \ vec3.x1 == test_class.x and \ vec3.x2 == test_class.y and \ vec3.x3 == test_class.z
def test_instantiation_with_args(): """ The class should initialize with three positional arguments. """ test_class = Vec3Test() vec3 = Vec3(test_class.x, test_class.y, test_class.z) assert vec3 is not None and \ vec3.x1 == test_class.x and \ vec3.x2 == test_class.y and \ vec3.x3 == test_class.z
def flow_field_grid_fixture(sample_inputs_fixture) -> FlowFieldGrid: turbine_coordinates = [ Vec3(c) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS)) ] rotor_diameters = ROTOR_DIAMETER * np.ones( (N_WIND_DIRECTIONS, N_WIND_SPEEDS, N_TURBINES)) return FlowFieldGrid(turbine_coordinates=turbine_coordinates, reference_turbine_diameter=rotor_diameters, wind_directions=np.array(WIND_DIRECTIONS), wind_speeds=np.array(WIND_SPEEDS), grid_resolution=[3, 2, 2])
def test_coordinates(): """ The class should return a dict_items containing all items """ test_class = TurbineMapTest() hub_height = test_class.turbines[0].hub_height coordinates = [ [test_class.coordinates[0][0], test_class.coordinates[1][0], hub_height], [test_class.coordinates[0][1], test_class.coordinates[1][1], hub_height] ] baseline_coordinates = [Vec3(c) for c in coordinates] test_coordinates = test_class.instance.coords for (test, baseline) in zip(test_coordinates, baseline_coordinates): assert test == baseline
def turbine_grid_fixture(sample_inputs_fixture) -> TurbineGrid: turbine_coordinates = [ Vec3(c) for c in list(zip(X_COORDS, Y_COORDS, Z_COORDS)) ] # TODO: The TurbineGrid requires that the rotor diameters be 1d but the Farm constructs them as 3d # Can we make this consistent? rotor_diameters = ROTOR_DIAMETER * np.ones((N_TURBINES)) return TurbineGrid(turbine_coordinates=turbine_coordinates, reference_turbine_diameter=rotor_diameters, wind_directions=np.array(WIND_DIRECTIONS), wind_speeds=np.array(WIND_SPEEDS), grid_resolution=TURBINE_GRID_RESOLUTION)
def test_add(vec3_fixture): """ The overloaded operator should accept a scalar value and apply it to all components. It should also accept a Vec3 value and perform an element-wise operation. """ scalar = vec3_fixture + 1 assert scalar.x1 == vec3_fixture.x1 + 1 assert scalar.x2 == vec3_fixture.x2 + 1 assert scalar.x3 == vec3_fixture.x3 + 1 vector = vec3_fixture + Vec3([2, 3, 4]) assert vector.x1 == vec3_fixture.x1 + 2 assert vector.x2 == vec3_fixture.x2 + 3 assert vector.x3 == vec3_fixture.x3 + 4
def test_subtract(vec3_fixture): """ The overloaded operator should accept a scalar value and apply it to all components. It should also accept a Vec3 value and perform an element-wise operation. """ scalar = vec3_fixture - 1 assert scalar.x1 == vec3_fixture.x1 - 1 assert scalar.x2 == vec3_fixture.x2 - 1 assert scalar.x3 == vec3_fixture.x3 - 1 vector = vec3_fixture - Vec3([2, 3, 4]) assert vector.x1 == vec3_fixture.x1 - 2 assert vector.x2 == vec3_fixture.x2 - 3 assert vector.x3 == vec3_fixture.x3 - 4
def test_multiply(vec3_fixture): """ The overloaded operator should accept a scalar value and apply it to all components. It should also accept a Vec3 value and perform an element-wise operation. """ scalar = vec3_fixture * 10 assert scalar.x1 == vec3_fixture.x1 * 10 assert scalar.x2 == vec3_fixture.x2 * 10 assert scalar.x3 == vec3_fixture.x3 * 10 vector = vec3_fixture * Vec3([2, 3, 4]) assert vector.x1 == vec3_fixture.x1 * 2 assert vector.x2 == vec3_fixture.x2 * 3 assert vector.x3 == vec3_fixture.x3 * 4
def test_divide(vec3_fixture): """ The overloaded operator should accept a scalar value and apply it to all components. It should also accept a Vec3 value and perform an element-wise operation. """ scalar = vec3_fixture / 10.0 np.testing.assert_allclose(scalar.x1, vec3_fixture.x1 / 10.0) np.testing.assert_allclose(scalar.x2, vec3_fixture.x2 / 10.0) np.testing.assert_allclose(scalar.x3, vec3_fixture.x3 / 10.0) vector = vec3_fixture / Vec3([10, 100, 1000]) np.testing.assert_allclose(vector.x1, vec3_fixture.x1 / 10.0) np.testing.assert_allclose(vector.x2, vec3_fixture.x2 / 100.0) np.testing.assert_allclose(vector.x3, vec3_fixture.x3 / 1000.0)
def test_divide(vec3_fixture): """ The overloaded operator should accept a scalar value and apply it to all components. It should also accept a Vec3 value and perform an element-wise operation. """ from floris.utilities import Vec3 scalar = vec3_fixture / 10.0 assert scalar.x1 == vec3_fixture.x1 / 10.0 assert scalar.x2 == vec3_fixture.x2 / 10.0 assert scalar.x3 == vec3_fixture.x3 / 10.0 vector = vec3_fixture / Vec3(10, 100, 1000) assert vector.x1 == vec3_fixture.x1 / 10.0 assert vector.x2 == vec3_fixture.x2 / 100.0 assert vector.x3 == vec3_fixture.x3 / 1000.0
def test_turbinegrid_dynamic_properties(turbine_grid_fixture): assert turbine_grid_fixture.n_turbines == N_TURBINES assert turbine_grid_fixture.n_wind_speeds == N_WIND_SPEEDS assert turbine_grid_fixture.n_wind_directions == N_WIND_DIRECTIONS # TODO: @Rob @Chris This breaks n_turbines since the validator is not run. Is this case ok? Do we enforce that turbine_coordinates must be set by =? # turbine_grid_fixture.turbine_coordinates.append(Vec3([100.0, 200.0, 300.0])) # assert turbine_grid_fixture.n_turbines == N_TURBINES + 1 turbine_grid_fixture.turbine_coordinates = [ *turbine_grid_fixture.turbine_coordinates, Vec3([100.0, 200.0, 300.0]) ] assert turbine_grid_fixture.n_turbines == N_TURBINES + 1 turbine_grid_fixture.wind_speeds = [*turbine_grid_fixture.wind_speeds, 0.0] assert turbine_grid_fixture.n_wind_speeds == N_WIND_SPEEDS + 1 turbine_grid_fixture.wind_directions = [ *turbine_grid_fixture.wind_directions, 0.0 ] assert turbine_grid_fixture.n_wind_directions == N_WIND_DIRECTIONS + 1
) # our domain does _not_ include boundary points else: zrange = (zhub - 1 - buf, zhub + 1 + buf) Nx = int((xrange[1] - xrange[0]) / spacing) + 1 Ny = int((yrange[1] - yrange[0]) / spacing) + 1 Nz = int((zrange[1] - zrange[0]) / spacing) + 1 N = Nx * Ny * Nz print('Nx,Ny,Nz =', Nx, Ny, Nz) x1 = (np.arange(Nx) * spacing + xrange[0]) * R y1 = (np.arange(Ny) * spacing + yrange[0]) * R z1 = (np.arange(Nz) * spacing + zrange[0]) * R print('Calculating floris wake') fi.floris.farm.flow_field.reinitialize_flow_field( with_resolution=Vec3(Nx, Ny, Nz), bounds_to_set=list(xrange) + list(yrange) + list(zrange), ) fi.calculate_wake() print('Setting up poisson system (N={:d})'.format(N)) A = pyamg.gallery.poisson((Nx, Ny, Nz), format='csr') # RHS u0 = fi.floris.farm.flow_field.u du0_dx = np.empty(u0.shape) du0_dx[1:-1, :, :] = (u0[2:, :, :] - u0[:-2, :, :]) / (2 * spacing) du0_dx[0, :, :] = (u0[1, :, :] - u0[0, :, :]) / spacing du0_dx[-1, :, :] = (u0[-1, :, :] - u0[-2, :, :]) / spacing b = -du0_dx.ravel()
def vec3_fixture(): return Vec3([4, 4, 0])
def vec3_fixture(): from floris.utilities import Vec3 return Vec3(4, 4, 0)
def construct_coordinates(self): self.coordinates = np.array( [Vec3([x, y, z]) for x, y, z in zip(self.layout_x, self.layout_y, self.hub_heights)] )