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