diff --git a/docs/assets/daylight_factor.png b/docs/assets/daylight_factor.png new file mode 100644 index 0000000..8004dfd Binary files /dev/null and b/docs/assets/daylight_factor.png differ diff --git a/docs/how-to/guide_ep1.md b/docs/how-to/guide_ep1.md index 157595f..60cc730 100644 --- a/docs/how-to/guide_ep1.md +++ b/docs/how-to/guide_ep1.md @@ -19,16 +19,19 @@ from pyenergyplus.dataset import ref_models, weather_files !!! tip "Tips: Reference EnergyPlus models and weather files" The `pyenergyplus.dataset` module contains a dictionary of EnergyPlus models and weather files. The keys are the names of the models and weather files. The values are the file paths to the models and weather files. + ```python + ref_models.keys() ``` - >>> ref_models.keys() - dict_keys([ - 'full_service_restaurant', 'hospital', 'large_hotel', - 'large_office', 'medium_office', 'midrise_apartment', - 'outpatient', 'primary_school', 'quick_service_restaurant', - 'secondary_school', 'small_hotel', 'small_office', - 'standalone_retail', 'strip_mall', 'supermarket', 'warehouse' - ]) - ``` + + > ``` + dict_keys([ + 'full_service_restaurant', 'hospital', 'large_hotel', + 'large_office', 'medium_office', 'midrise_apartment', + 'outpatient', 'primary_school', 'quick_service_restaurant', + 'secondary_school', 'small_hotel', 'small_office', + 'standalone_retail', 'strip_mall', 'supermarket', 'warehouse' + ]) + > ``` ## 1 Initialize an EnergyPlus model @@ -62,11 +65,11 @@ epmodel = fr.load_energyplus_model(idf) You can access any EnergyPlus model objects (simulation parameters) as you would do to a class attribute. The EnergyPlus model objects share the same name as that in the Input Data File (IDF) but in lower case separated by underscores. For example, the `FenestrationSurface:Detailed` object in IDF is `fenestration_surface_detailed` in `EnergyPlusModel`. ```python ->>> epmodel.fenestration_surface_detailed -``` +epmodel.fenestration_surface_detailed ``` +> ``` {'Perimeter_bot_ZN_1_Wall_South_Window': FenestrationSurfaceDetailed(surface_type=, construction_name='Window Non-res Fixed', building_surface_name='Perimeter_bot_ZN_1_Wall_South', outside_boundary_condition_object=None, view_factor_to_ground=, frame_and_divider_name=None, multiplier=1.0, number_of_vertices=NumberOfVertice2(root=4.0), vertex_1_x_coordinate=1.5, vertex_1_y_coordinate=0.0, vertex_1_z_coordinate=2.3293, vertex_2_x_coordinate=1.5, vertex_2_y_coordinate=0.0, vertex_2_z_coordinate=1.0213, vertex_3_x_coordinate=10.5, vertex_3_y_coordinate=0.0, vertex_3_z_coordinate=1.0213, vertex_4_x_coordinate=10.5, vertex_4_y_coordinate=0.0, vertex_4_z_coordinate=2.3293)}' -``` +>``` !!! example "Example: Edit the `fenestration_surface_detailed` object" diff --git a/docs/how-to/guide_rad7.md b/docs/how-to/guide_rad7.md new file mode 100644 index 0000000..2e3a4d6 --- /dev/null +++ b/docs/how-to/guide_rad7.md @@ -0,0 +1,185 @@ +# How to set up a workflow configuration for Radiance simulation? + +**What is daylight factor?** + +Daylight factor (DF) is the ratio of the interior horizontal illuminance to the exterior unobsturcted horizontal illuminance under overcast sky conditions. The higher the daylight factor, the more daylight is available in the room. A minimum daylight factor of 2% is usually recommended for critical visual task zones. + +## Workflow + +1. Build a Radiance model +2. Generate a CIE overcast sky +3. Use raytracing to get the interior horizontal illuminance +4. Compute the daylight factor + +## 0. Import the required classes and functions + +```python +import datatime +import frads as fr +import pyradiance as pr +import numpy as np +``` + +## 1. Build a Radiance model + +If you already have a Radiance model setup, please have a octree file storing the scene files and continue on to the next step. If not, follow below to set up a sample Radiance model. See [How to setup a simple rtrace workflow?](guide_rad1.md) for more details. + +Use `gen room` in a command line interface to generate +a simple Radiance model. The example 'aroom' is a open-office sized side-lit room with four same-sized windows. The room will be 12 meters wide, 14 meters deep, a floor to floor height of 4 meters, and a ceiling height of 3 meters. Each window is 2.5 meters in width and 1.8 meters in height and has a sill height of 1 meter. Windows are 0.4 meters apart from each other. Finally, the facade has a thickness of 0.1 meters. + +``` +$ gen room 12 14 4 3 \ + -w 0.4 1 2.5 1.8 \ + -w 3.3 1 2.5 1.8 \ + -w 6.2 1 2.5 1.8 \ + -w 9.1 1 2.5 1.8 \ + -t 0.1 -n aroom +``` + +In a Python environment, call `pyradiance.oconv` to generate a `octree` file storing the material and geometry files generated from the `gen room` command in the 'Objects' directory + +```python +fpaths = ["Objects/materials_aroom.mat", + "Objects/ceiling_aroom.rad", + "Objects/wall_aroom.rad", + "Objects/floor_aroom.rad", + "Objects/window_00_aroom.rad", + "Objects/window_01_aroom.rad", + "Objects/window_02_aroom.rad", + "Objects/window_03_aroom.rad", +] +``` + +```python +room_octree = "aroom.oct" +with open(room_octree, 'wb') as f: + f.write(pr.oconv(*fpaths)) +``` + +## 2. Generate a CIE overcast sky + +Use `pyradiance.gensky` to generate a CIE overcast sky. The function returns a brightness function (skyfunc) to vary the brightness of the glow material. We will assume the overcast sky has a diffuse horizontal illuminance of 10,000 lux (horizontal diffuse irradiance of 55.866 w/m2). + +```python +dif_hor_illum = 10000 +dif_hor_ird = dif_hor_illum / 179 +``` +```python +sky_func = pr.gensky( + dt=datetime.datetime(2024, 12, 21, 12, 0), + cloudy=True, + horizontal_brightness=dif_hor_ird, # (1) + ) + +print(sky_func) +``` + +1. zenith brightness is computed from the horizontal diffuse irradiance (in watts/meter2) + +> ``` +> void brightfunc skyfunc +> 2 skybr skybright.cal +> 0 +> 3 2 2.286e+01 3.557e+00 +> ``` + + + +```python +sky_glow = "skyfunc glow sky_glow 0 0 4 1 1 1 0".encode() + +sky = "sky_glow source sky 0 0 4 0 0 1 180".encode() +``` + +```python +sky_scene = sky_func + b'\n' + sky_glow + b'\n' + sky +``` + +```python title="add sky scene to octree" +room_sky_octree = f"aroom_37_122_1221_1200.oct" +with open(room_sky_octree, "wb") as f: + f.write(pr.oconv(stdin=sky_descr, octree=room_octree)) +``` + + +## 3. Use raytracing to get the interior horizontal illuminance + +Generate a grid of horizontal workplane sensors for interior horizontal illuminance computation. See [How to setup a simple rtrace workflow?](guide_rad1.md) for more details. + +```python title="generate grid sensors based on the floor polygon" +floor_primitives = fr.unpack_primitives("Objects/floor_aroom.rad") +floor_polygon = fr.parse_polygon(floor_primitives[0]) +grid = fr.gen_grid(floor_polygon, 1, 0.75) +``` + +Use `pyrandiance.rtrace` to compute ray tracing from the sensors. The function returns the irradiance results of all sensors in bytes. + +```python title="rtrace to get irradiance" +option = ["-I+", "-ab", "1", "-ad", "64", "-aa", "0", "-lw", "0.01"] +rays = "\n".join([" ".join(map(str, row)) for row in grid]) +ird_results = pr.rtrace( + rays.encode(), room_sky_octree, params=option, header=False +) +print(ird_results) +``` +The sensor data are separeted by '\n'. + +Each sensor data has rgb channels irradiance separated by '\t' + +> ```'4.386912e+00\t4.386912e+00\t4.386912e+00\t\n2.373928e+00\t2.373928e+00\t2.373928e+00\t ... 0.000000e+00\t0.000000e+00\t0.000000e+00\t\n' ``` + +```python title="reformat the irradiance result" +rows = ird_results.decode().strip().split("\n") +data = [ + [float(element) for element in row.split("\t") if element != ""] + for row in rows +] +ird_array = np.array(data) +``` + +Apply coefficients to convert irradiance into illuminance + +```python title="convert irradiance to illuminance" +ird_array[:, 0] *= 47.4 #red +ird_array[:, 1] *= 119.9 #blue +ird_array[:, 2] *= 11.6 #green +illum = np.sum(ird_array, axis=1) +``` + +## 4. Compute the daylight factor + + +```python title="daylight factor = interior illuminance / exterior illuminance * 100" +df = illum / dif_hor_illum * 100 +``` + +### data visualization + +```python title="import visualization packages" +import matplotlib.pyplot as plt +``` + +```python +fig, ax = plt.subplots() +x = [data[0] for data in grid] +y = [data[1] for data in grid] +_plot = ax.scatter( + x, + y, + c=df, + cmap="plasma", + s=15, + vmin=0, + vmax=max(df), + rasterized=True, +) +ax.set( + xlabel="x position [m]", + ylabel="y position [m]", +) + +fig.colorbar(_plot, ax=ax, label="Daylight Factor [%]") +fig.tight_layout() +``` + +![daylight_factor](../assets/daylight_factor.png) \ No newline at end of file diff --git a/docs/how-to/index.md b/docs/how-to/index.md index db924a3..9fb338b 100644 --- a/docs/how-to/index.md +++ b/docs/how-to/index.md @@ -8,9 +8,11 @@ 4. How to simulate spatial daylight autonomy using two-phase method? -6. How to simulate annual glare index using five-phase method? +5. How to simulate annual glare index using five-phase method? -7. How to simulate annual melanopic equivalent daylight illuminance? +6. How to simulate annual melanopic equivalent daylight illuminance? + +7. [How to calculate daylight factor?](guide_rad7.md) ## EnergyPlus