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
tomwer/gui/cluster/slurm.py
CHANGED
@@ -28,13 +28,23 @@ __license__ = "MIT"
|
|
28
28
|
__date__ = "11/10/2021"
|
29
29
|
|
30
30
|
|
31
|
+
import logging
|
31
32
|
from typing import Optional
|
33
|
+
from functools import lru_cache as cache
|
32
34
|
|
33
35
|
from silx.gui import qt
|
34
|
-
from sluurp.utils import get_partitions
|
36
|
+
from sluurp.utils import get_partitions, get_partition_gpus
|
35
37
|
|
36
38
|
from tomwer.core.settings import SlurmSettings, SlurmSettingsMode
|
37
39
|
from tomwer.gui.utils.qt_utils import block_signals
|
40
|
+
from tomwer.gui.configuration.action import (
|
41
|
+
BasicConfigurationAction,
|
42
|
+
ExpertConfigurationAction,
|
43
|
+
)
|
44
|
+
from tomwer.gui.configuration.level import ConfigurationLevel
|
45
|
+
from nxtomomill.io.utils import convert_str_to_tuple
|
46
|
+
|
47
|
+
_logger = logging.getLogger(__name__)
|
38
48
|
|
39
49
|
|
40
50
|
class SlurmSettingsDialog(qt.QDialog):
|
@@ -58,10 +68,7 @@ class SlurmSettingsDialog(qt.QDialog):
|
|
58
68
|
self._buttons.button(qt.QDialogButtonBox.Close).clicked.connect(self.close)
|
59
69
|
|
60
70
|
# connect signal /slot
|
61
|
-
self._mainWidget.sigConfigChanged.connect(self.
|
62
|
-
|
63
|
-
def _configChanged(self, *args, **kwargs):
|
64
|
-
self.sigConfigChanged.emit()
|
71
|
+
self._mainWidget.sigConfigChanged.connect(self.sigConfigChanged)
|
65
72
|
|
66
73
|
def isSlurmActive(self):
|
67
74
|
return self._mainWidget.isSlurmActive()
|
@@ -84,6 +91,29 @@ class SlurmSettingsWindow(qt.QMainWindow):
|
|
84
91
|
|
85
92
|
def __init__(self, parent: Optional[qt.QWidget] = None) -> None:
|
86
93
|
super().__init__(parent)
|
94
|
+
|
95
|
+
# define toolbar
|
96
|
+
toolbar = qt.QToolBar(self)
|
97
|
+
self.addToolBar(qt.Qt.TopToolBarArea, toolbar)
|
98
|
+
|
99
|
+
self.__configurationModesAction = qt.QAction(self)
|
100
|
+
self.__configurationModesAction.setCheckable(False)
|
101
|
+
menu = qt.QMenu(self)
|
102
|
+
self.__configurationModesAction.setMenu(menu)
|
103
|
+
toolbar.addAction(self.__configurationModesAction)
|
104
|
+
|
105
|
+
self.__configurationModesGroup = qt.QActionGroup(self)
|
106
|
+
self.__configurationModesGroup.setExclusive(True)
|
107
|
+
self.__configurationModesGroup.triggered.connect(self._userModeChanged)
|
108
|
+
|
109
|
+
self._basicConfigAction = BasicConfigurationAction(toolbar)
|
110
|
+
menu.addAction(self._basicConfigAction)
|
111
|
+
self.__configurationModesGroup.addAction(self._basicConfigAction)
|
112
|
+
self._expertConfiguration = ExpertConfigurationAction(toolbar)
|
113
|
+
menu.addAction(self._expertConfiguration)
|
114
|
+
self.__configurationModesGroup.addAction(self._expertConfiguration)
|
115
|
+
|
116
|
+
# define maini widget
|
87
117
|
self._mainWidget = qt.QWidget(self)
|
88
118
|
self._mainWidget.setLayout(qt.QFormLayout())
|
89
119
|
|
@@ -92,13 +122,15 @@ class SlurmSettingsWindow(qt.QMainWindow):
|
|
92
122
|
self._modeCombox.addItems(SlurmSettingsMode.values())
|
93
123
|
self._modeCombox.setCurrentText(SlurmSettingsMode.GENERIC.value)
|
94
124
|
|
95
|
-
self._settingsWidget = SlurmSettingsWidget(self)
|
125
|
+
self._settingsWidget = SlurmSettingsWidget(self, jobLimitation=None)
|
96
126
|
self._mainWidget.layout().addRow(self._settingsWidget)
|
97
127
|
|
98
128
|
self.setCentralWidget(self._mainWidget)
|
99
129
|
|
100
130
|
# set up
|
101
131
|
self._reloadPredefinedSettings()
|
132
|
+
self._basicConfigAction.setChecked(True)
|
133
|
+
self._userModeChanged(self._basicConfigAction)
|
102
134
|
|
103
135
|
# connect signal / slot
|
104
136
|
self._modeCombox.currentIndexChanged.connect(self._reloadPredefinedSettings)
|
@@ -106,6 +138,17 @@ class SlurmSettingsWindow(qt.QMainWindow):
|
|
106
138
|
# when the settings widget is edited them we automatically move to 'manual' settings. To notify visually the user
|
107
139
|
self._settingsWidget.sigConfigChanged.connect(self._switchToManual)
|
108
140
|
|
141
|
+
def _userModeChanged(self, action):
|
142
|
+
self.__configurationModesAction.setIcon(action.icon())
|
143
|
+
self.__configurationModesAction.setToolTip(action.tooltip())
|
144
|
+
if action is self._basicConfigAction:
|
145
|
+
level = ConfigurationLevel.OPTIONAL
|
146
|
+
elif action is self._expertConfiguration:
|
147
|
+
level = ConfigurationLevel.ADVANCED
|
148
|
+
else:
|
149
|
+
raise NotImplementedError
|
150
|
+
self._settingsWidget.setConfigurationLevel(level)
|
151
|
+
|
109
152
|
def _reloadPredefinedSettings(self, *args, **kkwargs):
|
110
153
|
"""
|
111
154
|
reload settings from some predefined configuration
|
@@ -125,6 +168,7 @@ class SlurmSettingsWindow(qt.QMainWindow):
|
|
125
168
|
"job_name": settingsClass.PROJECT_NAME,
|
126
169
|
"walltime": settingsClass.DEFAULT_WALLTIME,
|
127
170
|
"python_venv": settingsClass.PYTHON_VENV,
|
171
|
+
"modules": settingsClass.MODULES_TO_LOAD,
|
128
172
|
}
|
129
173
|
)
|
130
174
|
|
@@ -179,13 +223,17 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
179
223
|
self._queue = qt.QComboBox(self)
|
180
224
|
self._queue.setEditable(True)
|
181
225
|
for partition in get_partitions():
|
226
|
+
if partition in ("nice*",):
|
227
|
+
# filter some node that we cannot access in fact
|
228
|
+
continue
|
182
229
|
self._queue.addItem(partition)
|
183
230
|
self.layout().addRow("queue / partition", self._queue)
|
184
231
|
|
185
232
|
# n workers
|
186
233
|
self._nWorkers = qt.QSpinBox(self)
|
187
234
|
self._nWorkers.setRange(1, 100)
|
188
|
-
self.
|
235
|
+
self._nWorkersLabel = qt.QLabel("number of task", self)
|
236
|
+
self.layout().addRow(self._nWorkersLabel, self._nWorkers)
|
189
237
|
|
190
238
|
# ncores active
|
191
239
|
self._nCores = qt.QSpinBox(self)
|
@@ -218,17 +266,34 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
218
266
|
self._wallTimeLabel = qt.QLabel("wall time", self)
|
219
267
|
self.layout().addRow(self._wallTimeLabel, self._wallTimeQLE)
|
220
268
|
|
221
|
-
# python exe
|
222
|
-
self.
|
223
|
-
self.
|
224
|
-
|
225
|
-
)
|
269
|
+
# python exe / modules
|
270
|
+
self._preProcessingGroup = qt.QGroupBox("pre-processing", self)
|
271
|
+
self._preProcessingGroup.setLayout(qt.QFormLayout())
|
272
|
+
self._preProcessingButtonGroup = qt.QButtonGroup(self)
|
273
|
+
self._preProcessingButtonGroup.setExclusive(True)
|
274
|
+
self.layout().addRow(self._preProcessingGroup)
|
275
|
+
|
276
|
+
# python venv
|
277
|
+
self._pythonVenv = qt.QLineEdit("/scisoft/tomotools/activate stable", self)
|
278
|
+
self._sourceScriptCB = qt.QRadioButton("source script (python venv)", self)
|
279
|
+
self._preProcessingButtonGroup.addButton(self._sourceScriptCB)
|
280
|
+
self._preProcessingGroup.layout().addRow(self._sourceScriptCB, self._pythonVenv)
|
226
281
|
self._pythonVenv.setToolTip(
|
227
282
|
"""
|
228
283
|
Optional path to a bash script to source before executing the script.
|
229
284
|
"""
|
230
285
|
)
|
231
286
|
|
287
|
+
self._modulesQLE = qt.QLineEdit(", ".join(SlurmSettings.MODULES_TO_LOAD), self)
|
288
|
+
self._modulesCB = qt.QRadioButton("module(s) to load", self)
|
289
|
+
self._preProcessingButtonGroup.addButton(self._modulesCB)
|
290
|
+
self._preProcessingGroup.layout().addRow(self._modulesCB, self._modulesQLE)
|
291
|
+
self._preProcessingGroup.setToolTip(
|
292
|
+
"""
|
293
|
+
Optional list of modules to load before executing the script. each module must be separated by a coma
|
294
|
+
"""
|
295
|
+
)
|
296
|
+
|
232
297
|
# job name
|
233
298
|
self._jobName = qt.QLineEdit("", self)
|
234
299
|
self._jobName.setToolTip(
|
@@ -257,6 +322,39 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
257
322
|
self._dashboardPortLabel = qt.QLabel("dashboard port", self)
|
258
323
|
self.layout().addRow(self._dashboardPortLabel, self._dashboardPort)
|
259
324
|
|
325
|
+
# sbatch advance parameters
|
326
|
+
self._sbatchAdvancedParameters = qt.QGroupBox("sbatch advanced settings", self)
|
327
|
+
self._sbatchAdvancedParameters.setLayout(qt.QFormLayout())
|
328
|
+
self.layout().addRow(self._sbatchAdvancedParameters)
|
329
|
+
|
330
|
+
## export parameter
|
331
|
+
self._exportValueCM = qt.QComboBox(self)
|
332
|
+
self._exportValueCM.addItems(("NONE", "ALL"))
|
333
|
+
self._exportValueCM.setItemData(
|
334
|
+
self._exportValueCM.findText("NONE"),
|
335
|
+
"""
|
336
|
+
Only SLURM_* variables from the user environment will be defined. User must use absolute path to the binary to be executed that will define the environment. User can not specify explicit environment variables with "NONE". However, Slurm will then implicitly attempt to load the user's environment on the node where the script is being executed, as if --get-user-env was specified. \nThis option is particularly important for jobs that are submitted on one cluster and execute on a different cluster (e.g. with different paths). To avoid steps inheriting environment export settings (e.g. "NONE") from sbatch command, the environment variable SLURM_EXPORT_ENV should be set to "ALL" in the job script.
|
337
|
+
""",
|
338
|
+
)
|
339
|
+
self._exportValueCM.setItemData(
|
340
|
+
self._exportValueCM.findText("ALL"),
|
341
|
+
"""
|
342
|
+
All of the user's environment will be loaded (either from the caller's environment or from a clean environment if --get-user-env is specified). \nCan fail when submitting cross-platform jobs and user has some module loaded
|
343
|
+
""",
|
344
|
+
)
|
345
|
+
self._exportValueCM.setCurrentText("NONE")
|
346
|
+
self._sbatchAdvancedParameters.layout().addRow("--export", self._exportValueCM)
|
347
|
+
|
348
|
+
## gpu card
|
349
|
+
self._gpuCardCB = qt.QComboBox(self)
|
350
|
+
self._gpuCardCB.setToolTip(
|
351
|
+
"Specify a GPU card to be used. Using the -C command from sbatch"
|
352
|
+
)
|
353
|
+
self._gpuCardCB.setEditable(
|
354
|
+
True
|
355
|
+
) # let the user the ability to provide a GPU that is not found for now (expecting he knows what he is doing)
|
356
|
+
self._sbatchAdvancedParameters.layout().addRow("-C (gpu card)", self._gpuCardCB)
|
357
|
+
|
260
358
|
# simplify gui
|
261
359
|
self._wallTimeLabel.hide()
|
262
360
|
self._wallTimeQLE.hide()
|
@@ -266,16 +364,23 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
266
364
|
self._job_nameQLabel.hide()
|
267
365
|
self._portLabel.hide() # for now we don't use the port. This can be done automatically
|
268
366
|
self._port.hide() # for now we don't use the port. This can be done automatically
|
367
|
+
# for now nworker == ntask is not used
|
368
|
+
self._nWorkers.setVisible(False)
|
369
|
+
self._nWorkersLabel.setVisible(False)
|
269
370
|
|
270
371
|
# set up the gui
|
271
372
|
self._nCores.setValue(SlurmSettings.N_CORES_PER_TASK)
|
272
373
|
self._nWorkers.setValue(SlurmSettings.N_TASKS)
|
273
374
|
self._memory.setValue(SlurmSettings.MEMORY_PER_WORKER)
|
274
|
-
self._queue.
|
375
|
+
if self._queue.findText(SlurmSettings.PARTITION) >= 0:
|
376
|
+
self._queue.setCurrentText(SlurmSettings.PARTITION)
|
275
377
|
self._nGpu.setValue(n_gpu)
|
276
378
|
self._jobName.setText(SlurmSettings.PROJECT_NAME)
|
277
379
|
self._wallTimeQLE.setText(SlurmSettings.DEFAULT_WALLTIME)
|
278
|
-
self.
|
380
|
+
self._modulesCB.setChecked(True) # by default we go for modules
|
381
|
+
self._preProcessingModeChanged()
|
382
|
+
self._partitionChanged()
|
383
|
+
self._nGpuChanged()
|
279
384
|
|
280
385
|
# connect signal / slot
|
281
386
|
self._nCores.valueChanged.connect(self._configurationChanged)
|
@@ -286,8 +391,20 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
286
391
|
self._jobName.editingFinished.connect(self._configurationChanged)
|
287
392
|
self._wallTimeQLE.editingFinished.connect(self._configurationChanged)
|
288
393
|
self._pythonVenv.editingFinished.connect(self._configurationChanged)
|
394
|
+
self._modulesQLE.editingFinished.connect(self._configurationChanged)
|
395
|
+
self._preProcessingButtonGroup.buttonClicked.connect(self._configurationChanged)
|
289
396
|
self._port.sigRangeChanged.connect(self._configurationChanged)
|
290
397
|
self._dashboardPort.valueChanged.connect(self._configurationChanged)
|
398
|
+
self._preProcessingButtonGroup.buttonClicked.connect(
|
399
|
+
self._preProcessingModeChanged
|
400
|
+
)
|
401
|
+
self._queue.currentTextChanged.connect(self._partitionChanged)
|
402
|
+
self._nGpu.valueChanged.connect(self._nGpuChanged)
|
403
|
+
self._gpuCardCB.currentTextChanged.connect(self._configurationChanged)
|
404
|
+
|
405
|
+
def _nGpuChanged(self, *args, **kwargs):
|
406
|
+
nGpu = self.getNGPU()
|
407
|
+
self._gpuCardCB.setEnabled(nGpu > 0)
|
291
408
|
|
292
409
|
def _configurationChanged(self, *args, **kwargs):
|
293
410
|
self.sigConfigChanged.emit()
|
@@ -341,64 +458,122 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
341
458
|
self._wallTimeQLE.setText(walltime)
|
342
459
|
|
343
460
|
def getPythonExe(self):
|
344
|
-
|
461
|
+
if self._sourceScriptCB.isChecked():
|
462
|
+
return self._pythonVenv.text()
|
463
|
+
else:
|
464
|
+
return None
|
345
465
|
|
346
466
|
def setPythonExe(self, python_venv):
|
347
467
|
self._pythonVenv.setText(python_venv)
|
468
|
+
if python_venv != "":
|
469
|
+
self._sourceScriptCB.setChecked(True)
|
470
|
+
|
471
|
+
def getModulesToLoad(self) -> tuple:
|
472
|
+
if self._modulesCB.isChecked():
|
473
|
+
return convert_str_to_tuple(self._modulesQLE.text())
|
474
|
+
else:
|
475
|
+
return tuple()
|
476
|
+
|
477
|
+
def setModulesToLoad(self, modules: tuple):
|
478
|
+
if not isinstance(modules, (tuple, list)):
|
479
|
+
raise TypeError(
|
480
|
+
f"modules is expected to be a tuple or a list. Get {type(modules)} instead"
|
481
|
+
)
|
482
|
+
self._modulesQLE.setText(str(modules))
|
483
|
+
if len(modules) > 0:
|
484
|
+
self._modulesCB.setChecked(True)
|
485
|
+
|
486
|
+
def getGpuCard(self) -> Optional[str]:
|
487
|
+
card = self._gpuCardCB.currentText()
|
488
|
+
if card == "any" or self._nGpu == 0:
|
489
|
+
return None
|
490
|
+
else:
|
491
|
+
return card
|
492
|
+
|
493
|
+
def getSBatchExtraParams(self):
|
494
|
+
return {
|
495
|
+
"export": self._exportValueCM.currentText(),
|
496
|
+
"gpu_card": self.getGpuCard(),
|
497
|
+
}
|
498
|
+
|
499
|
+
def setSBatchExtraParams(self, params: dict):
|
500
|
+
export_ = params.get("export", None)
|
501
|
+
if export_ is not None:
|
502
|
+
index = self._exportValueCM.findText(export_)
|
503
|
+
if index >= 0:
|
504
|
+
self._exportValueCM.setCurrentIndex(index)
|
505
|
+
gpu_card = params.get("gpu_card", None)
|
506
|
+
if gpu_card is not None:
|
507
|
+
index = self._gpuCardCB.findText("gpu_card")
|
508
|
+
if index >= 0:
|
509
|
+
self._gpuCardCB.setCurrentIndex(index)
|
510
|
+
else:
|
511
|
+
# policy when setting the extra params: if doesn't exists / found then won't set it.
|
512
|
+
# because they can be part of .ows, this parameter is hidden by default.
|
513
|
+
# so safer to use 'any' in the case it is unknown (debatable).
|
514
|
+
_logger.warning(f"unable to find gpu {gpu_card}. Won't set it")
|
348
515
|
|
349
516
|
def setConfiguration(self, config: dict) -> None:
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
517
|
+
with block_signals(self):
|
518
|
+
active_slurm = config.get("active_slurm", None)
|
519
|
+
if active_slurm is not None:
|
520
|
+
self._slurmCB.setChecked(active_slurm)
|
521
|
+
|
522
|
+
n_cores = config.get("cpu-per-task", None)
|
523
|
+
if n_cores is not None:
|
524
|
+
self.setNCores(n_cores)
|
525
|
+
|
526
|
+
n_workers = config.get("n_tasks", None)
|
527
|
+
if n_workers is not None:
|
528
|
+
self.setNWorkers(n_workers)
|
529
|
+
|
530
|
+
memory = config.get("memory", None)
|
531
|
+
if memory is not None:
|
532
|
+
if isinstance(memory, str):
|
533
|
+
memory = memory.replace(" ", "").lower().rstrip("gb")
|
534
|
+
self.setMemory(int(memory))
|
535
|
+
|
536
|
+
queue_ = config.get("partition", None)
|
537
|
+
if queue_ is not None:
|
538
|
+
queue_ = queue_.rstrip("'").rstrip('"')
|
539
|
+
queue_ = queue_.lstrip("'").lstrip('"')
|
540
|
+
self.setQueue(queue_)
|
541
|
+
|
542
|
+
n_gpu = config.get("n_gpus", None)
|
543
|
+
if n_gpu is not None:
|
544
|
+
self.setNGPU(int(n_gpu))
|
545
|
+
|
546
|
+
project_name = config.get("job_name", None)
|
547
|
+
if project_name is not None:
|
548
|
+
self.setProjectName(project_name)
|
549
|
+
|
550
|
+
wall_time = config.get("walltime", None)
|
551
|
+
if wall_time is not None:
|
552
|
+
self.setWallTime(wall_time)
|
553
|
+
|
554
|
+
python_venv = config.get("python_venv", None)
|
555
|
+
if python_venv is not None:
|
556
|
+
python_venv = python_venv.rstrip("'").rstrip('"')
|
557
|
+
python_venv = python_venv.lstrip("'").lstrip('"')
|
558
|
+
self.setPythonExe(python_venv)
|
559
|
+
|
560
|
+
modules = config.get("modules", None)
|
561
|
+
if modules is not None:
|
562
|
+
modules = convert_str_to_tuple(modules)
|
563
|
+
self.setModulesToLoad(modules)
|
564
|
+
|
565
|
+
sbatch_extra_params = config.get("sbatch_extra_params", {})
|
566
|
+
self.setSBatchExtraParams(sbatch_extra_params)
|
567
|
+
|
568
|
+
n_jobs = config.get("n_jobs", None)
|
569
|
+
if n_jobs is not None:
|
570
|
+
self.setNJobs(n_jobs)
|
571
|
+
self._preProcessingModeChanged() # make sure modules and python venv is enabled according to the activate mode
|
572
|
+
|
398
573
|
self.sigConfigChanged.emit()
|
399
574
|
|
400
575
|
def getConfiguration(self) -> dict:
|
401
|
-
|
576
|
+
config = {
|
402
577
|
"cpu-per-task": self.getNCores(),
|
403
578
|
"n_tasks": self.getNWorkers(),
|
404
579
|
"n_jobs": self.getNJobs(),
|
@@ -407,14 +582,48 @@ class SlurmSettingsWidget(qt.QWidget):
|
|
407
582
|
"n_gpus": self.getNGPU(),
|
408
583
|
"job_name": self.getProjectName(),
|
409
584
|
"walltime": self.getWallTime(),
|
410
|
-
"
|
585
|
+
"sbatch_extra_params": self.getSBatchExtraParams(),
|
411
586
|
}
|
587
|
+
if self._modulesCB.isChecked():
|
588
|
+
config["modules"] = self.getModulesToLoad()
|
589
|
+
elif self._sourceScriptCB.isChecked():
|
590
|
+
config["python_venv"] = self.getPythonExe()
|
591
|
+
else:
|
592
|
+
raise ValueError("'modules' or python environement should be enable")
|
593
|
+
return config
|
412
594
|
|
413
595
|
def getSlurmClusterConfiguration(self):
|
414
596
|
from tomwer.core.cluster import SlurmClusterConfiguration
|
415
597
|
|
416
598
|
return SlurmClusterConfiguration().from_dict(self.getConfiguration())
|
417
599
|
|
600
|
+
def _preProcessingModeChanged(self):
|
601
|
+
self._modulesQLE.setEnabled(self._modulesCB.isChecked())
|
602
|
+
self._pythonVenv.setEnabled(self._sourceScriptCB.isChecked())
|
603
|
+
|
604
|
+
def setConfigurationLevel(self, level: ConfigurationLevel):
|
605
|
+
self._sbatchAdvancedParameters.setVisible(level >= ConfigurationLevel.ADVANCED)
|
606
|
+
|
607
|
+
def _partitionChanged(self, *args, **kwargs):
|
608
|
+
partition = self.getQueue()
|
609
|
+
gpus = self._getGpus(partition=partition)
|
610
|
+
self._gpuCardCB.clear()
|
611
|
+
self._gpuCardCB.addItems(gpus)
|
612
|
+
self._gpuCardCB.setCurrentText("any")
|
613
|
+
|
614
|
+
@cache(maxsize=None)
|
615
|
+
def _getGpus(self, partition) -> tuple:
|
616
|
+
try:
|
617
|
+
gpus = get_partition_gpus(partition)
|
618
|
+
except Exception as e:
|
619
|
+
_logger.error(f"Failed to detect GPU on {partition}. Error is {e}")
|
620
|
+
gpus = ("any",)
|
621
|
+
else:
|
622
|
+
gpus = list(gpus) + [
|
623
|
+
"any",
|
624
|
+
]
|
625
|
+
return gpus
|
626
|
+
|
418
627
|
|
419
628
|
class _PortRangeSelection(qt.QWidget):
|
420
629
|
sigRangeChanged = qt.Signal()
|
tomwer/gui/cluster/supervisor.py
CHANGED
@@ -102,6 +102,7 @@ class FutureTomwerScanObserverWidget(qt.QWidget):
|
|
102
102
|
)
|
103
103
|
if future_tomo_obj is not None:
|
104
104
|
self.sigConversionRequested.emit(future_tomo_obj)
|
105
|
+
self.observationTable.model().updateIndices()
|
105
106
|
self.observationTable.model().layoutChanged.emit()
|
106
107
|
|
107
108
|
def _cancelSelected(self, *args, **kwargs):
|
@@ -123,6 +124,7 @@ class FutureTomwerScanObserverWidget(qt.QWidget):
|
|
123
124
|
self.observationTable.model().filtered_status = (
|
124
125
|
self.filterWidget.getFilteredStatus()
|
125
126
|
)
|
127
|
+
self.observationTable.model().endResetModel()
|
126
128
|
|
127
129
|
def updateView(self):
|
128
130
|
"""
|
@@ -265,6 +267,16 @@ class _DatasetProcessModel(qt.QAbstractTableModel):
|
|
265
267
|
del self._tomoObjStatus[future_tomo_obj]
|
266
268
|
self.layoutChanged.emit()
|
267
269
|
|
270
|
+
def updateIndices(self):
|
271
|
+
"""
|
272
|
+
Update tomo object indices when a tomo object has been removed (during a convertion for example)
|
273
|
+
"""
|
274
|
+
tomo_objs = list(self.futureTomoObjs.values())
|
275
|
+
self.futureTomoObjs.clear()
|
276
|
+
for i_tomo_obj, tomo_obj in enumerate(tomo_objs):
|
277
|
+
self.futureTomoObjs[i_tomo_obj] = tomo_obj
|
278
|
+
self._computeUnfilteredFutureTomoObjs()
|
279
|
+
|
268
280
|
def getUnfilteredFutureTomoObjs(self):
|
269
281
|
return self._filteredFutureTomoObjs
|
270
282
|
|
@@ -58,12 +58,16 @@ class TestSlurmWidget(TestCaseQt):
|
|
58
58
|
"cpu-per-task": SlurmSettings.N_CORES_PER_TASK,
|
59
59
|
"n_tasks": SlurmSettings.N_TASKS,
|
60
60
|
"memory": SlurmSettings.MEMORY_PER_WORKER,
|
61
|
-
"partition":
|
61
|
+
"partition": "",
|
62
62
|
"n_gpus": SlurmSettings.N_GPUS_PER_WORKER,
|
63
63
|
"job_name": "tomwer_{scan}_-_{process}_-_{info}",
|
64
64
|
"n_jobs": 1,
|
65
|
-
"
|
65
|
+
"modules": ("tomotools/stable",),
|
66
66
|
"walltime": "01:00:00",
|
67
|
+
"sbatch_extra_params": {
|
68
|
+
"export": "NONE",
|
69
|
+
"gpu_card": None,
|
70
|
+
},
|
67
71
|
}
|
68
72
|
assert dict_res == expected_dict, f"{dict_res} vs {expected_dict}"
|
69
73
|
|
@@ -75,6 +79,10 @@ class TestSlurmWidget(TestCaseQt):
|
|
75
79
|
"memory": 156,
|
76
80
|
"partition": "test-queue",
|
77
81
|
"n_gpus": 5,
|
82
|
+
"modules": "mymodule, mysecond/10.3",
|
83
|
+
"sbatch_extra_params": {
|
84
|
+
"export": "ALL",
|
85
|
+
},
|
78
86
|
}
|
79
87
|
)
|
80
88
|
|
@@ -83,6 +91,10 @@ class TestSlurmWidget(TestCaseQt):
|
|
83
91
|
assert self.slurmWidget.getMemory() == 156
|
84
92
|
assert self.slurmWidget.getQueue() == "test-queue"
|
85
93
|
assert self.slurmWidget.getNGPU() == 5
|
94
|
+
assert self.slurmWidget.getSBatchExtraParams() == {
|
95
|
+
"export": "ALL",
|
96
|
+
"gpu_card": None,
|
97
|
+
}
|
86
98
|
|
87
99
|
|
88
100
|
def test_SlurmSettingsWindow(qtapp): # noqa F811
|
@@ -36,7 +36,7 @@ from silx.gui import qt
|
|
36
36
|
from silx.gui.utils.testutils import TestCaseQt
|
37
37
|
|
38
38
|
from tomwer.core.futureobject import FutureTomwerObject
|
39
|
-
from tomwer.core.utils.scanutils import
|
39
|
+
from tomwer.core.utils.scanutils import MockNXtomo
|
40
40
|
from tomwer.gui.cluster.supervisor import FutureTomwerScanObserverWidget
|
41
41
|
|
42
42
|
|
@@ -52,12 +52,12 @@ class TestSupervisor(TestCaseQt):
|
|
52
52
|
self._future_tomo_objs = []
|
53
53
|
for i in range(5):
|
54
54
|
# create scan
|
55
|
-
scan =
|
55
|
+
scan = MockNXtomo(
|
56
56
|
scan_path=os.path.join(self.tempdir, f"scan_test{i}"),
|
57
57
|
n_proj=10,
|
58
58
|
n_ini_proj=10,
|
59
59
|
create_ini_dark=False,
|
60
|
-
|
60
|
+
create_ini_flat=False,
|
61
61
|
dim=10,
|
62
62
|
).scan
|
63
63
|
self._scans.append(scan)
|
File without changes
|
@@ -1,35 +1,4 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# /*##########################################################################
|
3
|
-
#
|
4
|
-
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
# of this software and associated documentation files (the "Software"), to deal
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
11
|
-
# furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
# THE SOFTWARE.
|
23
|
-
#
|
24
|
-
# ###########################################################################*/
|
25
|
-
|
26
|
-
__authors__ = ["H. Payno"]
|
27
|
-
__license__ = "MIT"
|
28
|
-
__date__ = "04/08/2020"
|
29
|
-
|
30
|
-
|
31
1
|
from silx.gui import qt
|
32
|
-
|
33
2
|
from tomwer.gui import icons as tomwer_icons
|
34
3
|
|
35
4
|
|
@@ -114,7 +83,7 @@ class FilterAction(qt.QAction):
|
|
114
83
|
qt.QAction.__init__(self, icon, "filter configuration", parent)
|
115
84
|
self.setToolTip(
|
116
85
|
"If activated will only display the configuration"
|
117
|
-
"for the active nabu
|
86
|
+
"for the active nabu step"
|
118
87
|
)
|
119
88
|
self.setCheckable(True)
|
120
89
|
self.setShortcut(qt.QKeySequence(qt.Qt.Key_F))
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from silx.utils.enum import Enum as _Enum
|
2
|
+
|
3
|
+
|
4
|
+
class ConfigurationLevel(_Enum):
|
5
|
+
REQUIRED = "required"
|
6
|
+
OPTIONAL = "optional"
|
7
|
+
ADVANCED = "advanced"
|
8
|
+
|
9
|
+
def _get_num_value(self) -> int:
|
10
|
+
if self is self.REQUIRED:
|
11
|
+
return 0
|
12
|
+
elif self is self.OPTIONAL:
|
13
|
+
return 1
|
14
|
+
elif self is self.ADVANCED:
|
15
|
+
return 2
|
16
|
+
|
17
|
+
def __le__(self, other):
|
18
|
+
if not isinstance(other, ConfigurationLevel):
|
19
|
+
raise TypeError(
|
20
|
+
f"other is expected to be an instance of ConfigurationLevel. {type(other)} provided"
|
21
|
+
)
|
22
|
+
return self._get_num_value() <= other._get_num_value()
|