ChessAnalysisPipeline 0.0.15__py3-none-any.whl → 0.0.16__py3-none-any.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 ChessAnalysisPipeline might be problematic. Click here for more details.
- CHAP/__init__.py +1 -1
- CHAP/common/__init__.py +4 -0
- CHAP/common/models/integration.py +29 -26
- CHAP/common/models/map.py +186 -255
- CHAP/common/processor.py +956 -160
- CHAP/common/reader.py +93 -27
- CHAP/common/writer.py +15 -5
- CHAP/edd/__init__.py +2 -2
- CHAP/edd/models.py +299 -449
- CHAP/edd/processor.py +639 -448
- CHAP/edd/reader.py +232 -15
- CHAP/giwaxs/__init__.py +8 -0
- CHAP/giwaxs/models.py +100 -0
- CHAP/giwaxs/processor.py +520 -0
- CHAP/giwaxs/reader.py +5 -0
- CHAP/giwaxs/writer.py +5 -0
- CHAP/pipeline.py +47 -9
- CHAP/runner.py +160 -71
- CHAP/tomo/models.py +25 -25
- CHAP/tomo/processor.py +51 -79
- CHAP/utils/general.py +18 -0
- CHAP/utils/models.py +76 -49
- CHAP/utils/parfile.py +10 -2
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/METADATA +1 -1
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/RECORD +29 -25
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/WHEEL +1 -1
- CHAP/utils/scanparsers.py +0 -1544
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/LICENSE +0 -0
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/entry_points.txt +0 -0
- {ChessAnalysisPipeline-0.0.15.dist-info → ChessAnalysisPipeline-0.0.16.dist-info}/top_level.txt +0 -0
CHAP/runner.py
CHANGED
|
@@ -21,25 +21,35 @@ class RunConfig():
|
|
|
21
21
|
'outputdir': '.',
|
|
22
22
|
'interactive': False,
|
|
23
23
|
'log_level': 'INFO',
|
|
24
|
-
'profile': False
|
|
24
|
+
'profile': False,
|
|
25
|
+
'spawn': 0}
|
|
25
26
|
|
|
26
|
-
def __init__(self, config={}):
|
|
27
|
-
"""RunConfig constructor
|
|
27
|
+
def __init__(self, config={}, comm=None):
|
|
28
|
+
"""RunConfig constructor.
|
|
28
29
|
|
|
29
|
-
:param config: Pipeline configuration options
|
|
30
|
-
|
|
30
|
+
:param config: Pipeline configuration options,
|
|
31
|
+
defaults to `{}`.
|
|
32
|
+
:type config: dict, optional
|
|
33
|
+
:param comm: MPI communicator, defaults to `None`.
|
|
34
|
+
:type comm: mpi4py.MPI.Comm, optional
|
|
31
35
|
"""
|
|
32
36
|
# System modules
|
|
33
37
|
from tempfile import NamedTemporaryFile
|
|
34
38
|
|
|
39
|
+
# Make sure os.makedirs is only called from the root node
|
|
40
|
+
if comm is None:
|
|
41
|
+
rank = 0
|
|
42
|
+
else:
|
|
43
|
+
rank = comm.Get_rank()
|
|
35
44
|
for opt in self.opts:
|
|
36
45
|
setattr(self, opt, config.get(opt, self.opts[opt]))
|
|
37
46
|
|
|
38
47
|
# Check if root exists (create it if not) and is readable
|
|
39
|
-
if not
|
|
40
|
-
os.
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
if not rank:
|
|
49
|
+
if not os.path.isdir(self.root):
|
|
50
|
+
os.makedirs(self.root)
|
|
51
|
+
if not os.access(self.root, os.R_OK):
|
|
52
|
+
raise OSError('root directory is not accessible for reading '
|
|
43
53
|
f'({self.root})')
|
|
44
54
|
|
|
45
55
|
# Check if inputdir exists and is readable
|
|
@@ -56,16 +66,21 @@ class RunConfig():
|
|
|
56
66
|
if not os.path.isabs(self.outputdir):
|
|
57
67
|
self.outputdir = os.path.realpath(
|
|
58
68
|
os.path.join(self.root, self.outputdir))
|
|
59
|
-
if not
|
|
60
|
-
os.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
if not rank:
|
|
70
|
+
if not os.path.isdir(self.outputdir):
|
|
71
|
+
os.makedirs(self.outputdir)
|
|
72
|
+
try:
|
|
73
|
+
tmpfile = NamedTemporaryFile(dir=self.outputdir)
|
|
74
|
+
except:
|
|
75
|
+
raise OSError('output directory is not accessible for writing '
|
|
76
|
+
f'({self.outputdir})')
|
|
66
77
|
|
|
67
78
|
self.log_level = self.log_level.upper()
|
|
68
79
|
|
|
80
|
+
# Make sure os.makedirs completes before continuing all nodes
|
|
81
|
+
if comm is not None:
|
|
82
|
+
comm.barrier()
|
|
83
|
+
|
|
69
84
|
def parser():
|
|
70
85
|
"""Return an argument parser for the `CHAP` CLI. This parser has
|
|
71
86
|
one argument: the input CHAP configuration file.
|
|
@@ -77,50 +92,93 @@ def parser():
|
|
|
77
92
|
return parser
|
|
78
93
|
|
|
79
94
|
def main():
|
|
80
|
-
"""Main function"""
|
|
95
|
+
"""Main function."""
|
|
96
|
+
# Third party modules
|
|
97
|
+
try:
|
|
98
|
+
from mpi4py import MPI
|
|
99
|
+
have_mpi = True
|
|
100
|
+
comm = MPI.COMM_WORLD
|
|
101
|
+
except:
|
|
102
|
+
have_mpi = False
|
|
103
|
+
comm = None
|
|
104
|
+
|
|
81
105
|
args = parser().parse_args()
|
|
82
106
|
|
|
83
|
-
#
|
|
107
|
+
# Read the input config file
|
|
84
108
|
configfile = args.config
|
|
85
109
|
with open(configfile) as file:
|
|
86
110
|
config = safe_load(file)
|
|
87
|
-
|
|
111
|
+
|
|
112
|
+
# Check if run was a worker spawned by another Processor
|
|
113
|
+
run_config = RunConfig(config.get('config', {}), comm)
|
|
114
|
+
if have_mpi and run_config.spawn:
|
|
115
|
+
sub_comm = MPI.Comm.Get_parent()
|
|
116
|
+
common_comm = sub_comm.Merge(True)
|
|
117
|
+
# Read worker specific input config file
|
|
118
|
+
if run_config.spawn > 0:
|
|
119
|
+
with open(f'{configfile}_{common_comm.Get_rank()}') as file:
|
|
120
|
+
config = safe_load(file)
|
|
121
|
+
run_config = RunConfig(config.get('config', {}), common_comm)
|
|
122
|
+
else:
|
|
123
|
+
with open(f'{configfile}_{sub_comm.Get_rank()}') as file:
|
|
124
|
+
config = safe_load(file)
|
|
125
|
+
run_config = RunConfig(config.get('config', {}), comm)
|
|
126
|
+
else:
|
|
127
|
+
common_comm = comm
|
|
128
|
+
|
|
129
|
+
# Get the pipeline configurations
|
|
88
130
|
pipeline_config = config.get('pipeline', [])
|
|
89
131
|
|
|
90
|
-
#
|
|
132
|
+
# Profiling setup
|
|
91
133
|
if run_config.profile:
|
|
92
134
|
from cProfile import runctx # python profiler
|
|
93
135
|
from pstats import Stats # profiler statistics
|
|
94
|
-
cmd = 'runner(run_config, pipeline_config)'
|
|
136
|
+
cmd = 'runner(run_config, pipeline_config, common_comm)'
|
|
95
137
|
runctx(cmd, globals(), locals(), 'profile.dat')
|
|
96
138
|
info = Stats('profile.dat')
|
|
97
139
|
info.sort_stats('cumulative')
|
|
98
140
|
info.print_stats()
|
|
99
141
|
else:
|
|
100
|
-
runner(run_config, pipeline_config)
|
|
142
|
+
runner(run_config, pipeline_config, common_comm)
|
|
143
|
+
|
|
144
|
+
# Disconnect the spawned worker
|
|
145
|
+
if have_mpi and run_config.spawn:
|
|
146
|
+
common_comm.barrier()
|
|
147
|
+
sub_comm.Disconnect()
|
|
101
148
|
|
|
102
|
-
def runner(run_config, pipeline_config):
|
|
103
|
-
"""Main runner funtion
|
|
149
|
+
def runner(run_config, pipeline_config, comm=None):
|
|
150
|
+
"""Main runner funtion.
|
|
104
151
|
|
|
105
|
-
:param run_config: CHAP run configuration
|
|
106
|
-
:type run_config: RunConfig
|
|
107
|
-
:param pipeline_config: CHAP Pipeline configuration
|
|
152
|
+
:param run_config: CHAP run configuration.
|
|
153
|
+
:type run_config: CHAP.runner.RunConfig
|
|
154
|
+
:param pipeline_config: CHAP Pipeline configuration.
|
|
108
155
|
:type pipeline_config: dict
|
|
156
|
+
:param comm: MPI communicator, defaults to `None`.
|
|
157
|
+
:type comm: mpi4py.MPI.Comm, optional
|
|
158
|
+
:return: The pipeline's returned data field.
|
|
109
159
|
"""
|
|
160
|
+
# System modules
|
|
161
|
+
from time import time
|
|
162
|
+
|
|
110
163
|
# logging setup
|
|
111
164
|
logger, log_handler = setLogger(run_config.log_level)
|
|
112
165
|
logger.info(f'Input pipeline configuration: {pipeline_config}\n')
|
|
113
166
|
|
|
114
|
-
#
|
|
115
|
-
|
|
167
|
+
# Run the pipeline
|
|
168
|
+
t0 = time()
|
|
169
|
+
data = run(pipeline_config,
|
|
116
170
|
run_config.inputdir, run_config.outputdir, run_config.interactive,
|
|
117
|
-
logger, run_config.log_level, log_handler)
|
|
171
|
+
logger, run_config.log_level, log_handler, comm)
|
|
172
|
+
logger.info(f'Executed "run" in {time()-t0:.3f} seconds')
|
|
173
|
+
return data
|
|
118
174
|
|
|
119
|
-
def setLogger(log_level=
|
|
120
|
-
"""
|
|
121
|
-
Helper function to set CHAP logger
|
|
175
|
+
def setLogger(log_level='INFO'):
|
|
176
|
+
"""Helper function to set CHAP logger.
|
|
122
177
|
|
|
123
|
-
:param log_level:
|
|
178
|
+
:param log_level: Logger level, defaults to `"INFO"`.
|
|
179
|
+
:type log_level: str
|
|
180
|
+
:return: The CHAP logger and logging handler.
|
|
181
|
+
:rtype: logging.Logger, logging.StreamHandler
|
|
124
182
|
"""
|
|
125
183
|
logger = logging.getLogger(__name__)
|
|
126
184
|
log_level = getattr(logging, log_level.upper())
|
|
@@ -133,22 +191,46 @@ def setLogger(log_level="INFO"):
|
|
|
133
191
|
|
|
134
192
|
def run(
|
|
135
193
|
pipeline_config, inputdir=None, outputdir=None, interactive=False,
|
|
136
|
-
logger=None, log_level=None, log_handler=None):
|
|
137
|
-
"""
|
|
138
|
-
Run given pipeline_config
|
|
194
|
+
logger=None, log_level=None, log_handler=None, comm=None):
|
|
195
|
+
"""Run a given pipeline_config.
|
|
139
196
|
|
|
140
|
-
:param pipeline_config: CHAP
|
|
197
|
+
:param pipeline_config: CHAP Pipeline configuration.
|
|
198
|
+
:type pipeline_config: dict
|
|
199
|
+
:param inputdir: Input directory, defaults to `None'`.
|
|
200
|
+
:type inputdir: str, optional
|
|
201
|
+
:param outputdir: Output directory, defaults to `None'`.
|
|
202
|
+
:type outputdir: str, optional
|
|
203
|
+
:param interactive: Allows for user interactions,
|
|
204
|
+
defaults to `False`.
|
|
205
|
+
:type interactive: bool, optional
|
|
206
|
+
:param logger: CHAP logger, defaults to `None`.
|
|
207
|
+
:type logger: logging.Logger, optional
|
|
208
|
+
:param log_level: Logger level, defaults to `None`.
|
|
209
|
+
:type log_level: str, optional
|
|
210
|
+
:param log_handler: logging handler, defaults to `None`.
|
|
211
|
+
:type log_handler: logging.StreamHandler, optional
|
|
212
|
+
:param comm: MPI communicator, defaults to `None`.
|
|
213
|
+
:type comm: mpi4py.MPI.Comm, optional
|
|
214
|
+
:return: The `data` field of the first item in the returned
|
|
215
|
+
list of pipeline items.
|
|
141
216
|
"""
|
|
142
217
|
# System modules
|
|
143
218
|
from tempfile import NamedTemporaryFile
|
|
144
219
|
|
|
220
|
+
# Make sure os.makedirs is only called from the root node
|
|
221
|
+
if comm is None:
|
|
222
|
+
rank = 0
|
|
223
|
+
else:
|
|
224
|
+
rank = comm.Get_rank()
|
|
225
|
+
|
|
145
226
|
objects = []
|
|
146
227
|
kwds = []
|
|
147
228
|
for item in pipeline_config:
|
|
148
|
-
#
|
|
229
|
+
# Load individual object with given name from its module
|
|
149
230
|
kwargs = {'inputdir': inputdir,
|
|
150
231
|
'outputdir': outputdir,
|
|
151
|
-
'interactive': interactive
|
|
232
|
+
'interactive': interactive,
|
|
233
|
+
'comm': comm}
|
|
152
234
|
if isinstance(item, dict):
|
|
153
235
|
name = list(item.keys())[0]
|
|
154
236
|
item_args = item[name]
|
|
@@ -156,39 +238,41 @@ def run(
|
|
|
156
238
|
# "outputdir" and "interactive" with the item's arguments
|
|
157
239
|
# joining "inputdir" and "outputdir" and giving precedence
|
|
158
240
|
# for "interactive" in the latter
|
|
159
|
-
if
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
241
|
+
if item_args is not None:
|
|
242
|
+
if 'inputdir' in item_args:
|
|
243
|
+
newinputdir = os.path.normpath(os.path.join(
|
|
244
|
+
kwargs['inputdir'], item_args.pop('inputdir')))
|
|
245
|
+
if not os.path.isdir(newinputdir):
|
|
246
|
+
raise OSError(
|
|
247
|
+
f'input directory does not exist ({newinputdir})')
|
|
248
|
+
if not os.access(newinputdir, os.R_OK):
|
|
249
|
+
raise OSError('input directory is not accessible for '
|
|
250
|
+
f'reading ({newinputdir})')
|
|
251
|
+
kwargs['inputdir'] = newinputdir
|
|
252
|
+
if 'outputdir' in item_args:
|
|
253
|
+
newoutputdir = os.path.normpath(os.path.join(
|
|
254
|
+
kwargs['outputdir'], item_args.pop('outputdir')))
|
|
255
|
+
if not rank:
|
|
256
|
+
if not os.path.isdir(newoutputdir):
|
|
257
|
+
os.makedirs(newoutputdir)
|
|
258
|
+
try:
|
|
259
|
+
tmpfile = NamedTemporaryFile(dir=newoutputdir)
|
|
260
|
+
except:
|
|
261
|
+
raise OSError('output directory is not accessible '
|
|
262
|
+
f'for writing ({newoutputdir})')
|
|
263
|
+
kwargs['outputdir'] = newoutputdir
|
|
264
|
+
kwargs = {**kwargs, **item_args}
|
|
181
265
|
else:
|
|
182
266
|
name = item
|
|
183
267
|
if "users" in name:
|
|
184
|
-
#
|
|
268
|
+
# Load users module. This is required in CHAPaaS which can
|
|
185
269
|
# have common area for users module. Otherwise, we will be
|
|
186
270
|
# required to have invidual user's PYTHONPATHs to load user
|
|
187
271
|
# processors.
|
|
188
272
|
try:
|
|
189
273
|
import users
|
|
190
274
|
except ImportError:
|
|
191
|
-
if logger:
|
|
275
|
+
if logger is not None:
|
|
192
276
|
logger.error(f'Unable to load {name}')
|
|
193
277
|
continue
|
|
194
278
|
clsName = name.split('.')[-1]
|
|
@@ -199,23 +283,28 @@ def run(
|
|
|
199
283
|
modName, clsName = name.split('.')
|
|
200
284
|
module = __import__(f'CHAP.{modName}', fromlist=[clsName])
|
|
201
285
|
obj = getattr(module, clsName)()
|
|
202
|
-
if log_level:
|
|
286
|
+
if log_level is not None:
|
|
203
287
|
obj.logger.setLevel(log_level)
|
|
204
|
-
if log_handler:
|
|
288
|
+
if log_handler is not None:
|
|
205
289
|
obj.logger.addHandler(log_handler)
|
|
206
|
-
if logger:
|
|
290
|
+
if logger is not None:
|
|
207
291
|
logger.info(f'Loaded {obj}')
|
|
208
292
|
objects.append(obj)
|
|
209
293
|
kwds.append(kwargs)
|
|
210
294
|
pipeline = Pipeline(objects, kwds)
|
|
211
|
-
if log_level:
|
|
295
|
+
if log_level is not None:
|
|
212
296
|
pipeline.logger.setLevel(log_level)
|
|
213
|
-
if log_handler:
|
|
297
|
+
if log_handler is not None:
|
|
214
298
|
pipeline.logger.addHandler(log_handler)
|
|
215
|
-
if logger:
|
|
299
|
+
if logger is not None:
|
|
216
300
|
logger.info(f'Loaded {pipeline} with {len(objects)} items\n')
|
|
217
301
|
logger.info(f'Calling "execute" on {pipeline}')
|
|
218
|
-
|
|
302
|
+
|
|
303
|
+
# Make sure os.makedirs completes before continuing all nodes
|
|
304
|
+
if comm is not None:
|
|
305
|
+
comm.barrier()
|
|
306
|
+
|
|
307
|
+
return pipeline.execute()[0]['data']
|
|
219
308
|
|
|
220
309
|
|
|
221
310
|
if __name__ == '__main__':
|
CHAP/tomo/models.py
CHANGED
|
@@ -36,7 +36,7 @@ class Detector(BaseModel):
|
|
|
36
36
|
columns: conint(gt=0)
|
|
37
37
|
pixel_size: conlist(
|
|
38
38
|
item_type=confloat(gt=0, allow_inf_nan=False),
|
|
39
|
-
|
|
39
|
+
min_length=1, max_length=2)
|
|
40
40
|
lens_magnification: confloat(gt=0, allow_inf_nan=False) = 1.0
|
|
41
41
|
|
|
42
42
|
|
|
@@ -53,8 +53,8 @@ class TomoReduceConfig(BaseModel):
|
|
|
53
53
|
:type delta_theta: float, optional
|
|
54
54
|
"""
|
|
55
55
|
img_row_bounds: Optional[
|
|
56
|
-
conlist(item_type=conint(ge=-1),
|
|
57
|
-
delta_theta: Optional[confloat(gt=0, allow_inf_nan=False)]
|
|
56
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
57
|
+
delta_theta: Optional[confloat(gt=0, allow_inf_nan=False)] = None
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class TomoFindCenterConfig(BaseModel):
|
|
@@ -84,19 +84,19 @@ class TomoFindCenterConfig(BaseModel):
|
|
|
84
84
|
reconstruction in pixels, defaults to no filtering performed.
|
|
85
85
|
:type ring_width: float, optional
|
|
86
86
|
"""
|
|
87
|
-
center_stack_index: Optional[conint(ge=0)]
|
|
87
|
+
center_stack_index: Optional[conint(ge=0)] = None
|
|
88
88
|
center_rows: Optional[conlist(
|
|
89
|
-
item_type=conint(ge=0),
|
|
89
|
+
item_type=conint(ge=0), min_length=2, max_length=2)] = None
|
|
90
90
|
center_offsets: Optional[conlist(
|
|
91
91
|
item_type=confloat(allow_inf_nan=False),
|
|
92
|
-
|
|
93
|
-
center_offset_min: Optional[confloat(allow_inf_nan=False)]
|
|
94
|
-
center_offset_max: Optional[confloat(allow_inf_nan=False)]
|
|
92
|
+
min_length=2, max_length=2)] = None
|
|
93
|
+
center_offset_min: Optional[confloat(allow_inf_nan=False)] = None
|
|
94
|
+
center_offset_max: Optional[confloat(allow_inf_nan=False)] = None
|
|
95
95
|
center_search_range: Optional[conlist(
|
|
96
96
|
item_type=confloat(allow_inf_nan=False),
|
|
97
|
-
|
|
98
|
-
gaussian_sigma: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
99
|
-
ring_width: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
97
|
+
min_length=1, max_length=3)] = None
|
|
98
|
+
gaussian_sigma: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
99
|
+
ring_width: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
100
100
|
|
|
101
101
|
|
|
102
102
|
class TomoReconstructConfig(BaseModel):
|
|
@@ -126,15 +126,15 @@ class TomoReconstructConfig(BaseModel):
|
|
|
126
126
|
:type ring_width: float, optional
|
|
127
127
|
"""
|
|
128
128
|
x_bounds: Optional[
|
|
129
|
-
conlist(item_type=conint(ge=-1),
|
|
129
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
130
130
|
y_bounds: Optional[
|
|
131
|
-
conlist(item_type=conint(ge=-1),
|
|
131
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
132
132
|
z_bounds: Optional[
|
|
133
|
-
conlist(item_type=conint(ge=-1),
|
|
133
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
134
134
|
secondary_iters: conint(ge=0) = 0
|
|
135
|
-
gaussian_sigma: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
136
|
-
remove_stripe_sigma: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
137
|
-
ring_width: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
135
|
+
gaussian_sigma: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
136
|
+
remove_stripe_sigma: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
137
|
+
ring_width: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
138
138
|
|
|
139
139
|
|
|
140
140
|
class TomoCombineConfig(BaseModel):
|
|
@@ -150,11 +150,11 @@ class TomoCombineConfig(BaseModel):
|
|
|
150
150
|
:type z_bounds: list[int], optional
|
|
151
151
|
"""
|
|
152
152
|
x_bounds: Optional[
|
|
153
|
-
conlist(item_type=conint(ge=-1),
|
|
153
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
154
154
|
y_bounds: Optional[
|
|
155
|
-
conlist(item_type=conint(ge=-1),
|
|
155
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
156
156
|
z_bounds: Optional[
|
|
157
|
-
conlist(item_type=conint(ge=-1),
|
|
157
|
+
conlist(item_type=conint(ge=-1), min_length=2, max_length=2)] = None
|
|
158
158
|
|
|
159
159
|
|
|
160
160
|
class TomoSimConfig(BaseModel):
|
|
@@ -186,19 +186,19 @@ class TomoSimConfig(BaseModel):
|
|
|
186
186
|
:type beam_intensity: float, optional
|
|
187
187
|
:ivar background_intensity: Background intensity in counts,
|
|
188
188
|
defaults to 20.
|
|
189
|
-
:type background_intensity
|
|
189
|
+
:type background_intensity: float, optional
|
|
190
190
|
:ivar slit_size: Vertical beam height in mm, defaults to 1.0.
|
|
191
|
-
:type slit_size
|
|
191
|
+
:type slit_size: float, optional
|
|
192
192
|
"""
|
|
193
193
|
station: Literal['id1a3', 'id3a', 'id3b']
|
|
194
|
-
detector: Detector.
|
|
194
|
+
detector: Detector.model_construct()
|
|
195
195
|
sample_type: Literal[
|
|
196
196
|
'square_rod', 'square_pipe', 'hollow_cube', 'hollow_brick',
|
|
197
197
|
'hollow_pyramid']
|
|
198
198
|
sample_size: conlist(
|
|
199
199
|
item_type=confloat(gt=0, allow_inf_nan=False),
|
|
200
|
-
|
|
201
|
-
wall_thickness: Optional[confloat(ge=0, allow_inf_nan=False)]
|
|
200
|
+
min_length=1, max_length=3)
|
|
201
|
+
wall_thickness: Optional[confloat(ge=0, allow_inf_nan=False)] = None
|
|
202
202
|
mu: Optional[confloat(gt=0, allow_inf_nan=False)] = 0.05
|
|
203
203
|
theta_step: confloat(gt=0, allow_inf_nan=False)
|
|
204
204
|
beam_intensity: Optional[confloat(gt=0, allow_inf_nan=False)] = 1.e9
|