honeybee-radiance-postprocess 0.4.226__tar.gz → 0.4.228__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/PKG-INFO +1 -1
  2. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/postprocess.py +70 -8
  3. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/translate.py +70 -1
  4. honeybee-radiance-postprocess-0.4.228/honeybee_radiance_postprocess/helper.py +177 -0
  5. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/PKG-INFO +1 -1
  6. honeybee-radiance-postprocess-0.4.226/honeybee_radiance_postprocess/helper.py +0 -159
  7. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/CODE_OF_CONDUCT.md +0 -0
  8. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/CONTRIBUTING.md +0 -0
  9. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/LICENSE +0 -0
  10. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/MANIFEST.in +0 -0
  11. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/README.md +0 -0
  12. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/dev-requirements.txt +0 -0
  13. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/__init__.py +0 -0
  14. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/__main__.py +0 -0
  15. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/annual.py +0 -0
  16. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/annualdaylight.py +0 -0
  17. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/__init__.py +0 -0
  18. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/grid.py +0 -0
  19. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/leed.py +0 -0
  20. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/mtxop.py +0 -0
  21. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/schedule.py +0 -0
  22. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/two_phase.py +0 -0
  23. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/cli/util.py +0 -0
  24. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/dynamic.py +0 -0
  25. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/electriclight.py +0 -0
  26. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/en17037.py +0 -0
  27. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/leed.py +0 -0
  28. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/metrics.py +0 -0
  29. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/reader.py +0 -0
  30. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/results.py +0 -0
  31. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/type_hints.py +0 -0
  32. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess/util.py +0 -0
  33. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/SOURCES.txt +0 -0
  34. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/dependency_links.txt +0 -0
  35. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/entry_points.txt +0 -0
  36. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/requires.txt +0 -0
  37. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/honeybee_radiance_postprocess.egg-info/top_level.txt +0 -0
  38. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/requirements.txt +0 -0
  39. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/setup.cfg +0 -0
  40. {honeybee-radiance-postprocess-0.4.226 → honeybee-radiance-postprocess-0.4.228}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-radiance-postprocess
3
- Version: 0.4.226
3
+ Version: 0.4.228
4
4
  Summary: Postprocessing of Radiance results and matrices
5
5
  Home-page: https://github.com/ladybug-tools/honeybee-radiance-postprocess
6
6
  Author: Ladybug Tools
@@ -697,6 +697,7 @@ def annual_metrics_file(
697
697
  @click.option(
698
698
  '--grids-info', '-gi', help='An optional JSON file with grid information. '
699
699
  'If no file is provided the command will look for a file in the folder.',
700
+ default=None, show_default=True,
700
701
  type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
701
702
  )
702
703
  @click.option(
@@ -726,27 +727,88 @@ def grid_summary_metric(
726
727
  if grids_info:
727
728
  with open(grids_info) as gi:
728
729
  grids_info = json.load(gi)
729
- else:
730
- gi_file = folder.joinpath('grids_info.json')
731
- with open(gi_file) as gi:
732
- grids_info = json.load(gi)
733
730
 
734
731
  # get grid metrics
735
732
  if grid_metrics:
736
733
  with open(grid_metrics) as gm:
737
734
  grid_metrics = json.load(gm)
735
+
736
+ # check to see if there is a HBJSON with sensor grid meshes for areas
737
+ if model:
738
+ grid_areas = model_grid_areas(model, grids_info)
738
739
  else:
739
- gi_file = folder.joinpath('grids_info.json')
740
- with open(gi_file) as gi:
740
+ grid_areas = None
741
+
742
+ grid_summary(folder, extension, grid_areas, grids_info, name, grid_metrics)
743
+
744
+ except Exception:
745
+ _logger.exception('Failed to calculate grid summary.')
746
+ sys.exit(1)
747
+ else:
748
+ sys.exit(0)
749
+
750
+
751
+ @post_process.command('grid-summary-annual-daylight')
752
+ @click.argument(
753
+ 'folder',
754
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
755
+ )
756
+ @click.option(
757
+ '--model', '-m', help='An optional HBJSON model file. This will be used to '
758
+ 'find the area of the grids. The area is used when calculating percentages '
759
+ 'of floor area.',
760
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
761
+ )
762
+ @click.option(
763
+ '--grids-info', '-gi', help='An optional JSON file with grid information. '
764
+ 'If no file is provided the command will look for a file in the folder.',
765
+ default=None, show_default=True,
766
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
767
+ )
768
+ @click.option(
769
+ '--name', '-n', help='Optional filename of grid summary.',
770
+ type=str, default='grid_summary', show_default=True
771
+ )
772
+ @click.option(
773
+ '--grid-metrics', '-gm', help='An optional JSON file with additional '
774
+ 'custom metrics to calculate.', default=None,
775
+ type=click.Path(exists=True, file_okay=True, dir_okay=False, resolve_path=True)
776
+ )
777
+ def grid_summary_annual_daylight_metric(
778
+ folder, model, grids_info, name, grid_metrics
779
+ ):
780
+ """Calculate a grid summary.
781
+
782
+ \b
783
+ Args:
784
+ folder: A folder with annual daylight metrics.
785
+ """
786
+ try:
787
+ # create Path object
788
+ folder = Path(folder)
789
+
790
+ # get grids information
791
+ if grids_info:
792
+ with open(grids_info) as gi:
741
793
  grids_info = json.load(gi)
742
794
 
795
+ # get grid metrics
796
+ if grid_metrics:
797
+ with open(grid_metrics) as gm:
798
+ grid_metrics = json.load(gm)
799
+
743
800
  # check to see if there is a HBJSON with sensor grid meshes for areas
744
801
  if model:
745
802
  grid_areas = model_grid_areas(model, grids_info)
746
803
  else:
747
- grid_areas = [None] * len(grids_info)
804
+ grid_areas = None
748
805
 
749
- grid_summary(folder, extension, grids_info, grid_areas, name, grid_metrics)
806
+ for metric in ['da', 'cda', 'udi', 'udi_lower', 'udi_upper']:
807
+ metric_folder = folder.joinpath(metric)
808
+ extension = metric.split('_')[0]
809
+ grid_summary(
810
+ metric_folder, extension, grids_info, grid_areas, name,
811
+ grid_metrics)
750
812
 
751
813
  except Exception:
752
814
  _logger.exception('Failed to calculate grid summary.')
@@ -1,9 +1,11 @@
1
1
  """Commands to translate objects."""
2
2
  import sys
3
3
  import logging
4
+ from pathlib import Path
5
+ import shutil
4
6
  import numpy as np
5
7
  import click
6
- from pathlib import Path
8
+ import json
7
9
 
8
10
  from ..reader import binary_to_array
9
11
 
@@ -129,3 +131,70 @@ def binary_to_npy(mtx_file, conversion, name, output_folder):
129
131
  sys.exit(1)
130
132
  else:
131
133
  sys.exit(0)
134
+
135
+
136
+ @translate.command('annual-daylight-npy-to-ill')
137
+ @click.argument(
138
+ 'folder',
139
+ type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True)
140
+ )
141
+ @click.option(
142
+ '--output-folder', '-of', help='Output folder. If not provided the output '
143
+ 'folder will be created in the same directory as the results folder. The '
144
+ 'new folder will be called results_ill.', default=None,
145
+ type=click.Path(exists=False, file_okay=False, dir_okay=True, resolve_path=True)
146
+ )
147
+ def annual_daylight_npy_to_ill(folder, output_folder):
148
+ """Convert an annual daylight results folder to older version.
149
+
150
+ This command reads an annual daylight results folder with results saved as
151
+ npy files (NumPy), and converts the npy files to text files in the old
152
+ results folder format.
153
+
154
+ \b
155
+ Args:
156
+ folder: Results folder. This folder is an output folder of annual
157
+ daylight recipe. Folder should include grids_info.json and
158
+ sun-up-hours.txt.
159
+ """
160
+ try:
161
+ folder = Path(folder)
162
+ static_ill_folder = folder.joinpath('__static_apertures__/default/total')
163
+ if not static_ill_folder.exists():
164
+ raise FileNotFoundError(
165
+ 'No results were found for static apertures in the results '
166
+ 'folder.')
167
+ grids_info_file = folder.joinpath('grids_info.json')
168
+ if not grids_info_file.exists():
169
+ raise FileNotFoundError(
170
+ 'The file grids_info.json was not found in the results folder.')
171
+ sun_up_hours_file = folder.joinpath('sun-up-hours.txt')
172
+ if not sun_up_hours_file.exists():
173
+ raise FileNotFoundError(
174
+ 'The file sun-up-hours.txt was not found in the results folder.')
175
+
176
+ if output_folder is None:
177
+ output_folder = folder.parent.joinpath('results_ill')
178
+ else:
179
+ output_folder = Path(output_folder)
180
+ output_folder.mkdir(parents=True, exist_ok=True)
181
+
182
+ with open(grids_info_file) as json_file:
183
+ grids_info = json.load(json_file)
184
+
185
+ for grid_info in grids_info:
186
+ full_id = grid_info['full_id']
187
+ npy_file = static_ill_folder.joinpath(f'{full_id}.npy')
188
+
189
+ array = np.load(npy_file)
190
+ output = Path(output_folder, full_id + '.ill')
191
+ np.savetxt(output, array, fmt='%.7e', delimiter='\t')
192
+
193
+ # copy grids_info and sun-up-hours
194
+ shutil.copy(grids_info_file, output_folder.joinpath('grids_info.json'))
195
+ shutil.copy(sun_up_hours_file, output_folder.joinpath('sun-up-hours.txt'))
196
+ except Exception:
197
+ _logger.exception('Converting annual daylight results folder failed.')
198
+ sys.exit(1)
199
+ else:
200
+ sys.exit(0)
@@ -0,0 +1,177 @@
1
+ """Helper functions."""
2
+ import json
3
+ import numpy as np
4
+
5
+ from honeybee.model import Model
6
+
7
+
8
+ def model_grid_areas(model, grids_info):
9
+ if isinstance(model, Model):
10
+ hb_model = model
11
+ else:
12
+ hb_model = Model.from_file(model)
13
+
14
+ full_ids = [grid_info['full_id'] for grid_info in grids_info]
15
+ sensor_grids = hb_model.properties.radiance.sensor_grids
16
+ grid_areas = []
17
+ for s_grid in sensor_grids:
18
+ if s_grid.identifier in full_ids:
19
+ if s_grid.mesh is not None:
20
+ grid_areas.append(s_grid.mesh.face_areas)
21
+ grid_areas = [np.array(grid) for grid in grid_areas]
22
+ if not grid_areas:
23
+ grid_areas = [None] * len(full_ids)
24
+
25
+ return grid_areas
26
+
27
+
28
+ def grid_summary(
29
+ folder, extension, grid_areas=None, grids_info=None, name='grid_summary',
30
+ grid_metrics=None
31
+ ):
32
+ """Calculate a grid summary for a single metric.
33
+
34
+ Args:
35
+ folder: A folder with results.
36
+ extension: Extension of the files to collect data from.
37
+ grid_areas: A list of area of each sensor.
38
+ grids_info: Grid information as a dictionary.
39
+ name: Optional filename of grid summary.
40
+ grid_metrics: Additional customized metrics to calculate.
41
+ """
42
+ if grids_info is None:
43
+ gi_file = folder.joinpath('grids_info.json')
44
+ if not gi_file.exists():
45
+ raise FileNotFoundError(
46
+ f'The file grids_info.json was not found in the folder: {folder}.')
47
+ with open(gi_file) as gi:
48
+ grids_info = json.load(gi)
49
+
50
+ if grid_areas is None:
51
+ grid_areas = [None] * len(grids_info)
52
+
53
+ # set up the default data types
54
+ dtype = [
55
+ ('Sensor Grid', 'O'),
56
+ ('Mean', np.float32),
57
+ ('Minimum', np.float32),
58
+ ('Maximum', np.float32),
59
+ ('Uniformity Ratio', np.float32)
60
+ ]
61
+
62
+ if grid_metrics is not None:
63
+ for gr_m in grid_metrics:
64
+ gr_m_h = []
65
+ for k, v in gr_m.items():
66
+ gr_m_h.append(k + str(v))
67
+ dtype.append((' '.join(gr_m_h), np.float32))
68
+
69
+ header = [dt[0] for dt in dtype]
70
+
71
+ arrays = []
72
+ for grid_info, grid_area in zip(grids_info, grid_areas):
73
+ full_id = grid_info['full_id']
74
+ array = np.loadtxt(folder.joinpath(f'{full_id}.{extension}'))
75
+ _mean = array.mean()
76
+ _min = array.min()
77
+ _max = array.max()
78
+ _uniformity_ratio = _min / _mean * 100
79
+
80
+ data = [full_id, _mean, _min, _max, _uniformity_ratio]
81
+
82
+ if grid_metrics is not None:
83
+ # get grid metrics
84
+ grid_metrics_data = \
85
+ _get_grid_metrics(array, grid_metrics, grid_info, grid_area)
86
+ data.extend(grid_metrics_data)
87
+
88
+ arrays.append(tuple(data))
89
+
90
+ # create structured array
91
+ struct_array = np.array(arrays, dtype=dtype)
92
+
93
+ # write header to file
94
+ with open(folder.joinpath(f'{name}.csv'), 'w') as grid_summary_file:
95
+ grid_summary_file.write(','.join(header))
96
+ # write structured array to grid_summary_file
97
+ fmt = ['%s' , '%.2f', '%.2f', '%.2f', '%.2f']
98
+ if grid_metrics is not None:
99
+ fmt.extend(['%.2f' for _gr_m in grid_metrics])
100
+ with open(folder.joinpath(f'{name}.csv'), 'a') as grid_summary_file:
101
+ grid_summary_file.write('\n')
102
+ np.savetxt(grid_summary_file, struct_array, delimiter=',', fmt=fmt)
103
+
104
+ return grid_summary_file
105
+
106
+
107
+ def _calculate_percentage(gr_metric_bool, grid_info, grid_area=None):
108
+ """Calculate percentage of floor area where True.
109
+
110
+ Args:
111
+ gr_metric_bool: A NumPy array of booleans.
112
+ grid_info: Grid information.
113
+ grid_area: A NumPy array of area for each sensor. (Default: None).
114
+
115
+ Returns:
116
+ The percentage of floor area where gr_metric_bool is True.
117
+ """
118
+ if grid_area is not None:
119
+ gr_metric_pct = \
120
+ grid_area[gr_metric_bool].sum() / grid_area.sum() * 100
121
+ else:
122
+ gr_metric_pct = \
123
+ gr_metric_bool.sum() / grid_info['count'] * 100
124
+ return gr_metric_pct
125
+
126
+
127
+ def _numeric_type(array, gr_metric):
128
+ if 'minimum' in gr_metric:
129
+ gr_metric_bool = array > gr_metric['minimum']
130
+ elif 'exclusiveMinimum' in gr_metric:
131
+ gr_metric_bool = array >= gr_metric['minimum']
132
+ elif 'maximum' in gr_metric:
133
+ gr_metric_bool = array < gr_metric['maximum']
134
+ elif 'exclusiveMaximum' in gr_metric:
135
+ gr_metric_bool = array <= gr_metric['exclusiveMaximum']
136
+ return gr_metric_bool
137
+
138
+
139
+ def _grid_summary_all_any(array, gr_metric, grid_info, grid_area, keyword):
140
+ gr_metric_arrays = []
141
+ for gr_m in gr_metric[keyword]:
142
+ assert len(gr_m) == 1
143
+ gr_metric_arrays.append(_numeric_type(array, gr_m))
144
+ if keyword == 'allOf':
145
+ gr_metric_bool = np.all(gr_metric_arrays, axis=0)
146
+ else:
147
+ gr_metric_bool = np.any(gr_metric_arrays, axis=0)
148
+ gr_metric_pct = \
149
+ _calculate_percentage(gr_metric_bool, grid_info, grid_area)
150
+ return gr_metric_pct
151
+
152
+
153
+ def _get_grid_metrics(array, grid_metrics, grid_info, grid_area):
154
+ grid_metrics_data = []
155
+ for gr_metric in grid_metrics:
156
+ if len(gr_metric) == 1:
157
+ if 'allOf' in gr_metric:
158
+ gr_metric_pct = \
159
+ _grid_summary_all_any(
160
+ array, gr_metric, grid_info, grid_area, 'allOf')
161
+ elif 'anyOf' in gr_metric:
162
+ gr_metric_pct = \
163
+ _grid_summary_all_any(
164
+ array, gr_metric, grid_info, grid_area, 'anyOf')
165
+ else:
166
+ gr_metric_bool = _numeric_type(array, gr_metric)
167
+ gr_metric_pct = \
168
+ _calculate_percentage(gr_metric_bool, grid_info, grid_area)
169
+ elif len(gr_metric) == 2:
170
+ gr_metric_arrays = []
171
+ for k, threshold in gr_metric.items():
172
+ gr_metric_arrays.append(_numeric_type(array, {k: threshold}))
173
+ gr_metric_bool = np.all(gr_metric_arrays, axis=0)
174
+ gr_metric_pct = \
175
+ _calculate_percentage(gr_metric_bool, grid_info, grid_area)
176
+ grid_metrics_data.append(gr_metric_pct)
177
+ return grid_metrics_data
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-radiance-postprocess
3
- Version: 0.4.226
3
+ Version: 0.4.228
4
4
  Summary: Postprocessing of Radiance results and matrices
5
5
  Home-page: https://github.com/ladybug-tools/honeybee-radiance-postprocess
6
6
  Author: Ladybug Tools
@@ -1,159 +0,0 @@
1
- """Helper functions."""
2
- import numpy as np
3
-
4
- from honeybee.model import Model
5
-
6
-
7
- def model_grid_areas(model, grids_info):
8
- if isinstance(model, Model):
9
- hb_model = model
10
- else:
11
- hb_model = Model.from_file(model)
12
-
13
- full_ids = [grid_info['full_id'] for grid_info in grids_info]
14
- sensor_grids = hb_model.properties.radiance.sensor_grids
15
- grid_areas = []
16
- for s_grid in sensor_grids:
17
- if s_grid.identifier in full_ids:
18
- if s_grid.mesh is not None:
19
- grid_areas.append(s_grid.mesh.face_areas)
20
- grid_areas = [np.array(grid) for grid in grid_areas]
21
- if not grid_areas:
22
- grid_areas = [None] * len(full_ids)
23
-
24
- return grid_areas
25
-
26
-
27
- def grid_summary(
28
- folder, extension, grids_info, grid_areas, name='grid_summary',
29
- grid_metrics=None
30
- ):
31
- """Calculate a grid summary for a single metric.
32
-
33
- Args:
34
- folder: A folder with results.
35
- extension: Extension of the files to collect data from.
36
- grids_info: Grid information as a dictionary.
37
- grid_areas:
38
- name: Optional filename of grid summary.
39
- grid_metrics: Additional customized metrics to calculate.
40
- """
41
- # set up the default data types
42
- dtype = [
43
- ('Sensor Grid', 'O'),
44
- ('Mean', np.float32),
45
- ('Minimum', np.float32),
46
- ('Maximum', np.float32),
47
- ('Uniformity Ratio', np.float32)
48
- ]
49
-
50
- if grid_metrics is not None:
51
- for gr_m in grid_metrics:
52
- gr_m_h = []
53
- for k, v in gr_m.items():
54
- gr_m_h.append(k + str(v))
55
- dtype.append((' '.join(gr_m_h), np.float32))
56
-
57
- header = [dt[0] for dt in dtype]
58
-
59
- arrays = []
60
- for grid_info, grid_area in zip(grids_info, grid_areas):
61
- full_id = grid_info['full_id']
62
- array = np.loadtxt(folder.joinpath(f'{full_id}.{extension}'))
63
- _mean = array.mean()
64
- _min = array.min()
65
- _max = array.max()
66
- _uniformity_ratio = _min / _mean * 100
67
-
68
- data = [full_id, _mean, _min, _max, _uniformity_ratio]
69
-
70
- grid_metrics_data = []
71
- if grid_metrics is not None:
72
- for gr_metric in grid_metrics:
73
- if len(gr_metric) == 1:
74
- for k, v in gr_metric.items():
75
- if k == 'anyOff' or k == 'allOff':
76
- gr_metric_arrays = []
77
- for vv in v:
78
- for kk, threshold in vv.items():
79
- if kk == 'minimum':
80
- gr_metric_arrays.append(array > threshold)
81
- elif kk == 'exclusiveMinimum':
82
- gr_metric_arrays.append(array >= threshold)
83
- elif kk == 'maximum':
84
- gr_metric_arrays.append(array < threshold)
85
- elif kk == 'exclusiveMaximum':
86
- gr_metric_arrays.append(array <= threshold)
87
- if k == 'anyOff':
88
- gr_metric_bool = np.any(gr_metric_arrays, axis=0)
89
- else:
90
- gr_metric_bool = np.all(gr_metric_arrays, axis=0)
91
- gr_metric_pct = \
92
- _calculate_percentage(gr_metric_bool, grid_info, grid_area)
93
- else:
94
- threshold = v
95
- if k == 'minimum':
96
- gr_metric_bool = array > threshold
97
- elif k == 'exclusiveMinimum':
98
- gr_metric_bool = array >= threshold
99
- elif k == 'maximum':
100
- gr_metric_bool = array < threshold
101
- elif k == 'exclusiveMaximum':
102
- gr_metric_bool = array <= threshold
103
- gr_metric_pct = \
104
- _calculate_percentage(gr_metric_bool, grid_info, grid_area)
105
- elif len(gr_metric) == 2:
106
- gr_metric_arrays = []
107
- for k, threshold in gr_metric.items():
108
- if k == 'minimum':
109
- gr_metric_arrays.append(array > threshold)
110
- elif k == 'exclusiveMinimum':
111
- gr_metric_arrays.append(array >= threshold)
112
- elif k == 'maximum':
113
- gr_metric_arrays.append(array < threshold)
114
- elif k == 'exclusiveMaximum':
115
- gr_metric_arrays.append(array <= threshold)
116
- gr_metric_bool = np.all(gr_metric_arrays, axis=0)
117
- gr_metric_pct = \
118
- _calculate_percentage(gr_metric_bool, grid_info, grid_area)
119
- grid_metrics_data.append(gr_metric_pct)
120
-
121
- data.extend(grid_metrics_data)
122
-
123
- arrays.append(tuple(data))
124
-
125
- # create structured array
126
- struct_array = np.array(arrays, dtype=dtype)
127
-
128
- # write header to file
129
- with open(folder.joinpath(f'{name}.csv'), 'w') as file:
130
- file.write(','.join(header))
131
- # write structured array to file
132
- fmt = ['%s' , '%.2f', '%.2f', '%.2f', '%.2f']
133
- if grid_metrics is not None:
134
- fmt.extend(['%.2f' for d in grid_metrics])
135
- with open(folder.joinpath(f'{name}.csv'), 'a') as file:
136
- file.write('\n')
137
- np.savetxt(file, struct_array, delimiter=',', fmt=fmt)
138
-
139
- return file
140
-
141
-
142
- def _calculate_percentage(gr_metric_bool, grid_info, grid_area=None):
143
- """Calculate percentage of floor area where True.
144
-
145
- Args:
146
- gr_metric_bool: A NumPy array of booleans.
147
- grid_info: Grid information.
148
- grid_area: A NumPy array of area for each sensor. (Default: None).
149
-
150
- Returns:
151
- The percentage of floor area where gr_metric_bool is True.
152
- """
153
- if grid_area is not None:
154
- gr_metric_pct = \
155
- grid_area[gr_metric_bool].sum() / grid_area.sum() * 100
156
- else:
157
- gr_metric_pct = \
158
- gr_metric_bool.sum() / grid_info['count'] * 100
159
- return gr_metric_pct