cars 1.0.0rc3__cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

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 (220) hide show
  1. cars/__init__.py +74 -0
  2. cars/applications/__init__.py +40 -0
  3. cars/applications/application.py +117 -0
  4. cars/applications/application_constants.py +29 -0
  5. cars/applications/application_template.py +146 -0
  6. cars/applications/auxiliary_filling/__init__.py +29 -0
  7. cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +105 -0
  8. cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
  9. cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +632 -0
  10. cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
  11. cars/applications/dem_generation/__init__.py +30 -0
  12. cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
  13. cars/applications/dem_generation/bulldozer_config/base_config.yaml +46 -0
  14. cars/applications/dem_generation/bulldozer_dem_app.py +641 -0
  15. cars/applications/dem_generation/bulldozer_memory.py +55 -0
  16. cars/applications/dem_generation/dem_generation_algo.py +107 -0
  17. cars/applications/dem_generation/dem_generation_constants.py +32 -0
  18. cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
  19. cars/applications/dense_match_filling/__init__.py +30 -0
  20. cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
  21. cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
  22. cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
  23. cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
  24. cars/applications/dense_match_filling/zero_padding_app.py +302 -0
  25. cars/applications/dense_matching/__init__.py +30 -0
  26. cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
  27. cars/applications/dense_matching/census_mccnn_sgm_app.py +1461 -0
  28. cars/applications/dense_matching/cpp/__init__.py +0 -0
  29. cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-313-x86_64-linux-gnu.so +0 -0
  30. cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
  31. cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
  32. cars/applications/dense_matching/cpp/meson.build +9 -0
  33. cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
  34. cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
  35. cars/applications/dense_matching/dense_matching_algo.py +401 -0
  36. cars/applications/dense_matching/dense_matching_constants.py +89 -0
  37. cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
  38. cars/applications/dense_matching/disparity_grid_algo.py +597 -0
  39. cars/applications/dense_matching/loaders/__init__.py +23 -0
  40. cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
  41. cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
  42. cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
  43. cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
  44. cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
  45. cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
  46. cars/applications/dense_matching/loaders/config_mapping.json +13 -0
  47. cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
  48. cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
  49. cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
  50. cars/applications/dsm_filling/__init__.py +32 -0
  51. cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
  52. cars/applications/dsm_filling/border_interpolation_app.py +278 -0
  53. cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
  54. cars/applications/dsm_filling/bulldozer_filling_app.py +288 -0
  55. cars/applications/dsm_filling/exogenous_filling_app.py +341 -0
  56. cars/applications/dsm_merging/__init__.py +28 -0
  57. cars/applications/dsm_merging/abstract_dsm_merging_app.py +101 -0
  58. cars/applications/dsm_merging/weighted_fusion_app.py +639 -0
  59. cars/applications/grid_correction/__init__.py +30 -0
  60. cars/applications/grid_correction/abstract_grid_correction_app.py +103 -0
  61. cars/applications/grid_correction/grid_correction_app.py +557 -0
  62. cars/applications/grid_generation/__init__.py +30 -0
  63. cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
  64. cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
  65. cars/applications/grid_generation/grid_generation_algo.py +388 -0
  66. cars/applications/grid_generation/grid_generation_constants.py +46 -0
  67. cars/applications/grid_generation/transform_grid.py +88 -0
  68. cars/applications/ground_truth_reprojection/__init__.py +30 -0
  69. cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
  70. cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
  71. cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
  72. cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
  73. cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
  74. cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
  75. cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
  76. cars/applications/point_cloud_outlier_removal/small_components_app.py +522 -0
  77. cars/applications/point_cloud_outlier_removal/statistical_app.py +528 -0
  78. cars/applications/rasterization/__init__.py +30 -0
  79. cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
  80. cars/applications/rasterization/rasterization_algo.py +534 -0
  81. cars/applications/rasterization/rasterization_constants.py +38 -0
  82. cars/applications/rasterization/rasterization_wrappers.py +639 -0
  83. cars/applications/rasterization/simple_gaussian_app.py +1152 -0
  84. cars/applications/resampling/__init__.py +28 -0
  85. cars/applications/resampling/abstract_resampling_app.py +187 -0
  86. cars/applications/resampling/bicubic_resampling_app.py +760 -0
  87. cars/applications/resampling/resampling_algo.py +590 -0
  88. cars/applications/resampling/resampling_constants.py +36 -0
  89. cars/applications/resampling/resampling_wrappers.py +309 -0
  90. cars/applications/sensors_subsampling/__init__.py +32 -0
  91. cars/applications/sensors_subsampling/abstract_subsampling_app.py +109 -0
  92. cars/applications/sensors_subsampling/rasterio_subsampling_app.py +420 -0
  93. cars/applications/sensors_subsampling/subsampling_algo.py +108 -0
  94. cars/applications/sparse_matching/__init__.py +30 -0
  95. cars/applications/sparse_matching/abstract_sparse_matching_app.py +599 -0
  96. cars/applications/sparse_matching/sift_app.py +724 -0
  97. cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
  98. cars/applications/sparse_matching/sparse_matching_constants.py +66 -0
  99. cars/applications/sparse_matching/sparse_matching_wrappers.py +282 -0
  100. cars/applications/triangulation/__init__.py +32 -0
  101. cars/applications/triangulation/abstract_triangulation_app.py +227 -0
  102. cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
  103. cars/applications/triangulation/pc_transform.py +552 -0
  104. cars/applications/triangulation/triangulation_algo.py +371 -0
  105. cars/applications/triangulation/triangulation_constants.py +38 -0
  106. cars/applications/triangulation/triangulation_wrappers.py +259 -0
  107. cars/bundleadjustment.py +750 -0
  108. cars/cars.py +179 -0
  109. cars/conf/__init__.py +23 -0
  110. cars/conf/geoid/egm96.grd +0 -0
  111. cars/conf/geoid/egm96.grd.hdr +15 -0
  112. cars/conf/input_parameters.py +156 -0
  113. cars/conf/mask_cst.py +35 -0
  114. cars/core/__init__.py +23 -0
  115. cars/core/cars_logging.py +402 -0
  116. cars/core/constants.py +191 -0
  117. cars/core/constants_disparity.py +50 -0
  118. cars/core/datasets.py +140 -0
  119. cars/core/geometry/__init__.py +27 -0
  120. cars/core/geometry/abstract_geometry.py +1130 -0
  121. cars/core/geometry/shareloc_geometry.py +604 -0
  122. cars/core/inputs.py +568 -0
  123. cars/core/outputs.py +176 -0
  124. cars/core/preprocessing.py +722 -0
  125. cars/core/projection.py +843 -0
  126. cars/core/roi_tools.py +215 -0
  127. cars/core/tiling.py +774 -0
  128. cars/core/utils.py +164 -0
  129. cars/data_structures/__init__.py +23 -0
  130. cars/data_structures/cars_dataset.py +1544 -0
  131. cars/data_structures/cars_dict.py +74 -0
  132. cars/data_structures/corresponding_tiles_tools.py +186 -0
  133. cars/data_structures/dataframe_converter.py +185 -0
  134. cars/data_structures/format_transformation.py +297 -0
  135. cars/devibrate.py +689 -0
  136. cars/extractroi.py +264 -0
  137. cars/orchestrator/__init__.py +23 -0
  138. cars/orchestrator/achievement_tracker.py +125 -0
  139. cars/orchestrator/cluster/__init__.py +37 -0
  140. cars/orchestrator/cluster/abstract_cluster.py +250 -0
  141. cars/orchestrator/cluster/abstract_dask_cluster.py +381 -0
  142. cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
  143. cars/orchestrator/cluster/dask_config/README.md +94 -0
  144. cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
  145. cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
  146. cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
  147. cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
  148. cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
  149. cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
  150. cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
  151. cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
  152. cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
  153. cars/orchestrator/cluster/local_dask_cluster.py +116 -0
  154. cars/orchestrator/cluster/log_wrapper.py +728 -0
  155. cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
  156. cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
  157. cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
  158. cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
  159. cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
  160. cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +986 -0
  161. cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
  162. cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
  163. cars/orchestrator/cluster/sequential_cluster.py +139 -0
  164. cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
  165. cars/orchestrator/memory_tools.py +47 -0
  166. cars/orchestrator/orchestrator.py +755 -0
  167. cars/orchestrator/orchestrator_constants.py +29 -0
  168. cars/orchestrator/registry/__init__.py +23 -0
  169. cars/orchestrator/registry/abstract_registry.py +143 -0
  170. cars/orchestrator/registry/compute_registry.py +106 -0
  171. cars/orchestrator/registry/id_generator.py +116 -0
  172. cars/orchestrator/registry/replacer_registry.py +213 -0
  173. cars/orchestrator/registry/saver_registry.py +363 -0
  174. cars/orchestrator/registry/unseen_registry.py +118 -0
  175. cars/orchestrator/tiles_profiler.py +279 -0
  176. cars/pipelines/__init__.py +26 -0
  177. cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
  178. cars/pipelines/conf_resolution/conf_first_resolution.yaml +4 -0
  179. cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
  180. cars/pipelines/default/__init__.py +26 -0
  181. cars/pipelines/default/default_pipeline.py +1095 -0
  182. cars/pipelines/filling/__init__.py +26 -0
  183. cars/pipelines/filling/filling.py +981 -0
  184. cars/pipelines/formatting/__init__.py +26 -0
  185. cars/pipelines/formatting/formatting.py +190 -0
  186. cars/pipelines/merging/__init__.py +26 -0
  187. cars/pipelines/merging/merging.py +439 -0
  188. cars/pipelines/parameters/__init__.py +0 -0
  189. cars/pipelines/parameters/advanced_parameters.py +256 -0
  190. cars/pipelines/parameters/advanced_parameters_constants.py +68 -0
  191. cars/pipelines/parameters/application_parameters.py +72 -0
  192. cars/pipelines/parameters/depth_map_inputs.py +0 -0
  193. cars/pipelines/parameters/dsm_inputs.py +349 -0
  194. cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
  195. cars/pipelines/parameters/output_constants.py +52 -0
  196. cars/pipelines/parameters/output_parameters.py +435 -0
  197. cars/pipelines/parameters/sensor_inputs.py +859 -0
  198. cars/pipelines/parameters/sensor_inputs_constants.py +51 -0
  199. cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
  200. cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
  201. cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
  202. cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
  203. cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
  204. cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
  205. cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
  206. cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
  207. cars/pipelines/pipeline.py +119 -0
  208. cars/pipelines/pipeline_constants.py +38 -0
  209. cars/pipelines/pipeline_template.py +135 -0
  210. cars/pipelines/subsampling/__init__.py +26 -0
  211. cars/pipelines/subsampling/subsampling.py +358 -0
  212. cars/pipelines/surface_modeling/__init__.py +26 -0
  213. cars/pipelines/surface_modeling/surface_modeling.py +2098 -0
  214. cars/pipelines/tie_points/__init__.py +26 -0
  215. cars/pipelines/tie_points/tie_points.py +536 -0
  216. cars/starter.py +167 -0
  217. cars-1.0.0rc3.dist-info/METADATA +289 -0
  218. cars-1.0.0rc3.dist-info/RECORD +220 -0
  219. cars-1.0.0rc3.dist-info/WHEEL +6 -0
  220. cars-1.0.0rc3.dist-info/entry_points.txt +8 -0
@@ -0,0 +1,381 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ Contains abstract function for abstract dask Cluster
23
+ """
24
+
25
+ # Standard imports
26
+ import logging
27
+ import os
28
+ import time
29
+
30
+ # Third party imports
31
+ from abc import abstractmethod
32
+
33
+ import dask
34
+ import numpy as np
35
+ import psutil
36
+ import xarray as xr
37
+ import yaml
38
+ from dask.config import global_config as global_dask_config
39
+ from dask.config import set as dask_config_set
40
+ from dask.delayed import Delayed
41
+ from dask.distributed import as_completed
42
+ from dask.sizeof import sizeof as dask_sizeof
43
+ from distributed.diagnostics.plugin import WorkerPlugin
44
+ from distributed.utils import CancelledError
45
+
46
+ from cars.core import cars_logging
47
+
48
+ # CARS imports
49
+ from cars.orchestrator.cluster import abstract_cluster
50
+
51
+
52
+ class AbstractDaskCluster(
53
+ abstract_cluster.AbstractCluster
54
+ ): # pylint: disable=R0902
55
+ """
56
+ AbstractDaskCluster
57
+ """
58
+
59
+ def __init__( # pylint: disable=R0917
60
+ self,
61
+ conf_cluster,
62
+ out_dir,
63
+ log_dir,
64
+ launch_worker=True,
65
+ data_to_propagate=None,
66
+ ):
67
+ """
68
+ Init function of AbstractDaskCluster
69
+
70
+ :param conf_cluster: configuration for cluster
71
+ :param data_to_propagate: data to propagate to new cluster if reset
72
+ :type data_to_propagate: dict
73
+
74
+ """
75
+
76
+ # call parent init
77
+ super().__init__(
78
+ conf_cluster, out_dir, log_dir, launch_worker=launch_worker
79
+ )
80
+ # retrieve parameters
81
+ self.nb_workers = self.checked_conf_cluster["nb_workers"]
82
+ self.task_timeout = self.checked_conf_cluster["task_timeout"]
83
+ self.walltime = self.checked_conf_cluster["walltime"]
84
+ self.use_memory_logger = self.checked_conf_cluster["use_memory_logger"]
85
+ self.config_name = self.checked_conf_cluster["config_name"]
86
+ self.launch_worker = launch_worker
87
+
88
+ self.activate_dashboard = self.checked_conf_cluster[
89
+ "activate_dashboard"
90
+ ]
91
+ self.python = self.checked_conf_cluster["python"]
92
+ if self.checked_conf_cluster["mode"] == "slurm_dask":
93
+ self.account = self.checked_conf_cluster["account"]
94
+ self.qos = self.checked_conf_cluster["qos"]
95
+
96
+ if self.launch_worker:
97
+ # Set DASK CARS specific config
98
+ # TODO: update with adequate configuration through tests
99
+ set_config()
100
+
101
+ # Save dask config used
102
+ save_config(self.out_dir, "dask_config_" + self.config_name)
103
+
104
+ # Create cluster
105
+ self.cluster, self.client = self.start_dask_cluster()
106
+
107
+ # Add plugin to monitor memory of workers
108
+ if self.use_memory_logger:
109
+ plugin = ComputeDSMMemoryLogger(self.out_dir)
110
+ self.client.register_worker_plugin(plugin)
111
+
112
+ @abstractmethod
113
+ def check_conf(self, conf):
114
+ """
115
+ Check configuration
116
+
117
+ :param conf: configuration to check
118
+ :type conf: dict
119
+
120
+ :return: overloaded configuration
121
+ :rtype: dict
122
+
123
+ """
124
+
125
+ @abstractmethod
126
+ def start_dask_cluster(self):
127
+ """
128
+ Start dask cluster
129
+ """
130
+
131
+ def create_task_wrapped(self, func, nout=1):
132
+ """
133
+ Create task
134
+
135
+ :param func: function
136
+ :param nout: number of outputs
137
+ """
138
+ return dask.delayed(
139
+ cars_logging.wrap_logger(func, self.worker_log_dir, self.log_level),
140
+ nout=nout,
141
+ )
142
+
143
+ def get_delayed_type(self):
144
+ """
145
+ Get delayed type
146
+ """
147
+ return Delayed
148
+
149
+ def start_tasks(self, task_list):
150
+ """
151
+ Start all tasks
152
+
153
+ :param task_list: task list
154
+ """
155
+
156
+ return self.client.compute(task_list)
157
+
158
+ def scatter(self, data, broadcast=True):
159
+ """
160
+ Distribute data through workers
161
+
162
+ :param data: task data
163
+ """
164
+ return self.client.scatter(data, broadcast=broadcast)
165
+
166
+ def future_iterator(self, future_list, timeout=None):
167
+ """
168
+ Start all tasks
169
+
170
+ :param future_list: future_list list
171
+ """
172
+
173
+ return DaskFutureIterator(future_list, timeout=timeout)
174
+
175
+
176
+ class DaskFutureIterator:
177
+ """
178
+ iterator on dask futures, similar to as_completed
179
+ Only returns the actual results, delete the future after usage
180
+ """
181
+
182
+ def __init__(self, future_list, timeout=None): # pylint: disable=W0613
183
+ # TODO: python 3.9: add timeout=timeout as parameter
184
+ self.dask_a_c = as_completed(future_list, with_results=True)
185
+ self.prev = None
186
+
187
+ def __iter__(self):
188
+ return self
189
+
190
+ def __next__(self):
191
+ try:
192
+ fut, res = self.dask_a_c.__next__()
193
+ except StopIteration as exception:
194
+ if self.prev is not None:
195
+ self.prev.cancel()
196
+ self.prev = None
197
+ raise exception
198
+ except dask.distributed.TimeoutError as exception:
199
+ raise TimeoutError("No tasks available") from exception
200
+ # release previous future
201
+ if self.prev is not None:
202
+ self.prev.cancel()
203
+ # store current future
204
+ self.prev = fut
205
+
206
+ if isinstance(res, CancelledError):
207
+ raise RuntimeError("CancelError from worker {}".format(res))
208
+ return res
209
+
210
+
211
+ def set_config():
212
+ """
213
+ Set particular DASK config such as:
214
+ - scheduler
215
+ """
216
+ # TODO: export API to prepare.run and compute_dsm.run() to set scheduler
217
+ # example mode debug: dask_config_set(scheduler='single-threaded')
218
+ # example mode multithread: dask_config_set(scheduler='threads')
219
+ # Here set Multiprocess mode instead multithread because of GIL blocking
220
+ dask_config_set(scheduler="processes")
221
+
222
+
223
+ def save_config(output_dir: str, file_name: str):
224
+ """
225
+ Save DASK global config
226
+
227
+ :param output_dir: output directory path
228
+ :param file_name: output file name
229
+
230
+ """
231
+ logging.info(
232
+ "Save DASK global merged config for debug "
233
+ "(1: $DASK_DIR if exists, 2: ~/.config/dask/, ... ) "
234
+ )
235
+ # write global merged DASK config in YAML
236
+ write_yaml_config(global_dask_config, output_dir, file_name)
237
+
238
+
239
+ def write_yaml_config(yaml_config: dict, output_dir: str, file_name: str):
240
+ """
241
+ Writes a YAML config to disk.
242
+ TODO: put in global file if needed elsewhere than DASK conf save.
243
+
244
+ :param yaml_config: YAML config to write
245
+ :param output_dir: output directory path
246
+ :param file_name: output file name
247
+ """
248
+ # file path where to store the dask config
249
+ yaml_config_path = os.path.join(output_dir, file_name + ".yaml")
250
+ with open(yaml_config_path, "w", encoding="utf-8") as yaml_config_file:
251
+ yaml.dump(yaml_config, yaml_config_file)
252
+
253
+
254
+ @dask_sizeof.register_lazy("xarray")
255
+ def register_xarray():
256
+ """
257
+ Add hook to dask so it correctly estimates memory used by xarray
258
+ """
259
+
260
+ @dask_sizeof.register(xr.DataArray)
261
+ # pylint: disable=unused-variable
262
+ def sizeof_xarray_dataarray(xarr):
263
+ """
264
+ Inner function for total size of xarray_dataarray
265
+ """
266
+ total_size = dask_sizeof(xarr.values)
267
+ for __, carray in xarr.coords.items():
268
+ total_size += dask_sizeof(carray.values)
269
+ total_size += dask_sizeof(xarr.attrs)
270
+ return total_size
271
+
272
+ @dask_sizeof.register(xr.Dataset)
273
+ # pylint: disable=unused-variable
274
+ def sizeof_xarray_dataset(xdat):
275
+ """
276
+ Inner function for total size of xarray_dataset
277
+ """
278
+ total_size = 0
279
+ for __, varray in xdat.data_vars.items():
280
+ total_size += dask_sizeof(varray.values)
281
+ for __, carray in xdat.coords.items():
282
+ total_size += dask_sizeof(carray)
283
+ total_size += dask_sizeof(xdat.attrs)
284
+ return total_size
285
+
286
+
287
+ class ComputeDSMMemoryLogger(WorkerPlugin):
288
+ """A subclass of WorkerPlugin dedicated to monitoring workers memory
289
+
290
+ This plugin enables two things:
291
+
292
+ - Additional dask log traces (for each worker internal state change):
293
+
294
+ - amount of tasks
295
+ - associated memory
296
+ - A numpy data file with memory metrics and timing
297
+ """
298
+
299
+ def __init__(self, outdir):
300
+ """
301
+ Constructor
302
+ :param outdir: output directory
303
+ :type outdir: string
304
+ """
305
+ self.outdir = outdir
306
+
307
+ def setup(self, worker):
308
+ """
309
+ Associate plugin with a worker
310
+ :param worker: The worker to associate the plugin with
311
+ """
312
+ # Pylint Exception : Inherited attributes outside __init__
313
+ # pylint: disable=attribute-defined-outside-init
314
+ self.worker = worker
315
+ self.name = worker.name
316
+ # Measure plugin registration time
317
+ self.start_time = time.time()
318
+ # Data will hold the memory traces as numpy array
319
+ self.data = [[0, 0, 0, 0]]
320
+
321
+ def transition(self, key, start, finish, **kwargs):
322
+ """
323
+ Callback when worker changes internal state
324
+ """
325
+ # TODO Pylint Exception : Inherited attributes outside __init__
326
+ # pylint: disable=attribute-defined-outside-init
327
+
328
+ # Define cumulants
329
+ total_in_memory = 0
330
+ total_nbytes = 0
331
+
332
+ # Measure elapsed time for the state change
333
+ elapsed_time = time.time() - self.start_time
334
+
335
+ # Walk the worker known memory
336
+ for task_key in self.worker.state.tasks.keys():
337
+ task_size = self.worker.state.tasks[task_key].get_nbytes()
338
+
339
+ total_in_memory += task_size
340
+ total_nbytes += 1
341
+
342
+ # Use psutil to capture python process memory as well
343
+ process = psutil.Process(os.getpid())
344
+ process_memory = process.memory_info().rss
345
+
346
+ # Update data records
347
+ self.data = np.concatenate(
348
+ (
349
+ self.data,
350
+ np.array(
351
+ [
352
+ [
353
+ elapsed_time,
354
+ total_in_memory,
355
+ total_nbytes,
356
+ process_memory,
357
+ ]
358
+ ]
359
+ ),
360
+ )
361
+ )
362
+ # Convert nbytes size for logger
363
+ total_nbytes = float(total_nbytes) / 1000000
364
+ process_memory = float(process_memory) / 1000000
365
+
366
+ # Log memory state
367
+ logging.info(
368
+ "Memory report: data created = {} ({} Mb), "
369
+ "python process memory = {} Mb".format(
370
+ total_in_memory,
371
+ total_nbytes,
372
+ process_memory,
373
+ )
374
+ )
375
+
376
+ # Save data records in npy file
377
+ # TODO: Save only every x seconds ?
378
+ file = os.path.join(
379
+ self.outdir, "dask_log", "memory_" + repr(self.name) + ".npy"
380
+ )
381
+ np.save(file, self.data)
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env python
2
+ # coding: utf8
3
+ #
4
+ # Copyright (c) 2020 Centre National d'Etudes Spatiales (CNES).
5
+ #
6
+ # This file is part of CARS
7
+ # (see https://github.com/CNES/cars).
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+ """
22
+ Contains functions cluster conf checker
23
+ """
24
+ import time
25
+
26
+ from json_checker import And, Checker, Or
27
+
28
+
29
+ def create_checker_schema(conf):
30
+ """
31
+ Create checker shema that it can be overloaded
32
+
33
+ :param conf: configuration to check
34
+ :type conf: dict
35
+
36
+ :return: overloaded configuration
37
+ :rtype: dict
38
+
39
+ """
40
+
41
+ # init conf
42
+ if conf is not None:
43
+ overloaded_conf = conf.copy()
44
+ else:
45
+ conf = {}
46
+ overloaded_conf = {}
47
+
48
+ # Overload conf
49
+ overloaded_conf["mode"] = conf.get("mode", "unknowed_dask")
50
+ overloaded_conf["use_memory_logger"] = conf.get("use_memory_logger", False)
51
+ overloaded_conf["nb_workers"] = conf.get("nb_workers", 2)
52
+ overloaded_conf["task_timeout"] = conf.get("task_timeout", 600)
53
+ overloaded_conf["max_ram_per_worker"] = conf.get("max_ram_per_worker", 2000)
54
+ overloaded_conf["walltime"] = conf.get("walltime", "00:59:00")
55
+ overloaded_conf["config_name"] = conf.get("config_name", "unknown")
56
+ overloaded_conf["activate_dashboard"] = conf.get(
57
+ "activate_dashboard", False
58
+ )
59
+ overloaded_conf["python"] = conf.get("python", None)
60
+ overloaded_conf["profiling"] = conf.get("profiling", {})
61
+
62
+ cluster_schema = {
63
+ "mode": str,
64
+ "use_memory_logger": bool,
65
+ "nb_workers": And(int, lambda x: x > 0),
66
+ "task_timeout": And(int, lambda x: x > 0),
67
+ "max_ram_per_worker": And(Or(float, int), lambda x: x > 0),
68
+ "walltime": str,
69
+ "config_name": str,
70
+ "activate_dashboard": bool,
71
+ "profiling": dict,
72
+ "python": Or(None, str),
73
+ }
74
+
75
+ return overloaded_conf, cluster_schema
76
+
77
+
78
+ def check_configuration(overloaded_conf, cluster_schema):
79
+ """
80
+ Check configuration from overload conf and cluster schema
81
+
82
+
83
+ :param conf: overloaded_conf to check
84
+ :type conf: dict
85
+ :param conf: cluster_schema checking rules
86
+ :type conf: dict
87
+
88
+ :return: overloaded configuration
89
+ :rtype: dict
90
+
91
+ """
92
+ # Check conf
93
+ checker = Checker(cluster_schema)
94
+ checker.validate(overloaded_conf)
95
+
96
+ # Check walltime format
97
+ walltime = overloaded_conf["walltime"]
98
+ try:
99
+ time.strptime(walltime, "%H:%M:%S")
100
+ except ValueError as err:
101
+ raise ValueError("Walltime should be formatted as HH:MM:SS") from err
102
+
103
+ return overloaded_conf
@@ -0,0 +1,94 @@
1
+ # CARS Dask configuration
2
+
3
+ This file contains the description of DASK configuration used with CARS
4
+
5
+ This configuration is split into 3 files:
6
+ - [dask.yaml](./dask.yaml) : basic DASK configuration
7
+ - [distributed.yaml](./distributed.yaml) : configuration of DASK distributed : scheduler and workers
8
+ - [jobqueue.yaml](./jobqueue.yaml) : configuration of DASK and PBS cluster interface
9
+
10
+
11
+ ## dask.yaml configuration
12
+
13
+
14
+ | Option | CARS value | Default Dask value | Comments |
15
+ | ------- | ----------- | ------------------- | -------- |
16
+ | temporary-directory | null | None = null | Default: tmpdir = dask-worker-space local |
17
+ | dataframe:shuffle-compression| null | None = null | Default: no compression . TODO: test if gain |
18
+ | array:svg:size | 120 | 120 | Default. |
19
+ | array:slicing:split-large-chunks| null | None = null | Default. TODO: set to true if too much warnings. Test if adds perfomance issues |
20
+ | optimization:fuse:active| **true** | None = null | **Activated** TODO: test impact on configuration activation |
21
+ | optimization:fuse:ave-width| 1| 1 | Default. **TODO : to test/adapt limit of width= num_nodes/height** |
22
+ | optimization:fuse:max-width| null| None = null | Default : depends on de ave-width. 1.5 + ave_width * log(ave_width + 1) |
23
+ | optimization:fuse:max-height| .inf | inf | Default : No max limitation. All possibilities. |
24
+ | optimization:fuse:max-depth-new-edges| null|None = null | Default : depends on ave-width. ave_width * 1.5 |
25
+ | optimization:fuse:subgraphs| null | None = null | Default: Let optimizer choose. TODO: test?|
26
+ | optimization:fuse:rename-keys| true | true | Default. TODO: test ?|
27
+
28
+ ## Configuration distributed.yaml
29
+
30
+
31
+ | Option | CARS value | Default Dask value | Comments |
32
+ | ------- | ----------- | ------------------- | -------- |
33
+ | version | **2** | NA| Not defined in documentation | Default in example. TODO: keep ? why specify ? no documentation... |
34
+ | logging:distributed| **info** | info | DASK distributed log level. *Adapt depending the output loglevel. Set to debug for mac level* |
35
+ | logging:distributed.client| warning | warning | See for Client, adapt of refined analysis |
36
+ | logging:distributed.worker| debug | not set | Default. For more workers infors : uncomment.|
37
+ | logging:bokeh | **critical** | error ? | Log limitation on warnings / errors polluting output. |
38
+ | logging:tornado | **critical** | warning ? | Duplicate in output configuration . To test in dask.yaml. Link with http://stackoverflow.com/questions/21234772/python-tornado-disable-logging-to-stderr ?. The idea is to delete tornado messages, but does not talk about dask conf|
39
+ | logging:tornado.application | **error** | ? | dig for more performance analysis of tornado (cf timeout TCP ...), We need to upgrade tornato loglevel. TODO |
40
+ | scheduler:blocked-handlers| [] | [] | Default. |
41
+ | scheduler:allowed-failures| **10** | 3 | Augmented for some failed cases. TODO: lower this value |
42
+ | scheduler:bandwidth| **100000** | 100000000 | Tested values, set lower : 100mbps vs 100G ? estimated flow. enough ? TODO: analyse the use of this parameter. |
43
+ | scheduler:transition-log-length| 100000 | 100000 | Default. Unit? TODO: Storage size in spinning logs. Seems ok if memory doent freeze |
44
+ | scheduler:work-stealing| True | True | Default. load balancing of workers tasks. TODO: Could be dangerous for stability, working with images |
45
+ | worker:blocked-handlers| [] | [] | Default |
46
+ | :worker:multiprocessing-method| **forkserver** | spawn | Tested modification. TODO: see the gain with forkserver. Perf vs stability ... spawn vs fork vs forkserver. Seems ok with forkserver as intermediate solution but maybe not that slow with spawn, ans more stable, with software stacked on each multiprocessed worker. |
47
+ | worker:connections:outgoing et incoming| 50 and **50** | 50 and 10 | Default for outgoing. Modified to 50 for incoming. TODO: Precise analysis of conections, current connections. Beware not to saturate. |
48
+ | worker:validate| **true** | false | Augmentation for debug Default. TODO: see impact? |
49
+ | worker:lifetime:restart | **True** | False | Commented. TODO: to test. What is deadline ? See lifetime utilisation. "Lifetime was intended to provide a mechanism for a periodic reset of workers, such as might be useful when dealing with libraries that might leak memory and so benefit from cycling worker processes. It is orthogonal to adaptive." mrocklin https://github.com/dask/distributed/issues/3141 . Does lifetime as to be set the same as walltime ? |
50
+ | worker:lifetime:duration| null | None=null | Default. |
51
+ | worker:lifetime:stagger| 0 | 0 | Default. |
52
+ | worker:profile:interval| 10 ms | 10ms | Default. |
53
+ | worker:profile:cycle| 1000 ms | 1000ms | Default. |
54
+ | worker:memory:target| 0.60 | 0.6 | Default. |
55
+ | worker:memory:spill| 0.70 | 0.7 | Default. |
56
+ | worker:memory:pause| 0.80 | 0.8 | Default. |
57
+ | worker:memory:terminate| 0.95 | 0.95 | Default. |
58
+ | comm:retry:count| **10** | 0 | Tested for stability improvement. TODO: Default: 0 should not change that. For now we keep it to 10. May be lower comminuration issue between workers |
59
+ | comm:compression| auto | auto | Default. |
60
+ | comm:default-scheme| tcp | tcp | Default. |
61
+ | comm:socket-backlog| 2048 | 2048 | Default. TODO: not sufficient ? |
62
+ | comm:timeouts:connects| **60s** | 10s | Augmentation of value following done tests. TODO: issues before. Do not touch it ... |
63
+ | comm:timeouts:tcp| **120s** | 30s | Augmentation of value following done tests. TODO: issues before. Do not touch it ... |
64
+ | comm:require-encryption| **False** | None=null | Deactivated. No need |
65
+ | dashboard:export-tool| False | False | Default |
66
+ | admin:tick:interval | 20 ms | 20 ms | Default. |
67
+ | admin:tick:limit| **1s** | 3s | TODO: test it : default 3s, keep 1s ? |
68
+ | admin:log-format| %(asctime)s :: %(name)s - %(levelname)s - %(message)s' | %(name)s - %(levelname)s - %(message)s | default ok |
69
+ | admin:pdb-on-err| False| False | Default. TODO test : set to true for debug. |
70
+
71
+ ## Configuration jobqueue.yaml
72
+
73
+ The main configuration is done with [dask usage in CARS](https://github.com/CNES/cars/blob/master/cars/orchestrator/cluster/pbs_dask_cluster.py)
74
+
75
+ But also in documented file [jobqueue.yaml](./jobqueue.yaml) if not overloaded in CARS.
76
+ [Jobqueue documentation](https://jobqueue.dask.org/en/latest/configuration.html)
77
+
78
+ ## Official configurations :
79
+
80
+ Reference dask configuration of dask projects are stored in [reference_confs](./reference_confs/)
81
+
82
+ ### Dask
83
+
84
+ - default: https://raw.githubusercontent.com/dask/dask/main/dask/dask.yaml
85
+ - schema: https://raw.githubusercontent.com/dask/dask/main/dask/dask-schema.yaml
86
+
87
+ ### Distributed
88
+
89
+ - default: https://raw.githubusercontent.com/dask/distributed/main/distributed/distributed.yaml
90
+ - schema: https://raw.githubusercontent.com/dask/distributed/main/distributed/distributed-schema.yaml
91
+
92
+ ### Jobqueue
93
+
94
+ - default: https://raw.githubusercontent.com/dask/dask-jobqueue/main/dask_jobqueue/jobqueue.yaml
@@ -0,0 +1,21 @@
1
+ temporary-directory: null # Directory for local disk like /tmp, /scratch, or /local. null -> local dask-worker-space directory.
2
+
3
+ dataframe:
4
+ shuffle:
5
+ compression: null # compression for on disk-shuffling. Partd supports ZLib, BZ2, SNAPPY, BLOSC
6
+
7
+ array:
8
+ svg:
9
+ size: 120 # pixels for jupyter notebook array rendering
10
+ slicing:
11
+ split-large-chunks: null # How to handle large output chunks in slicing. Warns by default.
12
+
13
+ optimization:
14
+ fuse: # Options for Dask's task fusion optimizations
15
+ active: true
16
+ ave-width: 1 # Upper limit for width, where width = num_nodes / height
17
+ max-width: null # 1.5 + ave_width * log(ave_width + 1)
18
+ max-height: .inf # Fuse all possibilities
19
+ max-depth-new-edges: null # ave_width * 1.5
20
+ subgraphs: null # true for dask.dataframe, false for everything else. Set to null to let the default optimizer of individual dask collections decide.
21
+ rename-keys: true # Set to true to rename the fused keys with `default_fused_keys_renamer`. Can be costly.
@@ -0,0 +1,70 @@
1
+ distributed:
2
+ version: 2
3
+ logging: # Logging dask distributed module conf
4
+ distributed: warning
5
+ distributed.client: warning
6
+ distributed.worker: warning
7
+ distributed.scheduler: warning
8
+ distributed.nanny: warning
9
+ distributed.core: warning
10
+ bokeh: critical
11
+ # http://stackoverflow.com/questions/21234772/python-tornado-disable-logging-to-stderr
12
+ tornado: critical
13
+ tornado.application: error
14
+
15
+ scheduler:
16
+ blocked-handlers: [] # message operation list to block from scheduler to worker
17
+ allowed-failures: 10 # number of retries before a task is considered bad
18
+ bandwidth: 100000000 # 100 MB/s estimated worker-worker bandwidth
19
+ work-stealing: True # workers should steal tasks from each other
20
+
21
+ worker:
22
+ blocked-handlers: [] # message operation list to block from scheduler to worker
23
+ multiprocessing-method: forkserver # can be fork, spawn or forkserver multiprocessing method
24
+ connections: # Maximum concurrent connections for data
25
+ outgoing: 50 # This helps to control network saturation
26
+ incoming: 50
27
+ validate: True # Check worker state at every step for debugging
28
+ lifetime:
29
+ duration: null
30
+ stagger: 0 # Random amount of time by which to stagger lifetime. Avoid kill at the same lifetime
31
+ restart: False # Do we ressurrect the worker after the lifetime deadline?
32
+ profile:
33
+ interval: 10ms # Time between statistical profiling queries
34
+ cycle: 1000ms # Time between starting new profile
35
+ memory:
36
+ target: False # target fraction to stay below
37
+ spill: False # fraction at which we spill to disk
38
+ pause: False # fraction at which we pause worker threads
39
+ terminate: False # fraction at which we terminate the worker
40
+ comm:
41
+ retry: # some operations (such as gathering data) are subject to re-tries with the below parameters
42
+ count: 10 # the maximum retry attempts. 0 disables re-trying.
43
+ compression: auto # Compression for communication; Default: auto
44
+ default-scheme: tcp # default scheme (can be tls for secure comm)
45
+ socket-backlog: 2048 # default value, must be large enough for data between workers
46
+
47
+ timeouts:
48
+ connect: 60s # time before connecting fails (default: 10s)
49
+ tcp: 120s # time before calling an unresponsive connection dead (default: 30s)
50
+
51
+ require-encryption: False # Whether to require encryption on non-local comms
52
+
53
+ ###################
54
+ # Bokeh dashboard #
55
+ ###################
56
+
57
+ dashboard:
58
+ export-tool: False # Deactivate bokeh dashboard for performance
59
+
60
+ ##################
61
+ # Administrative #
62
+ ##################
63
+
64
+ admin:
65
+ tick:
66
+ interval: 20ms # time between event loop health checks
67
+ limit: 1s # time allowed before triggering a warning
68
+ log-format: '%(asctime)s :: %(name)s - %(levelname)s - %(message)s'
69
+ pdb-on-err: False # enter debug mode on scheduling error
70
+ low-level-log-length: 100000 # How long should we keep the transition log in memory (default length 100000 (bytes?))