diff --git a/Utilities/Shading.py b/Utilities/Shading.py index ee82e76..1052ac5 100644 --- a/Utilities/Shading.py +++ b/Utilities/Shading.py @@ -4,10 +4,6 @@ import logging import math from tqdm import tqdm -from ladybug_geometry.geometry3d.pointvector import Point3D, Vector3D -from ladybug_geometry.geometry3d.plane import Plane -from ladybug_geometry.geometry3d.polyface import Polyface3D - import pvlib from Utilities.Processes import ( @@ -23,6 +19,19 @@ def define_grid_layout(c): c["array"]["system_size"], c["panel"]["peak_power"] ) + # calculate pitch + pitch = c["array"]["spacing"] + c["panel"]["dimensions"]["thickness"] + # calculate minimum pitch if we don't want panel overlap at all + min_pitch = c["panel"]["dimensions"]["length"] * math.cos( + c["array"]["tilt"] / 180 * math.pi + ) + if pitch < min_pitch: + logger.warning( + f"Spacing is less than minimum pitch. Setting spacing to {min_pitch}." + ) + pitch = min_pitch + logger.info(f"Pitch between panels: {pitch}m") + # get maximum number of panels based on spacing and dimensions max__panels_per_row = np.floor( ( @@ -36,7 +45,7 @@ def define_grid_layout(c): c["environment"]["roof"]["dimensions"]["length"] - 2 * c["array"]["edge_setback"] ) - / (c["array"]["spacing"] + c["panel"]["dimensions"]["thickness"]) + / pitch ) max_no_of_panels = max__panels_per_row * max_number_of_rows logger.info( @@ -82,50 +91,7 @@ def define_grid_layout(c): "z": z, } ) - return coordinates - - -def create_panels(coordinates, c): - panel_width = c["panel"]["dimensions"]["width"] - panel_length = c["panel"]["dimensions"]["length"] - panel_thickness = c["panel"]["dimensions"]["thickness"] - - # if viewed from above, and assumming the roof is a rectangle, the - # global origin is at the bottom left corner of the roof - - # For a vertical panel: - # - The vertical direction (panel height) is along the Z-axis. - y_axis = Vector3D(0, 1, 0) # points east, therefore front face is east facing - - # - The horizontal direction along the panel's width. - # Here, we assume the width runs in the positive X-direction. - x_axis = Vector3D(1, 0, 0) # points north - - panel_object = [] - base_planes = [] - for index, row in coordinates.iterrows(): - # Create the bottom-left corner of the panel - panel_origin = Point3D(row["x"], row["y"], row["z"]) - - # Create the plane for the panel - panel_plane = Plane(o=panel_origin, n=y_axis, x=x_axis) - - # Create the panel geometry - panel = Polyface3D.from_box( - width=panel_width, - depth=panel_thickness, - height=panel_length, - base_plane=panel_plane, - ) - - panel_object.append(panel) - base_planes.append(panel_plane) - - panels = pd.DataFrame(columns=["panel", "base_plane"]) - panels["panel"] = panel_object - panels["base_plane"] = base_planes - - return panels + return coordinates, no_of_panels def get_solar_data(c): @@ -152,23 +118,11 @@ def get_solar_data(c): return solar_positions -def calculate_sun_vector(solar_zenith, solar_azimuth): - """ - Calculate the sun vector from solar zenith and azimuth angles. - Args: - solar_zenith (float): Solar zenith angle in degrees. - solar_azimuth (float): Solar azimuth angle in degrees. - - Returns: - Vector3D: Sun vector as a 3D vector. - """ - # Convert angles from degrees to radians - zenith_rad = math.radians(solar_zenith) - azimuth_rad = math.radians(solar_azimuth) - - # Calculate the sun vector components - x = math.sin(zenith_rad) * math.cos(azimuth_rad) - z = math.sin(zenith_rad) * math.sin(azimuth_rad) - y = math.cos(zenith_rad) - - return Vector3D(x, y, z) +def calculate_shading(c, coordinates, solar_positions): + # calculate shading row by row + logger.info("Calculating shading for each row of panels") + row_coordinates = np.unique(coordinates["y"]) + for row in row_coordinates: + # get number of panels in row for width of row + panels_in_row = coordinates[coordinates["y"] == row].shape[0] + row_width = panels_in_row * c["panel"]["dimensions"]["width"] diff --git a/config.yml b/config.yml index 2920928..7cec3b4 100644 --- a/config.yml +++ b/config.yml @@ -1,7 +1,10 @@ array: - system_size: 500 # in kWp - spacing: 1 # spacing between adjacent panel rows in m + system_size: 100 # in kWp + spacing: 1.5 # spacing between adjacent panel rows in m edge_setback: 1.8 # distance from the edge of the roof to the array + front_face_azimuth: 90 # 90=east, 180=south, 270=west + tilt: 90 + slope: 0 # degrees from horizontal (+ve means shaded row is higher than the row in front) simulation_date_time: start: 2025-03-30 00:00 # start date and time in ISO 8601 format diff --git a/main.py b/main.py index 18beee3..eb695d1 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ # %% import yaml import logging -from Utilities.Shading import calculate_shading_fraction +from Utilities.Shading import define_grid_layout logging.basicConfig( level=logging.INFO, @@ -24,6 +24,7 @@ with open(config_path, "r") as file: logger.info("Configuration loaded successfully.") logger.debug(f"Configuration: {c}") -calculate_shading_fraction(c) +shading = define_grid_layout(c) +logger.info("Shading calculation completed successfully.") # %%