def test_shadows_coords_left_right_of_cut_point(): """Test that coords left and right of cut point are created correctly""" # Ground inputs shadow_coords = np.array( [[[[0], [0]], [[2], [0]]], [[[3], [0]], [[5], [0]]]], dtype=float) overlap = [False] # --- Create timeseries ground cut_point = TsPointCoords([2.5], [0]) ts_ground = TsGround.from_ordered_shadows_coords( shadow_coords, flag_overlap=overlap, cut_point_coords=[cut_point]) # Get left and right shadows shadows_left = ts_ground.shadow_coords_left_of_cut_point(0) shadows_right = ts_ground.shadow_coords_right_of_cut_point(0) # Reformat for testing shadows_left = [shadow.as_array for shadow in shadows_left] shadows_right = [shadow.as_array for shadow in shadows_right] expected_shadows_left = [ shadow_coords[0], [cut_point.as_array, cut_point.as_array] ] expected_shadows_right = [[cut_point.as_array, cut_point.as_array], shadow_coords[1]] # Test that correct np.testing.assert_allclose(shadows_left, expected_shadows_left) np.testing.assert_allclose(shadows_right, expected_shadows_right) # --- Case where pv rows are flat, cut point are inf cut_point = TsPointCoords([np.inf], [0]) ts_ground = TsGround.from_ordered_shadows_coords( shadow_coords, flag_overlap=overlap, cut_point_coords=[cut_point]) # Get right shadows shadows_right = ts_ground.shadow_coords_right_of_cut_point(0) # Test that correct maxi = MAX_X_GROUND expected_shadows_right = np.array([[[[maxi], [0.]], [[maxi], [0.]]], [[[maxi], [0.]], [[maxi], [0.]]]]) shadows_right = [shadow.as_array for shadow in shadows_right] np.testing.assert_allclose(shadows_right, expected_shadows_right) # --- Case where pv rows are flat, cut point are - inf cut_point = TsPointCoords([-np.inf], [0]) ts_ground = TsGround.from_ordered_shadows_coords( shadow_coords, flag_overlap=overlap, cut_point_coords=[cut_point]) # Get left shadows shadows_left = ts_ground.shadow_coords_left_of_cut_point(0) # Test that correct mini = MIN_X_GROUND expected_shadows_left = np.array([[[[mini], [0.]], [[mini], [0.]]], [[[mini], [0.]], [[mini], [0.]]]]) shadows_left = [shadow.as_array for shadow in shadows_left] np.testing.assert_allclose(shadows_left, expected_shadows_left)
def test_ts_ground_overlap(): shadow_coords = np.array([[[[0, 0], [0, 0]], [[2, 1], [0, 0]]], [[[1, 2], [0, 0]], [[5, 5], [0, 0]]]]) overlap = [True, False] # Test without overlap ts_ground = TsGround.from_ordered_shadows_coords(shadow_coords) np.testing.assert_allclose(ts_ground.shadow_elements[0].b2.x, [2, 1]) # Test with overlap ts_ground = TsGround.from_ordered_shadows_coords(shadow_coords, flag_overlap=overlap) np.testing.assert_allclose(ts_ground.shadow_elements[0].b2.x, [1, 1])
def fit(self, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth): """Fit the ordered PV array to the list of solar and surface angles. All intermediate PV array results necessary to build the geometries will be calculated here using vectorization as much as possible. Intemediate results include: PV row coordinates for all timestamps, ground element coordinates for all timestamps, cases of direct shading, ... Parameters ---------- solar_zenith : array-like or float Solar zenith angles [deg] solar_azimuth : array-like or float Solar azimuth angles [deg] surface_tilt : array-like or float Surface tilt angles, from 0 to 180 [deg] surface_azimuth : array-like or float Surface azimuth angles [deg] """ self.n_states = len(solar_zenith) # Calculate rotation angles rotation_vec = _get_rotation_from_tilt_azimuth(surface_azimuth, self.axis_azimuth, surface_tilt) # Save rotation vector self.rotation_vec = rotation_vec # Calculate the solar 2D vectors for all timestamps self.solar_2d_vectors = _get_solar_2d_vectors(solar_zenith, solar_azimuth, self.axis_azimuth) # Calculate the angle made by 2D sun vector and x-axis alpha_vec = np.arctan2(self.solar_2d_vectors[1], self.solar_2d_vectors[0]) # Calculate the coordinates of all PV rows for all timestamps self._calculate_pvrow_elements_coords(alpha_vec, rotation_vec) # Calculate ground elements coordinates for all timestamps self.ts_ground = TsGround.from_ts_pvrows_and_angles( self.ts_pvrows, alpha_vec, rotation_vec, y_ground=self.y_ground, flag_overlap=self.has_direct_shading, param_names=self.param_names) # Save surface rotation angles self.rotation_vec = rotation_vec # Index all timeseries surfaces self._index_all_ts_surfaces()
def test_ts_ground_to_geometry(): # There should be an overlap shadow_coords = np.array([[[[0, 0], [0, 0]], [[2, 1], [0, 0]]], [[[1, 2], [0, 0]], [[5, 5], [0, 0]]]]) overlap = [True, False] cut_point_coords = [TsPointCoords.from_array(np.array([[2, 2], [0, 0]]))] # Test with overlap ts_ground = TsGround.from_ordered_shadows_coords( shadow_coords, flag_overlap=overlap, cut_point_coords=cut_point_coords) # Run some checks for index 0 pvground = ts_ground.at(0, merge_if_flag_overlap=False, with_cut_points=False) assert pvground.n_surfaces == 4 assert pvground.list_segments[0].illum_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.length == 5 np.testing.assert_allclose(pvground.shaded_length, 5) # Run some checks for index 1 pvground = ts_ground.at(1, with_cut_points=False) assert pvground.n_surfaces == 5 assert pvground.list_segments[0].illum_collection.n_surfaces == 3 assert pvground.list_segments[0].shaded_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.length == 4 np.testing.assert_allclose(pvground.shaded_length, 4) # Run some checks for index 0, when merging pvground = ts_ground.at(0, merge_if_flag_overlap=True, with_cut_points=False) assert pvground.n_surfaces == 3 assert pvground.list_segments[0].illum_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.n_surfaces == 1 assert pvground.list_segments[0].shaded_collection.length == 5 np.testing.assert_allclose(pvground.shaded_length, 5) # Run some checks for index 0, when merging and with cut points pvground = ts_ground.at(0, merge_if_flag_overlap=True, with_cut_points=True) assert pvground.n_surfaces == 4 assert pvground.list_segments[0].illum_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.n_surfaces == 2 assert pvground.list_segments[0].shaded_collection.length == 5 np.testing.assert_allclose(pvground.shaded_length, 5)
def test_ts_ground_from_ts_pvrow(): """Check that ground geometries are created correctly from ts pvrow""" # Create a ts pv row xy_center = (0, 2) width = 2. df_inputs = pd.DataFrame({ 'rotation_vec': [20., -90., 0.], 'shaded_length_front': [1.3, 0., 1.9], 'shaded_length_back': [0, 0.3, 0.6] }) cut = {'front': 3, 'back': 4} param_names = ['test1', 'test2'] ts_pvrow = TsPVRow.from_raw_inputs(xy_center, width, df_inputs.rotation_vec, cut, df_inputs.shaded_length_front, df_inputs.shaded_length_back, param_names=param_names) # Create ground from it alpha_vec = np.deg2rad([80., 90., 70.]) ts_ground = TsGround.from_ts_pvrows_and_angles([ts_pvrow], alpha_vec, df_inputs.rotation_vec, param_names=param_names) assert len(ts_ground.shadow_elements) == 1 # Check at specific times ground_0 = ts_ground.at(0) assert ground_0.n_surfaces == 4 assert ground_0.list_segments[0].shaded_collection.n_surfaces == 1 ground_1 = ts_ground.at(1) # vertical, sun above assert ground_1.n_surfaces == 2 # only 2 illuminated surfaces assert ground_1.list_segments[0].shaded_collection.n_surfaces == 0 assert ground_1.shaded_length == 0 # no shadow (since shadow length 0ish) np.testing.assert_allclose(ground_0.shaded_length, 1.7587704831436) np.testing.assert_allclose(ts_ground.at(2).shaded_length, width) # flat # Check that all have surface params for surf in ground_0.all_surfaces: assert surf.param_names == param_names