diff --git a/Code/Mantid/docs/source/algorithms/AlignAndFocusPowder-v1.rst b/Code/Mantid/docs/source/algorithms/AlignAndFocusPowder-v1.rst index 0320223ce49e61458ff9c7fad2c13e2dec50e41c..2477b9d64b38c005874a08b7ef7830fa646f5dd0 100644 --- a/Code/Mantid/docs/source/algorithms/AlignAndFocusPowder-v1.rst +++ b/Code/Mantid/docs/source/algorithms/AlignAndFocusPowder-v1.rst @@ -32,6 +32,11 @@ sub-algorithms as listed below. #. :ref:`algm-EditInstrumentGeometry` (if appropriate) #. :ref:`algm-ConvertUnits` to time-of-flight +Workflow +######## + +.. diagram:: AlignAndFocusPowder-v1_wkflw.dot + Usage ----- @@ -46,15 +51,4 @@ The files needed for this example are not present in our standard usage data dow CalFileName='pg3_mantid_det.cal', Params='100') - - - - - - -.. image:: /images/AlignAndFocusPowderFlowchart.png - .. categories:: - - - diff --git a/Code/Mantid/docs/source/algorithms/DgsAbsoluteUnitsReduction-v1.rst b/Code/Mantid/docs/source/algorithms/DgsAbsoluteUnitsReduction-v1.rst index 9fbbcde5bd3cdf8c3f5ec9aa97326668f8fc1cd6..e563d679de49ee411950d51012ec2c7aac344077 100644 --- a/Code/Mantid/docs/source/algorithms/DgsAbsoluteUnitsReduction-v1.rst +++ b/Code/Mantid/docs/source/algorithms/DgsAbsoluteUnitsReduction-v1.rst @@ -65,8 +65,7 @@ with the cross-section units of :math:`millibarns/steradian`. Workflow ######## -.. figure:: /images/DgsAbsoluteUnitsReductionWorkflow.png - :alt: DgsAbsoluteUnitsReductionWorkflow.png +.. diagram:: DgsAbsoluteUnitsReduction-v1_wkflw.dot Usage ----- diff --git a/Code/Mantid/docs/source/algorithms/DgsReduction-v1.rst b/Code/Mantid/docs/source/algorithms/DgsReduction-v1.rst index e5728c4127e5c52543d9b43a7c10bd4200477ef6..cd0050dacbad961cf5a3a3e5c3bfb343c874ea87 100644 --- a/Code/Mantid/docs/source/algorithms/DgsReduction-v1.rst +++ b/Code/Mantid/docs/source/algorithms/DgsReduction-v1.rst @@ -22,8 +22,7 @@ They will be detailed in the child algorithm diagrams. Items in parallelograms are output workspaces from their respective algorithms. Not all output workspaces are subsequently used by other algorithms. -.. figure:: /images/DgsReductionWorkflow.png - :alt: DgsReductionWorkflow.png +.. diagram:: DgsReduction-v1_wkflw.dot Usage ----- diff --git a/Code/Mantid/docs/source/algorithms/DgsRemap-v1.rst b/Code/Mantid/docs/source/algorithms/DgsRemap-v1.rst index 5fb5dbefa3effa8bd652fbd11644024bf6da5334..8b4887ee8ac12a86f5fd8b6d70a9e631087bdd6c 100644 --- a/Code/Mantid/docs/source/algorithms/DgsRemap-v1.rst +++ b/Code/Mantid/docs/source/algorithms/DgsRemap-v1.rst @@ -16,8 +16,7 @@ then masking. Workflow ######## -.. figure:: /images/DgsRemapWorkflow.png - :alt: DgsRemapWorkflow.png +.. diagram:: DgsRemap-v1_wkflw.dot Usage ----- diff --git a/Code/Mantid/docs/source/algorithms/MuonLoad-v1.rst b/Code/Mantid/docs/source/algorithms/MuonLoad-v1.rst index 678f315baf77db5ee83631011af792b042d0b8be..88f1768100e8d416ba8614473ca3dfbd800a8a11 100644 --- a/Code/Mantid/docs/source/algorithms/MuonLoad-v1.rst +++ b/Code/Mantid/docs/source/algorithms/MuonLoad-v1.rst @@ -24,7 +24,7 @@ Specifically: Workflow ######## -.. image:: ../images/MuonWorkflow.png +.. diagram:: MuonLoad-v1_wkflw.dot Usage ----- diff --git a/Code/Mantid/docs/source/diagrams/AlignAndFocusPowder-v1_wkflw.dot b/Code/Mantid/docs/source/diagrams/AlignAndFocusPowder-v1_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..ecf7ba1b8fe8b0c9b5b52f634528420b303cac22 --- /dev/null +++ b/Code/Mantid/docs/source/diagrams/AlignAndFocusPowder-v1_wkflw.dot @@ -0,0 +1,99 @@ +digraph AlignAndFocusPowder { + label="AlignAndFocusPowder Flowchart" + $global_style + + subgraph params { + $param_style + InputWorkspace + OutputWorkspace + RemovePromptPulseWidth + CompressTolerance + CropWaveLengthMin + MaskWorkspace + CalFileName + OffsetsWorkspace + GroupingWorkspace + UnwrapRef + LowResRef + params1 [label="Params"] + params2 [label="Params"] + } + + subgraph algoritms { + $algorithm_style + removePromptPulse [label="RemovePromptPulse v1"] + compressEvents [label="CompressEvents v1"] + cropWorkspace [label="CropWorkspace v1"] + maskDetectors [label="MaskDetectors v1"] + rebin1 [label="Rebin v1"] + rebin2 [label="Rebin v1"] + resampleX [label="ResampleX v1"] + alignDetectors [label="AlignDetectors v1"] + convertUnits1 [label="ConvertUnits v1\nTime-of-Flight"] + convertUnits2 [label="ConvertUnits v1\nd-spacing"] + convertUnits3 [label="ConvertUnits v1\nTime-of-Flight"] + unwrapSNS [label="UnwrapSNS v1"] + removeLowResTOF [label="RemoveLowResTOF v1"] + diffFocus [label="DiffractionFocussing v2"] + sortEvents [label="SortEvents v1"] + editGeom [label="EditInstrumentGeometry v1"] + loadCalFile [label="LoadCalFile v1"] + } + + subgraph decisions { + $decision_style + isEventWorkspace1 [label="Is event workspace?"] + isEventWorkspace2 [label="Is event workspace?"] + isDspace1 [label="Is d-space binning?"] + isDspace2 [label="Is d-space binning?"] + ifParams [label="LRef, minwl, or\nDIFCref specified?"] + } + + + InputWorkspace -> isEventWorkspace1 + + isEventWorkspace1 -> removePromptPulse [label="Yes"] + RemovePromptPulseWidth -> removePromptPulse + removePromptPulse -> compressEvents + CompressTolerance -> compressEvents + compressEvents -> cropWorkspace + + isEventWorkspace1 -> cropWorkspace [label="No"] + CropWaveLengthMin -> cropWorkspace + + cropWorkspace -> maskDetectors + MaskWorkspace -> maskDetectors + maskDetectors -> isDspace1 + isDspace1 -> resampleX [label="Yes"] + resampleX -> alignDetectors + isDspace1 -> rebin1 [label="No"] + params1 -> rebin1 + rebin1 -> alignDetectors + OffsetsWorkspace -> alignDetectors + alignDetectors -> ifParams + + ifParams -> isDspace2 [label="No"] + ifParams -> convertUnits1 [label="Yes"] + convertUnits1 -> unwrapSNS + UnwrapRef -> unwrapSNS + unwrapSNS -> removeLowResTOF + LowResRef -> removeLowResTOF + removeLowResTOF -> convertUnits2 + convertUnits2 -> isDspace2 + + isDspace2 -> diffFocus [label="No"] + isDspace2 -> rebin2 [label="Yes"] + params2 -> rebin2 + rebin2 -> diffFocus + GroupingWorkspace -> diffFocus + diffFocus -> isEventWorkspace2 + isEventWorkspace2 -> sortEvents [label="Yes"] + isEventWorkspace2 -> editGeom [label="No"] + sortEvents -> editGeom + editGeom -> convertUnits3 + convertUnits3 -> OutputWorkspace + + CalFileName -> loadCalFile + loadCalFile -> OffsetsWorkspace + loadCalFile -> GroupingWorkspace +} diff --git a/Code/Mantid/docs/source/diagrams/AlignAndFocusPowderFlowchart.dot b/Code/Mantid/docs/source/diagrams/AlignAndFocusPowderFlowchart.dot deleted file mode 100644 index aeb7dc9d1f2b22e2e5db5c2f3a24bad66cbc9e37..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/diagrams/AlignAndFocusPowderFlowchart.dot +++ /dev/null @@ -1,46 +0,0 @@ -digraph { - label="AlignAndFocusPowder Flowchart" - LoadCalFile[shape="box", stype="rounded"] - RemovePromptPulse[shape="box", stype="rounded"] - CompressEvents_or_SortEvents[shape="box", stype="rounded"] - CropWorkspaces[shape="box", stype="rounded"] - MaskBinsFromTable[shape="box", stype="rounded"] - MaskDetectors[shape="box", stype="rounded"] - Rebin_or_ResampleX_ifTOF[shape="box", stype="rounded"] - AlignDetectors[shape="box", stype="rounded"] - ConvertUnits_to_TOF[shape="box", stype="rounded"] - UnwrapSNS[shape="box", stype="rounded"] - RemoveLowResTOF[shape="box", stype="rounded"] - ConvertUnits_to_dSpacing[shape="box", stype="rounded"] - SortEvents[shape="box", stype="rounded"] - DiffractionFocussing[shape="box", stype="rounded"] - SortEvents[shape="box", stype="rounded"] - Rebin_or_ResampleX_ifdSpacing[shape="box", stype="rounded"] - Rebin_or_ResampleX__ifdSpacing[shape="box", stype="rounded"] - EditInstrumentGeometry[shape="box", stype="rounded"] - ConjoinWorkspaces[shape="box", stype="rounded"] - ConvertUnits__to_TOF[shape="box", stype="rounded"] - CompressEvents[shape="box", stype="rounded"] - Rebin_or_ResampleX[shape="box", stype="rounded"] - - InputWorkspace -> RemovePromptPulse -> CompressEvents_or_SortEvents -> CropWorkspaces -> MaskBinsFromTable -> MaskDetectors -> Rebin_or_ResampleX_ifTOF -> AlignDetectors -> ConvertUnits_to_TOF -> UnwrapSNS -> RemoveLowResTOF -> ConvertUnits_to_dSpacing -> Rebin_or_ResampleX_ifdSpacing -> SortEvents -> DiffractionFocussing -> SortEvents -> Rebin_or_ResampleX__ifdSpacing -> EditInstrumentGeometry -> ConjoinWorkspaces -> ConvertUnits__to_TOF -> CompressEvents -> Rebin_or_ResampleX -> OutputWorkspace; - CalFileName -> LoadCalFile -> GroupingWorkspace -> DiffractionFocussing - LoadCalFile -> OffsetsWorkspace -> AlignDetectors - MaskWorkspace -> MaskDetectors - MaskBinTable -> MaskBinsFromTable - Params -> Rebin_or_ResampleX_ifTOF - Params -> Rebin_or_ResampleX_ifdSpacing - Params -> Rebin_or_ResampleX__ifdSpacing - Params -> Rebin_or_ResampleX - RemovePromptPulseWidth ->RemovePromptPulse - CompressTolerance -> CompressEvents_or_SortEvents - CompressTolerance -> CompressEvents - UnwrapRef -> UnwrapSNS - LowResRef -> RemoveLowResTOF - CropWaveLengthMin -> CropWorkspaces - PrimaryFlightPath -> EditInstrumentGeometry - SpectrumIDs -> EditInstrumentGeometry - L2 -> EditInstrumentGeometry - Polar -> EditInstrumentGeometry - Azimuthal -> EditInstrumentGeometry -} diff --git a/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReduction-v1_wkflw.dot b/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReduction-v1_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..6787c18f478858e23522791d43c6e7b83adaa8f2 --- /dev/null +++ b/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReduction-v1_wkflw.dot @@ -0,0 +1,76 @@ +digraph DgsReduction { + label = "DgsAbsoluteUnitsReduction Flowchart" + $global_style + + subgraph params { + $param_style + absUDWS [label="Absolute Units\nDetector Vanadium\nWorkspace"] + absUSWS [label="Absolute Units\nSample Workspace"] + absUMWS [label="Absolute Units\nMask Workspace"] + detDiagParam [label="Detector\nDiagnostic\nParameters"] + AbsUnitsIncidentEnergy + VanadiumMass + VanadiumRmm + AbsUnitsMinimumEnergy + AbsUnitsMaximumEnergy + MaskWorkspace + GroupingWorkspace + OutputWorkspace + } + + subgraph decisions { + $decision_style + isIAUDV [label="Is Integrated\nAbsolute Units\nDetector Vanadium?"] + } + + subgraph values { + $value_style + procSample [label="Processed\nSample\nWorkspace"] + pauw [label="Processed Absolute\nUnits Workspace"] + sampleCoeff [label="SampleMass\ndivided by\nSampleRmm\ndivided by\nScattering XSec"] + IAUDV [label="Integrated\nAbsolute Units\nDetector Vanadium"] + } + + subgraph algorithms { + $algorithm_style + DgsProcessDetectorVanadium + DgsConvertToEnergyTransfer + Divide + Rebin [label="Rebin (as integration)"] + ConvertToMatrixWorkspace + DetectorDiagnostic + MaskDetectors + ConvertFromDistribution + WeightedMeanOfWorkspace + Multiply + } + + absUDWS -> DgsProcessDetectorVanadium + MaskWorkspace -> DgsConvertToEnergyTransfer + MaskWorkspace -> DgsProcessDetectorVanadium + DgsProcessDetectorVanadium -> IAUDV + GroupingWorkspace -> DgsConvertToEnergyTransfer + absUSWS -> DgsConvertToEnergyTransfer + AbsUnitsIncidentEnergy -> DgsConvertToEnergyTransfer + IAUDV -> DgsConvertToEnergyTransfer + DgsConvertToEnergyTransfer -> Divide + VanadiumMass -> Divide + VanadiumRmm -> Divide + Divide -> Rebin + AbsUnitsMinimumEnergy -> Rebin + AbsUnitsMaximumEnergy -> Rebin + Rebin -> ConvertToMatrixWorkspace + ConvertToMatrixWorkspace -> DetectorDiagnostic + detDiagParam -> DetectorDiagnostic + DetectorDiagnostic -> procSample + procSample -> absUMWS + procSample -> MaskDetectors + MaskDetectors -> ConvertFromDistribution + ConvertFromDistribution -> WeightedMeanOfWorkspace + WeightedMeanOfWorkspace -> isIAUDV + sampleCoeff -> Multiply + isIAUDV -> Multiply [label="Yes"] + isIAUDV -> pauw [label="No"] + Multiply -> pauw + pauw -> OutputWorkspace +} diff --git a/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReductionWorkflow.xml b/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReductionWorkflow.xml deleted file mode 100644 index 3af1358267da9f77d28893810f44b55fb939c08e..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/diagrams/DgsAbsoluteUnitsReductionWorkflow.xml +++ /dev/null @@ -1 +0,0 @@ -<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.45 Safari/537.36"><diagram>7Vxbk6I4FP41Vs0+7JSI2vrYrd2z/dC7U3O7PG2lJWpqkFiA3fb++jmBHAgk7YBy01kfLEhCSL5zcq4JPXu22b/zyXb9wB3q9gZ9Z9+z573BYNLvw78oeMkVrHzmxEWWLNgxhwaZopBzN2TbbOGCex5dhJmyJXeznW3JimoFHxfE1Uu/Midcy8ENxmn5X5St1vgaazyNa4LwBftw6JLs3PDPqAjqRPWGYF/RNO1bgMbnHLoRV5v9jLoCHpx6jMXdK7XJIH3qyYEcfkAO4om4OznGnpiRvSc9++b6MeDuLqTQ4LPHwkCp+kg2W5jVoP+V+z+CLVnAdW6ywZpsxeVmvxJ0frt0+fNiTfzwrUNC8kgCqLxZMtedcZf70TP2HfxmMygPQp//oEpNP/olNUgCOX51whKDJ+qHVPJUVCQBeEf5hob+CzSRtcOppKFkONuOb59TMlsSxv5aIfGVLCOS21ZJzyngcCExN+MvX1Ua/zkNgaMBnEH/C/GIw3YbuFQaXAJdJL5IFnnbBFmGh8jyQIIfl8H51jQL8bggxEiZUyAeHYL4nc93W+atLgNmeyiXeQswS9GmwDxfBe99vqBBgEIklSCFEd7GPegAz2YC4oYBnmTZ2BrJHlSAkdVVgEcVAHxl4OMcjNRzrn2fP8PdwiVBwBaAAt2z8BuU9N+O5N13uLPk9XvqMxgKFdgJzAAb/0VpLm5F+6ROe8AB60UOgbqP/Pk2LbiJCqBCIMzAxIk6ce6AknIIDgnWVEzQYFDIooDvfFiUqhYLib+ispXkOzGMgxT0qUtC9pQ1sk6hx+R/eqD66gQ9pBWcFUAz7om5fuK3HvVXL5984gVLwOpcBZBtZSXQYCLVWxMSCN+tQHzvhRQQC4Fnjjcnk9o399ef51/+KKmAO6J8J1njHkilU+ZKCg2VMqikT6IMjrZrwkgRLkXkiYRQlSfIdM0LFMvks3ZMwnM/XPMV94hrEvNr7rP/uBfWIuilvK2OLtGjgCYRT2GDLWeekCBJz+9FQbrqEsGGJlk+DpFrb6N3d2T7gRXbIK+1H/alQDa3h4t4hikHJlAVY0qTI98FpvyVZXHQLinAjfWznk5LKyvSLQwQYhfxCpFPlWAKG51S7CienNZR2cUwzFkHaAlUxnymcMWZ27xFpJ+cZa0sWFgrmeIZr9PA414EQkKAKfBiSoKUIA0ToQjsyM3d0zqaVhjHb6hsoenRFDCqI2P63ltAMsILY4emhKkcAIzhv2LNdcFaHuUighbqcdVcxrLKzeULjKUUWlAG+7o9QaYHUNAlhMB3tPha4GzoAwxmJEINfqGNQSyV0VGxVs3oyWh1jD9syoRh64NYtChg/h2P90Ri2wjeuss4Z08gr8834GTnTNeRXLYqnJg/qDrgZMxanmFYQ8pYVeziTJqXu8acYxlQEcai9mMG0hTho5TfqxGNQupPsm5H6FDOkL8gOphc+hbpoNvaH+gj86DoDfQLDWWMm3GvTGi623J8aNp8Upsc1+1tdGcemMc2u02r3kz1Nt8olyi2pxKBJrwbQ2YyQZvsfwO0hyOpcBtBW8871mOjZIKp5SyWQkLZEOSqPplbLD46tOWLfxEfPSKygoGb48lVTusm1PqV1i0eLDfo4EIEliKoXgIX3o94csbybOlgskLbo4PusSZ7Jh5I6LP9MfviOmb7DAZAcFXAjPoGfTyWbaq2ftDSOncv1pSdR/ZpWkOMMIJTg4bQ/WPctTJnZOXxAMKvl7QWJk2uhVOd3vLWUqF9hQbjB/mgBZmse6TFdlddzobxUS6TPTZFzWs7K1EuPZRPsZ6UXk3slPwDkQumr4uo+BWLJaCrjcgUnpqHRX6sd3Uct+MhpxfGMjxdVSLW1n1pschQIZTJUnVdD1yhg9CIHtC9ZnlWQOwkVc8X4QGwAgeOzsGIwnWTWUuSyZrXNBjw+90S4UaJ1h4VdF9Y+mB3Pt/MGax+9rgT8ecLEjeTviEvW5e4Gepe7tfoFdR5oMT7Z3kBTq4lFlcGYVPmeyIFb+UIX4iTi1JAlQy4PluQDF3dcFkSVUQwg2prGb/hwSOhqh2i+FpKC+l2XcaJ0azMsPpXBiuwttPPuqN7v1SAjo4D9ey7MvjSBQuEptTwXUa/pvFFjSbxnRq2OWL2SkUXy05C9zQ3tg7JUUhWGGIxyCgtyArdAfybn6cMNti8uPpbwFV3AB/giyVs65bJS3fLBLNywQg4L2I4nVnXJgvsQ0H0O3y0ps6k2jHuXJGgVEXM3drWZvwswO/mViPi3RAxI93pi4NJLW4vP13IDDQ3D10WRchcTbFR5jMfuV0VR4Fq8vN0Aw0mAy+9IS5bgSk2X8B8BRfeIHNdy4oNc5yI+yoRv9mcwQS9DgWY2j4yo7sUMa+1t82+AkARrXY4zZQFA07rw7fSQuCm+Ks93z5SPRnbBvcNCnBfwqGVs1/TB5pO3k1z+OB6qfQUrr2O6H7dYUg/epF+B0PZSZBGHohPIvQq0U6t+LsWrvxkc4HsVVkFU0MIsoqdmLjrs3Mb6ktaUchBrWxGgNv0o5BxwjT9eKZ9+xM=</diagram></mxfile> \ No newline at end of file diff --git a/Code/Mantid/docs/source/diagrams/DgsReduction-v1_wkflw.dot b/Code/Mantid/docs/source/diagrams/DgsReduction-v1_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..b223146f629dee85915578a4e02815647cb35dd5 --- /dev/null +++ b/Code/Mantid/docs/source/diagrams/DgsReduction-v1_wkflw.dot @@ -0,0 +1,67 @@ +digraph DgsReduction { + label = "DgsReduction Flowchart" + $global_style + + subgraph params { + $param_style + Sample + HardMask + DetectorVanadium + ComparsionDetectorVanadium + Grouping + AbsoluteUnitsSample + AbsoluteUnitsDetectorVanadium + OutputWorkspace + } + + subgraph decisions { + $decision_style + isAbsUnits [label="Absolute\nUnits?"] + } + + subgraph algorithms { + $algorithm_style + DgsDiagnose + DgsProcessDetectorVanadium + DgsConvertToEnergyTransfer + DgsAbsoluteUnitsReduction + Divide + } + + subgraph values { + $value_style + detVanMask [label="DetVan\nDiag Mask"] + intDetVan [label="Integrated\nDetVan"] + procSamp [label="Processed\nSample"] + background [label="Time-independent\nbackground"] + procUnits [label="Processed\nAbsolute\nUnits"] + absUnits [label="Absolute\nUnits\nDiag Mask"] + SPhiE [label="S(φ, E)"] + } + + Sample -> DgsConvertToEnergyTransfer + Sample -> DgsDiagnose + HardMask -> DgsConvertToEnergyTransfer + HardMask -> DgsDiagnose + DetectorVanadium -> DgsDiagnose + DetectorVanadium -> DgsProcessDetectorVanadium + ComparsionDetectorVanadium -> DgsDiagnose + Grouping -> DgsConvertToEnergyTransfer + DgsDiagnose -> detVanMask + detVanMask -> DgsConvertToEnergyTransfer + detVanMask -> DgsProcessDetectorVanadium + DgsProcessDetectorVanadium -> intDetVan + intDetVan -> DgsConvertToEnergyTransfer + AbsoluteUnitsSample -> DgsAbsoluteUnitsReduction + AbsoluteUnitsDetectorVanadium -> DgsAbsoluteUnitsReduction + DgsAbsoluteUnitsReduction -> procUnits + DgsAbsoluteUnitsReduction -> absUnits + DgsConvertToEnergyTransfer -> background + DgsConvertToEnergyTransfer -> procSamp + procSamp -> isAbsUnits + isAbsUnits -> Divide [label="Yes"] + isAbsUnits -> SPhiE [label="No"] + procUnits -> Divide + Divide -> SPhiE + SPhiE -> OutputWorkspace +} diff --git a/Code/Mantid/docs/source/diagrams/DgsReductionWorkflow.xml b/Code/Mantid/docs/source/diagrams/DgsReductionWorkflow.xml deleted file mode 100644 index 75f4e54c463102d4aeb1a39f22dfd948eea246f9..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/diagrams/DgsReductionWorkflow.xml +++ /dev/null @@ -1 +0,0 @@ -<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.45 Safari/537.36"><diagram>7VxLc+K4Fv41qZpZhPIbvOyQR/eib6UmuTPTqyk1FsYVY1G2Sci/7yM4AskyDibEbROzoLAsydJ3Pp2XZC7s8Xx1l5LF7DsLaHxhGcHqwr6+sKyRYcA3L3gtFIRpFGyKTCxYRgHNlKKcsTiPFmrhhCUJneRK2ZTFamcLElKt4GFCYr30nyjIZzg4y9uVf6VROBOPMT1/cyfLX0UfAZ2SZZxfrovgHr89J6Kv9TTtG4AmZQy64b/mqzGNOTxi6hssbvfc3Q4ypQkOpLoBDuKZxEsc43WYXUckTFhGtfFnM7LgP+erkItuMI3Zy2RG0nywSNmEZgD71TSK4zGLWbpuYo/Ht/CB8ixP2ROV7hjrz/aOABVHJE8BZ/VM05wiS9ZFOKU7yuY0T1+hCt51fGOw6X7zwQ6QUOYICfWyk6NpY9lMkqGLZQTpFG4ftEMUfiCo5QDbOsA0BzICCpw69ooAAn+ThATRcl4D8CyH7/9MHXAO93jcMOCu4Q4cf/cZKYB7+AgJbx8Xhwy3dwK4HQ3uMZvD1KKMJRLg5ygDb4j4CdTNgSQR30cmNiAEVxOCBipNgi9pyl7gahKTLIsmgAldRfm/UGIMXLz6AVccX/77nqYRDIVyJDmCgFT6KlXnl7z+9l6xwVpc4qkJS2Aom7JbkN62YYBXJaoUizK2TCc4DwQVegkp1sLJ0kCxJ7rYUhqTPHpWzct7YEdpSrB/JWkgUfw7yZ46S2/ou4reoxEa4gb4bepKXSc4iP8BL2n8k73c7Ao4yxpnv8xs+yog2Yzy6az75+OD31wYEXg8BzEfNe0xzJftrpCqLKNt4cFLBJ9xzyIY8c7Qi35Ek834sZbsFYmGgonFhptZag3XRNlO7DDu6Bbq83EH12XPnZrc0Q3rA5kvgBZdVeqmpfqNQmNvHceBZQ5tH7xzx3aGo2FzKh492OOX6ceuyPevQUGmT70IQZMSPiFRbcErZCUDEk5Iwcc2kWs7Vm16PHaFY7ReiMfvN8G1CFqOiFRaFp57vhqaoE1EUG0Xe5RptqfJqcP1kgDyLmXLRZSEnVWyoCSr4IZUlXq7OS0rkmcq3ccs4ZN7ZDcJTcPXx5Qk2RQ0X1fpXkhGGRg9IPzOyFFv63FMY+RHyR9q9DCG/lBTd7QpQxh7h7JK4Gfv5ZRFGp+OGXW9HKvo5fgn9nL0TNWZ0a40O9JrpAO2S4R1VfZLwOOVk/ewPQVVamYzA5Lzxm1wyBzfqXTIxPKTiSAiA5kIzin2p/QdwE7YfBylvMAEd/oFViXvmrnrtshbCFfRqNi0F3jVjqiuUSsFztJ8xkKWkLgxi3vsRtunE39dR84TUaEYIFqMfeMo1rfxVMS++q6LkVd5/Xc7ik5N4/QWdw1fZu+Oy6f0GI9WZn1Y8gabzaHKNkisnJZteu7vW5JTcCRzkK1yeGTtkJ6F66nmomxMCDTheTqHHBNpv2ES8MhrWTCpd0yq5K8nf89CuQvh97F/XULo6edHEMTltySgC0n/XpHJUwibMgko5S7qYLOwHzNSNwTcwoZAyWbYh6lkPR+Me4/cAMIDtjKofe6gVTawKvsC8DcIeM1MaFttIKo3xQYil9qj8lwU7NEqTzCk0M/pNKAIv86RDqjcezrUoENJMjzMvvzMWLzM6f+TKM/+osFykkf8cHtHd8dd0wXiKae+HP2oelNb4K6eHhV4S9ZvDf25v04AR/P2v0PjioRcE68T6HH5ATLp+MlIR7yk9DsAb39kXjsqEySSbZLQr7/fJm1NiypzFHltC1Xo51IY3w8wUScO4ltBlZK9hp4q76eKHt5fR8/wBm9nXRfLrQzkh5BrfSOQb8qrqYzrtyZzv1XtZJhfOMU0tIYK2A2G+cIotzzVeZByRCopyrF1sV0Ls5ueHsw9/LGYRRcWNDVu/qy5yH4SeD+/JefLLX8whD9CMEae73quZagJNX9UUHL6ujMN5T2fIToVJ1+GNc++tDS9IpabvAQFu/r0So0VWfNVzLbSoeQwgdDSvUaukr8e5u71gOzbOvqZTqKM5+Q0/Txdf5rO5FTud3ie6hbpJwBEJkLmhSh7lzpuf+x40H5viUckqNWr4xrLUY8Pf8C/Ox3PCMGBxn1kIf12+8gdYIQetv6PfbCKOFa+vQN2hHz13e9DNlu6/vqHZzjqnx5UpikaPJEnEiZn6BALqvUO8U7+cLn7o8FN9d0fMto3vwA=</diagram></mxfile> \ No newline at end of file diff --git a/Code/Mantid/docs/source/diagrams/DgsRemap-v1_wkflw.dot b/Code/Mantid/docs/source/diagrams/DgsRemap-v1_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..ffd9d684206d8101591d05d87be9a25d07d0151c --- /dev/null +++ b/Code/Mantid/docs/source/diagrams/DgsRemap-v1_wkflw.dot @@ -0,0 +1,37 @@ +digraph DgsRemap { + label="DgsRemap Flowchart" + $global_style + + subgraph params { + $param_style + InputWorkspace + MaskWorkspace + GroupingWorkspace + OutputWorkspace + } + + subgraph algorithms { + $algorithm_style + maskDet1 [label="MaskDetectors"] + maskDet2 [label="MaskDetectors"] + groupDet1 [label="GroupDetectors"] + groupDet2 [label="GroupDetectors"] + } + + subgraph decisions { + $decision_style + ExecuteOppositeOrder + } + + InputWorkspace -> ExecuteOppositeOrder + ExecuteOppositeOrder -> maskDet1 [label="True"] + ExecuteOppositeOrder -> groupDet2 [label="False"] + maskDet1 -> groupDet1 + groupDet2 -> maskDet2 + groupDet1 -> OutputWorkspace + maskDet2 -> OutputWorkspace + GroupingWorkspace -> groupDet1 + GroupingWorkspace -> groupDet2 + MaskWorkspace -> maskDet1 + MaskWorkspace -> maskDet2 +} diff --git a/Code/Mantid/docs/source/diagrams/DgsRemapWorkflow.xml b/Code/Mantid/docs/source/diagrams/DgsRemapWorkflow.xml deleted file mode 100644 index 52448c7d20cf8de04210ee2f5575a99d75f519fc..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/diagrams/DgsRemapWorkflow.xml +++ /dev/null @@ -1 +0,0 @@ -<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.45 Safari/537.36"><diagram>3ZrPcuI4EIefhqqdw6RsDGzmOCGQnUNmUzWHbE5Tii2MKsZySSIh8/RpiZYtsMjGAcy/A9gt2bS+bn6tBjrRcLa4EaSY3vKEZp1ukCw60XWn270MAnjWhtc1QypYsjSFaJizhMoVk+I8U6xYNcY8z2msVmwTnq3erCAprRl+xSSrW+9ZoqboXHdQ2f+hLJ3atwkH35YjUr3aeyR0QuaZ+mpMMKaHZ8TeyywzGgEawTncRh/NFkOaaTx26UsW4w2jpZOC5ujI+xegE88km6OPHb2iaEE60dWPvJgrGHVM91w8yYLEtLY2OSWFPpwtUh3Wi0nGX+IpEeoiIYo8EgmDVxOWZUOecWGuicbwGA7BLpXgT9QZCcyjHLHE0V13fbjkZyoUxRQyJlzvDeUzqsQrTMHRbh/zCfMrRETBSxXWMETb1AmpvY5gdqXlrSvAcICM/byjGu/RgsZzRf8tCi4ZvIqEigZwpYLn3+GRsO311tiG/TpbO8dlO9gB216N7S2RT07yjpmQ8H7jJrlLYyYZz+t8J+bRMt/IckK+XauNDt9LD15r2wYvRnJFKtY40jz5LgR/gbM4I1KyGCjQBVP/gUXnqD5+gOPgoo9nd1QwcAVyHqzaloNbejpO0afmCntSuyABmUYXJE1nMGlUma5o9mj80YwZqLm5TTKGWBqXNoVE8rkAkXM1Ej5oKcVZmGr6vd8Nm6AZUex5tYRsEwSsNp8OgiG2hyA4SP8nJB8hjip5FMT/9qrKNSw+VlzIBlpSCB5TCa6sS8lwqMW6ZSkJ18pg5CuDPqneRRm8PFOo/QDTBaH2LKw2oOJ+04F6I/i8OL9UbZWq3QmeH9b1ZG1VAULrboX1AXq5Eytmnv3FR+obFjO3vmEo2q9vYb0F/MlPYmfXcBvngW4/2wegXm8EnUblbqkTNDmvzjvqYQ+BgjOw/NvovMN6e9hQbcrM1llrc36nWW7EZMfdC+4KVtIek+8Aab9tE3miQcD97pEEYesmck9BaAgVS6YLFZP9AEzrbeJ+mDZDZMXUZYS5eABG9a7PqW/L7+rO7Lvm9Yrn3WLvreJtaAg3Ui5tfwGabmAmszyFQ0g6+uV8wuBtIPcVBhvytr6zM9pRim2lvVtriaeIHaxrKXOgrW+jPwG12jlMuWB/eK4+2B76SB9Mtb0/ER4t6UZtuBXI42gJPb8NnqZOeKi2tS+D0+q3czPm/McgGr0B</diagram></mxfile> \ No newline at end of file diff --git a/Code/Mantid/docs/source/diagrams/MuonLoad-v1_wkflw.dot b/Code/Mantid/docs/source/diagrams/MuonLoad-v1_wkflw.dot new file mode 100644 index 0000000000000000000000000000000000000000..2dc82fa8f9cb7a22ba6ec1385779e72ff1ca73ca --- /dev/null +++ b/Code/Mantid/docs/source/diagrams/MuonLoad-v1_wkflw.dot @@ -0,0 +1,52 @@ +digraph MuonLoad { + label="MuonLoad Flowchart" + $global_style + + subgraph params { + $param_style + Filename + CustomDeadTimeTable + DetectorGroupingTable + TimeZero + Xmin + Xmax + RebinParams + OutputType + Alpha + FirstPairIndex + SecondPairIndex + GroupIndex + OutputWorkspace + } + + subgraph algorithms { + $algorithm_style + LoadMuonNexus + ApplyDeadTimeCorr + MuonGroupDetectors + ChangeBinOffset + CropWorkspace + Rebin + MuonCalculateAsymmetry + } + + Filename -> LoadMuonNexus + LoadMuonNexus -> ApplyDeadTimeCorr + LoadMuonNexus -> CustomDeadTimeTable + LoadMuonNexus -> DetectorGroupingTable + ApplyDeadTimeCorr -> MuonGroupDetectors + MuonGroupDetectors -> ChangeBinOffset + TimeZero -> ChangeBinOffset + ChangeBinOffset -> CropWorkspace + Xmin -> CropWorkspace + Xmax -> CropWorkspace + CropWorkspace -> Rebin + RebinParams -> Rebin + Rebin -> MuonCalculateAsymmetry + OutputType -> MuonCalculateAsymmetry + FirstPairIndex -> MuonCalculateAsymmetry + SecondPairIndex -> MuonCalculateAsymmetry + GroupIndex -> MuonCalculateAsymmetry + Alpha -> MuonCalculateAsymmetry + MuonCalculateAsymmetry -> OutputWorkspace +} diff --git a/Code/Mantid/docs/source/diagrams/MuonWorkflow.xml b/Code/Mantid/docs/source/diagrams/MuonWorkflow.xml deleted file mode 100644 index 245f45dc5a2f338e5487b3e5a0aee7b6f114b08b..0000000000000000000000000000000000000000 --- a/Code/Mantid/docs/source/diagrams/MuonWorkflow.xml +++ /dev/null @@ -1 +0,0 @@ -<mxfile userAgent="Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; BRI/2; InfoPath.3)"><diagram>1Ztfk6I4EMA/jY9nAeHv4yyzM3dVt7dTN1O1c/dylZGo1AKhQpjRb79BOihRPEFARktLgob0L013pzvOkB9vHhlO199oQKKZocWYr2fofmYYmniJhhSvyO8kXK152azrtrc/8yMM5Pddw963Py9wROAH+9Zaw5JGQa1hQZOELORlyjZOacTDNKs1rvIwIEoTC+udBVsYlQZyBBulIeNbOcSALHEe8d92TeKcMUNfBRpGqRhN8Sne+CQq8MirQB8z46HhC5XUjCQgUuNv3nGUw0gewogkOCZHQ8zWOC0+xptVMV3zZUQ/FmvM+Dzj4v0/fYa+LMMo8mlE2e4n6EE8fF+0Z5zRn+TgjLZ7VGfkJO4k34tgHYsAUr0Txgnw3DWBPI+ExoSzrfjKx14xPNAXmBELOMDvkavP4UoY5nRVdVO0rg+Uz1YZig+AsRHpnxQH33Ka/EU2edaCa8rogmRiSCpX3y/Iduda3SZXctVNoAFgdZWs5Q1L9ggmSYI7xuiHOFpEOMvCxRELVGfhNrIggWIvMpqzBTSBWELzV0QKcJrXackZiTAP3+sXaCP6XZpG23uCg5cwFhrA2BQUC8Hx9ZplVJoDumV4I+tWccc+Mpqn94QLp0DZJG5d0+yNMGg+8DV1R/KUhG1j7gyKuFDdfwmjU/A1ZhVT9OtsTAkGOrBs6HUYpP4aJyvyJUy+L5eZsEwTUFnrRCTSUWVtxShYpqqy6HKj4AzmcISYbPsqmgo93R38Iw40MTQ4fCJMqD4nBUcYRUWr2YSedUhSfw89Ukn+CpcEP32ioRhKRd02nbmYDOR6yNUsBIOBKbBdRb/LQUIXx7yrYV2s4YymPyj7maVYyD4F/e4tnNLr4ZStujxHb2GQu6j3axwmkwj8m6Oy6yJ/t24vdOHiBvVwrzHeTALoQN7NdiuAsgtLGzhq+Ju8tdLS4ZZRfcVibv2+d42jUMy1B4ZaRLs+jha58AHkLtvGB33flrLT25pCeibA7CmRGULWXK7rLoBcKX4bzA8hy/gTDtkfSSBGPgHL4PTlvRTL4MncgOxA09vQ7aDCz0Tk74JpwXWGgStgKnR1SGsMg/YuStd4EkAH8mOuq5pcy4NLD0P0e87TnL9sBcAJYJUOqHeslorV0LSBzYCfZ5zGMjP2gt8E1ykg7m2VIGM5mRhTTYExSgD2hBmO26TEhiM7kE1wTDW2tWQC4HbZ7Jrkcn3YNlcgidWy17tgdrT09YWJlE3IqzyK+HyQRhFHZ7IoXnPO6SwZGQ0dkikD0EmRqcvaMWMkg5NeZT2dMfIcbe5qnlA8USLwkLJilHXJoTJG7Yk2L+zOEz1xX01ee5qLrOdtCEzaDWUtY6guucAAc/yGM3Gyb2fk9ZcMrKrSVdBvqQ4J2V6LaEq6i5ErrF7zIuj83QQXP9SwEu9oGiZLf7s6YJisJhNN6lpvdUBZOGgIJwdeBzXfve0VTUfQ0FbTTjj9spI9mqL1i6Gj+5LV+0MOZb35k3Jo4dpGKJuZjroYNtFxQac5+Dnq0JKmv+oOHXmDUq7+Yql+J6jZWZ7ffHNq0sb1DP1y6OghZeXxhuu4fjl03IwlCzGfKe7WUXPa4vykA6QbKn97YWUxoLWwp3Y1jCvsLvabTEVBN/vaTaPWa5TNBvZ+/TGRbJdudkx0VMw+lX0wOzpHmWi+YTR7X+5mb+MSDm4EVyueCo2u26JOwCgBTRNGtXOsMAT/v3PsYnr9LYxg5Tm1RPEVO+50q+N6qVqEj7RgEof7P4SU4fv+jzPo6y8=</diagram></mxfile> \ No newline at end of file diff --git a/Code/Mantid/docs/source/diagrams/ReflectometryReductionOneAuto-v1-Groups_wkflw.dot b/Code/Mantid/docs/source/diagrams/ReflectometryReductionOneAuto-v1-Groups_wkflw.dot index 800adcf0915111e196bb28ae702c8e43e113a6c9..91c67807bd67b7e83e7be83cbd3a892a3931212e 100644 --- a/Code/Mantid/docs/source/diagrams/ReflectometryReductionOneAuto-v1-Groups_wkflw.dot +++ b/Code/Mantid/docs/source/diagrams/ReflectometryReductionOneAuto-v1-Groups_wkflw.dot @@ -22,11 +22,11 @@ digraph ReflectometryReductionOne { inputWorkspace -> reflRedOne reflRedOne -> reflRedOne_0 [label="InputWorkspace[0]"] reflRedOne -> reflRedOne_1 [label="InputWorkspace[1]"] + reflRedOne_0 -> thetaOut [label="θ"] reflRedOne_0 -> groupIvQ [label="IvQ"] reflRedOne_1 -> groupIvQ [label="IvQ"] reflRedOne_0 -> groupIvLam [label="Ivλ"] reflRedOne_1 -> groupIvLam [label="Ivλ"] - reflRedOne_0 -> thetaOut [label="θ"] groupIvQ -> outputWorkspaceMT [label="IvQ"] groupIvLam -> outputWorkspaceWL [label="Ivλ"] } diff --git a/Code/Mantid/docs/source/images/AlignAndFocusPowderFlowchart.png b/Code/Mantid/docs/source/images/AlignAndFocusPowderFlowchart.png deleted file mode 100644 index 04c544852200a11ea13879122ceba9f10a22273a..0000000000000000000000000000000000000000 Binary files a/Code/Mantid/docs/source/images/AlignAndFocusPowderFlowchart.png and /dev/null differ diff --git a/Code/Mantid/docs/source/images/DgsReductionWorkflow.png b/Code/Mantid/docs/source/images/DgsReductionWorkflow.png deleted file mode 100644 index 6bed2ae0165b1347a7ec44f565b65d183f7c9d50..0000000000000000000000000000000000000000 Binary files a/Code/Mantid/docs/source/images/DgsReductionWorkflow.png and /dev/null differ diff --git a/Code/Mantid/docs/source/images/DgsRemapWorkflow.png b/Code/Mantid/docs/source/images/DgsRemapWorkflow.png deleted file mode 100644 index 3da968ea3c1400d912943218499a0a425483a814..0000000000000000000000000000000000000000 Binary files a/Code/Mantid/docs/source/images/DgsRemapWorkflow.png and /dev/null differ diff --git a/Code/Mantid/docs/source/images/MuonWorkflow.png b/Code/Mantid/docs/source/images/MuonWorkflow.png deleted file mode 100644 index a994cd3a3d291d7bc8e89de6b763c3ffda1a5f3b..0000000000000000000000000000000000000000 Binary files a/Code/Mantid/docs/source/images/MuonWorkflow.png and /dev/null differ diff --git a/Code/Mantid/docs/sphinxext/mantiddoc/directives/diagram.py b/Code/Mantid/docs/sphinxext/mantiddoc/directives/diagram.py index 7e63ead920c780b65c0ea77a9c4b35f6b52b2d4b..e9fd957acb915fbaef50a8af7fbd0dac8d43d6df 100644 --- a/Code/Mantid/docs/sphinxext/mantiddoc/directives/diagram.py +++ b/Code/Mantid/docs/sphinxext/mantiddoc/directives/diagram.py @@ -11,6 +11,7 @@ STYLE = dict() STYLE["global_style"] = """ fontname = Helvetica labelloc = t +ordering = out node[fontname="Helvetica", style = filled] edge[fontname="Helvetica"] """ diff --git a/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py b/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py index a90287538184c6aed0ff9351ee968687aebd3680..0715a8e6b8facf72e7316894b6c63c311a380975 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py +++ b/Code/Mantid/scripts/Inelastic/Direct/DirectEnergyConversion.py @@ -88,7 +88,7 @@ class DirectEnergyConversion(object): bkgd_range =[15000,19000] :integration range for background tests - second_white - If provided an additional set of tests is performed on this. + second_white - If provided an additional set of tests is performed on this. (default = None) hardmaskPlus - A file specifying those spectra that should be masked without testing (default=None) @@ -148,7 +148,7 @@ class DirectEnergyConversion(object): #------------------------------------------------------------------------------- def diagnose(self, white,diag_sample=None,**kwargs): - """ run diagnostics on the provided workspaces. + """ run diagnostics on the provided workspaces. this method does some additional processing before moving on to the diagnostics: 1) Computes the white beam integrals, converting to energy @@ -192,64 +192,69 @@ class DirectEnergyConversion(object): bleed_pixels - If the bleed test is on then this is the number of pixels ignored within the bleed test diagnostic """ - lhs_names = funcreturns.lhs_info('names') - if len(lhs_names) > 0: - var_name = lhs_names[0] - else: - var_name = "diag_mask" - + # output workspace name. + try: + n,r = funcreturns.lhs_info('both') + out_ws_name = r[0] + except: + out_ws_name = None # modify properties using input arguments - self.prop_man.set_input_parameters(**kwargs) + self.prop_man.set_input_parameters(**kwargs) # obtain proper run descriptor in case it is not a run descriptor but # something else - white = self.get_run_descriptor(white) + white = self.get_run_descriptor(white) # return all diagnostics parameters - diag_params = self.prop_man.get_diagnostics_parameters() - - if self.use_hard_mask_only: - if mtd.doesExist('hard_mask_ws'): - diag_mask = mtd['hard_mask_ws'] - else: # build hard mask - # in this peculiar way we can obtain working mask which - # accounts for initial data grouping in the - # data file. SNS or 1 to 1 maps may probably avoid this - # stuff and can load masks directly - white_data = white.get_ws_clone('white_ws_clone') - - diag_mask = LoadMask(Instrument=self.instr_name,InputFile=self.hard_mask_file,\ - OutputWorkspace='hard_mask_ws') - MaskDetectors(Workspace=white_data, MaskedWorkspace=diag_mask) - DeleteWorkspace(diag_mask) - diag_mask,masked_list = ExtractMask(InputWorkspace=white_data) - DeleteWorkspace(Workspace='white_ws_clone') - - return diag_mask - + diag_params = self.prop_man.get_diagnostics_parameters() + + if self.use_hard_mask_only: + # build hard mask + diag_mask,n_masks = white.get_masking() + if diag_mask is None: + # in this peculiar way we can obtain working mask which + # accounts for initial data grouping in the + # data file. SNS or 1 to 1 maps may probably avoid this + # stuff and can load masks directly + white_data = white.get_ws_clone('white_ws_clone') + + diag_mask = LoadMask(Instrument=self.instr_name,InputFile=self.hard_mask_file,\ + OutputWorkspace='hard_mask_ws') + MaskDetectors(Workspace=white_data, MaskedWorkspace=diag_mask) + white.add_masked_ws(white_data) + DeleteWorkspace(Workspace='white_ws_clone') + diag_mask,n_masks = white.get_masking() + if not(out_ws_name is None): + dm = CloneWorkspace(diag_mask,OutputWorkspace=out_ws_name) + return dm + else: + return None # Get the white beam vanadium integrals - whiteintegrals = self.do_white(white, None, None) # No grouping yet - if self.second_white: - second_white = self.second_white - other_whiteintegrals = self.do_white(PropertyManager.second_white, None, None) # No grouping yet - self.second_white = other_whiteintegrals + whiteintegrals = self.do_white(white, None, None) # No grouping yet + if self.second_white: + #TODO: fix THIS DOES NOT WORK! + second_white = self.second_white + other_whiteintegrals = self.do_white(PropertyManager.second_white, None, None) # No grouping yet + self.second_white = other_whiteintegrals # Get the background/total counts from the sample run if present - if diag_sample: - diag_sample = self.get_run_descriptor(diag_sample) - # If the bleed test is requested then we need to pass in the - # sample_run as well + if not diag_sample is None: + diag_sample = self.get_run_descriptor(diag_sample) + sample_mask,n_sam_masked = diag_sample.get_masking() + if sample_mask is None: + # If the bleed test is requested then we need to pass in the + # sample_run as well if self.bleed_test: - # initiate reference to reducer to be able to work with Run - # Descriptors + # initiate reference to reducer to be able to work with Run + # Descriptors diagnostics.__Reducer__ = self diag_params['sample_run'] = diag_sample - # Set up the background integrals for diagnostic purposes + # Set up the background integrals for diagnostic purposes result_ws = self.normalise(diag_sample, self.normalise_method) - #>>> here result workspace is being processed -- not touching - #result ws + #>>> here result workspace is being processed -- not touching + #result ws bkgd_range = self.background_test_range background_int = Integration(result_ws,\ RangeLower=bkgd_range[0],RangeUpper=bkgd_range[1],\ @@ -262,273 +267,292 @@ class DirectEnergyConversion(object): diagnostics.normalise_background(background_int, whiteintegrals,\ diag_params.get('second_white',None)) diag_params['background_int'] = background_int - diag_params['sample_counts'] = total_counts + diag_params['sample_counts'] = total_counts + + + # extract existing white mask if one is defined and provide it for + # diagnose to use instead of constantly diagnosing the same vanadium + white_mask,num_masked = white.get_masking() + if not(white_mask is None) and not(sample_mask is None): + # nothing to do then + total_mask = sample_mask+white_mask + return total_mask + else: + pass # have to run diagnostics after all # Check how we should run diag - diag_spectra_blocks = self.diag_spectra - if diag_spectra_blocks is None: + diag_spectra_blocks = self.diag_spectra + + if not(white_mask is None): + diag_params['white_mask']=white + # keep white mask workspace for further usage + if diag_spectra_blocks is None: # Do the whole lot at once - diagnostics.diagnose(whiteintegrals, **diag_params) - else: - for index, bank in enumerate(diag_spectra_blocks): - diag_params['start_index'] = bank[0] - 1 - diag_params['end_index'] = bank[1] - 1 - diagnostics.diagnose(whiteintegrals, **diag_params) - - if 'sample_counts' in diag_params: - DeleteWorkspace(Workspace='background_int') - DeleteWorkspace(Workspace='total_counts') - if 'second_white' in diag_params: - DeleteWorkspace(Workspace=diag_params['second_white']) - # Extract a mask workspace - diag_mask, det_ids = ExtractMask(InputWorkspace=whiteintegrals,OutputWorkspace=var_name) - - DeleteWorkspace(Workspace=whiteintegrals) - #TODO do we need this? - #self.spectra_masks = diag_mask - return diag_mask + white_masked_ws =diagnostics.diagnose(whiteintegrals, **diag_params) + if white_masked_ws: + white.add_masked_ws(white_masked_ws) + DeleteWorkspace(white_masked_ws) + else: + for index, bank in enumerate(diag_spectra_blocks): + diag_params['start_index'] = bank[0] - 1 + diag_params['end_index'] = bank[1] - 1 + white_masked_ws=diagnostics.diagnose(whiteintegrals, **diag_params) + if white_masked_ws: + white.add_masked_ws(white_masked_ws) + DeleteWorkspace(white_masked_ws) + + if out_ws_name: + if not(diag_sample is None): + diag_sample.add_masked_ws(whiteintegrals) + mask,n_removed = diag_sample.get_masking() + diag_mask = CloneWorkspace(mask,OutputWorkspace=out_ws_name) + else: # either WB was diagnosed or WB masks were applied to it + # Extract a mask workspace + diag_mask, det_ids = ExtractMask(InputWorkspace=whiteintegrals,OutputWorkspace=out_ws_name) + else: + diag_mask=None + # Clean up + if 'sample_counts' in diag_params: + DeleteWorkspace(Workspace='background_int') + DeleteWorkspace(Workspace='total_counts') + if 'second_white' in diag_params: + DeleteWorkspace(Workspace=diag_params['second_white']) + DeleteWorkspace(Workspace=whiteintegrals) + + return diag_mask #------------------------------------------------------------------------------- def convert_to_energy(self,wb_run=None,sample_run=None,ei_guess=None,rebin=None,map_file=None, monovan_run=None,wb_for_monovan_run=None,**kwargs): - """ One step conversion of run into workspace containing information about energy transfer + """ One step conversion of run into workspace containing information about energy transfer """ # Support for old reduction interface: - self.prop_man.set_input_parameters_ignore_nan\ + self.prop_man.set_input_parameters_ignore_nan\ (wb_run=wb_run,sample_run=sample_run,incident_energy=ei_guess,energy_bins=rebin, map_file=map_file,monovan_run=monovan_run,wb_for_monovan_run=wb_for_monovan_run) # - self.prop_man.set_input_parameters(**kwargs) + self.prop_man.set_input_parameters(**kwargs) # output workspace name. - try: - n,r = funcreturns.lhs_info('both') - out_ws_name = r[0] - except: - out_ws_name = None - + try: + n,r = funcreturns.lhs_info('both') + out_ws_name = r[0] + except: + out_ws_name = None + prop_man = self.prop_man + # check if reducer can find all non-run files necessary for the reduction + # and verify some other properties which can be wrong before starting a long run. + prop_man.log("****************************************************************") + prop_man.validate_properties() + prop_man.log("****************************************************************") # inform user on what parameters have changed from script or gui # if monovan present, check if abs_norm_ parameters are set - self.prop_man.log_changed_values('notice') - prop_man = self.prop_man - #process complex parameters + self.prop_man.log_changed_values('notice') - start_time = time.time() - # check if reducer can find all non-run files necessary for the reduction - # before starting long run. - #TODO: - # Reducer.check_necessary_files(monovan_run) + start_time = time.time() + - PropertyManager.sample_run.set_action_suffix('') - sample_ws = PropertyManager.sample_run.get_workspace() + PropertyManager.sample_run.set_action_suffix('') + sample_ws = PropertyManager.sample_run.get_workspace() # Update reduction properties which may change in the workspace but have # not been modified from input parameters. # E.g. detector number have changed - oldChanges = self.prop_man.getChangedProperties() - allChanges = self.prop_man.update_defaults_from_instrument(sample_ws.getInstrument()) - workspace_defined_prop = allChanges.difference(oldChanges) - if len(workspace_defined_prop) > 0: - prop_man.log("****************************************************************") - prop_man.log('*** Sample run {0} properties change default reduction properties: '.\ - format(PropertyManager.sample_run.get_ws_name())) - prop_man.log_changed_values('notice',False,oldChanges) - prop_man.log("****************************************************************") - - - - masking = None - masks_done = False - if not prop_man.run_diagnostics: - header = "*** Diagnostics including hard masking is skipped " - masks_done = True + oldChanges = self.prop_man.getChangedProperties() + allChanges = self.prop_man.update_defaults_from_instrument(sample_ws.getInstrument()) + workspace_defined_prop = allChanges.difference(oldChanges) + if len(workspace_defined_prop) > 0: + prop_man.log("****************************************************************") + prop_man.log('*** Sample run {0} properties change default reduction properties: '.\ + format(PropertyManager.sample_run.get_workspace().name())) + prop_man.log_changed_values('notice',False,oldChanges) + prop_man.log("****************************************************************") + + + + masking = None + masks_done = False + if not prop_man.run_diagnostics: + header = "*** Diagnostics including hard masking is skipped " + masks_done = True #if Reducer.save_and_reuse_masks : # SAVE AND REUSE MASKS - if self.spectra_masks: - masks_done = True + if self.spectra_masks: + masks_done = True #-------------------------------------------------------------------------------------------------- # Diagnostics here # ------------------------------------------------------------------------------------------------- # diag the sample and detector vanadium. It will deal with hard mask only # if it is set that way - if not masks_done: - prop_man.log("======== Run diagnose for sample run ===========================",'notice') - masking = self.diagnose(PropertyManager.wb_run,PropertyManager.mask_run,\ + if not masks_done: + prop_man.log("======== Run diagnose for sample run ===========================",'notice') + masking = self.diagnose(PropertyManager.wb_run,PropertyManager.mask_run,\ second_white=None,print_diag_results=True) - if prop_man.use_hard_mask_only: - header = "*** Hard mask file applied to workspace with {0:d} spectra masked {1:d} spectra" - else: - header = "*** Diagnostics processed workspace with {0:d} spectra and masked {1:d} bad spectra" + if prop_man.use_hard_mask_only: + header = "*** Hard mask file applied to workspace with {0:d} spectra masked {1:d} spectra" + else: + header = "*** Diagnostics processed workspace with {0:d} spectra and masked {1:d} bad spectra" # diagnose absolute units: - if self.monovan_run != None : - if self.mono_correction_factor == None : - if self.use_sam_msk_on_monovan == True: - prop_man.log(' Applying sample run mask to mono van') - else: - if not self.use_hard_mask_only : # in this case the masking2 is different but - #points to the same - #workspace - # Should be better - # solution for that. - prop_man.log("======== Run diagnose for monochromatic vanadium run ===========",'notice') - - masking2 = self.diagnose(PropertyManager.wb_for_monovan_run,PropertyManager.monovan_run,\ + if self.monovan_run != None : + if self.mono_correction_factor == None : + if self.use_sam_msk_on_monovan == True: + prop_man.log(' Applying sample run mask to mono van') + else: + if not self.use_hard_mask_only : # in this case the masking2 is different but + # points to the same workspace + # Should be better solution for that. + prop_man.log("======== Run diagnose for monochromatic vanadium run ===========",'notice') + masking2 = self.diagnose(PropertyManager.wb_for_monovan_run,PropertyManager.monovan_run,\ second_white = None,print_diag_results=True) - masking += masking2 - DeleteWorkspace(masking2) - - - else: # if Reducer.mono_correction_factor != None : - pass + masking += masking2 + DeleteWorkspace(masking2) + else: # if Reducer.mono_correction_factor != None : + pass + else: + pass # Very important statement propagating masks for further usage in # convert_to_energy. # This property is also directly accessible from GUI. - self.spectra_masks = masking + self.spectra_masks = masking # save mask if it does not exist and has been already loaded #if Reducer.save_and_reuse_masks and not masks_done: # SaveMask(InputWorkspace=masking,OutputFile = # mask_file_name,GroupedDetectors=True) - else: - header = '*** Using stored mask file for workspace with {0} spectra and {1} masked spectra' - masking = self.spectra_masks + else: + header = '*** Using stored mask file for workspace with {0} spectra and {1} masked spectra' + masking = self.spectra_masks # estimate and report the number of failing detectors - failed_sp_list,nMaskedSpectra = get_failed_spectra_list_from_masks(masking) - if masking: - nSpectra = masking.getNumberHistograms() - else: - nSpectra = 0 - prop_man.log(header.format(nSpectra,nMaskedSpectra),'notice') + nMaskedSpectra = get_failed_spectra_list_from_masks(masking) + if masking: + nSpectra = masking.getNumberHistograms() + else: + nSpectra = 0 + prop_man.log(header.format(nSpectra,nMaskedSpectra),'notice') #-------------------------------------------------------------------------------------------------- # now reduction #-------------------------------------------------------------------------------------------------- # SNS or GUI motor stuff - self.calculate_rotation(PropertyManager.sample_run.get_workspace()) + self.calculate_rotation(PropertyManager.sample_run.get_workspace()) # - if self.monovan_run != None: - MonovanCashNum = PropertyManager.monovan_run.run_number() - if self.mono_correction_factor: - calculate_abs_units = False # correction factor given, so no calculations - else: - calculate_abs_units = True - else: - MonovanCashNum = None - calculate_abs_units = False - PropertyManager.mono_correction_factor.set_cash_mono_run_number(MonovanCashNum) - - - if PropertyManager.incident_energy.multirep_mode(): - self._multirep_mode = True - ws_base = None - mono_ws_base = None - num_ei_cuts = len(self.incident_energy) - if self.check_background: + if self.monovan_run != None: + MonovanCashNum = PropertyManager.monovan_run.run_number() + if self.mono_correction_factor: + calculate_abs_units = False # correction factor given, so no calculations + else: + calculate_abs_units = True + else: + MonovanCashNum = None + calculate_abs_units = False + PropertyManager.mono_correction_factor.set_cash_mono_run_number(MonovanCashNum) + + + if PropertyManager.incident_energy.multirep_mode(): + self._multirep_mode = True + ws_base = None + mono_ws_base = None + num_ei_cuts = len(self.incident_energy) + if self.check_background: # find the count rate seen in the regions of the histograms # defined as the background regions, if the user defined such # region - ws_base = PropertyManager.sample_run.get_workspace() - bkgd_range = self.bkgd_range - bkgr_ws=self._find_or_build_bkgr_ws(ws_base,bkgd_range[0],bkgd_range[1]) - RenameWorkspace(InputWorkspace=bkgr_ws, OutputWorkspace='bkgr_ws_source') + ws_base = PropertyManager.sample_run.get_workspace() + bkgd_range = self.bkgd_range + bkgr_ws=self._find_or_build_bkgr_ws(ws_base,bkgd_range[0],bkgd_range[1]) + RenameWorkspace(InputWorkspace=bkgr_ws, OutputWorkspace='bkgr_ws_source') # initialize list to store resulting workspaces to return - result = [] - else: - self._multirep_mode = False - num_ei_cuts = 0 + result = [] + else: + self._multirep_mode = False + num_ei_cuts = 0 - cut_ind = 0 # do not do enumerate if it generates all sequence at once + cut_ind = 0 # do not do enumerate if it generates all sequence at once # -- code below uses current energy state from # PropertyManager.incident_energy - for ei_guess in PropertyManager.incident_energy: - cut_ind +=1 + for ei_guess in PropertyManager.incident_energy: + cut_ind +=1 #--------------- - if self._multirep_mode: - tof_range = self.find_tof_range_for_multirep(ws_base) - ws_base = PropertyManager.sample_run.chop_ws_part(ws_base,tof_range,self._do_early_rebinning,cut_ind,num_ei_cuts) - prop_man.log("*** Processing multirep chunk: #{0}/{1} for provisional energy: {2} meV".format(cut_ind,num_ei_cuts,ei_guess),'notice') + if self._multirep_mode: + tof_range = self.find_tof_range_for_multirep(ws_base) + ws_base = PropertyManager.sample_run.chop_ws_part(ws_base,tof_range,self._do_early_rebinning,cut_ind,num_ei_cuts) + prop_man.log("*** Processing multirep chunk: #{0}/{1} for provisional energy: {2} meV".format(cut_ind,num_ei_cuts,ei_guess),'notice') #--------------- #Run the conversion first on the sample - deltaE_ws_sample = self.mono_sample(PropertyManager.sample_run,ei_guess,PropertyManager.wb_run,\ + deltaE_ws_sample = self.mono_sample(PropertyManager.sample_run,ei_guess,PropertyManager.wb_run,\ self.map_file,masking) # calculate absolute units integral and apply it to the workspace - cashed_mono_int = PropertyManager.mono_correction_factor.get_val_from_cash(prop_man) - if MonovanCashNum != None or self.mono_correction_factor or cashed_mono_int : + cashed_mono_int = PropertyManager.mono_correction_factor.get_val_from_cash(prop_man) + if MonovanCashNum != None or self.mono_correction_factor or cashed_mono_int : # do not remove background from vanadium (sample background is not fit for that anyway) - current_bkg_opt = self.check_background - self.check_background= False + current_bkg_opt = self.check_background + self.check_background= False # what we want to do with absolute units: - if self.mono_correction_factor: # Correction provided. Just apply it - deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ - ei_guess,PropertyManager.wb_for_monovan_run) - elif cashed_mono_int: # Correction cashed from previous run - self.mono_correction_factor = cashed_mono_int - deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ - ei_guess,PropertyManager.wb_for_monovan_run) - self.mono_correction_factor = None - else: # Calculate corrections - if self._multirep_mode and calculate_abs_units: - mono_ws_base = PropertyManager.monovan_run.chop_ws_part(mono_ws_base,tof_range,self._do_early_rebinning,\ - cut_ind,num_ei_cuts) - deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ - ei_guess,PropertyManager.wb_for_monovan_run) - self.check_background = current_bkg_opt + if self.mono_correction_factor: # Correction provided. Just apply it + deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ + ei_guess,PropertyManager.wb_for_monovan_run, + ' provided ') + elif cashed_mono_int: # Correction cashed from previous run + self.mono_correction_factor = cashed_mono_int + deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ + ei_guess,PropertyManager.wb_for_monovan_run, + ' -cached- ') + self.mono_correction_factor = None + else: # Calculate corrections + if self._multirep_mode and calculate_abs_units: + mono_ws_base = PropertyManager.monovan_run.chop_ws_part(mono_ws_base,tof_range,self._do_early_rebinning,\ + cut_ind,num_ei_cuts) + deltaE_ws_sample = self.apply_absolute_normalization(deltaE_ws_sample,PropertyManager.monovan_run,\ + ei_guess,PropertyManager.wb_for_monovan_run, + 'calculated') + # monovan workspace has been certainly deleted from memory after calculations + PropertyManager.monovan_run._in_cash = True + self.check_background = current_bkg_opt + + # ensure that the sample_run name is intact with workspace - PropertyManager.sample_run.synchronize_ws(deltaE_ws_sample) + PropertyManager.sample_run.synchronize_ws(deltaE_ws_sample) # - ei = (deltaE_ws_sample.getRun().getLogData("Ei").value) + ei = (deltaE_ws_sample.getRun().getLogData("Ei").value) # PropertyManager.incident_energy.set_current(ei) # let's not do it -- # this makes subsequent calls to this method depend on # # previous calls - prop_man.log("*** Incident energy found for sample run: {0} meV".format(ei),'notice') + prop_man.log("*** Incident energy found for sample run: {0} meV".format(ei),'notice') # - self.save_results(deltaE_ws_sample) - if out_ws_name: - if self._multirep_mode: - result.append(deltaE_ws_sample) - else: # delete workspace if no output is requested - self.sample_run = None - - - - results_name = deltaE_ws_sample.name() - if out_ws_name and not self._multirep_mode: - if results_name != out_ws_name: - RenameWorkspace(InputWorkspace=results_name,OutputWorkspace=out_ws_name) - result = mtd[out_ws_name] - else: - pass - - end_time = time.time() - prop_man.log("*** Elapsed time = {0} sec".format(end_time - start_time),'notice') - - # Hack for multirep mode? -# if mtd.doesExist('hard_mask_ws') == True: - # DeleteWorkspace(Workspace='hard_mask_ws') - - # - # CLEAN-up (may be worth to do in separate procedure) - # Currently clear masks unconditionally TODO: cash masks with appropriate - # precautions - self.spectra_masks = None - #self.prop_man.wb_run = None # clean up memory of the wb run (only in - #case of file based wb) + self.save_results(deltaE_ws_sample) + # prepare output workspace + if out_ws_name: + if self._multirep_mode: + result.append(deltaE_ws_sample) + else: + results_name = deltaE_ws_sample.name() + if results_name != out_ws_name: + RenameWorkspace(InputWorkspace=results_name,OutputWorkspace=out_ws_name) + result = mtd[out_ws_name] + else: # delete workspace if no output is requested + self.sample_run = None - if 'bkgr_ws_source' in mtd: - DeleteWorkspace('bkgr_ws_source') + end_time = time.time() + prop_man.log("*** Elapsed time = {0} sec".format(end_time - start_time),'notice') - return result + # CLEAR existing workspaces only if it is not run within loop + #prop_man.monovan_run = None + #prop_man.wb_run = None + self.spectra_masks = None + if 'masking' in mtd: + DeleteWorkspace(masking) + return result def do_white(self, run, spectra_masks=None, map_file=None): """ @@ -590,13 +614,13 @@ class DirectEnergyConversion(object): self.prop_man.log("Could not find such sample environment log. Will use psi=motor_offset") motor_rotation = 0 else: - motor_rotation = float('nan') + motor_rotation = float('nan') self.prop_man.psi = motor_rotation + motor_offset #------------------------------------------------------------------------------- def get_ei(self, data_run, ei_guess): - """ - Calculate incident energy of neutrons and the time of the of the - peak in the monitor spectrum + """ Calculate incident energy of neutrons and the time of the of the + peak in the monitor spectrum + The X data is corrected to set the first monitor peak at t=0 by subtracting t_mon + t_det_delay where the detector delay time is retrieved from the the instrument @@ -611,25 +635,17 @@ class DirectEnergyConversion(object): data_ws = data_run.get_workspace() monitor_ws = data_run.get_monitors_ws() if not monitor_ws: - raise RuntimeError("Can not find monitors workspace for workspace {0}, run N{1}".\ + raise RuntimeError("Can not find monitors workspace for workspace {0}, run N{1}".\ format(data_ws.name(),data_ws.getRunNumber())) separate_monitors = data_run.is_monws_separate() data_run.set_action_suffix('_shifted') - ##------------------------------------------------------------- - ## check if monitors are in the main workspace or provided separately - #data_ws,monitors_ws = - #self.check_monitor_ws(data_ws,monitors_ws,ei_mon_spectra) - ##------------------------------------------------ # Calculate the incident energy ei,mon1_peak,mon1_index,tzero = \ GetEi(InputWorkspace=monitor_ws, Monitor1Spec=int(ei_mon_spectra[0]), Monitor2Spec=int(ei_mon_spectra[1]), EnergyEstimate=ei_guess,FixEi=fix_ei) - # modify current energy estimate and store it in properties for the - # future - #PropertyManager.incident_energy.set_current(ei) # Store found incident energy in the class itself if self.prop_man.normalise_method == 'monitor-2' and not separate_monitors: @@ -637,8 +653,8 @@ class DirectEnergyConversion(object): # instrument is shifted in case it is shifted to this monitor (usual # case) #Find TOF range, correspondent to incident energy monitor peak - energy_rage = self.mon2_norm_energy_range - self._mon2_norm_time_range = self.get_TOF_for_energies(monitor_ws,energy_rage,\ + energy_rage = self.mon2_norm_energy_range + self._mon2_norm_time_range = self.get_TOF_for_energies(monitor_ws,energy_rage,\ [self.mon2_norm_spec],None,self._debug_mode) #end if separate_monitors: @@ -674,13 +690,12 @@ class DirectEnergyConversion(object): MaskDetectors(Workspace=ws_name, MaskedWorkspace=spec_masks) if not map_file is None: GroupDetectors(InputWorkspace=ws_name,OutputWorkspace=ws_name,\ - MapFile= map_file, KeepUngroupedSpectra=0, Behaviour='Average') + MapFile= map_file, KeepUngroupedSpectra=0, Behaviour='Average') return mtd[ws_name] #------------------------------------------------------------------------------- def normalise(self, run, method, range_offset=0.0,external_monitors_ws=None): - """ - Apply normalization using specified source + """ Apply normalization using specified source """ run = self.get_run_descriptor(run) @@ -700,16 +715,16 @@ class DirectEnergyConversion(object): method = method.lower() for case in common.switch(method): if case('monitor-1'): - method,old_ws_name = self._normalize_to_monitor1(run,old_ws_name, range_offset,external_monitors_ws) - break + method,old_ws_name = self._normalize_to_monitor1(run,old_ws_name, range_offset,external_monitors_ws) + break if case('monitor-2'): - method,old_ws_name = self._normalize_to_monitor2(run,old_ws_name, range_offset,external_monitors_ws) - break + method,old_ws_name = self._normalize_to_monitor2(run,old_ws_name, range_offset,external_monitors_ws) + break if case('current'): NormaliseByCurrent(InputWorkspace=old_ws_name,OutputWorkspace=old_ws_name) break if case(): # default - raise RuntimeError('Normalization method {0} not found. It must be one of monitor-1, monitor-2, current, or None'.format(method)) + raise RuntimeError('Normalization method {0} not found. It must be one of monitor-1, monitor-2, current, or None'.format(method)) #endCase @@ -726,27 +741,28 @@ class DirectEnergyConversion(object): # get monitor's workspace separate_monitors = run.is_monws_separate() if external_monitor_ws: - separate_monitors = True - mon_ws = external_monitor_ws + separate_monitors = True + mon_ws = external_monitor_ws else: - mon_ws = run.get_monitors_ws() + mon_ws = run.get_monitors_ws() if not mon_ws: # no monitors - if self.__in_white_normalization: # we can normalize wb integrals by current separately as they often do not + if self.__in_white_normalization: # we can normalize wb integrals by current separately as they often do not # have monitors - self.normalise(run,'current',range_offset) - new_name = run.get_ws_name() - return ('current',new_name) - else: - raise RuntimeError('Normalise by monitor-1:: Workspace {0} for run {1} does not have monitors in it'\ - .format(run.get_ws_name(),run.__get__())) + self.normalise(run,'current',range_offset) + ws = run.get_workspace() + new_name = ws.name() + return ('current',new_name) + else: + raise RuntimeError('Normalise by monitor-1:: Workspace {0} for run {1} does not have monitors in it'\ + .format(ws.name(),run.run_number())) range = self.norm_mon_integration_range if self._debug_mode: - kwargs = {'NormFactorWS':'NormMon1_WS' + data_ws.getName()} + kwargs = {'NormFactorWS':'NormMon1_WS' + data_ws.getName()} else: - kwargs = {} + kwargs = {} mon_spect = self.prop_man.mon1_norm_spec if separate_monitors: @@ -759,9 +775,8 @@ class DirectEnergyConversion(object): range_min = float(range[0] + range_offset) range_max = float(range[1] + range_offset) - - - NormaliseToMonitor(InputWorkspace=old_name,OutputWorkspace=old_name, IntegrationRangeMin=range_min, + # Normalize to monitor 1 + NormaliseToMonitor(InputWorkspace=old_name,OutputWorkspace=old_name,IntegrationRangeMin=range_min, IntegrationRangeMax=range_max,IncludePartialBins=True,**kwargs) return ('monitor-1',old_name) # @@ -771,26 +786,28 @@ class DirectEnergyConversion(object): # get monitor's workspace separate_monitors = run.is_monws_separate() if external_monitor_ws: - separate_monitors = True - mon_ws = external_monitor_ws + separate_monitors = True + mon_ws = external_monitor_ws else: - mon_ws = run.get_monitors_ws() + mon_ws = run.get_monitors_ws() if not mon_ws: # no monitors - if self.__in_white_normalization: # we can normalize wb integrals by current separately as they often do not + if self.__in_white_normalization: # we can normalize wb integrals by current separately as they often do not # have monitors - self.normalise(run,'current',range_offset) - new_name = run.get_ws_name() - return ('current',new_name) - else: - raise RuntimeError('Normalize by monitor-2:: Workspace {0} for run {1} does not have monitors in it'\ - .format(run.get_ws_name(),run.__get__())) + self.normalise(run,'current',range_offset) + ws = run.get_workspace() + new_name =ws.name() + return ('current',new_name) + else: + ws = run.get_workspace() + raise RuntimeError('Normalize by monitor-2:: Workspace {0} for run {1} does not have monitors in it'\ + .format(ws.name(),run.run_number())) # if self._debug_mode: - kwargs = {'NormFactorWS':'NormMon2_WS' + mon_ws.getName()} + kwargs = {'NormFactorWS':'NormMon2_WS' + mon_ws.getName()} else: - kwargs = {} + kwargs = {} mon_spect = self.prop_man.mon2_norm_spec mon_index = int(mon_ws.getIndexFromSpectrumNumber(mon_spect)) @@ -802,24 +819,23 @@ class DirectEnergyConversion(object): #Find TOF range, correspondent to incident energy monitor peak if self._mon2_norm_time_range: # range has been found during ei-calculations - range = self._mon2_norm_time_range - range_min = range[0] + range_offset - range_max = range[1] + range_offset - self._mon2_norm_time_range = None + range = self._mon2_norm_time_range + range_min = range[0] + range_offset + range_max = range[1] + range_offset + self._mon2_norm_time_range = None else: - mon_ws_name = mon_ws.name() #monitor's workspace and detector's workspace are e - if mon_ws_name.find('_shifted') != -1: + mon_ws_name = mon_ws.name() #monitor's workspace and detector's workspace are e + if mon_ws_name.find('_shifted') != -1: # monitor-2 normalization ranges have to be identified before the # instrument is shifted raise RuntimeError("Instrument have been shifted but no time range has been identified. Monitor-2 normalization can not be performed ") - else: + else: # instrument and workspace shifted, so TOF will be calculated wrt # shifted instrument - energy_rage = self.mon2_norm_energy_range - TOF_range = self.get_TOF_for_energies(mon_ws,energy_rage,[mon_spect],None,self._debug_mode) - range_min = TOF_range[0] - range_max = TOF_range[1] - + energy_rage = self.mon2_norm_energy_range + TOF_range = self.get_TOF_for_energies(mon_ws,energy_rage,[mon_spect],None,self._debug_mode) + range_min = TOF_range[0] + range_max = TOF_range[1] # Normalize to monitor 2 NormaliseToMonitor(InputWorkspace=old_name,OutputWorkspace=old_name,IntegrationRangeMin=range_min, IntegrationRangeMax=range_max,IncludePartialBins=True,**kwargs) @@ -831,7 +847,7 @@ class DirectEnergyConversion(object): energy range requested """ if not workspace: - workspace = PropertyManager.sample_run.get_workspace() + workspace = PropertyManager.sample_run.get_workspace() spectra_id = self.prop_man.multirep_tof_specta_list if not spectra_id: @@ -854,14 +870,14 @@ class DirectEnergyConversion(object): nBlocks = len(spectra_id) if nBlocks > 1: - tof_min,t_step,tof_max = process_block(TOF_range[0]) - for ind in xrange(1,nBlocks): - tof_min1,t_step1,tof_max1 = process_block(TOF_range[ind]) - tof_min = min(tof_min,tof_min1) - tof_max = max(tof_max,tof_max1) - t_step = min(t_step,t_step1) + tof_min,t_step,tof_max = process_block(TOF_range[0]) + for ind in xrange(1,nBlocks): + tof_min1,t_step1,tof_max1 = process_block(TOF_range[ind]) + tof_min = min(tof_min,tof_min1) + tof_max = max(tof_max,tof_max1) + t_step = min(t_step,t_step1) else: - tof_min,t_step,tof_max = process_block(TOF_range) + tof_min,t_step,tof_max = process_block(TOF_range) #end return (tof_min,t_step,tof_max) # @@ -912,13 +928,18 @@ class DirectEnergyConversion(object): """ if formats: # clear up existing save formats as one is defined in parameters - self.prop_man.save_format = None - + self.prop_man.save_format = None + # set up internal format variable from method parameters self.prop_man.set_input_parameters_ignore_nan(save_file_name=save_file,save_format=formats) - - #TODO: deal with this. This all should be incorporated in sample_run - save_file = self.prop_man.save_file_name formats = self.prop_man.save_format + + if save_file: + save_file,ext = os.path.splitext(save_file) + if len(ext) > 1: + formats.add(ext[1:]) + else: + save_file = self.prop_man.save_file_name + if save_file is None: save_file = workspace.getName() elif os.path.isdir(save_file): @@ -929,34 +950,31 @@ class DirectEnergyConversion(object): pass prop_man = self.prop_man - - save_file,ext = os.path.splitext(save_file) - if len(ext) > 1: - formats.add(ext[1:]) - name_orig = workspace.name() for file_format in formats: for case in common.switch(file_format): if case('nxspe'): - filename = save_file + '.nxspe' - name_supported = name_orig.replace('/','of') - if name_supported != name_orig: - RenameWorkspace(InputWorkspace=name_orig,OutputWorkspace=name_supported) - SaveNXSPE(InputWorkspace=name_supported,Filename= filename, KiOverKfScaling=prop_man.apply_kikf_correction,psi=prop_man.psi) - if name_supported != name_orig: - RenameWorkspace(InputWorkspace=name_supported,OutputWorkspace=name_orig) - break + filename = save_file + '.nxspe' + # nxspe can not write workspace with / in the name (something to do with folder names inside nxspe) + name_supported = name_orig.replace('/','of') + if name_supported != name_orig: + RenameWorkspace(InputWorkspace=name_orig,OutputWorkspace=name_supported) + SaveNXSPE(InputWorkspace=name_supported,Filename= filename,\ + KiOverKfScaling=prop_man.apply_kikf_correction,psi=prop_man.psi) + if name_supported != name_orig: + RenameWorkspace(InputWorkspace=name_supported,OutputWorkspace=name_orig) + break if case('spe'): - filename = save_file + '.spe' - SaveSPE(InputWorkspace=workspace,Filename= filename) - break + filename = save_file + '.spe' + SaveSPE(InputWorkspace=workspace,Filename= filename) + break if case('nxs'): - filename = save_file + '.nxs' - SaveNexus(InputWorkspace=workspace,Filename= filename) - break + filename = save_file + '.nxs' + SaveNexus(InputWorkspace=workspace,Filename= filename) + break if case(): # default, could also just omit condition or 'if True' - prop_man.log("Unknown file format {0} requested to save results. No saving performed this format".format(file_format)) - + prop_man.log("Unknown file format {0} requested to save results. No saving performed this format".\ + format(file_format)) ######### @property def prop_man(self): @@ -986,7 +1004,7 @@ class DirectEnergyConversion(object): """ set up spectra masks """ self._spectra_masks = value #------------------------------------------------------------------------------- - def apply_absolute_normalization(self,sample_ws,monovan_run=None,ei_guess=None,wb_mono=None): + def apply_absolute_normalization(self,sample_ws,monovan_run=None,ei_guess=None,wb_mono=None,abs_norm_factor_is=None): """ Function applies absolute normalization factor to the target workspace and calculates this factor if necessary @@ -1004,12 +1022,15 @@ class DirectEnergyConversion(object): if prop_man.mono_correction_factor: absnorm_factor = float(prop_man.mono_correction_factor) prop_man.log('*** Using supplied workspace correction factor ******','notice') - abs_norm_factor_is = 'provided' + if not abs_norm_factor_is: + abs_norm_factor_is = ' provided ' + else: mvir = prop_man.monovan_integr_range prop_man.log('*** Evaluating the integral from the monovan run and calculate the correction factor ******','notice') prop_man.log(' Using absolute units vanadium integration range : [{0:8f}:{1:8f}] ******'.format(mvir[0],mvir[1]),'notice') - abs_norm_factor_is = 'calculated' + if not abs_norm_factor_is: + abs_norm_factor_is = 'calculated' # convert to monovanadium to energy deltaE_wkspace_monovan = self.mono_sample(monovan_run,ei_guess,wb_mono, @@ -1020,7 +1041,7 @@ class DirectEnergyConversion(object): prop_man.log(' Incident energy found for monovanadium run: ' + str(ei_monovan) + ' meV','notice') - (anf_LibISIS,anf_SS2,anf_Puas,anf_TGP) = self.get_abs_normalization_factor(deltaE_wkspace_monovan.getName(),ei_monovan) + (anf_LibISIS,anf_SS2,anf_Puas,anf_TGP) = self.get_abs_normalization_factor(monovan_run,ei_monovan) prop_man.log('*** Absolute correction factor(s): S^2: {0:10.4f}\n*** LibISIS: {1:10.4f} Poisson: {2:10.4f} TGP: {3:10.4f} '\ .format(anf_LibISIS,anf_SS2,anf_Puas,anf_TGP),'notice') @@ -1029,10 +1050,7 @@ class DirectEnergyConversion(object): # Store the factor for further usage PropertyManager.mono_correction_factor.set_val_to_cash(prop_man,anf_TGP) # reset current monovan run to run number (if it makes sense) -- - # workspace is not good for further processing any more - mono_run_num = PropertyManager.monovan_run.run_number() - prop_man.monovan_run = None # delete everything from memory - prop_man.monovan_run = mono_run_num + ## workspace is not good for further processing any more #end prop_man.log('*** Using {0} value : {1} of absolute units correction factor (TGP)'.format(abs_norm_factor_is,absnorm_factor),'notice') prop_man.log('*******************************************************************************************','notice') @@ -1041,12 +1059,12 @@ class DirectEnergyConversion(object): return sample_ws #------------------------------------------------------------------------------- - def get_abs_normalization_factor(self,deltaE_wkspaceName,ei_monovan): + def get_abs_normalization_factor(self,monovan_run,ei_monovan): """get absolute normalization factor for monochromatic vanadium Inputs: - @param: deltaE_wkspace -- the name (string) of monovan workspace, converted to energy - @param: ei_monovan -- monovan sample incident energy + @param: monvan_run -- run descriptor of converted to energy monovan workspace + @param: ei_monovan -- monovan sample incident energy @returns the value of monovan absolute normalization factor. deletes monovan workspace (deltaE_wkspace) if abs norm factor was calculated successfully @@ -1065,9 +1083,11 @@ class DirectEnergyConversion(object): # list of two number representing the minimal (ei_monovan[0]) # and the maximal (ei_monovan[1]) energy to integrate the spectra minmax = propman.monovan_integr_range + mono_vs = monovan_run.get_workspace() + ws_name = mono_vs.name() - - data_ws = Integration(InputWorkspace=deltaE_wkspaceName,OutputWorkspace='van_int',RangeLower=minmax[0],RangeUpper=minmax[1],IncludePartialBins='1') + data_ws = Integration(InputWorkspace=mono_vs,OutputWorkspace='van_int', + RangeLower=minmax[0],RangeUpper=minmax[1],IncludePartialBins='1') nhist = data_ws.getNumberHistograms() # extract wb integrals for combined spectra @@ -1075,23 +1095,21 @@ class DirectEnergyConversion(object): error = [] izerc = 0 for i in range(nhist): - try: - det = data_ws.getDetector(i) - except Exception: - continue - if det.isMasked(): - continue - sig = data_ws.readY(i)[0] - err = data_ws.readE(i)[0] - if sig != sig: #ignore NaN (hopefully it will mean mask some day) - continue - if (err <= 0) or (sig <= 0): # count Inf and negative||zero readings. Presence of this indicates that - # something went wrong - izerc+=1 - continue - - signal.append(sig) - error.append(err) + try: + det = data_ws.getDetector(i) + except Exception: + continue + if det.isMasked(): + continue + sig = data_ws.readY(i)[0] + err = data_ws.readE(i)[0] + if sig != sig: #ignore NaN (hopefully it will mean mask some day) + continue + if (err <= 0) or (sig <= 0): # count Inf and negative||zero readings. + izerc+=1 # Presence of this indicates that + continue # something went wrong + signal.append(sig) + error.append(err) #---------------- Loop finished norm_factor = {} @@ -1120,8 +1138,8 @@ class DirectEnergyConversion(object): signal_sum = sum(map(lambda e: e * e,error)) weight_sum = sum(map(lambda s,e: e * e / s,signal,error)) if weight_sum == 0.0: - prop_man.log("WB integral has been calculated incorrectly, look at van_int workspace: {0}".format(deltaE_wkspaceName),'error') - raise ArithmeticError("Division by 0 weight when calculating WB integrals from workspace {0}".format(deltaE_wkspaceName)) + prop_man.log("WB integral has been calculated incorrectly, look at van_int workspace: {0}".format(ws_name),'error') + raise ArithmeticError("Division by 0 weight when calculating WB integrals from workspace {0}".format(ws_name)) norm_factor['Poisson'] = signal_sum / weight_sum #------------------------------------------------------------------------- # Guess which estimates value sum(n_i^2/Sigma_i^2)/sum(n_i/Sigma_i^2) @@ -1129,8 +1147,8 @@ class DirectEnergyConversion(object): signal_sum = sum(map(lambda s,e: s * s / (e * e),signal,error)) weight_sum = sum(map(lambda s,e: s / (e * e),signal,error)) if weight_sum == 0.0: - prop_man.log("WB integral has been calculated incorrectly, look at van_int workspace: {0}".format(deltaE_wkspaceName),'error') - raise ArithmeticError("Division by 0 weight when calculating WB integrals from workspace {0}".format(deltaE_wkspaceName)) + prop_man.log("WB integral has been calculated incorrectly, look at van_int workspace: {0}".format(ws_name),'error') + raise ArithmeticError("Division by 0 weight when calculating WB integrals from workspace {0}".format(ws_name)) norm_factor['TGP'] = signal_sum / weight_sum # # @@ -1150,11 +1168,11 @@ class DirectEnergyConversion(object): # check for NaN if (norm_factor['LibISIS'] != norm_factor['LibISIS']) | (izerc != 0): # It is an error, print diagnostics: - if norm_factor['LibISIS'] != norm_factor['LibISIS']: - log_value = '\n--------> Absolute normalization factor is NaN <----------------------------------------------\n' - else: - log_value = '\n--------> Warning, Monovanadium has zero spectra <--------------------------------------------\n' - log1_value = \ + if norm_factor['LibISIS'] != norm_factor['LibISIS']: + log_value = '\n--------> Absolute normalization factor is NaN <----------------------------------------------\n' + else: + log_value = '\n--------> Warning, Monovanadium has zero spectra <--------------------------------------------\n' + log1_value = \ "--------> Processing workspace: {0}\n"\ "--------> Monovan Integration range : min={1}, max={2} (meV)\n"\ "--------> Summed: {3} spectra with total signal: {4} and error: {5}\n"\ @@ -1164,24 +1182,22 @@ class DirectEnergyConversion(object): "--------> Abs norm factors: Sigma^2: {9}\n"\ "--------> Abs norm factors: Poisson: {10}\n"\ "--------> Abs norm factors: TGP : {11}\n"\ - .format(deltaE_wkspaceName,minmax[0],minmax[1],nhist,sum(signal),sum(error),izerc,scale_factor,\ + .format(ws_name,minmax[0],minmax[1],nhist,sum(signal),sum(error),izerc,scale_factor, norm_factor['LibISIS'],norm_factor['SigSq'],norm_factor['Poisson'],norm_factor['TGP']) - log_value = log_value + log1_value - propman.log(log_value,'error') + log_value = log_value + log1_value + propman.log(log_value,'error') else: if not self._debug_mode: - DeleteWorkspace(Workspace=deltaE_wkspaceName) + monovan_run.clear_resulting_ws() DeleteWorkspace(Workspace=data_ws) return (norm_factor['LibISIS'],norm_factor['SigSq'],norm_factor['Poisson'],norm_factor['TGP']) #--------------------------------------------------------------------------- # Behind the scenes stuff #--------------------------------------------------------------------------- - def __init__(self, instr_name=None,reload_instrument=False): - """ - Constructor - """ + """Constructor """ + object.__setattr__(self,'_descriptors',[]) object.__setattr__(self,'_propMan',None) # Debug parameter. Usually True unless investigating a problem @@ -1210,27 +1226,27 @@ class DirectEnergyConversion(object): #end def __getattr__(self,attr_name): - """ overloaded to return values of properties non-existing in the class dictionary + """ overloaded to return values of properties non-existing in the class dictionary from the property manager class except this property already have descriptor in self class """ - if attr_name in self._descriptors: - return object.__getattr__(self,attr_name) - else: - return getattr(self._propMan,attr_name) + if attr_name in self._descriptors: + return object.__getattr__(self,attr_name) + else: + return getattr(self._propMan,attr_name) def __setattr__(self,attr_name,attr_value): - """ overloaded to prohibit adding non-starting with _properties to the class instance + """ overloaded to prohibit adding non-starting with _properties to the class instance and add all other properties to property manager except this property already - have a descriptor - """ - if attr_name[0] == '_': + have a descriptor + """ + if attr_name[0] == '_': object.__setattr__(self,attr_name,attr_value) - else: - if attr_name in self._descriptors: - object.__setattr__(self,attr_name,attr_value) - else: - setattr(self._propMan,attr_name,attr_value) + else: + if attr_name in self._descriptors: + object.__setattr__(self,attr_name,attr_value) + else: + setattr(self._propMan,attr_name,attr_value) def initialise(self, instr,reload_instrument=False): """ @@ -1274,20 +1290,20 @@ class DirectEnergyConversion(object): instrument = workspace.getInstrument() name = instrument.getName() if name != self.prop_man.instr_name: - self.prop_man = PropertyManager(name,workspace) + self.prop_man = PropertyManager(name,workspace) def get_run_descriptor(self,run): - """ Spawn temporary run descriptor for input data given in format, + """ Spawn temporary run descriptor for input data given in format, different from run descriptor. Return existing run descriptor, if it is what provided. """ - if not isinstance(run,RunDescriptor): - tRun = copy.copy(PropertyManager._tmp_run) - tRun.__set__(None,run) - return tRun - else: - return run + if not isinstance(run,RunDescriptor): + tRun = copy.copy(PropertyManager._tmp_run) + tRun.__set__(None,run) + return tRun + else: + return run # # ------------------------------------------------------------------------------------------- # This actually does the conversion for the mono-sample and @@ -1348,10 +1364,10 @@ class DirectEnergyConversion(object): energy_bins = PropertyManager.energy_bins.get_abs_range(self.prop_man) if energy_bins: - Rebin(InputWorkspace=result_name,OutputWorkspace=result_name,Params= energy_bins,PreserveEvents=False) - if bkgr_ws: # remove background after converting units and rebinning - RemoveBackground(InputWorkspace=result_name,OutputWorkspace=result_name,BkgWorkspace=bkgr_ws,EMode='Direct') - DeleteWorkspace(bkgr_ws) + Rebin(InputWorkspace=result_name,OutputWorkspace=result_name,Params= energy_bins,PreserveEvents=False) + if bkgr_ws: # remove background after converting units and rebinning + RemoveBackground(InputWorkspace=result_name,OutputWorkspace=result_name,BkgWorkspace=bkgr_ws,EMode='Direct') + DeleteWorkspace(bkgr_ws) else: pass # TODO: investigate way of removing background from event workspace if we want # result to be an event workspace @@ -1360,8 +1376,8 @@ class DirectEnergyConversion(object): if self.apply_detector_eff and energy_bins: #should detector efficiency work on event workspace too? At the moment it is #not (01/02/2015) - DetectorEfficiencyCor(InputWorkspace=result_name,OutputWorkspace=result_name) - self.prop_man.log("_do_mono: finished DetectorEfficiencyCor for : " + result_name,'information') + DetectorEfficiencyCor(InputWorkspace=result_name,OutputWorkspace=result_name) + self.prop_man.log("_do_mono: finished DetectorEfficiencyCor for : " + result_name,'information') ############# data_run.synchronize_ws(mtd[result_name]) @@ -1382,13 +1398,13 @@ class DirectEnergyConversion(object): bkgr_ws = CloneWorkspace(InputWorkspace='bkgr_ws_source',OutputWorkspace='bkgr_ws') if time_shift != 0: # Workspace has probably been shifted, so to have correct units conversion # one needs to do appropriate shift here as well - CopyInstrumentParameters(result_ws,bkgr_ws) + CopyInstrumentParameters(result_ws,bkgr_ws) # Adjust the TOF such that the first monitor peak is at t=0 - ScaleX(InputWorkspace=bkgr_ws,OutputWorkspace='bkgr_ws',Operation="Add",Factor=time_shift,\ + ScaleX(InputWorkspace=bkgr_ws,OutputWorkspace='bkgr_ws',Operation="Add",Factor=time_shift,\ InstrumentParameter="DelayTime",Combine=True) else: - bkgr_ws = Rebin(result_ws,Params=[bkg_range_min,(bkg_range_max - bkg_range_min) * 1.001,bkg_range_max],PreserveEvents=False) - bkgr_ws = self.normalise(bkgr_ws, self.normalise_method, time_shift) + bkgr_ws = Rebin(result_ws,Params=[bkg_range_min,(bkg_range_max - bkg_range_min) * 1.001,bkg_range_max],PreserveEvents=False) + bkgr_ws = self.normalise(bkgr_ws, self.normalise_method, time_shift) return bkgr_ws @@ -1404,13 +1420,14 @@ class DirectEnergyConversion(object): self._do_mono_ISIS(run,ei_guess,\ white_run, map_file, spectra_masks, Tzero) else: - result_name = run.set_action_suffix('_spe') - self._do_mono_SNS(run,result_name,ei_guess,\ + result_name = run.set_action_suffix('_spe') + self._do_mono_SNS(run,result_name,ei_guess,\ white_run, map_file, spectra_masks, Tzero) - run.synchronize_ws() + run.synchronize_ws() prop_man = self.prop_man - result_name = run.get_ws_name() + ws = run.get_workspace() + result_name = ws.name() ####################### # Ki/Kf Scaling... if prop_man.apply_kikf_correction: @@ -1420,8 +1437,8 @@ class DirectEnergyConversion(object): # Make sure that our binning is consistent if prop_man.energy_bins: - bins = PropertyManager.energy_bins.get_abs_range(prop_man) - Rebin(InputWorkspace=result_name,OutputWorkspace= result_name,Params=bins) + bins = PropertyManager.energy_bins.get_abs_range(prop_man) + Rebin(InputWorkspace=result_name,OutputWorkspace= result_name,Params=bins) # Masking and grouping result_ws = mtd[result_name] @@ -1457,12 +1474,12 @@ class DirectEnergyConversion(object): old_log_val = targ_ws.getRun().getLogData(done_Log).value done_log_VAL = self._build_white_tag() if old_log_val == done_log_VAL: - run.synchronize_ws(targ_ws) - if self._keep_wb_workspace: + run.synchronize_ws(targ_ws) + if self._keep_wb_workspace: result = run.get_ws_clone() - else: + else: result = run.get_workspace() - return result + return result else: DeleteWorkspace(Workspace=new_ws_name) else: @@ -1503,29 +1520,23 @@ class DirectEnergyConversion(object): white_tag = 'NormBy:{0}_IntergatedIn:{1:0>10.2f}:{2:0>10.2f}'.format(self.normalise_method,low,upp) return white_tag -#------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- -#------------------------------------------------------------------------------- def get_failed_spectra_list_from_masks(masked_wksp): """Compile a list of spectra numbers that are marked as masked in the masking workspace - Input: - masking_workspace - A special masking workspace containing masking data + Input: + masking_workspace - A special masking workspace containing masking data """ #TODO: get rid of this and use data, obtained form diagnostics - failed_spectra = [] if masked_wksp is None: - return (failed_spectra,0) + return (failed_spectra,0) masking_wksp,sp_list = ExtractMask(masked_wksp) DeleteWorkspace(masking_wksp) n_spectra = len(sp_list) - return (sp_list.tolist(),n_spectra) - - + return n_spectra #----------------------------------------------------------------- if __name__ == "__main__": pass diff --git a/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py b/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py index 102426faa1ce55416280bd359430478b0618d286..d333b7ff12e603639910c095e34bdfbbd881e890 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py +++ b/Code/Mantid/scripts/Inelastic/Direct/NonIDF_Properties.py @@ -58,7 +58,7 @@ class NonIDF_Properties(object): super(NonIDF_Properties,self).__setattr__('wb_for_monovan_run',None) super(NonIDF_Properties,self).__setattr__('second_white',None) super(NonIDF_Properties,self).__setattr__('_tmp_run',None) - + super(NonIDF_Properties,self).__setattr__('_cashe_sum_ws',False) #end def log(self, msg,level="notice"): @@ -97,8 +97,6 @@ class NonIDF_Properties(object): second_white = RunDescriptor("Second white beam currently unused in the workflow despite being referred to in Diagnostics. Should it be used for Monovan Diagnostics?") # _tmp_run = RunDescriptor("_TMP","Property used for storing intermediate run data during reduction") - # property responsible for summing runs - sum_runs = SumRuns(sample_run) #----------------------------------------------------------------------------------- def getDefaultParameterValue(self,par_name): """ method to get default parameter value, specified in IDF """ @@ -122,6 +120,17 @@ class NonIDF_Properties(object): #----------------------------------------------------------------------------------- # ----------------------------------------------------------------------------- @property + def cashe_sum_ws(self): + """ Used together with sum_runs property. If True, a workspace + with partial sum is stored in ADS + and used later to add more runs to it + """ + return self._cashe_sum_ws + @cashe_sum_ws.setter + def cashe_sum_ws(self,val): + self._cashe_sum_ws = bool(val) + # ----------------------------------------------------------------------------- + @property def log_to_mantid(self): """ Property specify if high level log should be printed to stdout or added to common Mantid log""" return self._log_to_mantid diff --git a/Code/Mantid/scripts/Inelastic/Direct/PropertiesDescriptors.py b/Code/Mantid/scripts/Inelastic/Direct/PropertiesDescriptors.py index 0459aa0c1819d47ad33cfc132b67bf310a285e15..13ec719bfc4b6e8de2b73aa9ac79ef7d9080bef7 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/PropertiesDescriptors.py +++ b/Code/Mantid/scripts/Inelastic/Direct/PropertiesDescriptors.py @@ -20,6 +20,14 @@ class PropDescriptor(object): def dependencies(self): """ Returns the list of other properties names, this property depends on""" return [] + def validate(self,instance, owner): + """ Interface to validate property descriptor, + provided to check properties interaction before long run + + Return validation result, errors severity (0 -- fine, 1 -- warning, 2-- error) + and error message if any + """ + return (True,0,'') # end PropDescriptor #----------------------------------------------------------------------------------------- @@ -30,172 +38,34 @@ class SumRuns(PropDescriptor): """ Boolean property specifies if list of files provided as input for sample_run property should be summed. - It also specifies various auxiliary operations, defined for summing runs, so property - is deeply entangled with the sample_run property """ def __init__(self,sample_run_prop): # internal reference to sample run property self._sample_run = sample_run_prop # class containing this property - self._holder = None # - self._last_ind2sum = -1 self._sum_runs = False - self._run_numbers = [] - self._file_guess = [] - self._fext = [] - - # def __get__(self,instance,holder_class): - if not self._holder: - self._holder = holder_class - if instance is None: - return self - return self._sum_runs + if instance is None: + return self + return self._sum_runs # def __set__(self,instance,value): - if not self._holder: - from Direct.PropertyManager import PropertyManager - self._holder = PropertyManager - old_value = self._sum_runs if isinstance(value,bool): self._sum_runs = value - self._last_ind2sum = -1 elif isinstance(value,int): if value > 0: - self._last_ind2sum = int(value) - 1 - self._sum_runs = True + self._sum_runs = True else: - self._last_ind2sum = -1 - self._sum_runs = False + self._sum_runs = False else: self._sum_runs = bool(value) - self._last_ind2sum = -1 # if old_value != self._sum_runs: - if len(self._run_numbers) > 0 and self._sum_runs: - # clear previous state of sample_run - ind = self.get_last_ind2sum() - self._sample_run.__set__(None,self._run_numbers[ind]) - # - def set_list2add(self,runs_to_add,fnames=None,fext=None): - """Set run numbers to add together with possible file guess-es """ - if not isinstance(runs_to_add,list): - raise KeyError('Can only set list of run numbers to add') - runs = [] - for item in runs_to_add: - runs.append(int(item)) - self._run_numbers = runs - if fnames: - self._file_guess = fnames - if len(self._file_guess) != len(self._run_numbers): - self._file_guess = [''] * len(self._run_numbers) - - if fext: - self._fext = fext - if len(self._fext) != len(self._run_numbers): - self._fext = [''] * len(self._run_numbers) - # - def clear_sum(self): - """Clear all defined summation""" - # if last_to_sum is -1, sum all run list provided - self._last_ind2sum = -1 - self._sum_runs = False - self._run_numbers = [] - self._file_guess = [] - self._fext = [] - # - def get_last_ind2sum(self): - """Get last run number contributing to sum""" - if self._last_ind2sum > 0: - return self._last_ind2sum - else: - return len(self._run_numbers) - 1 - # - def set_last_ind2sum(self,run_number): - """Check and set last number, contributing to summation - if this number is out of summation range, clear the summation - """ - run_number = int(run_number) - if run_number in self._run_numbers: - self._last_ind2sum = self._run_numbers.index(run_number) + 1 - return self._last_ind2sum - else: - self.clear_sum() - return 0 - # - def get_run_list2sum(self): - """Get run numbers of the files to be summed together """ - num_to_load = len(self._run_numbers) - if self._last_ind2sum > 0 and self._last_ind2sum < num_to_load: - num_to_load = self._last_ind2sum - return self._run_numbers[:num_to_load] + self._sample_run.notify_sum_runs_changed(old_value,self._sum_runs) - # - def load_and_sum_runs(self,inst_name,monitors_with_ws): - """ Load multiple runs and sum them together """ - - logger = lambda mess : (getattr(getattr(self,'_holder'),'log')\ - (self._sample_run._holder,mess)) - logger("*** Summing multiple runs ****") - - runs_to_load = self.get_run_list2sum() - num_to_load = len(runs_to_load) - logger("*** Loading #{0}/{1}, run N: {2} ".\ - format(1,num_to_load,self._run_numbers[0])) - - - file_h = os.path.join(self._file_guess[0],'{0}{1}{2}'.\ - format(inst_name,runs_to_load[0],self._fext[0])) - ws = self._sample_run.load_file(inst_name,'Summ',False,monitors_with_ws, - False,file_hint=file_h) - - sum_ws_name = ws.name() - sum_mon_name = sum_ws_name + '_monitors' - AddedRunNumbers = str(self._sample_run.run_number()) - - for ind,run_num in enumerate(runs_to_load[1:num_to_load]): - - file_h = os.path.join(self._file_guess[ind + 1],'{0}{1}{2}'.\ - format(inst_name,run_num,self._fext[ind + 1])) - logger("*** Adding #{0}/{1}, run N: {2} ".\ - format(ind + 2,num_to_load,run_num)) - term_name = '{0}_ADDITIVE_#{1}/{2}'.format(inst_name,ind + 2,num_to_load)# - - wsp = self._sample_run.load_file(inst_name,term_name,False,\ - monitors_with_ws,False,file_hint=file_h) - - wsp_name = wsp.name() - wsp_mon_name = wsp_name + '_monitors' - Plus(LHSWorkspace=sum_ws_name,RHSWorkspace=wsp_name,\ - OutputWorkspace=sum_ws_name,ClearRHSWorkspace=True) - AddedRunNumbers+=',{0}'.format(run_num) - if not monitors_with_ws: - Plus(LHSWorkspace=sum_mon_name,RHSWorkspace=wsp_mon_name,\ - OutputWorkspace=sum_mon_name,ClearRHSWorkspace=True) - if wsp_name in mtd: - DeleteWorkspace(wsp_name) - if wsp_mon_name in mtd: - DeleteWorkspace(wsp_mon_name) - logger("*** Summing multiple runs completed ****") - - AddSampleLog(Workspace=sum_ws_name,LogName = 'SumOfRuns:', - LogText=AddedRunNumbers,LogType='String') - ws = mtd[sum_ws_name] - return ws - # - def sum_ext(self): - if self._sum_runs: - last = self.get_last_ind2sum() - sum_ext = "SumOf{0}".format(len(self._run_numbers[:last + 1])) - else: - sum_ext = '' - return sum_ext - # - def get_runs(self): - return self._run_numbers #-------------------------------------------------------------------------------------------------------------------- class IncidentEnergy(PropDescriptor): """ Property for incident energy or range of incident energies to be processed @@ -213,58 +83,55 @@ class IncidentEnergy(PropDescriptor): def __get__(self,instance,owner=None): """ return incident energy or list of incident energies """ if instance is None: - return self - + return self return self._incident_energy + def __set__(self,instance,value): - """ Set up incident energy or range of energies in various formats """ - if value != None: - if isinstance(value,str): - if value.find('[') > -1: - energy_list = True - value = value.translate(None, '[]').strip() - else: - energy_list = False - en_list = str.split(value,',') - if len(en_list) > 1: - rez = [] - for en_str in en_list: - val = float(en_str) - rez.append(val) - self._incident_energy = rez - else: - if energy_list: - self._incident_energy = [float(value)] + """ Set up incident energy or range of energies in various formats """ + if value != None: + if isinstance(value,str): + if value.find('[') > -1: + energy_list = True + value = value.translate(None, '[]').strip() + else: + energy_list = False + en_list = str.split(value,',') + if len(en_list) > 1: + rez = [] + for en_str in en_list: + val = float(en_str) + rez.append(val) + self._incident_energy = rez + else: + if energy_list: + self._incident_energy = [float(value)] + else: + self._incident_energy = float(value) + else: + if isinstance(value,list): + rez = [] + for val in value: + en_val = float(val) + if en_val <= 0: + raise KeyError("Incident energy has to be positive, but is: {0} ".format(en_val)) else: - self._incident_energy = float(value) + rez.append(en_val) + self._incident_energy = rez else: - if isinstance(value,list): - rez = [] - for val in value: - en_val = float(val) - if en_val <= 0: - raise KeyError("Incident energy has to be positive, but is: {0} ".format(en_val)) - else: - rez.append(en_val) - self._incident_energy = rez - else: - self._incident_energy = float(value) - else: - raise KeyError("Incident energy have to be positive number of list of positive numbers. Got None") - - # - inc_en = self._incident_energy - if isinstance(inc_en,list): - self._num_energies = len(inc_en) - for en in inc_en: - if en <= 0: - raise KeyError("Incident energy have to be positive number of list of positive numbers." + " For input argument {0} got negative value {1}".format(value,en)) - else: - self._num_energies = 1 - if inc_en <= 0: - raise KeyError("Incident energy have to be positive number of list of positive numbers." + " For value {0} got negative {1}".format(value,inc_en)) - self._cur_iter_en = 0 - + self._incident_energy = float(value) + else: + raise KeyError("Incident energy have to be positive number of list of positive numbers. Got None") + + if isinstance(self._incident_energy,list): + self._num_energies = len(self._incident_energy) + else: + self._num_energies = 1 + self._cur_iter_en = 0 + + ok,sev,message = self.validate(instance) + if not ok: + raise KeyError(message) + def multirep_mode(self): """ return true if energy is defined as list of energies and false otherwise """ if isinstance(self._incident_energy,list): @@ -280,13 +147,19 @@ class IncidentEnergy(PropDescriptor): else: return self._incident_energy # - def set_current(self,value): - """ set current energy value (used in multirep mode) to - + def set_current(self,value,ind=None): + """ set current energy value (used in multirep mode) as + energy estimate for the reduction + + ind -- if provided, the number of the value in the list of + values (can be used together with enumerate) """ if isinstance(self._incident_energy,list): - ind = self._cur_iter_en - self._incident_energy[ind]=value + if ind is None: + ind = self._cur_iter_en + else: + self._cur_iter_en = ind + self._incident_energy[ind] = value else: self._incident_energy = value @@ -300,16 +173,30 @@ class IncidentEnergy(PropDescriptor): """ part of iterator """ self._cur_iter_en += 1 ind = self._cur_iter_en - if ind < self._num_energies: - if isinstance(self._incident_energy,list): - return self._incident_energy[ind] - else: - return self._incident_energy + if ind < self._num_energies: + if isinstance(self._incident_energy,list): + return self._incident_energy[ind] + else: + return self._incident_energy else: - raise StopIteration + raise StopIteration + def validate(self,instance,owner=None): + # + inc_en = self._incident_energy + if isinstance(inc_en,list): + for ind,en in enumerate(inc_en): + if en <= 0: + return (False,2,"Incident energy have to be positive number or list of positive numbers.\n" + + "For input argument {0} got negative energy {1}".format(ind,en)) + else: + if inc_en <= 0: + return (False,2,"Incident energy have to be positive number or list of positive numbers.\n" + + "Got single negative incident energy {0} ".format(inc_en)) + return (True,0,'') # end IncidentEnergy #----------------------------------------------------------------------------------------- + class EnergyBins(PropDescriptor): """ Energy binning, requested for final converted to energy transfer workspace. @@ -331,22 +218,22 @@ class EnergyBins(PropDescriptor): def __get__(self,instance,owner=None): """ binning range for the result of convertToenergy procedure or list of such ranges """ if instance is None: - return self + return self return self._energy_bins def __set__(self,instance,values): - if values != None: - if isinstance(values,str): - values = values.translate(None, '[]').strip() - lst = values.split(',') - self.__set__(instance,lst) - return - else: - value = values - if len(value) != 3: + if values != None: + if isinstance(values,str): + values = values.translate(None, '[]').strip() + lst = values.split(',') + self.__set__(instance,lst) + return + else: + value = values + if len(value) != 3: raise KeyError("Energy_bin value has to be a tuple of 3 elements or string of 3 comma-separated numbers") - value = (float(value[0]),float(value[1]),float(value[2])) + value = (float(value[0]),float(value[1]),float(value[2])) # Let's not support list of multiple absolute energy bins for the # time being # nBlocks = len(value) @@ -354,10 +241,10 @@ class EnergyBins(PropDescriptor): # raise KeyError("Energy_bin value has to be either list of # n-blocks of 3 number each or string representation of this list # with numbers separated by commas") - else: + else: value = None #TODO: implement single value settings according to rebin? - self._energy_bins = value + self._energy_bins = value def get_abs_range(self,instance=None): """ return energies related to incident energies either as @@ -367,28 +254,28 @@ class EnergyBins(PropDescriptor): ei = self._incident_energy.get_current() if self._energy_bins: if self.is_range_valid(): - rez = self._calc_relative_range(ei) + rez = self._calc_relative_range(ei) else: - if instance: - instance.log("*** WARNING! Got energy_bins specified as absolute values in multirep mode.\n"\ + if instance: + instance.log("*** WARNING! Got energy_bins specified as absolute values in multirep mode.\n"\ " Will normalize these values by max value and treat as relative values ",\ "warning") - mult = self._range / self._energy_bins[2] - rez = self._calc_relative_range(ei,mult) + mult = self._range / self._energy_bins[2] + rez = self._calc_relative_range(ei,mult) return rez else: - return None + return None else: # Absolute energy ranges - if self.is_range_valid(): - return self._energy_bins - else: - if instance: - instance.log("*** WARNING! Requested maximum binning range exceeds incident energy!\n"\ + if self.is_range_valid(): + return self._energy_bins + else: + if instance: + instance.log("*** WARNING! Requested maximum binning range exceeds incident energy!\n"\ " Will normalize binning range by max value and treat as relative range",\ "warning") - mult = self._range / self._energy_bins[2] - ei = self._incident_energy.get_current() - return self._calc_relative_range(ei,mult) + mult = self._range / self._energy_bins[2] + ei = self._incident_energy.get_current() + return self._calc_relative_range(ei,mult) def is_range_valid(self): """Method verifies if binning range is consistent with incident energy """ @@ -402,6 +289,19 @@ class EnergyBins(PropDescriptor): mult = range_mult * ei return (self._energy_bins[0] * mult ,self._energy_bins[1] * mult,self._energy_bins[2] * mult) + def validate(self,instance,owner): + """ function verifies if the energy binning is consistent with incident energies """ + ei = instance.incident_energy + ebin = instance.energy_bins + if isinstance(ei,list): # ebin expected to be relative + if ebin[2]>1: + return(False,1,"Binning for multiple energy range should be relative to incident energy. Got ebin_max={0} > 1\n"+\ + "Energy range will be normalized and treated as relative range") + else: + if ebin[2] > ei: + return (False,2,'Max rebin range {0:f} exceeds incident energy {1:f}'.format(ebin[2],en)) + return(True,0,'') +#----------------------------------------------------------------------------------------- #end EnergyBins #----------------------------------------------------------------------------------------- @@ -411,11 +311,15 @@ class SaveFileName(PropDescriptor): See similar property get_sample_ws_name TODO: (leave only one) """ def __init__(self,Name=None): - self._file_name = Name + self._file_name = Name + self._custom_print = None def __get__(self,instance,owner=None): if instance is None: - return self + return self + if not (self._custom_print is None): + return self._custom_print(instance,owner) + if self._file_name: return self._file_name else: @@ -441,6 +345,8 @@ class SaveFileName(PropDescriptor): def __set__(self,instance,value): self._file_name = value + def set_custom_print(self,routine): + self._custom_print = routine #end SaveFileName #----------------------------------------------------------------------------------------- class InstrumentDependentProp(PropDescriptor): @@ -451,30 +357,17 @@ class InstrumentDependentProp(PropDescriptor): self._prop_name = prop_name def __get__(self,instance,owner=None): - if instance is None: - return self + if instance is None: + return self - if instance._pInstrument is None: + if instance._pInstrument is None: raise KeyError("Attempt to use uninitialized property manager") - else: + else: return getattr(instance,self._prop_name) def __set__(self,instance,values): raise AttributeError("Property {0} can not be assigned".format(self._prop_name)) #end InstrumentDependentProp #----------------------------------------------------------------------------------------- -def check_ei_bin_consistent(ei,binning_range): - """ function verifies if the energy binning is consistent with incident energies """ - if isinstance(ei,list): - for en in ei: - range = binning_range[en] - if range[2] > en: - return (False,'Max rebin range {0:f} exceeds incident energy {1:f}'.format(range[2],en)) - else: - if binning_range[2] > ei: - return (False,'Max rebin range {0:f} exceeds incident energy {1:f}'.format(binning_range[2],ei)) - - return (True,'') -#----------------------------------------------------------------------------------------- class VanadiumRMM(PropDescriptor): """ define constant static rmm for vanadium """ def __get__(self,instance,owner=None): @@ -508,56 +401,79 @@ class mon2NormalizationEnergyRange(PropDescriptor): def __get__(self,instance,owner): - """ Return actual energy range from internal relative range and incident energy """ - if instance is None: - return self - return [self._relative_range[0] * instance.incident_energy,self._relative_range[1] * instance.incident_energy] + """ Return actual energy range from internal relative range and incident energy """ + if instance is None: + return self + ei = owner.incident_energy.get_current() + return [self._relative_range[0]*ei, self._relative_range[1]*ei] def __set__(self,instance,val): - """ set detector calibration file using various formats """ - if isinstance(val,list): - self._relative_range = self._check_range(val,instance) - elif isinstance(val,str): - val = self._parce_string2list(val) - self.__set__(instance,val) - else: + """ set detector calibration file using various formats """ + if isinstance(val,list): + self._relative_range = self._check_range(val,instance) + elif isinstance(val,str): + val = self._parce_string2list(val) + self.__set__(instance,val) + else: raise KeyError('mon2_norm_energy_range needs to be initialized by two values.\n'\ 'Trying to assign value {0} of unknown type {1}'.format(val,type(val))) # def _check_range(self,val,instance): """ method to check if list of values acceptable as ranges """ + if len(val) != 2: - raise KeyError('mon2_normalization_energy_range can be initialized by list of two values only. Got {0} values'.format(len(val))) - val1 = float(val[0]) + raise KeyError("mon2_norm_energy_range needs to be initialized by lost of two values. Got {0}".format(len(val))) + self._relative_range = (float(val[0]),float(val[1])) + ok,sev,message=self.validate(instance) + if not ok: + if sev == 1: + instance.log(message,'warning') + else: + raise KeyError(message) + + return self._relative_range + # + def _parce_string2list(self,val): + """ method splits input string containing comma into list of strings""" + value = val.strip('[]()') + val = value.split(',') + return val + + def validate(self,instance,owner=None): + """ function verifies if the energy range is consistent with incident energies """ + range = self._relative_range + if len(range ) != 2: + return(False,2,'mon2_normalization_energy_range can be initialized by list of two values only. Got {0} values'.format(len(range))) + + result = (True,0,'') + + val1 = float(range[0]) if val1 < 0.1 or val1 > 0.9: message = "Lower mon2_norm_energy_range describes lower limit of energy to integrate neutron signal after the chopper.\n"\ "The limit is defined as (this value)*incident_energy. Are you sure you want to set this_value to {0}?\n".format(val1) if val1 > 1: - raise KeyError(message) + return(False,2,message) else: - instance.log(message,'warning') - val2 = float(val[1]) + result = (False,1,message) + + + val2 = float(range[1]) if val2 < 1.1 or val2 > 1.9: - message = "Upper mon2_norm_energy_range describes upper limit of energy to integrate neutron signal after the chopper.\n"\ + message = "Upper mon2_norm_energy_range describes upper limit of energy to integrate neutron signal after the chopper.\n"\ "The limit is defined as (this value)*incident_energy. Are you sure you want to set this_value to {0}?\n".format(val2) - if val2 < 1: - raise KeyError(message) - else: - instance.log(message,'warning') + if val2 > 1: + if result[0]: + result = (False,1,message) + else: + result = (False,1,result[2]+message) + else: + return (False,2,message) - return [val1,val2] - # - def _parce_string2list(self,val): - """ method splits input string containing comma into list of strings""" - value = val.strip('[]()') - val = value.split(',') - return val + return result #----------------------------------------------------------------------------------------- class PropertyFromRange(PropDescriptor): """ Descriptor for property, which can have one value from a list of values """ - _current_value = None - def __init__(self,availible_values,default_value): self._availible_values = availible_values self.__set__(None,default_value) @@ -565,49 +481,48 @@ class PropertyFromRange(PropDescriptor): def __get__(self,instance,owner): """ Return current value for the property with range of values. """ if instance is None: - return self + return self return self._current_value def __set__(self,instance,val): - """ set detector calibration file using various formats """ - if val in self._availible_values: - self._current_value = val - else: - raise KeyError(' Property can not have value {0}'.format(val)) + if val in self._availible_values: + self._current_value = val + else: + raise KeyError(' Property can not have value {0}'.format(val)) #----------------------------------------------------------------------------------------- class DetCalFile(PropDescriptor): """ property describes various sources for the detector calibration file """ def __init__(self): self._det_cal_file = None + self._calibrated_by_run = False def __get__(self,instance,owner): if instance is None: - return self + return self return self._det_cal_file def __set__(self,instance,val): - """ set detector calibration file using various formats """ + """ set detector calibration file using various formats """ - if val is None or isinstance(val,api.Workspace) or isinstance(val,str): + if val is None or isinstance(val,api.Workspace) or isinstance(val,str): # nothing provided or workspace provided or filename probably provided - if str(val) in mtd: - # workspace name provided - val = mtd[str(val)] - self._det_cal_file = val - return + if str(val) in mtd: + # workspace name provided + val = mtd[str(val)] + self._det_cal_file = val + self._calibrated_by_run = False + return - if isinstance(val,int): + if isinstance(val,int): #if val in instance.all_run_numbers: TODO: retrieve workspace from #run numbers - file_hint = str(val) - file_name = FileFinder.findRuns(file_hint)[0] - self._det_cal_file = file_name - return - - raise NameError('Detector calibration file name can be a workspace name present in Mantid or string describing an file name') + self._det_cal_file = val + self._calibrated_by_run = True + return + raise NameError('Detector calibration file name can be a workspace name present in Mantid or string describing an file name') #if Reducer.det_cal_file != None : # if isinstance(Reducer.det_cal_file,str) and not Reducer.det_cal_file # in mtd : # it is a file @@ -619,30 +534,80 @@ class DetCalFile(PropDescriptor): #else: # Reducer.log('Setting detector calibration to detector block info from # '+str(sample_run)) + + def calibrated_by_run(self): + """ reports if the detector calibration is in a run-file or separate file(workspace)""" + return self._calibrated_by_run + + def find_file(self,**kwargs): + """ Method to find file, correspondent to + current _det_cal_file file hint + """ + if self._det_cal_file is None: + # nothing to look for + return (True,"No Detector calibration file defined") + if isinstance(self._det_cal_file,int): # this can be only a run number + file_hint = str(self._det_cal_file) + try: + file_name = FileFinder.findRuns(file_hint)[0] + except: + return (False,"Can not find run file corresponding to run N: {0}".format(file_hint)) + self._det_cal_file = file_name + return (True,file_name) + if isinstance(self._det_cal_file,api.Workspace): + # nothing to do. Workspace used for calibration + return (True,'Workspace {0} used for detectors calibration'.format(self._det_cal_file.name())) + # string can be a run number or a file name: + file_name = prop_helpers.findFile(self._det_cal_file) + if len(file_name) == 0: # it still can be a run number as string + try: + file_name = FileFinder.findRuns(self._det_cal_file)[0] + except: + return (False,"Can not find file or run file corresponding to name : {0}".format(self._det_cal_file)) + else: + pass + self._det_cal_file=file_name + return (True,file_name) #end DetCalFile #----------------------------------------------------------------------------------------- class MapMaskFile(PropDescriptor): """ common method to wrap around an auxiliary file name """ - def __init__(self,file_ext,doc_string=None): + def __init__(self,prop_name,file_ext,doc_string=None): self._file_name = None self._file_ext = file_ext - if not doc_string is None: + self._prop_name=prop_name + + if not(doc_string is None): self.__doc__ = doc_string def __get__(self,instance,type=None): if instance is None: - return self + return self return self._file_name def __set__(self,instance,value): - if value != None: - fileName, fileExtension = os.path.splitext(value) - if not fileExtension: - value = value + self._file_ext + if not(value is None): + fileName, fileExtension = os.path.splitext(value) + if not fileExtension: + value = value + self._file_ext self._file_name = value + def find_file(self,**kwargs): + """ Method to find file, correspondent to + current MapMaskFile file hint + """ + if self._file_name is None: + return (True,'No file for {0} is defined'.format(self._prop_name)) + + file_name = prop_helpers.findFile(self._file_name) + if len(file_name) == 0: # it still can be a run number as string + return (False,'No file for {0} corresponding to guess: {1} found'.format(self._prop_name,self._file_name)) + else: + self._file_name = file_name + return (True,file_name) #end MapMaskFile + #----------------------------------------------------------------------------------------- class HardMaskPlus(prop_helpers.ComplexProperty): """ Legacy HardMaskPlus class which sets up hard_mask_file to file and use_hard_mask_only to True""" @@ -650,23 +615,23 @@ class HardMaskPlus(prop_helpers.ComplexProperty): prop_helpers.ComplexProperty.__init__(self,['use_hard_mask_only','run_diagnostics']) def __get__(self,instance,type=None): if instance is None: - return self + return self return instance.hard_mask_file def __set__(self,instance,value): if value != None: - fileName, fileExtension = os.path.splitext(value) - if not fileExtension: - value = value + '.msk' - instance.hard_mask_file = value - prop_helpers.ComplexProperty.__set__(self,instance.__dict__,[False,True]) + fileName, fileExtension = os.path.splitext(value) + if not fileExtension: + value = value + '.msk' + instance.hard_mask_file = value + prop_helpers.ComplexProperty.__set__(self,instance.__dict__,[False,True]) else: - prop_helpers.ComplexProperty.__set__(self,instance.__dict__,[True,False]) + prop_helpers.ComplexProperty.__set__(self,instance.__dict__,[True,False]) try: - del instance.__changed_properties['hardmaskOnly'] + del instance.__changed_properties['hardmaskOnly'] except: - pass + pass #----------------------------------------------------------------------------------------- class HardMaskOnly(prop_helpers.ComplexProperty): @@ -680,7 +645,7 @@ class HardMaskOnly(prop_helpers.ComplexProperty): def __get__(self,instance,type=None): if instance is None: - return self + return self return prop_helpers.gen_getter(instance.__dict__,'use_hard_mask_only') def __set__(self,instance,value): @@ -710,7 +675,7 @@ class HardMaskOnly(prop_helpers.ComplexProperty): run_diagnostics = True prop_helpers.ComplexProperty.__set__(self,instance.__dict__,[use_hard_mask_only,run_diagnostics]) try: - del instance.__changed_properties['hardmaskPlus'] + del instance.__changed_properties['hardmaskPlus'] except: pass #end HardMaskOnly @@ -734,14 +699,14 @@ class MonovanIntegrationRange(prop_helpers.ComplexProperty): def __get__(self,instance,owner): if instance is None: - return self + return self if isinstance(instance,dict): - ei = 1 - tDict = instance + ei = 1 + tDict = instance else: - ei = owner.incident_energy.get_current() - tDict = instance.__dict__ + ei = owner.incident_energy.get_current() + tDict = instance.__dict__ if self._rel_range: # relative range if ei is None: @@ -754,17 +719,17 @@ class MonovanIntegrationRange(prop_helpers.ComplexProperty): def __set__(self,instance,value): if isinstance(instance,dict): - dDict = instance + dDict = instance else: - tDict = instance.__dict__ + tDict = instance.__dict__ if value is None: if not self._rel_range: self._rel_range = True self._other_prop = ['monovan_lo_frac','monovan_hi_frac'] else: if self._rel_range: - self._rel_range = False - self._other_prop = ['monovan_lo_value','monovan_hi_value'] + self._rel_range = False + self._other_prop = ['monovan_lo_value','monovan_hi_value'] if isinstance(value,str): values = value.split(',') @@ -776,11 +741,26 @@ class MonovanIntegrationRange(prop_helpers.ComplexProperty): raise KeyError("monovan_integr_range has to be list of two values, "\ "defining min/max values of integration range or None to use relative to incident energy limits") prop_helpers.ComplexProperty.__set__(self,tDict,value) + + def validate(self,instance, owner): + """ check if monovan integration range has reasonable value """ + + if instance.monovan_run is None: + return (True,0,'') + + range = sepf.__get__(instance,owner) + ei = instance.incident_energy + if range[0]>=range[1]: + return (False,2,'monovan integration range limits = [{0}:{1}] are wrong'.format(range[0],range[1])) + if range[0]<-100*ei or range[0]>100*ei: + return (False,1,'monovan integration is suspiciously wide: [{0}:{1}]. This may be incorrect'.format(range[0],range[1])) + return (True,0,'') + #end MonovanIntegrationRange #----------------------------------------------------------------------------------------- class SpectraToMonitorsList(PropDescriptor): - """ property describes list of spectra, used as monitors to estimate incident energy + """ property describes list of spectra, used as monitors to estimate incident energy in a direct scattering experiment. Necessary when a detector working in event mode is used as monitor. Specifying this number would copy @@ -788,25 +768,25 @@ class SpectraToMonitorsList(PropDescriptor): Written to work with old IDF too, where this property is absent. """ - def __init__(self): - self._spectra_to_monitors_list = None + def __init__(self): + self._spectra_to_monitors_list = None - def __get__(self,instance,type=None): - if instance is None: - return self - return self._spectra_to_monitors_list + def __get__(self,instance,type=None): + if instance is None: + return self + return self._spectra_to_monitors_list - def __set__(self,instance,spectra_list): + def __set__(self,instance,spectra_list): """ Sets copy spectra to monitors variable as a list of monitors using different forms of input """ self._spectra_to_monitors_list = self._convert_to_list(spectra_list) - def _convert_to_list(self,spectra_list): - """ convert any spectra_list representation into a list """ - if spectra_list is None: + def _convert_to_list(self,spectra_list): + """ convert any spectra_list representation into a list """ + if spectra_list is None: return None - if isinstance(spectra_list,str): + if isinstance(spectra_list,str): if spectra_list.lower() is 'none': result = None else: @@ -815,7 +795,7 @@ class SpectraToMonitorsList(PropDescriptor): for spectum in spectra : result.append(int(spectum)) - else: + else: if isinstance(spectra_list,list): if len(spectra_list) == 0: result = None @@ -825,23 +805,23 @@ class SpectraToMonitorsList(PropDescriptor): result.append(int(spectra_list[i])) else: result = [int(spectra_list)] - return result + return result #end SpectraToMonitorsList #----------------------------------------------------------------------------------------- class SaveFormat(PropDescriptor): # formats available for saving the data - save_formats = ['spe','nxspe','nxs'] - def __init__(self): - self._save_format = set() + save_formats = ['spe','nxspe','nxs'] + def __init__(self): + self._save_format = set() - def __get__(self,instance,type=None): + def __get__(self,instance,type=None): if instance is None: - return self + return self return self._save_format - def __set__(self,instance,value): + def __set__(self,instance,value): """ user can clear save formats by setting save_format=None or save_format = [] or save_format='' if empty string or empty list is provided as part of the list, all save_format-s set up earlier are cleared""" @@ -865,24 +845,33 @@ class SaveFormat(PropDescriptor): return else: try: - # set single default save format recursively - for val in value: - self.__set__(instance,val) - return + # set single default save format recursively + for val in value: + self.__set__(instance,val) + return except: - raise KeyError(' Attempting to set unknown saving format {0} of type {1}. Allowed values can be spe, nxspe or nxs'\ + raise KeyError(' Attempting to set unknown saving format {0} of type {1}. Allowed values can be spe, nxspe or nxs'\ .format(value,type(value))) #end if different types self._save_format.add(value) + + def validate(self,instance, owner): + + n_formats = len(self._save_format) + if n_formats == 0: + return (False,1,'No internal save format is defined. Results may be lost') + else: + return (True,0,'') #end SaveFormat #----------------------------------------------------------------------------------------- class DiagSpectra(PropDescriptor): - """ class describes spectra list which should be used in diagnostics + """ class describes spectra groups list, for groups to be + used in diagnostics consist of tuples list where each tuple are the numbers indicating first-last spectra in the group. - if None, all spectra are used in diagnostics + if None, all spectra used in diagnostics """ def __init__(self): @@ -890,7 +879,7 @@ class DiagSpectra(PropDescriptor): def __get__(self,instance,type=None): if instance is None: - return self + return self return self._diag_spectra @@ -930,23 +919,36 @@ class BackbgroundTestRange(PropDescriptor): self._background_test_range = None def __get__(self,instance,type=None): - if instance is None: - return self + if instance is None: + return self - if self._background_test_range: - return self._background_test_range - else: - return instance.bkgd_range + if self._background_test_range: + return self._background_test_range + else: + return instance.bkgd_range def __set__(self,instance,value): if value is None: - self._background_test_range = None - return + self._background_test_range = None + return if isinstance(value,str): value = str.split(value,',') if len(value) != 2: - raise ValueError("background test range can be set to a 2 element list of floats") - self._background_test_range = [float(value[0]),float(value[1])] + raise ValueError("background test range can be only a 2 element list of floats") + self._background_test_range = (float(value[0]),float(value[1])) + + def validate(self,instance, owner=None): + """ validate background test range """ + range = self.__get__(instance,owner) + if range is None: + return (True,0,'') + if range[0]>=range[1]: + return (False,2,' Background test range: [{0}:{1}] is incorrect '.format(range[0],range[1])) + if range[0]<0: + return (False,2,' Background test range is TOF range, so it can not be negative={0}'.format(range[0])) + if range[1]>20000: + return (False,1,' Background test range is TOF range, its max value looks suspiciously big={0}'.format(range[1])) + return (True,0,'') #end BackbgroundTestRange #----------------------------------------------------------------------------------------- @@ -954,33 +956,33 @@ class MultirepTOFSpectraList(PropDescriptor): """ property describes list of spectra numbers, used to identify TOF range corresponding to the particular energy range - Usually it is list of two numbers, specifying monitors which are + Usually it is list of two numbers, specifying spectra with detectors located closest and furthest from the sample """ def __init__(self): self._spectra_list = None def __get__(self,instance,type=None): - if instance is None: - return self + if instance is None: + return self - return self._spectra_list + return self._spectra_list def __set__(self,instance,value): if value is None: - self._spectra_list = None - return + self._spectra_list = None + return if isinstance(value,str): value = str.split(value,',') self.__set__(instance,value) return if isinstance(value, list): - rez =[] - for val in value: - rez.append(int(val)) + rez = [] + for val in value: + rez.append(int(val)) else: rez = [int(value)] - self._spectra_list=rez + self._spectra_list = rez #end MultirepTOFSpectraList class MonoCorrectionFactor(PropDescriptor): @@ -988,29 +990,33 @@ class MonoCorrectionFactor(PropDescriptor): experimental scattering cross-section into absolute units ( mb/str/mev/fu) - There are independent two sources for this factor: - 1) if user explicitly specifies correction value. - This value then will be applied to all subsequent runs + Two independent sources for this factor can be defined: + 1) if user explicitly specifies correction value. + This value then will be applied to all subsequent runs without any checks if the correction is appropriate 2) set/get cashed value correspondent to current monovan run number, incident energy and integration range. This value is cashed at first run and reapplied if no changes to the values it depends on were identified """ - def __init__(self,ei_prop): + def __init__(self,ei_prop,monovan_run_prop): self._cor_factor = None - self._mono_run_number=None + self._mono_run_number = None self._ei_prop = ei_prop - self.cashed_values={} + self.cashed_values = {} + self._mono_run_prop=monovan_run_prop - def __get__(self,instance,type=None): - if instance is None: - return self + def __get__(self,instance,type): + if instance is None: + return self - return self._cor_factor + return self._cor_factor def __set__(self,instance,value): - self._cor_factor = value + self._cor_factor = value + # + if value is None: + self._mono_run_prop._in_cash=False # enable monovan run validation if any # def set_val_to_cash(self,instance,value): """ """ @@ -1026,26 +1032,32 @@ class MonoCorrectionFactor(PropDescriptor): mono_int_range = instance.monovan_integr_range cash_id = self._build_cash_val_id(mono_int_range) if cash_id in self.cashed_values: - return self.cashed_values[cash_id] + return self.cashed_values[cash_id] else: - return None + return None def set_cash_mono_run_number(self,new_value): if new_value is None: - self.cashed_values={} - self._mono_run_number = None - return + self.cashed_values = {} + self._mono_run_number = None + return if self._mono_run_number != int(new_value): - self.cashed_values={} - self._mono_run_number = int(new_value) + self.cashed_values = {} + self._mono_run_number = int(new_value) def _build_cash_val_id(self,mono_int_range): - ei = self._ei_prop.get_current() - cash_id = "Ei={0:0>9.4e}:Int({1:0>9.4e}:{2:0>9.5e}):Run{3}".\ + ei = self._ei_prop.get_current() + cash_id = "Ei={0:0>9.4e}:Int({1:0>9.4e}:{2:0>9.5e}):Run{3}".\ format(ei,mono_int_range[0],mono_int_range[1],self._mono_run_number) - return cash_id + return cash_id + def validate(self,instance, owner=None): + if self._cor_factor is None: + return (True,0,'') + if self._cor_factor<=0: + return (False,2,'Mono-correction factor has to be positive if specified: {0}'.format(self._cor_factor)) + return (True,0,'') #----------------------------------------------------------------------------------------- # END Descriptors for PropertyManager itself #----------------------------------------------------------------------------------------- diff --git a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py index 33c518c10e4c8a6aed352e4adf79cb1961fd38e4..ecfbf8a856d74ac7b41aca37d7fb6382df4bfbc9 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py +++ b/Code/Mantid/scripts/Inelastic/Direct/PropertyManager.py @@ -99,7 +99,9 @@ class PropertyManager(NonIDF_Properties): object.__setattr__(self,class_dec+'file_properties',['det_cal_file','map_file','hard_mask_file']) object.__setattr__(self,class_dec+'abs_norm_file_properties',['monovan_mapfile']) - # properties with allowed values + # Clear caches on construction to make class more like usual class then singleton (and cashes are dangerous) + PropertyManager.mono_correction_factor.set_cash_mono_run_number(None) + def _convert_params_to_properties(self,param_list,detine_subst_dict=True,descr_list=[]): """ method processes parameters obtained from IDF and modifies the IDF properties @@ -156,16 +158,16 @@ class PropertyManager(NonIDF_Properties): # replace common substitutions for string value if type(val) is str : - val1 = val.lower() - if val1 == 'none' or len(val1) == 0: - val = None - if val1 == 'default': - val = self.getDefaultParameterValue(name0) + val1 = val.lower() + if val1 == 'none' or len(val1) == 0: + val = None + if val1 == 'default': + val = self.getDefaultParameterValue(name0) # boolean property? - if val1 in ['true','yes']: - val = True - if val1 in ['false','no']: - val = False + if val1 in ['true','yes']: + val = True + if val1 in ['false','no']: + val = False if type(val) is list and len(val) == 0: @@ -173,30 +175,31 @@ class PropertyManager(NonIDF_Properties): # set property value: if name in self.__descriptors: - super(PropertyManager,self).__setattr__(name,val) + super(PropertyManager,self).__setattr__(name,val) else: - other_prop=prop_helpers.gen_setter(self.__dict__,name,val) + other_prop=prop_helpers.gen_setter(self.__dict__,name,val) # record the fact that the property have changed self.__changed_properties.add(name) # ---------------------------- def __getattr__(self,name): - """ Overloaded get method, disallowing non-existing properties being get but allowing - a property been called with different names specified in substitution dictionary. """ + """ Overloaded get method, disallowing non-existing properties being get but allowing + a property been called with different names specified in substitution dictionary. + """ - if name in self.__subst_dict: - name = self.__subst_dict[name] - return getattr(self,name) + if name in self.__subst_dict: + name = self.__subst_dict[name] + return getattr(self,name) #end - if name in self.__descriptors: + if name in self.__descriptors: # This can only happen only if descriptor is called through synonims dictionary # This to work, all descriptors should define getter to return self on Null instance. - descr=getattr(PropertyManager,name) - return descr.__get__(self,name) - else: - return prop_helpers.gen_getter(self.__dict__,name) + descr=getattr(PropertyManager,name) + return descr.__get__(self,name) + else: + return prop_helpers.gen_getter(self.__dict__,name) ##end #---------------------------------------------------------------------------------- # Overloaded setters/getters @@ -204,11 +207,11 @@ class PropertyManager(NonIDF_Properties): # det_cal_file = DetCalFile() # - map_file = MapMaskFile('.map',"Spectra to detector mapping file for the sample run") + map_file = MapMaskFile('map_file','.map',"Spectra to detector mapping file for the sample run") # - monovan_mapfile = MapMaskFile('.map',"Spectra to detector mapping file for the monovanadium integrals calculation") + monovan_mapfile = MapMaskFile('monovan_map_file','.map',"Spectra to detector mapping file for the monovanadium integrals calculation") # - hard_mask_file = MapMaskFile('.msk',"Hard mask file") + hard_mask_file = MapMaskFile('hard_mask_file','.msk',"Hard mask file") # monovan_integr_range = MonovanIntegrationRange() # @@ -230,13 +233,16 @@ class PropertyManager(NonIDF_Properties): # multirep_tof_specta_list=MultirepTOFSpectraList() # - mono_correction_factor = MonoCorrectionFactor(NonIDF_Properties.incident_energy) - + mono_correction_factor = MonoCorrectionFactor(NonIDF_Properties.incident_energy, + NonIDF_Properties.monovan_run) + # property responsible for summing runs + sum_runs = SumRuns(NonIDF_Properties.sample_run) #---------------------------------------------------------------------------------------------------------------- def getChangedProperties(self): """ method returns set of the properties changed from defaults """ decor_prop = '_'+type(self).__name__+'__changed_properties' return self.__dict__[decor_prop] + # def setChangedProperties(self,value=set([])): """ Method to clear changed properties list""" if isinstance(value,set): @@ -244,14 +250,14 @@ class PropertyManager(NonIDF_Properties): self.__dict__[decor_prop] =value else: raise KeyError("Changed properties can be initialized by appropriate properties set only") - + # @property def relocate_dets(self) : if self.det_cal_file != None: return True else: return False - + # def set_input_parameters_ignore_nan(self,**kwargs): """ Like similar method set_input_parameters this one is used to set changed parameters from dictionary of parameters. @@ -260,41 +266,21 @@ class PropertyManager(NonIDF_Properties): with value equal to None. As such, this method is used as interface to set data from a function with a list of given parameters (*args vrt **kwargs), with some parameters missing. - """ - # if sum is in parameters one needs to set it first - if 'sum_runs' in kwargs and not kwargs['sum_runs'] is None: - self.sum_runs = kwargs['sum_runs'] - del kwargs['sum_runs'] - if 'sum' in kwargs and not kwargs['sum'] is None: - self.sum_runs = kwargs['sum'] - del kwargs['sum'] - - + """ + for par_name,value in kwargs.items() : if not value is None: setattr(self,par_name,value) - - - + # def set_input_parameters(self,**kwargs): """ Set input properties from a dictionary of parameters """ - # if sum is in parameters one needs to set it first to interpret - # - if 'sum_runs' in kwargs : - self.sum_runs = kwargs['sum_runs'] - del kwargs['sum_runs'] - if 'sum' in kwargs : - self.sum_runs = kwargs['sum'] - del kwargs['sum'] - - for par_name,value in kwargs.items() : setattr(self,par_name,value) return self.getChangedProperties() - + # def get_used_monitors_list(self): """ Method returns list of monitors ID used during reduction """ @@ -307,14 +293,13 @@ class PropertyManager(NonIDF_Properties): used_mon.add(self.mon2_norm_spec) break if case(): # default, could also just omit condition or 'if True' - pass + pass used_mon.add(self.ei_mon1_spec) used_mon.add(self.ei_mon2_spec) return used_mon - - + # def get_diagnostics_parameters(self): """ Return the dictionary of the properties used in diagnostics with their values defined in IDF @@ -335,7 +320,7 @@ class PropertyManager(NonIDF_Properties): self.log('--- Diagnostics property {0} is not found in instrument properties. Default value: {1} is used instead \n'.format(key,value),'warning') return result - + # def update_defaults_from_instrument(self,pInstrument,ignore_changes=False): """ Method used to update default parameters from the same instrument (with different parameters). @@ -368,17 +353,17 @@ class PropertyManager(NonIDF_Properties): # remove old changes which are not related to IDF (not to reapply it again) for prop_name in old_changes: if not prop_name in param_list: - try: - dependencies = getattr(PropertyManager,prop_name).dependencies() - except: - dependencies = [] - modified = False - for name in dependencies: - if name in param_list: - modified = True - break - if not modified: - del old_changes[prop_name] + try: + dependencies = getattr(PropertyManager,prop_name).dependencies() + except: + dependencies = [] + modified = False + for name in dependencies: + if name in param_list: + modified = True + break + if not modified: + del old_changes[prop_name] #end param_list,descr_dict = self._convert_params_to_properties(param_list,False,self.__descriptors) @@ -395,16 +380,16 @@ class PropertyManager(NonIDF_Properties): if not key in old_changes_list: try: # this is reliability check, and except ideally should never be hit. May occur if old IDF contains # properties, not present in recent IDF. - cur_val = getattr(self,key) - setattr(self,key,val) - new_val = getattr(self,key) + cur_val = getattr(self,key) + setattr(self,key,val) + new_val = getattr(self,key) except: - self.log("property {0} have not been found in existing IDF. Ignoring this property"\ + self.log("property {0} have not been found in existing IDF. Ignoring this property"\ .format(key),'warning') - continue + continue if isinstance(new_val,api.Workspace) and isinstance(cur_val,api.Workspace): # do simplified workspace comparison which is appropriate here - if new_val.name() == cur_val.name() and \ + if new_val.name() == cur_val.name() and \ new_val.getNumberHistograms() == cur_val.getNumberHistograms() and \ new_val.getNEvents() == cur_val.getNEvents() and \ new_val.getAxis(0).getUnit().unitID() == cur_val.getAxis(0).getUnit().unitID(): @@ -412,16 +397,16 @@ class PropertyManager(NonIDF_Properties): # #end if new_val != cur_val: - changed_descriptors.add(key) + changed_descriptors.add(key) # dependencies removed either properties are equal or not try: - dependencies = getattr(PropertyManager,key).dependencies() + dependencies = getattr(PropertyManager,key).dependencies() except: - dependencies = [] + dependencies = [] for dep_name in dependencies: if dep_name in sorted_param: - del sorted_param[dep_name] + del sorted_param[dep_name] else: # remove property from old changes list not to reapply it again? pass #end loop @@ -442,19 +427,19 @@ class PropertyManager(NonIDF_Properties): try: # this is reliability check, and except ideally should never be hit. May occur if old IDF contains # properties, not present in recent IDF. - cur_val = getattr(self,public_name) + cur_val = getattr(self,public_name) except: self.log("property {0} have not been found in existing IDF. Ignoring this property"\ .format(public_name),'warning') continue if prop_new_val !=cur_val : - setattr(self,public_name,prop_new_val) + setattr(self,public_name,prop_new_val) # Dependencies removed either properties are equal or not try: - dependencies = val.dependencies() + dependencies = val.dependencies() except: - dependencies =[] + dependencies =[] for dep_name in dependencies: # delete dependent properties not to deal with them again del sorted_param[dep_name] @@ -483,41 +468,153 @@ class PropertyManager(NonIDF_Properties): else: return None #end + def _get_properties_with_files(self): + """ Method returns list of properties, which may have + files as their values + + it does not include sample run, as this one will be + treated separately. + """ + + run_files_prop=['wb_run','monovan_run','mask_run','wb_for_monovan_run','second_white'] + map_mask_prop =['det_cal_file','map_file','hard_mask_file'] + + abs_units = not(self.monovan_run is None) + files_to_check =[] + # run files to check + for prop_name in run_files_prop: + theProp = getattr(PropertyManager,prop_name) + if theProp.has_own_value(): + if theProp.is_existing_ws(): # it is loaded workspace + continue # we do not care if it has file or not + val = theProp.__get__(self,PropertyManager) + if not(val is None) : + files_to_check.append(prop_name) + + # other files to check: + for prop_name in map_mask_prop: + val = getattr(self,prop_name) + if not(val is None or isinstance(val,api.Workspace)): + files_to_check.append(prop_name) + # Absolute units files (only one?) + if abs_units: + val = self.monovan_mapfile + if not(val is None) : + files_to_check.append('monovan_mapfile') + # + return files_to_check + # + def find_files_to_sum(self,num_files=None): + """ method searches for run files in run list to sum and returns + list of runs with run-files missing or ok and empty list if all files + are there + + if num_files is not None, find specified number of files out of total + file list to sum + """ + # this returns only runs, left to sum with current sample_run sum settings + runs,sum_ws,added = PropertyManager.sample_run.get_runs_to_sum(None,num_files) + if len(runs) == 0: + return (True,[],[]) + + ok,not_found_list,found_list = PropertyManager.sample_run.find_run_files(runs) + return (ok,not_found_list,found_list) + # + def _check_file_properties(self): + """ Method verifies if all files necessary for a reduction are available. - def _check_file_exist(self,file_name): - file_path = FileFinder.getFullPath(file) - if len(file_path) == 0: - try: - file_path = common.find_file(file) - except: - file_path ='' - - - def _check_necessary_files(self,monovan_run): - """ Method verifies if all files necessary for a run are available. - - useful for long runs to check if all files necessary for it are present/accessible + useful for long runs to check if all files necessary for it are + present/accessible before starting the run """ - - def check_files_list(files_list): - file_missing = False - for prop in files_list : - file = getattr(self,prop) - if not (file is None) and isinstance(file,str): - file_path = self._check_file_exist(file) - if len(file_path)==0: - self.log(" Can not find file ""{0}"" for property: {1} ".format(file,prop),'error') - file_missing=True - - return file_missing - - base_file_missing = check_files_list(self.__file_properties) - abs_file_missing=False - if not monovan_run is None: - abs_file_missing = check_files_list(self.__abs_norm_file_properties) - - if base_file_missing or abs_file_missing: - raise RuntimeError(" Files needed for the run are missing ") + file_prop_names = self._get_properties_with_files() + file_errors={} + for prop_name in file_prop_names: + theProp = getattr(PropertyManager,prop_name) + ok,file = theProp.find_file(be_quet=True) + if not ok: + file_errors[prop_name]=file + + if self.sum_runs : + ok,missing,found=self.find_files_to_sum() + if not ok and not self.cashe_sum_ws: + file_errors['missing_runs_toSum']=str(missing) + + result = (len(file_errors)==0) + return (result,file_errors) + # + def _check_ouptut_dir(self): + """ check if default save directory is accessible for writing """ + targ_dir = config['defaultsave.directory'] + test_file = os.path.join(targ_dir,'test_file.txt') + try: + fp = open(test_file,'w') + fp.close() + os.remove(test_file) + return (True,'') + except: + return (False,'Can not write to default save directory {0}.\n Reduction results can be lost'.format(targ_dir)) + # + def validate_properties(self,fail_on_errors=True): + """ Method validates if some properties values for + properties set up in the property manager are correct + """ + + if self.mono_correction_factor: # disable check for monovan_run, as it is not used if mono_correction provided + PropertyManager.monovan_run._in_cash = True # as soon as monovan_run is set up (mono correction disabled) + # this will be dropped + error_list={} + error_level=0 + + ok,fail_prop = self._check_file_properties() + if not ok : + for prop in fail_prop: + mess = "*** ERROR : properties : {0} -->{1}".format(prop,fail_prop[prop]) + if fail_on_errors: + self.log(mess,'warning') + else: + error_list[prop]=mess + error_level=2 + + ok,mess= self._check_ouptut_dir() + if not ok: + mess = '*** WARNING: saving results: --> {1}'.format(mess) + + if fail_on_errors: + self.log(mess,'warning') + else: + error_list['file_output']=mess + error_level=max(1,error_level) + + # verify interconnected properties + changed_prop = self.getChangedProperties() + for prop in changed_prop: + try: + theProp =getattr(PropertyManager,prop) + except: # not all changed properties are property manager properties + continue # we are not validating them + try: + ok,sev,message = theProp.validate(self,PropertyManager) + if not (ok): + error_level=max(sev,error_level) + if sev == 1: + base = '*** WARNING: properties : {0} --> {1}' + else: + base = '*** ERROR : properties : {0} --> {1}' + mess = base.format(prop,message) + if fail_on_errors: + self.log(mess,'warning') + else: + error_list[prop]=mess + except: # its simple dictionary value, which do not have validator or + pass # other property without validator + #end + if error_level>1 and fail_on_errors: + raise RuntimeError('*** Invalid properties found. Can not run convert_to energy') + if error_level>0: + OK = False + else: + OK = True + return (OK,error_level,error_list) # def _check_monovan_par_changed(self): """ method verifies, if properties necessary for monovanadium reduction have indeed been changed from defaults """ @@ -533,62 +630,62 @@ class PropertyManager(NonIDF_Properties): # def log_changed_values(self,log_level='notice',display_header=True,already_changed=set()): - """ inform user about changed parameters and about the parameters that should be changed but have not + """ inform user about changed parameters and about the parameters that should be changed but have not This method is abstract method of NonIDF_Properties but is fully defined in PropertyManager display_header==True prints nice additional information about run. If False, only list of changed properties displayed. """ - if display_header: + if display_header: # we may want to run absolute units normalization and this function has been called with monovan run or helper procedure - if self.monovan_run != None : + if self.monovan_run != None : # check if mono-vanadium is provided as multiple files list or just put in brackets occasionally - self.log("****************************************************************",'notice') - self.log('*** Output will be in absolute units of mb/str/mev/fu','notice') - non_changed = self._check_monovan_par_changed() - if len(non_changed) > 0: - for prop in non_changed: - value = getattr(self,prop) - message = "\n***WARNING!: Abs units norm. parameter : {0} not changed from default val: {1}"\ + self.log("****************************************************************",'notice') + self.log('*** Output will be in absolute units of mb/str/mev/fu','notice') + non_changed = self._check_monovan_par_changed() + if len(non_changed) > 0: + for prop in non_changed: + value = getattr(self,prop) + message = "\n***WARNING!: Abs units norm. parameter : {0} not changed from default val: {1}"\ "\n This may need to change for correct absolute units reduction\n" - self.log(message.format(prop,value),'warning') + self.log(message.format(prop,value),'warning') # now let's report on normal run. - if PropertyManager.incident_energy.multirep_mode(): - ei = self.incident_energy - mess = "*** Provisional Incident energies: {0:>8.3f}".format(ei[0]) - for en in ei[1:]: - mess += "; {0:>8.3f}".format(en) - mess+=" mEv" - self.log(mess,log_level) - else: - self.log("*** Provisional Incident energy: {0:>12.3f} mEv".format(self.incident_energy),log_level) + if PropertyManager.incident_energy.multirep_mode(): + ei = self.incident_energy + mess = "*** Provisional Incident energies: {0:>8.3f}".format(ei[0]) + for en in ei[1:]: + mess += "; {0:>8.3f}".format(en) + mess+=" mEv" + self.log(mess,log_level) + else: + self.log("*** Provisional Incident energy: {0:>12.3f} mEv".format(self.incident_energy),log_level) #end display_header - self.log("****************************************************************",log_level) - changed_Keys= self.getChangedProperties() - for key in changed_Keys: - if key in already_changed: - continue - val = getattr(self,key) - self.log(" Value of : {0:<25} is set to : {1:<20} ".format(key,val),log_level) - - if not display_header: - return - - save_dir = config.getString('defaultsave.directory') - self.log("****************************************************************",log_level) - if self.monovan_run != None and not 'van_mass' in changed_Keys: # This output is - self.log("*** Monochromatic vanadium mass used : {0} ".format(self.van_mass),log_level) # Adroja request from may 2014 + self.log("****************************************************************",log_level) + changed_Keys= self.getChangedProperties() + for key in changed_Keys: + if key in already_changed: + continue + val = getattr(self,key) + self.log(" Value of : {0:<25} is set to : {1:<20} ".format(key,val),log_level) + + if not display_header: + return + + save_dir = config.getString('defaultsave.directory') + self.log("****************************************************************",log_level) + if self.monovan_run != None and not 'van_mass' in changed_Keys: # This output is Adroja request from may 2014 + self.log("*** Monochromatic vanadium mass used : {0} ".format(self.van_mass),log_level) # - self.log("*** By default results are saved into: {0}".format(save_dir),log_level) - self.log("*** Output will be normalized to {0}".format(self.normalise_method),log_level) - if self.map_file == None: + self.log("*** By default results are saved into: {0}".format(save_dir),log_level) + self.log("*** Output will be normalized to {0}".format(self.normalise_method),log_level) + if self.map_file == None: self.log('*** one2one map selected',log_level) - self.log("****************************************************************",log_level) + self.log("****************************************************************",log_level) #def help(self,keyword=None) : diff --git a/Code/Mantid/scripts/Inelastic/Direct/ReductionHelpers.py b/Code/Mantid/scripts/Inelastic/Direct/ReductionHelpers.py index d1943b913b8cce121b9106e9c2d1ce5a8b5baa8b..468f6aca787f41f0f7972cc8df660b0fe5b5d844 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/ReductionHelpers.py +++ b/Code/Mantid/scripts/Inelastic/Direct/ReductionHelpers.py @@ -50,6 +50,20 @@ class ComplexProperty(object): return len(self._other_prop) #end ComplexProperty +def findFile(fileName): + """ Simple search within Mantid data search directories for + a file which is not a run file + """ + + if os.path.exists(fileName): + return os.path.abspath(fileName) + fbase = os.path.basename(fileName) + search_path = config.getDataSearchDirs() + for path in search_path: + fname = os.path.join(path,fbase) + if os.path.exists(fname): + return fname + return '' def get_default_parameter(instrument, name): @@ -362,6 +376,3 @@ def parse_run_file_name(run_string): fext = fext[0] # extensions should be either all the same or all defined return (filepath,filenum,fext) - - - diff --git a/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py b/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py index e18d3e1aa7ded0accc9edb5adde1feb9e702b52e..099c676f03d67efdeeee21346d749769777e4518 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py +++ b/Code/Mantid/scripts/Inelastic/Direct/ReductionWrapper.py @@ -6,7 +6,6 @@ from mantid.kernel import funcreturns from Direct.PropertyManager import PropertyManager # this import is used by children from Direct.DirectEnergyConversion import DirectEnergyConversion -#import inspect import os from abc import abstractmethod @@ -24,36 +23,29 @@ class ReductionWrapper(object): self.advanced_vars = None def __init__(self,instrumentName,web_var=None): - """ sets properties defaults for the instrument with Name + """ sets properties defaults for the instrument with Name and define if wrapper runs from web services or not """ # internal variable, indicating if we should try to wait for input files to appear - self._wait_for_file=False + self._wait_for_file=False + # internal variable, used in system tests to validate workflow, + # with waiting for files. It is the holder to the function + # used during debugging "wait for files" workflow + # instead of Pause algorithm + self._debug_wait_for_files_operation=None # The variables which are set up from web interface or to be exported to # web interface - if web_var: - self._run_from_web = True - self._wvs = web_var - else: - self._run_from_web = False - self._wvs = ReductionWrapper.var_holder() + if web_var: + self._run_from_web = True + self._wvs = web_var + else: + self._run_from_web = False + self._wvs = ReductionWrapper.var_holder() # Initialize reduced for given instrument - self.reducer = DirectEnergyConversion(instrumentName) + self.reducer = DirectEnergyConversion(instrumentName) - self._validation_fname=None -# - def get_validation_file_name(self,ReferenceFile=None): - """ function provides name of the file with mantid - workspace reduced earlier and which should be validated - against results of current reduction - Should be overloaded to return real file name for particular - reduction - """ - if ReferenceFile: - self._validation_fname = ReferenceFile - return self._validation_fname @property def wait_for_file(self): @@ -79,7 +71,7 @@ class ReductionWrapper(object): interface If no file is provided, reduce_var.py file will be written - to + to the folder, containing current script """ if not FileName: @@ -89,51 +81,84 @@ class ReductionWrapper(object): f.write("standard_vars = {\n") str_wrapper = ' ' for key,val in self._wvs.standard_vars.iteritems(): - if isinstance(val,str): - row = "{0}\'{1}\':\'{2}\'".format(str_wrapper,key,val) - else: - row = "{0}\'{1}\':{2}".format(str_wrapper,key,val) - f.write(row) - str_wrapper=',\n ' + if isinstance(val,str): + row = "{0}\'{1}\':\'{2}\'".format(str_wrapper,key,val) + else: + row = "{0}\'{1}\':{2}".format(str_wrapper,key,val) + f.write(row) + str_wrapper=',\n ' f.write("\n}\nadvanced_vars={\n") str_wrapper=' ' for key,val in self._wvs.advanced_vars.iteritems(): - if isinstance(val,str): - row = "{0}\'{1}\':\'{2}\'".format(str_wrapper,key,val) - else: - row = "{0}\'{1}\':{2}".format(str_wrapper,key,val) - f.write(row) - str_wrapper=',\n ' + if isinstance(val,str): + row = "{0}\'{1}\':\'{2}\'".format(str_wrapper,key,val) + else: + row = "{0}\'{1}\':{2}".format(str_wrapper,key,val) + f.write(row) + str_wrapper=',\n ' f.write("\n}\n") f.close() + def validate_settings(self): + """ method validates initial parameters, provided for reduction """ + + self.def_advanced_properties() + self.def_main_properties() + if self._run_from_web: + web_vars = dict(self._wvs.standard_vars.items()+self._wvs.advanced_vars.items()) + self.reducer.prop_man.set_input_parameters(**web_vars) + else: + pass # we should set already set up variables using + + # validate properties and report result + return self.reducer.prop_man.validate_properties(False) # -# +# def validate_result(self,build_validation=False,Error=1.e-3,ToleranceRelErr=True): - """ Overload this using build_or_validate_result to have possibility to run or validate result """ + """ Overload this using build_or_validate_result to have possibility to run or validate result """ return True - def build_or_validate_result(self,sample_run,validationFile,build_validation=False,Error=1.e-3,ToleranceRelErr=True): - """ Method validates results of the reduction against reference file provided - by get_validation_file_name() method - - At the moment, get_validation_file_name method should return the name of a file, - where workspace sample reduced workspace with default properties - is stored. - CheckWorkspaceMatch method is applied to verify if current reduced workspace is - equivalent to the workspace, stored in the reference file. + def set_custom_output_filename(self): + """ define custom name of output files if standard one is not satisfactory + User expected to overload this method within class instantiation """ + return None + + + def build_or_validate_result(self,sample_run,validation_file,build_validation=False,Error=1.e-3,ToleranceRelErr=True): + """ Method validates results of the reduction against reference file or workspace. + + Inputs: + sample_run -- the run number to reduce or validate against existing result + validation_file -- The name of nxs file, containing workspace, produced by reducing SampleRun, + or the pointer to the workspace, which is the reference workspace + for SampleRun reduction. + + Returns: + True if reduction for sample_run produces result within Error from the reference file + as reported by CheckWorkspaceMatch. + False if CheckWorkspaceMatch comparison between sample and reduction is unsuccessful + + True if was not able to load reference file. In this case, algorithm builds validation + file and returns True if the reduction and saving of this file is successful + """ if not build_validation: - if validationFile: - if isinstance(validationFile,api.Workspace): - sample = validationFile - validationFile = sample.name() - else: - sample = Load(validationFile) - else: - build_validation=True + if validation_file: + if isinstance(validation_file,api.Workspace): + sample = validation_file + validation_file = sample.name() + else: + try: + sample = Load(validation_file) + except: + self.reducer.prop_man.log\ + ("*** WARNING:can not load (find?) validation file {0}\n"\ + " Building validation".format(validation_file),'warning') + build_validation=True + else: + build_validation=True # just in case, to be sure @@ -152,10 +177,10 @@ class ReductionWrapper(object): reduced = self.reduce() if build_validation: - if validationFile: - result_name = os.path.splitext(validationFile)[0] + if validation_file: + result_name = os.path.splitext(validation_file)[0] else: - result_name = self.reducer.prop_man.save_file_name + result_name = self.reducer.prop_man.save_file_name self.reducer.prop_man.log("*** Saving validation file with name: {0}.nxs".format(result_name),'notice') SaveNexus(reduced,Filename=result_name+'.nxs') return True,'Created validation file {0}.nxs'.format(result_name) @@ -194,8 +219,17 @@ class ReductionWrapper(object): """ raise NotImplementedError('def_advanced_properties has to be implemented') - - + # + def _run_pause(self,timeToWait=0): + """ a wrapper around pause algorithm allowing to run something + instead of pause in debug mode + """ + + if not self._debug_wait_for_files_operation is None: + self._debug_wait_for_files_operation() + else: + Pause(timeToWait) + # def reduce(self,input_file=None,output_directory=None): """ The method performs all main reduction operations over single run file @@ -204,25 +238,118 @@ class ReductionWrapper(object): reduction properties between script and web variables """ if input_file: - self.reducer.sample_run = input_file + self.reducer.sample_run = str(input_file) + if output_directory: + config['defaultsave.directory'] = str(output_directory) timeToWait = self._wait_for_file - if timeToWait: - file = PropertyManager.sample_run.find_file(be_quet=True) - while file.find('ERROR:')>=0: + if timeToWait>0: + Found,input_file = PropertyManager.sample_run.find_file(be_quet=True) + while not Found: file_hint,fext = PropertyManager.sample_run.file_hint() self.reducer.prop_man.log("*** Waiting {0} sec for file {1} to appear on the data search path"\ .format(timeToWait,file_hint),'notice') - Pause(timeToWait) - file = PropertyManager.sample_run.find_file(be_quet=True) + + self._run_pause(timeToWait) + Found,input_file = PropertyManager.sample_run.find_file(file_hint=file_hint,be_quet=True) ws = self.reducer.convert_to_energy(None,input_file) else: ws = self.reducer.convert_to_energy(None,input_file) return ws - - + # + def sum_and_reduce(self): + """ procedure used to sum and reduce runs in case when not all files + are available and user have to wait for these files to appear + """ + if not PropertyManager.sample_run._run_list: + raise RuntimeError("sum_and_reduce expects run file list to be defined") + + self.reducer.prop_man.sum_runs = True + + timeToWait = self._wait_for_file + if timeToWait>0: + run_files = PropertyManager.sample_run.get_run_list() + num_files_to_sum = len(PropertyManager.sample_run) + + ok,missing,found = self.reducer.prop_man.find_files_to_sum() + n_found = len(found) + if not ok: + # necessary to cache intermediate sums in memory + self.reducer.prop_man.cashe_sum_ws = True + while not(ok): + while n_found>0: + last_found = found[-1] + self.reducer.prop_man.sample_run = last_found # request to reduce all up to last found + ws = self.reducer.convert_to_energy() + # reset search to whole file list again + self.reducer.prop_man.sample_run = run_files[num_files_to_sum-1] + ok,missing,found = self.reducer.prop_man.find_files_to_sum() + n_found = len(found) + if ok: # no need to cache sum any more. All necessary files found + self.reducer.prop_man.cashe_sum_ws = False + + self.reducer.prop_man.log("*** Waiting {0} sec for runs {1} to appear on the data search path"\ + .format(timeToWait,str(missing)),'notice') + self._run_pause(timeToWait) + ok,missing,found = self.reducer.prop_man.find_files_to_sum() + n_found = len(found) + #end not(ok) + if n_found>0: + # cash sum can be dropped now if it has not been done before + self.reducer.prop_man.cashe_sum_ws = False + ws = self.reducer.convert_to_energy() + else: + ws = self.reducer.convert_to_energy() + + return ws + # + def run_reduction(self): + """" Reduces runs one by one or sum all them together and reduce after this + + if wait_for_file time is > 0, it will until missing files appear on the + data search path + """ + try: + n,r = funcreturns.lhs_info('both') + out_ws_name = r[0] + except: + out_ws_name = None + + if self.reducer.sum_runs: +# --------### sum runs provided ------------------------------------### + if out_ws_name is None: + self.sum_and_reduce() + return None + else: + red_ws=self.sum_and_reduce() + RenameWorkspace(InputWorkspace=red_ws,OutputWorkspace=out_ws_name) + return mtd[out_ws_name] + else: +# --------### reduce list of runs one by one ----------------------------### + runs = PropertyManager.sample_run.get_run_list() + if out_ws_name is None: + for run in runs: + self.reduce(run) + #end + return None + else: + results=[] + nruns = len(runs) + for num,run in enumerate(runs): + red_ws=self.reduce(run) + if nruns >1: + out_name = out_ws_name+'#{0}of{1}'.format(num+1,nruns) + RenameWorkspace(InputWorkspace=red_ws,OutputWorkspace=out_name) + red_ws = mtd[out_name] + results.append(red_ws) + #end + if len(results) == 1: + return results[0] + else: + return results + #end def MainProperties(main_prop_definition): @@ -282,15 +409,15 @@ def iliad(reduce): output_directory=None # add input file folder to data search directory if file has it if input_file and isinstance(input_file,str): - data_path = os.path.dirname(input_file) - if len(data_path)>0: - try: - config.appendDataSearchDir(str(data_path)) - args[1] = os.path.basename(input_file) - except: # if mantid is not available, this should ignore config - pass + data_path = os.path.dirname(input_file) + if len(data_path)>0: + try: + config.appendDataSearchDir(str(data_path)) + args[1] = os.path.basename(input_file) + except: # if mantid is not available, this should ignore config + pass if output_directory: - config['defaultsave.directory'] = output_directory + config['defaultsave.directory'] = str(output_directory) if host._run_from_web: web_vars = dict(host._wvs.standard_vars.items()+host._wvs.advanced_vars.items()) @@ -298,23 +425,25 @@ def iliad(reduce): else: pass # we should set already set up variables using - + custom_print_function = host.set_custom_output_filename() + if not custom_print_function is None: + PropertyManager.save_file_name.set_custom_print(custom_print_function) + # rez = reduce(*args) # prohibit returning workspace to web services. if host._run_from_web and not isinstance(rez,str): rez="" else: - if isinstance(rez,list): + if isinstance(rez,list): # multirep run, just return as it is - return rez - if out_ws_name and rez.name() != out_ws_name : - rez=RenameWorkspace(InputWorkspace=rez,OutputWorkspace=out_ws_name) + return rez + if out_ws_name and rez.name() != out_ws_name : + rez=RenameWorkspace(InputWorkspace=rez,OutputWorkspace=out_ws_name) return rez return iliad_wrapper - if __name__=="__main__": pass diff --git a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py index edddf86fb180e33d6f0c55559de275ddc5ad3aea..62d7b2b0342ba33f0ab7f920815b5b82c697189c 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py +++ b/Code/Mantid/scripts/Inelastic/Direct/RunDescriptor.py @@ -1,14 +1,283 @@ #pylint: disable=invalid-name """ File contains Descriptors used describe run for direct inelastic reduction """ - from mantid.simpleapi import * from Direct.PropertiesDescriptors import * import re +class RunList(object): + """ helper class to maintain list of runs used in RunDescriptor for summing + or subsequent processing range of files. + + Supports basic operations with this list + """ + def __init__(self,run_list,file_names=None,fext=None): + """ """ + self._last_ind2sum = -1 + self._file_path = None + self._fext = None + self.set_list2add(run_list,file_names,fext) + self._partial_sum_ws_name = None + # + def set_list2add(self,runs_to_add,fnames=None,fext=None): + """Set run numbers to add together with possible file guess-es """ + if not isinstance(runs_to_add,list): + raise KeyError('Can only set list of run numbers to add') + runs = [] + for item in runs_to_add: + runs.append(int(item)) + self._run_numbers = runs + self._set_fnames(fnames,fext) +#-------------------------------------------------------------------------------------------------- + # + def set_cashed_sum_ws(self,ws,new_ws_name=None): + """ store the name of a workspace in the class + as reference clone + """ + if new_ws_name: + old_name = ws.name() + if old_name != new_ws_name: + old_mon_name = old_name + '_monitors' + RenameWorkspace(ws,OutputWorkspace=new_ws_name) + if old_mon_name in mtd: + RenameWorkspace(old_mon_name,OutputWorkspace=new_ws_name + '_monitors') + else: + new_ws_name = ws.name() + self._partial_sum_ws_name = new_ws_name + # + def get_cashed_sum_ws(self): + """ """ + if not (self._partial_sum_ws_name): + return None + if self._partial_sum_ws_name in mtd: + return mtd[self._partial_sum_ws_name] + else: + return None + # + def get_cashed_sum_clone(self): + """ """ + origin = self.get_cashed_sum_ws() + if not origin: + return None + origin_name = origin.name() + mon_name = origin_name + '_monitors' + if mon_name in mtd: + CloneWorkspace(InputWorkspace=mon_name,OutputWorkspace=origin_name + '_clone_monitors') + ws = CloneWorkspace(InputWorkspace=origin_name,OutputWorkspace=origin_name + '_clone') + return ws + # + def del_cashed_sum(self): + """ """ + if not self._partial_sum_ws_name: + return + if self._partial_sum_ws_name in mtd: + DeleteWorkspace(self._partial_sum_ws_name) + mon_ws = self._partial_sum_ws_name + '_monitors' + if mon_ws in mtd: + DeleteWorkspace(mon_ws) +#-------------------------------------------------------------------------------------------------- + # + def _set_fnames(self,fnames,fext): + """ sets filenames lists and file extension lists + of length correspondent to run number length + + if length of the list provided differs from the length + of the run list, expands fnames list and fext list + to the whole runnumber list using last for fext and + first for fnames members of the + """ + if fnames: + if isinstance(fnames,list): + self._file_path = fnames + else: + self._file_path = [fnames] + + if not(self._file_path): + self._file_path = [''] * len(self._run_numbers) + else: + if len(self._file_path) != len(self._run_numbers): + self._file_path = [self._file_path[0]] * len(self._run_numbers) + + if fext: + if isinstance(fext,list): + self._fext = fext + else: + self._fext = [fext] + + if not (self._fext): + self._fext = [''] * len(self._run_numbers) + else: + if len(self._fext) != len(self._run_numbers): + base_fext = self._fext[-1] + self._fext = [base_fext] * len(self._run_numbers) + # + def get_file_guess(self,inst_name,run_num,default_fext=None): + """ return the name of run file for run number provided + + note, that internally set file extension overwrites + default_fext if not empty + """ + index = self._run_numbers.index(run_num) + guess = self._get_file_guess(inst_name,run_num,index,default_fext) + return (guess,index) + # + def _get_file_guess(self,inst_name,run_num,index,def_fext=None): + """ get file guess given index of the run in the list of runs """ + path_guess = self._file_path[index] + fext = self._fext[index] + if def_fext and len(fext) == 0: + fext = def_fext + guess = os.path.join(path_guess,'{0}{1}{2}'.\ + format(inst_name,run_num,fext)) + return guess + # + def add_or_replace_run(self,run_number,fpath='',fext=None,default_fext=False): + """ add run number to list of existing runs + + Let's prohibit adding the same run numbers using this method. + Equivalent run numbers can still be added using list assignment + + file path and file extension are added/modified if present + regardless of run being added or replaced + """ + if not(run_number in self._run_numbers): + self._run_numbers.append(run_number) + if not fpath: + fpath = self._file_path[-1] + self._file_path.append(fpath) + if not fext: + fext = self._fext[-1] + self._fext.append(fext) + + self._last_ind2sum=len(self._run_numbers)-1 + return self._last_ind2sum + else: + ext_ind = self._run_numbers.index(run_number) + if len(fpath)>0: + self._file_path[ext_ind]=fpath + if fext: + if not(default_fext and len(self._fext[ext_ind])>0): #not keep existing + self._fext[ext_ind]=fext + self._last_ind2sum=ext_ind + return ext_ind + # + def check_runs_equal(self,run_list,fpath=None,fext=None): + """ returns true if all run numbers in existing list are + in the comparison list and vice versa. + + if lists numbers coincide, + sets new file_path and fext list if such are provided + """ + if len(run_list) != len(self._run_numbers): + return False + + for run in run_list: + if not(run in self._run_numbers): + return False + self._set_fnames(fpath,fext) + return True + # + def get_current_run_info(self,sum_runs,ind=None): + """ return last run info for file to sum""" + if ind: + if not(ind > -1 and ind < len(self._run_numbers)): + raise RuntimeError("Index {0} is outside of the run list of {1} runs".format(ind,len(self._run_numbers))) + else: + ind = self.get_last_ind2sum(sum_runs) + return self._run_numbers[ind],self._file_path[ind],self._fext[ind],ind + # + def set_last_ind2sum(self,run_number): + """Check and set last number, contributing to summation + if this number is out of summation range, clear the summation + """ + run_number = int(run_number) + if run_number in self._run_numbers: + self._last_ind2sum = self._run_numbers.index(run_number) + else: + self._last_ind2sum = -1 + # + def get_run_list2sum(self,num_to_sum=None): + """Get run numbers of the files to be summed together + from the list of defined run numbers + """ + n_runs = len(self._run_numbers) + if num_to_sum: + if num_to_sum<=0: + num_to_sum = 1 + if num_to_sum>n_runs: + num_to_sum = n_runs + else: + num_to_sum=n_runs + + if self._last_ind2sum >= 0 and self._last_ind2sum < num_to_sum: + num_to_sum = self._last_ind2sum + 1 + + return self._run_numbers[:num_to_sum] + # + def get_last_ind2sum(self,sum_runs): + """Get last run number contributing to sum""" + + if self._last_ind2sum >= 0 and self._last_ind2sum < len(self._run_numbers): + ind = self._last_ind2sum + else: + if sum_runs: + ind = len(self._run_numbers) - 1 + else: + ind = 0 + return ind + # + def sum_ext(self,sum_runs): + if sum_runs: + last = self.get_last_ind2sum(sum_runs) + sum_ext = "SumOf{0}".format(len(self._run_numbers[:last + 1])) + else: + sum_ext = '' + return sum_ext + # + def get_runs(self): + return self._run_numbers + # + def find_run_files(self,inst_name,run_list=None,default_fext=None): + """ find run files correspondent to the run list provided + and set path to these files as new internal parameters + for the files in list + + Return the list of the runs, which files were + not found and found + + Run list have to coincide or be part of self._run_numbers + No special check for correctness is performed, so may fail + miserably + """ + if not run_list: + run_list = self._run_numbers + not_found=[] + found = [] + for run in run_list: + file_hint,index = self.get_file_guess(inst_name,run,default_fext) + try: + file = FileFinder.findRuns(file_hint)[0] + fpath,fname = os.path.split(file) + fname,fex = os.path.splitext(fname) + self._fext[index] = fex + self._file_path[index] = fpath + #self._last_ind2sum = index + found.append(run) + except RuntimeError: + not_found.append(run) + return not_found,found +#-------------------------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------------------------- +#-------------------------------------------------------------------------------------------------- + class RunDescriptor(PropDescriptor): - """ descriptor supporting a run and a workspace """ + """ descriptor to work with a run or list of runs specified + either as run number (run file) or as + this run loaded in memory as a workspace + + Used to help + """ # the host class referencing contained all instantiated descriptors. # Descriptors methods rely on it to work (e.g. to extract file loader @@ -16,129 +285,151 @@ class RunDescriptor(PropDescriptor): # so it has to be set up manually by PropertyManager __init__ method _holder = None _logger = None - # class level reference to the property manager - _PropMan = None + _sum_log_name = 'SumRuns' #-------------------------------------------------------------------------------------------------------------------- def __init__(self,prop_name,DocString=None): """ """ + self._prop_name = prop_name + if not DocString is None: + self.__doc__ = DocString + + self._ws_name = None + # pointer to workspace used to mask this workspace obtained at diag for + # this ws + self._mask_ws_name = None + + self._clear_all() + + def __len__(self): + """ overloaded len function, which + return length of the run-files list + to work with + """ + if not(self._run_number): + return 0 + if self._run_list: + return len(self._run_list._run_numbers) + else: + return 1 +#-------------------------------------------------------------------------------------------------------------------- + def _clear_all(self): + """ clear all internal properties, workspaces and caches, + associated with this run + """ # Run number self._run_number = None # Extension of the file to load data from # - self._prop_name = prop_name self._run_file_path = '' - self._run_ext = None - # Workspace name which corresponds to the run + self._fext= None + + if self._ws_name: + mon_ws = self._ws_name + '_monitors' + # Workspace name which corresponds to the run + if self._ws_name in mtd: + DeleteWorkspace(self._ws_name) + if mon_ws in mtd: + DeleteWorkspace(mon_ws) + self._ws_name = None # none if not loaded - # String used to identify the workspace related to this property w.r.t. - # other workspaces + # String used to identify the workspace related to this property + # w.r.t. other workspaces self._ws_cname = '' self._ws_suffix = '' - self._bind_to_sum = False - + # property contains run lists + self._run_list = None # - if not DocString is None: - self.__doc__ = DocString + self._in_cash = False + # clear masking workspace if any available + if self._mask_ws_name: + if self._mask_ws_name in mtd: + DeleteWorkspace(self._mask_ws_name) + self._mask_ws_name = None + #-------------------------------------------------------------------------------------------------------------------- def __get__(self,instance,owner): - """ return current run number or workspace if it is loaded""" - if not RunDescriptor._PropMan: - RunDescriptor._PropMan = owner - if instance is None: - return self + """ return current run number or workspace if it is loaded""" + if instance is None: + return self - if self._ws_name and self._ws_name in mtd: - return mtd[self._ws_name] - else: + if self._ws_name and self._ws_name in mtd: + return mtd[self._ws_name] + else: return self._run_number #-------------------------------------------------------------------------------------------------------------------- def __set__(self,instance,value): - """ Set up Run number and define workspace name from any source """ + """ Set up Run number and define workspace name from any source """ # - if not RunDescriptor._PropMan: - from PropertyManager import PropertyManager - RunDescriptor._PropMan = PropertyManager - - old_ws_name = self._ws_name - clear_fext = True - #end - if value == None: # clear current run number - self._run_number = None - self._ws_name = None - self._ws_cname = '' - self._ws_suffix = '' - # only one RunDescriptor can be summed under current approach. - # To disentangle one run descriptor from another -- set up binding - self._bind_to_sum = False - self._clear_old_ws(old_ws_name,self._ws_name,clear_fext) - RunDescriptor._PropMan.sum_runs.clear_sum() - return - if isinstance(value, api.Workspace): - #if 'SumOfRuns:' in value.getRun(): - # TODO: not implemented - - #else: - if self._ws_name != value.name(): - self._set_ws_as_source(value) - self._clear_old_ws(old_ws_name,self._ws_name,clear_fext) - self._bind_to_sum = False - RunDescriptor._PropMan.sum_runs.clear_sum() - return - else: # it is just reassigning the same workspace to itself - return - - if isinstance(value,str): # it may be run number as string or it may be a workspace name - if value in mtd: # workspace name - ws = mtd[value] - self.__set__(instance,ws) - return - else: - file_path,run_num,fext = prop_helpers.parse_run_file_name(value) - - if isinstance(run_num,list): - RunDescriptor._PropMan.sum_runs.set_list2add(run_num,file_path,fext) - self._bind_to_sum = True - if instance.sum_runs: - last_run_ind = RunDescriptor._PropMan.sum_runs.get_last_ind2sum() - main_fext = fext[last_run_ind].lower() - self._run_file_path = file_path[last_run_ind].lower() - else: - self.__set__(instance,run_num) - self._run_file_path = file_path - main_fext = fext.lower() - - # - if len(main_fext) > 0: - self._run_ext = main_fext - else: # will be default file extension - self._run_ext = None - clear_fext = False - elif isinstance(value,list): - if len(value) == 1: - self.__set__(instance,value[0]) - return - self._bind_to_sum = True - RunDescriptor._PropMan.sum_runs.set_list2add(value) - if instance.sum_runs: - last_run_ind = RunDescriptor._PropMan.sum_runs.get_last_ind2sum() - self._run_number = value[last_run_ind] - else: - self._run_number = value[0] - clear_fext = True - else: - clear_fext = True - self._run_number = int(value) - if self._bind_to_sum and instance and instance.sum_runs: - num2_sum = RunDescriptor._PropMan.sum_runs.set_last_ind2sum(self._run_number) - if num2_sum == 0: - self._bind_to_sum = False - instance.sum_runs = False + if value == None: # clear current run number + self._clear_all() + return + if isinstance(value, api.Workspace): + if self._ws_name: + if self._ws_name != value.name(): + self._clear_all() + self._set_ws_as_source(value) + else: + return # do nothing + # it is just reassigning the same workspace to itself + else: # first assignment of workspace to property + self._set_ws_as_source(value) + return + + if isinstance(value,str): # it may be run number as string or it may be a workspace name + if value in mtd: # workspace name + ws = mtd[value] + self.__set__(instance,ws) + return + else: # split string into run indexes and auxiliary file parameters + file_path,run_num,fext = prop_helpers.parse_run_file_name(value) + + if isinstance(run_num,list): + self._set_run_list(instance,run_num,file_path,fext) + else: + self._set_single_run(instance,run_num,file_path,fext,False) + elif isinstance(value,list): + self._set_run_list(instance,value,"",instance.data_file_ext) + else: + self._set_single_run(instance,value,"",instance.data_file_ext,True) +#-------------------------------------------------------------------------------------------------------------------- + def _set_single_run(self,instance,run_number,file_path='',fext=None,default_fext=False): + """ """ + self._run_number = int(run_number) + # build workspace name for current run number + new_ws_name = self._build_ws_name() + + if self._run_list and instance.sum_runs: + ind = self._run_list.add_or_replace_run(self._run_number,file_path,fext,default_fext) + self._run_file_path = self._run_list._file_path[ind] + self._fext= self._run_list._fext[ind] + self._ws_name = new_ws_name + else: + if self._ws_name != new_ws_name: + self._clear_all() + # clear all would invalidate run number and workspace number + self._run_number = int(run_number) + self._run_file_path = file_path + self._fext= fext + self._ws_name = new_ws_name + else: # nothing to do, there is workspace, which corresponds to this run number + pass # and it may be already loaded (may be not) - self._ws_cname = '' - self._ws_name = None - self._clear_old_ws(old_ws_name,None,clear_fext) #-------------------------------------------------------------------------------------------------------------------- + def _set_run_list(self,instance,run_list,file_path=None,fext=None): + + if self._run_list and self._run_list.check_runs_equal(run_list,file_path,fext): + return + else: + self._clear_all() + self._run_list = RunList(run_list,file_path,fext) + run_num,file_path,main_fext,ind = self._run_list.get_current_run_info(instance.sum_runs) + self._run_list.set_last_ind2sum(ind) + self._run_number = run_num + self._run_file_path = file_path + self._fext= main_fext + self._ws_name = self._build_ws_name() + def run_number(self): """ Return run number regardless of workspace is loaded or not""" if self._ws_name and self._ws_name in mtd: @@ -146,6 +437,40 @@ class RunDescriptor(PropDescriptor): return ws.getRunNumber() else: return self._run_number +#-------------------------------------------------------------------------------------------------------------------- +# Masking +#-------------------------------------------------------------------------------------------------------------------- + def get_masking(self): + """ return masking workspace specific to this particular workspace + together with number of masked spectra + """ + if self._mask_ws_name: + mask_ws = mtd[self._mask_ws_name] + num_masked = mask_ws.getRun().getLogData('NUM_SPECTRA_Masked').value + return (mask_ws,num_masked) + else: + return (None,0) +#-------------------------------------------------------------------------------------------------------------------- + def add_masked_ws(self,masked_ws): + """ extract masking from the workspace provided and store masks + to use with this run workspace + """ + if self._mask_ws_name: + mask_ws = mtd[self._mask_ws_name] + num_masked = mask_ws.getRun().getLogData('NUM_SPECTRA_Masked').value + add_mask_name = self._prop_name+'_tmp_masking' + else: + num_masked = 0 + add_mask_name = self._prop_name+'CurrentMasking' + masks,spectra=ExtractMask(InputWorkspace=masked_ws,OutputWorkspace=add_mask_name) + + num_masked+=len(spectra) + if self._mask_ws_name: + mask_ws +=masks + else: + self._mask_ws_name=add_mask_name + AddSampleLog(Workspace=self._mask_ws_name,LogName = 'NUM_SPECTRA_Masked', + LogText=str(num_masked),LogType='Number') #-------------------------------------------------------------------------------------------------------------------- def is_monws_separate(self): """ """ @@ -159,18 +484,87 @@ class RunDescriptor(PropDescriptor): return True else: return False + #-------------------------------------------------------------------------------------------------------------------- def get_run_list(self): """ Returns list of the files, assigned to current property """ current_run = self.run_number() - if self._bind_to_sum: - runs = RunDescriptor._PropMan.sum_runs.get_runs() + if self._run_list: + runs = self._run_list.get_runs() if current_run in runs: return runs else: return [current_run] else: - return [current_run] + return [current_run] +#-------------------------------------------------------------------------------------------------------------------- + @staticmethod + def get_sum_run_list(ws): + """retrieve list of contributed run numbers from the sum workspace log""" + + summed_runs=[] + if RunDescriptor._sum_log_name in ws.getRun(): + summed_str = ws.getRun().getLogData(RunDescriptor._sum_log_name).value + run_nums = summed_str.split(',') + for run_str in run_nums: + summed_runs.append(int(run_str)) + else: + raise RuntimeError("Presumably sum workspace {0} does not have sum log attached to it".format(ws.name())) + return summed_runs +#-------------------------------------------------------------------------------------------------------------------- + def get_runs_to_sum(self,existing_sum_ws=None,num_files=None): + """ return list of runs, expected to be summed together + excluding the runs, already summed and added to cached sum workspace + """ + + if not RunDescriptor._holder.sum_runs: + return ([],None,0) + if not self._run_list: + return ([],None,0) + # + summed_runs = [] + if not existing_sum_ws: + existing_sum_ws = self._run_list.get_cashed_sum_ws() + if existing_sum_ws: + summed_runs = RunDescriptor.get_sum_run_list(existing_sum_ws) + n_existing_sums = len(summed_runs) + + runs2_sum = self._run_list.get_run_list2sum(num_files) + for run in summed_runs: + if run in runs2_sum: + del runs2_sum[runs2_sum.index(run)] + return (runs2_sum,existing_sum_ws,n_existing_sums) +#-------------------------------------------------------------------------------------------------------------------- + def find_run_files(self,run_list=None): + """ find run files correspondent to the run list provided + and set path to these files as new internal parameters + for the files in the list + + Returns True and empty list or False and + the list of the runs, which files were not found + or not belong to the existing run list. + """ + + if not self._run_list: + if not run_list: + return (True,[],[]) + else: + return (False,run_list,[]) + + if run_list: + existing = self._run_list.get_runs() + non_existing=[] + for run in run_list: + if not(run in existing): + raise RuntimeError('run {0} is not in the existing run list'.format(run)) + + inst = RunDescriptor._holder.short_instr_name + default_fext= RunDescriptor._holder.data_file_ext + not_found,found=self._run_list.find_run_files(inst,run_list,default_fext) + if len(not_found) == 0: + return (True,[],found) + else: + return (False,not_found,found) #-------------------------------------------------------------------------------------------------------------------- def set_action_suffix(self,suffix=None): """ method to set part of the workspace name, which indicate some action performed over this workspace @@ -178,9 +572,12 @@ class RunDescriptor(PropDescriptor): e.g.: default suffix of a loaded workspace is 'RAW' but we can set it to SPE to show that conversion to energy will be performed for this workspace. - method returns the name of the workspace is will have with this suffix. Algorithms would later - work on the initial workspace and modify it in-place or to produce workspace with new name (depending if one + method returns the name of the workspace is will have with this suffix. + + Algorithms would later + work on the initial workspace and modify it in-place or to produce workspace with new name (depending if one wants to keep initial workspace) + synchronize_ws(ws_pointer) then should synchronize workspace and its name. TODO: This method should be automatically invoked by an algorithm decorator @@ -208,20 +605,20 @@ class RunDescriptor(PropDescriptor): new_name = self._build_ws_name() old_name = workspace.name() if new_name != old_name: - RenameWorkspace(InputWorkspace=old_name,OutputWorkspace=new_name) + RenameWorkspace(InputWorkspace=old_name,OutputWorkspace=new_name) - old_mon_name = old_name + '_monitors' - new_mon_name = new_name + '_monitors' - if old_mon_name in mtd: - RenameWorkspace(InputWorkspace=old_mon_name,OutputWorkspace=new_mon_name) + old_mon_name = old_name + '_monitors' + new_mon_name = new_name + '_monitors' + if old_mon_name in mtd: + RenameWorkspace(InputWorkspace=old_mon_name,OutputWorkspace=new_mon_name) self._ws_name = new_name #-------------------------------------------------------------------------------------------------------------------- def get_file_ext(self): """ Method returns current file extension for file to load workspace from e.g. .raw or .nxs extension """ - if self._run_ext: - return self._run_ext + if self._fext and len(self._fext)>0: + return self._fext else: # return IDF default return RunDescriptor._holder.data_file_ext #-------------------------------------------------------------------------------------------------------------------- @@ -232,20 +629,20 @@ class RunDescriptor(PropDescriptor): value = '.' + val else: value = val - self._run_ext = value + self._fext= value else: raise AttributeError('Source file extension can be only a string') #-------------------------------------------------------------------------------------------------------------------- @staticmethod - def _check_claibration_source(): - """ if user have not specified calibration as input to the script, + def _check_calibration_source(): + """ if user have not specified calibration as input to the script, try to retrieve calibration stored in file with run properties""" - changed_prop = RunDescriptor._holder.getChangedProperties() - if 'det_cal_file' in changed_prop: - use_workspace_calibration = False - else: - use_workspace_calibration = True - return use_workspace_calibration + changed_prop = RunDescriptor._holder.getChangedProperties() + if 'det_cal_file' in changed_prop: + use_workspace_calibration = False + else: + use_workspace_calibration = True + return use_workspace_calibration #-------------------------------------------------------------------------------------------------------------------- def get_workspace(self): """ Method returns workspace correspondent to current run number(s) @@ -254,7 +651,7 @@ class RunDescriptor(PropDescriptor): Returns Mantid pointer to the workspace, corresponding to this run number """ if not self._ws_name: - self._ws_name = self._build_ws_name() + self._ws_name = self._build_ws_name() if self._ws_name in mtd: @@ -262,32 +659,32 @@ class RunDescriptor(PropDescriptor): if ws.run().hasProperty("calibrated"): return ws # already calibrated else: - prefer_ws_calibration = self._check_claibration_source() - self.apply_calibration(ws,RunDescriptor._holder.det_cal_file,prefer_ws_calibration) - return ws + prefer_ws_calibration = self._check_calibration_source() + self.apply_calibration(ws,RunDescriptor._holder.det_cal_file,prefer_ws_calibration) + return ws else: - if self._run_number: - prefer_ws_calibration = self._check_claibration_source() - inst_name = RunDescriptor._holder.short_inst_name - calibration = RunDescriptor._holder.det_cal_file - if self._bind_to_sum and RunDescriptor._holder.sum_runs : # Sum runs - ws = RunDescriptor._PropMan.sum_runs.load_and_sum_runs(inst_name,RunDescriptor._holder.load_monitors_with_workspace) - else: # load current workspace - ws = self.load_run(inst_name, calibration,False, RunDescriptor._holder.load_monitors_with_workspace,prefer_ws_calibration) - - - self.synchronize_ws(ws) - self.apply_calibration(ws,calibration,prefer_ws_calibration) - - return ws - else: - return None + if self._run_number: + prefer_ws_calibration = self._check_calibration_source() + inst_name = RunDescriptor._holder.short_inst_name + calibration = RunDescriptor._holder.det_cal_file + if self._run_list and RunDescriptor._holder.sum_runs : # Sum runs + ws = self._load_and_sum_runs(inst_name,RunDescriptor._holder.load_monitors_with_workspace) + else: # load current workspace + ws = self.load_run(inst_name, calibration,False, RunDescriptor._holder.load_monitors_with_workspace,prefer_ws_calibration) + + + self.synchronize_ws(ws) + self.apply_calibration(ws,calibration,prefer_ws_calibration) + + return ws + else: + return None #-------------------------------------------------------------------------------------------------------------------- def get_ws_clone(self,clone_name='ws_clone'): - """ Get unbounded clone of eisting Run workspace """ + """ Get unbounded clone of existing Run workspace """ ws = self.get_workspace() CloneWorkspace(InputWorkspace=ws,OutputWorkspace=clone_name) - mon_ws_name = self.get_ws_name() + '_monitors' + mon_ws_name = ws.name() + '_monitors' if mon_ws_name in mtd: cl_mon_name = clone_name + '_monitors' CloneWorkspace(InputWorkspace=mon_ws_name,OutputWorkspace=cl_mon_name) @@ -298,39 +695,39 @@ class RunDescriptor(PropDescriptor): """ assign all parts of the run if input value is workspace """ self._run_number = value.getRunNumber() ws_name = value.name() - self._ws_suffix='' + self._ws_suffix = '' self._split_ws_name(ws_name) self.synchronize_ws(value) #-------------------------------------------------------------------------------------------------------------------- def chop_ws_part(self,origin,tof_range,rebin,chunk_num,n_chunks): - """ chop part of the original workspace and sets it up as new original. - Return the old one """ + """ chop part of the original workspace and sets it up to this run as new original + Return the pointer to workspace being chopped """ if not origin: - origin = self.get_workspace() + origin = self.get_workspace() origin_name = origin.name() try: - mon_ws = mtd[origin_name+'_monitors'] + mon_ws = mtd[origin_name + '_monitors'] except: - mon_ws = None + mon_ws = None - target_name = '#{0}/{1}#'.format(chunk_num,n_chunks)+origin_name + target_name = '#{0}/{1}#'.format(chunk_num,n_chunks) + origin_name if chunk_num == n_chunks: - RenameWorkspace(InputWorkspace=origin_name,OutputWorkspace=target_name) - if mon_ws: - RenameWorkspace(InputWorkspace=mon_ws,OutputWorkspace=target_name+'_monitors') - origin_name = target_name - origin_invalidated=True + RenameWorkspace(InputWorkspace=origin_name,OutputWorkspace=target_name) + if mon_ws: + RenameWorkspace(InputWorkspace=mon_ws,OutputWorkspace=target_name + '_monitors') + origin_name = target_name + origin_invalidated = True else: - if mon_ws: - CloneWorkspace(InputWorkspace=mon_ws,OutputWorkspace=target_name+'_monitors') - origin_invalidated=False + if mon_ws: + CloneWorkspace(InputWorkspace=mon_ws,OutputWorkspace=target_name + '_monitors') + origin_invalidated = False if rebin: # debug and compatibility mode with old reduction - Rebin(origin_name,OutputWorkspace=target_name,Params=[tof_range[0],tof_range[1],tof_range[2]],PreserveEvents=False) + Rebin(origin_name,OutputWorkspace=target_name,Params=[tof_range[0],tof_range[1],tof_range[2]],PreserveEvents=False) else: - CropWorkspace(origin_name,OutputWorkspace=target_name,XMin=tof_range[0],XMax=tof_range[2]) + CropWorkspace(origin_name,OutputWorkspace=target_name,XMin=tof_range[0],XMax=tof_range[2]) self._set_ws_as_source(mtd[target_name]) if origin_invalidated: @@ -346,8 +743,10 @@ class RunDescriptor(PropDescriptor): workspace which contains monitors. """ data_ws = self.get_workspace() + if not data_ws: + return None - monWS_name = self.get_ws_name() + '_monitors' + monWS_name = data_ws.name() + '_monitors' if monWS_name in mtd: mon_ws = mtd[monWS_name] monitors_separate = True @@ -361,31 +760,29 @@ class RunDescriptor(PropDescriptor): mon_ws = self.copy_spectrum2monitors(data_ws,mon_ws,specID) if monitor_ID: - try: + try: ws_index = mon_ws.getIndexFromSpectrumNumber(monitor_ID) - except: # - mon_ws = None + except: # + mon_ws = None else: mon_list = self._holder.get_used_monitors_list() for monID in mon_list: try: ws_ind = mon_ws.getIndexFromSpectrumNumber(int(monID)) except: - mon_ws = None - break + mon_ws = None + break return mon_ws #-------------------------------------------------------------------------------------------------------------------- - def get_ws_name(self): - """ return workspace name. If ws name is not defined, build it first and set up as the target ws name - """ + def is_existing_ws(self): + """ method verifies if property value relates to workspace, present in ADS """ if self._ws_name: if self._ws_name in mtd: - return self._ws_name + return True else: - raise RuntimeError('Getting workspace name {0} for undefined workspace. Run get_workspace first'.format(self._ws_name)) - - self._ws_name = self._build_ws_name() - return self._ws_name + return False + else: + return False #-------------------------------------------------------------------------------------------------------------------- def file_hint(self,run_num_str=None,filePath=None,fileExt=None,**kwargs): """ procedure to provide run file guess name from run properties @@ -393,7 +790,7 @@ class RunDescriptor(PropDescriptor): main purpose -- to support customized order of file extensions """ if not run_num_str: - run_num_str = str(self.run_number()) + run_num_str = str(self.run_number()) inst_name = RunDescriptor._holder.short_inst_name @@ -404,9 +801,9 @@ class RunDescriptor(PropDescriptor): old_ext = self.get_file_ext() else: if fileExt: - old_ext = fileExt + old_ext = fileExt else: - old_ext = self.get_file_ext() + old_ext = self.get_file_ext() hint = inst_name + run_num_str + old_ext if not filePath: @@ -436,40 +833,40 @@ class RunDescriptor(PropDescriptor): try: file = FileFinder.findRuns(file_hint)[0] fname,fex = os.path.splitext(file) - self._run_ext = fex + self._fext= fex if old_ext != fex: - message = ' Cannot find run-file with extension {0}.\n'\ - ' Found file {1} instead'.format(old_ext,file) + message = '*** Cannot find run-file with extension {0}.\n'\ + ' Found file {1} instead'.format(old_ext,file) RunDescriptor._logger(message,'notice') self._run_file_path = os.path.dirname(fname) - return file + return (True,file) except RuntimeError: - message = 'Cannot find file matching hint {0} on current search paths ' \ - 'for instrument {1}'.format(file_hint,inst_name) + message = '*** Cannot find file matching hint {0} on Mantid search paths '.\ + format(file_hint) if not 'be_quet' in kwargs: RunDescriptor._logger(message,'warning') - return 'ERROR:find_file: ' + message + return (False,message) #-------------------------------------------------------------------------------------------------------------------- def load_file(self,inst_name,ws_name,run_number=None,load_mon_with_workspace=False,filePath=None,fileExt=None,**kwargs): """ load run for the instrument name provided. If run_numner is None, look for the current run""" - data_file = self.find_file(None,filePath,fileExt,**kwargs) - if data_file.find('ERROR') > -1: - self._ws_name = None - raise IOError(data_file) + ok,data_file = self.find_file(None,filePath,fileExt,**kwargs) + if not ok: + self._ws_name = None + raise IOError(data_file) if load_mon_with_workspace: - mon_load_option = 'Include' + mon_load_option = 'Include' else: - mon_load_option = 'Separate' + mon_load_option = 'Separate' # try: # Hack: LoadEventNexus does not understand Separate at the moment and throws. # And event loader always loads monitors separately - Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = mon_load_option) + Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = mon_load_option) except ValueError: #mon_load_option =str(int(load_mon_with_workspace)) - Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = '1',MonitorsAsEvents='0') + Load(Filename=data_file, OutputWorkspace=ws_name,LoadMonitors = '1',MonitorsAsEvents='0') RunDescriptor._logger("Loaded {0}".format(data_file),'information') @@ -490,11 +887,7 @@ class RunDescriptor(PropDescriptor): ws_name = kwargs['ws_name'] del kwargs['ws_name'] else: - try: - ws_name = self.get_ws_name() - except RuntimeError: - self._ws_name = None - ws_name = self.get_ws_name() + ws_name = self._build_ws_name() #----------------------------------- if ws_name in mtd and not force: RunDescriptor._logger("{0} already loaded as workspace.".format(ws_name),'information') @@ -513,10 +906,10 @@ class RunDescriptor(PropDescriptor): calibration option (e.g. det_cal_file used a while ago) and try to use it """ - if not (calibration or use_ws_calibration): + if not calibration or use_ws_calibration: return if not isinstance(loaded_ws, api.Workspace): - raise RuntimeError(' Calibration can be applied to a workspace only and got object of type {0}'.format(type(loaded_ws))) + raise RuntimeError(' Calibration can be applied to a workspace only and got object of type {0}'.format(type(loaded_ws))) if loaded_ws.run().hasProperty("calibrated"): return # already calibrated @@ -533,7 +926,7 @@ class RunDescriptor(PropDescriptor): test_name = ws_calibration ws_calibration = FileFinder.getFullPath(ws_calibration) if len(ws_calibration) == 0: - raise RuntimeError('Can not find defined in run {0} calibration file {1}\n'\ + raise RuntimeError('Can not find defined in run {0} calibration file {1}\n'\ 'Define det_cal_file reduction parameter properly'.format(loaded_ws.name(),test_name)) RunDescriptor._logger('*** load_data: Calibrating data using workspace defined calibration file: {0}'.format(ws_calibration),'notice') except KeyError: # no det_cal_file defined in workspace @@ -554,7 +947,7 @@ class RunDescriptor(PropDescriptor): #-------------------------------------------------------------------------------------------------------------------- @staticmethod def copy_spectrum2monitors(data_ws,mon_ws,spectraID): - """ + """ this routine copies a spectrum form workspace to monitor workspace and rebins it according to monitor workspace binning @param data_ws -- the event workspace which detector is considered as monitor or Mantid pointer to this workspace @@ -564,28 +957,28 @@ class RunDescriptor(PropDescriptor): """ # ---------------------------- - try: - ws_index = mon_ws.getIndexFromSpectrumNumber(spectraID) + try: + ws_index = mon_ws.getIndexFromSpectrumNumber(spectraID) # Spectra is already in the monitor workspace - return mon_ws - except: - ws_index = data_ws.getIndexFromSpectrumNumber(spectraID) + return mon_ws + except: + ws_index = data_ws.getIndexFromSpectrumNumber(spectraID) # - x_param = mon_ws.readX(0) - bins = [x_param[0],x_param[1] - x_param[0],x_param[-1]] - ExtractSingleSpectrum(InputWorkspace=data_ws,OutputWorkspace='tmp_mon',WorkspaceIndex=ws_index) - Rebin(InputWorkspace='tmp_mon',OutputWorkspace='tmp_mon',Params=bins,PreserveEvents='0') + x_param = mon_ws.readX(0) + bins = [x_param[0],x_param[1] - x_param[0],x_param[-1]] + ExtractSingleSpectrum(InputWorkspace=data_ws,OutputWorkspace='tmp_mon',WorkspaceIndex=ws_index) + Rebin(InputWorkspace='tmp_mon',OutputWorkspace='tmp_mon',Params=bins,PreserveEvents='0') # should be vice versa but Conjoin invalidate ws pointers and hopefully # nothing could happen with workspace during conjoining #AddSampleLog(Workspace=monWS,LogName=done_log_name,LogText=str(ws_index),LogType='Number') - mon_ws_name = mon_ws.getName() - ConjoinWorkspaces(InputWorkspace1=mon_ws,InputWorkspace2='tmp_mon') - mon_ws = mtd[mon_ws_name] + mon_ws_name = mon_ws.getName() + ConjoinWorkspaces(InputWorkspace1=mon_ws,InputWorkspace2='tmp_mon') + mon_ws = mtd[mon_ws_name] - if 'tmp_mon' in mtd: - DeleteWorkspace(WorkspaceName='tmp_mon') - return mon_ws + if 'tmp_mon' in mtd: + DeleteWorkspace(WorkspaceName='tmp_mon') + return mon_ws #-------------------------------------------------------------------------------------------------------------------- def clear_monitors(self): """ method removes monitor workspace form analysis data service if it is there @@ -595,14 +988,42 @@ class RunDescriptor(PropDescriptor): monWS_name = self._ws_name + '_monitors' if monWS_name in mtd: DeleteWorkspace(monWS_name) +#-------------------------------------------------------------------------------------------------------------------- + def clear_resulting_ws(self): + """ remove workspace from memory as if it has not been processed + and clear all operations indicators except cashes and run lists. + + Attempt to get workspace for a file based run should in this case + load workspace again + """ + ws_name = self._ws_name + mon_name = ws_name+'_monitors' + self._ws_name ='' + self._ws_cname = '' + self._ws_suffix = '' + if ws_name in mtd: + ws = mtd[ws_name] + self._run_number = ws.getRunNumber() + DeleteWorkspace(ws_name) + if mon_name in mtd: + DeleteWorkspace(mon_name) + if self._run_list: + ind = self._run_list.add_or_replace_run(self._run_number) + self._run_file_path = self._run_list._file_path[ind] + self._fext= self._run_list._fext[ind] #-------------------------------------------------------------------------------------------------------------------- - def _build_ws_name(self): + def _build_ws_name(self,sum_runs=None): instr_name = self._instr_name() + if self._run_list: + if not sum_runs: + sum_runs = RunDescriptor._holder.sum_runs + sum_ext = self._run_list.sum_ext(sum_runs) + else: + sum_ext = '' - sum_ext = RunDescriptor._PropMan.sum_runs.sum_ext() if self._run_number: ws_name = '{0}{1}{2}{3:0>#6d}{4}{5}'.format(self._prop_name,instr_name,self._ws_cname,self._run_number,sum_ext,self._ws_suffix) else: @@ -622,45 +1043,138 @@ class RunDescriptor(PropDescriptor): """ # Remove suffix name = self.rremove(ws_name,self._ws_suffix) - sumExt = RunDescriptor._PropMan.sum_runs.sum_ext() + if self._run_list: + summed = RunDescriptor._holder.sum_runs + sumExt = self._run_list.sum_ext(summed) + else: + sumExt = '' if len(sumExt) > 0: name = self.rremove(ws_name,sumExt) # remove _prop_name: name = name.replace(self._prop_name,'',1) try: - part_ind = re.search('#(.+?)#', name).group(0) - name =name.replace(part_ind,'',1) + part_ind = re.search('#(.+?)#', name).group(0) + name = name.replace(part_ind,'',1) except AttributeError: - part_ind='' + part_ind = '' if self._run_number: instr_name = self._instr_name() name = name.replace(instr_name,'',1) - self._ws_cname = part_ind+filter(lambda c: not c.isdigit(), name) + self._ws_cname = part_ind + filter(lambda c: not c.isdigit(), name) else: - self._ws_cname = part_ind+name + self._ws_cname = part_ind + name # def _instr_name(self): - if RunDescriptor._holder: + if RunDescriptor._holder: instr_name = RunDescriptor._holder.short_inst_name - else: + else: instr_name = '_test_instrument' - return instr_name - - def _clear_old_ws(self,old_ws_name,new_name,clear_fext=False): - """ helper method used in __set__. When new data (run or wod) """ - if old_ws_name: - if new_name != old_ws_name: - if old_ws_name in mtd: - DeleteWorkspace(old_ws_name) - old_mon_ws = old_ws_name + '_monitors' - if old_mon_ws in mtd: - DeleteWorkspace(old_mon_ws) - if clear_fext: - self._run_ext = None - self._run_file_path = '' + return instr_name + + + def has_own_value(self): + """ interface property used to verify if + the class got its own values or been shadowed by + property, this one depends on + + """ + return not(self._in_cash) + + def notify_sum_runs_changed(self,old_value,new_value): + """ Take actions on changes to sum_runs option + + """ + if self._run_list: + if old_value != new_value: + rl = self._run_list + self._clear_all() + rl.set_last_ind2sum(-1) # this will reset index to default + self._run_list = rl + run_num,file_path,main_fext,ind = self._run_list.get_current_run_info(new_value) + self._run_list.set_last_ind2sum(ind) + self._run_number = run_num + self._run_file_path = file_path + self._fext= main_fext + self._ws_name = self._build_ws_name(new_value) + if new_value is False: + self._run_list.del_cashed_sum() + + def _load_and_sum_runs(self,inst_name,monitors_with_ws): + """ Load multiple runs and sum them together + + monitors_with_ws -- if true, load monitors with workspace + """ + + RunDescriptor._logger("*** Summing multiple runs ****") + + runs_to_sum,sum_ws,n_already_summed = self.get_runs_to_sum() + num_to_sum = len(runs_to_sum) + + if sum_ws: + RunDescriptor._logger("*** Use cached sum of {0} workspaces and adding {1} remaining".\ + format(n_already_summed,num_to_sum)) + sum_ws_name = sum_ws.name() + sum_mon_name = sum_ws_name + '_monitors' + AddedRunNumbers = sum_ws.getRun().getLogData(RunDescriptor._sum_log_name).value + load_start=0 + else: + RunDescriptor._logger("*** Loading #{0}/{1}, run N: {2} ".\ + format(1,num_to_sum,runs_to_sum[0])) + + f_guess,index = self._run_list.get_file_guess(inst_name,runs_to_sum[0]) + ws = self.load_file(inst_name,'Sum_ws',False,monitors_with_ws, + False,file_hint=f_guess) + + sum_ws_name = ws.name() + sum_mon_name = sum_ws_name + '_monitors' + #AddedRunNumbers = [ws.getRunNumber()] + AddedRunNumbers = str(ws.getRunNumber()) + load_start =1 + #end + + for ind,run_num in enumerate(runs_to_sum[load_start:num_to_sum]): + + RunDescriptor._logger("*** Adding #{0}/{1}, run N: {2} ".\ + format(ind + 1+load_start,num_to_sum,run_num)) + + term_name = '{0}_ADDITIVE_#{1}/{2}'.format(inst_name,ind + 1+load_start,num_to_sum)# + f_guess,index = self._run_list.get_file_guess(inst_name,run_num) + + wsp = self.load_file(inst_name,term_name,False, + monitors_with_ws,False,file_hint=f_guess) + + wsp_name = wsp.name() + wsp_mon_name = wsp_name + '_monitors' + Plus(LHSWorkspace=sum_ws_name,RHSWorkspace=wsp_name, + OutputWorkspace=sum_ws_name,ClearRHSWorkspace=True) + # AddedRunNumbers.append(run_num) + AddedRunNumbers+=',' + str(run_num) + if not monitors_with_ws: + Plus(LHSWorkspace=sum_mon_name,RHSWorkspace=wsp_mon_name, + OutputWorkspace=sum_mon_name,ClearRHSWorkspace=True) + if wsp_name in mtd: + DeleteWorkspace(wsp_name) + if wsp_mon_name in mtd: + DeleteWorkspace(wsp_mon_name) + #end for + RunDescriptor._logger("*** Summing multiple runs completed ****") + + #AddSampleLog(Workspace=sum_ws_name,LogName = + #RunDescriptor._sum_log_name, + # LogText=AddedRunNumbers,LogType='Number Series') + AddSampleLog(Workspace=sum_ws_name,LogName = RunDescriptor._sum_log_name, + LogText=AddedRunNumbers,LogType='String') + + if RunDescriptor._holder.cashe_sum_ws: + # store workspace in cash for further usage + self._run_list.set_cashed_sum_ws(mtd[sum_ws_name],self._prop_name+'Sum_ws') + ws = self._run_list.get_cashed_sum_clone() + else: + ws = mtd[sum_ws_name] + return ws #------------------------------------------------------------------------------------------------------------------------------- @@ -675,30 +1189,154 @@ class RunDescriptorDependent(RunDescriptor): def __init__(self,host_run,ws_preffix,DocString=None): RunDescriptor.__init__(self,ws_preffix,DocString) self._host = host_run - self._this_run_defined = False + self._has_own_value = False def __get__(self,instance,owner=None): - """ return dependent run number which is host run number if this one has not been set or this run number if it was""" - if self._this_run_defined: - if instance is None: - return self - else: - return super(RunDescriptorDependent,self).__get__(instance,owner) - else: - return self._host.__get__(instance,owner) + """ return dependent run number which is host run number if this one has not been set + or this run number if it was + """ + if instance is None: # this class functions and the host functions + return self + + if self._has_own_value: # this allows to switch between + return super(RunDescriptorDependent,self).__get__(instance,owner) + else: + return self._host.__get__(instance,owner) + def __set__(self,instance,value): if value is None: - self._this_run_defined = False - return - self._this_run_defined = True + self._has_own_value = False + return + self._has_own_value = True super(RunDescriptorDependent,self).__set__(instance,value) - #def __del__(self): - # # destructor removes bounded workspace - # # Probably better not to at current approach - # if self._ws_name in mtd: - # DeleteWorkspace(self._ws_name) - # object.__del__(self) + def has_own_value(self): + """ interface property used to verify if + the class got its own values or been shadowed by + property, this one depends on + """ + return self._has_own_value + #-------------------------------------------------------------- + # TODO -- how to automate all these functions below? + def run_number(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).run_number() + else: + return self._host.run_number() + # + def is_monws_separate(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).is_monws_separate() + else: + return self._host.is_monws_separate() + + def get_run_list(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_run_list() + else: + return self._host.get_run_list() + + def set_action_suffix(self,suffix=None): + if self._has_own_value: + return super(RunDescriptorDependent,self).set_action_suffix(suffix) + else: + return self._host.set_action_suffix(suffix) + + def synchronize_ws(self,workspace=None): + if self._has_own_value: + return super(RunDescriptorDependent,self).synchronize_ws(workspace) + else: + return self._host.synchronize_ws(workspace) + + def get_file_ext(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_file_ext() + else: + return self._host.get_file_ext() + + def set_file_ext(self,val): + if self._has_own_value: + return super(RunDescriptorDependent,self).set_file_ex(val) + else: + return self._host.set_file_ex(val) - + def get_workspace(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_workspace() + else: + return self._host.get_workspace() + + def get_ws_clone(self,clone_name='ws_clone'): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_ws_clone() + else: + return self._host.get_ws_clone() + + def chop_ws_part(self,origin,tof_range,rebin,chunk_num,n_chunks): + if self._has_own_value: + return super(RunDescriptorDependent,self).chop_ws_part(origin,tof_range,rebin,chunk_num,n_chunks) + else: + return self._host.chop_ws_part(origin,tof_range,rebin,chunk_num,n_chunks) + + def get_monitors_ws(self,monitor_ID=None): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_monitors_ws(monitor_ID) + else: + return self._host.get_monitors_ws(monitor_ID) + + def is_existing_ws(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).is_existing_ws() + else: + return self._host.is_existing_ws() + + def file_hint(self,run_num_str=None,filePath=None,fileExt=None,**kwargs): + if self._has_own_value: + return super(RunDescriptorDependent,self).file_hint(run_num_str,filePath,fileExt,**kwargs) + else: + return self._host.file_hint(run_num_str,filePath,fileExt,**kwargs) + + def find_file(self,inst_name=None,run_num=None,filePath=None,fileExt=None,**kwargs): + if self._has_own_value: + return super(RunDescriptorDependent,self).find_file(inst_name,run_num,filePath,fileExt,**kwargs) + else: + return self._host.find_file(inst_name,run_num,filePath,fileExt,**kwargs) + + def load_file(self,inst_name,ws_name,run_number=None,load_mon_with_workspace=False,filePath=None,fileExt=None,**kwargs): + if self._has_own_value: + return super(RunDescriptorDependent,self).load_file(inst_name,ws_name,run_number,load_mon_with_workspace,filePath,fileExt,**kwargs) + else: + return self._host.load_file(inst_name,ws_name,run_number,load_mon_with_workspace,filePath,fileExt,**kwargs) + + def load_run(self,inst_name, calibration=None, force=False, mon_load_option=False,use_ws_calibration=True,\ + filePath=None,fileExt=None,**kwargs): + if self._has_own_value: + return super(RunDescriptorDependent,self).load_run(inst_name,calibration, force, mon_load_option,use_ws_calibration,\ + filePath,fileExt,**kwargs) + else: + return self._host.load_run(inst_name,calibration, force, mon_load_option,use_ws_calibration,\ + filePath,fileExt,**kwargs) + + def apply_calibration(self,loaded_ws,calibration=None,use_ws_calibration=True): + if self._has_own_value: + return super(RunDescriptorDependent,self).apply_calibration(loaded_ws,calibration,use_ws_calibration) + else: + return self._host.apply_calibration(loaded_ws,calibration,use_ws_calibration) + + def clear_monitors(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).clear_monitors() + else: + return self._host.clear_monitors() + def get_masking(self): + if self._has_own_value: + return super(RunDescriptorDependent,self).get_masking() + else: + return self._host.get_masking() + def add_masked_ws(self,masked_ws): + if self._has_own_value: + return super(RunDescriptorDependent,self).add_masked_ws(masked_ws) + else: + return self._host.add_masked_ws(masked_ws) +#-------------------------------------------------------------------------------------------------------------------- diff --git a/Code/Mantid/scripts/Inelastic/Direct/diagnostics.py b/Code/Mantid/scripts/Inelastic/Direct/diagnostics.py index 76ba5a12bb48b402de0e445d76b30e17b8a774e6..1891c01c73c893468a9d6f2127676c8aec188891 100644 --- a/Code/Mantid/scripts/Inelastic/Direct/diagnostics.py +++ b/Code/Mantid/scripts/Inelastic/Direct/diagnostics.py @@ -68,40 +68,63 @@ def diagnose(white_int,**kwargs): # Hard mask hardmask_file = kwargs.get('hard_mask_file', None) - if hardmask_file is not None: + + # process subsequent calls to this routine, when white mask is already defined + white= kwargs.get('white_mask',None) # and white beam is not changed + # white mask assumed to be global so no sectors in there + if not(white is None) and isinstance(white,RunDescriptor.RunDescriptor): + hardmask_file = None + white_mask,num_failed = white.get_masking() + add_masking(white_int, white_mask) + van_mask = None + else: # prepare workspace to keep white mask + white_mask = None + van_mask = CloneWorkspace(white_int) + + if not (hardmask_file is None): LoadMask(Instrument=kwargs.get('instr_name',''),InputFile=parser.hard_mask_file, OutputWorkspace='hard_mask_ws') MaskDetectors(Workspace=white_int, MaskedWorkspace='hard_mask_ws') + MaskDetectors(Workspace=van_mask, MaskedWorkspace='hard_mask_ws') # Find out how many detectors we hard masked _dummy_ws,masked_list = ExtractMask(InputWorkspace='hard_mask_ws') DeleteWorkspace('_dummy_ws') test_results[0][0] = os.path.basename(parser.hard_mask_file) test_results[0][1] = len(masked_list) + DeleteWorkspace('hard_mask_ws') if not parser.use_hard_mask_only : - # White beam Test - __white_masks, num_failed = do_white_test(white_int, parser.tiny, parser.huge, - parser.van_out_lo, parser.van_out_hi, - parser.van_lo, parser.van_hi, - parser.van_sig, start_index, end_index) - test_results[1] = [str(__white_masks), num_failed] - add_masking(white_int, __white_masks, start_index, end_index) - DeleteWorkspace(__white_masks) - - # Second white beam test - if 'second_white' in kwargs: - __second_white_masks, num_failed = do_second_white_test(white_int, parser.second_white, parser.tiny, parser.huge,\ + # White beam Test + if white_mask: + test_results[1] = ['white_mask cache global', num_failed] + else: + __white_masks, num_failed = do_white_test(white_int, parser.tiny, parser.huge, + parser.van_out_lo, parser.van_out_hi, + parser.van_lo, parser.van_hi, + parser.van_sig, start_index, end_index) + test_results[1] = [str(__white_masks), num_failed] + add_masking(white_int, __white_masks, start_index, end_index) + if van_mask: + add_masking(van_mask, __white_masks, start_index, end_index) + DeleteWorkspace(__white_masks) + + # Second white beam test + if 'second_white' in kwargs: #NOT IMPLEMENTED + raise NotImplementedError("Second white is not yet implemented") + __second_white_masks, num_failed = do_second_white_test(white_int, parser.second_white, parser.tiny, parser.huge,\ parser.van_out_lo, parser.van_out_hi,\ parser.van_lo, parser.van_hi, parser.variation,\ parser.van_sig, start_index, end_index) - test_results[2] = [str(__second_white_masks), num_failed] - add_masking(white_int, __second_white_masks, start_index, end_index) + test_results[2] = [str(__second_white_masks), num_failed] + add_masking(white_int, __second_white_masks, start_index, end_index) + #TODO + #add_masking(van_mask, __second_white_masks, start_index, end_index) # # Zero total count check for sample counts # - zero_count_failures = 0 - if kwargs.get('sample_counts',None) is not None and kwargs.get('samp_zero',False): + zero_count_failures = 0 + if kwargs.get('sample_counts',None) is not None and kwargs.get('samp_zero',False): add_masking(parser.sample_counts, white_int) maskZero, zero_count_failures = FindDetectorsOutsideLimits(InputWorkspace=parser.sample_counts,\ StartWorkspaceIndex=start_index, EndWorkspaceIndex=end_index,\ @@ -112,10 +135,10 @@ def diagnose(white_int,**kwargs): # # Background check # - if hasattr(parser, 'background_int'): + if hasattr(parser, 'background_int'): add_masking(parser.background_int, white_int) __bkgd_mask, failures = do_background_test(parser.background_int, parser.samp_lo,\ - parser.samp_hi, parser.samp_sig, parser.samp_zero, start_index, end_index) + parser.samp_hi, parser.samp_sig, parser.samp_zero, start_index, end_index) test_results[3] = [str(__bkgd_mask), zero_count_failures + failures] add_masking(white_int, __bkgd_mask, start_index, end_index) DeleteWorkspace(__bkgd_mask) @@ -123,7 +146,7 @@ def diagnose(white_int,**kwargs): # # Bleed test # - if hasattr(parser, 'bleed_test') and parser.bleed_test: + if hasattr(parser, 'bleed_test') and parser.bleed_test: if not hasattr(parser, 'sample_run'): raise RuntimeError("Bleed test requested but the sample_run keyword has not been provided") __bleed_masks, failures = do_bleed_test(parser.sample_run, parser.bleed_maxrate, parser.bleed_pixels) @@ -135,21 +158,22 @@ def diagnose(white_int,**kwargs): end_index_name=" to: end" default = True if hasattr(parser, 'print_diag_results') and parser.print_diag_results: - default=True + default=True if 'start_index' in kwargs: - default = False - start_index_name = "from: "+str(kwargs['start_index']) + default = False + start_index_name = "from: "+str(kwargs['start_index']) if 'end_index' in kwargs : - default = False - end_index_name = " to: "+str(kwargs['end_index']) + default = False + end_index_name = " to: "+str(kwargs['end_index']) testName=start_index_name+end_index_name if not default : - testName = " For bank: "+start_index_name+end_index_name + testName = " For bank: "+start_index_name+end_index_name if hasattr(parser, 'print_diag_results') and parser.print_diag_results: print_test_summary(test_results,testName) + return van_mask #------------------------------------------------------------------------------- @@ -325,11 +349,11 @@ def do_bleed_test(sample_run, max_framerate, ignored_pixels): if __Reducer__: # Try to use generic loader which would work with files or workspaces alike sample_run = __Reducer__.get_run_descriptor(sample_run) data_ws = sample_run.get_workspace() # this will load data if necessary - ws_name = sample_run.get_ws_name()+'_bleed' + ws_name = data_ws.name()+'_bleed' else: # may be sample run is already a run descriptor despite __Reducer__ have not been exposed data_ws = sample_run.get_workspace() # this will load data if necessary - ws_name = sample_run.get_ws_name()+'_bleed' + ws_name = data_ws.name()+'_bleed' if max_framerate is None: max_framerate = float(data_ws.getInstrument().getNumberParameter('max-tube-framerate')[0]) diff --git a/Code/Mantid/scripts/test/DirectEnergyConversionTest.py b/Code/Mantid/scripts/test/DirectEnergyConversionTest.py index 897c2e03e105ffe503c77ff2bae6fb06bae24c73..1c78b4bd456867cb4523dad85b0f57f32c314f01 100644 --- a/Code/Mantid/scripts/test/DirectEnergyConversionTest.py +++ b/Code/Mantid/scripts/test/DirectEnergyConversionTest.py @@ -1,5 +1,5 @@ import os, sys -#os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release;"+os.environ["PATH"] +#os.environ["PATH"] = r"c:\Mantid\Code\builds\br_master\bin\Release;"+os.environ["PATH"] from mantid.simpleapi import * from mantid import api import unittest @@ -8,7 +8,6 @@ from Direct.DirectEnergyConversion import DirectEnergyConversion from Direct.PropertyManager import PropertyManager import Direct.dgreduce as dgreduce - #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- #----------------------------------------------------------------------------------------------------------------------------------------- @@ -25,9 +24,6 @@ class DirectEnergyConversionTest(unittest.TestCase): api.AnalysisDataService.clear() pass - #def test_build_coupled_keys_dict_simple(self): - # params = ["] - def test_init_reducer(self): tReducer = self.reducer self.assertFalse(tReducer.prop_man is None) @@ -73,10 +69,8 @@ class DirectEnergyConversionTest(unittest.TestCase): - # redefine test save methors to produce test ouptut - + # redefine test save methods to produce test output tReducer.prop_man.save_format=['spe','nxspe','nxs'] - tReducer.save_results(tws,'save_formats_test_file.tt') files = ['save_formats_test_file.spe','save_formats_test_file.nxspe','save_formats_test_file.nxs'] @@ -162,8 +156,9 @@ class DirectEnergyConversionTest(unittest.TestCase): tReducer = DirectEnergyConversion(mono_ws.getInstrument()) tReducer.prop_man.incident_energy = 5. tReducer.prop_man.monovan_integr_range=[-10,10] + tReducer.wb_run = mono_ws - (nf1,nf2,nf3,nf4) = tReducer.get_abs_normalization_factor(mono_ws.getName(),5.) + (nf1,nf2,nf3,nf4) = tReducer.get_abs_normalization_factor(PropertyManager.wb_run,5.) self.assertAlmostEqual(nf1,0.58561121802167193,7) self.assertAlmostEqual(nf1,nf2) self.assertAlmostEqual(nf2,nf3) @@ -175,7 +170,8 @@ class DirectEnergyConversionTest(unittest.TestCase): sig = mono_ws.dataY(0) sig[:]=0 - (nf1,nf2,nf3,nf4) = tReducer.get_abs_normalization_factor(mono_ws.getName(),5.) + tReducer.wb_run = mono_ws + (nf1,nf2,nf3,nf4) = tReducer.get_abs_normalization_factor(PropertyManager.wb_run,5.) self.assertAlmostEqual(nf1,0.585611218022,7) self.assertAlmostEqual(nf1,nf2) self.assertAlmostEqual(nf2,nf3) @@ -206,10 +202,6 @@ class DirectEnergyConversionTest(unittest.TestCase): self.assertTrue(isinstance(ws,api.MatrixWorkspace)) - ##def test_diag_call(self): - ## tReducer = self.reducer - ## # should do nothing as already initialized above, but if not will initiate the instrument - ## tReducer.initialise("MAP") ## tReducet.di def test_energy_to_TOF_range(self): @@ -292,8 +284,8 @@ class DirectEnergyConversionTest(unittest.TestCase): def test_tof_range(self): - run=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=6, BankPixelWidth=1, NumEvents=10, XUnit='DeltaE', - XMin=-20, XMax=65, BinWidth=0.2) + run=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=6, BankPixelWidth=1, NumEvents=10,\ + XUnit='DeltaE', XMin=-20, XMax=65, BinWidth=0.2) LoadInstrument(run,InstrumentName='MARI') red = DirectEnergyConversion(run.getInstrument()) @@ -327,16 +319,16 @@ class DirectEnergyConversionTest(unittest.TestCase): def test_multirep_mode(self): # create test workspace - run_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100000, XUnit='Energy', - XMin=3, XMax=200, BinWidth=0.1) + run_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1,\ + NumEvents=100000,XUnit='Energy', XMin=3, XMax=200, BinWidth=0.1) LoadInstrument(run_monitors,InstrumentName='MARI') ConvertUnits(InputWorkspace='run_monitors', OutputWorkspace='run_monitors', Target='TOF') run_monitors = mtd['run_monitors'] tof = run_monitors.dataX(3) tMin = tof[0] tMax = tof[-1] - run = CreateSampleWorkspace( Function='Multiple Peaks',WorkspaceType='Event',NumBanks=8, BankPixelWidth=1, NumEvents=100000, - XUnit='TOF',xMin=tMin,xMax=tMax) + run = CreateSampleWorkspace( Function='Multiple Peaks',WorkspaceType='Event',NumBanks=8, BankPixelWidth=1,\ + NumEvents=100000, XUnit='TOF',xMin=tMin,xMax=tMax) LoadInstrument(run,InstrumentName='MARI') # do second @@ -383,16 +375,16 @@ class DirectEnergyConversionTest(unittest.TestCase): def test_multirep_abs_units_mode(self): # create test workspace - run_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100000, XUnit='Energy', - XMin=3, XMax=200, BinWidth=0.1) + run_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1,\ + NumEvents=100000, XUnit='Energy', XMin=3, XMax=200, BinWidth=0.1) LoadInstrument(run_monitors,InstrumentName='MARI') ConvertUnits(InputWorkspace='run_monitors', OutputWorkspace='run_monitors', Target='TOF') run_monitors = mtd['run_monitors'] tof = run_monitors.dataX(3) tMin = tof[0] tMax = tof[-1] - run = CreateSampleWorkspace( Function='Multiple Peaks',WorkspaceType='Event',NumBanks=8, BankPixelWidth=1, NumEvents=100000, - XUnit='TOF',xMin=tMin,xMax=tMax) + run = CreateSampleWorkspace( Function='Multiple Peaks',WorkspaceType='Event',NumBanks=8, BankPixelWidth=1,\ + NumEvents=100000, XUnit='TOF',xMin=tMin,xMax=tMax) LoadInstrument(run,InstrumentName='MARI') # build "monovanadium" @@ -408,7 +400,7 @@ class DirectEnergyConversionTest(unittest.TestCase): # Run multirep tReducer = DirectEnergyConversion(run.getInstrument()) - tReducer.prop_man.run_diagnostics=False # temporary + tReducer.prop_man.run_diagnostics=True tReducer.hard_mask_file=None tReducer.map_file=None tReducer.prop_man.background_range=[0.99*tMax,tMax] @@ -416,7 +408,6 @@ class DirectEnergyConversionTest(unittest.TestCase): tReducer.save_format=None tReducer.prop_man.normalise_method='monitor-1' tReducer.norm_mon_integration_range=[tMin,tMax] - #tReducer.prop_man. result = tReducer.convert_to_energy(wb_ws,run,[67.,122.],[-2,0.02,0.8],None,mono) @@ -448,5 +439,4 @@ class DirectEnergyConversionTest(unittest.TestCase): if __name__=="__main__": - unittest.main() - + unittest.main() diff --git a/Code/Mantid/scripts/test/DirectPropertyManagerTest.py b/Code/Mantid/scripts/test/DirectPropertyManagerTest.py index 2ef643c166d4bd0de71755c9720ce9b626277721..72439cf273e5d93568560af10faf82a0eef43fc0 100644 --- a/Code/Mantid/scripts/test/DirectPropertyManagerTest.py +++ b/Code/Mantid/scripts/test/DirectPropertyManagerTest.py @@ -1,5 +1,5 @@ import os -os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release;"+os.environ["PATH"] +#os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release;"+os.environ["PATH"] from mantid.simpleapi import * from mantid import api import unittest @@ -32,7 +32,7 @@ class DirectPropertyManagerTest(unittest.TestCase): idf_file=api.ExperimentInfo.getInstrumentFilename(InstrumentName) tmp_ws_name = '__empty_' + InstrumentName if not mtd.doesExist(tmp_ws_name): - LoadEmptyInstrument(Filename=idf_file,OutputWorkspace=tmp_ws_name) + LoadEmptyInstrument(Filename=idf_file,OutputWorkspace=tmp_ws_name) return mtd[tmp_ws_name].getInstrument() @@ -359,7 +359,7 @@ class DirectPropertyManagerTest(unittest.TestCase): propman.background_test_range = [1000,2000] bkg_test_range = propman.background_test_range - self.assertEqual(bkg_test_range,[1000,2000]) + self.assertEqual(bkg_test_range,(1000.,2000.)) def test_check_monovan_changed(self): propman = self.prop_man @@ -632,21 +632,23 @@ class DirectPropertyManagerTest(unittest.TestCase): ic+=1 self.assertEqual(ic,3) - #def test_incident_energy_custom_enum(self): - ###### Custom enum does not work - # propman = self.prop_man - # en_source = [20,40,80] - # propman.incident_energy=en_source - # propman.energy_bins=[-2,0.1,0.8] - # self.assertTrue(PropertyManager.incident_energy.multirep_mode()) - - # ic=0 - # for ind,en in enumerate(PropertyManager.incident_energy): - # ic+=1 - # self.assertAlmostEqual(en,en_source[ind]) - # en_internal = PropertyManager.incident_energy.get_current() - # self.assertAlmostEqual(en_internal,en_source[ind]) - # self.assertEqual(ind,ic-1) + def test_incident_energy_custom_enum(self): + ##### Custom enum works in a peculiar way + propman = self.prop_man + en_source = [20,40,80] + propman.incident_energy=en_source + propman.energy_bins=[-2,0.1,0.8] + self.assertTrue(PropertyManager.incident_energy.multirep_mode()) + + ic=0 + for ind,en in enumerate(PropertyManager.incident_energy): + ic+=1 + # propagate current energy value to incident energy class + PropertyManager.incident_energy.set_current(en,ind) + self.assertAlmostEqual(en,en_source[ind]) + en_internal = PropertyManager.incident_energy.get_current() + self.assertAlmostEqual(en_internal,en_source[ind]) + self.assertEqual(ind,ic-1) def test_ignore_complex_defailts_changes_fom_instrument(self) : ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=4, NumEvents=10) @@ -693,55 +695,55 @@ class DirectPropertyManagerTest(unittest.TestCase): def test_monovan_integration_range(self): - propman = self.prop_man + propman = self.prop_man - propman.incident_energy = 10 - propman.monovan_lo_frac = -0.6 - propman.monovan_hi_frac = 0.7 + propman.incident_energy = 10 + propman.monovan_lo_frac = -0.6 + propman.monovan_hi_frac = 0.7 - range = propman.abs_units_van_range - self.assertAlmostEqual(range[0],-6.) - self.assertAlmostEqual(range[1], 7.) + range = propman.abs_units_van_range + self.assertAlmostEqual(range[0],-6.) + self.assertAlmostEqual(range[1], 7.) - range = propman.monovan_integr_range - self.assertAlmostEqual(range[0],-6.) - self.assertAlmostEqual(range[1], 7.) + range = propman.monovan_integr_range + self.assertAlmostEqual(range[0],-6.) + self.assertAlmostEqual(range[1], 7.) - propman.monovan_lo_value = -10 - propman.monovan_hi_value = 10 + propman.monovan_lo_value = -10 + propman.monovan_hi_value = 10 - range = propman.abs_units_van_range - self.assertAlmostEqual(range[0],-6.) - self.assertAlmostEqual(range[1], 7.) + range = propman.abs_units_van_range + self.assertAlmostEqual(range[0],-6.) + self.assertAlmostEqual(range[1], 7.) - propman.abs_units_van_range=[-40,40] - self.assertAlmostEqual(propman.monovan_lo_value,-40) - self.assertAlmostEqual(propman.monovan_hi_value,40) + propman.abs_units_van_range=[-40,40] + self.assertAlmostEqual(propman.monovan_lo_value,-40) + self.assertAlmostEqual(propman.monovan_hi_value,40) - range = propman.monovan_integr_range - self.assertAlmostEqual(range[0],-40) - self.assertAlmostEqual(range[1], 40) + range = propman.monovan_integr_range + self.assertAlmostEqual(range[0],-40) + self.assertAlmostEqual(range[1], 40) - propman.abs_units_van_range=None + propman.abs_units_van_range=None - range = propman.monovan_integr_range - self.assertAlmostEqual(range[0],-6.) - self.assertAlmostEqual(range[1], 7.) - # - propman.monovan_lo_frac = -0.7 - range = propman.monovan_integr_range - self.assertAlmostEqual(range[0],-7.) + range = propman.monovan_integr_range + self.assertAlmostEqual(range[0],-6.) + self.assertAlmostEqual(range[1], 7.) + # + propman.monovan_lo_frac = -0.7 + range = propman.monovan_integr_range + self.assertAlmostEqual(range[0],-7.) def test_save_filename(self): - propman = self.prop_man + propman = self.prop_man - propman.incident_energy = 10 - propman.sample_run = 0 - propman.monovan_run = None + propman.incident_energy = 10 + propman.sample_run = 0 + propman.monovan_run = None - name = propman.save_file_name - self.assertEqual(name,'MAR00000Ei10d00meV') + name = propman.save_file_name + self.assertEqual(name,'MAR00000Ei10d00meV') def test_log_to_Mantid(self): propman = self.prop_man @@ -814,7 +816,18 @@ class DirectPropertyManagerTest(unittest.TestCase): self.assertTrue(propman1.run_diagnostics) - + def test_sum_runs(self): + propman = self.prop_man + propman.sum_runs = True + self.assertTrue(propman.sum_runs) + propman.sum_runs = False + self.assertFalse(propman.sum_runs) + + propman.sum_runs = 10 #TODO should we define number of runs to sum? + self.assertTrue(propman.sum_runs) + propman.sum_runs = 0 + self.assertFalse(propman.sum_runs) + #def test_do_white(self) : # tReducer = self.reducer # monovan = 1000 @@ -824,7 +837,6 @@ class DirectPropertyManagerTest(unittest.TestCase): - def test_monitors_list(self): propman = self.prop_man mons = propman.get_used_monitors_list() @@ -872,6 +884,24 @@ class DirectPropertyManagerTest(unittest.TestCase): self.assertAlmostEqual(range[0],9.5) self.assertAlmostEqual(range[1],10.5) +# Test multirep mode + propman.incident_energy = [10,20,30] + range = propman.mon2_norm_energy_range + self.assertAlmostEqual(range[0],9.5) + self.assertAlmostEqual(range[1],10.5) + + PropertyManager.incident_energy.next() + range = propman.mon2_norm_energy_range + self.assertAlmostEqual(range[0],2*9.5) + self.assertAlmostEqual(range[1],2*10.5) + + PropertyManager.incident_energy.next() + range = propman.mon2_norm_energy_range + self.assertAlmostEqual(range[0],3*9.5) + self.assertAlmostEqual(range[1],3*10.5) + + + def test_multirep_tof_specta_list(self): propman = self.prop_man @@ -913,6 +943,93 @@ class DirectPropertyManagerTest(unittest.TestCase): PropertyManager.mono_correction_factor.set_cash_mono_run_number(11060) self.assertTrue(PropertyManager.mono_correction_factor.get_val_from_cash(propman) is None) + def test_mono_file_properties(self): + propman = self.prop_man + propman.wb_run = 11001 + sw = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=4, NumEvents=10) + propman.monovan_run = sw + propman.mask_run = CloneWorkspace(sw,OutputWorkspace='mask_clone') + propman.map_file = None + propman.hard_mask_file='testmasking.xml' + propman.det_cal_file=11001 + propman.monovan_mapfile = None + + + file_prop = propman._get_properties_with_files() + + self.assertEqual(len(file_prop),3) + self.assertTrue('wb_run' in file_prop) + self.assertFalse('monovan_run' in file_prop) + self.assertFalse('mask_run' in file_prop) + self.assertFalse('wb_for_monovan_run' in file_prop) + + self.assertTrue('hard_mask_file' in file_prop) + self.assertTrue('det_cal_file' in file_prop) + + ok,fail_list = propman._check_file_properties() + self.assertTrue(ok) + + api.AnalysisDataService.clear() + + propman.monovan_run = 11002 + propman.mask_run = None + propman.wb_for_monovan_run=11001 + propman.map_file = 'some_missing_map' + + ok,fail_list = propman._check_file_properties() + self.assertFalse(ok) + self.assertEqual(len(fail_list),2) + self.assertTrue('monovan_run' in fail_list) + self.assertTrue('map_file' in fail_list) + + def test_find_files2sum(self): + propman = self.prop_man + propman.sample_run = [11001,11111] + + propman.sum_runs =False + ok,not_found,found = propman.find_files_to_sum() + self.assertTrue(ok) + self.assertEqual(len(not_found),0) + self.assertEqual(len(found),0) + + propman.sum_runs =True + ok,not_found,found = propman.find_files_to_sum() + self.assertFalse(ok) + self.assertEqual(len(not_found),1) + self.assertEqual(len(found),1) + self.assertEqual(not_found[0],11111) + self.assertEqual(found[0],11001) + + + ok,err_list=propman._check_file_properties() + self.assertFalse(ok) + self.assertEqual(len(err_list),2) + self.assertTrue('missing_runs_toSum' in err_list) + self.assertEqual(err_list['missing_runs_toSum'],'[11111]') + + def test_custom_print(self): + + propman = self.prop_man + propman.sample_run = 1000 + propman.incident_energy = 20. + + def custom_print(propman,PropertyManager): + + ei = propman.incident_energy + run_n = PropertyManager.sample_run.run_number() + name = "RUN{0}atEi{1:<4.1f}meV_One2One".format(run_n,ei) + return name + + PropertyManager.save_file_name.set_custom_print(custom_print) + + + self.assertEqual(propman.save_file_name,'RUN1000atEi20.0meV_One2One') + + propman.sample_run = 2000 + self.assertEqual(propman.save_file_name,'RUN2000atEi20.0meV_One2One') + # clean up + PropertyManager.save_file_name.set_custom_print(None) + if __name__=="__main__": unittest.main() #tester = DirectPropertyManagerTest('test_set_energy_bins_and_ei') diff --git a/Code/Mantid/scripts/test/MariReduction.py b/Code/Mantid/scripts/test/MariReduction.py index 44a63b6fa310ac8be634ccbea87aada934c5a852..69b940459d6b4f31212e2fb358fb051e4a9bd711 100644 --- a/Code/Mantid/scripts/test/MariReduction.py +++ b/Code/Mantid/scripts/test/MariReduction.py @@ -1,4 +1,7 @@ """ Sample MARI reduction scrip used in testing ReductionWrapper """ +import os +#os.environ["PATH"] =\ +#r"c:/Mantid/Code/builds/br_10881/bin/Release;"+os.environ["PATH"] from Direct.ReductionWrapper import * try: @@ -13,47 +16,62 @@ class ReduceMARI(ReductionWrapper): #-------------------------------------------------------------------------------------------------# @MainProperties def def_main_properties(self): - """ Define main properties used in reduction """ - prop = {} - prop['sample_run'] = 11001 - prop['wb_run'] = 11060 - prop['incident_energy'] = 12 - prop['energy_bins'] = [-11,0.05,11] - - # Absolute units reduction properties. - prop['monovan_run'] = 11015 - prop['sample_mass'] = 10 - prop['sample_rmm'] = 435.96 - return prop + + """ Define main properties used in reduction """ + prop = {} + prop['sample_run'] = 11001 + prop['wb_run'] = 11060 + prop['incident_energy'] = 12 + prop['energy_bins'] = [-11,0.05,11] + + # Absolute units reduction properties. + prop['monovan_run'] = 11015 + prop['sample_mass'] = 10 + prop['sample_rmm'] = 435.96 + return prop #-------------------------------------------------------------------------------------------------# @AdvancedProperties def def_advanced_properties(self): - """ separation between simple and advanced properties depends - on scientist, experiment and user. - main properties override advanced properties. - """ - prop = {} - prop['map_file'] = "mari_res.map" - prop['monovan_mapfile'] = "mari_res.map" - prop['hard_mask_file'] = "mar11015.msk" - prop['det_cal_file'] = "11060" - prop['save_format'] = '' - return prop + """ separation between simple and advanced properties depends + on scientist, experiment and user. + main properties override advanced properties. + """ + prop = {} + prop['map_file'] = "mari_res.map" + prop['monovan_mapfile'] = "mari_res.map" + prop['hard_mask_file'] = "mar11015.msk" + prop['det_cal_file'] = "11060" + prop['save_format'] = '' + return prop # #-------------------------------------------------------------------------------------------------# @iliad def reduce(self,input_file=None,output_directory=None): - """ Method executes reduction over single file + """ Method executes reduction over single file + Overload only if custom reduction is needed + """ + ws = ReductionWrapper.reduce(self,input_file,output_directory) + #SaveNexus(ws,Filename = 'MARNewReduction.nxs') + return ws +#------------------------------------------------------------------------------------------------ # + def validate_result(self,build_validation=False): + """ Change this method to verify different results """ - Overload only if custom reduction is needed - """ - ws = ReductionWrapper.reduce(input_file,output_directory) - #SaveNexus(ws,Filename = 'MARNewReduction.nxs') - return ws + # Two commented code rows below define location of the validation file in this script folder + # (which is incorrect for Mantid development, as the files are on the data search path or + # mantid distribution, as the files are not there) + #run_dir = os.path.dirname(os.path.realpath(__file__)) + #validation_file = os.path.join(run_dir,"MARIReduction.nxs") + + # build_validation -- if true, build and overwrite new workspace rather then validating the old one + # if file is missing, the validation tries to build it + rez,message = ReductionWrapper.build_or_validate_result(self,11001,"MARIReduction.nxs", + build_validation,1.e-3) + return rez,message def __init__(self,web_var=None): - """ sets properties defaults for the instrument with Name""" - ReductionWrapper.__init__(self,'MAR',web_var) + """ sets properties defaults for the instrument with Name""" + ReductionWrapper.__init__(self,'MAR',web_var) #-------------------------------------------------------------------------------------------------# #-------------------------------------------------------------------------------------------------# #-------------------------------------------------------------------------------------------------# @@ -79,28 +97,30 @@ if __name__ == "__main__": ##### Here one sets up folders where to find input data and where to save results ##### # It can be done here or from Mantid GUI # Folder where map files are located: - map_mask_dir = 'd:/Data/MantidSystemTests/Data' + map_mask_dir = 'd:/Data/MantidSystemTests/Data' # folder where input data can be found - data_dir = 'd:/Data/Mantid_Testing/14_11_27' - # auxiliary folder with results - ref_data_dir = 'd:/Data/MantidSystemTests/SystemTests/AnalysisTests/ReferenceResults' - # Set input path to - config.setDataSearchDirs('{0};{1};{2}'.format(data_dir,map_mask_dir,ref_data_dir)) - # use appendDataSearch directory to add to existing data search path - #config.appendDataSearchDir('d:/Data/Mantid_GIT/Test/AutoTestData') - # folder to save resulting spe/nxspe files. - config['defaultsave.directory'] = data_dir + data_dir = 'd:/Data/Mantid_Testing/14_11_27' + # auxiliary folder with results + ref_data_dir = 'd:/Data/MantidSystemTests/SystemTests/AnalysisTests/ReferenceResults' + # Set input path to + config.setDataSearchDirs('{0};{1};{2}'.format(data_dir,map_mask_dir,ref_data_dir)) + # use appendDataSearch directory to add to existing data search path + #config.appendDataSearchDir('d:/Data/Mantid_GIT/Test/AutoTestData') + # folder to save resulting spe/nxspe files. + config['defaultsave.directory'] = data_dir ###### Initialize reduction class above and set up reduction properties. Note no parameters ###### - rd = ReduceMARI() - # set up advanced and main properties - rd.def_advanced_properties() - rd.def_main_properties() - - # uncomment rows below to save web variables to use in web services. - #run_dir = os.path.dirname(os.path.realpath(__file__)) - #file = os.path.join(run_dir,'reduce_vars.py') - #rd.save_web_variables(file) + rd = ReduceMARI() + # set up advanced and main properties + rd.def_advanced_properties() + rd.def_main_properties() - rd.reduce() + # uncomment rows below to save web variables to use in web services. + #run_dir = os.path.dirname(os.path.realpath(__file__)) + #file = os.path.join(run_dir,'reduce_vars.py') + #rd.save_web_variables(file) + # Web-like reduction over sequence of files + #rd.reduce() +###### Run reduction on all files provided as parameters ###### + red_ws = rd.run_reduction() diff --git a/Code/Mantid/scripts/test/ReductionWrapperTest.py b/Code/Mantid/scripts/test/ReductionWrapperTest.py index cda0accc84f16827c61786d8a1ff83f2861efd09..83f558655efabda3fe01cec3898df7c0e03a9841 100644 --- a/Code/Mantid/scripts/test/ReductionWrapperTest.py +++ b/Code/Mantid/scripts/test/ReductionWrapperTest.py @@ -2,7 +2,7 @@ import os,sys #os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release;"+os.environ["PATH"] from mantid.simpleapi import * -from mantid import api +from mantid import api,config from Direct.ReductionWrapper import ReductionWrapper import MariReduction as mr @@ -78,6 +78,56 @@ class ReductionWrapperTest(unittest.TestCase): if os.path.isfile(fcomp): os.remove(fcomp) + def test_validate_settings(self): + dsp = config.getDataSearchDirs() + # clear all not to find any files + config.setDataSearchDirs('') + + red = mr.ReduceMARI() + ok,level,errors = red.validate_settings() + + self.assertFalse(ok) + self.assertEqual(level,2) + self.assertEqual(len(errors),7) + + + + + # this run should be in data search directory for basic Mantid + red.reducer.wb_run = 11001 + red.reducer.det_cal_file = '11001' + red.reducer.monovan_run = None + red.reducer.hard_mask_file = None + red.reducer.map_file = None + red.reducer.save_format = 'nxspe' + + path = [] + for item in dsp: + path.append(item) + config.setDataSearchDirs(path) + + + # hack -- let's pretend we are running from webservices + # but web var are empty (not to overwrite values above) + red._run_from_web = True + red._wvs.standard_vars={} + red._wvs.advanced_vars={} + ok,level,errors = red.validate_settings() + + self.assertTrue(ok) + self.assertEqual(level,0) + self.assertEqual(len(errors),0) + + # this is how we set it up from web + red._wvs.advanced_vars={'save_format':''} + ok,level,errors = red.validate_settings() + + self.assertFalse(ok) + self.assertEqual(level,1) + self.assertEqual(len(errors),1) + + + if __name__=="__main__": unittest.main() diff --git a/Code/Mantid/scripts/test/RunDescriptorTest.py b/Code/Mantid/scripts/test/RunDescriptorTest.py index 5ab61fe01be7586647d09adb150d4b183597657e..be90ba7db068b85559b77807fdd2fe3f3f6ec353 100644 --- a/Code/Mantid/scripts/test/RunDescriptorTest.py +++ b/Code/Mantid/scripts/test/RunDescriptorTest.py @@ -1,5 +1,5 @@ import os,sys,inspect -#os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release"+os.environ["PATH"] +#os.environ["PATH"] = r"c:/Mantid/Code/builds/br_master/bin/Release;"+os.environ["PATH"] from mantid.simpleapi import * from mantid import api import unittest @@ -22,7 +22,7 @@ class RunDescriptorTest(unittest.TestCase): if self.prop_man == None or type(self.prop_man) != type(PropertyManager): self.prop_man = PropertyManager("MAR") def tearDown(self): - pass + api.AnalysisDataService.clear() @staticmethod def getInstrument(InstrumentName='MAR'): @@ -31,7 +31,7 @@ class RunDescriptorTest(unittest.TestCase): idf_file=api.ExperimentInfo.getInstrumentFilename(InstrumentName) tmp_ws_name = '__empty_' + InstrumentName if not mtd.doesExist(tmp_ws_name): - LoadEmptyInstrument(Filename=idf_file,OutputWorkspace=tmp_ws_name) + LoadEmptyInstrument(Filename=idf_file,OutputWorkspace=tmp_ws_name) return mtd[tmp_ws_name].getInstrument() @@ -53,21 +53,35 @@ class RunDescriptorTest(unittest.TestCase): self.assertEqual(rez,'Success!') + def test_descr_dependend(self): propman = self.prop_man propman.wb_run = 100 + self.assertTrue(PropertyManager.wb_run.has_own_value()) self.assertEqual(propman.wb_run,100) self.assertEqual(propman.wb_for_monovan_run,100) + self.assertFalse(PropertyManager.wb_for_monovan_run.has_own_value()) + self.assertTrue(PropertyManager.wb_run.has_own_value()) propman.wb_for_monovan_run = 200 self.assertEqual(propman.wb_for_monovan_run,200) self.assertEqual(propman.wb_run,100) + self.assertTrue(PropertyManager.wb_run.has_own_value()) + self.assertTrue(PropertyManager.wb_for_monovan_run.has_own_value()) + + propman.wb_for_monovan_run = None + self.assertFalse(PropertyManager.wb_for_monovan_run.has_own_value()) + self.assertEqual(propman.wb_for_monovan_run,100) + self.assertEqual(propman.wb_run,100) + + def test_find_file(self): propman = self.prop_man propman.sample_run = 11001 - file=PropertyManager.sample_run.find_file() + ok,file=PropertyManager.sample_run.find_file() + self.assertTrue(ok) self.assertTrue(len(file)>0) ext = PropertyManager.sample_run.get_file_ext() @@ -95,10 +109,10 @@ class RunDescriptorTest(unittest.TestCase): propman.sample_run = 101111 PropertyManager.sample_run.set_file_ext('nxs') - file=PropertyManager.sample_run.find_file() + ok,file=PropertyManager.sample_run.find_file() self.assertEqual(testFile1,os.path.normpath(file)) PropertyManager.sample_run.set_file_ext('.raw') - file=PropertyManager.sample_run.find_file() + ok,file=PropertyManager.sample_run.find_file() self.assertEqual(testFile2,os.path.normpath(file)) os.remove(testFile1) @@ -109,12 +123,12 @@ class RunDescriptorTest(unittest.TestCase): # MARI run with number 11001 and extension raw must among unit test files propman.sample_run = 11001 - PropertyManager.sample_run.set_file_ext('raw') + PropertyManager.sample_run.set_file_ext('nxs') ws = PropertyManager.sample_run.get_workspace() + self.assertEqual(PropertyManager.sample_run.get_file_ext(),'.raw') self.assertTrue(isinstance(ws, api.Workspace)) - self.assertEqual(ws.name(), PropertyManager.sample_run.get_ws_name()) mon_ws = PropertyManager.sample_run.get_monitors_ws() self.assertTrue(isinstance(mon_ws, api.Workspace)) @@ -140,12 +154,12 @@ class RunDescriptorTest(unittest.TestCase): propman = self.prop_man propman.sample_run = run_ws - self.assertEqual(PropertyManager.sample_run.get_ws_name(),'SR_run_ws') ws = PropertyManager.sample_run.get_workspace() self.assertEqual(ws.name(),'SR_run_ws') propman.sample_run = ws - self.assertEqual(PropertyManager.sample_run.get_ws_name(),'SR_run_ws') + ws = PropertyManager.sample_run.get_workspace() + self.assertEqual(ws.name(),'SR_run_ws') self.assertTrue('SR_run_ws' in mtd) propman.sample_run = 11001 @@ -154,12 +168,11 @@ class RunDescriptorTest(unittest.TestCase): propman.load_monitors_with_workspace = False ws = PropertyManager.sample_run.get_workspace() ws_name = ws.name() - self.assertEqual(PropertyManager.sample_run.get_ws_name(),ws_name) + self.assertEqual('SR_MAR011001',ws_name) self.assertTrue(ws_name in mtd) self.assertTrue(ws_name+'_monitors' in mtd) propman.sample_run = ws - self.assertEqual(PropertyManager.sample_run.get_ws_name(),ws_name) self.assertTrue(ws_name in mtd) ws1 = PropertyManager.sample_run.get_workspace() @@ -174,72 +187,64 @@ class RunDescriptorTest(unittest.TestCase): propman.sample_run = ws1 self.assertEqual(ws1.name(),PropertyManager.sample_run._ws_name) - ws_name = PropertyManager.sample_run.get_ws_name() + ws = PropertyManager.sample_run.get_workspace() + ws_name = ws.name() # if no workspace is available, attempt to get workspace name fails DeleteWorkspace(ws_name) - self.assertRaises(RuntimeError,PropertyManager.sample_run.get_ws_name) propman.sample_run = None self.assertFalse(ws_name+'_monitors' in mtd) - # name of empty property workspace - self.assertEqual(PropertyManager.sample_run.get_ws_name(),'SR_') + def test_assign_fname(self): + propman = self.prop_man + propman.sample_run = 'MAR11001.RAW' + + self.assertEqual(PropertyManager.sample_run.run_number(),11001) + self.assertEqual(PropertyManager.sample_run._fext,'.RAW') - def test_sum_runs(self): + def test_chop_ws_part(self): propman = self.prop_man - propman.sample_run = [11001,11001] - ws = PropertyManager.sample_run.get_workspace() - test_val1 = ws.dataY(3)[0] - test_val2 = ws.dataY(6)[100] - test_val3 = ws.dataY(50)[200] - self.assertEqual(ws.name(),'SR_MAR011001') - self.assertEqual(ws.getNEvents(),2455286) + ws=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100, XUnit='TOF', + XMin=2000, XMax=20000, BinWidth=1) - #propman.sample_run = [11001,11001] - propman.sum_runs = True - ws = PropertyManager.sample_run.get_workspace() - self.assertEqual(ws.name(),'SR_MAR011001SumOf2') - ws_name = PropertyManager.sample_run.get_ws_name() - self.assertEqual(ws.name(),ws_name) + ws_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100, XUnit='TOF', + XMin=2000, XMax=20000, BinWidth=1) - self.assertEqual(2*test_val1, ws.dataY(3)[0]) - self.assertEqual(2*test_val2, ws.dataY(6)[100]) - self.assertEqual(2*test_val3, ws.dataY(50)[200]) + propman.sample_run = ws + ws1 = PropertyManager.sample_run.chop_ws_part(None,(2000,1,5000),False,1,2) - propman.sample_run = "MAR11001.raw,11001.nxs,MAR11001.raw" - self.assertFalse('SR_MAR011001SumOf2' in mtd) - ws = PropertyManager.sample_run.get_workspace() - self.assertEqual(ws.name(),'SR_MAR011001SumOf3') - ws_name = PropertyManager.sample_run.get_ws_name() - self.assertEqual(ws.name(),ws_name) + rez=CheckWorkspacesMatch('SR_ws',ws1) + self.assertEqual(rez,'Success!') - self.assertEqual(3*test_val1, ws.dataY(3)[0]) - self.assertEqual(3*test_val2, ws.dataY(6)[100]) - self.assertEqual(3*test_val3, ws.dataY(50)[200]) + wsc=PropertyManager.sample_run.get_workspace() + x =wsc.readX(0) + self.assertAlmostEqual(x[0],2000) + self.assertAlmostEqual(x[-1],5000) - propman.sum_runs = 2 - propman.sample_run = "/home/my_path/MAR11001.raw,c:/somewhere/11001.nxs,MAR11001.raw" - self.assertFalse('SR_MAR011001SumOf3' in mtd) - self.assertFalse('SR_MAR011001SumOf2' in mtd) - ws = PropertyManager.sample_run.get_workspace() - self.assertEqual(ws.name(),'SR_MAR011001SumOf2') - ws_name = PropertyManager.sample_run.get_ws_name() - self.assertEqual(ws.name(),ws_name) + self.assertEqual(wsc.name(),'SR_#1/2#ws') + self.assertTrue('SR_#1/2#ws_monitors' in mtd) - def test_assign_fname(self): - propman = self.prop_man - propman.sample_run = 'MAR11001.RAW' + ws1 = PropertyManager.sample_run.chop_ws_part(ws1,(10000,100,20000),True,2,2) + x =ws1.readX(0) + self.assertAlmostEqual(x[0],10000) + self.assertAlmostEqual(x[-1],20000) + + self.assertEqual(ws1.name(),'SR_#2/2#ws') + self.assertTrue('SR_#2/2#ws_monitors' in mtd) + - self.assertEqual(PropertyManager.sample_run.run_number(),11001) - self.assertEqual(PropertyManager.sample_run._run_ext,'.raw') def test_get_run_list(self): + """ verify the logic behind setting a run file as + a sample run when run list is defined + + """ propman = PropertyManager('MAR') propman.sample_run = [10204] @@ -247,27 +252,45 @@ class RunDescriptorTest(unittest.TestCase): runs = PropertyManager.sample_run.get_run_list() self.assertEqual(len(runs),1) self.assertEqual(runs[0],10204) + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),0) + self.assertTrue(sum_ws is None) + self.assertEqual(n_sum,0) + + + # the same run list changes nothing + propman.sample_run = [10204] + self.assertEqual(propman.sample_run,10204) + runs = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(runs),1) + self.assertEqual(runs[0],10204) + propman.sample_run = [11230,10382,10009] self.assertEqual(propman.sample_run,11230) + + propman.sum_runs = True + self.assertEqual(propman.sample_run,10009) propman.sample_run = [11231,10382,10010] self.assertEqual(propman.sample_run,10010) - sum_list = PropertyManager.sum_runs.get_run_list2sum() + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() self.assertEqual(len(sum_list),3) - runs = PropertyManager.sample_run.get_run_list() self.assertEqual(runs[0],sum_list[0]) + # Autoreduction workflow with summation. Runs appear + # one by one and summed together when next run appears propman.sample_run = 11231 - sum_list = PropertyManager.sum_runs.get_run_list2sum() + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),1) self.assertEqual(sum_list[0],11231) self.assertEqual(propman.sample_run,11231) propman.sample_run = 10382 - sum_list = PropertyManager.sum_runs.get_run_list2sum() + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() self.assertEqual(len(sum_list),2) self.assertEqual(sum_list[0],11231) self.assertEqual(sum_list[1],10382) @@ -276,7 +299,7 @@ class RunDescriptorTest(unittest.TestCase): self.assertEqual(len(runs),3) propman.sample_run = 10010 - sum_list = PropertyManager.sum_runs.get_run_list2sum() + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() self.assertEqual(len(sum_list),3) self.assertEqual(sum_list[0],11231) self.assertEqual(sum_list[1],10382) @@ -285,50 +308,168 @@ class RunDescriptorTest(unittest.TestCase): self.assertEqual(len(runs),3) self.assertTrue(propman.sum_runs) + # check asigning file with path + propman.sample_run = 'c:/data/MAR10382.nxs' + self.assertEqual(propman.sample_run,10382) + self.assertEqual(PropertyManager.sample_run._run_list._last_ind2sum,1) + self.assertEqual(PropertyManager.sample_run._run_list._file_path[1],'c:/data') + self.assertEqual(PropertyManager.sample_run._run_list._fext[1],'.nxs') - propman.sample_run = 10011 - sum_list = PropertyManager.sum_runs.get_run_list2sum() - self.assertEqual(len(sum_list),0) + + # check extend when summing + propman.sample_run = 10999 + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),4) + self.assertEqual(sum_list[0],11231) + self.assertEqual(sum_list[1],10382) + self.assertEqual(sum_list[2],10010) + self.assertEqual(sum_list[3],10999) + self.assertTrue(propman.sum_runs) runs = PropertyManager.sample_run.get_run_list() - self.assertEqual(len(runs),1) - self.assertEqual(runs[0],10011) - self.assertFalse(propman.sum_runs) + self.assertEqual(len(runs),4) + self.assertTrue(propman.sum_runs) - def test_chop_ws_part(self): + + propman.sum_runs=False + run_list = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(run_list),4) + self.assertEqual(propman.sample_run,11231) + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),0) + + # check clear list when not summing + propman.sample_run = 11999 + run_list = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(run_list),1) + + def test_sum_runs(self): propman = self.prop_man - ws=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100, XUnit='TOF', - XMin=2000, XMax=20000, BinWidth=1) + propman.sample_run = [11001,11001] + ws = PropertyManager.sample_run.get_workspace() + test_val1 = ws.dataY(3)[0] + test_val2 = ws.dataY(6)[100] + test_val3 = ws.dataY(50)[200] + self.assertEqual(ws.name(),'SR_MAR011001') + self.assertEqual(ws.getNEvents(),2455286) - ws_monitors=CreateSampleWorkspace(Function='Multiple Peaks', NumBanks=4, BankPixelWidth=1, NumEvents=100, XUnit='TOF', - XMin=2000, XMax=20000, BinWidth=1) + #propman.sample_run = [11001,11001] + propman.sum_runs = True + self.assertFalse('SR_MAR011001' in mtd) + ws = PropertyManager.sample_run.get_workspace() + self.assertEqual(ws.name(),'SR_MAR011001SumOf2') + + self.assertEqual(2*test_val1, ws.dataY(3)[0]) + self.assertEqual(2*test_val2, ws.dataY(6)[100]) + self.assertEqual(2*test_val3, ws.dataY(50)[200]) - propman.sample_run = ws - ws1 = PropertyManager.sample_run.chop_ws_part(None,(2000,1,5000),False,1,2) + propman.sample_run = "MAR11001.raw,11001.nxs,MAR11001.raw" + self.assertFalse('SR_MAR011001SumOf2' in mtd) + ws = PropertyManager.sample_run.get_workspace() + self.assertEqual(ws.name(),'SR_MAR011001SumOf3') + + self.assertEqual(3*test_val1, ws.dataY(3)[0]) + self.assertEqual(3*test_val2, ws.dataY(6)[100]) + self.assertEqual(3*test_val3, ws.dataY(50)[200]) - rez=CheckWorkspacesMatch('SR_ws',ws1) - self.assertEqual(rez,'Success!') + #TODO: Partial sum is not implemented. Should it? + #propman.sum_runs = 2 + #propman.sample_run = "/home/my_path/MAR11001.raw,c:/somewhere/11001.nxs,MAR11001.raw" + #self.assertFalse('SR_MAR011001SumOf3' in mtd) + #self.assertFalse('SR_MAR011001SumOf2' in mtd) + #ws = PropertyManager.sample_run.get_workspace() + #self.assertEqual(ws.name(),'SR_MAR011001SumOf2') - wsc=PropertyManager.sample_run.get_workspace() - x =wsc.readX(0) - self.assertAlmostEqual(x[0],2000) - self.assertAlmostEqual(x[-1],5000) - self.assertEqual(wsc.name(),'SR_#1/2#ws') - self.assertTrue('SR_#1/2#ws_monitors' in mtd) + propman.sample_run = 11111 + sum_list,sum_ws,n_sum = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),4) + runs = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(runs),4) + self.assertEqual(runs[3],11111) + self.assertTrue(propman.sum_runs) + self.assertTrue('SR_MAR011001SumOf3' in mtd) + propman.cashe_sum_ws = True # Not used at this stage but will be used at loading + PropertyManager.sample_run._run_list.set_cashed_sum_ws(mtd['SR_MAR011001SumOf3'],'SumWS_cashe') + self.assertTrue('SumWS_cashe' in mtd) + self.assertFalse('SR_MAR011001SumOf3' in mtd) - ws1 = PropertyManager.sample_run.chop_ws_part(ws1,(10000,100,20000),True,2,2) - x =ws1.readX(0) - self.assertAlmostEqual(x[0],10000) - self.assertAlmostEqual(x[-1],20000) + sum_list,sum_ws,n_summed = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sum_list),1) + self.assertEqual(n_summed,3) + self.assertEqual(sum_ws.name(),'SumWS_cashe') + self.assertEqual(sum_list[0],11111) - self.assertEqual(ws1.name(),'SR_#2/2#ws') - self.assertTrue('SR_#2/2#ws_monitors' in mtd) + # file 1 does not exist, so can not be found. Otherwise it should load it + self.assertRaises(IOError,PropertyManager.sample_run.get_workspace) - api.AnalysisDataService.clear() + # Clear all + propman.sum_runs=False + self.assertFalse('SR_MAR011001SumOf3' in mtd) + # disabling sum_runs clears sum cash + self.assertFalse('SumWS_cashe' in mtd) + runs = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(runs),4) + self.assertEqual(propman.sample_run,11001) + + propman.sample_run = 10111 + runs = PropertyManager.sample_run.get_run_list() + self.assertEqual(len(runs),1) + self.assertEqual(runs[0],10111) + self.assertEqual(propman.sample_run,10111) + sums,ws,n_sums = PropertyManager.sample_run.get_runs_to_sum() + self.assertEqual(len(sums),0) + self.assertTrue(ws is None) + self.assertEqual(n_sums,0) + + def test_find_runfiles(self): + propman = self.prop_man + propman.sample_run = [11001,11111] + + nf,found=PropertyManager.sample_run._run_list.find_run_files('MAR') + self.assertEqual(len(nf),1) + self.assertEqual(len(found),1) + self.assertEqual(nf[0],11111) + + def test_add_masks(self): + propman = self.prop_man + ws=CreateSampleWorkspace(Function='Multiple Peaks',WorkspaceType='Event', + NumBanks=4, BankPixelWidth=1, NumEvents=100, XUnit='TOF', + XMin=2000, XMax=20000, BinWidth=1) + + PropertyManager.sample_run.add_masked_ws(ws) + + masks,masked = PropertyManager.sample_run.get_masking() + self.assertEqual(masked,0) + self.assertTrue(isinstance(masks,api.MatrixWorkspace)) + ws_name = PropertyManager.sample_run._mask_ws_name + self.assertTrue(ws_name in mtd) + + propman.sample_run = None + self.assertFalse(ws_name in mtd) + + + def test_runDescriptorDependant(self): + propman = self.prop_man + self.assertTrue(PropertyManager.wb_run.has_own_value()) + propman.wb_for_monovan_run = None + self.assertFalse(PropertyManager.wb_for_monovan_run.has_own_value()) + propman.wb_run = 2000 + self.assertEqual(propman.wb_for_monovan_run,2000) + self.assertEqual(propman.wb_run,2000) + self.assertFalse(PropertyManager.wb_for_monovan_run.has_own_value()) + propman.wb_for_monovan_run = None + self.assertEqual(propman.wb_for_monovan_run,2000) + self.assertEqual(propman.wb_run,2000) + + + propman.wb_for_monovan_run = 3000 + self.assertTrue(PropertyManager.wb_for_monovan_run.has_own_value()) + self.assertEqual(propman.wb_run,2000) + self.assertEqual(propman.wb_for_monovan_run,3000) diff --git a/README.md b/README.md index 0057183c12e8e1488e89dde311a62ee5523ba938..65158b33336e0f0adfaad88210c2df0507571c0f 100644 --- a/README.md +++ b/README.md @@ -11,5 +11,3 @@ Useful links * Issue tracking: http://trac.mantidproject.org/mantid/ * Build server: http://builds.mantidproject.org * Developer site: http://developer.mantidproject.org - -[](https://bitdeli.com/free "Bitdeli Badge")