wip shading modelling
This commit is contained in:
parent
a36a8db753
commit
0a4d980f4f
@ -4,10 +4,6 @@ import logging
|
|||||||
import math
|
import math
|
||||||
from tqdm import tqdm
|
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
|
import pvlib
|
||||||
|
|
||||||
from Utilities.Processes import (
|
from Utilities.Processes import (
|
||||||
@ -23,6 +19,19 @@ def define_grid_layout(c):
|
|||||||
c["array"]["system_size"], c["panel"]["peak_power"]
|
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
|
# get maximum number of panels based on spacing and dimensions
|
||||||
max__panels_per_row = np.floor(
|
max__panels_per_row = np.floor(
|
||||||
(
|
(
|
||||||
@ -36,7 +45,7 @@ def define_grid_layout(c):
|
|||||||
c["environment"]["roof"]["dimensions"]["length"]
|
c["environment"]["roof"]["dimensions"]["length"]
|
||||||
- 2 * c["array"]["edge_setback"]
|
- 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
|
max_no_of_panels = max__panels_per_row * max_number_of_rows
|
||||||
logger.info(
|
logger.info(
|
||||||
@ -82,50 +91,7 @@ def define_grid_layout(c):
|
|||||||
"z": z,
|
"z": z,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return coordinates
|
return coordinates, no_of_panels
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
def get_solar_data(c):
|
def get_solar_data(c):
|
||||||
@ -152,23 +118,11 @@ def get_solar_data(c):
|
|||||||
return solar_positions
|
return solar_positions
|
||||||
|
|
||||||
|
|
||||||
def calculate_sun_vector(solar_zenith, solar_azimuth):
|
def calculate_shading(c, coordinates, solar_positions):
|
||||||
"""
|
# calculate shading row by row
|
||||||
Calculate the sun vector from solar zenith and azimuth angles.
|
logger.info("Calculating shading for each row of panels")
|
||||||
Args:
|
row_coordinates = np.unique(coordinates["y"])
|
||||||
solar_zenith (float): Solar zenith angle in degrees.
|
for row in row_coordinates:
|
||||||
solar_azimuth (float): Solar azimuth angle in degrees.
|
# get number of panels in row for width of row
|
||||||
|
panels_in_row = coordinates[coordinates["y"] == row].shape[0]
|
||||||
Returns:
|
row_width = panels_in_row * c["panel"]["dimensions"]["width"]
|
||||||
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)
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
array:
|
array:
|
||||||
system_size: 500 # in kWp
|
system_size: 100 # in kWp
|
||||||
spacing: 1 # spacing between adjacent panel rows in m
|
spacing: 1.5 # spacing between adjacent panel rows in m
|
||||||
edge_setback: 1.8 # distance from the edge of the roof to the array
|
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:
|
simulation_date_time:
|
||||||
start: 2025-03-30 00:00 # start date and time in ISO 8601 format
|
start: 2025-03-30 00:00 # start date and time in ISO 8601 format
|
||||||
|
5
main.py
5
main.py
@ -1,7 +1,7 @@
|
|||||||
# %%
|
# %%
|
||||||
import yaml
|
import yaml
|
||||||
import logging
|
import logging
|
||||||
from Utilities.Shading import calculate_shading_fraction
|
from Utilities.Shading import define_grid_layout
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
@ -24,6 +24,7 @@ with open(config_path, "r") as file:
|
|||||||
logger.info("Configuration loaded successfully.")
|
logger.info("Configuration loaded successfully.")
|
||||||
logger.debug(f"Configuration: {c}")
|
logger.debug(f"Configuration: {c}")
|
||||||
|
|
||||||
calculate_shading_fraction(c)
|
shading = define_grid_layout(c)
|
||||||
|
logger.info("Shading calculation completed successfully.")
|
||||||
|
|
||||||
# %%
|
# %%
|
||||||
|
Loading…
x
Reference in New Issue
Block a user