tomwer 1.2.1__py3-none-any.whl → 1.3.12__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.
- orangecontrib/tomwer/tutorials/icat_publication.ows +58 -0
- orangecontrib/tomwer/widgets/__init__.py +11 -11
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +2 -2
- orangecontrib/tomwer/widgets/control/DataListOW.py +9 -7
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
- orangecontrib/tomwer/widgets/control/DataSelectorOW.py +21 -10
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
- orangecontrib/tomwer/widgets/control/EDF2NXTomomillOW.py +24 -7
- orangecontrib/tomwer/widgets/control/EmailOW.py +4 -4
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +64 -23
- orangecontrib/tomwer/widgets/control/NXtomoConcatenate.py +20 -8
- orangecontrib/tomwer/widgets/control/NotifierOW.py +1 -0
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
- orangecontrib/tomwer/widgets/control/VolumeSelector.py +7 -4
- orangecontrib/tomwer/widgets/control/VolumeSymLinkOW.py +182 -182
- orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +5 -5
- orangecontrib/tomwer/widgets/edit/DarkFlatPatchOW.py +4 -4
- orangecontrib/tomwer/widgets/edit/ImageKeyEditorOW.py +3 -3
- orangecontrib/tomwer/widgets/edit/ImageKeyUpgraderOW.py +8 -1
- orangecontrib/tomwer/widgets/edit/NXtomoEditorOW.py +3 -3
- orangecontrib/tomwer/widgets/edit/test/test_nxtomo_editor.py +3 -3
- orangecontrib/tomwer/widgets/icat/PublishProcessedDataOW.py +115 -0
- orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -0
- orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -0
- orangecontrib/tomwer/widgets/icat/__init__.py +13 -0
- orangecontrib/tomwer/widgets/icat/icons/add_gallery.png +0 -0
- orangecontrib/tomwer/widgets/icat/icons/add_gallery.svg +82 -0
- orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.png +0 -0
- orangecontrib/tomwer/widgets/icat/icons/publish_processed_data.svg +95 -0
- orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.png +0 -0
- orangecontrib/tomwer/widgets/icat/icons/raw_screenshots.svg +143 -0
- orangecontrib/tomwer/widgets/icons/tomwer_data_portal.png +0 -0
- orangecontrib/tomwer/widgets/icons/tomwer_data_portal.svg +76 -0
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +22 -20
- orangecontrib/tomwer/widgets/reconstruction/CastNabuVolumeOW.py +19 -3
- orangecontrib/tomwer/widgets/reconstruction/NabuHelicalPrepareWeightsDoubleOW.py +184 -169
- orangecontrib/tomwer/widgets/reconstruction/NabuOW.py +23 -0
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +39 -5
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +18 -22
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +18 -26
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +15 -19
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/LivesliceOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/NXtomoMetadataViewerOW.py +3 -3
- orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
- orangecontrib/tomwer/widgets/visualization/VolumeViewerOW.py +3 -29
- tomwer/__main__.py +7 -64
- tomwer/app/axis.py +3 -3
- tomwer/app/canvas.py +8 -0
- tomwer/app/canvas_launcher/config.py +16 -14
- tomwer/app/canvas_launcher/environ.py +1 -0
- tomwer/app/canvas_launcher/mainwindow.py +4 -1
- tomwer/app/darkref.py +1 -1
- tomwer/app/darkrefpatch.py +1 -1
- tomwer/app/diffframe.py +3 -3
- tomwer/app/imagekeyeditor.py +5 -5
- tomwer/app/imagekeyupgrader.py +5 -5
- tomwer/app/intensitynormalization.py +14 -13
- tomwer/app/{saaxis.py → multicor.py} +3 -3
- tomwer/app/{sadeltabeta.py → multipag.py} +3 -3
- tomwer/app/nabuapp.py +0 -11
- tomwer/app/radiostack.py +6 -4
- tomwer/app/samplemoved.py +3 -2
- tomwer/app/scanviewer.py +4 -2
- tomwer/app/sinogramviewer.py +3 -2
- tomwer/app/slicestack.py +3 -2
- tomwer/app/zstitching.py +88 -6
- tomwer/core/cluster/cluster.py +26 -0
- tomwer/core/log/logger.py +7 -5
- tomwer/core/process/conditions/filters.py +1 -1
- tomwer/core/process/control/datalistener/datalistener.py +19 -14
- tomwer/core/process/control/datawatcher/edfdwprocess.py +0 -9
- tomwer/core/process/control/nxtomoconcatenate.py +13 -13
- tomwer/core/process/control/nxtomomill.py +92 -34
- tomwer/core/process/control/scantransfer.py +20 -43
- tomwer/core/process/control/scanvalidator.py +3 -2
- tomwer/core/process/control/test/test_concatenate_nxtomos.py +9 -9
- tomwer/core/process/control/test/test_email.py +4 -4
- tomwer/core/process/control/test/test_h52nx_process.py +59 -7
- tomwer/core/process/control/test/test_volume_link.py +64 -64
- tomwer/core/process/control/timer.py +1 -1
- tomwer/core/process/control/volumesymlink.py +200 -200
- tomwer/core/process/edit/darkflatpatch.py +14 -15
- tomwer/core/process/edit/imagekeyeditor.py +41 -39
- tomwer/core/process/icat/__init__.py +0 -0
- tomwer/core/process/icat/createscreenshots.py +100 -0
- tomwer/core/process/icat/gallery.py +377 -0
- tomwer/core/process/icat/icatbase.py +36 -0
- tomwer/core/process/icat/publish.py +228 -0
- tomwer/core/process/icat/screenshots.py +27 -0
- tomwer/core/process/output.py +52 -0
- tomwer/core/process/reconstruction/axis/axis.py +280 -69
- tomwer/core/process/reconstruction/axis/mode.py +163 -48
- tomwer/core/process/reconstruction/axis/params.py +29 -21
- tomwer/core/process/reconstruction/darkref/darkrefs.py +41 -127
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +4 -3
- tomwer/core/process/reconstruction/darkref/params.py +1 -1
- tomwer/core/process/reconstruction/nabu/castvolume.py +4 -4
- tomwer/core/process/reconstruction/nabu/helical.py +9 -5
- tomwer/core/process/reconstruction/nabu/nabucommon.py +71 -78
- tomwer/core/process/reconstruction/nabu/nabuscores.py +425 -53
- tomwer/core/process/reconstruction/nabu/nabuslices.py +114 -93
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +54 -27
- tomwer/core/process/reconstruction/nabu/plane.py +9 -0
- tomwer/core/process/reconstruction/nabu/settings.py +2 -2
- tomwer/core/process/reconstruction/nabu/utils.py +164 -26
- tomwer/core/process/reconstruction/output.py +108 -0
- tomwer/core/process/reconstruction/saaxis/saaxis.py +238 -264
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +151 -87
- tomwer/core/process/reconstruction/scores/params.py +7 -4
- tomwer/core/process/reconstruction/scores/scores.py +13 -0
- tomwer/core/process/reconstruction/test/test_axis_params.py +2 -2
- tomwer/core/process/reconstruction/test/test_darkref.py +3 -3
- tomwer/core/process/reconstruction/test/test_darkref_copy.py +7 -7
- tomwer/core/process/reconstruction/test/test_saaxis.py +3 -4
- tomwer/core/process/reconstruction/test/test_sadeltabeta.py +2 -2
- tomwer/core/process/stitching/nabustitcher.py +13 -12
- tomwer/core/process/task.py +34 -26
- tomwer/core/process/test/test_axis.py +13 -12
- tomwer/core/process/test/test_dark_and_flat.py +10 -7
- tomwer/core/process/test/test_data_transfer.py +10 -8
- tomwer/core/process/test/test_nabu.py +14 -6
- tomwer/core/process/test/test_normalization.py +4 -4
- tomwer/core/scan/blissscan.py +3 -3
- tomwer/core/scan/edfscan.py +13 -10
- tomwer/core/scan/hdf5scan.py +19 -530
- tomwer/core/scan/nxtomoscan.py +534 -0
- tomwer/core/scan/scanbase.py +72 -44
- tomwer/core/scan/scanfactory.py +13 -13
- tomwer/core/scan/test/test_edf.py +2 -2
- tomwer/core/scan/test/test_future_scan.py +3 -3
- tomwer/core/scan/test/test_h5.py +18 -16
- tomwer/core/scan/test/test_process_registration.py +4 -40
- tomwer/core/scan/test/test_scan.py +5 -78
- tomwer/core/settings.py +22 -2
- tomwer/core/test/test_scanutils.py +8 -7
- tomwer/core/test/test_utils.py +35 -28
- tomwer/core/tomwer_object.py +1 -1
- tomwer/core/utils/__init__.py +0 -466
- tomwer/core/utils/deprecation.py +1 -1
- tomwer/core/utils/dictutils.py +14 -0
- tomwer/core/utils/lbsram.py +35 -0
- tomwer/core/utils/nxtomoutils.py +1 -1
- tomwer/core/utils/scanutils.py +6 -6
- tomwer/core/utils/spec.py +263 -0
- tomwer/core/volume/edfvolume.py +6 -6
- tomwer/core/volume/hdf5volume.py +6 -6
- tomwer/core/volume/jp2kvolume.py +6 -6
- tomwer/core/volume/rawvolume.py +6 -6
- tomwer/core/volume/tiffvolume.py +12 -12
- tomwer/core/volume/volumefactory.py +2 -2
- tomwer/gui/cluster/slurm.py +274 -65
- tomwer/gui/cluster/supervisor.py +12 -0
- tomwer/gui/cluster/test/test_cluster.py +14 -2
- tomwer/gui/cluster/test/test_supervisor.py +3 -3
- tomwer/gui/configuration/__init__.py +0 -0
- tomwer/gui/{reconstruction/nabu → configuration}/action.py +1 -32
- tomwer/gui/configuration/level.py +22 -0
- tomwer/gui/control/actions.py +54 -0
- tomwer/gui/control/datalist.py +83 -16
- tomwer/gui/control/datalistener.py +4 -16
- tomwer/gui/control/datawatcher/controlwidget.py +2 -4
- tomwer/gui/control/datawatcher/datawatcher.py +1 -24
- tomwer/gui/control/{email.py → emailnotifier.py} +9 -18
- tomwer/gui/control/history.py +2 -2
- tomwer/gui/control/observations.py +2 -2
- tomwer/gui/control/reducedarkflatselector.py +9 -9
- tomwer/gui/control/selectorwidgetbase.py +36 -9
- tomwer/gui/control/serie/seriecreator.py +5 -22
- tomwer/gui/control/test/test_email.py +1 -1
- tomwer/gui/control/test/test_scanvalidator.py +6 -5
- tomwer/gui/control/test/test_single_tomo_obj.py +3 -3
- tomwer/gui/control/tomoobjdisplaymode.py +8 -0
- tomwer/gui/debugtools/datasetgenerator.py +3 -3
- tomwer/gui/edit/dkrfpatch.py +20 -26
- tomwer/gui/edit/imagekeyeditor.py +11 -12
- tomwer/gui/edit/nxtomoeditor.py +111 -44
- tomwer/gui/edit/nxtomowarmer.py +7 -6
- tomwer/gui/edit/test/test_dkrf_patch.py +13 -13
- tomwer/gui/edit/test/test_image_key_editor.py +3 -3
- tomwer/gui/edit/test/test_nx_editor.py +40 -16
- tomwer/gui/icat/__init__.py +0 -0
- tomwer/gui/icat/createscreenshots.py +80 -0
- tomwer/gui/icat/gallery.py +214 -0
- tomwer/gui/icat/publish.py +187 -0
- tomwer/gui/imagefromfile.py +2 -2
- tomwer/gui/qfolderdialog.py +24 -1
- tomwer/gui/reconstruction/axis/CompareImages.py +88 -168
- tomwer/gui/reconstruction/axis/axis.py +171 -57
- tomwer/gui/reconstruction/axis/radioaxis.py +122 -257
- tomwer/gui/reconstruction/darkref/darkrefcopywidget.py +3 -2
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
- tomwer/gui/reconstruction/nabu/castvolume.py +14 -3
- tomwer/gui/reconstruction/nabu/check.py +9 -9
- tomwer/gui/reconstruction/nabu/helical.py +29 -12
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +2 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/output.py +126 -35
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +39 -32
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +222 -31
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +57 -27
- tomwer/gui/reconstruction/nabu/nabuflow.py +12 -20
- tomwer/gui/reconstruction/nabu/slices.py +10 -11
- tomwer/gui/reconstruction/nabu/volume.py +22 -10
- tomwer/gui/reconstruction/normalization/intensity.py +18 -48
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +8 -24
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +1 -1
- tomwer/gui/reconstruction/saaxis/saaxis.py +9 -21
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +45 -12
- tomwer/gui/reconstruction/scores/control.py +2 -9
- tomwer/gui/reconstruction/scores/scoreplot.py +13 -11
- tomwer/gui/reconstruction/test/test_axis.py +41 -16
- tomwer/gui/reconstruction/test/test_nabu.py +31 -9
- tomwer/gui/reconstruction/test/test_saaxis.py +3 -3
- tomwer/gui/reconstruction/test/test_sadeltabeta.py +12 -2
- tomwer/gui/settings.py +5 -28
- tomwer/gui/stackplot.py +2 -5
- tomwer/gui/stitching/action.py +49 -0
- tomwer/gui/stitching/config/axisparams.py +7 -24
- tomwer/gui/stitching/config/output.py +10 -8
- tomwer/gui/stitching/config/positionoveraxis.py +22 -23
- tomwer/gui/stitching/normalization.py +117 -0
- tomwer/gui/stitching/stitchandbackground.py +4 -6
- tomwer/gui/stitching/stitching.py +267 -45
- tomwer/gui/stitching/stitching_preview.py +62 -55
- tomwer/gui/stitching/stitching_raw.py +13 -12
- tomwer/gui/stitching/z_stitching/fineestimation.py +0 -60
- tomwer/gui/utils/buttons.py +112 -29
- tomwer/gui/utils/inputwidget.py +43 -25
- tomwer/gui/utils/lineselector/lineselector.py +1 -1
- tomwer/gui/utils/scandescription.py +4 -0
- tomwer/gui/utils/step.py +144 -0
- tomwer/gui/utils/unitsystem.py +2 -5
- tomwer/gui/utils/vignettes.py +176 -15
- tomwer/gui/visualization/dataviewer.py +48 -35
- tomwer/gui/visualization/diffviewer/diffviewer.py +7 -16
- tomwer/gui/visualization/diffviewer/shiftwidget.py +2 -5
- tomwer/gui/visualization/scanoverview.py +1 -1
- tomwer/gui/visualization/sinogramviewer.py +20 -36
- tomwer/gui/visualization/test/test_diffviewer.py +3 -3
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +4 -4
- tomwer/gui/visualization/test/test_sinogramviewer.py +2 -2
- tomwer/gui/visualization/test/test_stacks.py +3 -3
- tomwer/gui/visualization/test/test_volumeviewer.py +65 -67
- tomwer/gui/visualization/volumeviewer.py +114 -113
- tomwer/io/utils/h5pyutils.py +3 -3
- tomwer/io/utils/raw_and_processed_data.py +84 -0
- tomwer/io/utils/tomoobj.py +4 -6
- tomwer/io/utils/utils.py +7 -7
- tomwer/resources/gui/icons/parameters.svg +1 -1
- tomwer/resources/gui/icons/ruler.png +0 -0
- tomwer/resources/gui/icons/ruler.svg +273 -0
- tomwer/resources/gui/icons/short_description.png +0 -0
- tomwer/resources/gui/icons/short_description.svg +58 -0
- tomwer/resources/gui/icons/url.png +0 -0
- tomwer/resources/gui/icons/url.svg +58 -0
- tomwer/resources/gui/illustrations/no_rot.svg +1 -1
- tomwer/synctools/stacks/edit/darkflatpatch.py +19 -14
- tomwer/synctools/stacks/edit/imagekeyeditor.py +2 -2
- tomwer/synctools/stacks/reconstruction/axis.py +4 -4
- tomwer/synctools/stacks/reconstruction/castvolume.py +22 -7
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +25 -20
- tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
- tomwer/synctools/stacks/reconstruction/normalization.py +2 -2
- tomwer/synctools/stacks/reconstruction/saaxis.py +2 -2
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +2 -2
- tomwer/synctools/test/test_darkRefs.py +7 -58
- tomwer/synctools/test/test_foldertransfer.py +6 -6
- tomwer/synctools/utils/scanstages.py +6 -6
- tomwer/tests/conftest.py +34 -0
- tomwer/tests/datasets.py +13 -0
- tomwer/tests/test_scripts.py +91 -41
- tomwer/tests/utils.py +5 -0
- tomwer/third_part/WaitingOverlay.py +110 -0
- tomwer/third_part/__init__.py +0 -0
- tomwer/version.py +2 -2
- tomwer-1.3.12-py3.11-nspkg.pth +1 -0
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/METADATA +73 -58
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/RECORD +287 -286
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/WHEEL +1 -1
- orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
- orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
- orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
- orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
- tomwer/app/lamino.py +0 -143
- tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
- tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
- tomwer/core/process/test/test_lamino.py +0 -76
- tomwer/core/test/test_lamino.py +0 -92
- tomwer/gui/reconstruction/lamino/__init__.py +0 -31
- tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
- tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
- tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
- tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
- tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
- tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
- tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
- tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -760
- tomwer/gui/reconstruction/test/test_lamino.py +0 -189
- tomwer/resources/gui/icons/esrf_1.svg +0 -307
- tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
- tomwer/resources/gui/icons/triangle.svg +0 -80
- tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
- tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
- tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
- tomwer/resources/gui/illustrations/manual_slice.png +0 -0
- tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
- tomwer/resources/gui/illustrations/psi_angle.png +0 -0
- tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
- tomwer/resources/gui/illustrations/rotation_center.png +0 -0
- tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
- tomwer/resources/gui/illustrations/slice_stack.png +0 -0
- tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
- tomwer/resources/gui/illustrations/xy_slice.png +0 -0
- tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
- tomwer/resources/gui/illustrations/xz_slice.png +0 -0
- tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
- tomwer/resources/gui/illustrations/yz_slice.png +0 -0
- tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
- tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
- tomwer/synctools/test/test_scanstages.py +0 -162
- tomwer/tests/utils/__init__.py +0 -247
- tomwer/tests/utils/utilstest.py +0 -220
- tomwer-1.2.1-py3.11-nspkg.pth +0 -1
- /tomwer/core/process/control/{email.py → emailnotifier.py} +0 -0
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/LICENSE +0 -0
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/entry_points.txt +0 -0
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/namespace_packages.txt +0 -0
- {tomwer-1.2.1.dist-info → tomwer-1.3.12.dist-info}/top_level.txt +0 -0
@@ -32,27 +32,26 @@ __license__ = "MIT"
|
|
32
32
|
__date__ = "10/02/2021"
|
33
33
|
|
34
34
|
|
35
|
-
import copy
|
36
35
|
import logging
|
37
36
|
import os
|
38
37
|
from typing import Optional
|
39
38
|
|
40
39
|
import h5py
|
41
40
|
import numpy
|
41
|
+
from multiprocessing import Pool
|
42
42
|
from processview.core.manager import DatasetState, ProcessManager
|
43
43
|
from processview.core.superviseprocess import SuperviseProcess
|
44
44
|
from silx.io.url import DataUrl
|
45
|
-
from
|
45
|
+
from tomwer.core.utils.deprecation import deprecated_warning
|
46
46
|
|
47
47
|
from tomoscan.io import HDF5File
|
48
48
|
|
49
49
|
import tomwer.version
|
50
50
|
from tomwer.core.process.reconstruction.axis import AxisRP
|
51
51
|
from tomwer.core.process.reconstruction.nabu.nabuscores import (
|
52
|
-
|
52
|
+
run_nabu_multicor,
|
53
53
|
)
|
54
54
|
from tomwer.core.process.reconstruction.nabu.nabuslices import (
|
55
|
-
SingleSliceRunner,
|
56
55
|
interpret_tomwer_configuration,
|
57
56
|
)
|
58
57
|
from tomwer.core.process.reconstruction.scores import (
|
@@ -63,9 +62,7 @@ from tomwer.core.process.reconstruction.scores import (
|
|
63
62
|
)
|
64
63
|
from tomwer.core.process.reconstruction.scores.params import ScoreMethod
|
65
64
|
from tomwer.core.process.task import Task
|
66
|
-
from tomwer.core.
|
67
|
-
from tomwer.core.scan.edfscan import EDFTomoScan
|
68
|
-
from tomwer.core.scan.hdf5scan import HDF5TomoScan
|
65
|
+
from tomwer.core.scan.nxtomoscan import NXtomoScan
|
69
66
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
70
67
|
from tomwer.core.scan.scanfactory import ScanFactory
|
71
68
|
from tomwer.core.utils import logconfig
|
@@ -82,6 +79,11 @@ from tomwer.core.process.reconstruction.nabu.nabucommon import (
|
|
82
79
|
)
|
83
80
|
from tomwer.core.futureobject import FutureTomwerObject
|
84
81
|
from tomwer.core.process.reconstruction.saaxis.params import ReconstructionMode
|
82
|
+
from tomwer.core.process.reconstruction.nabu.utils import (
|
83
|
+
get_multi_cor_recons_volume_identifiers,
|
84
|
+
get_nabu_multicor_file_prefix,
|
85
|
+
)
|
86
|
+
from tomwer.core.process.reconstruction.nabu.nabuscores import _ReconstructorMultiCor
|
85
87
|
|
86
88
|
from ..nabu import utils
|
87
89
|
from .params import SAAxisParams
|
@@ -89,7 +91,7 @@ from .params import SAAxisParams
|
|
89
91
|
_logger = logging.getLogger(__name__)
|
90
92
|
|
91
93
|
|
92
|
-
DEFAULT_RECONS_FOLDER = "
|
94
|
+
DEFAULT_RECONS_FOLDER = "multi_cor_results"
|
93
95
|
|
94
96
|
|
95
97
|
def one_slice_several_cor(
|
@@ -139,6 +141,8 @@ class SAAxisTask(
|
|
139
141
|
"dump_roi",
|
140
142
|
"dump_process",
|
141
143
|
"serialize_output_data",
|
144
|
+
"compute_scores", # for GUI we want to post pone the score calculation
|
145
|
+
"pool_size",
|
142
146
|
),
|
143
147
|
):
|
144
148
|
"""
|
@@ -148,6 +152,8 @@ class SAAxisTask(
|
|
148
152
|
As the saaxis is integrating the score calculation we will never get a future_tomo_scan as output
|
149
153
|
"""
|
150
154
|
|
155
|
+
DEFAULT_POOL_SIZE = 10
|
156
|
+
|
151
157
|
def __init__(
|
152
158
|
self, process_id=None, inputs=None, varinfo=None, node_attrs=None, execinfo=None
|
153
159
|
):
|
@@ -214,7 +220,7 @@ class SAAxisTask(
|
|
214
220
|
return best_cor
|
215
221
|
|
216
222
|
def _config_preprocessing(
|
217
|
-
self, scan, config,
|
223
|
+
self, scan, config, file_format, output_dir, cluster_config
|
218
224
|
):
|
219
225
|
"""convert general configuration to nabu - single reconstruction - configuration"""
|
220
226
|
nabu_configurations = interpret_tomwer_configuration(config, scan=None)
|
@@ -232,17 +238,8 @@ class SAAxisTask(
|
|
232
238
|
# work on file name...
|
233
239
|
if output_dir is None:
|
234
240
|
output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
|
235
|
-
if scan.process_file is not None:
|
236
|
-
steps_file_basename, _ = os.path.splitext(scan.process_file)
|
237
|
-
steps_file_basename = "_".join(
|
238
|
-
("steps_file_basename", "nabu", "sinogram", "save", "step")
|
239
|
-
)
|
240
|
-
steps_file_basename = steps_file_basename + ".hdf5"
|
241
|
-
steps_file = os.path.join(output_dir, steps_file_basename)
|
242
|
-
else:
|
243
|
-
steps_file = ""
|
244
241
|
|
245
|
-
|
242
|
+
nabu_configuration = nabu_configurations[0][0]
|
246
243
|
if cluster_config == {}:
|
247
244
|
cluster_config = None
|
248
245
|
is_cluster_job = cluster_config is not None
|
@@ -250,98 +247,75 @@ class SAAxisTask(
|
|
250
247
|
raise ValueError(
|
251
248
|
"job on cluster requested but no access to slurm cluster found"
|
252
249
|
)
|
253
|
-
configs = {}
|
254
|
-
|
255
|
-
for i_cor, cor in enumerate(cor_positions):
|
256
|
-
nabu_configuration = copy.deepcopy(base_config)
|
257
|
-
nabu_configuration["pipeline"] = {
|
258
|
-
"save_steps": "sinogram" if i_cor == 0 else "",
|
259
|
-
"resume_from_step": "sinogram",
|
260
|
-
"steps_file": steps_file,
|
261
|
-
}
|
262
|
-
# convert cor from tomwer ref to nabu ref
|
263
|
-
if scan.dim_1 is not None:
|
264
|
-
cor_nabu_ref = cor + scan.dim_1 / 2.0
|
265
|
-
else:
|
266
|
-
_logger.warning("enable to get image half width. Set it to 1024")
|
267
|
-
cor_nabu_ref = cor + 1024
|
268
|
-
# handle reconstruction section
|
269
|
-
if "reconstruction" not in nabu_configuration:
|
270
|
-
nabu_configuration["reconstruction"] = {}
|
271
|
-
nabu_configuration["reconstruction"]["rotation_axis_position"] = str(
|
272
|
-
cor_nabu_ref
|
273
|
-
)
|
274
|
-
# handle output section
|
275
|
-
if "output" not in nabu_configuration:
|
276
|
-
nabu_configuration["output"] = {}
|
277
|
-
nabu_configuration["output"]["location"] = output_dir
|
278
|
-
nabu_configuration["output"]["file_format"] = file_format
|
279
|
-
# handle resources section
|
280
|
-
nabu_configuration["resources"] = utils.get_nabu_resources_desc(
|
281
|
-
scan=scan, workers=1, method="local"
|
282
|
-
)
|
283
|
-
configs[cor] = nabu_configuration
|
284
|
-
return configs
|
285
250
|
|
286
|
-
|
251
|
+
# handle reconstruction section
|
252
|
+
if "reconstruction" not in nabu_configuration:
|
253
|
+
nabu_configuration["reconstruction"] = {}
|
254
|
+
nabu_configuration["reconstruction"]["rotation_axis_position"] = ""
|
255
|
+
# handle output section
|
256
|
+
if "output" not in nabu_configuration:
|
257
|
+
nabu_configuration["output"] = {}
|
258
|
+
nabu_configuration["output"]["location"] = output_dir
|
259
|
+
nabu_configuration["output"]["file_format"] = file_format
|
260
|
+
# handle resources section
|
261
|
+
nabu_configuration["resources"] = utils.get_nabu_resources_desc(
|
262
|
+
scan=scan, workers=1, method="local"
|
263
|
+
)
|
264
|
+
return nabu_configuration
|
265
|
+
|
266
|
+
def _run_nabu_multicor(
|
287
267
|
self,
|
288
268
|
scan,
|
289
|
-
|
269
|
+
nabu_config,
|
270
|
+
cors,
|
290
271
|
slice_index,
|
291
272
|
file_format,
|
292
|
-
|
293
|
-
cluster_config,
|
273
|
+
cluster_config: Optional[dict],
|
294
274
|
dry_run=False,
|
295
275
|
):
|
296
|
-
|
297
|
-
|
276
|
+
if not (cluster_config is None or isinstance(cluster_config, dict)):
|
277
|
+
raise TypeError(
|
278
|
+
f"cluster_config is expected to be a dict. Get {type(cluster_config)} instead."
|
279
|
+
)
|
280
|
+
runner = run_nabu_multicor(
|
281
|
+
nabu_config=nabu_config,
|
298
282
|
scan=scan,
|
283
|
+
cors=cors,
|
299
284
|
slice_index=slice_index,
|
300
285
|
dry_run=dry_run,
|
301
286
|
file_format=file_format,
|
302
|
-
|
303
|
-
cluster_config=cluster_config.to_dict()
|
304
|
-
if cluster_config is not None
|
305
|
-
else None,
|
287
|
+
cluster_config=cluster_config if cluster_config is not None else None,
|
306
288
|
process_id=self.process_id,
|
307
289
|
instanciate_classes_only=True,
|
308
290
|
output_file_prefix_pattern="cor_{file_name}_{value}", # as the cor is evolving, create different files to make sure the name will be unique
|
309
291
|
)
|
310
292
|
|
311
|
-
|
312
|
-
|
313
|
-
recons_urls = {}
|
293
|
+
future_tomo_obj = None
|
294
|
+
recons_urls = dict()
|
314
295
|
std_outs = []
|
315
296
|
std_errs = []
|
316
297
|
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
future_tomo_obj = FutureTomwerObject(
|
339
|
-
tomo_obj=scan,
|
340
|
-
process_requester_id=self.process_id,
|
341
|
-
futures=res.future_slurm_jobs,
|
342
|
-
)
|
343
|
-
future_tomo_objs[cor] = future_tomo_obj
|
344
|
-
return success, recons_urls, future_tomo_objs, std_outs, std_errs
|
298
|
+
self._current_processing = runner
|
299
|
+
try:
|
300
|
+
result = runner.run()
|
301
|
+
except TimeoutError as e:
|
302
|
+
_logger.error(e)
|
303
|
+
else:
|
304
|
+
success = result.success
|
305
|
+
if isinstance(result, ResultsWithStd):
|
306
|
+
std_outs.append(result.std_out)
|
307
|
+
std_errs.append(result.std_err)
|
308
|
+
if isinstance(result, ResultsLocalRun):
|
309
|
+
recons_urls = {
|
310
|
+
cor: recons for cor, recons in zip(cors, result.results_identifiers)
|
311
|
+
}
|
312
|
+
if isinstance(result, ResultSlurmRun):
|
313
|
+
future_tomo_obj = FutureTomwerObject(
|
314
|
+
tomo_obj=scan,
|
315
|
+
process_requester_id=self.process_id,
|
316
|
+
futures=result.future_slurm_jobs,
|
317
|
+
)
|
318
|
+
return success, recons_urls, (future_tomo_obj,), std_outs, std_errs
|
345
319
|
|
346
320
|
def _resolve_futures(
|
347
321
|
self,
|
@@ -349,6 +323,7 @@ class SAAxisTask(
|
|
349
323
|
nabu_config,
|
350
324
|
slice_index,
|
351
325
|
file_format,
|
326
|
+
cors,
|
352
327
|
cor_reconstructions,
|
353
328
|
future_tomo_objs: dict,
|
354
329
|
output_dir,
|
@@ -359,54 +334,50 @@ class SAAxisTask(
|
|
359
334
|
if output_dir is None:
|
360
335
|
output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
|
361
336
|
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
if "phase" in nabu_config:
|
366
|
-
phase_method = nabu_config["phase"].get("method", "").lower()
|
367
|
-
if phase_method in ("pag", "paganin"):
|
368
|
-
pag = True
|
369
|
-
elif phase_method in ("ctf",):
|
370
|
-
ctf = True
|
371
|
-
if "delta_beta" in nabu_config["phase"]:
|
372
|
-
db = round(float(nabu_config["phase"]["delta_beta"]))
|
373
|
-
|
374
|
-
for cor, future_tomo_obj in future_tomo_objs.items():
|
337
|
+
file_prefix = get_nabu_multicor_file_prefix(scan)
|
338
|
+
|
339
|
+
for future_tomo_obj in future_tomo_objs:
|
375
340
|
if self._cancelled:
|
376
341
|
break
|
342
|
+
|
343
|
+
if future_tomo_obj is None:
|
344
|
+
continue
|
345
|
+
|
377
346
|
future_tomo_obj.results()
|
378
|
-
# for saaxis we need to retrieve reconstruction url
|
379
347
|
if future_tomo_obj.cancelled() or future_tomo_obj.exceptions():
|
380
348
|
continue
|
381
|
-
|
382
|
-
|
349
|
+
|
350
|
+
for cor in cors:
|
351
|
+
cor_nabu_ref = _ReconstructorMultiCor.convert_cor_from_rel_to_abs(
|
383
352
|
scan=scan,
|
384
|
-
|
385
|
-
pag=pag,
|
386
|
-
db=db,
|
387
|
-
ctf=ctf,
|
353
|
+
cor=cor,
|
388
354
|
)
|
389
|
-
|
390
|
-
|
391
|
-
recons_vol_id = utils.get_recons_volume_identifier(
|
355
|
+
volume_identifiers = get_multi_cor_recons_volume_identifiers(
|
392
356
|
scan=scan,
|
393
|
-
|
357
|
+
slice_index=slice_index,
|
358
|
+
location=nabu_config["output"]["location"],
|
394
359
|
file_prefix=file_prefix,
|
395
|
-
|
396
|
-
|
397
|
-
start_z=None,
|
398
|
-
end_z=None,
|
399
|
-
expects_single_slice=True,
|
360
|
+
file_format=file_format,
|
361
|
+
cors=(cor_nabu_ref,),
|
400
362
|
)
|
401
|
-
|
402
|
-
|
363
|
+
volume_identifier = volume_identifiers.get(cor_nabu_ref, None)
|
364
|
+
if volume_identifier is None:
|
365
|
+
_logger.warning(
|
366
|
+
f"failed to load volume for {cor}. Something went wrong on slurm submission job"
|
367
|
+
)
|
368
|
+
cor_reconstructions[cor] = volume_identifier
|
403
369
|
|
404
|
-
def _post_processing(self, scan, slice_index, cor_reconstructions):
|
370
|
+
def _post_processing(self, scan, slice_index, cor_reconstructions: dict):
|
405
371
|
"""
|
406
372
|
compute score along the different slices
|
373
|
+
|
374
|
+
:param dict cor_reconstructions: key is expected to be a float with the cor value and the value is expected to be a volume identifier (volume with a single frame)
|
407
375
|
"""
|
408
376
|
post_processing = _PostProcessing(
|
409
|
-
slice_index=slice_index,
|
377
|
+
slice_index=slice_index,
|
378
|
+
scan=scan,
|
379
|
+
cor_reconstructions=cor_reconstructions,
|
380
|
+
pool_size=self.get_input_value("pool_size", self.DEFAULT_POOL_SIZE),
|
410
381
|
)
|
411
382
|
post_processing._cancelled = self._cancelled
|
412
383
|
self._current_processing = post_processing
|
@@ -435,6 +406,16 @@ class SAAxisTask(
|
|
435
406
|
else:
|
436
407
|
return list(slice_index.values())[0]
|
437
408
|
|
409
|
+
def get_output_dir(self, params: SAAxisParams, scan: TomwerScanBase):
|
410
|
+
output_dir = params.output_dir or None
|
411
|
+
if output_dir is None:
|
412
|
+
output_dir = (
|
413
|
+
params.nabu_params.get("output", {}).get("location", None) or None
|
414
|
+
)
|
415
|
+
if output_dir is None:
|
416
|
+
output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
|
417
|
+
return output_dir
|
418
|
+
|
438
419
|
def run(self):
|
439
420
|
scan = data_identifier_to_scan(self.inputs.data)
|
440
421
|
if scan is None:
|
@@ -451,10 +432,10 @@ class SAAxisTask(
|
|
451
432
|
configuration = self.inputs.sa_axis_params
|
452
433
|
params = SAAxisParams.from_dict(configuration)
|
453
434
|
# insure output dir is created
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
435
|
+
params.output_dir = self.get_output_dir(params=params, scan=scan)
|
436
|
+
if not os.path.exists(params.output_dir):
|
437
|
+
os.makedirs(params.output_dir)
|
438
|
+
|
458
439
|
# try to find an estimated cor
|
459
440
|
# from a previously computed cor
|
460
441
|
if params.estimated_cor is None and scan.axis_params is not None:
|
@@ -480,9 +461,7 @@ class SAAxisTask(
|
|
480
461
|
if mode is not ReconstructionMode.VERTICAL:
|
481
462
|
raise ValueError(f"{mode} is not handled for now")
|
482
463
|
|
483
|
-
|
484
|
-
if output_dir is None:
|
485
|
-
output_dir = os.path.join(scan.path, DEFAULT_RECONS_FOLDER)
|
464
|
+
nabu_config = configuration.get("nabu_params", {})
|
486
465
|
nabu_output_config = configuration.get("output", {})
|
487
466
|
file_format = nabu_output_config.get("file_format", "hdf5")
|
488
467
|
slice_index = self._preprocess_slice_index(
|
@@ -493,18 +472,14 @@ class SAAxisTask(
|
|
493
472
|
dry_run = self._dry_run
|
494
473
|
|
495
474
|
# step one: complete nabu configuration(s)
|
496
|
-
|
475
|
+
nabu_config = self._config_preprocessing(
|
497
476
|
scan=scan,
|
498
|
-
config=
|
499
|
-
cor_positions=params.cors,
|
477
|
+
config=nabu_config,
|
500
478
|
file_format=file_format,
|
501
|
-
output_dir=output_dir,
|
479
|
+
output_dir=params.output_dir,
|
502
480
|
cluster_config=cluster_config,
|
503
481
|
)
|
504
482
|
# step 2: run reconstructions
|
505
|
-
advancement = Progress(
|
506
|
-
f"sa-axis - slice {slice_index} of {scan.get_identifier().short_description()}"
|
507
|
-
)
|
508
483
|
cors_res = {}
|
509
484
|
rois = {}
|
510
485
|
|
@@ -515,12 +490,12 @@ class SAAxisTask(
|
|
515
490
|
future_tomo_objs,
|
516
491
|
self._std_outs,
|
517
492
|
self._std_errs,
|
518
|
-
) = self.
|
493
|
+
) = self._run_nabu_multicor(
|
519
494
|
scan=scan,
|
520
|
-
|
495
|
+
nabu_config=nabu_config,
|
496
|
+
cors=tuple(params.cors),
|
521
497
|
slice_index=slice_index,
|
522
498
|
file_format=file_format,
|
523
|
-
advancement=advancement,
|
524
499
|
cluster_config=cluster_config,
|
525
500
|
dry_run=dry_run,
|
526
501
|
)
|
@@ -532,29 +507,37 @@ class SAAxisTask(
|
|
532
507
|
# step 3: wait for future if any
|
533
508
|
self._resolve_futures(
|
534
509
|
scan=scan,
|
535
|
-
nabu_config=
|
510
|
+
nabu_config=nabu_config,
|
536
511
|
slice_index=slice_index,
|
537
512
|
file_format=file_format,
|
538
513
|
cor_reconstructions=cor_reconstructions,
|
514
|
+
cors=tuple(params.cors),
|
539
515
|
future_tomo_objs=future_tomo_objs,
|
540
|
-
output_dir=output_dir,
|
516
|
+
output_dir=params.output_dir,
|
541
517
|
)
|
542
518
|
|
543
519
|
# step 4: run post processing (compute score for each slice)
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
520
|
+
if self.get_input_value("compute_scores", True):
|
521
|
+
try:
|
522
|
+
cors_res, rois = self._post_processing(
|
523
|
+
scan=scan,
|
524
|
+
slice_index=slice_index,
|
525
|
+
cor_reconstructions=cor_reconstructions,
|
526
|
+
)
|
527
|
+
except Exception as e:
|
528
|
+
_logger.error(e)
|
529
|
+
mess = (
|
530
|
+
f"sa-axis -post-processing- computation for {str(scan)} failed."
|
531
|
+
)
|
532
|
+
state = DatasetState.FAILED
|
533
|
+
cors_res = {}
|
534
|
+
else:
|
535
|
+
state = DatasetState.WAIT_USER_VALIDATION
|
536
|
+
mess = "sa-axis computation succeeded"
|
555
537
|
else:
|
556
|
-
|
557
|
-
|
538
|
+
cors_res = {}
|
539
|
+
state = DatasetState.FAILED
|
540
|
+
mess = "couldn't find 'compute_scores'"
|
558
541
|
|
559
542
|
if self._cancelled:
|
560
543
|
state = DatasetState.CANCELLED
|
@@ -671,7 +654,7 @@ class SAAxisTask(
|
|
671
654
|
def process_to_tomwer_processes(scan):
|
672
655
|
if scan.process_file is not None:
|
673
656
|
entry = "entry"
|
674
|
-
if isinstance(scan,
|
657
|
+
if isinstance(scan, NXtomoScan):
|
675
658
|
entry = scan.entry
|
676
659
|
|
677
660
|
cor = None
|
@@ -749,128 +732,119 @@ class SAAxisTask(
|
|
749
732
|
class _PostProcessing:
|
750
733
|
"""class used to run SA-axis post-processing on reconstructed slices"""
|
751
734
|
|
752
|
-
def __init__(self, cor_reconstructions, slice_index, scan) -> None:
|
735
|
+
def __init__(self, cor_reconstructions, slice_index, scan, pool_size) -> None:
|
753
736
|
self._cor_reconstructions = cor_reconstructions
|
754
737
|
self._slice_index = slice_index
|
755
738
|
self._scan = scan
|
756
739
|
self._cancelled = False
|
740
|
+
self.pool_size = pool_size
|
741
|
+
|
742
|
+
@staticmethod
|
743
|
+
def compute_score(item: tuple):
|
744
|
+
cor, (url, data), mask_disk_radius, cancelled = item
|
745
|
+
if cancelled:
|
746
|
+
return (None, None), None
|
747
|
+
|
748
|
+
if data is None:
|
749
|
+
score = None
|
750
|
+
data_roi = None
|
751
|
+
else:
|
752
|
+
if not isinstance(data, numpy.ndarray):
|
753
|
+
raise TypeError(
|
754
|
+
f"data should be a numpy array. Get {type(data)} instead"
|
755
|
+
)
|
756
|
+
assert data.ndim == 2, f"data should be 2D. Get {data.ndim} instead"
|
757
|
+
data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
|
758
|
+
|
759
|
+
# move data_roi to [0-1] range
|
760
|
+
# preprocessing: get percentile 0 and 99 from image and
|
761
|
+
# "clean" highest and lowest pixels from it
|
762
|
+
min_p, max_p = numpy.percentile(data_roi, (1, 99))
|
763
|
+
data_roi_int = data_roi[...]
|
764
|
+
data_roi_int[data_roi_int < min_p] = min_p
|
765
|
+
data_roi_int[data_roi_int > max_p] = max_p
|
766
|
+
data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
|
767
|
+
|
768
|
+
score = ComputedScore(
|
769
|
+
tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
|
770
|
+
std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
|
771
|
+
tomo_consistency=None,
|
772
|
+
)
|
773
|
+
return {cor: (url, score)}, {cor: data_roi}
|
757
774
|
|
758
775
|
def run(self):
|
759
776
|
datasets = self.load_datasets()
|
760
|
-
|
777
|
+
assert isinstance(datasets, dict)
|
761
778
|
mask_disk_radius = get_disk_mask_radius(datasets)
|
779
|
+
with Pool(self.pool_size) as pool:
|
780
|
+
res = pool.map(
|
781
|
+
self.compute_score,
|
782
|
+
[
|
783
|
+
(
|
784
|
+
*item,
|
785
|
+
mask_disk_radius,
|
786
|
+
self._cancelled,
|
787
|
+
)
|
788
|
+
for item in datasets.items()
|
789
|
+
],
|
790
|
+
)
|
762
791
|
scores = {}
|
763
792
|
rois = {}
|
764
|
-
for
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
if data is None:
|
769
|
-
score = None
|
770
|
-
else:
|
771
|
-
assert data.ndim == 2
|
772
|
-
data_roi = apply_roi(data=data, radius=mask_disk_radius, url=url)
|
773
|
-
rois[cor] = data_roi
|
774
|
-
|
775
|
-
# move data_roi to [0-1] range
|
776
|
-
# preprocessing: get percentile 0 and 99 from image and
|
777
|
-
# "clean" highest and lowest pixels from it
|
778
|
-
min_p, max_p = numpy.percentile(data_roi, (1, 99))
|
779
|
-
data_roi_int = data_roi[...]
|
780
|
-
data_roi_int[data_roi_int < min_p] = min_p
|
781
|
-
data_roi_int[data_roi_int > max_p] = max_p
|
782
|
-
data_roi_int = (data_roi_int - min_p) / (max_p - min_p)
|
783
|
-
|
784
|
-
if isinstance(self._scan, EDFTomoScan):
|
785
|
-
_logger.info("tomo consistency is not handled for EDF scan")
|
786
|
-
tomo_consistency_score = None
|
787
|
-
else:
|
788
|
-
try:
|
789
|
-
projections_with_angle = self._scan.projections_with_angle()
|
790
|
-
angles_ = [
|
791
|
-
frame_angle
|
792
|
-
for frame_angle, frame in projections_with_angle.items()
|
793
|
-
]
|
794
|
-
angles = []
|
795
|
-
for angle in angles_:
|
796
|
-
if not isinstance(angle, str):
|
797
|
-
angles.append(angle)
|
798
|
-
if self._slice_index == "middle":
|
799
|
-
if self._scan.dim_2 is not None:
|
800
|
-
self._slice_index = self._scan.dim_2 // 2
|
801
|
-
else:
|
802
|
-
_logger.warning(
|
803
|
-
"scan.dim_2 returns None, unable to deduce middle "
|
804
|
-
"pick 1024"
|
805
|
-
)
|
806
|
-
self._slice_index = 1024
|
807
|
-
tomo_consistency_score = compute_score(
|
808
|
-
data=data,
|
809
|
-
method=ScoreMethod.TOMO_CONSISTENCY,
|
810
|
-
angles=angles,
|
811
|
-
original_sinogram=self._scan.get_sinogram(
|
812
|
-
self._slice_index
|
813
|
-
),
|
814
|
-
detector_width=self._scan.dim_1,
|
815
|
-
original_axis_position=cor + self._scan.dim_1 / 2.0,
|
816
|
-
)
|
817
|
-
except Exception as e:
|
818
|
-
_logger.error(e)
|
819
|
-
tomo_consistency_score = None
|
820
|
-
score = ComputedScore(
|
821
|
-
tv=compute_score(data=data_roi_int, method=ScoreMethod.TV),
|
822
|
-
std=compute_score(data=data_roi_int, method=ScoreMethod.STD),
|
823
|
-
tomo_consistency=tomo_consistency_score,
|
824
|
-
)
|
825
|
-
scores[cor] = (url, score)
|
793
|
+
for mydict in res:
|
794
|
+
myscores, myrois = mydict
|
795
|
+
scores.update(myscores)
|
796
|
+
rois.update(myrois)
|
826
797
|
return scores, rois
|
827
798
|
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
volume = VolumeFactory.create_tomo_object_from_identifier(
|
840
|
-
volume_identifiers[0]
|
799
|
+
@staticmethod
|
800
|
+
def _load_dataset(item: tuple):
|
801
|
+
cor, volume_identifier = item
|
802
|
+
if volume_identifier is None:
|
803
|
+
return {cor: (None, None)}
|
804
|
+
|
805
|
+
volume = VolumeFactory.create_tomo_object_from_identifier(volume_identifier)
|
806
|
+
urls = tuple(volume.browse_data_urls())
|
807
|
+
if len(urls) == 0:
|
808
|
+
_logger.error(
|
809
|
+
f"volume {volume.get_identifier().to_str()} has no url / slices. Unable to load any data."
|
841
810
|
)
|
842
|
-
|
843
|
-
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
f"url is expected to be a str or DataUrl not {type(url)}"
|
851
|
-
)
|
811
|
+
return {cor: (None, None)}
|
812
|
+
if len(urls) != 1:
|
813
|
+
_logger.error(
|
814
|
+
f"volume is expected to have at most one url (single slice volume). get {len(urls)} - most likely nabu reconstruction failed. Do you have GPU ? Are the requested COR values valid ? - Especially for Half-acquisition"
|
815
|
+
)
|
816
|
+
url = urls[0]
|
817
|
+
if not isinstance(url, (DataUrl, str)):
|
818
|
+
raise TypeError(f"url is expected to be a str or DataUrl not {type(url)}")
|
852
819
|
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
elif data.shape[2] == 1:
|
865
|
-
data = data.reshape(data.shape[0], data.shape[1])
|
866
|
-
else:
|
867
|
-
raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
|
868
|
-
elif data.ndim == 2:
|
869
|
-
pass
|
820
|
+
try:
|
821
|
+
data = get_slice_data(url=url)
|
822
|
+
except Exception as e:
|
823
|
+
_logger.error(f"Fail to compute a score for {url.path()}. Reason is {e}")
|
824
|
+
return {cor: (url, None)}
|
825
|
+
else:
|
826
|
+
if data.ndim == 3:
|
827
|
+
if data.shape[0] == 1:
|
828
|
+
data = data.reshape(data.shape[1], data.shape[2])
|
829
|
+
elif data.shape[2] == 1:
|
830
|
+
data = data.reshape(data.shape[0], data.shape[1])
|
870
831
|
else:
|
871
|
-
raise ValueError("Data is expected to be 2D. Not {data.ndim}D")
|
832
|
+
raise ValueError(f"Data is expected to be 2D. Not {data.ndim}D")
|
833
|
+
elif data.ndim == 2:
|
834
|
+
pass
|
835
|
+
else:
|
836
|
+
raise ValueError("Data is expected to be 2D. Not {data.ndim}D")
|
837
|
+
return {cor: (url, data)}
|
872
838
|
|
873
|
-
|
839
|
+
def load_datasets(self):
|
840
|
+
with Pool(self.pool_size) as pool:
|
841
|
+
res = pool.map(
|
842
|
+
self._load_dataset,
|
843
|
+
self._cor_reconstructions.items(),
|
844
|
+
)
|
845
|
+
datasets_ = {}
|
846
|
+
for mydict in res:
|
847
|
+
datasets_.update(mydict)
|
874
848
|
return datasets_
|
875
849
|
|
876
850
|
def cancel(self):
|