code for creating panel geometries
This commit is contained in:
parent
1aa9bb60b3
commit
58e84a7998
18
Utilities/Processes.py
Normal file
18
Utilities/Processes.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_no_of_panels(system_size, panel_peak_power):
|
||||||
|
"""
|
||||||
|
Calculate the number of panels needed for a given system size and panel peak power.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
system_size (float): The total system size in kWp.
|
||||||
|
panel_peak_power (float): The peak power of a single panel in Wp.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: The number of panels needed.
|
||||||
|
"""
|
||||||
|
panel_peak_power_kWp = panel_peak_power / 1000 # Convert Wp to kWp
|
||||||
|
no_of_panels = np.ceil(system_size / panel_peak_power_kWp)
|
||||||
|
|
||||||
|
return no_of_panels
|
113
Utilities/Shading.py
Normal file
113
Utilities/Shading.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from ladybug_geometry.geometry3d.pointvector import Point3D, Vector3D
|
||||||
|
from ladybug_geometry.geometry3d.plane import Plane
|
||||||
|
from ladybug_geometry.geometry3d.polyface import Polyface3D
|
||||||
|
|
||||||
|
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"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# 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"]
|
||||||
|
)
|
||||||
|
/ (c["array"]["spacing"] + c["panel"]["dimensions"]["thickness"])
|
||||||
|
)
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
def create_panels(coordinates, c):
|
||||||
|
panel_width = c["panel"]["dimensions"]["width"]
|
||||||
|
panel_length = c["panel"]["dimensions"]["length"]
|
||||||
|
panel_thickness = c["panel"]["dimensions"]["thickness"]
|
||||||
|
|
||||||
|
# For a vertical panel:
|
||||||
|
# - The vertical direction (panel height) is along the Z-axis.
|
||||||
|
y_axis = Vector3D(0, 0, 1) # points upward
|
||||||
|
|
||||||
|
# - 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 east
|
||||||
|
|
||||||
|
panels = []
|
||||||
|
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(origin=panel_origin, y_axis=y_axis, x_axis=x_axis)
|
||||||
|
|
||||||
|
# Create the panel geometry
|
||||||
|
panel = Polyface3D.from_box(
|
||||||
|
width=panel_width,
|
||||||
|
depth=panel_length,
|
||||||
|
height=panel_thickness,
|
||||||
|
base_plane=panel_plane,
|
||||||
|
)
|
||||||
|
|
||||||
|
panels.append(panel)
|
||||||
|
|
||||||
|
return panels
|
0
Utilities/__init__.py
Normal file
0
Utilities/__init__.py
Normal file
26
config.yml
Normal file
26
config.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
array:
|
||||||
|
system_size: 500 # in kWp
|
||||||
|
spacing: 1 # spacing between adjacent panel rows in m
|
||||||
|
edge_setback: 1.8 # distance from the edge of the roof to the array
|
||||||
|
|
||||||
|
environment:
|
||||||
|
roof:
|
||||||
|
dimensions:
|
||||||
|
# dimensions all in m
|
||||||
|
length: 100
|
||||||
|
width: 125
|
||||||
|
albedo: 0.8 # % of light reflected from the surface
|
||||||
|
tilt: 0 # degrees from horizontal
|
||||||
|
|
||||||
|
location:
|
||||||
|
latitude: 3.1186108758412945
|
||||||
|
longitude: 101.57639813680093
|
||||||
|
|
||||||
|
panel:
|
||||||
|
peak_power: 710 # in Wp
|
||||||
|
bifaciality: 0.85 # rear face efficiency relative to front face
|
||||||
|
# dimensions all in m
|
||||||
|
dimensions:
|
||||||
|
length: 2.384
|
||||||
|
width: 1.303
|
||||||
|
thickness: 0.033
|
29
main.py
Normal file
29
main.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# %%
|
||||||
|
import yaml
|
||||||
|
import logging
|
||||||
|
from Utilities.Shading import define_grid_layout
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
)
|
||||||
|
|
||||||
|
stream_handler = logging.StreamHandler()
|
||||||
|
stream_handler.setLevel(logging.INFO)
|
||||||
|
stream_formatter = logging.Formatter("%(levelname)s: %(message)s")
|
||||||
|
stream_handler.setFormatter(stream_formatter)
|
||||||
|
logging.getLogger().addHandler(stream_handler)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
config_path = "config.yml"
|
||||||
|
|
||||||
|
with open(config_path, "r") as file:
|
||||||
|
c = yaml.safe_load(file)
|
||||||
|
logger.info("Configuration loaded successfully.")
|
||||||
|
logger.debug(f"Configuration: {c}")
|
||||||
|
|
||||||
|
coordinates = define_grid_layout(c)
|
||||||
|
|
||||||
|
# %%
|
44
requirements.txt
Normal file
44
requirements.txt
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
asttokens==3.0.0
|
||||||
|
certifi==2025.1.31
|
||||||
|
charset-normalizer==3.4.1
|
||||||
|
colorama==0.4.6
|
||||||
|
comm==0.2.2
|
||||||
|
debugpy==1.8.13
|
||||||
|
decorator==5.2.1
|
||||||
|
executing==2.2.0
|
||||||
|
h5py==3.13.0
|
||||||
|
idna==3.10
|
||||||
|
ipykernel==6.29.5
|
||||||
|
ipython==9.0.2
|
||||||
|
ipython_pygments_lexers==1.1.1
|
||||||
|
jedi==0.19.2
|
||||||
|
jupyter_client==8.6.3
|
||||||
|
jupyter_core==5.7.2
|
||||||
|
ladybug-geometry==1.34.1
|
||||||
|
matplotlib-inline==0.1.7
|
||||||
|
nest-asyncio==1.6.0
|
||||||
|
nominatim==0.1
|
||||||
|
numpy==2.2.4
|
||||||
|
packaging==24.2
|
||||||
|
pandas==2.2.3
|
||||||
|
parso==0.8.4
|
||||||
|
platformdirs==4.3.7
|
||||||
|
prompt_toolkit==3.0.50
|
||||||
|
psutil==7.0.0
|
||||||
|
pure_eval==0.2.3
|
||||||
|
pvlib==0.12.0
|
||||||
|
Pygments==2.19.1
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
pytz==2025.2
|
||||||
|
pywin32==310
|
||||||
|
PyYAML==6.0.2
|
||||||
|
pyzmq==26.3.0
|
||||||
|
requests==2.32.3
|
||||||
|
scipy==1.15.2
|
||||||
|
six==1.17.0
|
||||||
|
stack-data==0.6.3
|
||||||
|
tornado==6.4.2
|
||||||
|
traitlets==5.14.3
|
||||||
|
tzdata==2025.2
|
||||||
|
urllib3==2.3.0
|
||||||
|
wcwidth==0.2.13
|
17
test_sim.py
17
test_sim.py
@ -1,17 +0,0 @@
|
|||||||
# %%
|
|
||||||
import pvlib
|
|
||||||
|
|
||||||
from pvlib.modelchain import ModelChain
|
|
||||||
from pvlib.pvsystem import PVSystem
|
|
||||||
from pvlib.location import Location
|
|
||||||
|
|
||||||
# %%
|
|
||||||
location = Location(
|
|
||||||
latitude=3.1114844514593343, longitude=101.5785743614895, tz="Asia/Kuala_Lumpur"
|
|
||||||
)
|
|
||||||
system = PVSystem(
|
|
||||||
surface_tilt=90,
|
|
||||||
surface_azimuth=90,
|
|
||||||
)
|
|
||||||
sandia_modules = pvlib.pvsystem.retrieve_sam("SandiaMod")
|
|
||||||
cec_inverters = pvlib.pvsystem.retrieve_sam("CECInverter")
|
|
Loading…
x
Reference in New Issue
Block a user