cars 1.0.0rc1__cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.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.
Potentially problematic release.
This version of cars might be problematic. Click here for more details.
- cars/__init__.py +74 -0
- cars/applications/__init__.py +37 -0
- cars/applications/application.py +117 -0
- cars/applications/application_constants.py +29 -0
- cars/applications/application_template.py +146 -0
- cars/applications/auxiliary_filling/__init__.py +29 -0
- cars/applications/auxiliary_filling/abstract_auxiliary_filling_app.py +104 -0
- cars/applications/auxiliary_filling/auxiliary_filling_algo.py +475 -0
- cars/applications/auxiliary_filling/auxiliary_filling_from_sensors_app.py +630 -0
- cars/applications/auxiliary_filling/auxiliary_filling_wrappers.py +90 -0
- cars/applications/dem_generation/__init__.py +30 -0
- cars/applications/dem_generation/abstract_dem_generation_app.py +116 -0
- cars/applications/dem_generation/bulldozer_config/base_config.yaml +42 -0
- cars/applications/dem_generation/bulldozer_dem_app.py +655 -0
- cars/applications/dem_generation/bulldozer_memory.py +55 -0
- cars/applications/dem_generation/dem_generation_algo.py +107 -0
- cars/applications/dem_generation/dem_generation_constants.py +32 -0
- cars/applications/dem_generation/dem_generation_wrappers.py +323 -0
- cars/applications/dense_match_filling/__init__.py +30 -0
- cars/applications/dense_match_filling/abstract_dense_match_filling_app.py +242 -0
- cars/applications/dense_match_filling/fill_disp_algo.py +113 -0
- cars/applications/dense_match_filling/fill_disp_constants.py +39 -0
- cars/applications/dense_match_filling/fill_disp_wrappers.py +83 -0
- cars/applications/dense_match_filling/zero_padding_app.py +302 -0
- cars/applications/dense_matching/__init__.py +30 -0
- cars/applications/dense_matching/abstract_dense_matching_app.py +261 -0
- cars/applications/dense_matching/census_mccnn_sgm_app.py +1460 -0
- cars/applications/dense_matching/cpp/__init__.py +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.cpython-312-i386-linux-gnu.so +0 -0
- cars/applications/dense_matching/cpp/dense_matching_cpp.py +94 -0
- cars/applications/dense_matching/cpp/includes/dense_matching.hpp +58 -0
- cars/applications/dense_matching/cpp/meson.build +9 -0
- cars/applications/dense_matching/cpp/src/bindings.cpp +13 -0
- cars/applications/dense_matching/cpp/src/dense_matching.cpp +207 -0
- cars/applications/dense_matching/dense_matching_algo.py +401 -0
- cars/applications/dense_matching/dense_matching_constants.py +89 -0
- cars/applications/dense_matching/dense_matching_wrappers.py +951 -0
- cars/applications/dense_matching/disparity_grid_algo.py +588 -0
- cars/applications/dense_matching/loaders/__init__.py +23 -0
- cars/applications/dense_matching/loaders/config_census_sgm_default.json +31 -0
- cars/applications/dense_matching/loaders/config_census_sgm_homogeneous.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_mountain_and_vegetation.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_shadow.json +30 -0
- cars/applications/dense_matching/loaders/config_census_sgm_sparse.json +36 -0
- cars/applications/dense_matching/loaders/config_census_sgm_urban.json +30 -0
- cars/applications/dense_matching/loaders/config_mapping.json +13 -0
- cars/applications/dense_matching/loaders/config_mccnn.json +28 -0
- cars/applications/dense_matching/loaders/global_land_cover_map.tif +0 -0
- cars/applications/dense_matching/loaders/pandora_loader.py +593 -0
- cars/applications/dsm_filling/__init__.py +32 -0
- cars/applications/dsm_filling/abstract_dsm_filling_app.py +101 -0
- cars/applications/dsm_filling/border_interpolation_app.py +270 -0
- cars/applications/dsm_filling/bulldozer_config/base_config.yaml +44 -0
- cars/applications/dsm_filling/bulldozer_filling_app.py +279 -0
- cars/applications/dsm_filling/exogenous_filling_app.py +333 -0
- cars/applications/grid_generation/__init__.py +30 -0
- cars/applications/grid_generation/abstract_grid_generation_app.py +142 -0
- cars/applications/grid_generation/epipolar_grid_generation_app.py +327 -0
- cars/applications/grid_generation/grid_correction_app.py +496 -0
- cars/applications/grid_generation/grid_generation_algo.py +388 -0
- cars/applications/grid_generation/grid_generation_constants.py +46 -0
- cars/applications/grid_generation/transform_grid.py +88 -0
- cars/applications/ground_truth_reprojection/__init__.py +30 -0
- cars/applications/ground_truth_reprojection/abstract_ground_truth_reprojection_app.py +137 -0
- cars/applications/ground_truth_reprojection/direct_localization_app.py +629 -0
- cars/applications/ground_truth_reprojection/ground_truth_reprojection_algo.py +275 -0
- cars/applications/point_cloud_outlier_removal/__init__.py +30 -0
- cars/applications/point_cloud_outlier_removal/abstract_outlier_removal_app.py +385 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_algo.py +392 -0
- cars/applications/point_cloud_outlier_removal/outlier_removal_constants.py +43 -0
- cars/applications/point_cloud_outlier_removal/small_components_app.py +527 -0
- cars/applications/point_cloud_outlier_removal/statistical_app.py +531 -0
- cars/applications/rasterization/__init__.py +30 -0
- cars/applications/rasterization/abstract_pc_rasterization_app.py +183 -0
- cars/applications/rasterization/rasterization_algo.py +534 -0
- cars/applications/rasterization/rasterization_constants.py +38 -0
- cars/applications/rasterization/rasterization_wrappers.py +634 -0
- cars/applications/rasterization/simple_gaussian_app.py +1152 -0
- cars/applications/resampling/__init__.py +28 -0
- cars/applications/resampling/abstract_resampling_app.py +187 -0
- cars/applications/resampling/bicubic_resampling_app.py +762 -0
- cars/applications/resampling/resampling_algo.py +614 -0
- cars/applications/resampling/resampling_constants.py +36 -0
- cars/applications/resampling/resampling_wrappers.py +309 -0
- cars/applications/sparse_matching/__init__.py +30 -0
- cars/applications/sparse_matching/abstract_sparse_matching_app.py +498 -0
- cars/applications/sparse_matching/sift_app.py +735 -0
- cars/applications/sparse_matching/sparse_matching_algo.py +360 -0
- cars/applications/sparse_matching/sparse_matching_constants.py +68 -0
- cars/applications/sparse_matching/sparse_matching_wrappers.py +238 -0
- cars/applications/triangulation/__init__.py +32 -0
- cars/applications/triangulation/abstract_triangulation_app.py +227 -0
- cars/applications/triangulation/line_of_sight_intersection_app.py +1243 -0
- cars/applications/triangulation/pc_transform.py +552 -0
- cars/applications/triangulation/triangulation_algo.py +371 -0
- cars/applications/triangulation/triangulation_constants.py +38 -0
- cars/applications/triangulation/triangulation_wrappers.py +259 -0
- cars/bundleadjustment.py +757 -0
- cars/cars.py +177 -0
- cars/conf/__init__.py +23 -0
- cars/conf/geoid/egm96.grd +0 -0
- cars/conf/geoid/egm96.grd.hdr +15 -0
- cars/conf/input_parameters.py +156 -0
- cars/conf/mask_cst.py +35 -0
- cars/core/__init__.py +23 -0
- cars/core/cars_logging.py +402 -0
- cars/core/constants.py +191 -0
- cars/core/constants_disparity.py +50 -0
- cars/core/datasets.py +140 -0
- cars/core/geometry/__init__.py +27 -0
- cars/core/geometry/abstract_geometry.py +1119 -0
- cars/core/geometry/shareloc_geometry.py +598 -0
- cars/core/inputs.py +568 -0
- cars/core/outputs.py +176 -0
- cars/core/preprocessing.py +722 -0
- cars/core/projection.py +843 -0
- cars/core/roi_tools.py +215 -0
- cars/core/tiling.py +774 -0
- cars/core/utils.py +164 -0
- cars/data_structures/__init__.py +23 -0
- cars/data_structures/cars_dataset.py +1541 -0
- cars/data_structures/cars_dict.py +74 -0
- cars/data_structures/corresponding_tiles_tools.py +186 -0
- cars/data_structures/dataframe_converter.py +185 -0
- cars/data_structures/format_transformation.py +297 -0
- cars/devibrate.py +689 -0
- cars/extractroi.py +264 -0
- cars/orchestrator/__init__.py +23 -0
- cars/orchestrator/achievement_tracker.py +125 -0
- cars/orchestrator/cluster/__init__.py +37 -0
- cars/orchestrator/cluster/abstract_cluster.py +244 -0
- cars/orchestrator/cluster/abstract_dask_cluster.py +375 -0
- cars/orchestrator/cluster/dask_cluster_tools.py +103 -0
- cars/orchestrator/cluster/dask_config/README.md +94 -0
- cars/orchestrator/cluster/dask_config/dask.yaml +21 -0
- cars/orchestrator/cluster/dask_config/distributed.yaml +70 -0
- cars/orchestrator/cluster/dask_config/jobqueue.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask-schema.yaml +137 -0
- cars/orchestrator/cluster/dask_config/reference_confs/dask.yaml +26 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed-schema.yaml +1009 -0
- cars/orchestrator/cluster/dask_config/reference_confs/distributed.yaml +273 -0
- cars/orchestrator/cluster/dask_config/reference_confs/jobqueue.yaml +212 -0
- cars/orchestrator/cluster/dask_jobqueue_utils.py +204 -0
- cars/orchestrator/cluster/local_dask_cluster.py +116 -0
- cars/orchestrator/cluster/log_wrapper.py +1075 -0
- cars/orchestrator/cluster/mp_cluster/__init__.py +27 -0
- cars/orchestrator/cluster/mp_cluster/mp_factorizer.py +212 -0
- cars/orchestrator/cluster/mp_cluster/mp_objects.py +535 -0
- cars/orchestrator/cluster/mp_cluster/mp_tools.py +93 -0
- cars/orchestrator/cluster/mp_cluster/mp_wrapper.py +505 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_cluster.py +873 -0
- cars/orchestrator/cluster/mp_cluster/multiprocessing_profiler.py +399 -0
- cars/orchestrator/cluster/pbs_dask_cluster.py +207 -0
- cars/orchestrator/cluster/sequential_cluster.py +139 -0
- cars/orchestrator/cluster/slurm_dask_cluster.py +234 -0
- cars/orchestrator/orchestrator.py +905 -0
- cars/orchestrator/orchestrator_constants.py +29 -0
- cars/orchestrator/registry/__init__.py +23 -0
- cars/orchestrator/registry/abstract_registry.py +143 -0
- cars/orchestrator/registry/compute_registry.py +106 -0
- cars/orchestrator/registry/id_generator.py +116 -0
- cars/orchestrator/registry/replacer_registry.py +213 -0
- cars/orchestrator/registry/saver_registry.py +363 -0
- cars/orchestrator/registry/unseen_registry.py +118 -0
- cars/orchestrator/tiles_profiler.py +279 -0
- cars/pipelines/__init__.py +26 -0
- cars/pipelines/conf_resolution/conf_final_resolution.yaml +5 -0
- cars/pipelines/conf_resolution/conf_first_resolution.yaml +2 -0
- cars/pipelines/conf_resolution/conf_intermediate_resolution.yaml +2 -0
- cars/pipelines/default/__init__.py +26 -0
- cars/pipelines/default/default_pipeline.py +786 -0
- cars/pipelines/parameters/__init__.py +0 -0
- cars/pipelines/parameters/advanced_parameters.py +417 -0
- cars/pipelines/parameters/advanced_parameters_constants.py +69 -0
- cars/pipelines/parameters/application_parameters.py +71 -0
- cars/pipelines/parameters/depth_map_inputs.py +0 -0
- cars/pipelines/parameters/dsm_inputs.py +918 -0
- cars/pipelines/parameters/dsm_inputs_constants.py +25 -0
- cars/pipelines/parameters/output_constants.py +52 -0
- cars/pipelines/parameters/output_parameters.py +454 -0
- cars/pipelines/parameters/sensor_inputs.py +842 -0
- cars/pipelines/parameters/sensor_inputs_constants.py +49 -0
- cars/pipelines/parameters/sensor_loaders/__init__.py +29 -0
- cars/pipelines/parameters/sensor_loaders/basic_classif_loader.py +86 -0
- cars/pipelines/parameters/sensor_loaders/basic_image_loader.py +98 -0
- cars/pipelines/parameters/sensor_loaders/pivot_classif_loader.py +90 -0
- cars/pipelines/parameters/sensor_loaders/pivot_image_loader.py +105 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader.py +93 -0
- cars/pipelines/parameters/sensor_loaders/sensor_loader_template.py +71 -0
- cars/pipelines/parameters/sensor_loaders/slurp_classif_loader.py +86 -0
- cars/pipelines/pipeline.py +119 -0
- cars/pipelines/pipeline_constants.py +31 -0
- cars/pipelines/pipeline_template.py +139 -0
- cars/pipelines/unit/__init__.py +26 -0
- cars/pipelines/unit/unit_pipeline.py +2850 -0
- cars/starter.py +167 -0
- cars-1.0.0rc1.dist-info/METADATA +292 -0
- cars-1.0.0rc1.dist-info/RECORD +200 -0
- cars-1.0.0rc1.dist-info/WHEEL +6 -0
- cars-1.0.0rc1.dist-info/entry_points.txt +8 -0
|
@@ -0,0 +1,535 @@
|
|
|
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 class objects used by multiprocessing cluster
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import threading
|
|
26
|
+
import time
|
|
27
|
+
|
|
28
|
+
from cars.orchestrator.cluster.mp_cluster.mp_tools import replace_data_rec
|
|
29
|
+
from cars.orchestrator.cluster.mp_cluster.mp_wrapper import load_args_or_kwargs
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class MpJob: # pylint: disable=R0903
|
|
33
|
+
"""
|
|
34
|
+
Encapsulation of multiprocessing job Id (internal use for mp_local_cluster)
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
__slots__ = ["task_id", "r_idx"]
|
|
38
|
+
|
|
39
|
+
def __init__(self, idx, return_index):
|
|
40
|
+
self.__class__.__name__ = "MpJob"
|
|
41
|
+
self.task_id = idx
|
|
42
|
+
self.r_idx = return_index
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class MpDelayedTask: # pylint: disable=R0903
|
|
46
|
+
"""
|
|
47
|
+
Delayed task
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(self, func, args, kw_args):
|
|
51
|
+
"""
|
|
52
|
+
Init function of MpDelayedTask
|
|
53
|
+
|
|
54
|
+
:param func: function to run
|
|
55
|
+
:param args: args of function
|
|
56
|
+
:param kw_args: kwargs of function
|
|
57
|
+
|
|
58
|
+
"""
|
|
59
|
+
self.__class__.__name__ = "MpDelayedTask"
|
|
60
|
+
self.func = func
|
|
61
|
+
self.args = args
|
|
62
|
+
self.kw_args = kw_args
|
|
63
|
+
self.associated_objects = []
|
|
64
|
+
|
|
65
|
+
def __repr__(self):
|
|
66
|
+
"""
|
|
67
|
+
Repr function
|
|
68
|
+
:return: printable self CarsDataset
|
|
69
|
+
"""
|
|
70
|
+
return self.custom_print()
|
|
71
|
+
|
|
72
|
+
def __str__(self):
|
|
73
|
+
"""
|
|
74
|
+
Str function
|
|
75
|
+
:return: printable self CarsDataset
|
|
76
|
+
"""
|
|
77
|
+
return self.custom_print()
|
|
78
|
+
|
|
79
|
+
def custom_print(self):
|
|
80
|
+
"""
|
|
81
|
+
Return string of self
|
|
82
|
+
:return : printable delayed
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
res = (
|
|
86
|
+
"MpDelayedTask: \n "
|
|
87
|
+
+ str(self.func)
|
|
88
|
+
+ "\n"
|
|
89
|
+
+ "args : "
|
|
90
|
+
+ str(self.args)
|
|
91
|
+
+ "\n kw_args: \n"
|
|
92
|
+
+ str(self.kw_args)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
return res
|
|
96
|
+
|
|
97
|
+
def modify_delayed_task(self, wrapper):
|
|
98
|
+
"""
|
|
99
|
+
Modify delayed to add wrapper (disk, None)
|
|
100
|
+
|
|
101
|
+
:param wrapper: wrapper function
|
|
102
|
+
:type wrapper: fun
|
|
103
|
+
"""
|
|
104
|
+
used_func, used_kwargs = wrapper.get_function_and_kwargs(
|
|
105
|
+
self.func, self.kw_args, nout=len(self.associated_objects)
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
self.kw_args = used_kwargs
|
|
109
|
+
self.func = used_func
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class MpDelayed: # pylint: disable=R0903
|
|
113
|
+
"""
|
|
114
|
+
multiprocessing version of dask.delayed
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def __init__(self, delayed_task, return_index=0):
|
|
118
|
+
self.__class__.__name__ = "MpDelayed"
|
|
119
|
+
self.delayed_task = delayed_task
|
|
120
|
+
self.return_index = return_index
|
|
121
|
+
|
|
122
|
+
# register to delayed_task
|
|
123
|
+
self.delayed_task.associated_objects.append(self)
|
|
124
|
+
|
|
125
|
+
def __repr__(self):
|
|
126
|
+
"""
|
|
127
|
+
Repr function
|
|
128
|
+
:return: printable self CarsDataset
|
|
129
|
+
"""
|
|
130
|
+
return self.custom_print()
|
|
131
|
+
|
|
132
|
+
def __str__(self):
|
|
133
|
+
"""
|
|
134
|
+
Str function
|
|
135
|
+
:return: printable self CarsDataset
|
|
136
|
+
"""
|
|
137
|
+
return self.custom_print()
|
|
138
|
+
|
|
139
|
+
def custom_print(self):
|
|
140
|
+
"""
|
|
141
|
+
Return string of self
|
|
142
|
+
:return : printable delayed
|
|
143
|
+
"""
|
|
144
|
+
if "log_fun" in self.delayed_task.kw_args:
|
|
145
|
+
name = str(self.delayed_task.kw_args["log_fun"])
|
|
146
|
+
elif isinstance(self.delayed_task.args[0], FactorizedObject):
|
|
147
|
+
# Task is factorized
|
|
148
|
+
name = str(self.delayed_task.args[0])
|
|
149
|
+
else:
|
|
150
|
+
name = str(self.delayed_task.func)
|
|
151
|
+
|
|
152
|
+
res = (
|
|
153
|
+
("MpDELAYED : " + name) + " return index: " + str(self.return_index)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return res
|
|
157
|
+
|
|
158
|
+
def get_depending_delayed(self):
|
|
159
|
+
"""
|
|
160
|
+
Get all the delayed that current delayed depends on
|
|
161
|
+
|
|
162
|
+
:return list of depending delayed
|
|
163
|
+
:rtype: list(MpDelayed)
|
|
164
|
+
"""
|
|
165
|
+
|
|
166
|
+
def get_depending_delayed_rec(list_or_dict):
|
|
167
|
+
"""
|
|
168
|
+
Get all the delayed that current delayed depends on
|
|
169
|
+
|
|
170
|
+
:return list of depending delayed
|
|
171
|
+
:rtype: list(MpDelayed)
|
|
172
|
+
"""
|
|
173
|
+
|
|
174
|
+
depending_delayed = []
|
|
175
|
+
|
|
176
|
+
if isinstance(list_or_dict, (list, tuple)):
|
|
177
|
+
for arg in list_or_dict:
|
|
178
|
+
depending_delayed += get_depending_delayed_rec(arg)
|
|
179
|
+
|
|
180
|
+
elif isinstance(list_or_dict, dict):
|
|
181
|
+
for key in list_or_dict:
|
|
182
|
+
depending_delayed += get_depending_delayed_rec(
|
|
183
|
+
list_or_dict[key]
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
elif isinstance(list_or_dict, FactorizedObject):
|
|
187
|
+
depending_delayed += get_depending_delayed_rec(
|
|
188
|
+
list_or_dict.get_args()
|
|
189
|
+
)
|
|
190
|
+
depending_delayed += get_depending_delayed_rec(
|
|
191
|
+
list_or_dict.get_kwargs()
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
elif isinstance(list_or_dict, MpDelayed):
|
|
195
|
+
depending_delayed.append(list_or_dict)
|
|
196
|
+
|
|
197
|
+
return depending_delayed
|
|
198
|
+
|
|
199
|
+
depending_delayed_in_args = get_depending_delayed_rec(
|
|
200
|
+
self.delayed_task.args
|
|
201
|
+
)
|
|
202
|
+
depending_delayed_in_kwargs = get_depending_delayed_rec(
|
|
203
|
+
self.delayed_task.kw_args
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
return depending_delayed_in_args + depending_delayed_in_kwargs
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class MpFuture:
|
|
210
|
+
"""
|
|
211
|
+
Multiprocessing version of distributed.future
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
def __init__(self, mp_future_task, return_index):
|
|
215
|
+
"""
|
|
216
|
+
Init function of SequentialCluster
|
|
217
|
+
|
|
218
|
+
:param mp_future_task: Future task
|
|
219
|
+
:param return_index: index of return object
|
|
220
|
+
|
|
221
|
+
"""
|
|
222
|
+
self.__class__.__name__ = "MpFuture"
|
|
223
|
+
|
|
224
|
+
self.mp_future_task = mp_future_task
|
|
225
|
+
# register itself to future_task
|
|
226
|
+
self.mp_future_task.associated_futures.append(self)
|
|
227
|
+
|
|
228
|
+
self.result = None
|
|
229
|
+
self._success = None
|
|
230
|
+
self.return_index = return_index
|
|
231
|
+
self.event = threading.Event()
|
|
232
|
+
|
|
233
|
+
def cleanup(self):
|
|
234
|
+
"""
|
|
235
|
+
Cleanup future
|
|
236
|
+
"""
|
|
237
|
+
self.event.clear()
|
|
238
|
+
|
|
239
|
+
def ready(self):
|
|
240
|
+
"""
|
|
241
|
+
Check if future is ready
|
|
242
|
+
|
|
243
|
+
"""
|
|
244
|
+
return self.event.is_set()
|
|
245
|
+
|
|
246
|
+
def successful(self):
|
|
247
|
+
"""
|
|
248
|
+
Check if future is successful
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
if not self.ready():
|
|
252
|
+
raise ValueError("mp_future not ready!")
|
|
253
|
+
return self._success
|
|
254
|
+
|
|
255
|
+
def set(self, success, obj):
|
|
256
|
+
"""
|
|
257
|
+
Set results to future
|
|
258
|
+
|
|
259
|
+
:param success: success of future
|
|
260
|
+
:type success: bool
|
|
261
|
+
:param obj: result
|
|
262
|
+
|
|
263
|
+
"""
|
|
264
|
+
self._success = success
|
|
265
|
+
if self._success:
|
|
266
|
+
if not isinstance(obj, tuple):
|
|
267
|
+
if self.return_index > 0:
|
|
268
|
+
raise ValueError("Asked for index > 0 in a singleton")
|
|
269
|
+
self.result = obj
|
|
270
|
+
else:
|
|
271
|
+
self.result = obj[self.return_index]
|
|
272
|
+
else:
|
|
273
|
+
self.result = obj
|
|
274
|
+
self.event.set()
|
|
275
|
+
|
|
276
|
+
def wait(self, timeout=None):
|
|
277
|
+
"""
|
|
278
|
+
Wait
|
|
279
|
+
|
|
280
|
+
:param timeout: timeout to apply
|
|
281
|
+
|
|
282
|
+
"""
|
|
283
|
+
self.event.wait(timeout)
|
|
284
|
+
|
|
285
|
+
def get(self, timeout=None):
|
|
286
|
+
"""
|
|
287
|
+
Get result
|
|
288
|
+
|
|
289
|
+
:param timeout: timeout to apply
|
|
290
|
+
|
|
291
|
+
"""
|
|
292
|
+
self.wait(timeout)
|
|
293
|
+
if not self.ready():
|
|
294
|
+
raise TimeoutError
|
|
295
|
+
if not self._success:
|
|
296
|
+
raise self.result
|
|
297
|
+
return self.result
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class MpFutureIterator:
|
|
301
|
+
"""
|
|
302
|
+
iterator on multiprocessing.pool.AsyncResult, similar to as_completed
|
|
303
|
+
Only returns the actual results, delete the future after usage
|
|
304
|
+
"""
|
|
305
|
+
|
|
306
|
+
def __init__(self, future_list, cluster, timeout=None):
|
|
307
|
+
"""
|
|
308
|
+
Init function of MpFutureIterator
|
|
309
|
+
|
|
310
|
+
:param future_list: list of futures
|
|
311
|
+
|
|
312
|
+
"""
|
|
313
|
+
self.future_list = future_list
|
|
314
|
+
self.cluster = cluster
|
|
315
|
+
self.was_killed = False
|
|
316
|
+
self.timeout = timeout
|
|
317
|
+
self.past_time = time.time()
|
|
318
|
+
|
|
319
|
+
# update future list for cleaning
|
|
320
|
+
for future in future_list:
|
|
321
|
+
self.cluster.cl_future_list.append(future)
|
|
322
|
+
|
|
323
|
+
def __iter__(self):
|
|
324
|
+
"""
|
|
325
|
+
Iterate
|
|
326
|
+
|
|
327
|
+
"""
|
|
328
|
+
return self
|
|
329
|
+
|
|
330
|
+
def __next__(self):
|
|
331
|
+
"""
|
|
332
|
+
Next
|
|
333
|
+
|
|
334
|
+
"""
|
|
335
|
+
if not self.future_list:
|
|
336
|
+
raise StopIteration
|
|
337
|
+
res = None
|
|
338
|
+
while res is None:
|
|
339
|
+
if self.timeout is not None:
|
|
340
|
+
if time.time() - self.past_time > self.timeout:
|
|
341
|
+
raise TimeoutError("No task completed before timeout")
|
|
342
|
+
for item in self.future_list:
|
|
343
|
+
if item.ready():
|
|
344
|
+
if not item.successful():
|
|
345
|
+
raise RuntimeError("Failure in tasks")
|
|
346
|
+
res = item
|
|
347
|
+
self.past_time = time.time()
|
|
348
|
+
break
|
|
349
|
+
|
|
350
|
+
self.future_list.remove(res)
|
|
351
|
+
# transform result (depending on the wrapper)
|
|
352
|
+
transformed_res = self.cluster.wrapper.get_obj(res.get())
|
|
353
|
+
|
|
354
|
+
# update future list for cleaning
|
|
355
|
+
self.cluster.cl_future_list.remove(res)
|
|
356
|
+
|
|
357
|
+
return transformed_res
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
class PreviousData: # pylint: disable=R0903
|
|
361
|
+
"""
|
|
362
|
+
Object used in FactorisedObject for args already computed
|
|
363
|
+
in factorized function
|
|
364
|
+
|
|
365
|
+
"""
|
|
366
|
+
|
|
367
|
+
def __init__(self, delayed):
|
|
368
|
+
"""
|
|
369
|
+
Init function of PreviousData
|
|
370
|
+
|
|
371
|
+
:param return_index: position of data in output of task
|
|
372
|
+
"""
|
|
373
|
+
self.return_index = delayed.return_index
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def transform_mp_delayed_to_previous_data(obj):
|
|
377
|
+
"""
|
|
378
|
+
Replace MpDelayed by PreviousData object
|
|
379
|
+
|
|
380
|
+
:param data: data to replace if necessary
|
|
381
|
+
|
|
382
|
+
"""
|
|
383
|
+
|
|
384
|
+
new_data = obj
|
|
385
|
+
if isinstance(obj, MpDelayed):
|
|
386
|
+
new_data = PreviousData(obj)
|
|
387
|
+
return new_data
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
def transform_previous_data_to_results(obj, res):
|
|
391
|
+
"""
|
|
392
|
+
Replace PreviousData object by real data
|
|
393
|
+
|
|
394
|
+
:param data: data to replace if necessary
|
|
395
|
+
|
|
396
|
+
"""
|
|
397
|
+
|
|
398
|
+
new_data = obj
|
|
399
|
+
if isinstance(obj, PreviousData):
|
|
400
|
+
pos = obj.return_index
|
|
401
|
+
if isinstance(res, tuple):
|
|
402
|
+
new_data = res[pos]
|
|
403
|
+
else:
|
|
404
|
+
if pos != 0:
|
|
405
|
+
raise RuntimeError(
|
|
406
|
+
"Waiting multiple output but res is not tuple"
|
|
407
|
+
)
|
|
408
|
+
new_data = res
|
|
409
|
+
return new_data
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
class FactorizedObject:
|
|
413
|
+
"""
|
|
414
|
+
Object used as args of function factorised_func
|
|
415
|
+
It contains several tasks that can be run within a single function
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
def __init__(self, current_task, previous_task):
|
|
419
|
+
"""
|
|
420
|
+
Init function of FactorizedObject
|
|
421
|
+
|
|
422
|
+
:param current_task: last task to execute in factorized_func
|
|
423
|
+
(arg of task can be a factorized object)
|
|
424
|
+
:param previous_task: task to add and run before current task
|
|
425
|
+
(arg of task can NOT be a factorized object)
|
|
426
|
+
"""
|
|
427
|
+
current_task_is_factorized = False
|
|
428
|
+
current_factorized_object = None
|
|
429
|
+
|
|
430
|
+
current_fun = current_task.func
|
|
431
|
+
current_args = current_task.args
|
|
432
|
+
current_kwargs = current_task.kw_args
|
|
433
|
+
|
|
434
|
+
if isinstance(current_args[0], FactorizedObject):
|
|
435
|
+
current_task_is_factorized = True
|
|
436
|
+
current_factorized_object = current_args[0]
|
|
437
|
+
current_args = current_factorized_object.get_args()
|
|
438
|
+
current_kwargs = current_factorized_object.get_kwargs()
|
|
439
|
+
|
|
440
|
+
# Replace MpDelayed with PreviousData that will be computed
|
|
441
|
+
# in run method of FactorizedObject before the call of current_task
|
|
442
|
+
new_args = replace_data_rec(
|
|
443
|
+
current_args, transform_mp_delayed_to_previous_data
|
|
444
|
+
)
|
|
445
|
+
new_kwargs = replace_data_rec(
|
|
446
|
+
current_kwargs, transform_mp_delayed_to_previous_data
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
if current_task_is_factorized:
|
|
450
|
+
# List of tasks is initialized with all tasks in current
|
|
451
|
+
# factorized task
|
|
452
|
+
current_factorized_object.set_args(new_args)
|
|
453
|
+
current_factorized_object.set_kwargs(new_kwargs)
|
|
454
|
+
self.tasks = current_factorized_object.tasks
|
|
455
|
+
else:
|
|
456
|
+
# List of tasks is initialized with current task
|
|
457
|
+
self.tasks = [
|
|
458
|
+
{
|
|
459
|
+
"func": current_fun,
|
|
460
|
+
"args": new_args,
|
|
461
|
+
"kwargs": new_kwargs,
|
|
462
|
+
}
|
|
463
|
+
]
|
|
464
|
+
|
|
465
|
+
# Add at the end of the list the first task to be executed
|
|
466
|
+
# (self.tasks is a LIFO queue)
|
|
467
|
+
previous_fun = previous_task.func
|
|
468
|
+
previous_args = previous_task.args
|
|
469
|
+
previous_kwargs = previous_task.kw_args
|
|
470
|
+
|
|
471
|
+
self.tasks.append(
|
|
472
|
+
{
|
|
473
|
+
"func": previous_fun,
|
|
474
|
+
"args": previous_args,
|
|
475
|
+
"kwargs": previous_kwargs,
|
|
476
|
+
}
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
def __str__(self):
|
|
480
|
+
res = "Factorized Object : "
|
|
481
|
+
for task in reversed(self.tasks):
|
|
482
|
+
res += str(task["kwargs"]["log_fun"]) + ", "
|
|
483
|
+
return res
|
|
484
|
+
|
|
485
|
+
def get_args(self):
|
|
486
|
+
"""
|
|
487
|
+
Get args of first task to execute
|
|
488
|
+
"""
|
|
489
|
+
return self.tasks[-1]["args"]
|
|
490
|
+
|
|
491
|
+
def set_args(self, args):
|
|
492
|
+
"""
|
|
493
|
+
Set args of first task to execute
|
|
494
|
+
|
|
495
|
+
:param args: arguments to set
|
|
496
|
+
"""
|
|
497
|
+
self.tasks[-1]["args"] = args
|
|
498
|
+
|
|
499
|
+
def get_kwargs(self):
|
|
500
|
+
"""
|
|
501
|
+
Get kwargs of first task to execute
|
|
502
|
+
"""
|
|
503
|
+
return self.tasks[-1]["kwargs"]
|
|
504
|
+
|
|
505
|
+
def set_kwargs(self, kwargs):
|
|
506
|
+
"""
|
|
507
|
+
Set kwargs of first task to execute
|
|
508
|
+
|
|
509
|
+
:param args: keyword arguments to set
|
|
510
|
+
"""
|
|
511
|
+
self.tasks[-1]["kwargs"] = kwargs
|
|
512
|
+
|
|
513
|
+
def pop_next_task(self, previous_result=None):
|
|
514
|
+
"""
|
|
515
|
+
Run the next task to execute, remove it from the list and
|
|
516
|
+
return the result
|
|
517
|
+
|
|
518
|
+
:param previous_result: output of previous task
|
|
519
|
+
"""
|
|
520
|
+
task = self.tasks.pop()
|
|
521
|
+
func = task["func"]
|
|
522
|
+
args = task["args"]
|
|
523
|
+
kwargs = task["kwargs"]
|
|
524
|
+
if previous_result is not None:
|
|
525
|
+
# Replace PreviousData objects with output of previous task
|
|
526
|
+
args = replace_data_rec(
|
|
527
|
+
args, transform_previous_data_to_results, previous_result
|
|
528
|
+
)
|
|
529
|
+
kwargs = replace_data_rec(
|
|
530
|
+
kwargs, transform_previous_data_to_results, previous_result
|
|
531
|
+
)
|
|
532
|
+
# Load remaining args : shared data
|
|
533
|
+
args = load_args_or_kwargs(args)
|
|
534
|
+
kwargs = load_args_or_kwargs(kwargs)
|
|
535
|
+
return func(*args, **kwargs)
|
|
@@ -0,0 +1,93 @@
|
|
|
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 tools for multiprocessing
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def replace_data(list_or_dict, func_to_apply, *func_args):
|
|
27
|
+
"""
|
|
28
|
+
Replace MpJob in list or dict by their real data
|
|
29
|
+
(can deal with FactorizedObject)
|
|
30
|
+
|
|
31
|
+
:param list_or_dict: list or dict of data or mp_objects.FactorizedObject
|
|
32
|
+
:param func_to_apply: function to apply
|
|
33
|
+
:param func_args: function arguments
|
|
34
|
+
|
|
35
|
+
:return: list or dict with real data
|
|
36
|
+
:rtype: list, tuple, dict, mp_objects.FactorizedObject
|
|
37
|
+
"""
|
|
38
|
+
if (
|
|
39
|
+
isinstance(list_or_dict, (list, tuple))
|
|
40
|
+
and len(list_or_dict) == 1
|
|
41
|
+
and type(list_or_dict[0]).__name__ == "FactorizedObject"
|
|
42
|
+
):
|
|
43
|
+
# list_or_dict is a single FactorizedObject
|
|
44
|
+
factorized_object = list_or_dict[0]
|
|
45
|
+
args = factorized_object.get_args()
|
|
46
|
+
args = replace_data_rec(args, func_to_apply, *func_args)
|
|
47
|
+
kwargs = factorized_object.get_kwargs()
|
|
48
|
+
kwargs = replace_data_rec(kwargs, func_to_apply, *func_args)
|
|
49
|
+
|
|
50
|
+
factorized_object.set_args(args)
|
|
51
|
+
factorized_object.set_kwargs(kwargs)
|
|
52
|
+
return [factorized_object]
|
|
53
|
+
|
|
54
|
+
return replace_data_rec(list_or_dict, func_to_apply, *func_args)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def replace_data_rec(list_or_dict, func_to_apply, *func_args):
|
|
58
|
+
"""
|
|
59
|
+
Replace MpJob in list or dict by their real data recursively
|
|
60
|
+
|
|
61
|
+
:param list_or_dict: list or dict of data
|
|
62
|
+
:param func_to_apply: function to apply
|
|
63
|
+
:param func_args: function arguments
|
|
64
|
+
|
|
65
|
+
:return: list or dict with real data
|
|
66
|
+
:rtype: list, tuple, dict
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
if isinstance(list_or_dict, (list, tuple)):
|
|
70
|
+
res = []
|
|
71
|
+
for arg in list_or_dict:
|
|
72
|
+
if isinstance(arg, (list, tuple, dict)):
|
|
73
|
+
res.append(replace_data_rec(arg, func_to_apply, *func_args))
|
|
74
|
+
else:
|
|
75
|
+
res.append(func_to_apply(arg, *func_args))
|
|
76
|
+
if isinstance(list_or_dict, tuple):
|
|
77
|
+
res = tuple(res)
|
|
78
|
+
|
|
79
|
+
elif isinstance(list_or_dict, dict):
|
|
80
|
+
res = {}
|
|
81
|
+
for key, value in list_or_dict.items():
|
|
82
|
+
if isinstance(value, (list, dict, tuple)):
|
|
83
|
+
res[key] = replace_data_rec(value, func_to_apply, *func_args)
|
|
84
|
+
else:
|
|
85
|
+
res[key] = func_to_apply(value, *func_args)
|
|
86
|
+
|
|
87
|
+
else:
|
|
88
|
+
raise TypeError(
|
|
89
|
+
"Function only support list or dict or tuple, "
|
|
90
|
+
"but type is {}".format(list_or_dict)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
return res
|