honeybee-radiance-postprocess 0.4.543__tar.gz → 0.4.544__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 (60) hide show
  1. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/PKG-INFO +1 -1
  2. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/annual.py +11 -4
  3. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/annualdaylight.py +6 -1
  4. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/breeam/breeam.py +10 -5
  5. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/abnt.py +6 -1
  6. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/datacollection.py +6 -1
  7. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/grid.py +6 -1
  8. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/merge.py +6 -1
  9. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/mtxop.py +6 -1
  10. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/postprocess.py +8 -3
  11. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/translate.py +6 -1
  12. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/two_phase.py +6 -1
  13. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/viewfactor.py +6 -1
  14. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/data_type.py +6 -1
  15. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/electriclight.py +7 -1
  16. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/en17037.py +6 -1
  17. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/helper.py +17 -3
  18. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/ies/lm.py +6 -1
  19. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/ies/lm_schedule.py +6 -1
  20. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/leed/leed.py +38 -32
  21. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/leed/leed_schedule.py +20 -7
  22. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/metrics.py +33 -12
  23. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/reader.py +6 -1
  24. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/results/annual_daylight.py +17 -17
  25. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/results/annual_irradiance.py +6 -1
  26. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/results/results.py +49 -29
  27. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/type_hints.py +8 -1
  28. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/util.py +30 -2
  29. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/PKG-INFO +1 -1
  30. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/CODE_OF_CONDUCT.md +0 -0
  31. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/CONTRIBUTING.md +0 -0
  32. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/LICENSE +0 -0
  33. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/MANIFEST.in +0 -0
  34. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/README.md +0 -0
  35. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/dev-requirements.txt +0 -0
  36. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/__init__.py +0 -0
  37. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/__main__.py +0 -0
  38. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/annualirradiance.py +0 -0
  39. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/breeam/__init__.py +0 -0
  40. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/__init__.py +0 -0
  41. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/breeam.py +0 -0
  42. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/leed.py +0 -0
  43. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/schedule.py +0 -0
  44. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/util.py +0 -0
  45. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/cli/well.py +0 -0
  46. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/dynamic.py +0 -0
  47. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/ies/__init__.py +0 -0
  48. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/leed/__init__.py +0 -0
  49. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/results/__init__.py +0 -0
  50. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/vis_metadata.py +0 -0
  51. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/well/__init__.py +0 -0
  52. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess/well/well.py +0 -0
  53. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/SOURCES.txt +0 -0
  54. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/dependency_links.txt +0 -0
  55. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/entry_points.txt +0 -0
  56. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/requires.txt +0 -0
  57. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/honeybee_radiance_postprocess.egg-info/top_level.txt +0 -0
  58. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/requirements.txt +0 -0
  59. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/setup.cfg +0 -0
  60. {honeybee_radiance_postprocess-0.4.543 → honeybee_radiance_postprocess-0.4.544}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-radiance-postprocess
3
- Version: 0.4.543
3
+ Version: 0.4.544
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,10 +1,17 @@
1
1
  """Shared functions for post-processing annual results."""
2
2
  from typing import Union
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from ladybug.analysisperiod import AnalysisPeriod
6
11
  from .util import filter_array
7
12
 
13
+ is_cpu = not is_gpu
14
+
8
15
 
9
16
  def occupancy_schedule_8_to_6(
10
17
  timestep: int = 1, as_list: bool = False) -> Union[np.ndarray, list]:
@@ -19,10 +26,10 @@ def occupancy_schedule_8_to_6(
19
26
  Returns:
20
27
  A schedule as an array or list.
21
28
  """
22
- full_analysis_period = AnalysisPeriod(timestep=timestep)
23
- analysis_period = AnalysisPeriod(st_hour=8, end_hour=17, timestep=timestep)
29
+ full_analysis_period = np.array(AnalysisPeriod(timestep=timestep).hoys)
30
+ analysis_period = np.array(AnalysisPeriod(st_hour=8, end_hour=17, timestep=timestep).hoys)
24
31
  schedule = np.zeros(8760 * timestep).astype(int)
25
- hours = np.where(np.isin(full_analysis_period.hoys, analysis_period.hoys))[0]
32
+ hours = np.where(np.isin(full_analysis_period, analysis_period))[0]
26
33
  schedule[hours] = 1
27
34
  if as_list:
28
35
  schedule = schedule.tolist()
@@ -4,7 +4,12 @@ Note: These functions will most likely be moved to a separate package in the nea
4
4
  """
5
5
  import json
6
6
  import os
7
- import numpy as np
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from ladybug.color import Colorset
10
15
  from ladybug.datatype.fraction import Fraction
@@ -2,7 +2,12 @@
2
2
  from typing import Union
3
3
  from pathlib import Path
4
4
  import json
5
- import numpy as np
5
+ try:
6
+ import cupy as np
7
+ is_gpu = True
8
+ except ImportError:
9
+ is_gpu = False
10
+ import numpy as np
6
11
 
7
12
  from honeybee.model import Model
8
13
  from honeybee_radiance.writer import _filter_by_pattern
@@ -339,7 +344,7 @@ def breeam_daylight_assessment_4b(
339
344
  hb_model.properties.radiance.sensor_grids, filter=grids_filter)
340
345
  for s_grid in filt_grids:
341
346
  if s_grid.mesh is not None:
342
- grid_areas[s_grid.identifier] = np.array(s_grid.mesh.face_areas).sum()
347
+ grid_areas[s_grid.identifier] = int(np.array(s_grid.mesh.face_areas).sum())
343
348
  else:
344
349
  grid_areas[s_grid.identifier] = None
345
350
  hb_room = hb_model.rooms_by_identifier([s_grid.room_identifier])[0]
@@ -397,7 +402,7 @@ def breeam_daylight_assessment_4b(
397
402
  target_hrs = metrics['minimum_daylight_illuminance']['hours']
398
403
  min_comply = hrs_abv_min >= target_hrs
399
404
 
400
- minimum_illuminance_index = np.argsort(hrs_abv_target)[0]
405
+ minimum_illuminance_index = int(np.argsort(hrs_abv_target)[0])
401
406
  minimum_illuminance_sensor = \
402
407
  sensor_grid_mapper[grid_info['full_id']].sensors[minimum_illuminance_index]
403
408
  minimum_illuminance_sensors[grid_info['full_id']] = \
@@ -482,11 +487,11 @@ def breeam_daylight_assessment_4b(
482
487
  area_proportions = np.array(areas) / program_type_summary['total_area']
483
488
 
484
489
  weighted_hours_avg = area_proportions * np.array(avg_hrs)
485
- total_weighted_hours_avg = np.sum(weighted_hours_avg)
490
+ total_weighted_hours_avg = int(np.sum(weighted_hours_avg))
486
491
  program_type_summary['average-illuminance-hours'] = total_weighted_hours_avg
487
492
 
488
493
  weighted_hours_min = area_proportions * np.array(min_hrs)
489
- total_weighted_hours_min = np.sum(weighted_hours_min)
494
+ total_weighted_hours_min = int(np.sum(weighted_hours_min))
490
495
  program_type_summary['minimum-illuminance-hours'] = total_weighted_hours_min
491
496
 
492
497
  program_summary.append(program_type_summary)
@@ -4,7 +4,12 @@ import sys
4
4
  import logging
5
5
  from pathlib import Path
6
6
  import click
7
- import numpy as np
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from honeybee.model import Model
10
15
  from honeybee.room import Room
@@ -1,10 +1,15 @@
1
1
  """Commands to work with data collections."""
2
2
  import sys
3
3
  import logging
4
- import numpy as np
5
4
  from pathlib import Path
6
5
  import click
7
6
  import json
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from ladybug.datacollection import HourlyContinuousCollection, \
10
15
  HourlyDiscontinuousCollection
@@ -3,8 +3,13 @@ import click
3
3
  import sys
4
4
  import logging
5
5
  import json
6
- import numpy as np
7
6
  from pathlib import Path
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from honeybee_radiance_postprocess.reader import binary_to_array
10
15
  from ..annualdaylight import _annual_daylight_vis_metadata
@@ -3,8 +3,13 @@ import click
3
3
  import sys
4
4
  import logging
5
5
  import json
6
- import numpy as np
7
6
  from pathlib import Path
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from honeybee_radiance_postprocess.reader import binary_to_array
10
15
 
@@ -2,8 +2,13 @@
2
2
  import sys
3
3
  import logging
4
4
  from pathlib import Path
5
- import numpy as np
6
5
  import click
6
+ try:
7
+ import cupy as np
8
+ is_gpu = True
9
+ except ImportError:
10
+ is_gpu = False
11
+ import numpy as np
7
12
 
8
13
  from ..reader import binary_to_array, ascii_to_array
9
14
 
@@ -5,7 +5,12 @@ import os
5
5
  import logging
6
6
  import json
7
7
  import click
8
- import numpy as np
8
+ try:
9
+ import cupy as np
10
+ is_gpu = True
11
+ except ImportError:
12
+ is_gpu = False
13
+ import numpy as np
9
14
 
10
15
  from ladybug.location import Location
11
16
  from ladybug.wea import Wea
@@ -721,8 +726,8 @@ def annual_metrics_file(
721
726
  if grid_name is None:
722
727
  grid_name = file.stem
723
728
 
724
- sun_up_hours_mask = np.where(np.isin(study_hours, sun_up_hours))[0]
725
- sun_down_hours_mask = np.where(~np.isin(study_hours, sun_up_hours))[0]
729
+ sun_up_hours_mask = np.where(np.isin(np.array(study_hours), np.array(sun_up_hours)))[0]
730
+ sun_down_hours_mask = np.where(~np.isin(np.array(study_hours), np.array(sun_up_hours)))[0]
726
731
  occ_mask = np.array(schedule, dtype=int)[sun_up_hours_mask]
727
732
  sun_down_occ_hours = np.array(schedule, dtype=int)[sun_down_hours_mask].sum()
728
733
  total_hours = sum(schedule)
@@ -3,9 +3,14 @@ import sys
3
3
  import logging
4
4
  from pathlib import Path
5
5
  import shutil
6
- import numpy as np
7
6
  import click
8
7
  import json
8
+ try:
9
+ import cupy as np
10
+ is_gpu = True
11
+ except ImportError:
12
+ is_gpu = False
13
+ import numpy as np
9
14
 
10
15
  from ..reader import binary_to_array
11
16
  from ..util import get_delimiter
@@ -2,8 +2,13 @@
2
2
  import sys
3
3
  import logging
4
4
  from pathlib import Path
5
- import numpy as np
6
5
  import click
6
+ try:
7
+ import cupy as np
8
+ is_gpu = True
9
+ except ImportError:
10
+ is_gpu = False
11
+ import numpy as np
7
12
 
8
13
  from ..reader import binary_to_array, ascii_to_array
9
14
 
@@ -4,7 +4,12 @@ import os
4
4
  import sys
5
5
  import logging
6
6
  import math
7
- import numpy as np
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from honeybee_radiance.config import folders
10
15
 
@@ -1,6 +1,11 @@
1
1
  """Functions for NumPy data type (dtype)."""
2
2
  from typing import Tuple
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
 
6
11
  def smallest_integer_dtype(array: np.ndarray) -> np.signedinteger:
@@ -1,6 +1,12 @@
1
1
  """Functions for post-processing daylight outputs into electric lighting schedules."""
2
2
  from typing import List
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
9
+
4
10
 
5
11
  def array_to_dimming_fraction(
6
12
  array: np.ndarray, su_pattern: List[int], setpt: float, m_pow: float,
@@ -2,7 +2,12 @@
2
2
  from typing import Union
3
3
  from pathlib import Path
4
4
  import json
5
- import numpy as np
5
+ try:
6
+ import cupy as np
7
+ is_gpu = True
8
+ except ImportError:
9
+ is_gpu = False
10
+ import numpy as np
6
11
 
7
12
  from ladybug.color import Colorset
8
13
  from ladybug.datatype.fraction import Fraction
@@ -1,7 +1,12 @@
1
1
  """Helper functions."""
2
2
  import json
3
- import numpy as np
4
3
  from pathlib import Path
4
+ try:
5
+ import cupy as np
6
+ is_gpu = True
7
+ except ImportError:
8
+ is_gpu = False
9
+ import numpy as np
5
10
 
6
11
  from honeybee.model import Model
7
12
 
@@ -144,7 +149,10 @@ def grid_summary(
144
149
  arrays.append(tuple(data))
145
150
 
146
151
  # create structured array
147
- struct_array = np.array(arrays, dtype=dtype)
152
+ if is_gpu:
153
+ struct_array = None
154
+ else:
155
+ struct_array = np.array(arrays, dtype=dtype)
148
156
 
149
157
  header = [dt[0] for dt in dtype]
150
158
  # write header to file
@@ -153,7 +161,13 @@ def grid_summary(
153
161
  # write structured array to grid_summary_file
154
162
  with open(folder.joinpath(f'{name}.csv'), 'a') as grid_summary_file:
155
163
  grid_summary_file.write('\n')
156
- np.savetxt(grid_summary_file, struct_array, delimiter=',', fmt=fmt)
164
+ if is_gpu:
165
+ # CuPy doesn't support structured arrays; manually format rows
166
+ for row in arrays:
167
+ row_str = ','.join(fmt_val % val for fmt_val, val in zip(fmt, row))
168
+ grid_summary_file.write(row_str + '\n')
169
+ else:
170
+ np.savetxt(grid_summary_file, struct_array, delimiter=',', fmt=fmt)
157
171
 
158
172
  return grid_summary_file
159
173
 
@@ -2,7 +2,12 @@
2
2
  from typing import Tuple, Union
3
3
  from collections import defaultdict
4
4
  import itertools
5
- import numpy as np
5
+ try:
6
+ import cupy as np
7
+ is_gpu = True
8
+ except ImportError:
9
+ is_gpu = False
10
+ import numpy as np
6
11
 
7
12
  from honeybee_radiance.postprocess.annual import filter_schedule_by_hours
8
13
 
@@ -1,6 +1,11 @@
1
1
  """Module for dynamic LM schedules."""
2
2
  from typing import Tuple
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from ..results.annual_daylight import AnnualDaylight
6
11
  from ..util import filter_array
@@ -4,7 +4,12 @@ from pathlib import Path
4
4
  from collections import defaultdict
5
5
  import json
6
6
  import itertools
7
- import numpy as np
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from ladybug.analysisperiod import AnalysisPeriod
10
15
  from ladybug.datatype.generic import GenericType
@@ -22,10 +27,12 @@ from honeybee_radiance.postprocess.annual import filter_schedule_by_hours
22
27
  from ..metrics import da_array2d, ase_array2d
23
28
  from ..annual import schedule_to_hoys, occupancy_schedule_8_to_6
24
29
  from ..results.annual_daylight import AnnualDaylight
25
- from ..util import filter_array, recursive_dict_merge
30
+ from ..util import recursive_dict_merge, filter_array2d
26
31
  from ..dynamic import DynamicSchedule, ApertureGroupSchedule
27
32
  from .leed_schedule import shd_trans_schedule_descending, states_schedule_descending
28
33
 
34
+ is_cpu = not is_gpu
35
+
29
36
 
30
37
  def _create_grid_summary(
31
38
  grid_info, sda_grid, sda_blinds_up_grid, sda_blinds_down_grid, ase_grid,
@@ -117,7 +124,6 @@ def _leed_summary(
117
124
  """
118
125
  summary = {}
119
126
  summary_grid = {}
120
-
121
127
  if all(grid_area is not None for grid_area in grid_areas):
122
128
  # weighted by mesh face area
123
129
  total_area = 0
@@ -127,17 +133,17 @@ def _leed_summary(
127
133
  pass_sda_blinds_down) in \
128
134
  zip(pass_ase_grids, pass_sda_grids, grid_areas, grids_info,
129
135
  pass_sda_blinds_up_grids, pass_sda_blinds_down_grids):
130
- total_grid_area = grid_area.sum()
136
+ total_grid_area = float(grid_area.sum())
131
137
 
132
- area_pass_ase = grid_area[pass_ase].sum()
133
- ase_grid = (total_grid_area - area_pass_ase) / total_grid_area * 100
138
+ area_pass_ase = float(grid_area[pass_ase].sum())
139
+ ase_grid = float((total_grid_area - area_pass_ase) / total_grid_area * 100)
134
140
 
135
- area_pass_sda = grid_area[pass_sda].sum()
141
+ area_pass_sda = float(grid_area[pass_sda].sum())
136
142
  area_pass_sda_blind_up = grid_area[pass_sda_blinds_up].sum()
137
143
  area_pass_sda_blinds_down = grid_area[pass_sda_blinds_down].sum()
138
- sda_grid = area_pass_sda / total_grid_area * 100
139
- sda_blinds_up_grid = area_pass_sda_blind_up / total_grid_area * 100
140
- sda_blinds_down_grid = area_pass_sda_blinds_down / total_grid_area * 100
144
+ sda_grid = float(area_pass_sda / total_grid_area * 100)
145
+ sda_blinds_up_grid = float(area_pass_sda_blind_up / total_grid_area * 100)
146
+ sda_blinds_down_grid = float(area_pass_sda_blinds_down / total_grid_area * 100)
141
147
 
142
148
  # grid summary
143
149
  grid_summary = \
@@ -298,8 +304,7 @@ def shade_transmittance_per_light_path(
298
304
  def leed_states_schedule(
299
305
  results: Union[str, AnnualDaylight], grids_filter: str = '*',
300
306
  shade_transmittance: Union[float, dict] = 0.05,
301
- use_states: bool = False
302
- ) -> Tuple[dict, dict]:
307
+ use_states: bool = False) -> Tuple[dict, dict, dict]:
303
308
  """Calculate a schedule of each aperture group for LEED compliant sDA.
304
309
 
305
310
  This function calculates an annual shading schedule of each aperture
@@ -404,11 +409,9 @@ def leed_states_schedule(
404
409
  fail_to_comply[grid_info['name']] = \
405
410
  [int(hoy) for hoy in grid_comply]
406
411
 
407
- array_combinations_filter = np.apply_along_axis(
408
- filter_array, 1, array_combinations, occ_mask
409
- )
410
- max_indices = array_combinations_filter.argmax(axis=0)
411
- # select the combination for each hour
412
+ array_combinations_filter = filter_array2d(array_combinations, occ_mask)
413
+
414
+ max_indices = [int(i) for i in array_combinations_filter.argmax(axis=0)]
412
415
  combinations = [combinations[idx] for idx in max_indices]
413
416
  # merge the combinations of dicts
414
417
  for combination in combinations:
@@ -416,6 +419,8 @@ def leed_states_schedule(
416
419
  if light_path != '__static_apertures__':
417
420
  grid_states_schedule[light_path].append(value)
418
421
 
422
+ del array_list_combinations, array_combinations, array_combinations_filter, combination_arrays
423
+
419
424
  for key, value in grid_states_schedule.items():
420
425
  if key not in states_schedule:
421
426
  states_schedule[key] = value
@@ -502,7 +507,7 @@ def leed_option_one(
502
507
  schedule = occupancy_schedule_8_to_6(as_list=True)
503
508
 
504
509
  if not isinstance(results, AnnualDaylight):
505
- results = AnnualDaylight(results, schedule=schedule, cache_arrays=False)
510
+ results = AnnualDaylight(results, schedule=schedule, cache_arrays=True)
506
511
  else:
507
512
  # set schedule to default leed schedule
508
513
  results.schedule = schedule
@@ -555,8 +560,7 @@ def leed_option_one(
555
560
  for light_path in light_paths:
556
561
  array = results._get_array(
557
562
  grid_info, light_path, res_type='direct')
558
- array_filter = np.apply_along_axis(
559
- filter_array, 1, array, occ_mask)
563
+ array_filter = filter_array2d(array, occ_mask)
560
564
  arrays.append(array_filter)
561
565
  array = sum(arrays)
562
566
  # calculate ase per grid
@@ -575,6 +579,7 @@ def leed_option_one(
575
579
  hours_above.append(h_above)
576
580
  pass_ase = h_above < occ_hours
577
581
  pass_ase_grids.append(pass_ase)
582
+ results.clear_cached_arrays(res_type='direct') # don't need direct arrays
578
583
 
579
584
  # spatial daylight autonomy
580
585
  da_grids = []
@@ -589,42 +594,40 @@ def leed_option_one(
589
594
  pass
590
595
  else:
591
596
  light_paths.append(_lp)
592
- base_zero_array = np.apply_along_axis(filter_array, 1, np.zeros(
593
- (grid_info['count'], len(results.sun_up_hours))), occ_mask)
597
+ base_zero_array = filter_array2d(
598
+ np.zeros((grid_info['count'], len(results.sun_up_hours))), occ_mask)
594
599
  arrays = [base_zero_array.copy()]
595
600
  arrays_blinds_up = [base_zero_array.copy()]
596
601
  arrays_blinds_down = [base_zero_array.copy()]
597
602
  # combine total array for all light paths
598
603
  if use_states:
599
604
  array = results._array_from_states(grid_info, states=states_schedule, zero_array=True)
600
- array = np.apply_along_axis(filter_array, 1, array, occ_mask)
605
+ array = filter_array2d(array, occ_mask)
601
606
 
602
607
  for light_path in light_paths:
603
608
  # do an extra pass to calculate with blinds always up or down
604
609
  if light_path != '__static_apertures__':
605
610
  array_blinds_up = results._get_array(
606
611
  grid_info, light_path, state=0, res_type='total')
607
- array_filter = np.apply_along_axis(
608
- filter_array, 1, array_blinds_up, occ_mask)
612
+ array_filter = filter_array2d(array_blinds_up, occ_mask)
609
613
  arrays_blinds_up.append(array_filter)
610
614
  array_blinds_down = results._get_array(
611
615
  grid_info, light_path, state=1, res_type='total')
612
- array_filter = np.apply_along_axis(
613
- filter_array, 1, array_blinds_down, occ_mask)
616
+ array_filter = filter_array2d(array_blinds_down, occ_mask)
617
+ arrays_blinds_down.append(array_filter)
614
618
  arrays_blinds_down.append(array_filter)
615
619
  else:
616
620
  static_array = results._get_array(
617
621
  grid_info, light_path, state=0, res_type='total')
618
- array_filter = np.apply_along_axis(
619
- filter_array, 1, static_array, occ_mask)
622
+ array_filter = filter_array2d(static_array, occ_mask)
623
+ arrays.append(array_filter)
620
624
  arrays_blinds_up.append(array_filter)
621
625
  arrays_blinds_down.append(array_filter)
622
626
  else:
623
627
  for light_path in light_paths:
624
628
  array = results._get_array(
625
629
  grid_info, light_path, res_type='total')
626
- array_filter = np.apply_along_axis(
627
- filter_array, 1, array, occ_mask)
630
+ array_filter = filter_array2d(array, occ_mask)
628
631
  if light_path != '__static_apertures__':
629
632
  sun_up_hours = np.array(results.sun_up_hours).astype(int)
630
633
  shd_trans_array = states_schedule[light_path][sun_up_hours]
@@ -652,6 +655,7 @@ def leed_option_one(
652
655
  pass_sda_grids.append(da_grid >= target_time)
653
656
  pass_sda_blinds_up_grids.append(da_blinds_up_grid >= target_time)
654
657
  pass_sda_blinds_down_grids.append(da_blinds_down_grid >= target_time)
658
+ results.clear_cached_arrays(res_type='total')
655
659
 
656
660
  # create summaries for all grids and each grid individually
657
661
  summary, summary_grid = _leed_summary(
@@ -701,7 +705,9 @@ def leed_option_one(
701
705
  return hourly_data.to_dict()
702
706
 
703
707
  if use_states:
704
- states_schedule = {k:to_datacollection(k, v['schedule']) for k, v in states_schedule.to_dict().items()}
708
+ states_schedule = {
709
+ k: to_datacollection(k, v['schedule']) for k,
710
+ v in states_schedule.to_dict().items()}
705
711
  else:
706
712
  states_schedule = {k:to_datacollection(k, v) for k, v in states_schedule.items()}
707
713
 
@@ -1,9 +1,14 @@
1
1
  """Module for dynamic LEED schedules."""
2
2
  from typing import Tuple
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from ..results.annual_daylight import AnnualDaylight
6
- from ..util import filter_array
11
+ from ..util import filter_array2d
7
12
 
8
13
 
9
14
  def shd_trans_schedule_descending(
@@ -16,7 +21,7 @@ def shd_trans_schedule_descending(
16
21
  full_shd_trans_array = []
17
22
  for light_path in light_paths:
18
23
  array = results._get_array(grid_info, light_path, res_type="direct")
19
- array = np.apply_along_axis(filter_array, 1, array, occ_mask)
24
+ array = filter_array2d(array, occ_mask)
20
25
  full_direct.append(array)
21
26
  full_thresh.append((array >= 1000).sum(axis=0))
22
27
  full_shd_trans_array.append(shade_transmittances[light_path][1])
@@ -50,6 +55,7 @@ def shd_trans_schedule_descending(
50
55
  # Use the indices to get the relevant hours.
51
56
  thresh = np.take(full_thresh, above_2_indices, axis=1)
52
57
 
58
+ del full_direct, full_thresh
53
59
  # Sort and get indices. Negate the array to get descending order.
54
60
  # Descending order puts the "highest offender" light path first.
55
61
  sort_thresh = np.argsort(-thresh, axis=0).transpose()
@@ -59,6 +65,8 @@ def shd_trans_schedule_descending(
59
65
  0, (np.arange(full_direct_sum.shape[1]), combinations)
60
66
  )
61
67
 
68
+ del full_direct_sum
69
+
62
70
  if np.any(above_2_indices):
63
71
  # There are hours where the percentage of floor area is > 2%.
64
72
  for idx, lp in enumerate(light_paths):
@@ -142,6 +150,8 @@ def shd_trans_schedule_descending(
142
150
 
143
151
  combinations = _combination
144
152
 
153
+ del full_shd_trans_array, direct_sum, direct, thresh, sort_thresh
154
+
145
155
  # Merge the combinations of dicts.
146
156
  for combination in combinations:
147
157
  for light_path, shd_trans in combination.items():
@@ -162,27 +172,26 @@ def states_schedule_descending(
162
172
  for light_path in light_paths:
163
173
  array = results._get_array(
164
174
  grid_info, light_path, state=0, res_type="direct")
165
- array = np.apply_along_axis(filter_array, 1, array, occ_mask)
175
+ array = filter_array2d(array, occ_mask)
166
176
  full_direct.append(array)
167
177
  full_thresh.append((array >= 1000).sum(axis=0))
168
178
 
169
179
  array = results._get_array(
170
180
  grid_info, light_path, state=1, res_type="direct")
171
- array = np.apply_along_axis(filter_array, 1, array, occ_mask)
181
+ array = filter_array2d(array, occ_mask)
172
182
  full_direct_blinds.append(array)
173
183
 
174
184
  full_direct = np.array(full_direct)
175
185
  full_direct_blinds = np.array(full_direct_blinds)
176
186
  full_direct_sum = full_direct.sum(axis=0)
177
187
 
178
- new_array = full_direct.copy()
179
-
180
188
  percentage_sensors = (full_direct_sum >= 1000).sum(axis=0) / grid_count
181
189
  if not np.any(percentage_sensors > 0.02):
182
190
  combinations = [
183
191
  {light_path: 0 for light_path in light_paths}
184
192
  for i in range(full_direct_sum.shape[1])]
185
193
  else:
194
+ new_array = full_direct.copy()
186
195
  tracking_array = np.zeros(
187
196
  (new_array.shape[0], new_array.shape[2]), dtype=int)
188
197
 
@@ -235,6 +244,10 @@ def states_schedule_descending(
235
244
  fail_to_comply[grid_info['name']] = [
236
245
  int(hoy) for hoy in grid_comply]
237
246
 
247
+ del new_array, tracking_array, percentage_sensors, ranking_indices, final_summed_array
248
+
249
+ del full_direct, full_thresh, full_direct_blinds, full_direct_sum
250
+
238
251
  for combination in combinations:
239
252
  for light_path, value in combination.items():
240
253
  if light_path != '__static_apertures__':
@@ -1,13 +1,19 @@
1
1
  """Functions to calculate various metrics for 1D and 2D NumPy arrays."""
2
2
  from typing import Tuple, Union
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from .util import check_array_dim
6
11
 
12
+ is_cpu = not is_gpu
13
+
7
14
 
8
15
  def da_array2d(
9
- array: np.ndarray, total_occ: int = None,
10
- threshold: float = 300) -> np.ndarray:
16
+ array: np.ndarray, total_occ: int = None, threshold: float = 300) -> np.ndarray:
11
17
  """Calculate daylight autonomy for a 2D NumPy array.
12
18
 
13
19
  Args:
@@ -74,8 +80,11 @@ def cda_array2d(
74
80
  # set total_occ to number of columns in array
75
81
  total_occ = array.shape[1]
76
82
 
77
- cda = np.apply_along_axis(
78
- cda_array1d, 1, array, total_occ=total_occ, threshold=threshold)
83
+ if is_cpu:
84
+ cda = np.apply_along_axis(
85
+ cda_array1d, 1, array, total_occ=total_occ, threshold=threshold)
86
+ else:
87
+ cda = np.where(array >= threshold, 1, array / threshold).sum(axis=1) / total_occ * 100
79
88
 
80
89
  return cda
81
90
 
@@ -124,8 +133,11 @@ def udi_array2d(
124
133
  # set total_occ to number of columns in array
125
134
  total_occ = array.shape[1]
126
135
 
127
- udi = np.apply_along_axis(
128
- udi_array1d, 1, array, total_occ=total_occ, min_t=min_t, max_t=max_t)
136
+ if is_cpu:
137
+ udi = np.apply_along_axis(
138
+ udi_array1d, 1, array, total_occ=total_occ, min_t=min_t, max_t=max_t)
139
+ else:
140
+ udi = ((array >= min_t) & (array <= max_t)).sum(axis=1) / total_occ * 100
129
141
 
130
142
  return udi
131
143
 
@@ -174,9 +186,15 @@ def udi_lower_array2d(
174
186
  # set total_occ to number of columns in array
175
187
  total_occ = array.shape[1]
176
188
 
177
- udi = np.apply_along_axis(
178
- udi_lower_array1d, 1, array, total_occ=total_occ, min_t=min_t,
179
- sun_down_occ_hours=sun_down_occ_hours)
189
+ if is_cpu:
190
+ udi = np.apply_along_axis(
191
+ udi_lower_array1d, 1, array, total_occ=total_occ, min_t=min_t,
192
+ sun_down_occ_hours=sun_down_occ_hours)
193
+ else:
194
+ if min_t == 0:
195
+ return np.zeros(array.shape[0], dtype=np.float32)
196
+
197
+ udi = ((array < min_t).sum(axis=1) + sun_down_occ_hours) / total_occ * 100
180
198
 
181
199
  return udi
182
200
 
@@ -227,8 +245,11 @@ def udi_upper_array2d(
227
245
  # set total_occ to number of columns in array
228
246
  total_occ = array.shape[1]
229
247
 
230
- udi = np.apply_along_axis(
231
- udi_upper_array1d, 1, array, total_occ=total_occ, max_t=max_t)
248
+ if is_cpu:
249
+ udi = np.apply_along_axis(
250
+ udi_upper_array1d, 1, array, total_occ=total_occ, max_t=max_t)
251
+ else:
252
+ udi = (array > max_t).sum(axis=1) / total_occ * 100
232
253
 
233
254
  return udi
234
255
 
@@ -1,5 +1,10 @@
1
1
  """Post-processing reader functions."""
2
- import numpy as np
2
+ try:
3
+ import cupy as np
4
+ is_gpu = True
5
+ except ImportError:
6
+ is_gpu = False
7
+ import numpy as np
3
8
 
4
9
  from .util import binary_mtx_dimension
5
10
 
@@ -1,8 +1,13 @@
1
1
  import json
2
2
  from pathlib import Path
3
3
  from typing import Tuple, List
4
- import numpy as np
5
- import itertools
4
+ try:
5
+ import cupy as np
6
+ is_gpu = True
7
+ except ImportError:
8
+ is_gpu = False
9
+ import numpy as np
10
+
6
11
  from collections import defaultdict
7
12
 
8
13
  from ladybug.analysisperiod import AnalysisPeriod
@@ -14,13 +19,15 @@ from ladybug.header import Header
14
19
  from ..annual import occupancy_schedule_8_to_6
15
20
  from ..metrics import da_array2d, cda_array2d, udi_array2d, udi_lower_array2d, \
16
21
  udi_upper_array2d, ase_array2d
17
- from ..util import filter_array
22
+ from ..util import filter_array, filter_array2d
18
23
  from ..annualdaylight import _annual_daylight_vis_metadata
19
24
  from ..electriclight import array_to_dimming_fraction
20
25
  from .. import type_hints
21
26
  from ..dynamic import DynamicSchedule, ApertureGroupSchedule
22
27
  from .results import Results
23
28
 
29
+ is_cpu = not is_gpu
30
+
24
31
 
25
32
  class AnnualDaylight(Results):
26
33
  """Annual Daylight Results class.
@@ -71,8 +78,7 @@ class AnnualDaylight(Results):
71
78
  for grid_info in grids_info:
72
79
  array = self._array_from_states(grid_info, states=states, res_type='total')
73
80
  if np.any(array):
74
- array_filter = np.apply_along_axis(
75
- filter_array, 1, array, mask=self.occ_mask)
81
+ array_filter = filter_array2d(array, mask=self.occ_mask)
76
82
  results = da_array2d(
77
83
  array_filter, total_occ=self.total_occ, threshold=threshold)
78
84
  else:
@@ -102,8 +108,7 @@ class AnnualDaylight(Results):
102
108
  for grid_info in grids_info:
103
109
  array = self._array_from_states(grid_info, states=states, res_type='total')
104
110
  if np.any(array):
105
- array_filter = np.apply_along_axis(
106
- filter_array, 1, array, mask=self.occ_mask)
111
+ array_filter = filter_array2d(array, mask=self.occ_mask)
107
112
  results = cda_array2d(
108
113
  array_filter, total_occ=self.total_occ, threshold=threshold)
109
114
  else:
@@ -133,8 +138,7 @@ class AnnualDaylight(Results):
133
138
  for grid_info in grids_info:
134
139
  array = self._array_from_states(grid_info, states=states, res_type='total')
135
140
  if np.any(array):
136
- array_filter = np.apply_along_axis(
137
- filter_array, 1, array, mask=self.occ_mask)
141
+ array_filter = filter_array2d(array, mask=self.occ_mask)
138
142
  results = udi_array2d(
139
143
  array_filter, total_occ=self.total_occ, min_t=min_t, max_t=max_t)
140
144
  else:
@@ -165,8 +169,7 @@ class AnnualDaylight(Results):
165
169
  for grid_info in grids_info:
166
170
  array = self._array_from_states(grid_info, states=states, res_type='total')
167
171
  if np.any(array):
168
- array_filter = np.apply_along_axis(
169
- filter_array, 1, array, mask=self.occ_mask)
172
+ array_filter = filter_array2d(array, mask=self.occ_mask)
170
173
  results = udi_lower_array2d(
171
174
  array_filter, total_occ=self.total_occ,
172
175
  min_t=min_t, sun_down_occ_hours=sun_down_occ_hours)
@@ -197,8 +200,7 @@ class AnnualDaylight(Results):
197
200
  for grid_info in grids_info:
198
201
  array = self._array_from_states(grid_info, states=states, res_type='total')
199
202
  if np.any(array):
200
- array_filter = np.apply_along_axis(
201
- filter_array, 1, array, mask=self.occ_mask)
203
+ array_filter = filter_array2d(array, mask=self.occ_mask)
202
204
  results = udi_upper_array2d(
203
205
  array_filter, total_occ=self.total_occ, max_t=max_t)
204
206
  else:
@@ -242,8 +244,7 @@ class AnnualDaylight(Results):
242
244
  for grid_info in grids_info:
243
245
  array = self._array_from_states(grid_info, states=states, res_type='total')
244
246
  if np.any(array):
245
- array_filter = np.apply_along_axis(
246
- filter_array, 1, array, mask=self.occ_mask)
247
+ array_filter = filter_array2d(array, mask=self.occ_mask)
247
248
  da_results = da_array2d(
248
249
  array_filter, total_occ=self.total_occ, threshold=threshold)
249
250
  cda_results = cda_array2d(
@@ -379,8 +380,7 @@ class AnnualDaylight(Results):
379
380
  array = self._array_from_states(
380
381
  grid_info, states=states, res_type='direct')
381
382
  if np.any(array):
382
- array_filter = np.apply_along_axis(
383
- filter_array, 1, array, mask=self.occ_mask)
383
+ array_filter = filter_array2d(array, mask=self.occ_mask)
384
384
  results, h_above = ase_array2d(
385
385
  array_filter, occ_hours=occ_hours,
386
386
  direct_threshold=direct_threshold)
@@ -1,6 +1,11 @@
1
1
  import json
2
2
  from pathlib import Path
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from ladybug.datatype.energyflux import EnergyFlux
6
11
 
@@ -3,8 +3,13 @@ import json
3
3
  from pathlib import Path
4
4
  from itertools import islice, cycle
5
5
  from typing import Tuple, Union, List
6
- import numpy as np
7
6
  import itertools
7
+ try:
8
+ import cupy as np
9
+ is_gpu = True
10
+ except ImportError:
11
+ is_gpu = False
12
+ import numpy as np
8
13
 
9
14
  from ladybug.analysisperiod import AnalysisPeriod
10
15
  from ladybug.datacollection import HourlyContinuousCollection
@@ -21,6 +26,8 @@ from ..util import filter_array, hoys_mask, check_array_dim, \
21
26
  from .. import type_hints
22
27
  from ..dynamic import DynamicSchedule, ApertureGroupSchedule
23
28
 
29
+ is_cpu = not is_gpu
30
+
24
31
 
25
32
  class _ResultsFolder(object):
26
33
  """Base class for ResultsFolder.
@@ -239,14 +246,14 @@ class _ResultsFolder(object):
239
246
  def _get_sun_up_hours_mask(self) -> List[int]:
240
247
  """Get a sun up hours masking array of the study hours."""
241
248
  sun_up_hours_mask = \
242
- np.where(np.isin(self.study_hours, self.sun_up_hours))[0]
249
+ np.where(np.isin(np.array(self.study_hours), np.array(self.sun_up_hours)))[0]
243
250
 
244
251
  return sun_up_hours_mask
245
252
 
246
253
  def _get_sun_down_hours_mask(self) -> List[int]:
247
254
  """Get a sun down hours masking array of the study hours."""
248
255
  sun_down_hours_mask = \
249
- np.where(~np.isin(self.study_hours, self.sun_up_hours))[0]
256
+ np.where(~np.isin(np.array(self.study_hours), np.array(self.sun_up_hours)))[0]
250
257
 
251
258
  return sun_down_hours_mask
252
259
 
@@ -277,10 +284,11 @@ class Results(_ResultsFolder):
277
284
  * datatype
278
285
  * unit
279
286
  * cache_arrays
287
+ * use_gpu
280
288
  """
281
289
  __slots__ = ('_schedule', '_occ_pattern', '_total_occ', '_sun_down_occ_hours',
282
290
  '_occ_mask', '_arrays', '_valid_states', '_datatype', '_unit',
283
- '_cache_arrays')
291
+ '_cache_arrays', '_use_gpu')
284
292
 
285
293
  def __init__(self, folder, datatype: DataTypeBase = None,
286
294
  schedule: list = None, unit: str = None,
@@ -958,19 +966,23 @@ class Results(_ResultsFolder):
958
966
  values: A list of values to map to an annual array. This can be a
959
967
  regular list or a 1D NumPy array.
960
968
  timestep: Time step of the simulation.
961
- base_value: A value that will be applied for all the base array.
969
+ base_value: A value that will be applied for the base array.
962
970
  dtype: A NumPy dtype for the annual array.
963
971
 
964
972
  Returns:
965
973
  A 1D NumPy array.
966
974
  """
967
- values = np.array(values)
975
+ if not isinstance(values, np.ndarray):
976
+ values = np.array(values)
977
+ if not isinstance(hours, np.ndarray):
978
+ hours = np.array(hours)
968
979
  check_array_dim(values, 1)
969
- hours = np.array(hours)
970
980
  assert hours.shape == values.shape
971
- full_ap = AnalysisPeriod(timestep=timestep)
972
- indices = np.where(np.isin(full_ap.hoys, hours))[0]
973
- annual_array = np.repeat(base_value, 8760 * timestep).astype(dtype)
981
+
982
+ full_ap = np.array(AnalysisPeriod(timestep=timestep).hoys)
983
+ indices = np.where(np.isin(full_ap, hours))[0]
984
+ annual_array = np.repeat(np.array(base_value), 8760 * timestep).astype(dtype)
985
+
974
986
  annual_array[indices] = values
975
987
 
976
988
  return annual_array
@@ -1019,7 +1031,6 @@ class Results(_ResultsFolder):
1019
1031
  grid_id = grid_info['full_id']
1020
1032
 
1021
1033
  state_identifier = self._state_identifier(grid_id, light_path, state=state)
1022
-
1023
1034
  try:
1024
1035
  array = self.arrays[grid_id][light_path][state_identifier][res_type]
1025
1036
  except Exception:
@@ -1064,6 +1075,7 @@ class Results(_ResultsFolder):
1064
1075
  state_identifier = self._state_identifier(grid_id, light_path, state=state)
1065
1076
  file = self._get_file(grid_id, light_path, state_identifier, res_type,
1066
1077
  extension=extension)
1078
+
1067
1079
  array = np.load(file)
1068
1080
 
1069
1081
  if self.cache_arrays:
@@ -1073,12 +1085,12 @@ class Results(_ResultsFolder):
1073
1085
 
1074
1086
  return array
1075
1087
 
1076
- def _clear_cached_arrays(self, res_type: str = None):
1088
+ def clear_cached_arrays(self, res_type: str = None):
1077
1089
  """Clear the cached arrays.
1078
1090
 
1079
- This method will simply set the arrays property to an empty dictionary,
1080
- unless the res_type is selected in which case only 'total' or 'direct'
1081
- arrays will be deleted.
1091
+ This method will simply clear the arrays property to remove arrays from
1092
+ memory, unless the res_type is selected in which case only 'total' or
1093
+ 'direct' arrays will be deleted.
1082
1094
 
1083
1095
  Args:
1084
1096
  res_type: Which type of results to clear. This can be either
@@ -1276,29 +1288,37 @@ class Results(_ResultsFolder):
1276
1288
  grid_info, light_path, state=state, res_type=res_type)
1277
1289
  arrays.append(array)
1278
1290
  else:
1279
- # create default 0 array, we will add to this later
1280
- array = np.zeros((grid_info['count'], len(self.sun_up_hours)))
1281
1291
  # slice states to match sun up hours
1282
1292
  states_array = np.array(gr_schedule.schedule)[
1283
- list(map(int, self.sun_up_hours))]
1284
- for state in np.unique(states_array):
1285
- if state == -1:
1286
- # if state is -1 we continue since it is "turned off"
1287
- continue
1293
+ np.array(self.sun_up_hours, int)]
1294
+
1295
+ unique_states = np.unique(states_array)
1296
+ unique_states = unique_states[unique_states != -1] # skip -1
1297
+ temp_arrays = []
1298
+ for state in unique_states:
1299
+ state = int(state)
1288
1300
  # load static array (state is static)
1289
1301
  _array = self._get_array(
1290
1302
  grid_info, light_path, state=state, res_type=res_type)
1291
1303
  # get indices and add values to base array
1292
- states_indicies = states_array == state
1293
- array[:, states_indicies] += _array[:, states_indicies]
1304
+ state_indices = (states_array == state)
1305
+ masked_array = np.zeros_like(_array)
1306
+ masked_array[:, state_indices] = _array[:, state_indices]
1307
+ temp_arrays.append(masked_array)
1308
+ if temp_arrays:
1309
+ array = np.sum(np.stack(temp_arrays), axis=0)
1310
+ else:
1311
+ array = np.zeros((grid_info['count'], len(self.sun_up_hours)))
1294
1312
  arrays.append(array)
1295
- array = sum(arrays)
1313
+
1314
+ if len(arrays) == 0:
1315
+ array = np.zeros((grid_info['count'], len(self.sun_up_hours)))
1316
+ else:
1317
+ array = np.sum(np.stack(arrays, axis=0), axis=0)
1296
1318
 
1297
1319
  if not np.any(array):
1298
- if zero_array:
1299
- array = np.zeros((grid_info['count'], len(self.sun_up_hours)))
1300
- else:
1301
- array = np.array([])
1320
+ if not zero_array:
1321
+ array = np.asarray([])
1302
1322
 
1303
1323
  return array
1304
1324
 
@@ -1,8 +1,15 @@
1
1
  """Type hints for honeybee-radiance-postprocess."""
2
2
  from typing import Tuple, List
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
9
+
4
10
  from ladybug.datacollection import HourlyContinuousCollection
5
11
 
12
+
6
13
  annual_metric = Tuple[List[np.ndarray], List[dict]]
7
14
  annual_daylight_metrics = Tuple[
8
15
  List[np.ndarray],
@@ -1,9 +1,16 @@
1
1
  """Post-processing utility functions."""
2
2
  from typing import Tuple
3
- import numpy as np
3
+ try:
4
+ import cupy as np
5
+ is_gpu = True
6
+ except ImportError:
7
+ is_gpu = False
8
+ import numpy as np
4
9
 
5
10
  from honeybee_radiance.writer import _filter_by_pattern
6
11
 
12
+ is_cpu = not is_gpu
13
+
7
14
 
8
15
  def binary_mtx_dimension(filepath: str) -> Tuple[int, int, int, int, str]:
9
16
  """Return binary Radiance matrix dimensions if exist.
@@ -68,6 +75,27 @@ def check_array_dim(array: np.ndarray, dim: int):
68
75
  f'Expected {dim}-dimensional array. Dimension of array is {array.ndim}'
69
76
 
70
77
 
78
+ def filter_array2d(array: np.ndarray, mask: np.ndarray) -> np.ndarray:
79
+ """Filter a NumPy array by a masking array. The array will be passed as is
80
+ if the mask is None.
81
+
82
+ Args:
83
+ array: A NumPy array to filter.
84
+ mask: A NumPy array of ones/zeros or True/False.
85
+
86
+ Returns:
87
+ A filtered NumPy array.
88
+ """
89
+ if is_cpu:
90
+ array_filter = np.apply_along_axis(
91
+ filter_array, 1, array, mask=mask)
92
+ else:
93
+ mask = np.asarray(mask).astype(bool)
94
+ array_filter = array[:, mask]
95
+
96
+ return array_filter
97
+
98
+
71
99
  def filter_array(array: np.ndarray, mask: np.ndarray) -> np.ndarray:
72
100
  """Filter a NumPy array by a masking array. The array will be passed as is
73
101
  if the mask is None.
@@ -95,7 +123,7 @@ def hoys_mask(sun_up_hours: list, hoys: list) -> np.ndarray:
95
123
  A NumPy array of booleans.
96
124
  """
97
125
  if len(hoys) != 0:
98
- hoys_mask = np.where(np.isin(sun_up_hours, hoys), True, False)
126
+ hoys_mask = np.where(np.isin(np.array(sun_up_hours), np.array(hoys)), True, False)
99
127
  return hoys_mask
100
128
 
101
129
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: honeybee-radiance-postprocess
3
- Version: 0.4.543
3
+ Version: 0.4.544
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