python-microscopy 25.6.5__cp39-cp39-win_amd64.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.
- PYME/Acquire/ActionManager.py +450 -0
- PYME/Acquire/ExecTools.py +235 -0
- PYME/Acquire/Hardware/AAOptoelectronics/MDS.py +175 -0
- PYME/Acquire/Hardware/AAOptoelectronics/__init__.py +0 -0
- PYME/Acquire/Hardware/ARCoptix/__init__.py +0 -0
- PYME/Acquire/Hardware/ARCoptix/lcdriver.py +149 -0
- PYME/Acquire/Hardware/ARCoptix/lcserver32.py +123 -0
- PYME/Acquire/Hardware/AndorIXon/AndorCam.py +1095 -0
- PYME/Acquire/Hardware/AndorIXon/AndorControlFrame.py +312 -0
- PYME/Acquire/Hardware/AndorIXon/AndorIXon.py +737 -0
- PYME/Acquire/Hardware/AndorIXon/__init__.py +27 -0
- PYME/Acquire/Hardware/AndorNeo/AndorNeo.py +644 -0
- PYME/Acquire/Hardware/AndorNeo/AndorNeoControlFrame.py +161 -0
- PYME/Acquire/Hardware/AndorNeo/AndorZyla.py +761 -0
- PYME/Acquire/Hardware/AndorNeo/SDK3.py +307 -0
- PYME/Acquire/Hardware/AndorNeo/SDK3Cam.py +171 -0
- PYME/Acquire/Hardware/AndorNeo/ZylaControlPanel.py +105 -0
- PYME/Acquire/Hardware/AndorNeo/__init__.py +22 -0
- PYME/Acquire/Hardware/AndorNeo/parseAtdebug.py +46 -0
- PYME/Acquire/Hardware/AndorNeo/plotTimings.py +73 -0
- PYME/Acquire/Hardware/AndorNeo/testNeo.py +62 -0
- PYME/Acquire/Hardware/Camera.py +1199 -0
- PYME/Acquire/Hardware/CameraSkeleton.py +642 -0
- PYME/Acquire/Hardware/Coherent/OBIS.py +147 -0
- PYME/Acquire/Hardware/Coherent/Sapphire.py +162 -0
- PYME/Acquire/Hardware/Coherent/__init__.py +0 -0
- PYME/Acquire/Hardware/DMDGui.py +198 -0
- PYME/Acquire/Hardware/DigiData/DigiData.py +95 -0
- PYME/Acquire/Hardware/DigiData/DigiDataClient.py +30 -0
- PYME/Acquire/Hardware/DigiData/RemoteDigiData.py +51 -0
- PYME/Acquire/Hardware/DigiData/__init__.py +24 -0
- PYME/Acquire/Hardware/DigiData/axDD132x.py +348 -0
- PYME/Acquire/Hardware/EMCCDTheory.py +41 -0
- PYME/Acquire/Hardware/ExciterWheel.py +167 -0
- PYME/Acquire/Hardware/FilterWheel.py +184 -0
- PYME/Acquire/Hardware/FocCorr.py +106 -0
- PYME/Acquire/Hardware/FocCorrR.py +196 -0
- PYME/Acquire/Hardware/FrFilter.py +51 -0
- PYME/Acquire/Hardware/GCS/GCS_DLL.py +370 -0
- PYME/Acquire/Hardware/GCS/__init__.py +0 -0
- PYME/Acquire/Hardware/GCS/gcs.py +210 -0
- PYME/Acquire/Hardware/HamamatsuDCAM/HamamatsuDCAM.py +662 -0
- PYME/Acquire/Hardware/HamamatsuDCAM/HamamatsuORCA.py +602 -0
- PYME/Acquire/Hardware/HamamatsuDCAM/Hamamatsu_control_panel.py +54 -0
- PYME/Acquire/Hardware/HamamatsuDCAM/__init__.py +23 -0
- PYME/Acquire/Hardware/LaserControlFrame.py +160 -0
- PYME/Acquire/Hardware/MPBCommunications/MPBCW.py +132 -0
- PYME/Acquire/Hardware/MPBCommunications/__init__.py +0 -0
- PYME/Acquire/Hardware/Mercury/Mercury.py +269 -0
- PYME/Acquire/Hardware/Mercury/PI_Mercury_GCS_DLL.py +857 -0
- PYME/Acquire/Hardware/Mercury/__init__.py +22 -0
- PYME/Acquire/Hardware/Mercury/mercuryStepper.py +203 -0
- PYME/Acquire/Hardware/Mercury/mercuryStepperGCS.py +281 -0
- PYME/Acquire/Hardware/NikonTE2000.py +68 -0
- PYME/Acquire/Hardware/NikonTi.py +214 -0
- PYME/Acquire/Hardware/NikonTiGUI.py +81 -0
- PYME/Acquire/Hardware/OrielCornerstone.py +125 -0
- PYME/Acquire/Hardware/PM100USB.py +51 -0
- PYME/Acquire/Hardware/Piezos/__init__.py +22 -0
- PYME/Acquire/Hardware/Piezos/base_piezo.py +108 -0
- PYME/Acquire/Hardware/Piezos/offsetPiezo.py +162 -0
- PYME/Acquire/Hardware/Piezos/offsetPiezoREST.py +308 -0
- PYME/Acquire/Hardware/Piezos/piezo_c867.py +486 -0
- PYME/Acquire/Hardware/Piezos/piezo_e255.py +68 -0
- PYME/Acquire/Hardware/Piezos/piezo_e662.py +61 -0
- PYME/Acquire/Hardware/Piezos/piezo_e709.py +434 -0
- PYME/Acquire/Hardware/Piezos/piezo_e816.py +452 -0
- PYME/Acquire/Hardware/Piezos/piezo_e816_corr.py +70 -0
- PYME/Acquire/Hardware/Piezos/piezo_e816_dll.py +518 -0
- PYME/Acquire/Hardware/Piezos/piezo_e816b.py +70 -0
- PYME/Acquire/Hardware/Piezos/piezo_pipython_gcs.py +560 -0
- PYME/Acquire/Hardware/Piezos/piezo_test.py +55 -0
- PYME/Acquire/Hardware/Simulator/EmpiricalHist.py +273 -0
- PYME/Acquire/Hardware/Simulator/__init__.py +22 -0
- PYME/Acquire/Hardware/Simulator/dSimControl.py +961 -0
- PYME/Acquire/Hardware/Simulator/fakeCam.py +651 -0
- PYME/Acquire/Hardware/Simulator/fakePiezo.py +95 -0
- PYME/Acquire/Hardware/Simulator/fluor.py +336 -0
- PYME/Acquire/Hardware/Simulator/illuminate.cp39-win_amd64.dll.a +0 -0
- PYME/Acquire/Hardware/Simulator/illuminate.cp39-win_amd64.pyd +0 -0
- PYME/Acquire/Hardware/Simulator/illuminate.pyx +93 -0
- PYME/Acquire/Hardware/Simulator/lasersliders.py +90 -0
- PYME/Acquire/Hardware/Simulator/rend_im.py +446 -0
- PYME/Acquire/Hardware/Simulator/setup.py +69 -0
- PYME/Acquire/Hardware/Simulator/simcontrol.py +348 -0
- PYME/Acquire/Hardware/Simulator/simui_wx.py +794 -0
- PYME/Acquire/Hardware/Tango/__init__.py +0 -0
- PYME/Acquire/Hardware/Tango/marzhauser_tango.py +583 -0
- PYME/Acquire/Hardware/TiLightCrafter.py +388 -0
- PYME/Acquire/Hardware/__init__.py +22 -0
- PYME/Acquire/Hardware/aotf.py +271 -0
- PYME/Acquire/Hardware/arclampshutterpanel.py +71 -0
- PYME/Acquire/Hardware/cameraSoftwareBuffer.py +215 -0
- PYME/Acquire/Hardware/camera_noise.py +270 -0
- PYME/Acquire/Hardware/ccdAdjPanel.py +188 -0
- PYME/Acquire/Hardware/ccdCalibrator.py +161 -0
- PYME/Acquire/Hardware/cobaltLaser.py +108 -0
- PYME/Acquire/Hardware/cobaltLaser561.py +94 -0
- PYME/Acquire/Hardware/comports.py +26 -0
- PYME/Acquire/Hardware/driftTrackGUI.py +488 -0
- PYME/Acquire/Hardware/driftTracking.py +595 -0
- PYME/Acquire/Hardware/fakeShutters.py +52 -0
- PYME/Acquire/Hardware/focusKeys.py +204 -0
- PYME/Acquire/Hardware/focus_locks/__init__.py +0 -0
- PYME/Acquire/Hardware/focus_locks/reflection_focus_lock.py +684 -0
- PYME/Acquire/Hardware/frZStage.py +117 -0
- PYME/Acquire/Hardware/fw102.py +38 -0
- PYME/Acquire/Hardware/ids_peak_cam.py +561 -0
- PYME/Acquire/Hardware/ioslave.py +305 -0
- PYME/Acquire/Hardware/lasers.py +292 -0
- PYME/Acquire/Hardware/matchboxLaser.py +58 -0
- PYME/Acquire/Hardware/microscope_adapter.py +104 -0
- PYME/Acquire/Hardware/mpd_picosecond_delayer.py +395 -0
- PYME/Acquire/Hardware/multiview.py +287 -0
- PYME/Acquire/Hardware/olympusix81.py +59 -0
- PYME/Acquire/Hardware/pco/__init__.py +0 -0
- PYME/Acquire/Hardware/pco/pco_cam.py +348 -0
- PYME/Acquire/Hardware/pco/pco_edge_42_lt.py +34 -0
- PYME/Acquire/Hardware/pco/pco_sdk.py +1645 -0
- PYME/Acquire/Hardware/pco/pco_sdk_cam.py +518 -0
- PYME/Acquire/Hardware/pco/pco_sdk_cam_control_panel.py +54 -0
- PYME/Acquire/Hardware/phoxxLaser.py +199 -0
- PYME/Acquire/Hardware/phoxxLaserOLD.py +242 -0
- PYME/Acquire/Hardware/priorLumen.py +102 -0
- PYME/Acquire/Hardware/priorarclampshutter.py +52 -0
- PYME/Acquire/Hardware/setup.py +50 -0
- PYME/Acquire/Hardware/spacenav.py +148 -0
- PYME/Acquire/Hardware/splitter.py +394 -0
- PYME/Acquire/Hardware/thorlabsPiezo.py +98 -0
- PYME/Acquire/Hardware/thorlabs_cam.py +136 -0
- PYME/Acquire/Hardware/thorlabs_mff_flipper.py +400 -0
- PYME/Acquire/Hardware/toptica_ibeam.py +51 -0
- PYME/Acquire/Hardware/uc480/AndorControlFrame.py +308 -0
- PYME/Acquire/Hardware/uc480/__init__.py +27 -0
- PYME/Acquire/Hardware/uc480/uCam480.py +695 -0
- PYME/Acquire/Hardware/uc480/uc480.py +189 -0
- PYME/Acquire/Hardware/uc480/uc480Deprecated.py +87 -0
- PYME/Acquire/Hardware/uc480/uc480_h.py +767 -0
- PYME/Acquire/Hardware/uc480/uc480_h_gen.py +62 -0
- PYME/Acquire/Hardware/uc480/ucCamControlFrame.py +83 -0
- PYME/Acquire/Hardware/ueye.py +702 -0
- PYME/Acquire/PYMEAcquire.py +186 -0
- PYME/Acquire/Protocols/DMDMFM.py +74 -0
- PYME/Acquire/Protocols/__init__.py +22 -0
- PYME/Acquire/Protocols/darkCalibrate.py +56 -0
- PYME/Acquire/Protocols/dual671_470.py +45 -0
- PYME/Acquire/Protocols/dual671_488.py +46 -0
- PYME/Acquire/Protocols/gainCal.py +53 -0
- PYME/Acquire/Protocols/htsms-cal-psf.py +32 -0
- PYME/Acquire/Protocols/htsms-cal-registration.py +52 -0
- PYME/Acquire/Protocols/htsms-flow.py +29 -0
- PYME/Acquire/Protocols/htsms-staggered.py +31 -0
- PYME/Acquire/Protocols/htsms-tile.py +68 -0
- PYME/Acquire/Protocols/htsms-two-color.py +29 -0
- PYME/Acquire/Protocols/htsms-widefield.py +32 -0
- PYME/Acquire/Protocols/paint671.py +61 -0
- PYME/Acquire/Protocols/photoconversion.py +52 -0
- PYME/Acquire/Protocols/photoconversion2.py +55 -0
- PYME/Acquire/Protocols/prebleach488.py +70 -0
- PYME/Acquire/Protocols/prebleach490.py +69 -0
- PYME/Acquire/Protocols/prebleach561.py +72 -0
- PYME/Acquire/Protocols/prebleach561NeomEos2.py +70 -0
- PYME/Acquire/Protocols/prebleach561NeomEos2ND1.py +70 -0
- PYME/Acquire/Protocols/prebleach642.py +70 -0
- PYME/Acquire/Protocols/prebleach671.py +69 -0
- PYME/Acquire/Protocols/prebleach671ND1.py +58 -0
- PYME/Acquire/Protocols/prebleach671ND2.py +57 -0
- PYME/Acquire/Protocols/prebleach671Neo.py +69 -0
- PYME/Acquire/Protocols/recover671.py +62 -0
- PYME/Acquire/Protocols/sequence642_488.py +85 -0
- PYME/Acquire/Protocols/sequence642_561.py +87 -0
- PYME/Acquire/Protocols/shiftfield.py +198 -0
- PYME/Acquire/Protocols/simul488.py +59 -0
- PYME/Acquire/Protocols/simul642.py +63 -0
- PYME/Acquire/Protocols/simul642HTSMS.py +63 -0
- PYME/Acquire/Protocols/simulPA.py +37 -0
- PYME/Acquire/Protocols/simulSIM.py +76 -0
- PYME/Acquire/Protocols/simulStep.py +62 -0
- PYME/Acquire/Protocols/spdscan.py +178 -0
- PYME/Acquire/Protocols/standard470.py +45 -0
- PYME/Acquire/Protocols/standard488.py +47 -0
- PYME/Acquire/Protocols/standard671.py +48 -0
- PYME/Acquire/Protocols/standard671_no532.py +47 -0
- PYME/Acquire/Protocols/standardArclamp.py +46 -0
- PYME/Acquire/Protocols/strip_tile.py +204 -0
- PYME/Acquire/Protocols/tile.py +204 -0
- PYME/Acquire/Protocols/tile3D.py +192 -0
- PYME/Acquire/Protocols/tile671.py +190 -0
- PYME/Acquire/Protocols/tile_triggered.py +189 -0
- PYME/Acquire/Scripts/init.py +232 -0
- PYME/Acquire/Scripts/init_N1_Ti_Exeter_ZIx.py +374 -0
- PYME/Acquire/Scripts/init_N2_Ti_Zyla_lasers.py +290 -0
- PYME/Acquire/Scripts/init_Neo.py +266 -0
- PYME/Acquire/Scripts/init_NeoSim.py +159 -0
- PYME/Acquire/Scripts/init_TIRF.py +232 -0
- PYME/Acquire/Scripts/init_TIRF_Neo.py +242 -0
- PYME/Acquire/Scripts/init_TIRF_NeoO.py +241 -0
- PYME/Acquire/Scripts/init_TIRF_onecam.py +233 -0
- PYME/Acquire/Scripts/init_Ti.py +257 -0
- PYME/Acquire/Scripts/init_UOA_n.py +256 -0
- PYME/Acquire/Scripts/init_UOA_n2.py +246 -0
- PYME/Acquire/Scripts/init_Y1.py +249 -0
- PYME/Acquire/Scripts/init_Zyla.py +260 -0
- PYME/Acquire/Scripts/init_drift_tracking.py +80 -0
- PYME/Acquire/Scripts/init_emccd_basic.py +277 -0
- PYME/Acquire/Scripts/init_htsms.py +277 -0
- PYME/Acquire/Scripts/init_htsms_focus_lock.py +132 -0
- PYME/Acquire/Scripts/init_micrpi.py +45 -0
- PYME/Acquire/Scripts/init_orca.py +70 -0
- PYME/Acquire/Scripts/init_pco.py +49 -0
- PYME/Acquire/Scripts/init_rev.py +74 -0
- PYME/Acquire/Scripts/init_sim100.py +169 -0
- PYME/Acquire/Scripts/init_sim103.py +169 -0
- PYME/Acquire/Scripts/init_sim2.py +211 -0
- PYME/Acquire/Scripts/init_sim50.py +169 -0
- PYME/Acquire/Scripts/init_sim75.py +169 -0
- PYME/Acquire/Scripts/init_sim_drift_tracking.py +166 -0
- PYME/Acquire/Scripts/init_sim_htsms.py +224 -0
- PYME/Acquire/Scripts/init_sim_htsms_n.py +233 -0
- PYME/Acquire/Scripts/init_sim_main.py +229 -0
- PYME/Acquire/Scripts/init_sim_min.py +197 -0
- PYME/Acquire/Scripts/init_sim_rem.py +176 -0
- PYME/Acquire/Scripts/init_smi1.py +110 -0
- PYME/Acquire/Scripts/init_spectro.py +78 -0
- PYME/Acquire/Scripts/init_spim.py +116 -0
- PYME/Acquire/Scripts/init_thorcam.py +62 -0
- PYME/Acquire/Scripts/init_twophoton.py +112 -0
- PYME/Acquire/Scripts/init_uc480.py +262 -0
- PYME/Acquire/Scripts/init_ueye.py +261 -0
- PYME/Acquire/SpoolController.py +958 -0
- PYME/Acquire/Utils/MultiPointScanner.py +80 -0
- PYME/Acquire/Utils/__init__.py +13 -0
- PYME/Acquire/Utils/failsafe.py +157 -0
- PYME/Acquire/Utils/fastTiler.py +153 -0
- PYME/Acquire/Utils/pointScanner.py +496 -0
- PYME/Acquire/Utils/sarcSpacing.py +86 -0
- PYME/Acquire/Utils/strip_tiler.py +93 -0
- PYME/Acquire/Utils/tiler.py +464 -0
- PYME/Acquire/Utils/vibrationAnalysis.py +65 -0
- PYME/Acquire/__init__.py +44 -0
- PYME/Acquire/acquire_client.py +90 -0
- PYME/Acquire/acquire_server.py +316 -0
- PYME/Acquire/acquirebase.py +139 -0
- PYME/Acquire/acquiremainframe.py +716 -0
- PYME/Acquire/acquirewx.py +61 -0
- PYME/Acquire/acquisition_base.py +148 -0
- PYME/Acquire/actions.py +209 -0
- PYME/Acquire/autofocus.py +54 -0
- PYME/Acquire/eventLog.py +95 -0
- PYME/Acquire/event_loop.py +119 -0
- PYME/Acquire/frameWrangler.py +530 -0
- PYME/Acquire/htsms/__init__.py +8 -0
- PYME/Acquire/htsms/rule_ui.py +970 -0
- PYME/Acquire/htsms/rule_ui_v2.py +573 -0
- PYME/Acquire/htsms/tweeter.py +222 -0
- PYME/Acquire/microscope.py +1050 -0
- PYME/Acquire/positionTracker.py +181 -0
- PYME/Acquire/protocol.py +299 -0
- PYME/Acquire/protocol_acquisition.py +404 -0
- PYME/Acquire/sampleInformation.py +591 -0
- PYME/Acquire/sampleInformationDjangoDirect.py +446 -0
- PYME/Acquire/setup.py +52 -0
- PYME/Acquire/stackSettings.py +295 -0
- PYME/Acquire/stage_leveling.py +285 -0
- PYME/Acquire/ui/AnalysisSettingsUI.py +184 -0
- PYME/Acquire/ui/HDFSpoolFrame.py +584 -0
- PYME/Acquire/ui/__init__.py +0 -0
- PYME/Acquire/ui/actionUI.py +892 -0
- PYME/Acquire/ui/focus_lock_gui.py +149 -0
- PYME/Acquire/ui/intensity_trace.py +143 -0
- PYME/Acquire/ui/intsliders.py +222 -0
- PYME/Acquire/ui/lasersliders.py +329 -0
- PYME/Acquire/ui/mpd_picosecond_delay_panel.py +69 -0
- PYME/Acquire/ui/multiview_select.py +77 -0
- PYME/Acquire/ui/positionUI.py +519 -0
- PYME/Acquire/ui/preflight.py +58 -0
- PYME/Acquire/ui/scanner_panel.py +41 -0
- PYME/Acquire/ui/selectCameraPanel.py +46 -0
- PYME/Acquire/ui/seqdialog.py +501 -0
- PYME/Acquire/ui/splashScreen.py +175 -0
- PYME/Acquire/ui/spool_panel.py +830 -0
- PYME/Acquire/ui/tile_panel.py +556 -0
- PYME/Acquire/ui/tilesettingsui.py +91 -0
- PYME/Acquire/ui/voxelSizeDialog.py +149 -0
- PYME/Acquire/webui/__init__.py +36 -0
- PYME/Acquire/webui/ipy.py +361 -0
- PYME/Acquire/webui/static/css/pyme-bootstrap.css +9908 -0
- PYME/Acquire/webui/static/css/pymeacquire.css +85 -0
- PYME/Acquire/webui/static/js/pymeacquire.js +375 -0
- PYME/Acquire/webui/static/js/pzf.js +95 -0
- PYME/Acquire/webui/templates/PYMEAcquire.html +232 -0
- PYME/Acquire/webui/templates/login.html +84 -0
- PYME/Acquire/webui/templates/xtermpage.html +106 -0
- PYME/Acquire/xyztc.py +418 -0
- PYME/Acquire/zScanner.py +287 -0
- PYME/Analysis/BleachProfile/__init__.py +26 -0
- PYME/Analysis/BleachProfile/deMod.py +91 -0
- PYME/Analysis/BleachProfile/fitRecover.py +90 -0
- PYME/Analysis/BleachProfile/intensProf.py +519 -0
- PYME/Analysis/BleachProfile/kinModels.py +507 -0
- PYME/Analysis/BleachProfile/rawIntensity.py +227 -0
- PYME/Analysis/BleachProfile/rollins.py +555 -0
- PYME/Analysis/Colocalisation/__init__.py +27 -0
- PYME/Analysis/Colocalisation/colocScaleDep.py +126 -0
- PYME/Analysis/Colocalisation/correlationCoeffs.py +198 -0
- PYME/Analysis/Colocalisation/distColoc.py +110 -0
- PYME/Analysis/Colocalisation/edtColoc.py +191 -0
- PYME/Analysis/MetaData.py +278 -0
- PYME/Analysis/PSFEst/__init__.py +27 -0
- PYME/Analysis/PSFEst/dec.py +283 -0
- PYME/Analysis/PSFEst/extractImages.py +316 -0
- PYME/Analysis/PSFEst/fit_psf_zernikes.py +194 -0
- PYME/Analysis/PSFEst/psfQuality.py +225 -0
- PYME/Analysis/PSFGen/__init__.py +40 -0
- PYME/Analysis/PSFGen/fourier.py +138 -0
- PYME/Analysis/PSFGen/fourierHNA.py +1108 -0
- PYME/Analysis/PSFGen/fourierHNA2.py +979 -0
- PYME/Analysis/PSFGen/genCRBcurves.py +185 -0
- PYME/Analysis/PSFGen/nijboer_zernike.py +79 -0
- PYME/Analysis/PSFGen/ps_app.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/PSFGen/ps_app.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/PSFGen/test_ps_app.py +24 -0
- PYME/Analysis/Tracking/__init__.py +3 -0
- PYME/Analysis/Tracking/msd.py +57 -0
- PYME/Analysis/Tracking/trackUtils.py +528 -0
- PYME/Analysis/Tracking/tracking.py +152 -0
- PYME/Analysis/__init__.py +30 -0
- PYME/Analysis/_fithelpers.py +161 -0
- PYME/Analysis/angleFilter.py +287 -0
- PYME/Analysis/annealThresh.py +157 -0
- PYME/Analysis/autoencoder_classifier.py +45 -0
- PYME/Analysis/binAvg.py +144 -0
- PYME/Analysis/composite.py +183 -0
- PYME/Analysis/cramerRao.py +259 -0
- PYME/Analysis/deTile.py +441 -0
- PYME/Analysis/density_filter.py +45 -0
- PYME/Analysis/distributed_pyramid.py +426 -0
- PYME/Analysis/fiducial_matching.py +220 -0
- PYME/Analysis/gen_sCMOS_maps.py +355 -0
- PYME/Analysis/graphing_filters.py +311 -0
- PYME/Analysis/implicitFilter.py +359 -0
- PYME/Analysis/keep_pairs.py +69 -0
- PYME/Analysis/optic_flow.py +108 -0
- PYME/Analysis/piecewise.py +36 -0
- PYME/Analysis/piecewiseMapping.py +304 -0
- PYME/Analysis/piezo_movement_correction.py +153 -0
- PYME/Analysis/points/DeClump/__init__.py +78 -0
- PYME/Analysis/points/DeClump/deClump.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/DeClump/deClump.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/DeClump/deClumpGUI.py +87 -0
- PYME/Analysis/points/DeClump/pyDeClump.py +284 -0
- PYME/Analysis/points/DeClump/testClump.py +40 -0
- PYME/Analysis/points/DistHist/__init__.py +25 -0
- PYME/Analysis/points/DistHist/distHist.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/DistHist/distHist.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/DistHist/distHistThreaded.py +71 -0
- PYME/Analysis/points/DistHist/setup.py +54 -0
- PYME/Analysis/points/EdgeDB/__init__.py +24 -0
- PYME/Analysis/points/EdgeDB/edgeDB.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/EdgeDB/edgeDB.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/EdgeDB/edgeTest.py +66 -0
- PYME/Analysis/points/EdgeDB/edges.py +102 -0
- PYME/Analysis/points/EdgeDB/segment.py +75 -0
- PYME/Analysis/points/EdgeDB/setup.py +54 -0
- PYME/Analysis/points/QuadTree/QTrend.py +232 -0
- PYME/Analysis/points/QuadTree/__init__.py +25 -0
- PYME/Analysis/points/QuadTree/pointQT.py +227 -0
- PYME/Analysis/points/QuadTree/pointQTF.py +254 -0
- PYME/Analysis/points/QuadTree/qtUtils.py +36 -0
- PYME/Analysis/points/QuadTree/rendQT.py +118 -0
- PYME/Analysis/points/SoftRend/__init__.py +24 -0
- PYME/Analysis/points/SoftRend/setup.py +61 -0
- PYME/Analysis/points/SoftRend/testTetrahedra.py +41 -0
- PYME/Analysis/points/SoftRend/triRend.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/SoftRend/triRend.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/__init__.py +3 -0
- PYME/Analysis/points/arcfit/__init__.py +1 -0
- PYME/Analysis/points/arcfit/arcmf.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/arcfit/arcmf.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/arcfit/setup.py +51 -0
- PYME/Analysis/points/astigmatism/__init__.py +0 -0
- PYME/Analysis/points/astigmatism/astigTools.py +338 -0
- PYME/Analysis/points/astigmatism/astiglookup.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/astigmatism/astiglookup.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/astigmatism/setup.py +54 -0
- PYME/Analysis/points/cluster_morphology.py +199 -0
- PYME/Analysis/points/coordinate_tools.py +278 -0
- PYME/Analysis/points/features/__init__.py +0 -0
- PYME/Analysis/points/features/metal.py +46 -0
- PYME/Analysis/points/features/shaders/vect_feat_3d.metal +49 -0
- PYME/Analysis/points/fiducials.py +142 -0
- PYME/Analysis/points/gen3DTriangs.py +796 -0
- PYME/Analysis/points/moments.py +143 -0
- PYME/Analysis/points/multiview.py +458 -0
- PYME/Analysis/points/objectMeasure.py +206 -0
- PYME/Analysis/points/qpaint.py +97 -0
- PYME/Analysis/points/rings.py +372 -0
- PYME/Analysis/points/ripleys.py +427 -0
- PYME/Analysis/points/segmentLL.py +134 -0
- PYME/Analysis/points/setup.py +56 -0
- PYME/Analysis/points/spherical_harmonics.py +909 -0
- PYME/Analysis/points/surfit.py +829 -0
- PYME/Analysis/points/tCluster.py +75 -0
- PYME/Analysis/points/traveling_salesperson/__init__.py +0 -0
- PYME/Analysis/points/traveling_salesperson/queue_opt.py +117 -0
- PYME/Analysis/points/traveling_salesperson/sectioned_two_opt.py +327 -0
- PYME/Analysis/points/traveling_salesperson/setup.py +40 -0
- PYME/Analysis/points/traveling_salesperson/sort.py +78 -0
- PYME/Analysis/points/traveling_salesperson/two_opt.py +189 -0
- PYME/Analysis/points/traveling_salesperson/two_opt_utils.cp39-win_amd64.dll.a +0 -0
- PYME/Analysis/points/traveling_salesperson/two_opt_utils.cp39-win_amd64.pyd +0 -0
- PYME/Analysis/points/traveling_salesperson/two_opt_utils.pyx +41 -0
- PYME/Analysis/points/twoColour.py +572 -0
- PYME/Analysis/points/twoColourPlot.py +107 -0
- PYME/Analysis/processLogger.py +129 -0
- PYME/Analysis/profile_extraction.py +72 -0
- PYME/Analysis/setup.py +60 -0
- PYME/Analysis/splitting.py +372 -0
- PYME/Analysis/svmSegment.py +214 -0
- PYME/Analysis/thresholding.py +192 -0
- PYME/Analysis/tile_pyramid.py +938 -0
- PYME/Analysis/widefieldify.py +54 -0
- PYME/DSView/DisplayOptionsPanel.py +503 -0
- PYME/DSView/LUT/__init__.py +33 -0
- PYME/DSView/LUT/lut.cp39-win_amd64.dll.a +0 -0
- PYME/DSView/LUT/lut.cp39-win_amd64.pyd +0 -0
- PYME/DSView/LUT/setup.py +54 -0
- PYME/DSView/OpenSequenceDialog.py +83 -0
- PYME/DSView/OverlaysPanel.py +111 -0
- PYME/DSView/__init__.py +32 -0
- PYME/DSView/arrayViewPanel.py +1035 -0
- PYME/DSView/displayOptions.py +453 -0
- PYME/DSView/displaySettingsPanel.py +271 -0
- PYME/DSView/dsviewer.py +542 -0
- PYME/DSView/eventLogViewer.py +805 -0
- PYME/DSView/fitInfo.py +486 -0
- PYME/DSView/htmlServe.py +72 -0
- PYME/DSView/logparser.py +100 -0
- PYME/DSView/modules/LMAnalysis.py +1053 -0
- PYME/DSView/modules/LMDisplay.py +194 -0
- PYME/DSView/modules/__init__.py +162 -0
- PYME/DSView/modules/_base.py +39 -0
- PYME/DSView/modules/annotation.py +725 -0
- PYME/DSView/modules/arrayView.py +71 -0
- PYME/DSView/modules/blobFinding.py +455 -0
- PYME/DSView/modules/blobMeasure.py +1093 -0
- PYME/DSView/modules/camera_maps.py +38 -0
- PYME/DSView/modules/coloc.py +414 -0
- PYME/DSView/modules/composite.py +715 -0
- PYME/DSView/modules/convnet.py +24 -0
- PYME/DSView/modules/cropping.py +133 -0
- PYME/DSView/modules/dark_and_flatfield.py +31 -0
- PYME/DSView/modules/deconvolution.py +499 -0
- PYME/DSView/modules/eventView.py +80 -0
- PYME/DSView/modules/extractBlobs.py +46 -0
- PYME/DSView/modules/fastGraphPanel.py +85 -0
- PYME/DSView/modules/filtering.py +335 -0
- PYME/DSView/modules/flowView.py +268 -0
- PYME/DSView/modules/fourierRingCorrelation.py +172 -0
- PYME/DSView/modules/gl_image_view.py +12 -0
- PYME/DSView/modules/graphViewPanel.py +272 -0
- PYME/DSView/modules/measure/__init__.py +1 -0
- PYME/DSView/modules/measure/filterPan.py +239 -0
- PYME/DSView/modules/metadataView.py +28 -0
- PYME/DSView/modules/multithreshold.py +98 -0
- PYME/DSView/modules/neuroglancer.py +129 -0
- PYME/DSView/modules/object_tagging.py +157 -0
- PYME/DSView/modules/particleTracking.py +463 -0
- PYME/DSView/modules/playback.py +256 -0
- PYME/DSView/modules/prebleachExtraction.py +75 -0
- PYME/DSView/modules/profileFitting.py +137 -0
- PYME/DSView/modules/profilePlotting.py +408 -0
- PYME/DSView/modules/projections.py +48 -0
- PYME/DSView/modules/psfExtraction.py +570 -0
- PYME/DSView/modules/psfGeneration.py +138 -0
- PYME/DSView/modules/psfTools.py +661 -0
- PYME/DSView/modules/pupilTools.py +204 -0
- PYME/DSView/modules/pupilView.py +139 -0
- PYME/DSView/modules/recipes.py +266 -0
- PYME/DSView/modules/redimension.py +75 -0
- PYME/DSView/modules/segmentation.py +192 -0
- PYME/DSView/modules/sheetView.py +24 -0
- PYME/DSView/modules/shell.py +39 -0
- PYME/DSView/modules/shiftfield_estimation.py +433 -0
- PYME/DSView/modules/sparkprepare.py +94 -0
- PYME/DSView/modules/splitter.py +148 -0
- PYME/DSView/modules/synchronise.py +64 -0
- PYME/DSView/modules/templates/astigCal.html +42 -0
- PYME/DSView/modules/templates/measureView.html +69 -0
- PYME/DSView/modules/templates/measureView2.html +48 -0
- PYME/DSView/modules/templates/measureView3.html +98 -0
- PYME/DSView/modules/templates/trackView.html +139 -0
- PYME/DSView/modules/templates/tracksOverview.html +21 -0
- PYME/DSView/modules/tiling.py +147 -0
- PYME/DSView/modules/unmixing.py +148 -0
- PYME/DSView/modules/vis3D.py +320 -0
- PYME/DSView/modules/visgui.py +163 -0
- PYME/DSView/modules/webview.py +14 -0
- PYME/DSView/overlays.py +295 -0
- PYME/DSView/scrolledImagePanel.py +188 -0
- PYME/DSView/setup.py +53 -0
- PYME/DSView/splashScreen.py +158 -0
- PYME/DSView/voxSizeDialog.py +84 -0
- PYME/Deconv/__init__.py +35 -0
- PYME/Deconv/beadGen.py +55 -0
- PYME/Deconv/dec.py +659 -0
- PYME/Deconv/decTask.py +65 -0
- PYME/Deconv/decThread.py +113 -0
- PYME/Deconv/dec_test.py +47 -0
- PYME/Deconv/deconvDialogs.py +417 -0
- PYME/Deconv/fftwWisdom.py +62 -0
- PYME/Deconv/richardsonLucy.py +141 -0
- PYME/Deconv/richardsonLucyMV.py +151 -0
- PYME/Deconv/richardsonLucyMVM.py +218 -0
- PYME/Deconv/test_block_dec.py +46 -0
- PYME/Deconv/tq_block_dec.py +331 -0
- PYME/Deconv/wiener.py +163 -0
- PYME/IO/DataSources/AlignDataSource.py +91 -0
- PYME/IO/DataSources/ArrayDataSource.py +260 -0
- PYME/IO/DataSources/BGSDataSource.py +353 -0
- PYME/IO/DataSources/BaseDataSource.py +457 -0
- PYME/IO/DataSources/BioformatsDataSource.py +178 -0
- PYME/IO/DataSources/BufferedDataSource.py +99 -0
- PYME/IO/DataSources/ClusterPZFDataSource.py +124 -0
- PYME/IO/DataSources/ConcatenatedDataSource.py +56 -0
- PYME/IO/DataSources/CropDataSource.py +243 -0
- PYME/IO/DataSources/DcimgDataSource.py +54 -0
- PYME/IO/DataSources/ElectronsPerSecondDataSource.py +61 -0
- PYME/IO/DataSources/FlatFieldDataSource.py +77 -0
- PYME/IO/DataSources/HDFDataSource.py +160 -0
- PYME/IO/DataSources/HTTPDataSource.py +80 -0
- PYME/IO/DataSources/ImageSeriesDataSource.py +123 -0
- PYME/IO/DataSources/MultiviewDataSource.py +99 -0
- PYME/IO/DataSources/OBFDataSource.py +67 -0
- PYME/IO/DataSources/RandomDataSource.py +23 -0
- PYME/IO/DataSources/SupertileDatasource.py +148 -0
- PYME/IO/DataSources/TQDataSource.py +41 -0
- PYME/IO/DataSources/TiffDataSource.py +193 -0
- PYME/IO/DataSources/TileDataSource.py +91 -0
- PYME/IO/DataSources/UnsplitDataSource.py +92 -0
- PYME/IO/DataSources/__init__.py +59 -0
- PYME/IO/FileUtils/IJLut.py +43 -0
- PYME/IO/FileUtils/RawToHdf5.py +105 -0
- PYME/IO/FileUtils/SPAD.py +54 -0
- PYME/IO/FileUtils/TiffSeqToHdf5.py +87 -0
- PYME/IO/FileUtils/__init__.py +24 -0
- PYME/IO/FileUtils/compHdf.py +39 -0
- PYME/IO/FileUtils/fileID.py +246 -0
- PYME/IO/FileUtils/fnlGen.py +40 -0
- PYME/IO/FileUtils/freeSpace.py +59 -0
- PYME/IO/FileUtils/h5-thumbnailer.py +85 -0
- PYME/IO/FileUtils/h5ExFrames.py +98 -0
- PYME/IO/FileUtils/h5ToTiffSeries.py +50 -0
- PYME/IO/FileUtils/h5r-thumbnailer.py +118 -0
- PYME/IO/FileUtils/h5rFormatDef.py +99 -0
- PYME/IO/FileUtils/h5rToTxt.py +77 -0
- PYME/IO/FileUtils/nameUtils.py +300 -0
- PYME/IO/FileUtils/obf_support.py +538 -0
- PYME/IO/FileUtils/ply.py +147 -0
- PYME/IO/FileUtils/readSpeckle.py +78 -0
- PYME/IO/FileUtils/readTiff.py +64 -0
- PYME/IO/FileUtils/saveTiffStack.py +137 -0
- PYME/IO/FileUtils/setup.py +36 -0
- PYME/IO/FileUtils/sf-thumbnailer.py +76 -0
- PYME/IO/FileUtils/stl.py +44 -0
- PYME/IO/FileUtils/thumbnailDatabase.py +104 -0
- PYME/IO/HTTPSpooler_v2.py +141 -0
- PYME/IO/MetaDataHandler.py +1072 -0
- PYME/IO/PZFFormat.py +375 -0
- PYME/IO/Spooler.py +279 -0
- PYME/IO/__init__.py +12 -0
- PYME/IO/acquisition_backends.py +353 -0
- PYME/IO/buffer_helpers.cp39-win_amd64.dll.a +0 -0
- PYME/IO/buffer_helpers.cp39-win_amd64.pyd +0 -0
- PYME/IO/buffer_helpers.pyx +190 -0
- PYME/IO/buffers.py +291 -0
- PYME/IO/clusterDuplication.py +204 -0
- PYME/IO/clusterExport.py +152 -0
- PYME/IO/clusterGlob.py +108 -0
- PYME/IO/clusterIO.py +1076 -0
- PYME/IO/clusterListing.py +232 -0
- PYME/IO/clusterResults.py +206 -0
- PYME/IO/clusterUpload.py +49 -0
- PYME/IO/cluster_directory.py +419 -0
- PYME/IO/cluster_streaming.py +216 -0
- PYME/IO/compatibility.py +12 -0
- PYME/IO/countdir/__init__.py +5 -0
- PYME/IO/countdir/setup.py +58 -0
- PYME/IO/csv_flavours.py +251 -0
- PYME/IO/dataExporter.py +470 -0
- PYME/IO/dataWrap.py +108 -0
- PYME/IO/dcimg.py +167 -0
- PYME/IO/events.py +161 -0
- PYME/IO/h5File.py +148 -0
- PYME/IO/h5rFile.py +323 -0
- PYME/IO/image.py +1447 -0
- PYME/IO/load_psf.py +26 -0
- PYME/IO/pyme_h5ls.py +58 -0
- PYME/IO/ragged.py +138 -0
- PYME/IO/rgb_image.py +94 -0
- PYME/IO/tabular.py +1338 -0
- PYME/IO/testClusterSpooling.py +199 -0
- PYME/IO/unifiedIO.py +301 -0
- PYME/LMVis/Extras/QPobjectSegment.py +220 -0
- PYME/LMVis/Extras/__init__.py +55 -0
- PYME/LMVis/Extras/animation.py +359 -0
- PYME/LMVis/Extras/annotation.py +78 -0
- PYME/LMVis/Extras/clusterAnalysis.py +460 -0
- PYME/LMVis/Extras/dockedPanel.py +69 -0
- PYME/LMVis/Extras/extra_layers.py +373 -0
- PYME/LMVis/Extras/fiducial.py +230 -0
- PYME/LMVis/Extras/flagZMotionArtifacts.py +60 -0
- PYME/LMVis/Extras/fusionUtils.py +9 -0
- PYME/LMVis/Extras/multiColourAnalysis.py +103 -0
- PYME/LMVis/Extras/multiviewMapping.py +489 -0
- PYME/LMVis/Extras/objectMeasurements.py +246 -0
- PYME/LMVis/Extras/particleTracking.py +272 -0
- PYME/LMVis/Extras/perFrameVariable.py +77 -0
- PYME/LMVis/Extras/photophysics.py +72 -0
- PYME/LMVis/Extras/pointSetGeneration.py +232 -0
- PYME/LMVis/Extras/pointwiseColoc.py +54 -0
- PYME/LMVis/Extras/saved_views.py +125 -0
- PYME/LMVis/Extras/scaleBox.py +115 -0
- PYME/LMVis/Extras/sequentialSpecies.py +125 -0
- PYME/LMVis/Extras/setBGImage.py +74 -0
- PYME/LMVis/Extras/shiftmapGenerator.py +138 -0
- PYME/LMVis/Extras/showShortcuts.py +69 -0
- PYME/LMVis/Extras/snapshot.py +135 -0
- PYME/LMVis/Extras/spherical_harmonics.py +98 -0
- PYME/LMVis/Extras/subsets.py +15 -0
- PYME/LMVis/Extras/surface_fitting.py +52 -0
- PYME/LMVis/Extras/temperaturePlot.py +53 -0
- PYME/LMVis/Extras/vibration.py +112 -0
- PYME/LMVis/VisGUI.py +506 -0
- PYME/LMVis/__init__.py +39 -0
- PYME/LMVis/colourFilterGUI.py +77 -0
- PYME/LMVis/colourPanel.py +491 -0
- PYME/LMVis/displayPane.py +462 -0
- PYME/LMVis/dyeRatios.py +116 -0
- PYME/LMVis/genImageDialog.py +298 -0
- PYME/LMVis/gl_offScreenHandler.py +134 -0
- PYME/LMVis/gl_render.py +1302 -0
- PYME/LMVis/gl_render3D.py +1453 -0
- PYME/LMVis/gl_render3D_shaders.py +1213 -0
- PYME/LMVis/glcanvas_core.py +1157 -0
- PYME/LMVis/imageView.py +752 -0
- PYME/LMVis/imageView2.py +372 -0
- PYME/LMVis/importTextDialog.py +342 -0
- PYME/LMVis/layer_panel.py +231 -0
- PYME/LMVis/layers/AxesOverlayLayer.py +126 -0
- PYME/LMVis/layers/LUTOverlayLayer.py +346 -0
- PYME/LMVis/layers/OverlayLayer.py +46 -0
- PYME/LMVis/layers/ScaleBarOverlayLayer.py +97 -0
- PYME/LMVis/layers/ScaleBoxOverlayLayer.py +181 -0
- PYME/LMVis/layers/SelectionOverlayLayer.py +124 -0
- PYME/LMVis/layers/__init__.py +53 -0
- PYME/LMVis/layers/base.py +319 -0
- PYME/LMVis/layers/image_layer.py +363 -0
- PYME/LMVis/layers/labels.py +186 -0
- PYME/LMVis/layers/layer_defaults.py +97 -0
- PYME/LMVis/layers/mesh.py +378 -0
- PYME/LMVis/layers/octree.py +194 -0
- PYME/LMVis/layers/pointcloud.py +372 -0
- PYME/LMVis/layers/quiver.py +271 -0
- PYME/LMVis/layers/text.py +250 -0
- PYME/LMVis/layers/tracks.py +309 -0
- PYME/LMVis/mv_math.py +78 -0
- PYME/LMVis/objectDarkMeasure.py +120 -0
- PYME/LMVis/pipeline.py +1227 -0
- PYME/LMVis/pipelineView.py +115 -0
- PYME/LMVis/pointSettingsPanel.py +135 -0
- PYME/LMVis/progGraph.py +59 -0
- PYME/LMVis/quadTreeSettings.py +90 -0
- PYME/LMVis/rendGauss.py +158 -0
- PYME/LMVis/renderers.py +576 -0
- PYME/LMVis/sessionpaths.py +136 -0
- PYME/LMVis/setup.py +39 -0
- PYME/LMVis/setup_exe.py +71 -0
- PYME/LMVis/shader_programs/DefaultShaderProgram.py +149 -0
- PYME/LMVis/shader_programs/GLProgram.py +119 -0
- PYME/LMVis/shader_programs/GouraudShaderProgram.py +157 -0
- PYME/LMVis/shader_programs/PointSpriteShaderProgram.py +163 -0
- PYME/LMVis/shader_programs/ShaderProgramFactory.py +54 -0
- PYME/LMVis/shader_programs/TesselShaderProgram.py +47 -0
- PYME/LMVis/shader_programs/WireFrameShaderProgram.py +50 -0
- PYME/LMVis/shader_programs/__init__.py +20 -0
- PYME/LMVis/shader_programs/oit_compositor.py +23 -0
- PYME/LMVis/shader_programs/shader_loader.py +84 -0
- PYME/LMVis/shader_programs/shader_program.py +168 -0
- PYME/LMVis/shader_programs/shaders/bigflatpoints_fs.glsl +16 -0
- PYME/LMVis/shader_programs/shaders/bigpoints_gs.glsl +40 -0
- PYME/LMVis/shader_programs/shaders/bigpointsprites_fs.glsl +20 -0
- PYME/LMVis/shader_programs/shaders/bigspheres_fs.glsl +53 -0
- PYME/LMVis/shader_programs/shaders/compose_fs.glsl +41 -0
- PYME/LMVis/shader_programs/shaders/compose_vs.glsl +25 -0
- PYME/LMVis/shader_programs/shaders/default_fs.glsl +27 -0
- PYME/LMVis/shader_programs/shaders/default_vs.glsl +88 -0
- PYME/LMVis/shader_programs/shaders/flatpoints_fs.glsl +27 -0
- PYME/LMVis/shader_programs/shaders/gouraud_flatpoints_fs.glsl +30 -0
- PYME/LMVis/shader_programs/shaders/gouraud_fs.glsl +26 -0
- PYME/LMVis/shader_programs/shaders/gouraud_oit_fs.glsl +68 -0
- PYME/LMVis/shader_programs/shaders/gouraud_vs.glsl +135 -0
- PYME/LMVis/shader_programs/shaders/image_fs.glsl +60 -0
- PYME/LMVis/shader_programs/shaders/image_vs.glsl +79 -0
- PYME/LMVis/shader_programs/shaders/phong_fs.glsl +43 -0
- PYME/LMVis/shader_programs/shaders/phong_vs.glsl +45 -0
- PYME/LMVis/shader_programs/shaders/pointsprites_fs.glsl +33 -0
- PYME/LMVis/shader_programs/shaders/pointsprites_vs.glsl +77 -0
- PYME/LMVis/shader_programs/shaders/spheres_fs.glsl +102 -0
- PYME/LMVis/shader_programs/shaders/tessel_fs.glsl +23 -0
- PYME/LMVis/shader_programs/shaders/tessel_vs.glsl +37 -0
- PYME/LMVis/shader_programs/shaders/text_fs.glsl +42 -0
- PYME/LMVis/shader_programs/shaders/text_vs.glsl +84 -0
- PYME/LMVis/shader_programs/shaders/widelines_fs.glsl +19 -0
- PYME/LMVis/shader_programs/shaders/widelines_gs.glsl +56 -0
- PYME/LMVis/shader_programs/shaders/widelines_vs.glsl +51 -0
- PYME/LMVis/statusLog.py +57 -0
- PYME/LMVis/triBlobs.py +142 -0
- PYME/LMVis/view_clipping_pane.py +429 -0
- PYME/LMVis/views.py +275 -0
- PYME/LMVis/visCore.py +1005 -0
- PYME/LMVis/visHelpers.py +880 -0
- PYME/LMVis/visHelpersMin.py +230 -0
- PYME/LMVis/workspaceTree.py +238 -0
- PYME/__init__.py +22 -0
- PYME/cluster/HTTPDataServer.py +1063 -0
- PYME/cluster/HTTPRulePusher.py +382 -0
- PYME/cluster/HTTPTaskPusher.py +377 -0
- PYME/cluster/PYMERuleNodeServer.py +192 -0
- PYME/cluster/PYMERuleServer.py +109 -0
- PYME/cluster/__init__.py +0 -0
- PYME/cluster/clusterUI/accounts/__init__.py +0 -0
- PYME/cluster/clusterUI/accounts/admin.py +85 -0
- PYME/cluster/clusterUI/accounts/forms.py +8 -0
- PYME/cluster/clusterUI/accounts/migrations/0001_initial.py +31 -0
- PYME/cluster/clusterUI/accounts/migrations/__init__.py +0 -0
- PYME/cluster/clusterUI/accounts/models.py +44 -0
- PYME/cluster/clusterUI/accounts/templates/accounts/user_form.html +13 -0
- PYME/cluster/clusterUI/accounts/templates/registration/initial_complete.html +6 -0
- PYME/cluster/clusterUI/accounts/templates/registration/initial_confirm.html +13 -0
- PYME/cluster/clusterUI/accounts/templates/registration/initial_done.html +7 -0
- PYME/cluster/clusterUI/accounts/templates/registration/verification.html +2 -0
- PYME/cluster/clusterUI/accounts/templates/registration/verification_subject.txt +1 -0
- PYME/cluster/clusterUI/accounts/urls.py +19 -0
- PYME/cluster/clusterUI/accounts/views.py +36 -0
- PYME/cluster/clusterUI/clusterUI/__init__.py +0 -0
- PYME/cluster/clusterUI/clusterUI/settings.py +147 -0
- PYME/cluster/clusterUI/clusterUI/urls.py +31 -0
- PYME/cluster/clusterUI/clusterUI/wsgi.py +16 -0
- PYME/cluster/clusterUI/clusterbrowser/__init__.py +0 -0
- PYME/cluster/clusterUI/clusterbrowser/admin.py +3 -0
- PYME/cluster/clusterUI/clusterbrowser/apps.py +7 -0
- PYME/cluster/clusterUI/clusterbrowser/migrations/__init__.py +0 -0
- PYME/cluster/clusterUI/clusterbrowser/models.py +5 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/base.html +129 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/clusterbrowser/dirlisting.html +231 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/clusterbrowser/form_new_folder.html +18 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/clusterbrowser/form_upload_file.html +17 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/clusterbrowser/lightlisting.html +25 -0
- PYME/cluster/clusterUI/clusterbrowser/templates/registration/login.html +38 -0
- PYME/cluster/clusterUI/clusterbrowser/urls.py +10 -0
- PYME/cluster/clusterUI/clusterbrowser/views.py +148 -0
- PYME/cluster/clusterUI/clusterstatus/__init__.py +0 -0
- PYME/cluster/clusterUI/clusterstatus/admin.py +3 -0
- PYME/cluster/clusterUI/clusterstatus/apps.py +7 -0
- PYME/cluster/clusterUI/clusterstatus/migrations/__init__.py +0 -0
- PYME/cluster/clusterUI/clusterstatus/models.py +5 -0
- PYME/cluster/clusterUI/clusterstatus/templates/clusterstatus/load_content.html +29 -0
- PYME/cluster/clusterUI/clusterstatus/templates/clusterstatus/queue_info.html +28 -0
- PYME/cluster/clusterUI/clusterstatus/templates/clusterstatus/queue_info_content.html +50 -0
- PYME/cluster/clusterUI/clusterstatus/templates/clusterstatus/status_dash.html +29 -0
- PYME/cluster/clusterUI/clusterstatus/templates/clusterstatus/status_dash_content.html +90 -0
- PYME/cluster/clusterUI/clusterstatus/urls.py +9 -0
- PYME/cluster/clusterUI/clusterstatus/views.py +69 -0
- PYME/cluster/clusterUI/clusterui_tornado.py +117 -0
- PYME/cluster/clusterUI/deploy.py +62 -0
- PYME/cluster/clusterUI/localization/__init__.py +0 -0
- PYME/cluster/clusterUI/localization/admin.py +3 -0
- PYME/cluster/clusterUI/localization/apps.py +7 -0
- PYME/cluster/clusterUI/localization/migrations/__init__.py +0 -0
- PYME/cluster/clusterUI/localization/models.py +5 -0
- PYME/cluster/clusterUI/localization/templates/localization/settings_form.html +67 -0
- PYME/cluster/clusterUI/localization/urls.py +10 -0
- PYME/cluster/clusterUI/localization/views.py +170 -0
- PYME/cluster/clusterUI/manage.py +17 -0
- PYME/cluster/clusterUI/recipes/__init__.py +0 -0
- PYME/cluster/clusterUI/recipes/admin.py +3 -0
- PYME/cluster/clusterUI/recipes/migrations/__init__.py +0 -0
- PYME/cluster/clusterUI/recipes/models.py +3 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/extra_inputs.html +35 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/form_recipe.html +82 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/input_list.html +7 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/recipe_editor.html +28 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/recipe_editor_common.html +46 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/recipe_editrun.html +93 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/recipe_standalone.html +100 -0
- PYME/cluster/clusterUI/recipes/templates/recipes/recipe_template.html +109 -0
- PYME/cluster/clusterUI/recipes/urls.py +17 -0
- PYME/cluster/clusterUI/recipes/views.py +109 -0
- PYME/cluster/cluster_of_one.py +200 -0
- PYME/cluster/dataserver_wsgi.py +615 -0
- PYME/cluster/distribution.py +71 -0
- PYME/cluster/rulenodeserver.py +487 -0
- PYME/cluster/rules.py +979 -0
- PYME/cluster/ruleserver.py +1106 -0
- PYME/cluster/status.py +101 -0
- PYME/cluster/taskWorkerHTTP.py +522 -0
- PYME/cluster/webdav.py +1102 -0
- PYME/config.py +659 -0
- PYME/contrib/TextCtrlAutoComplete.py +582 -0
- PYME/contrib/__init__.py +7 -0
- PYME/contrib/aniso/__init__.py +2 -0
- PYME/contrib/aniso/aniso.py +268 -0
- PYME/contrib/auiFloatBook.py +94 -0
- PYME/contrib/congrid.py +127 -0
- PYME/contrib/dispatch/__init__.py +19 -0
- PYME/contrib/dispatch/dispatcher.py +289 -0
- PYME/contrib/gohlke/__init__.py +1 -0
- PYME/contrib/gohlke/_tifffile.cp39-win_amd64.dll.a +0 -0
- PYME/contrib/gohlke/_tifffile.cp39-win_amd64.pyd +0 -0
- PYME/contrib/gohlke/czifile.py +1289 -0
- PYME/contrib/gohlke/fcsfiles.py +514 -0
- PYME/contrib/gohlke/setup.py +54 -0
- PYME/contrib/gohlke/tifffile.py +3095 -0
- PYME/contrib/listctrlMixins.py +896 -0
- PYME/contrib/lzw.py +838 -0
- PYME/contrib/pad/__init__.py +13 -0
- PYME/contrib/pad/info_pad.py +18 -0
- PYME/contrib/pad/pad.py +670 -0
- PYME/contrib/setup.py +38 -0
- PYME/contrib/wxPlotPanel.py +137 -0
- PYME/experimental/SimReconstruction.py +49 -0
- PYME/experimental/__init__.pxd +0 -0
- PYME/experimental/__init__.py +4 -0
- PYME/experimental/_octree.cp39-win_amd64.dll.a +0 -0
- PYME/experimental/_octree.cp39-win_amd64.pyd +0 -0
- PYME/experimental/_octree.pyx +477 -0
- PYME/experimental/_treap.cp39-win_amd64.dll.a +0 -0
- PYME/experimental/_treap.cp39-win_amd64.pyd +0 -0
- PYME/experimental/_treap.pyx +267 -0
- PYME/experimental/_triangle_mesh.cp39-win_amd64.dll.a +0 -0
- PYME/experimental/_triangle_mesh.cp39-win_amd64.pyd +0 -0
- PYME/experimental/_triangle_mesh.pxd +149 -0
- PYME/experimental/_triangle_mesh.pyx +2787 -0
- PYME/experimental/aqavg.py +40 -0
- PYME/experimental/dcimgFileChucker.py +375 -0
- PYME/experimental/dcimgSpoolShim.py +174 -0
- PYME/experimental/dcimg_chuck_test.py +78 -0
- PYME/experimental/dual_marching_cubes.py +801 -0
- PYME/experimental/dual_marching_cubes_v2.py +645 -0
- PYME/experimental/expectationMaximisation.py +298 -0
- PYME/experimental/func_octree.cp39-win_amd64.dll.a +0 -0
- PYME/experimental/func_octree.cp39-win_amd64.pyd +0 -0
- PYME/experimental/func_octree.pyx +381 -0
- PYME/experimental/fusionRadial.py +520 -0
- PYME/experimental/fusionUtils.py +522 -0
- PYME/experimental/isosurface.py +147 -0
- PYME/experimental/labview_spooling_hacks.py +48 -0
- PYME/experimental/marching_cubes.py +811 -0
- PYME/experimental/marching_tetrahedra.py +343 -0
- PYME/experimental/modified_marching_cubes.py +1245 -0
- PYME/experimental/music.py +25 -0
- PYME/experimental/octree.py +188 -0
- PYME/experimental/pSpaceMap.py +34 -0
- PYME/experimental/pointFitConfoc.py +112 -0
- PYME/experimental/scanner_control.py +107 -0
- PYME/experimental/setup.py +109 -0
- PYME/experimental/spark.py +31 -0
- PYME/experimental/tcHist.py +71 -0
- PYME/experimental/treap.py +262 -0
- PYME/experimental/triangle_mesh.py +2287 -0
- PYME/experimental/triangle_mesh_utils.cp39-win_amd64.dll.a +0 -0
- PYME/experimental/triangle_mesh_utils.cp39-win_amd64.pyd +0 -0
- PYME/experimental/triangle_utils.py +87 -0
- PYME/experimental/triangular_mesh.py +2255 -0
- PYME/experimental/zMotionArtifactUtils.py +55 -0
- PYME/localization/FitFactories/AstigGaussFitFR.py +175 -0
- PYME/localization/FitFactories/AstigGaussGPUFitFR.py +326 -0
- PYME/localization/FitFactories/BeadConvolvedAstigGaussFit.py +206 -0
- PYME/localization/FitFactories/ChecksumFR.py +82 -0
- PYME/localization/FitFactories/ChecksumGPUFR.py +213 -0
- PYME/localization/FitFactories/ChecksumMultifitSR.py +86 -0
- PYME/localization/FitFactories/ConfocCOIR.py +93 -0
- PYME/localization/FitFactories/Dumbell3DFitR.py +193 -0
- PYME/localization/FitFactories/DumbellFitR.py +163 -0
- PYME/localization/FitFactories/FFBase.py +403 -0
- PYME/localization/FitFactories/Gauss3DFitR.py +213 -0
- PYME/localization/FitFactories/GaussFitConstrR.py +177 -0
- PYME/localization/FitFactories/GaussMultifitLinesR.py +351 -0
- PYME/localization/FitFactories/GaussMultifitR.py +326 -0
- PYME/localization/FitFactories/GaussMultifitSR.py +373 -0
- PYME/localization/FitFactories/InterpFitR.py +236 -0
- PYME/localization/FitFactories/InterpFitWFR.py +111 -0
- PYME/localization/FitFactories/Interpolators/CSInterpolator.py +148 -0
- PYME/localization/FitFactories/Interpolators/CubeSInterpolatorP.py +121 -0
- PYME/localization/FitFactories/Interpolators/CubicSplineInterpolator.py +69 -0
- PYME/localization/FitFactories/Interpolators/LinearInterpolator.py +135 -0
- PYME/localization/FitFactories/Interpolators/LinearPInterpolatorP.py +95 -0
- PYME/localization/FitFactories/Interpolators/__init__.py +33 -0
- PYME/localization/FitFactories/Interpolators/baseInterpolator.py +202 -0
- PYME/localization/FitFactories/LatFitCOIR.py +82 -0
- PYME/localization/FitFactories/LatGaussFitFR.py +220 -0
- PYME/localization/FitFactories/LatObjFindFR.py +85 -0
- PYME/localization/FitFactories/LatPSFFitR.py +142 -0
- PYME/localization/FitFactories/MultiviewFitInterpNR.py +400 -0
- PYME/localization/FitFactories/PRInterpFitQR.py +192 -0
- PYME/localization/FitFactories/PRInterpFitR.py +223 -0
- PYME/localization/FitFactories/ROIExtractNR.py +93 -0
- PYME/localization/FitFactories/SpecGaussFitFR.py +174 -0
- PYME/localization/FitFactories/SplitterFitCOIR.py +142 -0
- PYME/localization/FitFactories/SplitterFitFNR.py +312 -0
- PYME/localization/FitFactories/SplitterFitFusionR.py +318 -0
- PYME/localization/FitFactories/SplitterFitInterpBNR.py +357 -0
- PYME/localization/FitFactories/SplitterFitInterpNR.py +343 -0
- PYME/localization/FitFactories/SplitterFitScavNR.py +352 -0
- PYME/localization/FitFactories/SplitterMultifitSR.py +410 -0
- PYME/localization/FitFactories/SplitterObjFindR.py +194 -0
- PYME/localization/FitFactories/SplitterROIExtractNR.py +91 -0
- PYME/localization/FitFactories/SplitterShiftEstFR.py +230 -0
- PYME/localization/FitFactories/__init__.py +103 -0
- PYME/localization/FitFactories/fitCommon.py +195 -0
- PYME/localization/FitFactories/zEstimators/__init__.py +29 -0
- PYME/localization/FitFactories/zEstimators/astigEstimator.py +173 -0
- PYME/localization/FitFactories/zEstimators/biplaneEstimator.py +209 -0
- PYME/localization/FitFactories/zEstimators/genericDualEstimator.py +232 -0
- PYME/localization/FitFactories/zEstimators/genericEstimator.py +224 -0
- PYME/localization/FitFactories/zEstimators/priEstimator.py +255 -0
- PYME/localization/MetaDataEdit.py +543 -0
- PYME/localization/Test/30_9_series_A_1.sf +0 -0
- PYME/localization/Test/PRI.md +45 -0
- PYME/localization/Test/PRI_qr.md +52 -0
- PYME/localization/Test/PRI_r.md +52 -0
- PYME/localization/Test/__init__.py +22 -0
- PYME/localization/Test/astig.md +50 -0
- PYME/localization/Test/astigCOI.md +50 -0
- PYME/localization/Test/astig_gauss.md +52 -0
- PYME/localization/Test/astig_pe.md +50 -0
- PYME/localization/Test/astig_splitter.md +66 -0
- PYME/localization/Test/astig_splitterCOI.md +67 -0
- PYME/localization/Test/astig_splitterQ.md +66 -0
- PYME/localization/Test/astig_theory.md +50 -0
- PYME/localization/Test/astig_theory.psf +0 -0
- PYME/localization/Test/astig_theory.tif +0 -0
- PYME/localization/Test/beads1.psf +0 -0
- PYME/localization/Test/beads1.tif +0 -0
- PYME/localization/Test/biplane_splitter.md +75 -0
- PYME/localization/Test/biplane_splitter2.md +103 -0
- PYME/localization/Test/biplane_splitter3.md +115 -0
- PYME/localization/Test/defoc.md +48 -0
- PYME/localization/Test/dumbell_3d.md +52 -0
- PYME/localization/Test/fitTestJig.py +172 -0
- PYME/localization/Test/fitTestJigSCMOS.py +487 -0
- PYME/localization/Test/fitTestJigWC.py +225 -0
- PYME/localization/Test/gauss.md +50 -0
- PYME/localization/Test/gaussCOI.md +50 -0
- PYME/localization/Test/pri_pe.md +50 -0
- PYME/localization/Test/pri_theory.md +51 -0
- PYME/localization/Test/pri_theory.psf +0 -0
- PYME/localization/Test/pri_theory.tif +0 -0
- PYME/localization/Test/psf_astig.psf +0 -0
- PYME/localization/Test/psf_astig.tif +0 -0
- PYME/localization/Test/psf_astig_bg_d.psf +0 -0
- PYME/localization/Test/psf_astig_bg_d.tif +0 -0
- PYME/localization/Test/psf_astig_pe.psf +0 -0
- PYME/localization/Test/psf_astig_pe.tif +0 -0
- PYME/localization/Test/psf_decon.psf +0 -0
- PYME/localization/Test/psf_decon.tif +0 -0
- PYME/localization/Test/psf_decon_pe.psf +0 -0
- PYME/localization/Test/psf_decon_pe.tif +0 -0
- PYME/localization/Test/psf_guess.psf +0 -0
- PYME/localization/Test/splitter.md +63 -0
- PYME/localization/Test/splitter_scav.md +63 -0
- PYME/localization/Test/test.psf +0 -0
- PYME/localization/Test/test.tif +0 -0
- PYME/localization/Test/test_decon.psf +0 -0
- PYME/localization/Test/test_decon.tif +0 -0
- PYME/localization/Test/test_pe.psf +0 -0
- PYME/localization/Test/test_pe.tif +0 -0
- PYME/localization/Test/wf_theory.psf +0 -0
- PYME/localization/Test/wf_theory2.psf +0 -0
- PYME/localization/__init__.py +17 -0
- PYME/localization/autopsf/__init__.py +1 -0
- PYME/localization/autopsf/autopsf.py +486 -0
- PYME/localization/autopsf/roifit.py +310 -0
- PYME/localization/cInterp/__init__.py +24 -0
- PYME/localization/cInterp/cInterp.cp39-win_amd64.dll.a +0 -0
- PYME/localization/cInterp/cInterp.cp39-win_amd64.pyd +0 -0
- PYME/localization/cInterp/setup.py +54 -0
- PYME/localization/cModels/__init__.py +24 -0
- PYME/localization/cModels/gauss_app.cp39-win_amd64.dll.a +0 -0
- PYME/localization/cModels/gauss_app.cp39-win_amd64.pyd +0 -0
- PYME/localization/ofind.py +444 -0
- PYME/localization/ofind3d.py +306 -0
- PYME/localization/ofind_nofilt.py +128 -0
- PYME/localization/ofind_pri.py +478 -0
- PYME/localization/ofind_split.py +399 -0
- PYME/localization/ofind_xcorr.py +351 -0
- PYME/localization/ofind_xcorr_fw.py +441 -0
- PYME/localization/remFitBuf.py +657 -0
- PYME/localization/setup.py +56 -0
- PYME/localization/splitting.py +240 -0
- PYME/localization/twist.py +60 -0
- PYME/misc/TiSettings.py +36 -0
- PYME/misc/TiffImagePlugin.py +838 -0
- PYME/misc/VolProj.py +144 -0
- PYME/misc/__init__.py +25 -0
- PYME/misc/aligned_array.py +10 -0
- PYME/misc/aniso.py +29 -0
- PYME/misc/big_sur_fix.py +20 -0
- PYME/misc/check_for_updates.py +139 -0
- PYME/misc/colormaps.py +199 -0
- PYME/misc/colorsys.py +201 -0
- PYME/misc/computerName.py +33 -0
- PYME/misc/coverslipGeometries.py +60 -0
- PYME/misc/cython_numpy_monkey.py +40 -0
- PYME/misc/depGraph.py +406 -0
- PYME/misc/dirSize.py +31 -0
- PYME/misc/diskCleanup.py +64 -0
- PYME/misc/djangoRecarray.py +57 -0
- PYME/misc/django_widgets.py +27 -0
- PYME/misc/editgrid.py +101 -0
- PYME/misc/eventSpy.py +122 -0
- PYME/misc/exceptions.py +30 -0
- PYME/misc/facsPlot.py +89 -0
- PYME/misc/fbpIcons.py +90 -0
- PYME/misc/fftw_compat.py +28 -0
- PYME/misc/findCycles.py +91 -0
- PYME/misc/fortran_interrupt_defeat.py +43 -0
- PYME/misc/glassModel.py +64 -0
- PYME/misc/hash32.py +41 -0
- PYME/misc/hillcurve.py +88 -0
- PYME/misc/hybrid_ns.py +84 -0
- PYME/misc/kdFit.py +72 -0
- PYME/misc/locate.py +10 -0
- PYME/misc/memUsage.py +65 -0
- PYME/misc/memmap.py +52 -0
- PYME/misc/mock_ctypes.py +28 -0
- PYME/misc/mock_traits.py +59 -0
- PYME/misc/mock_traitsui.py +29 -0
- PYME/misc/pyme_zeroconf.py +287 -0
- PYME/misc/pyro_tracebacks.py +32 -0
- PYME/misc/read_agf.py +605 -0
- PYME/misc/sffake.py +16 -0
- PYME/misc/snells.py +71 -0
- PYME/misc/sqlite_ns.py +132 -0
- PYME/misc/sqlitendarray.py +56 -0
- PYME/misc/taskDef.py +44 -0
- PYME/misc/tempDB.py +56 -0
- PYME/misc/wxThread.py +33 -0
- PYME/misc/zemax.py +259 -0
- PYME/misc/zernike.py +151 -0
- PYME/pyme_warnings.py +70 -0
- PYME/recipes/Recipes/STEDDeconvolution.yaml +14 -0
- PYME/recipes/Recipes/STEDMinistacks.yaml +15 -0
- PYME/recipes/Recipes/STED_COP3.yaml +25 -0
- PYME/recipes/Recipes/blobMeas.yaml +19 -0
- PYME/recipes/Recipes/blobMeas2.yaml +37 -0
- PYME/recipes/Recipes/blobMeasSR.yaml +66 -0
- PYME/recipes/Recipes/coloc.yaml +43 -0
- PYME/recipes/Recipes/coloc_roi_masked.yaml +46 -0
- PYME/recipes/Recipes/multiblob.yaml +38 -0
- PYME/recipes/Recipes/pre_particleTracking.yaml +30 -0
- PYME/recipes/Recipes/segmentAndMeasureLoci.yaml +41 -0
- PYME/recipes/__init__.py +6 -0
- PYME/recipes/acquisition.py +158 -0
- PYME/recipes/bakeshop.py +32 -0
- PYME/recipes/base.py +1393 -0
- PYME/recipes/batchProcess.py +147 -0
- PYME/recipes/filters.py +394 -0
- PYME/recipes/fudges.py +41 -0
- PYME/recipes/graphing.py +108 -0
- PYME/recipes/html_recipe_editor.py +90 -0
- PYME/recipes/localisations.py +1386 -0
- PYME/recipes/machine_learning.py +286 -0
- PYME/recipes/measurement.py +1062 -0
- PYME/recipes/modules.py +50 -0
- PYME/recipes/multiview.py +435 -0
- PYME/recipes/output.py +667 -0
- PYME/recipes/pointcloud.py +510 -0
- PYME/recipes/processing.py +2954 -0
- PYME/recipes/pyramid.py +206 -0
- PYME/recipes/recipe.py +965 -0
- PYME/recipes/recipeGui.py +1029 -0
- PYME/recipes/recipeLayout.py +499 -0
- PYME/recipes/runRecipe.py +140 -0
- PYME/recipes/setup.py +37 -0
- PYME/recipes/simulation.py +91 -0
- PYME/recipes/skfilters.py +143 -0
- PYME/recipes/surface_fitting.py +776 -0
- PYME/recipes/tablefilters.py +275 -0
- PYME/recipes/tracking.py +343 -0
- PYME/recipes/traits.py +157 -0
- PYME/recipes/vertical_recipe_display.py +373 -0
- PYME/resources/__init__.py +23 -0
- PYME/resources/config_template/distributor.yaml +14 -0
- PYME/resources/config_template/nodeserver.yaml +15 -0
- PYME/resources/icons/LUT.png +0 -0
- PYME/resources/icons/YSM_Shield.png +0 -0
- PYME/resources/icons/YSM_logo.png +0 -0
- PYME/resources/icons/arrow.png +0 -0
- PYME/resources/icons/crosshairs.png +0 -0
- PYME/resources/icons/line_select.png +0 -0
- PYME/resources/icons/logo_fmhs.png +0 -0
- PYME/resources/icons/media-playback-pause.png +0 -0
- PYME/resources/icons/media-playback-start.png +0 -0
- PYME/resources/icons/media-skip-backward.png +0 -0
- PYME/resources/icons/media-skip-forward.png +0 -0
- PYME/resources/icons/mesh.png +0 -0
- PYME/resources/icons/mesh.svg +28 -0
- PYME/resources/icons/pmacquire.icns +0 -0
- PYME/resources/icons/pmacquire.ico +0 -0
- PYME/resources/icons/pmanal.icns +0 -0
- PYME/resources/icons/pmanal.ico +0 -0
- PYME/resources/icons/pmvis.icns +0 -0
- PYME/resources/icons/pmvis.ico +0 -0
- PYME/resources/icons/points.png +0 -0
- PYME/resources/icons/points.svg +16 -0
- PYME/resources/icons/pymeLogo.png +0 -0
- PYME/resources/icons/rect_select.png +0 -0
- PYME/resources/icons/squiggle_select.png +0 -0
- PYME/resources/icons/text3800.icns +0 -0
- PYME/resources/icons/text3800.ico +0 -0
- PYME/resources/icons/text3800.png +0 -0
- PYME/resources/icons/text3800.tif +0 -0
- PYME/resources/icons/text5377.icns +0 -0
- PYME/resources/icons/text5377.ico +0 -0
- PYME/resources/icons/text5377.png +0 -0
- PYME/resources/icons/tracks.png +0 -0
- PYME/resources/icons/tracks.svg +19 -0
- PYME/resources/icons/view-front.png +0 -0
- PYME/resources/icons/view-home.png +0 -0
- PYME/resources/icons/view-right.png +0 -0
- PYME/resources/icons/view-top.png +0 -0
- PYME/resources/test_datasets/README.md +8 -0
- PYME/resources/test_datasets/t_im.tif +0 -0
- PYME/resources/test_datasets/test_csv.csv +4282 -0
- PYME/resources/test_datasets/test_hdf.hdf +0 -0
- PYME/resources/web/rule_inline.html +21 -0
- PYME/resources/web/ruleserver.html +75 -0
- PYME/resources/web/static/bootstrap.min.js +7 -0
- PYME/resources/web/static/cluster.css +137 -0
- PYME/resources/web/static/css/bootstrap-theme.css +587 -0
- PYME/resources/web/static/css/bootstrap-theme.min.css +6 -0
- PYME/resources/web/static/css/bootstrap.css +6757 -0
- PYME/resources/web/static/css/bootstrap.min.css +6 -0
- PYME/resources/web/static/css/flat_design_colors_full.css +306 -0
- PYME/resources/web/static/css/recipe_editor.css +106 -0
- PYME/resources/web/static/dashboard.css +106 -0
- PYME/resources/web/static/fileselector.js +77 -0
- PYME/resources/web/static/fonts/glyphicons-halflings-regular.eot +0 -0
- PYME/resources/web/static/fonts/glyphicons-halflings-regular.svg +288 -0
- PYME/resources/web/static/fonts/glyphicons-halflings-regular.ttf +0 -0
- PYME/resources/web/static/fonts/glyphicons-halflings-regular.woff +0 -0
- PYME/resources/web/static/fonts/glyphicons-halflings-regular.woff2 +0 -0
- PYME/resources/web/static/images/osd_flat/LICENSE.txt +116 -0
- PYME/resources/web/static/images/osd_flat/README.md +9 -0
- PYME/resources/web/static/images/osd_flat/fullpage_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/fullpage_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/fullpage_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/fullpage_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/home_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/home_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/home_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/home_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/next_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/next_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/next_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/next_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/previous_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/previous_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/previous_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/previous_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateleft_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateleft_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateleft_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateleft_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateright_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateright_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateright_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/rotateright_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomin_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomin_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomin_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomin_rest.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomout_grouphover.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomout_hover.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomout_pressed.png +0 -0
- PYME/resources/web/static/images/osd_flat/zoomout_rest.png +0 -0
- PYME/resources/web/static/jigna-vue-bare.js +1395 -0
- PYME/resources/web/static/jquery.min.js +2 -0
- PYME/resources/web/static/jstree.min.js +6 -0
- PYME/resources/web/static/openSeadragonGL.js +102 -0
- PYME/resources/web/static/openseadragon-svg-overlay.js +103 -0
- PYME/resources/web/static/openseadragon-viewerinputhook.min.js +6 -0
- PYME/resources/web/static/openseadragon.min.js +9 -0
- PYME/resources/web/static/recipe_editor.js +119 -0
- PYME/resources/web/static/shaders/fragment/lut.glsl +20 -0
- PYME/resources/web/static/shaders/fragment/none.glsl +17 -0
- PYME/resources/web/static/shaders/fragment/outline.glsl +43 -0
- PYME/resources/web/static/shaders/fragment/rect.glsl +7 -0
- PYME/resources/web/static/shaders/fragment/sobel3.glsl +71 -0
- PYME/resources/web/static/shaders/fragment/white.glsl +4 -0
- PYME/resources/web/static/shaders/vertex/rect.glsl +22 -0
- PYME/resources/web/static/shaders/vertex/square.glsl +9 -0
- PYME/resources/web/static/utils.js +3 -0
- PYME/resources/web/static/viaWebGL.js +217 -0
- PYME/setup.py +109 -0
- PYME/setup_exe.py +57 -0
- PYME/simulation/__init__.py +0 -0
- PYME/simulation/locify.py +319 -0
- PYME/simulation/pointsets.py +279 -0
- PYME/simulation/wormlike.py +99 -0
- PYME/simulation/wormlike2.py +198 -0
- PYME/simulation/wormlike3.py +197 -0
- PYME/simulation/wormlike_curled.py +104 -0
- PYME/tileviewer/__init__.py +0 -0
- PYME/tileviewer/templates/roi_list.html +12 -0
- PYME/tileviewer/templates/tileviewer.html +247 -0
- PYME/tileviewer/tileviewer.py +207 -0
- PYME/ui/AUIFrame.py +279 -0
- PYME/ui/MetadataTree.py +469 -0
- PYME/ui/__init__.py +4 -0
- PYME/ui/about_dlg.py +29 -0
- PYME/ui/autoFoldPanel.py +643 -0
- PYME/ui/cascading_layout.py +45 -0
- PYME/ui/crop_dialog.py +145 -0
- PYME/ui/custom_traits_editors.py +508 -0
- PYME/ui/editFilterDialog.py +80 -0
- PYME/ui/editList.py +40 -0
- PYME/ui/fastGraph.py +240 -0
- PYME/ui/filterPane.py +348 -0
- PYME/ui/histLimits.py +543 -0
- PYME/ui/layerFoldPanel.py +232 -0
- PYME/ui/manualFoldPanel.py +870 -0
- PYME/ui/mytimer.py +116 -0
- PYME/ui/patch_traitsui.py +151 -0
- PYME/ui/progress.py +160 -0
- PYME/ui/recArrayView.py +145 -0
- PYME/ui/selection.py +71 -0
- PYME/ui/shell.py +37 -0
- PYME/ui/traitsui_constants.py +91 -0
- PYME/ui/wx_compat.py +43 -0
- PYME/update_version.py +159 -0
- PYME/util/__init__.py +3 -0
- PYME/util/authenticate.py +164 -0
- PYME/util/execfile.py +21 -0
- PYME/util/fProfile/__init__.py +1 -0
- PYME/util/fProfile/convertProfile.py +117 -0
- PYME/util/fProfile/fProfile.py +162 -0
- PYME/util/fProfile/html/404.html +60 -0
- PYME/util/fProfile/html/css/main.css +258 -0
- PYME/util/fProfile/html/css/normalize.css +427 -0
- PYME/util/fProfile/html/css/normalize.min.css +1 -0
- PYME/util/fProfile/html/index.html +64 -0
- PYME/util/fProfile/html/js/main.js +492 -0
- PYME/util/fProfile/html/js/plugins.js +24 -0
- PYME/util/fProfile/html/js/vendor/crossfilter.min.js +1 -0
- PYME/util/fProfile/html/js/vendor/jquery-1.11.2.min.js +4 -0
- PYME/util/fProfile/html/js/vendor/modernizr-2.8.3.min.js +4 -0
- PYME/util/fProfile/html/js/vendor/tinycolor-min.js +4 -0
- PYME/util/fProfile/viewProfile.py +30 -0
- PYME/util/install_dependencies.py +95 -0
- PYME/util/log_verbosity.py +11 -0
- PYME/util/mProfile/__init__.py +1 -0
- PYME/util/mProfile/colorize_db_t.py +297 -0
- PYME/util/mProfile/mProfile.py +164 -0
- PYME/util/mProfile/p.py +101 -0
- PYME/util/mProfile/tProfile.py +165 -0
- PYME/util/pymelauncher.py +47 -0
- PYME/util/shmarray/__init__.py +0 -0
- PYME/util/shmarray/shmTest.py +74 -0
- PYME/util/shmarray/shmarray.py +165 -0
- PYME/util/webframework.py +365 -0
- PYME/version.py +65 -0
- python_microscopy-25.6.5.dist-info/METADATA +68 -0
- python_microscopy-25.6.5.dist-info/RECORD +1277 -0
- python_microscopy-25.6.5.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module defines a RESTful HTTP server, the PYME Rule Server, which manages task distribution across a cluster through the use of rules.
|
|
3
|
+
Rules are essentially a json template which defines how tasks may be generated (by substitution into the template on the
|
|
4
|
+
client side). Generation of individual tasks on the client has the dual benefits of a) reducing the CPU load and memory
|
|
5
|
+
requirements on the server and b) dramatically decreasing the network bandwidth used for task distribution.
|
|
6
|
+
|
|
7
|
+
The exposed REST API is as follows:
|
|
8
|
+
|
|
9
|
+
============================================================= ====== ========================================
|
|
10
|
+
Endpoint Verb Brief Description
|
|
11
|
+
============================================================= ====== ========================================
|
|
12
|
+
:meth:`/add_integer_id_rule <RuleServer.add_integer_id_rule>` POST Add a new rule
|
|
13
|
+
:meth:`/release_rule_tasks <RuleServer.release_rule_tasks>` POST Release tasks IDs associated with a rule
|
|
14
|
+
:meth:`/task_advertisments <RuleServer.task_advertisements>` GET Retrieve a list of advertisements
|
|
15
|
+
:meth:`/bid_on_tasks <RuleServer.bid_on_tasks>` POST Submit bids on advertised tasks
|
|
16
|
+
:meth:`/handin <RuleServer.handin>` POST Advise rule server of task completion
|
|
17
|
+
:meth:`/distributor/queues <Ruleserver.get_queues>` GET Get status information
|
|
18
|
+
============================================================= ====== ========================================
|
|
19
|
+
|
|
20
|
+
Implementation details follow. The json format and parameters for the REST calls are defined in the docstrings of the
|
|
21
|
+
python functions defining that method (linked from the table above). The server is launched by the ``PYMERuleServer``
|
|
22
|
+
command (see :mod:`PYME.cluster.PYMERuleServer`) which loads this in a separate thread and takes care of logging and zeroconf
|
|
23
|
+
registration, rather than by directly running this file.
|
|
24
|
+
"""
|
|
25
|
+
#import cherrypy
|
|
26
|
+
import threading
|
|
27
|
+
import requests
|
|
28
|
+
import queue as Queue
|
|
29
|
+
from six.moves import xrange
|
|
30
|
+
|
|
31
|
+
import logging
|
|
32
|
+
logging.basicConfig(level=logging.WARN)
|
|
33
|
+
logger = logging.getLogger('ruleserver')
|
|
34
|
+
logger.setLevel(logging.DEBUG)
|
|
35
|
+
|
|
36
|
+
import time
|
|
37
|
+
import sys
|
|
38
|
+
import ujson as json
|
|
39
|
+
#import json
|
|
40
|
+
import os
|
|
41
|
+
|
|
42
|
+
from PYME.misc import computerName
|
|
43
|
+
from PYME import config
|
|
44
|
+
from PYME import resources
|
|
45
|
+
#from PYME.IO import clusterIO
|
|
46
|
+
from PYME.util import webframework
|
|
47
|
+
import collections
|
|
48
|
+
|
|
49
|
+
import uuid
|
|
50
|
+
|
|
51
|
+
import numpy as np
|
|
52
|
+
|
|
53
|
+
class Rule(object):
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
STATUS_UNAVAILABLE, STATUS_AVAILABLE, STATUS_ASSIGNED, STATUS_COMPLETE, STATUS_FAILED = range(5)
|
|
57
|
+
|
|
58
|
+
Bid = collections.namedtuple('Bid', 'bidder_id, cost')
|
|
59
|
+
|
|
60
|
+
DEFAULT_BID = Bid(0, sys.maxsize)
|
|
61
|
+
|
|
62
|
+
class IntegerIDRule(Rule):
|
|
63
|
+
"""
|
|
64
|
+
A rule which generates tasks based on a template.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
ruleID : str
|
|
69
|
+
A unique ID for this rule
|
|
70
|
+
task_template : str
|
|
71
|
+
A json template for generating tasks (see templates section below)
|
|
72
|
+
inputs_by_task : list of dict
|
|
73
|
+
A list of dictionaries mapping recipe variable names to URIs to treat as inputs (recipes only)
|
|
74
|
+
max_task_ID : int
|
|
75
|
+
The maximum number of tasks that can be generated by this rule. If the final number of tasks is not known at
|
|
76
|
+
creation, set this to a value which is garuanteed to be higher and then call `mark_release_complete()` after all tasks
|
|
77
|
+
have been released / made available.
|
|
78
|
+
task_timeout: float
|
|
79
|
+
A timeout in seconds for each task. If a task takes longer than task_timeout seconds it is assumed that
|
|
80
|
+
the node executing it has fallen over and we retry on a different node (up to a maximum number of times
|
|
81
|
+
set by the 'ruleserver-retries` config option).
|
|
82
|
+
rule_timeout : float
|
|
83
|
+
A timeout in seconds from the last task we processed after which we assume that no more tasks are coming and
|
|
84
|
+
we can delete the rule (to keep memory down in a long-term usage scenario).
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Notes
|
|
88
|
+
-----
|
|
89
|
+
|
|
90
|
+
*Templates*
|
|
91
|
+
|
|
92
|
+
Templates are a string which can be substituted to generate tasks. There are currently two supported formats for
|
|
93
|
+
templates, those for localization tasks, and those for recipes. Each take the form of a json dictionary:
|
|
94
|
+
|
|
95
|
+
**Localization**
|
|
96
|
+
|
|
97
|
+
.. code-block:: json
|
|
98
|
+
|
|
99
|
+
{
|
|
100
|
+
"id" : "{{ruleID}}~{{taskID}}",
|
|
101
|
+
"type" : "localization",
|
|
102
|
+
"taskdef" : {"frameIndex" : {{taskID}}, "metadata" : "PYME-CLUSTER://path/to/series/metadata.json"},
|
|
103
|
+
"inputs" : {"frames" : "PYME-CLUSTER://path/to/series.pcs"},
|
|
104
|
+
"outputs" : {"fitResults" : "PYME-CLUSTER://__aggregate_h5r/path/to/analysis.h5r/FitResults",
|
|
105
|
+
"driftResults" : "PYME-CLUSTER://__aggregate_h5r/path/to/analysis.h5r/DriftResults"}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
**Recipes**
|
|
110
|
+
The recipe can either be specified inline:
|
|
111
|
+
|
|
112
|
+
.. code-block:: json
|
|
113
|
+
|
|
114
|
+
{
|
|
115
|
+
"id" : "{{ruleID}}~{{taskID}}",
|
|
116
|
+
"type" : "recipe",
|
|
117
|
+
"taskdef" : {"recipe" : "<recipe as a YAML string>"},
|
|
118
|
+
"inputs" : {{taskInputs}},
|
|
119
|
+
"output_dir" : "PYME-CLUSTER://path/to/output/dir",
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
or using a cluster URI:
|
|
124
|
+
|
|
125
|
+
.. code-block:: json
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
"id" : "{{ruleID}}~{{taskID}}",
|
|
129
|
+
"type" : "recipe",
|
|
130
|
+
"taskdefRef" : "PYME-CLUSTER://path/to/recipe.yaml",
|
|
131
|
+
"inputs" : {{taskInputs}},
|
|
132
|
+
"output_dir" : "PYME-CLUSTER://path/to/output/dir",
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
The rule will substitute ``{{taskInputs}}`` with a dictionary mapping integer task IDs to recipe input files, e.g.
|
|
137
|
+
|
|
138
|
+
.. code-block:: json
|
|
139
|
+
|
|
140
|
+
{0 : {"recipe_input_0" : "input_0_URI_0","recipe_input_1" : "input_1_URI_0"},
|
|
141
|
+
1 : {"recipe_input_0" : "input_0_URI_1","recipe_input_1" : "input_1_URI_1"},
|
|
142
|
+
2 : {"recipe_input_0" : "input_0_URI_2","recipe_input_1" : "input_1_URI_2"},
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
Alternatively the inputs dictionary can be supplied directly (without relying on the taskInputs substitution).
|
|
147
|
+
|
|
148
|
+
*Rule Chaining*
|
|
149
|
+
|
|
150
|
+
Rules may also define a chained rule, to be run on completion of the original rule. This is accomplished by
|
|
151
|
+
supplying an "on_completion" dictionary. This is a dictionary, ``{'template' : <template>, 'max_tasks' : max_tasks,
|
|
152
|
+
'rule_timeout' : timeout, 'on_completion' : {...}}``, with the template following the format above and everything
|
|
153
|
+
but the template being optional (max_tasks defaults to 1). Follow on / chained rules are slightly more restricted
|
|
154
|
+
than standard rules in that recipe "inputs" must be hardcoded (no ``{{taskInputs}}`` substitution).
|
|
155
|
+
|
|
156
|
+
Chained rules are created once the original rule is finished (see
|
|
157
|
+
`IntegerIDRule.finished`). All tasks for the chained rule will be released
|
|
158
|
+
immediately.
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
TASK_INFO_DTYPE = np.dtype([('status', 'uint8'), ('nRetries', 'uint8'), ('expiry', 'f4'), ('cost', 'f4')])
|
|
162
|
+
|
|
163
|
+
# task cost threshold below which tasks are deemed 'local' and directly awarded to the first bidder
|
|
164
|
+
# rather than going to "auction" - ie. the "Buy Now" price
|
|
165
|
+
# TODO - Revisit - should this be a settable rule parameter rather than a constant?
|
|
166
|
+
COST_THRESHOLD = 0.2
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def __init__(self, ruleID, task_template, inputs_by_task = None,
|
|
170
|
+
max_task_ID=100000, task_timeout=600, rule_timeout=3600,
|
|
171
|
+
on_completion=None):
|
|
172
|
+
self.ruleID = ruleID
|
|
173
|
+
|
|
174
|
+
if not inputs_by_task is None:
|
|
175
|
+
self._inputs_by_task = {int(k):v for k, v in inputs_by_task.items()}
|
|
176
|
+
else:
|
|
177
|
+
self._inputs_by_task = None
|
|
178
|
+
|
|
179
|
+
self._template = task_template
|
|
180
|
+
self._task_info = np.zeros(max_task_ID, self.TASK_INFO_DTYPE)
|
|
181
|
+
|
|
182
|
+
# Number of times to re-queue a task if it times out is set by the 'ruleserver-retries' config option
|
|
183
|
+
# Setting a value of 0 effectively disables re-trying and makes analysis less robust.
|
|
184
|
+
# Note that a timeout is different to a failure - failing tasks will be marked as having failed and will not be re-tried. Timeouts will
|
|
185
|
+
# occur in one of 4 scenarios:
|
|
186
|
+
# - a worker falls over completely or is disconnected from the network
|
|
187
|
+
# - an unhandled exception - e.g. due to an IO error connecting to the ruleserver in `taskWorkerHTTP.taskWorker._return_task_results()`
|
|
188
|
+
# - analysis is getting massively bogged down and nothing is keeping up
|
|
189
|
+
# - the task timeout is unrealistically short for a given processing task
|
|
190
|
+
#
|
|
191
|
+
# In scenarios 1 & 2 it's reasonable to expect that retrying will result in success. In scenarios 3 & 4 it's a bit muddier, but seeing as a) these kind of
|
|
192
|
+
# failures tend to be a bit stochastic and b) the retries get punted to the back of the queue, when the load might have let up a bit, the odds are
|
|
193
|
+
# reasonably good.
|
|
194
|
+
self._n_retries = config.get('ruleserver-retries', 1)
|
|
195
|
+
self._timeout = task_timeout
|
|
196
|
+
|
|
197
|
+
self._rule_timeout = rule_timeout
|
|
198
|
+
self._cached_advert = None
|
|
199
|
+
self._active = True # making this rule inactive will cause it not to generate adverts (this is the closest we get to aborting)
|
|
200
|
+
self._seen_as_finished = False # flag to make sure completion logic only gets triggered once.
|
|
201
|
+
|
|
202
|
+
self.nTotal = 0
|
|
203
|
+
self.nAssigned = 0
|
|
204
|
+
self.nAvailable = 0
|
|
205
|
+
self.nCompleted = 0
|
|
206
|
+
self.nFailed = 0
|
|
207
|
+
self.n_returned_after_timeout = 0
|
|
208
|
+
self.n_repeats = 0
|
|
209
|
+
self.n_timed_out = 0
|
|
210
|
+
|
|
211
|
+
self._n_max = max_task_ID
|
|
212
|
+
|
|
213
|
+
self.on_completion = on_completion
|
|
214
|
+
|
|
215
|
+
self.avCost = 0
|
|
216
|
+
|
|
217
|
+
self.expiry = time.time() + self._rule_timeout
|
|
218
|
+
|
|
219
|
+
# store pending bids
|
|
220
|
+
self._pending_bids = {}
|
|
221
|
+
self._current_bidder_id = 0
|
|
222
|
+
|
|
223
|
+
self._info_lock = threading.Lock()
|
|
224
|
+
self._advert_lock = threading.Lock()
|
|
225
|
+
|
|
226
|
+
def mark_release_complete(self, n_tasks=None):
|
|
227
|
+
"""
|
|
228
|
+
Signal that all tasks which are going to be released for this rule have been, and that the rule should evaluate as finished once these tasks have been
|
|
229
|
+
evaluated. Used when the number of tasks is not known in advance. (See also __init__ docs)
|
|
230
|
+
|
|
231
|
+
FIXME - What happens when task release doesn't start at 0?
|
|
232
|
+
|
|
233
|
+
Parameters
|
|
234
|
+
----------
|
|
235
|
+
n_tasks : int, optional
|
|
236
|
+
mark complete at a given number of tasks. The default is to mark complete at the highest task number which has been released prior to making this call.
|
|
237
|
+
The use case for this optional parameter is to avoid the need for locking when this gets called from another thread than the `make_range_available()`
|
|
238
|
+
and implies a promise by the calling code that it will not release any more tasks above the given number.
|
|
239
|
+
|
|
240
|
+
Raises
|
|
241
|
+
------
|
|
242
|
+
ValueError
|
|
243
|
+
If `n_tasks` is supplied and is either smaller than the largest task already released or larger than larger than `max_task_ID`
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
with self._info_lock: #TODO - is this lock necessary (I suspect it's not)
|
|
247
|
+
if (n_tasks is not None):
|
|
248
|
+
if self.nTotal > n_tasks:
|
|
249
|
+
raise ValueError('n_tasks cannot be less than nTotal')
|
|
250
|
+
|
|
251
|
+
# extend _task_info array if necessary
|
|
252
|
+
if n_tasks > self._n_max:
|
|
253
|
+
raise ValueError('n_tasks cannot be greater than max_task_ID')
|
|
254
|
+
|
|
255
|
+
self._n_max = n_tasks
|
|
256
|
+
else:
|
|
257
|
+
self._n_max = self.nTotal
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def _update_nums(self):
|
|
263
|
+
self.nAvailable = int((self._task_info['status'] == STATUS_AVAILABLE).sum())
|
|
264
|
+
self.nAssigned = int((self._task_info['status'] == STATUS_ASSIGNED).sum())
|
|
265
|
+
|
|
266
|
+
def _update_cost(self):
|
|
267
|
+
av_cost = np.mean(self._task_info['cost'][self._task_info['status'] > STATUS_AVAILABLE])
|
|
268
|
+
if np.isnan(av_cost):
|
|
269
|
+
av_cost = 0
|
|
270
|
+
else:
|
|
271
|
+
av_cost = float(av_cost)
|
|
272
|
+
|
|
273
|
+
self.avCost = av_cost
|
|
274
|
+
|
|
275
|
+
def make_range_available(self, start, end):
|
|
276
|
+
"""
|
|
277
|
+
Make a range of tasks available (to be called once the underlying data is available)
|
|
278
|
+
[start, end)
|
|
279
|
+
|
|
280
|
+
Parameters
|
|
281
|
+
----------
|
|
282
|
+
start : int
|
|
283
|
+
first task number to release (inclusive)
|
|
284
|
+
end : int
|
|
285
|
+
last task number to release (exclusive)
|
|
286
|
+
|
|
287
|
+
Raises
|
|
288
|
+
------
|
|
289
|
+
RuntimeError
|
|
290
|
+
if asked to release a range which is invalid for the max tasks we can create from this rule
|
|
291
|
+
"""
|
|
292
|
+
|
|
293
|
+
if start < 0 or start > self._task_info.size or end < 0 or end > self._task_info.size:
|
|
294
|
+
raise RuntimeError('Range (%d, %d) invalid with maxTasks=%d' % (start, end, self._task_info.size))
|
|
295
|
+
|
|
296
|
+
#TODO - check existing status - it probably makes sense to only apply this to tasks which have STATUS_UNAVAILABLE
|
|
297
|
+
with self._info_lock:
|
|
298
|
+
self._task_info['status'][start:end] = STATUS_AVAILABLE
|
|
299
|
+
|
|
300
|
+
self.nTotal = int((self._task_info['status'] >0).sum())
|
|
301
|
+
|
|
302
|
+
self._update_nums()
|
|
303
|
+
|
|
304
|
+
self.expiry = time.time() + self._rule_timeout
|
|
305
|
+
|
|
306
|
+
with self._advert_lock:
|
|
307
|
+
self._cached_advert = None
|
|
308
|
+
|
|
309
|
+
def bid(self, bid):
|
|
310
|
+
"""Bid on tasks (and return any that match). Note the current implementation is very naive and doesn't
|
|
311
|
+
check bid cost - i.e. the first bid gets the task. This works if (and only if) the clients are well behaved
|
|
312
|
+
and preferentially bid on tasks which have a lowest cost for them.
|
|
313
|
+
|
|
314
|
+
Parameters
|
|
315
|
+
----------
|
|
316
|
+
|
|
317
|
+
bid : dict
|
|
318
|
+
A dictionary containing the ruleID, the IDs of the tasks to bid on, and their costs
|
|
319
|
+
``{"ruleID" : str ,"taskIDs" : [list of int],"taskCosts" : [list of float]}``
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
|
|
324
|
+
successful_bids: dict
|
|
325
|
+
A dictionary containing the ruleID, the IDs of the tasks awarded, and the rule template
|
|
326
|
+
``{"ruleID" : ruleID, "taskIDs": [list of int], "template" : "<rule template>"}``
|
|
327
|
+
|
|
328
|
+
"""
|
|
329
|
+
if not self._active:
|
|
330
|
+
# don't accept any bids
|
|
331
|
+
return {'ruleID': bid['ruleID'], 'taskIDs':[], 'template' : ''}
|
|
332
|
+
|
|
333
|
+
taskIDs = np.array(bid['taskIDs'], 'i')
|
|
334
|
+
costs = np.array(bid['costs'], 'f4')
|
|
335
|
+
|
|
336
|
+
if np.all(costs < self.COST_THRESHOLD):
|
|
337
|
+
# all tasks are below the "Buy Now" threshold, take a shortcut and directly award them to the bidder bypassing
|
|
338
|
+
# the rest of the biddng process. This enables high performance on localisation tasks
|
|
339
|
+
pass
|
|
340
|
+
else:
|
|
341
|
+
# NOTE: this bidding code is not high-performance. This is probably OK as code is bypassed in normal
|
|
342
|
+
# localisation scenario but might need to be revisited as it will be triggered in mixed cases where
|
|
343
|
+
# some bids are local and some are not.
|
|
344
|
+
with self._info_lock:
|
|
345
|
+
# get a unique bidder ID
|
|
346
|
+
self._current_bidder_id += 1
|
|
347
|
+
bidder_id = self._current_bidder_id
|
|
348
|
+
|
|
349
|
+
# record bids
|
|
350
|
+
for taskID, cost in zip(taskIDs, costs):
|
|
351
|
+
# get existing winning bid
|
|
352
|
+
_, winning_cost = self._pending_bids.get(taskID, DEFAULT_BID)
|
|
353
|
+
if cost < winning_cost:
|
|
354
|
+
# if we have a lower cost, over-write the winning bid
|
|
355
|
+
self._pending_bids[taskID] = Bid(bidder_id, cost)
|
|
356
|
+
|
|
357
|
+
#wait for other bids
|
|
358
|
+
time.sleep(0.2) #TODO - make this time configurable??
|
|
359
|
+
|
|
360
|
+
with self._info_lock:
|
|
361
|
+
# filter our tasks to only keep the wining ones
|
|
362
|
+
winners = [self._pending_bids[taskID].bidder_id==bidder_id for taskID in taskIDs]
|
|
363
|
+
|
|
364
|
+
taskIDs = taskIDs[winners]
|
|
365
|
+
costs = costs[winners]
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
with self._info_lock:
|
|
369
|
+
successful_bid_mask = self._task_info['status'][taskIDs] == STATUS_AVAILABLE
|
|
370
|
+
successful_bid_ids = taskIDs[successful_bid_mask]
|
|
371
|
+
self._task_info['status'][successful_bid_ids] = STATUS_ASSIGNED
|
|
372
|
+
self._task_info['cost'][successful_bid_ids] = costs[successful_bid_mask]
|
|
373
|
+
self._task_info['expiry'][successful_bid_ids] = time.time() + self._timeout
|
|
374
|
+
|
|
375
|
+
nTasks = len(successful_bid_ids)
|
|
376
|
+
self.nAvailable -= nTasks
|
|
377
|
+
self.nAssigned += nTasks
|
|
378
|
+
|
|
379
|
+
self._update_cost()
|
|
380
|
+
|
|
381
|
+
self.expiry = time.time() + self._rule_timeout
|
|
382
|
+
|
|
383
|
+
with self._advert_lock:
|
|
384
|
+
self._cached_advert = None
|
|
385
|
+
|
|
386
|
+
return {'ruleID': bid['ruleID'], 'taskIDs':successful_bid_ids.tolist(), 'template' : self._template}
|
|
387
|
+
|
|
388
|
+
def mark_complete(self, info):
|
|
389
|
+
"""
|
|
390
|
+
Mark a set of tasks as completed and/or failed
|
|
391
|
+
|
|
392
|
+
Parameters
|
|
393
|
+
----------
|
|
394
|
+
info : dict
|
|
395
|
+
A dictionary of the form: ``{"ruleID": str, "taskIDs" : [list of int], "status" : [list of int]}``
|
|
396
|
+
|
|
397
|
+
There should be an entry in status for each entry in taskIDs, the valid values of status being
|
|
398
|
+
``STATUS_COMPLETE=3`` or ``STATUS_FAILED=4``.
|
|
399
|
+
|
|
400
|
+
Returns
|
|
401
|
+
-------
|
|
402
|
+
|
|
403
|
+
"""
|
|
404
|
+
taskIDs = np.array(info['taskIDs'], 'i')
|
|
405
|
+
status = np.array(info['status'], 'uint8')
|
|
406
|
+
|
|
407
|
+
with self._info_lock:
|
|
408
|
+
old_status = np.copy(self._task_info['status'][taskIDs])
|
|
409
|
+
self._task_info['status'][taskIDs] = status
|
|
410
|
+
|
|
411
|
+
# if tasks have timed out (or results have already been recieved), they will register as not assigned
|
|
412
|
+
n_not_assigned = int((old_status != STATUS_ASSIGNED).sum())
|
|
413
|
+
|
|
414
|
+
# if we re-queue tasks after timeout we might receive answers from the re-queued tasks twice
|
|
415
|
+
n_already_complete = int((old_status == STATUS_COMPLETE).sum())
|
|
416
|
+
n_already_failed = int((old_status == STATUS_FAILED).sum())
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
self.nCompleted += (int((status == STATUS_COMPLETE).sum()) - n_already_complete)
|
|
420
|
+
self.nFailed += (int((status == STATUS_FAILED).sum()) - n_already_failed)
|
|
421
|
+
|
|
422
|
+
self.n_repeats += (n_already_complete + n_already_failed)
|
|
423
|
+
self.n_returned_after_timeout += n_not_assigned
|
|
424
|
+
self.nAvailable -= (n_not_assigned - (n_already_complete + n_already_failed))
|
|
425
|
+
|
|
426
|
+
nTasks = len(taskIDs) - n_not_assigned#(n_already_complete + n_already_failed)
|
|
427
|
+
self.nAssigned -= nTasks
|
|
428
|
+
|
|
429
|
+
self.expiry = time.time() + self._rule_timeout
|
|
430
|
+
|
|
431
|
+
@property
|
|
432
|
+
def advert(self):
|
|
433
|
+
""" The task advertisment.
|
|
434
|
+
|
|
435
|
+
If the rule has tasks available, a dictionary of the form:
|
|
436
|
+
``{"ruleID" : str, "taskTemplate" : str, "availableTaskIDs" : [list of int], "inputsByTask" : [optional] dict mapping task IDs to inputs}``
|
|
437
|
+
|
|
438
|
+
"inputsByTask" is only provided for some recipe tasks.
|
|
439
|
+
"""
|
|
440
|
+
if not self._active:
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
with self._advert_lock:
|
|
444
|
+
if not self._cached_advert:
|
|
445
|
+
availableTasks = np.where(self._task_info['status'] == STATUS_AVAILABLE)[0].tolist()
|
|
446
|
+
|
|
447
|
+
if len(availableTasks) == 0:
|
|
448
|
+
self._cached_advert = None
|
|
449
|
+
else:
|
|
450
|
+
self._cached_advert = {'ruleID' : self.ruleID,
|
|
451
|
+
'taskTemplate': self._template,
|
|
452
|
+
'availableTaskIDs': availableTasks}
|
|
453
|
+
|
|
454
|
+
#print self._inputs_by_task
|
|
455
|
+
|
|
456
|
+
if not self._inputs_by_task is None:
|
|
457
|
+
self._cached_advert['inputsByTask'] = {taskID: self._inputs_by_task[taskID] for taskID in availableTasks}
|
|
458
|
+
|
|
459
|
+
return self._cached_advert
|
|
460
|
+
|
|
461
|
+
# @property
|
|
462
|
+
# def nAvailable(self):
|
|
463
|
+
# return (self._task_info['status'] == STATUS_AVAILABLE).sum()
|
|
464
|
+
#
|
|
465
|
+
# @property
|
|
466
|
+
# def nAssigned(self):
|
|
467
|
+
# return (self._task_info['status'] == STATUS_ASSIGNED).sum()
|
|
468
|
+
|
|
469
|
+
# @property
|
|
470
|
+
# def nCompleted(self):
|
|
471
|
+
# return (self._task_info['status'] == STATUS_COMPLETE).sum()
|
|
472
|
+
|
|
473
|
+
# @property
|
|
474
|
+
# def nFailed(self):
|
|
475
|
+
# return (self._task_info['status'] == STATUS_FAILED).sum()
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
@property
|
|
479
|
+
def expired(self):
|
|
480
|
+
""" Whether the rule has expired (no available tasks, no tasks assigned, and time > expiry) and can be removed"""
|
|
481
|
+
return (self.nAvailable == 0) and (self.nAssigned == 0) and (time.time() > self.expiry)
|
|
482
|
+
|
|
483
|
+
@property
|
|
484
|
+
def finished(self):
|
|
485
|
+
"""
|
|
486
|
+
Whether the rule has finished (the maximum number of tasks which can be created have been completed).
|
|
487
|
+
"""
|
|
488
|
+
|
|
489
|
+
# TODO - change this so that we can release starting at task_ID > 0????
|
|
490
|
+
# TODO - make rules finish when some tasks fail.
|
|
491
|
+
|
|
492
|
+
# To fix: Potentially replace with `np.all(self._task_info['status']>=STATUS_COMPLETE)` (although this would need to be cached and refreshed - property access should be cheap).
|
|
493
|
+
# combined with a new enum value STATUS_INVALID==6 - `self.mark_release_complete()` could be re-written as `self._task_info['status'][self._task_info['status'] == 0] = STATUS_INVALID`
|
|
494
|
+
|
|
495
|
+
return (self.nAvailable == 0) and ((self.nCompleted + self.nFailed) >= self._n_max)
|
|
496
|
+
|
|
497
|
+
def inactivate(self):
|
|
498
|
+
"""
|
|
499
|
+
Mark rule as inactive (generates no adverts) to facilitate aborting / pausing long-running rules.
|
|
500
|
+
"""
|
|
501
|
+
self._active = False
|
|
502
|
+
|
|
503
|
+
def info(self):
|
|
504
|
+
"""
|
|
505
|
+
Get information / status about this rule
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
|
|
510
|
+
status : dict
|
|
511
|
+
A status dictionary of the form:
|
|
512
|
+
``{'tasksPosted': int, 'tasksRunning': int, 'tasksCompleted': int, 'tasksFailed' : int, 'averageExecutionCost' : float}``
|
|
513
|
+
|
|
514
|
+
"""
|
|
515
|
+
return {'tasksPosted': self.nTotal,
|
|
516
|
+
'tasksRunning': self.nAssigned,
|
|
517
|
+
'tasksCompleted': self.nCompleted,
|
|
518
|
+
'tasksFailed' : self.nFailed,
|
|
519
|
+
'averageExecutionCost' : self.avCost,
|
|
520
|
+
'active' : self._active,
|
|
521
|
+
'tasksTimedOut' : self.n_timed_out,
|
|
522
|
+
'tasksCompleteAfterTimeout' : self.n_returned_after_timeout,
|
|
523
|
+
'finished' : self.finished,
|
|
524
|
+
'expired' : self.expired,
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
def poll_timeouts(self):
|
|
528
|
+
t = time.time()
|
|
529
|
+
|
|
530
|
+
with self._info_lock:
|
|
531
|
+
timed_out = np.where((self._task_info['status'] == STATUS_ASSIGNED)*(self._task_info['expiry'] < t))[0]
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
nTimedOut = len(timed_out)
|
|
535
|
+
if nTimedOut > 0:
|
|
536
|
+
self._task_info['status'][timed_out] = STATUS_AVAILABLE
|
|
537
|
+
self._task_info['nRetries'][timed_out] += 1
|
|
538
|
+
|
|
539
|
+
self.nAssigned -= nTimedOut
|
|
540
|
+
self.nAvailable += nTimedOut
|
|
541
|
+
|
|
542
|
+
self.n_timed_out += nTimedOut
|
|
543
|
+
|
|
544
|
+
retry_failed = self._task_info['nRetries'][timed_out] > self._n_retries
|
|
545
|
+
self._task_info['status'][timed_out[retry_failed]] = STATUS_FAILED
|
|
546
|
+
self.nAvailable -= int(retry_failed.sum())
|
|
547
|
+
self.nFailed += int(retry_failed.sum())
|
|
548
|
+
|
|
549
|
+
#self._update_nums()
|
|
550
|
+
|
|
551
|
+
with self._advert_lock:
|
|
552
|
+
self._cached_advert = None
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
class RuleServer(object):
|
|
560
|
+
MAX_ADVERTISEMENTS = 5 * 10 * 50 * 12 #only advertise enough for 100 tasks on each core of each cluster node
|
|
561
|
+
def __init__(self):
|
|
562
|
+
self._rules = collections.OrderedDict()
|
|
563
|
+
|
|
564
|
+
#cherrypy.engine.subscribe('stop', self.stop)
|
|
565
|
+
|
|
566
|
+
self._do_poll = True
|
|
567
|
+
|
|
568
|
+
self._queueLock = threading.Lock()
|
|
569
|
+
|
|
570
|
+
self._advert_lock = threading.Lock()
|
|
571
|
+
|
|
572
|
+
#set up threads to poll the distributor and announce ourselves and get and return tasks
|
|
573
|
+
#self.pollThread = threading.Thread(target=self._poll)
|
|
574
|
+
#self.pollThread.start()
|
|
575
|
+
|
|
576
|
+
self._cached_advert = None
|
|
577
|
+
self._cached_advert_expiry = 0
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
self._info_lock = threading.Lock()
|
|
581
|
+
self._cached_info = None
|
|
582
|
+
self._cached_info_expiry = 0
|
|
583
|
+
self._cached_info_timeout = 5
|
|
584
|
+
self._finished_rule_timeout = 60 # keep finished rules around for a minute (so we can see them in the GUI)
|
|
585
|
+
self._failed_finished_rule_timeout = 5*60 # keep rules with failures around for 5 mins to give us a chance to look at errors
|
|
586
|
+
|
|
587
|
+
self._rule_n = 0
|
|
588
|
+
|
|
589
|
+
self._rule_lock = threading.Lock() # lock for when we modify the dictionary of rules
|
|
590
|
+
|
|
591
|
+
self.rulePollThread = threading.Thread(target=self._poll_rules)
|
|
592
|
+
self.rulePollThread.start()
|
|
593
|
+
|
|
594
|
+
with open(os.path.join(resources.get_web_dir(), 'ruleserver.html'), 'r') as f:
|
|
595
|
+
self._status_page = f.read()
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def _poll(self):
|
|
599
|
+
while self._do_poll:
|
|
600
|
+
time.sleep(1)
|
|
601
|
+
|
|
602
|
+
def _poll_rules(self):
|
|
603
|
+
while self._do_poll:
|
|
604
|
+
for qn in list(self._rules.keys()):
|
|
605
|
+
self._rules[qn].poll_timeouts()
|
|
606
|
+
|
|
607
|
+
# look for rules that have processed all tasks
|
|
608
|
+
if self._rules[qn].finished:
|
|
609
|
+
#with self._rule_lock:
|
|
610
|
+
# r = self._rules.pop(qn)
|
|
611
|
+
|
|
612
|
+
r = self._rules[qn]
|
|
613
|
+
if not r._seen_as_finished:
|
|
614
|
+
r._seen_as_finished = True # prevent following logic from executing twice
|
|
615
|
+
|
|
616
|
+
# shorten rule expiry (no need to keep lots of finished rules in memory)
|
|
617
|
+
if r.nFailed > 0:
|
|
618
|
+
# Allow a little more time if we have errors so we can click through to the diagnostics (TODO)
|
|
619
|
+
r.expiry = time.time() + self._failed_finished_rule_timeout
|
|
620
|
+
else:
|
|
621
|
+
# Allow some time so that rules can be seen as complete in the GUI
|
|
622
|
+
r.expiry = time.time() + self._finished_rule_timeout
|
|
623
|
+
|
|
624
|
+
follow_on = r.on_completion
|
|
625
|
+
if follow_on is not None:
|
|
626
|
+
# if a follow on rule is defined, add it
|
|
627
|
+
template = follow_on['template']
|
|
628
|
+
n_tasks = follow_on.get('max_tasks', 1)
|
|
629
|
+
timeout = follow_on.get('rule_timeout', 3600.)
|
|
630
|
+
ruleID = '%06d-%s' % (self._rule_n, uuid.uuid4().hex)
|
|
631
|
+
|
|
632
|
+
rule = IntegerIDRule(ruleID, template, max_task_ID=int(n_tasks),
|
|
633
|
+
rule_timeout=float(timeout), on_completion=follow_on.get('on_completion', None))
|
|
634
|
+
|
|
635
|
+
rule.make_range_available(0, int(n_tasks))
|
|
636
|
+
|
|
637
|
+
with self._rule_lock:
|
|
638
|
+
self._rules[ruleID] = rule
|
|
639
|
+
|
|
640
|
+
self._rule_n += 1
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
#remore queue if expired (no activity for an hour) to free up memory
|
|
644
|
+
if self._rules[qn].expired:
|
|
645
|
+
logger.debug('removing expired rule: %s' % self._rules[qn].ruleID)
|
|
646
|
+
with self._rule_lock:
|
|
647
|
+
r = self._rules.pop(qn)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
time.sleep(5)
|
|
651
|
+
|
|
652
|
+
def stop(self):
|
|
653
|
+
self._do_poll = False
|
|
654
|
+
|
|
655
|
+
#for queue in self._queues.values():
|
|
656
|
+
# queue.stop()
|
|
657
|
+
|
|
658
|
+
@webframework.register_endpoint('/task_advertisements')
|
|
659
|
+
def task_advertisements(self):
|
|
660
|
+
"""
|
|
661
|
+
HTTP endpoint (GET) for retrieving task advertisements.
|
|
662
|
+
|
|
663
|
+
Note - by default, a limited number of advertisements are posted at any given time (to limit bandwidth). This
|
|
664
|
+
should be enough to keep all the workers busy, with new adverts being posted once tasks are assigned to workers.
|
|
665
|
+
|
|
666
|
+
Returns
|
|
667
|
+
-------
|
|
668
|
+
|
|
669
|
+
adverts : json str
|
|
670
|
+
List of advertisements. See :attr:`IntegerIDRule.advert`
|
|
671
|
+
|
|
672
|
+
"""
|
|
673
|
+
with self._advert_lock:
|
|
674
|
+
t = time.time()
|
|
675
|
+
if (t > self._cached_advert_expiry):
|
|
676
|
+
adverts = []
|
|
677
|
+
nTasks = 0
|
|
678
|
+
ruleN = 0
|
|
679
|
+
|
|
680
|
+
rules = list(self._rules.values())
|
|
681
|
+
while ruleN < len(rules) and nTasks < self.MAX_ADVERTISEMENTS:
|
|
682
|
+
advert = rules[ruleN].advert
|
|
683
|
+
|
|
684
|
+
if not advert is None:
|
|
685
|
+
adverts.append(advert)
|
|
686
|
+
nTasks += len(advert['availableTaskIDs'])
|
|
687
|
+
|
|
688
|
+
ruleN += 1
|
|
689
|
+
|
|
690
|
+
self._cached_advert = json.dumps(adverts)
|
|
691
|
+
self._cached_advert_expiry = time.time() + 1 #regenerate advert once every second
|
|
692
|
+
|
|
693
|
+
return self._cached_advert
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
@webframework.register_endpoint('/bid_on_tasks')
|
|
697
|
+
def bid_on_tasks(self, body=''):
|
|
698
|
+
"""
|
|
699
|
+
HTTP endpoint (POST) for bidding on tasks.
|
|
700
|
+
|
|
701
|
+
Parameters
|
|
702
|
+
----------
|
|
703
|
+
body : json list of bids
|
|
704
|
+
A list of bids, each of which is a dictionary of the form
|
|
705
|
+
``{"ruleID" : str ,"taskIDs" : [list of int],"taskCosts" : [list of float]}``
|
|
706
|
+
see :meth:`IntegerIDRule.Bid` for details.
|
|
707
|
+
|
|
708
|
+
Returns
|
|
709
|
+
-------
|
|
710
|
+
assignments: json str
|
|
711
|
+
A json formatted list of task assignments, each of which has the form:
|
|
712
|
+
``{"ruleID" : ruleID, "taskIDs": [list of int], "template" : "<rule template>"}``
|
|
713
|
+
See :meth:`IntegerIDTask.bid`
|
|
714
|
+
|
|
715
|
+
"""
|
|
716
|
+
bids = json.loads(body)
|
|
717
|
+
|
|
718
|
+
succesfull_bids = []
|
|
719
|
+
|
|
720
|
+
for bid in bids:
|
|
721
|
+
rule = self._rules[bid['ruleID']]
|
|
722
|
+
|
|
723
|
+
succesfull_bids.append(rule.bid(bid))
|
|
724
|
+
#task_ids = bid['taskIDs']
|
|
725
|
+
#costs = bid['taskCosts']
|
|
726
|
+
|
|
727
|
+
#print(succesfull_bids)
|
|
728
|
+
return json.dumps(succesfull_bids)
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
@webframework.register_endpoint('/add_integer_id_rule')
|
|
733
|
+
def add_integer_id_rule(self, max_tasks= 1e6, release_start=None, release_end = None, ruleID = None, timeout=3600, body=''):
|
|
734
|
+
"""
|
|
735
|
+
HTTP endpoint (POST) for adding a new rule.
|
|
736
|
+
|
|
737
|
+
Add a rule that generates tasks based on an integer ID, such as a frame number (localization) or an index into
|
|
738
|
+
a list of inputs (recipes). By default, tasks are not released on creation, but later with
|
|
739
|
+
:func:`release_rule_tasks()`. This allows for the creation of a rule before a series has finished spooling.
|
|
740
|
+
|
|
741
|
+
Parameters
|
|
742
|
+
----------
|
|
743
|
+
max_tasks : int
|
|
744
|
+
The maximum number of tasks that could match this rule. Generally the number of frames in a localization
|
|
745
|
+
series (if known in advance) or the number of inputs on which to run a recipe. Allows us to pre-allocate a
|
|
746
|
+
task array of the correct size (passing this rather than relying on the default reduces memory usage).
|
|
747
|
+
release_start, release_end : int
|
|
748
|
+
Release a range of tasks for computation after creating the rule (avoids a
|
|
749
|
+
call to `release_rule_tasks()`
|
|
750
|
+
ruleID : str
|
|
751
|
+
A unique identifier for the rule. If not provided, one will be automatically generated
|
|
752
|
+
timeout : int
|
|
753
|
+
How long this rule should live for, in seconds. Defaults to an hour.
|
|
754
|
+
body : str
|
|
755
|
+
A json dictionary ``{'template' : "<rule template>", 'inputsByTask' : [list of URIs]}``. See :class:`IntegerIDRule`
|
|
756
|
+
for the format of the rule template. The ``inputsByTask`` parameter is only used for recipes, and can be omitted
|
|
757
|
+
for localisation analysis, or for recipe tasks using a hard coded ``"inputs"`` dictionary. An optional additional
|
|
758
|
+
parameter, "on_completion" parameter may be given, itself consisting of a new
|
|
759
|
+
``{'template': <template>, 'on_completion': {...}}`` dictionary.
|
|
760
|
+
|
|
761
|
+
Returns
|
|
762
|
+
-------
|
|
763
|
+
|
|
764
|
+
result : json str
|
|
765
|
+
The result of adding the rule. A dict of the form:
|
|
766
|
+
``{"ok" : "True", 'ruleID' : str}``
|
|
767
|
+
|
|
768
|
+
"""
|
|
769
|
+
with self._rule_lock:
|
|
770
|
+
# lock ~entire call so we don't hit KeyErrors if clients immediately
|
|
771
|
+
# try to abort/mark datasource complete, etc. after posting
|
|
772
|
+
rule_info = json.loads(body)
|
|
773
|
+
|
|
774
|
+
if ruleID is None:
|
|
775
|
+
ruleID = '%06d-%s' % (self._rule_n, uuid.uuid4().hex)
|
|
776
|
+
|
|
777
|
+
rule = IntegerIDRule(ruleID, rule_info['template'], max_task_ID=int(max_tasks), rule_timeout=float(timeout),
|
|
778
|
+
inputs_by_task=rule_info.get('inputsByTask', None), on_completion=rule_info.get('on_completion', None))
|
|
779
|
+
|
|
780
|
+
#print rule._inputs_by_task
|
|
781
|
+
if not release_start is None:
|
|
782
|
+
rule.make_range_available(int(release_start), int(release_end))
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
self._rules[ruleID] = rule
|
|
786
|
+
|
|
787
|
+
self._rule_n += 1
|
|
788
|
+
|
|
789
|
+
return json.dumps({'ok': 'True', 'ruleID' : ruleID})
|
|
790
|
+
|
|
791
|
+
@webframework.register_endpoint('/release_rule_tasks')
|
|
792
|
+
def release_rule_tasks(self, ruleID, release_start, release_end, body=''):
|
|
793
|
+
"""
|
|
794
|
+
HTTP Endpoint (POST or GET ) for releasing tasks associated with a rule.
|
|
795
|
+
|
|
796
|
+
When performing spooling data analysis we typically have one rule per series and one task per frame.
|
|
797
|
+
This method allows for the tasks associated with a particular frame (or range of frames) to be released as they
|
|
798
|
+
become available.
|
|
799
|
+
|
|
800
|
+
Parameters
|
|
801
|
+
----------
|
|
802
|
+
ruleID : str
|
|
803
|
+
The rule ID
|
|
804
|
+
release_start, release_end: int
|
|
805
|
+
The range of tasks IDs to release
|
|
806
|
+
body : str, empty
|
|
807
|
+
Needed for interface compatibility, ignored
|
|
808
|
+
|
|
809
|
+
Returns
|
|
810
|
+
-------
|
|
811
|
+
|
|
812
|
+
success : json str
|
|
813
|
+
``{"ok" : "True"}`` if successful.
|
|
814
|
+
|
|
815
|
+
"""
|
|
816
|
+
with self._rule_lock:
|
|
817
|
+
# take out the lock in case the rule is still being added in another
|
|
818
|
+
# request and we are already trying to release tasks
|
|
819
|
+
rule = self._rules[ruleID]
|
|
820
|
+
|
|
821
|
+
logger.debug('release_rule_tasks(ruleID = %s, release_start=%d, release_end=%d)' % (ruleID, int(release_start), int(release_end )))
|
|
822
|
+
|
|
823
|
+
rule.make_range_available(int(release_start), int(release_end))
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
return json.dumps({'ok': 'True'})
|
|
827
|
+
|
|
828
|
+
@webframework.register_endpoint('/inactivate_rule')
|
|
829
|
+
def inactivate_rule(self, ruleID):
|
|
830
|
+
with self._rule_lock:
|
|
831
|
+
# take out the lock in case the rule is still being added in another
|
|
832
|
+
# request and we are already trying to abort
|
|
833
|
+
self._rules[ruleID].inactivate()
|
|
834
|
+
|
|
835
|
+
return json.dumps({'ok': 'True'})
|
|
836
|
+
|
|
837
|
+
@webframework.register_endpoint('/handin')
|
|
838
|
+
def handin(self, body):
|
|
839
|
+
"""
|
|
840
|
+
HTTP Endpoint (POST) to mark tasks as having been completed
|
|
841
|
+
|
|
842
|
+
Parameters
|
|
843
|
+
----------
|
|
844
|
+
body : json list
|
|
845
|
+
A list of entries of the form ``{"ruleID": str, "taskIDs" : [list of int], "status" : [list of int]}``
|
|
846
|
+
where status has the same length as taskIDs with each entry being either ``STATUS_COMPLETE`` or
|
|
847
|
+
``STATUS_FAILED``. See :meth:`IntegerIDRule.mark_complete`.
|
|
848
|
+
|
|
849
|
+
Returns
|
|
850
|
+
-------
|
|
851
|
+
|
|
852
|
+
success : json str
|
|
853
|
+
``{"ok" : "True"}`` if successful.
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
"""
|
|
857
|
+
|
|
858
|
+
#logger.debug('Handing in tasks...')
|
|
859
|
+
expired_rules = set()
|
|
860
|
+
for handin in json.loads(body):
|
|
861
|
+
ruleID = handin['ruleID']
|
|
862
|
+
try:
|
|
863
|
+
rule = self._rules[ruleID]
|
|
864
|
+
rule.mark_complete(handin)
|
|
865
|
+
except KeyError: # rule may have expired
|
|
866
|
+
expired_rules.add(ruleID)
|
|
867
|
+
|
|
868
|
+
if len(expired_rules) == 0:
|
|
869
|
+
return json.dumps({'ok': 'True'})
|
|
870
|
+
else:
|
|
871
|
+
# rulenodeserver currently ignores what we say here other than 'ok'
|
|
872
|
+
return json.dumps({'ok': 'False', 'error': str(expired_rules)})
|
|
873
|
+
|
|
874
|
+
@webframework.register_endpoint('/mark_release_complete')
|
|
875
|
+
def mark_release_complete(self, ruleID, n_tasks=None):
|
|
876
|
+
"""
|
|
877
|
+
|
|
878
|
+
HTTP Endpoint (POST) to signal that no more tasks will be released for a rule and the rule can be regarded as finished once the previously released
|
|
879
|
+
tasks are complete.
|
|
880
|
+
|
|
881
|
+
Parameters
|
|
882
|
+
----------
|
|
883
|
+
rule_id : str
|
|
884
|
+
ID of the rule to update
|
|
885
|
+
n_tasks : int, [optional, discouraged]
|
|
886
|
+
a fixed number of tasks to truncate the rule at. Used for avoiding locks/race conditions in a multi-threaded client process. NOTE - this parameter
|
|
887
|
+
may disappear in a future version to enable rules with incomplete ranges to be marked as complete (see comments in `IntegerIDRule.finished`). Locking or
|
|
888
|
+
otherwise structuring the client such that no `release_rule_tasks()` calls can occur after a call to `mark_release_complete()` is therefore preferred.
|
|
889
|
+
|
|
890
|
+
Returns
|
|
891
|
+
-------
|
|
892
|
+
success : str
|
|
893
|
+
``{"ok" : "True"}`` if successful.
|
|
894
|
+
|
|
895
|
+
Raises
|
|
896
|
+
------
|
|
897
|
+
ValueError
|
|
898
|
+
If `value` is less than number of tasks already assigned.
|
|
899
|
+
|
|
900
|
+
FIXME - HTTP endpoints should not raise - they should handle the error and return an error response to the client.
|
|
901
|
+
"""
|
|
902
|
+
if n_tasks is not None:
|
|
903
|
+
n_tasks = int(n_tasks)
|
|
904
|
+
|
|
905
|
+
# take out the rule lock in case we are still creating the rule and the
|
|
906
|
+
# client POSTs this (e.g. if a series is started/stopped quickly)
|
|
907
|
+
with self._rule_lock:
|
|
908
|
+
self._rules[ruleID].mark_release_complete(n_tasks)
|
|
909
|
+
return json.dumps({'ok': 'True'})
|
|
910
|
+
|
|
911
|
+
@webframework.register_endpoint('/distributor/queues')
|
|
912
|
+
def get_queues(self):
|
|
913
|
+
"""
|
|
914
|
+
HTTP Endpoint (GET) - visible at "distributor/queues" - for querying ruleserver status.
|
|
915
|
+
|
|
916
|
+
Returns
|
|
917
|
+
-------
|
|
918
|
+
|
|
919
|
+
status: json str
|
|
920
|
+
A dictionary of the form ``{"ok" : True, "result" : {ruleID0 : rule0.info(), ruleID1 : rule1.info()}}``
|
|
921
|
+
See :meth:`IntegerIDRule.info`.
|
|
922
|
+
"""
|
|
923
|
+
with self._info_lock:
|
|
924
|
+
t = time.time()
|
|
925
|
+
if (t > self._cached_info_expiry):
|
|
926
|
+
with self._rule_lock:
|
|
927
|
+
self._cached_info = json.dumps({'ok': True, 'result': {qn: self._rules[qn].info() for qn in self._rules.keys()}})
|
|
928
|
+
self._cached_info_expiry = time.time() + self._cached_info_timeout
|
|
929
|
+
|
|
930
|
+
return self._cached_info
|
|
931
|
+
|
|
932
|
+
@webframework.register_endpoint('/queue_info_longpoll')
|
|
933
|
+
def get_queue_info(self):
|
|
934
|
+
"""
|
|
935
|
+
a throttled version of queue info
|
|
936
|
+
|
|
937
|
+
Returns
|
|
938
|
+
-------
|
|
939
|
+
|
|
940
|
+
"""
|
|
941
|
+
time.sleep(0.5)
|
|
942
|
+
return self.get_queues()
|
|
943
|
+
|
|
944
|
+
@webframework.register_endpoint('/', mimetype='text/html')
|
|
945
|
+
def status(self):
|
|
946
|
+
return self._status_page
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
# class CPRuleServer(RuleServer):
|
|
950
|
+
# @cherrypy.expose
|
|
951
|
+
# def add_integer_rule(self, queue=None, nodeID=None, numWant=50, timeout=5):
|
|
952
|
+
# cherrypy.response.headers['Content-Type'] = 'application/json'
|
|
953
|
+
#
|
|
954
|
+
# body = ''
|
|
955
|
+
# #if cherrypy.request.method == 'GET':
|
|
956
|
+
#
|
|
957
|
+
# if cherrypy.request.method == 'POST':
|
|
958
|
+
# body = cherrypy.request.body.read()
|
|
959
|
+
#
|
|
960
|
+
# return self._tasks(queue, nodeID, numWant, timeout, body)
|
|
961
|
+
#
|
|
962
|
+
# @cherrypy.expose
|
|
963
|
+
# def handin(self, nodeID):
|
|
964
|
+
# cherrypy.response.headers['Content-Type'] = 'application/json'
|
|
965
|
+
#
|
|
966
|
+
# body = cherrypy.request.body.read()
|
|
967
|
+
#
|
|
968
|
+
# return self._handin(nodeID, body)
|
|
969
|
+
#
|
|
970
|
+
# @cherrypy.expose
|
|
971
|
+
# def announce(self, nodeID, ip, port):
|
|
972
|
+
# cherrypy.response.headers['Content-Type'] = 'application/json'
|
|
973
|
+
#
|
|
974
|
+
# self._announce(nodeID, ip, port)
|
|
975
|
+
#
|
|
976
|
+
# @cherrypy.expose
|
|
977
|
+
# def queues(self):
|
|
978
|
+
# cherrypy.response.headers['Content-Type'] = 'application/json'
|
|
979
|
+
#
|
|
980
|
+
# return self._get_queues()
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
class WFRuleServer(webframework.APIHTTPServer, RuleServer):
|
|
984
|
+
"""
|
|
985
|
+
Combines the RuleServer with it's web framework.
|
|
986
|
+
|
|
987
|
+
Largely an artifact of initial experiments using cherrypy (allowed quickly switching between cherrypy
|
|
988
|
+
and our internal webframework).
|
|
989
|
+
"""
|
|
990
|
+
def __init__(self, port, bind_addr=''):
|
|
991
|
+
RuleServer.__init__(self)
|
|
992
|
+
|
|
993
|
+
server_address = (bind_addr, port)
|
|
994
|
+
webframework.APIHTTPServer.__init__(self, server_address)
|
|
995
|
+
self.daemon_threads = True
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
# def runCP(port):
|
|
999
|
+
# import socket
|
|
1000
|
+
# cherrypy.config.update({'server.socket_port': port,
|
|
1001
|
+
# 'server.socket_host': '0.0.0.0',
|
|
1002
|
+
# 'log.screen': False,
|
|
1003
|
+
# 'log.access_file': '',
|
|
1004
|
+
# 'log.error_file': '',
|
|
1005
|
+
# 'server.thread_pool': 50,
|
|
1006
|
+
# })
|
|
1007
|
+
#
|
|
1008
|
+
# logging.getLogger('cherrypy.access').setLevel(logging.ERROR)
|
|
1009
|
+
#
|
|
1010
|
+
# #externalAddr = socket.gethostbyname(socket.gethostname())
|
|
1011
|
+
#
|
|
1012
|
+
# distributor = CPRuleServer()
|
|
1013
|
+
#
|
|
1014
|
+
# app = cherrypy.tree.mount(distributor, '/distributor/')
|
|
1015
|
+
# app.log.access_log.setLevel(logging.ERROR)
|
|
1016
|
+
#
|
|
1017
|
+
# try:
|
|
1018
|
+
#
|
|
1019
|
+
# cherrypy.quickstart()
|
|
1020
|
+
# finally:
|
|
1021
|
+
# distributor._do_poll = False
|
|
1022
|
+
|
|
1023
|
+
|
|
1024
|
+
import threading
|
|
1025
|
+
|
|
1026
|
+
class ServerThread(threading.Thread):
|
|
1027
|
+
""""""
|
|
1028
|
+
def __init__(self, port, bind_addr='', profile=False):
|
|
1029
|
+
self.port = int(port)
|
|
1030
|
+
self._profile = profile
|
|
1031
|
+
self.bind_addr = bind_addr
|
|
1032
|
+
threading.Thread.__init__(self)
|
|
1033
|
+
|
|
1034
|
+
def run(self):
|
|
1035
|
+
""""""
|
|
1036
|
+
|
|
1037
|
+
if self._profile:
|
|
1038
|
+
from PYME.util import mProfile
|
|
1039
|
+
|
|
1040
|
+
mProfile.profileOn(['ruleserver.py', ])
|
|
1041
|
+
profileOutDir = config.get('dataserver-root', os.curdir) + '/LOGS/%s/mProf' % computerName.GetComputerName()
|
|
1042
|
+
|
|
1043
|
+
if self.bind_addr == '':
|
|
1044
|
+
import socket
|
|
1045
|
+
self.externalAddr = socket.gethostbyname(socket.gethostname())
|
|
1046
|
+
else:
|
|
1047
|
+
self.externalAddr = self.bind_addr
|
|
1048
|
+
|
|
1049
|
+
self.distributor = WFRuleServer(self.port, bind_addr=self.bind_addr)
|
|
1050
|
+
|
|
1051
|
+
logger.info('Starting ruleserver on %s:%d' % (self.externalAddr, self.port))
|
|
1052
|
+
try:
|
|
1053
|
+
self.distributor.serve_forever()
|
|
1054
|
+
finally:
|
|
1055
|
+
self.distributor._do_poll = False
|
|
1056
|
+
#logger.info('Shutting down ...')
|
|
1057
|
+
#self.distributor.shutdown()
|
|
1058
|
+
logger.info('Closing server ...')
|
|
1059
|
+
self.distributor.server_close()
|
|
1060
|
+
|
|
1061
|
+
if self._profile:
|
|
1062
|
+
mProfile.report(False, profiledir=profileOutDir)
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
def shutdown(self):
|
|
1066
|
+
self.distributor._do_poll = False
|
|
1067
|
+
logger.info('Shutting down ...')
|
|
1068
|
+
self.distributor.shutdown()
|
|
1069
|
+
logger.info('Closing server ...')
|
|
1070
|
+
self.distributor.server_close()
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
def on_SIGHUP(signum, frame):
|
|
1074
|
+
""""""
|
|
1075
|
+
from PYME.util import mProfile
|
|
1076
|
+
mProfile.report(False, profiledir=profileOutDir)
|
|
1077
|
+
raise RuntimeError('Recieved SIGHUP')
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
if __name__ == '__main__':
|
|
1081
|
+
import signal
|
|
1082
|
+
|
|
1083
|
+
port = sys.argv[1]
|
|
1084
|
+
|
|
1085
|
+
if (len(sys.argv) == 3) and (sys.argv[2] == '-k'):
|
|
1086
|
+
profile = True
|
|
1087
|
+
from PYME.util import mProfile
|
|
1088
|
+
|
|
1089
|
+
mProfile.profileOn(['ruleserver.py', ])
|
|
1090
|
+
profileOutDir = config.get('dataserver-root', os.curdir) + '/LOGS/%s/mProf' % computerName.GetComputerName()
|
|
1091
|
+
else:
|
|
1092
|
+
profile = False
|
|
1093
|
+
profileOutDir = None
|
|
1094
|
+
|
|
1095
|
+
if not sys.platform == 'win32':
|
|
1096
|
+
#windows doesn't support handling signals ... don't catch and hope for the best.
|
|
1097
|
+
#Note: This will make it hard to cleanly shutdown the distributor on Windows, but should be OK for testing and
|
|
1098
|
+
#development
|
|
1099
|
+
signal.signal(signal.SIGHUP, on_SIGHUP)
|
|
1100
|
+
|
|
1101
|
+
try:
|
|
1102
|
+
run(int(port))
|
|
1103
|
+
finally:
|
|
1104
|
+
if profile:
|
|
1105
|
+
mProfile.report(False, profiledir=profileOutDir)
|
|
1106
|
+
|