import numpy as np import pandas as pd import logging import math from tqdm import tqdm import pvlib from Utilities.Processes import ( calculate_no_of_panels, ) logger = logging.getLogger(__name__) def define_grid_layout(c): # get number of panels required no_of_panels = calculate_no_of_panels( 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( ( c["environment"]["roof"]["dimensions"]["width"] - 2 * c["array"]["edge_setback"] ) / c["panel"]["dimensions"]["width"] ) max_number_of_rows = np.floor( ( c["environment"]["roof"]["dimensions"]["length"] - 2 * c["array"]["edge_setback"] ) / pitch ) max_no_of_panels = max__panels_per_row * max_number_of_rows logger.info( f"Number of panels required: {no_of_panels}, Maximum panels possible: {max_no_of_panels}" ) if no_of_panels > max_no_of_panels: no_of_panels = max_no_of_panels logger.warning( f"Number of panels required exceeds maximum possible. Setting number of panels to {no_of_panels}." ) else: logger.info( f"Number of panels required is within the maximum possible. Setting number of panels to {no_of_panels}." ) # coordinate of panel determined by bottom left corner # x - row wise position, y - column wise position, z - height # first panel in row 1 is at (0, 0, 0) # nth panel in row 1 is at ((n-1)*panel_width, 0, 0) # first panel in nth row is at (0, (n-1)*(panel_thickness + spacing), 0) # create matrices for x, y, z coordinates of panels x = [] y = [] z = [] counter = 0 for j in range(int(max_number_of_rows)): for i in range(int(max__panels_per_row)): if counter < no_of_panels: x.append(i * c["panel"]["dimensions"]["width"]) y.append( j * (c["panel"]["dimensions"]["thickness"] + c["array"]["spacing"]) ) z.append(0) counter += 1 else: break coordinates = pd.DataFrame( { "x": x, "y": y, "z": z, } ) return coordinates, no_of_panels def get_solar_data(c): logger.info( f"Getting solar position data for {c['simulation_date_time']['start']} to {c['simulation_date_time']['end']}" ) """ Function to get solar position from PVLib """ latitude = c["environment"]["location"]["latitude"] longitude = c["environment"]["location"]["longitude"] tz = c["simulation_date_time"]["tz"] times = pd.date_range( c["simulation_date_time"]["start"], c["simulation_date_time"]["end"], freq="15min", tz=tz, ) # Get solar position data using PVLib solar_positions = pvlib.solarposition.get_solarposition(times, latitude, longitude) return solar_positions 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"]