From 51fb8b5afc63c9f063a394efa203a9892599d50c Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 15 Sep 2023 13:59:16 +0100 Subject: [PATCH 001/165] Adjusted handling of temp directory --- gudpy/core/nexus_processing.py | 10 ++-------- gudpy/gui/widgets/core/main_window.py | 2 ++ 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/gudpy/core/nexus_processing.py b/gudpy/core/nexus_processing.py index 234a3547..e51977cc 100644 --- a/gudpy/core/nexus_processing.py +++ b/gudpy/core/nexus_processing.py @@ -252,7 +252,7 @@ def __init__(self, gudrunFile): self.sample = None self.useTempDataFileDir = False self.interpolate = False - self.tmp = tempfile.TemporaryDirectory() + self.tmp = None self.path = "modex.cfg" self.goodFrameThreshold = 0 @@ -324,13 +324,7 @@ def preprocess(self, useTempDataFileDir=False, headless=True): Should processing be headless? """ - # Cleanup temp directory. - for f in os.listdir(self.tmp.name): - fp = os.path.join(self.tmp.name, f) - if os.path.isfile(fp): - os.remove(fp) - elif os.path.isdir(fp): - shutil.rmtree(fp) + self.tmp = tempfile.TemporaryDirectory() self.useTempDataFileDir = useTempDataFileDir # List to hold tasks, in the case of headful preprocessing. diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index ab4946a6..36f84ebb 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1318,6 +1318,7 @@ def errorNexusPreprocess(self): self.mainWidget, "GudPy Error", self.error ) + self.gudrunFile.nexus_processing.tmp.cleanup() def progressNexusProcess(self): progress = self.progressIncrementDCS( @@ -1401,6 +1402,7 @@ def nexusProcessingFinished(self): gudrunFile=self.gudrunFile.nexus_processing.gudrunFile, keyMap=self.keyMap ) + self.gudrunFile.nexus_processing.tmp.cleanup() def iterateGudrun(self, dialog, name): if not self.checkFilesExist_(): From 5776d646691d8c5e45056d7e8cb3ae1a14ce75cd Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 15 Sep 2023 14:06:15 +0100 Subject: [PATCH 002/165] Removed shutil.rmtree --- gudpy/core/nexus_processing.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gudpy/core/nexus_processing.py b/gudpy/core/nexus_processing.py index e51977cc..8d9ccf64 100644 --- a/gudpy/core/nexus_processing.py +++ b/gudpy/core/nexus_processing.py @@ -386,8 +386,6 @@ def preprocess(self, useTempDataFileDir=False, headless=True): self.dataFileDir = os.path.join(self.tmp.name, "data") # If headless, copy all the data files into this new directory. if headless: - if os.path.exists(self.dataFileDir): - shutil.rmtree(self.dataFileDir) os.makedirs(self.dataFileDir) for dataFile in self.ref.normalisation.dataFiles.dataFiles: self.copyfile( @@ -438,10 +436,6 @@ def preprocess(self, useTempDataFileDir=False, headless=True): ) # Otherwise, append the copies as tasks. else: - if os.path.exists(os.path.join(self.dataFileDir)): - tasks.append( - (shutil.rmtree, [os.path.join(self.dataFileDir)]) - ) tasks.append( ( os.makedirs, From 7efb585ebf977a66ebfb258e042b403d705b6513 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 25 Sep 2023 11:38:15 +0100 Subject: [PATCH 003/165] Docstring update --- gudpy/core/gudrun_file.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index d7bfaf69..1b99b887 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1512,12 +1512,13 @@ def dcs(self, path='', headless=True, iterative=False): Parameters ---------- - overwrite : bool, optional - Overwrite the initial file? (default is False). path : str, optional Path to parse from (default is empty, which indicates self.path). - purge : bool, optional - Should detectors be purged? + headless : bool, optional + Is this being run through CL or GUI? + iterative : bool, optional + Is Gudrun being iterated? + Returns ------- subprocess.CompletedProcess From 8bd67379a18ab96d873a3ef5f954930831999715 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 25 Sep 2023 11:39:10 +0100 Subject: [PATCH 004/165] Does not delete/replce existing outputs --- gudpy/core/output_file_handler.py | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 30249efa..6f0215b7 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -52,12 +52,9 @@ def getRunFiles(self): def organiseSampleFiles(self, run, sampleRunFile, tree=""): dir = self.gudrunFile.instrument.GudrunInputFileDir if tree: - outputDir = os.path.join(dir, tree, run) + outputDir = self.uniquify(os.path.join(dir, tree, run)) else: - outputDir = os.path.join(dir, run) - if os.path.exists(outputDir): - shutil.rmtree(outputDir) - if not os.path.exists(outputDir): + outputDir = self.uniquify(os.path.join(dir, run)) os.makedirs(outputDir) os.makedirs(os.path.join(outputDir, "outputs")) os.makedirs(os.path.join(outputDir, "diagnostics")) @@ -81,7 +78,10 @@ def organiseSampleFiles(self, run, sampleRunFile, tree=""): ) def naiveOrganise(self): + """ Calls `organiseSampleFiles` on members of `runFiles`""" + for run, runFile in self.runFiles: + print(f"{run} {runFile}") self.organiseSampleFiles(run, runFile) def iterativeOrganise(self, head): @@ -93,3 +93,24 @@ def iterativeOrganise(self, head): shutil.rmtree(path) for run, runFile in self.runFiles: self.organiseSampleFiles(run, runFile, tree=head) + + def uniquify(self, path): + """ + Function to increment path if it already exists + + Parameters + ---------- + path : str + requested path + + Returns + ------- + str + avaliable path + """ + root, ext = os.path.splitext(path) + fileCount = 1 + while os.path.exists(path): + path = root + "_" + str(fileCount) + ext + fileCount += 1 + return path From 7ce29cc959a30f84903fcecc120d0415da1d4c85 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 10:24:59 +0100 Subject: [PATCH 005/165] Organised iterator files, fixed some bugs --- gudpy/core/iterators/__init__.py | 0 .../{ => iterators}/composition_iterator.py | 30 ++++++++++------ .../core/{ => iterators}/density_iterator.py | 7 ++-- gudpy/core/{ => iterators}/radius_iterator.py | 7 ++-- .../{ => iterators}/single_param_iterator.py | 25 +++++++------ .../{ => iterators}/thickness_iterator.py | 8 ++--- .../{ => iterators}/tweak_factor_iterator.py | 24 +++++-------- .../wavelength_subtraction_iterator.py | 35 ++++++++----------- 8 files changed, 65 insertions(+), 71 deletions(-) create mode 100644 gudpy/core/iterators/__init__.py rename gudpy/core/{ => iterators}/composition_iterator.py (94%) rename gudpy/core/{ => iterators}/density_iterator.py (87%) rename gudpy/core/{ => iterators}/radius_iterator.py (87%) rename gudpy/core/{ => iterators}/single_param_iterator.py (86%) rename gudpy/core/{ => iterators}/thickness_iterator.py (86%) rename gudpy/core/{ => iterators}/tweak_factor_iterator.py (80%) rename gudpy/core/{ => iterators}/wavelength_subtraction_iterator.py (88%) diff --git a/gudpy/core/iterators/__init__.py b/gudpy/core/iterators/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/gudpy/core/composition_iterator.py b/gudpy/core/iterators/composition_iterator.py similarity index 94% rename from gudpy/core/composition_iterator.py rename to gudpy/core/iterators/composition_iterator.py index 00954713..89eb27f2 100644 --- a/gudpy/core/composition_iterator.py +++ b/gudpy/core/iterators/composition_iterator.py @@ -17,14 +17,14 @@ def gss( if ( (abs(bounds[2] - bounds[0]) / min([abs(bounds[0]), abs(bounds[2])])) - < (rtol/100)**2 + < (rtol / 100)**2 ): if endIterFunc: endIterFunc(n) return (bounds[2] + bounds[1]) / 2 # Calculate a potential centre = c + 2 - GR * (upper-c) - d = bounds[1] + (2 - (1 + math.sqrt(5))/2)*(bounds[2]-bounds[1]) + d = bounds[1] + (2 - (1 + math.sqrt(5)) / 2) * (bounds[2] - bounds[1]) # If the new centre evaluates to less than the current fd1 = f(d, *args) @@ -43,7 +43,7 @@ def gss( if endIterFunc: endIterFunc(n) return gss( - f, bounds, n+1, maxN, rtol, + f, bounds, n + 1, maxN, rtol, args=args, startIterFunc=startIterFunc, endIterFunc=endIterFunc ) # Otherwise, swap and reverse. @@ -52,7 +52,7 @@ def gss( if endIterFunc: endIterFunc() return gss( - f, bounds, n+1, maxN, rtol, + f, bounds, n + 1, maxN, rtol, args=args, startIterFunc=startIterFunc, endIterFunc=endIterFunc ) @@ -103,6 +103,9 @@ class CompositionIterator(): gss(f, bounds, n, args=()) Performs n iterations using cost function f, args and bounds. """ + + name = "IterateByComposition" + def __init__(self, gudrunFile): self.gudrunFile = gudrunFile self.components = [] @@ -118,6 +121,7 @@ def __init__(self, gudrunFile): ratio : int, optional Ratio of component. """ + def setComponent(self, component, ratio=1): self.components = [component] self.ratio = ratio @@ -132,6 +136,7 @@ def setComponent(self, component, ratio=1): ratio : int, optional Ratio of component. """ + def setComponents(self, components, ratio=1): self.components = [c for c in components if c] self.ratio = ratio @@ -146,6 +151,7 @@ def setComponents(self, components, ratio=1): sampleBackground : SampleBackground Target Sample Background. """ + def processSingleComponent(self, x, sampleBackground): self.gudrunFile.sampleBackgrounds = [sampleBackground] @@ -165,9 +171,9 @@ def processSingleComponent(self, x, sampleBackground): time.sleep(1) gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + self.gudrunFile.instrument.dataFileType, + "gud" + ) gudFile = GudFile( os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, gudPath @@ -177,7 +183,7 @@ def processSingleComponent(self, x, sampleBackground): if gudFile.averageLevelMergedDCS == gudFile.expectedDCS: return 0 else: - return (gudFile.expectedDCS-gudFile.averageLevelMergedDCS)**2 + return (gudFile.expectedDCS - gudFile.averageLevelMergedDCS)**2 """ Cost function for processing two components. @@ -191,6 +197,7 @@ def processSingleComponent(self, x, sampleBackground): totalMolecules : float Sum of molecules of both components. """ + def processTwoComponents(self, x, sampleBackground, totalMolecules): self.gudrunFile.sampleBackgrounds = [sampleBackground] x = abs(x) @@ -212,9 +219,9 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): time.sleep(1) gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + self.gudrunFile.instrument.dataFileType, + "gud" + ) gudFile = GudFile( os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, gudPath @@ -244,6 +251,7 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): rtol : float Relative tolerance """ + def iterate(self, n=10, rtol=10.): if not self.components or not self.ratio: return None diff --git a/gudpy/core/density_iterator.py b/gudpy/core/iterators/density_iterator.py similarity index 87% rename from gudpy/core/density_iterator.py rename to gudpy/core/iterators/density_iterator.py index 3e9f2a38..4e37e745 100644 --- a/gudpy/core/density_iterator.py +++ b/gudpy/core/iterators/density_iterator.py @@ -1,4 +1,4 @@ -from core.single_param_iterator import SingleParamIterator +from core.iterators.single_param_iterator import SingleParamIterator class DensityIterator(SingleParamIterator): @@ -18,6 +18,8 @@ class DensityIterator(SingleParamIterator): organiseOutput Organises the output of the iteration. """ + name = "IterateByDensity" + def applyCoefficientToAttribute(self, object, coefficient): """ Multiplies a sample's density by a given coefficient. @@ -32,6 +34,3 @@ def applyCoefficientToAttribute(self, object, coefficient): """ # Apply the coefficient to the density. object.density *= coefficient - - def organiseOutput(self, n): - self.gudrunFile.iterativeOrganise(f"IterateByDensity_{n}") diff --git a/gudpy/core/radius_iterator.py b/gudpy/core/iterators/radius_iterator.py similarity index 87% rename from gudpy/core/radius_iterator.py rename to gudpy/core/iterators/radius_iterator.py index a7a972bf..9776537d 100644 --- a/gudpy/core/radius_iterator.py +++ b/gudpy/core/iterators/radius_iterator.py @@ -1,4 +1,4 @@ -from core.single_param_iterator import SingleParamIterator +from core.iterators.single_param_iterator import SingleParamIterator class RadiusIterator(SingleParamIterator): @@ -21,6 +21,8 @@ class RadiusIterator(SingleParamIterator): organiseOutput Organises the output of the iteration. """ + name = "IterateByRadius" + def applyCoefficientToAttribute(self, object, coefficient): if self.targetRadius == "inner": object.innerRadius *= coefficient @@ -29,6 +31,3 @@ def applyCoefficientToAttribute(self, object, coefficient): def setTargetRadius(self, targetRadius): self.targetRadius = targetRadius - - def organiseOutput(self, n): - self.gudrunFile.iterativeOrganise(f"IterateByRadius_{n}") diff --git a/gudpy/core/single_param_iterator.py b/gudpy/core/iterators/single_param_iterator.py similarity index 86% rename from gudpy/core/single_param_iterator.py rename to gudpy/core/iterators/single_param_iterator.py index 63da54a3..48300a37 100644 --- a/gudpy/core/single_param_iterator.py +++ b/gudpy/core/iterators/single_param_iterator.py @@ -29,6 +29,7 @@ class SingleParamIterator(): organiseOutput To be overriden by sub-classes. """ + def __init__(self, gudrunFile): """ Constructs all the necessary attributes for the @@ -55,12 +56,12 @@ def performIteration(self, _n): for sampleBackground in self.gudrunFile.sampleBackgrounds: for sample in [ s for s in sampleBackground.samples - if s.runThisSample + if s.runThisSample and len(s.dataFiles) ]: gudPath = sample.dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + self.gudrunFile.instrument.dataFileType, + "gud" + ) gudFile = GudFile( os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -89,17 +90,19 @@ def applyCoefficientToAttribute(self, object, coefficient): """ pass - def organiseOutput(self, n): + def organiseOutput(self, nTotal, nCurrent): """ - Stub method to be overriden by sub-classes. - This method should organise the output of the iteration. + This should organises the output of the iteration. Parameters ---------- - n : int - Iteration no. + nTotal : int + Total number of requested iterations + nCurrent : int + Current iteration """ - pass + self.gudrunFile.iterativeOrganise( + nTotal, nCurrent, self.name) def iterate(self, n): """ @@ -118,4 +121,4 @@ def iterate(self, n): self.gudrunFile.process() time.sleep(1) self.performIteration(i) - self.organiseOutput(i) + self.organiseOutput(n, i) diff --git a/gudpy/core/thickness_iterator.py b/gudpy/core/iterators/thickness_iterator.py similarity index 86% rename from gudpy/core/thickness_iterator.py rename to gudpy/core/iterators/thickness_iterator.py index 3bf5a09a..7a5b8550 100644 --- a/gudpy/core/thickness_iterator.py +++ b/gudpy/core/iterators/thickness_iterator.py @@ -1,4 +1,4 @@ -from core.single_param_iterator import SingleParamIterator +from core.iterators.single_param_iterator import SingleParamIterator class ThicknessIterator(SingleParamIterator): @@ -19,6 +19,9 @@ class ThicknessIterator(SingleParamIterator): organiseOutput Organises the output of the iteration. """ + + name = "IterateByThickness" + def applyCoefficientToAttribute(self, object, coefficient): # Determine a new total thickness. totalThickness = object.upstreamThickness + object.downstreamThickness @@ -26,6 +29,3 @@ def applyCoefficientToAttribute(self, object, coefficient): # Assign the new thicknesses. object.downstreamThickness = totalThickness / 2 object.upstreamThickness = totalThickness / 2 - - def organiseOutput(self, n): - self.gudrunFile.iterativeOrganise(f"IterateByThickness_{n}") diff --git a/gudpy/core/tweak_factor_iterator.py b/gudpy/core/iterators/tweak_factor_iterator.py similarity index 80% rename from gudpy/core/tweak_factor_iterator.py rename to gudpy/core/iterators/tweak_factor_iterator.py index d7d8a642..5aadca3f 100644 --- a/gudpy/core/tweak_factor_iterator.py +++ b/gudpy/core/iterators/tweak_factor_iterator.py @@ -2,9 +2,10 @@ import time from core.gud_file import GudFile +from core.iterators.single_param_iterator import SingleParamIterator -class TweakFactorIterator(): +class TweakFactorIterator(SingleParamIterator): """ Class to represent a Tweak Factor Iterator. This class is used for iteratively tweaking by the tweak factor. @@ -26,17 +27,8 @@ class TweakFactorIterator(): iterate(n) Perform n iterations of iterating by tweak factor. """ - def __init__(self, gudrunFile): - """ - Constructs all the necessary attributes for the - TweakFactorIterator object. - Parameters - ---------- - gudrunFile : GudrunFile - Input GudrunFile that we will be using for iterating. - """ - self.gudrunFile = gudrunFile + name = "IterateByTweakFactor" def performIteration(self, _n): """ @@ -52,12 +44,12 @@ def performIteration(self, _n): for sampleBackground in self.gudrunFile.sampleBackgrounds: for sample in [ s for s in sampleBackground.samples - if s.runThisSample + if s.runThisSample and len(s.dataFiles) ]: gudPath = sample.dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + self.gudrunFile.instrument.dataFileType, + "gud" + ) gudFile = GudFile( os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -90,4 +82,4 @@ def iterate(self, n): self.gudrunFile.process(iterative=True) time.sleep(1) self.performIteration(i) - self.gudrunFile.iterativeOrganise(f"IterateByTweakFactor_{i+1}") + self.organiseOutput(n, i) diff --git a/gudpy/core/wavelength_subtraction_iterator.py b/gudpy/core/iterators/wavelength_subtraction_iterator.py similarity index 88% rename from gudpy/core/wavelength_subtraction_iterator.py rename to gudpy/core/iterators/wavelength_subtraction_iterator.py index 8296ee19..d1e34509 100644 --- a/gudpy/core/wavelength_subtraction_iterator.py +++ b/gudpy/core/iterators/wavelength_subtraction_iterator.py @@ -119,14 +119,12 @@ def zeroTopHatWidths(self): width of top hat functions for FT to zero, for each sample that is being run. """ - # Enumerator for sample backgrounds - iterator = enumerate(self.gudrunFile.sampleBackgrounds) # Iterate through all of the samples, and set top hat widths to zero. - for i, sampleBackground in iterator: - for j, sample in enumerate(sampleBackground.samples): + for sampleBackground in self.gudrunFile.sampleBackgrounds: + for sample in sampleBackground.samples: if sample.runThisSample: - target = self.gudrunFile.sampleBackgrounds[i].samples[j] + target = sample target.topHatW = 0 def resetTopHatWidths(self): @@ -135,16 +133,14 @@ def resetTopHatWidths(self): width of top hat functions for their previous values, for each sample that is being run. """ - # Enumerator for sample backgrounds - iterator = enumerate(self.gudrunFile.sampleBackgrounds) # Iterate through all of the samples, and set top hat widths to # their previous values - for i, sampleBackground in iterator: - for j, sample in enumerate(sampleBackground.samples): - if sample.runThisSample: - target = self.gudrunFile.sampleBackgrounds[i].samples[j] - target.topHatW = self.topHatWidths[j] + for sampleBackground in self.gudrunFile.sampleBackgrounds: + for sample, topHatW in zip( + sampleBackground.samples, self.topHatWidths): + target = sample + target.topHatW = topHatW def collectTopHatWidths(self): """ @@ -169,16 +165,13 @@ def setSelfScatteringFiles(self, scale): # Dict to pick suffix based on scale suffix = {Scales.Q: "msubw01", Scales.WAVELENGTH: "mint01"}[scale] - # Enumerator for sample backgrounds - iterator = enumerate(self.gudrunFile.sampleBackgrounds) - # Iterate through all of the samples, and set the suffixes of # all of their data files to the suffix # relevant to the specified scale - for i, sampleBackground in iterator: - for j, sample in enumerate(sampleBackground.samples): - if sample.runThisSample: - target = self.gudrunFile.sampleBackgrounds[i].samples[j] + for sampleBackground in self.gudrunFile.sampleBackgrounds: + for sample in sampleBackground.samples: + if sample.runThisSample and len(sample.dataFiles): + target = sample filename = target.dataFiles[0] target.fileSelfScattering = ( str(Path(filename).stem) + '.' + suffix @@ -255,8 +248,8 @@ def iterate(self, n): self.wavelengthIteration(i) self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.iterativeOrganise(f"WavelengthIteration_{i+1}") + self.gudrunFile.iterativeOrganise(n, i, "WavelengthIteration") self.QIteration(i) self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.iterativeOrganise(f"QIteration_{i+1}") + self.gudrunFile.iterativeOrganise(n, i, "QIteration") From 763fa98f6be21caf50646017bc50911cfd9b473c Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 10:27:11 +0100 Subject: [PATCH 006/165] Modified import statements to align with new directory structure --- gudpy/core/run_batch_files.py | 8 ++++---- gudpy/gui/widgets/core/main_window.py | 14 +++++++------- gudpy/gui/widgets/core/worker.py | 2 +- .../widgets/dialogs/iterate_composition_dialog.py | 2 +- .../iterate_inelasticity_subtractions_dialog.py | 2 +- gudpy/gui/widgets/dialogs/iterate_radius_dialog.py | 2 +- .../widgets/dialogs/iterate_tweak_factor_dialog.py | 2 +- gudpy/test/test_gudpy_workflows.py | 10 +++++----- 8 files changed, 21 insertions(+), 21 deletions(-) diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index ef7ebe75..dccf283c 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -1,10 +1,10 @@ from copy import deepcopy import os from core.enums import IterationModes -from core.tweak_factor_iterator import TweakFactorIterator -from core.thickness_iterator import ThicknessIterator -from core.radius_iterator import RadiusIterator -from core.density_iterator import DensityIterator +from core.iterators.tweak_factor_iterator import TweakFactorIterator +from core.iterators.thickness_iterator import ThicknessIterator +from core.iterators.radius_iterator import RadiusIterator +from core.iterators.density_iterator import DensityIterator class BatchProcessor: diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index ab4946a6..9b212725 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -35,13 +35,13 @@ ) from PySide6.QtCharts import QChartView -from core.single_param_iterator import SingleParamIterator -from core.composition_iterator import CompositionIterator -from core.density_iterator import DensityIterator -from core.radius_iterator import RadiusIterator +from core.iterators.single_param_iterator import SingleParamIterator +from core.iterators.composition_iterator import CompositionIterator +from core.iterators.density_iterator import DensityIterator +from core.iterators.radius_iterator import RadiusIterator from core.sample import Sample from core.container import Container -from core.thickness_iterator import ThicknessIterator +from core.iterators.thickness_iterator import ThicknessIterator from gui.widgets.dialogs.export_dialog import ExportDialog from gui.widgets.dialogs.iterate_composition_dialog import ( CompositionIterationDialog @@ -110,8 +110,8 @@ from core.gudrun_file import GudrunFile from core.exception import ParserException from core import config -from core.tweak_factor_iterator import TweakFactorIterator -from core.wavelength_subtraction_iterator import ( +from core.iterators.tweak_factor_iterator import TweakFactorIterator +from core.iterators.wavelength_subtraction_iterator import ( WavelengthSubtractionIterator ) from core.run_containers_as_samples import RunContainersAsSamples diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index 56d1e0c4..7fcc36c6 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -4,7 +4,7 @@ from core.gud_file import GudFile from core.sample import Sample -from core.composition_iterator import gss +from core.iterators.composition_iterator import gss class CompositionWorker(QObject): diff --git a/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py b/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py index 16042411..e57216a3 100644 --- a/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py @@ -3,7 +3,7 @@ from PySide6.QtCore import Qt from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.composition_iterator import ( +from core.iterators.composition_iterator import ( CompositionIterator, calculateTotalMolecules ) diff --git a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py b/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py index 6d070f86..84306c78 100644 --- a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py @@ -1,5 +1,5 @@ from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.wavelength_subtraction_iterator import ( +from core.iterators.wavelength_subtraction_iterator import ( WavelengthSubtractionIterator ) diff --git a/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py b/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py index c4d8ed97..187583a3 100644 --- a/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py @@ -1,5 +1,5 @@ from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.radius_iterator import RadiusIterator +from core.iterators.radius_iterator import RadiusIterator from core.enums import Geometry from core import config diff --git a/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py b/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py index f4a2e557..0c6b6bdb 100644 --- a/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py @@ -1,5 +1,5 @@ from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.tweak_factor_iterator import TweakFactorIterator +from core.iterators.tweak_factor_iterator import TweakFactorIterator class TweakFactorIterationDialog(IterationDialog): diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 60f9a278..f1f05432 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -7,12 +7,12 @@ from core.composition import Composition, Component from core.gudrun_file import GudrunFile -from core.thickness_iterator import ThicknessIterator -from core.density_iterator import DensityIterator -from core.tweak_factor_iterator import TweakFactorIterator -from core.composition_iterator import CompositionIterator +from core.iterators.thickness_iterator import ThicknessIterator +from core.iterators.density_iterator import DensityIterator +from core.iterators.tweak_factor_iterator import TweakFactorIterator +from core.iterators.composition_iterator import CompositionIterator from core.gud_file import GudFile -from core.wavelength_subtraction_iterator import ( +from core.iterators.wavelength_subtraction_iterator import ( WavelengthSubtractionIterator ) From f6a7aed6d6cad1d446cd3a201cef5692daa0de27 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 10:28:06 +0100 Subject: [PATCH 007/165] Stored strings in variables --- gudpy/core/output_file_handler.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 6f0215b7..272aa84f 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -6,8 +6,16 @@ class OutputFileHandler(): def __init__(self, gudrunFile): self.gudrunFile = gudrunFile - self.getRunFiles() - self.outputs = { + # String constants + self.NORM = "Normalisation" + self.NORM_BG = "NormalisationBackground" + self.SAMPLE = "Sample" + self.SAMPLE_BG = "SampleBackground" + self.SAMPLE_BGS = "SampleBackgrounds" + self.CONTAINERS = "Containers" + self.OUTPUTS = "Outputs" + self.DIAGNOSTICS = "Diagnostics" + self.Outputs = { "sampleOutputs": [ "dcs01", "dcsd01", From 7967aa5c10359cbc285455f9a6c9aef4a8f411c4 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 10:29:09 +0100 Subject: [PATCH 008/165] Uniquify default parameter names --- gudpy/core/gudrun_file.py | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 1b99b887..a89f5876 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -7,15 +7,16 @@ from copy import deepcopy from core.utils import ( - extract_nums_from_string, - firstword, boolifyNum, - extract_ints_from_string, - extract_floats_from_string, - firstNFloats, - firstNInts, - nthfloat, - nthint, - resolve + extract_nums_from_string, + firstword, boolifyNum, + extract_ints_from_string, + extract_floats_from_string, + firstNFloats, + firstNInts, + nthfloat, + nthint, + resolve, + uniquifyName ) from core.instrument import Instrument from core.beam import Beam @@ -1270,10 +1271,25 @@ def sampleBackgroundHelper(self): elif "GO" in line: self.getNextToken() elif "SAMPLE" in line and firstword(line) == "SAMPLE": - sampleBackground.samples.append(self.makeParse("SAMPLE")) + sample = self.makeParse("SAMPLE") + if not sample.name: + sample.name = uniquifyName( + "SAMPLE", + [s.name for s in sampleBackground.samples], + sep="", + incFirst=True) + sampleBackground.samples.append(sample) elif "CONTAINER" in line and firstword(line) == "CONTAINER": + container = self.makeParse("CONTAINER") + if not container.name: + container.name = uniquifyName( + "CONTAINER", + [c.name + for c in sampleBackground.samples[-1].containers], + sep="", + incFirst=True) sampleBackground.samples[-1].containers.append( - self.makeParse("CONTAINER") + container ) self.consumeWhitespace() line = self.peekNextToken() From 0892691f644f94da14edce8196742bcaf4ccebf9 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 10:33:00 +0100 Subject: [PATCH 009/165] Created extra util functions for uniquifying names and filenames --- gudpy/core/utils.py | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/gudpy/core/utils.py b/gudpy/core/utils.py index b28e2976..30e23a6e 100644 --- a/gudpy/core/utils.py +++ b/gudpy/core/utils.py @@ -162,3 +162,81 @@ def nthreplace(str, old, new, nth): if len(tokens) > nth: string = f'{old.join(tokens[:nth])}{new}{old.join(tokens[nth:])}' return string + + +def makeDir(targetPath): + """Creates directory if it doesn't already exist + + Parameters + ---------- + targetPath : str + Path where directory is to be made + """ + if not os.path.isdir(targetPath): + os.makedirs(targetPath) + + +def uniquify(path, sep="_", incFirst=False): + """ + Function to increment path based on the amount + of existing paths + + Parameters + ---------- + path : str + requested path + sep : str + desired seperator between basename and number + incFirst : bool + whether to increment the first instance of the + path + + Returns + ------- + str + avaliable path + """ + + root, ext = os.path.splitext(path) + fileCount = 1 + if incFirst: + path = root + sep + str(fileCount) + ext + fileCount += 1 + while os.path.exists(path): + path = root + sep + str(fileCount) + ext + fileCount += 1 + return path + + +def uniquifyName(basename, names, sep="_", incFirst=False): + """ + Function to increment a default name based on the amount + of existing default names + + Parameters + ---------- + basename : str + base default name + names : str[] + list of current existing names + sep : str + desired seperator between basename and number + incFirst : bool + whether to increment the first instance of the + path + + Returns + ------- + str + avaliable path + """ + + nameCount = 1 + name = basename + if incFirst: + name = basename + sep + str(nameCount) + nameCount += 1 + while name in names: + name = basename + sep + str(nameCount) + nameCount += 1 + return name From b87f924ac632179a24201f3e2a06e39ce9b90452 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 11:52:16 +0100 Subject: [PATCH 010/165] Output file handling process change --- gudpy/core/gudrun_file.py | 4 +- gudpy/core/output_file_handler.py | 218 +++++++++++++----- .../widgets/dialogs/iterate_density_dialog.py | 2 +- 3 files changed, 160 insertions(+), 64 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index a89f5876..98710253 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1645,9 +1645,9 @@ def naiveOrganise(self): outputFileHandler = OutputFileHandler(self) outputFileHandler.naiveOrganise() - def iterativeOrganise(self, head): + def iterativeOrganise(self, nTotal, nCurrent, head): outputFileHandler = OutputFileHandler(self) - outputFileHandler.iterativeOrganise(head) + outputFileHandler.iterativeOrganise(nTotal, nCurrent, head) def determineError(self, sample): gudPath = sample.dataFiles[0].replace( diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 272aa84f..ade9cf8c 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -1,11 +1,19 @@ import os import shutil +from core.utils import makeDir, uniquify class OutputFileHandler(): def __init__(self, gudrunFile): self.gudrunFile = gudrunFile + # Directory where Gudrun files are outputted + self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir + # Name the output directory as the input file + self.outputDir = os.path.join( + self.gudrunDir, + os.path.splitext(self.gudrunFile.filename)[0] + ) # String constants self.NORM = "Normalisation" self.NORM_BG = "NormalisationBackground" @@ -45,80 +53,168 @@ def __init__(self, gudrunFile): "trans01" ], "containerOutputs": [ - ] } - def getRunFiles(self): - self.runFiles = [ - [os.path.splitext(s.dataFiles[0])[0], s.pathName()] - for sampleBackground in self.gudrunFile.sampleBackgrounds - for s in sampleBackground.samples if s.runThisSample - and len(s.dataFiles) - ] + def createNormDir(self, outputDir): + # Create normalisation folders + for normFile in self.gudrunFile.normalisation.dataFiles: + self.copyOutputs(normFile, os.path.join(outputDir, self.NORM)) + for normBgFile in self.gudrunFile.normalisation.dataFilesBg: + self.copyOutputs(normBgFile, + os.path.join(outputDir, self.NORM_BG)) - def organiseSampleFiles(self, run, sampleRunFile, tree=""): - dir = self.gudrunFile.instrument.GudrunInputFileDir - if tree: - outputDir = self.uniquify(os.path.join(dir, tree, run)) - else: - outputDir = self.uniquify(os.path.join(dir, run)) - os.makedirs(outputDir) - os.makedirs(os.path.join(outputDir, "outputs")) - os.makedirs(os.path.join(outputDir, "diagnostics")) - if os.path.exists(os.path.join(dir, sampleRunFile)): - shutil.copyfile( - os.path.join(dir, sampleRunFile), - os.path.join(outputDir, "outputs", sampleRunFile) + def createSampleBgDir(self, outputDir, sampleBackground): + for dataFile in sampleBackground.dataFiles: + self.copyOutputs( + dataFile, + uniquify(os.path.join( + outputDir, self.SAMPLE_BGS, self.SAMPLE_BG), + sep="", + incFirst=True) ) - for f in os.listdir(dir): - for suffix in self.outputs["sampleOutputs"]: - if f == f"{run}.{suffix}": - shutil.copyfile( - os.path.join(dir, f), - os.path.join(outputDir, "outputs", f) - ) - for suffix in self.outputs["sampleDiagnostics"]: - if f == f"{run}.{suffix}": - shutil.copyfile( - os.path.join(dir, f), - os.path.join(outputDir, "diagnostics", f) + + def createSampleDir(self, outputDir, samples, tree=""): + # Create sample folders within background folders + for sample in [ + s for s in samples + if s.runThisSample and len(s.dataFiles) + ]: + if tree: + samplePath = os.path.join( + outputDir, + sample.name, + tree) + else: + samplePath = uniquify(os.path.join( + outputDir, + sample.name + )) + for dataFile in sample.dataFiles: + self.copySuffixedOutputs( + dataFile, + samplePath + ) + # Copy over .sample file + if os.path.exists(os.path.join( + self.gudrunDir, sample.pathName())): + shutil.copyfile( + os.path.join(self.gudrunDir, sample.pathName()), + os.path.join(samplePath, sample.pathName()) + ) + # Create container folders within sample folder + for container in sample.containers: + containerPath = uniquify(os.path.join( + samplePath, + (container.name.replace(" ", "_") + if container.name != "CONTAINER" + else "Container"))) + for dataFile in container.dataFiles: + self.copyOutputs( + dataFile, + containerPath ) + return samplePath def naiveOrganise(self): - """ Calls `organiseSampleFiles` on members of `runFiles`""" - - for run, runFile in self.runFiles: - print(f"{run} {runFile}") - self.organiseSampleFiles(run, runFile) + # Create normalisation and sample background folders + self.createNormDir(self.outputDir) + # Create sample folders + for sampleBackground in self.gudrunFile.sampleBackgrounds: + self.createSampleBgDir(self.outputDir, sampleBackground) + self.createSampleDir( + self.outputDir, + sampleBackground.samples) - def iterativeOrganise(self, head): - path = os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - head - ) - if os.path.exists(path): - shutil.rmtree(path) - for run, runFile in self.runFiles: - self.organiseSampleFiles(run, runFile, tree=head) + def iterativeOrganise(self, nTotal, nCurrent, head): + print(head) + print(f"Total {nTotal}") + print(f"Current {nCurrent}") + for sampleBackground in self.gudrunFile.sampleBackgrounds: + if nCurrent == 0: + self.createNormDir(self.outputDir) + self.createSampleBgDir(self.outputDir, sampleBackground) + self.createSampleDir( + self.gudrunDir, + sampleBackground.samples, + f"{head}_{nCurrent + 1}") + if nCurrent == nTotal: + for sample in [ + s for s in sampleBackground.samples + if s.runThisSample and len(s.dataFiles) + ]: + shutil.move( + os.path.join(self.gudrunDir, sample.name), + uniquify( + os.path.join( + self.outputDir, + f"{sample.name}_{head}")) + ) - def uniquify(self, path): + def copyOutputs(self, fpath, targetDir): """ - Function to increment path if it already exists + Function to copy all files with the same basename + as the provided filepath, except the original file. + Creates a folder in the target directory and all necessary + directories. Parameters ---------- - path : str - requested path + fpath : str + Full filename of target file + targetDir : str + Directory for the files to be copied to + """ + fname = os.path.splitext(fpath)[0] + runDir = os.path.join(targetDir, fname) + dirCreated = False + for f in os.listdir(self.gudrunDir): + # Get files with the same filename but not the same + # extension + if os.path.splitext(f)[0] == fname and f != fpath: + if not dirCreated: + makeDir(runDir) + dirCreated = True + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(runDir, f) + ) + + def copySuffixedOutputs(self, fname, targetDir): + """ + Function to copy all files with the same basename + as the provided filepath and splits them into outputs + and diagnostics folders based on their extension. + Creates a folder in the target directory and all necessary + directories. - Returns - ------- - str - avaliable path + Parameters + ---------- + fname : str + Full filename of target file + suffixes : str[] + List of target file extenstions + targetDir : str + Directory for the files to be copied to """ - root, ext = os.path.splitext(path) - fileCount = 1 - while os.path.exists(path): - path = root + "_" + str(fileCount) + ext - fileCount += 1 - return path + fname = os.path.splitext(fname)[0] + runDir = os.path.join(targetDir, fname) + outDir = os.path.join(runDir, self.OUTPUTS) + diagDir = os.path.join(runDir, self.DIAGNOSTICS) + for f in os.listdir(self.gudrunDir): + for suffix in self.Outputs["sampleOutputs"]: + if f == f"{fname}.{suffix}": + if not os.path.isdir(outDir): + makeDir(outDir) + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(outDir, f) + ) + for suffix in self.Outputs["sampleDiagnostics"]: + if f == f"{fname}.{suffix}": + if not os.path.isdir(diagDir): + makeDir(diagDir) + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(diagDir, f) + ) diff --git a/gudpy/gui/widgets/dialogs/iterate_density_dialog.py b/gudpy/gui/widgets/dialogs/iterate_density_dialog.py index d651d3eb..ad677fba 100644 --- a/gudpy/gui/widgets/dialogs/iterate_density_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_density_dialog.py @@ -1,5 +1,5 @@ from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.density_iterator import DensityIterator +from core.iterators.density_iterator import DensityIterator class DensityIterationDialog(IterationDialog): From 7c953a7faa5c43cee48d2fdf57dd9e7ce1c09326 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 11:52:38 +0100 Subject: [PATCH 011/165] Output file handling process change in main window --- gudpy/gui/widgets/core/main_window.py | 164 +++++++++++--------------- 1 file changed, 71 insertions(+), 93 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 9b212725..fa79724d 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -154,6 +154,7 @@ class GudPyMainWindow(QMainWindow): exit_() Exits """ + def __init__(self): """ Constructs all the necessary attributes for the GudPyMainWindow object. @@ -1076,9 +1077,9 @@ def runGudrun_(self): ) else: self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=self.runGudrunFinished + dcs, self.progressDCS, + func=func, args=args, + finished=self.runGudrunFinished ) def runContainersAsSamples(self): @@ -1178,9 +1179,9 @@ def finished(ec, es): ) else: self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished + dcs, self.progressDCS, + func=func, args=args, + finished=finished ) def purgeOptionsMessageBox(self, dcs, finished, func, args, text): @@ -1207,9 +1208,9 @@ def purgeOptionsMessageBox(self, dcs, finished, func, args, text): self.purgeBeforeRunning() elif result == messageBox.Yes: self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished + dcs, self.progressDCS, + func=func, args=args, + finished=finished ) else: messageBox.close() @@ -1346,7 +1347,7 @@ def preprocessNexusFinished(self): self.queue.put(t) self.currentFile = 0 self.keyMap = { - n+1: os.path.splitext( + n + 1: os.path.splitext( os.path.basename( self.nexusProcessingFiles[n] ) @@ -1381,7 +1382,7 @@ def processPulseFinished(self): timer.start() while (timer.elapsed() < 5000): QCoreApplication.processEvents() - self.nexusProcessingOutput[self.currentFile+1] = self.output + self.nexusProcessingOutput[self.currentFile + 1] = self.output self.currentFile += 1 self.output = "" func, args = self.queue.get() @@ -1402,27 +1403,6 @@ def nexusProcessingFinished(self): keyMap=self.keyMap ) - def iterateGudrun(self, dialog, name): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) - iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) - iterationDialog.widget.exec() - if not iterationDialog.iterator: - self.setControlsEnabled(True) - else: - self.queue = iterationDialog.queue - self.iterator = iterationDialog.iterator - self.numberIterations = iterationDialog.numberIterations - self.currentIteration = 0 - self.text = iterationDialog.text - self.outputIterations = {} - if isinstance(self.iterator, CompositionIterator): - self.iterateByComposition() - else: - self.nextIterableProc() - self.mainWidget.stopTaskButton.setEnabled(True) - def batchProcessing(self): if not self.checkFilesExist_(): return @@ -1445,7 +1425,7 @@ def batchProcessing(self): self.nextBatchProcess() def batchProcessFinished(self, ec, es): - self.outputBatches[self.currentIteration+1] = self.output + self.outputBatches[self.currentIteration + 1] = self.output self.output = "" self.currentIteration += 1 self.nextBatchProcess() @@ -1473,7 +1453,7 @@ def nextBatchProcess(self): with self.queue.mutex: remaining = list(self.queue.queue) n = remaining.index(None) - for _ in range(n+1): + for _ in range(n + 1): self.queue.get() self.nextBatchProcess() else: @@ -1530,7 +1510,8 @@ def finishedCompositionIteration(self, originalSample, updatedSample): def finishedCompositionIterations(self): for original, new in self.compositionMap.items(): - dialog = CompositionAcceptanceDialog(new, self.mainWidget) + dialog = CompositionAcceptanceDialog( + new, self.gudrunFile, self.mainWidget) result = dialog.widget.exec() if result: original.composition = new.composition @@ -1567,7 +1548,7 @@ def progressCompositionIteration(self, currentIteration): progress = ( currentIteration / self.numberIterations ) * (self.currentIteration / self.totalIterations) - self.mainWidget.progressBar.setValue(int(progress*100)) + self.mainWidget.progressBar.setValue(int(progress * 100)) def nextCompositionIteration(self): args, kwargs, sample = self.queue.get() @@ -1582,6 +1563,10 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) + self.gudrunFile.iterativeOrganise( + self.numberIterations - 1, + self.currentIteration, + self.iterator.name) self.currentIteration += 1 def iterateByComposition(self): @@ -1615,31 +1600,37 @@ def iterateByComposition(self): ) self.nextCompositionIteration() + def iterateGudrun(self, dialog, name): + if not self.checkFilesExist_(): + return + self.setControlsEnabled(False) + iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) + iterationDialog.widget.exec() + if not iterationDialog.iterator: + self.setControlsEnabled(True) + else: + self.queue = iterationDialog.queue + self.iterator = iterationDialog.iterator + self.numberIterations = iterationDialog.queue.qsize() + self.currentIteration = 0 + self.text = iterationDialog.text + self.outputIterations = {} + if isinstance(self.iterator, CompositionIterator): + self.iterateByComposition() + else: + self.nextIterableProc() + self.mainWidget.stopTaskButton.setEnabled(True) + def nextIteration(self): if self.error: self.procFinished(9, QProcess.NormalExit) return - if isinstance(self.iterator, TweakFactorIterator): - self.gudrunFile.iterativeOrganise( - f"IterateByTweakFactor_{self.currentIteration+1}" - ) - elif isinstance(self.iterator, ThicknessIterator): - self.gudrunFile.iterativeOrganise( - f"IterateByThickness_{self.currentIteration+1}" - ) - elif isinstance(self.iterator, RadiusIterator): + if isinstance(self.iterator, SingleParamIterator): self.gudrunFile.iterativeOrganise( - f"IterateByRadius_{self.currentIteration+1}" - ) - elif isinstance(self.iterator, DensityIterator): - self.gudrunFile.iterativeOrganise( - f"IterateByDensity_{self.currentIteration+1}" - ) - if isinstance( - self.iterator, ( - TweakFactorIterator, SingleParamIterator + self.numberIterations, + self.currentIteration, + self.iterator.name ) - ): time.sleep(1) self.iterator.performIteration(self.currentIteration) self.gudrunFile.write_out() @@ -1649,19 +1640,26 @@ def nextIteration(self): "gudrun_dcs", gudrunFile=self.gudrunFile ) - elif isinstance(self.iterator, WavelengthSubtractionIterator): - if self.currentIteration % 2 == 0: + if isinstance(self.iterator, WavelengthSubtractionIterator): + print(f"Q size: {self.queue.qsize()}") + if self.queue.qsize() % 2 != 0: self.iterator.gudrunFile.iterativeOrganise( - f"WavelengthIteration_{(self.currentIteration // 2) + 1}" + self.numberIterations + 1, + self.currentIteration, + "WavelengthIteration" ) - self.outputIterations[self.currentIteration + 1] = self.output else: self.iterator.gudrunFile.iterativeOrganise( - f"QIteration_{(self.currentIteration // 2) + 1}" - ) - self.outputIterations[self.currentIteration + 1] = self.output - if not self.queue.empty(): + self.numberIterations, + self.currentIteration, + "QIteration" + ) + self.currentIteration += 1 + self.outputIterations[self.currentIteration + 1] = self.output + else: self.currentIteration += 1 + + if not self.queue.empty(): self.nextIterableProc() else: self.procFinished(0, QProcess.NormalExit) @@ -1679,7 +1677,7 @@ def nextIterableProc(self): self.gudrunFile.instrument.GudrunInputFileDir ) if isinstance(self.iterator, WavelengthSubtractionIterator): - if self.currentIteration % 2 == 0: + if self.queue.qsize() % 2 == 0: self.iterator.wavelengthIteration(self.currentIteration) else: self.iterator.QIteration(self.currentIteration) @@ -1688,22 +1686,10 @@ def nextIterableProc(self): self.proc.start() def iterationStarted(self): - if isinstance( - self.iterator, ( - TweakFactorIterator, ThicknessIterator, - RadiusIterator, DensityIterator - ) - ): - self.mainWidget.currentTaskLabel.setText( - f"{self.text}" - f" {self.currentIteration+1}/{self.numberIterations}" - ) - elif isinstance(self.iterator, WavelengthSubtractionIterator): - iteration = math.ceil((self.currentIteration+1)/2) - self.mainWidget.currentTaskLabel.setText( - f"{self.text}" - f" {iteration}/{int(self.numberIterations/2)}" - ) + self.mainWidget.currentTaskLabel.setText( + f"{self.text}" + f" {self.currentIteration+1}/{self.numberIterations+1}" + ) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() def progressIteration(self): @@ -1714,15 +1700,7 @@ def progressIteration(self): f" from gudrun_dcs\n{self.error}" ) return - if isinstance( - self.iterator, ( - TweakFactorIterator, ThicknessIterator, - RadiusIterator, DensityIterator - ) - ): - progress /= self.numberIterations - elif isinstance(self.iterator, WavelengthSubtractionIterator): - progress /= self.numberIterations + progress /= self.numberIterations progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( progress if progress <= 100 else 100 @@ -1876,7 +1854,7 @@ def progressIncrementDCS(self, gudrunFile=None): for sample in sampleBackground.samples if sample.runThisSample ] - ), + ), *[ len(sample.containers) for sample in sampleBackground.samples @@ -1887,7 +1865,7 @@ def progressIncrementDCS(self, gudrunFile=None): ] ) ) - stepSize = math.ceil(100/markers) + stepSize = math.ceil(100 / markers) progress = stepSize * sum( [ stdout.count("Got to: INSTRUMENT"), @@ -1958,7 +1936,7 @@ def appendDfs(dfs): ] ) - stepSize = math.ceil(100/len(dataFiles)) + stepSize = math.ceil(100 / len(dataFiles)) progress = 0 for df in dataFiles: if df in stdout: @@ -2037,7 +2015,7 @@ def procFinished(self, ec, es): RadiusIterator, DensityIterator ) ): - self.outputIterations[self.currentIteration+1] = self.output + self.outputIterations[self.currentIteration + 1] = self.output self.sampleSlots.setSample(self.sampleSlots.sample) if self.iterator: output = self.outputIterations From fec2fb9c7485d8d16ba2ae8971e34e1f8263afe3 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 11:53:02 +0100 Subject: [PATCH 012/165] Modifying dialog functions as needed --- .../dialogs/composition_acceptance_dialog.py | 3 ++- .../iterate_inelasticity_subtractions_dialog.py | 14 +++++++++++++- .../widgets/dialogs/iterate_thickness_dialog.py | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/gudpy/gui/widgets/dialogs/composition_acceptance_dialog.py b/gudpy/gui/widgets/dialogs/composition_acceptance_dialog.py index 1e27aa2a..ec500356 100644 --- a/gudpy/gui/widgets/dialogs/composition_acceptance_dialog.py +++ b/gudpy/gui/widgets/dialogs/composition_acceptance_dialog.py @@ -7,9 +7,10 @@ class CompositionAcceptanceDialog(QDialog): - def __init__(self, sample, parent): + def __init__(self, sample, gudrunFile, parent): super(CompositionAcceptanceDialog, self).__init__(parent=parent) self.sample = sample + self.gudrunFile = gudrunFile self.accepted_ = False self.initComponents() diff --git a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py b/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py index 84306c78..1e3fda0c 100644 --- a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py @@ -1,3 +1,5 @@ +import os +from queue import Queue from gui.widgets.dialogs.iteration_dialog import IterationDialog from core.iterators.wavelength_subtraction_iterator import ( WavelengthSubtractionIterator @@ -8,7 +10,17 @@ class WavelengthInelasticitySubtractionsIterationDialog(IterationDialog): def iterate(self): self.iterator = WavelengthSubtractionIterator(self.gudrunFile) - self.numberIterations *= 2 self.enqueueTasks() self.text = "Inelasticity subtractions" self.widget.close() + + def enqueueTasks(self): + self.queue = Queue() + for _ in range((self.numberIterations * 2)): + self.queue.put( + self.iterator.gudrunFile.dcs( + path=os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + "gudpy.txt" + ), headless=False) + ) diff --git a/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py b/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py index 7501cfbe..57540b7f 100644 --- a/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py +++ b/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py @@ -1,5 +1,5 @@ from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.thickness_iterator import ThicknessIterator +from core.iterators.thickness_iterator import ThicknessIterator from core.enums import Geometry from core import config From b28273515fc0602917abca5a085b82aa0a6b4ece Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 11:53:14 +0100 Subject: [PATCH 013/165] Formatting --- gudpy/core/gudrun_file.py | 71 +++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 98710253..32f79961 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -142,6 +142,7 @@ def __init__(self, path=None, config_=False): """ self.path = path + self.filename = os.path.basename(path) self.yaml = YAML() # Construct the outpath. @@ -436,32 +437,32 @@ def parseInstrument(self): self.instrument.detectorCalibrationFileName = match.group() match = re.search( - pattern, - self.instrument.groupFileName + pattern, + self.instrument.groupFileName ) if match: self.instrument.groupFileName = match.group() match = re.search( - pattern, - self.instrument.deadtimeConstantsFileName + pattern, + self.instrument.deadtimeConstantsFileName ) if match: self.instrument.deadtimeConstantsFileName = match.group() match = re.search( - pattern, - self.instrument.neutronScatteringParametersFile + pattern, + self.instrument.neutronScatteringParametersFile ) if match: self.instrument.neutronScatteringParametersFile = match.group() match = re.search( - pattern, - self.instrument.neutronScatteringParametersFile + pattern, + self.instrument.neutronScatteringParametersFile ) if match: @@ -469,10 +470,10 @@ def parseInstrument(self): except Exception as e: raise ParserException( - "Whilst parsing Instrument, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." - f"{str(e)}" + "Whilst parsing Instrument, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." + f"{str(e)}" ) from e def parseBeam(self): @@ -552,8 +553,8 @@ def parseBeam(self): pattern = re.compile(r"StartupFiles\S*") match = re.search( - pattern, - self.beam.filenameIncidentBeamSpectrumParams + pattern, + self.beam.filenameIncidentBeamSpectrumParams ) if match: @@ -574,9 +575,9 @@ def parseBeam(self): except Exception as e: raise ParserException( - "Whilst parsing Beam, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." + "Whilst parsing Beam, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." ) from e def parseNormalisation(self): @@ -778,9 +779,9 @@ def parseNormalisation(self): except Exception as e: raise ParserException( - "Whilst parsing Normalisation, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." + "Whilst parsing Normalisation, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." ) from e def parseSampleBackground(self): @@ -822,9 +823,9 @@ def parseSampleBackground(self): return sampleBackground except Exception as e: raise ParserException( - "Whilst parsing Sample Background, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." + "Whilst parsing Sample Background, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." ) from e def parseSample(self): @@ -852,8 +853,6 @@ def parseSample(self): str(self.getNextToken()[:-2]).strip() .replace("SAMPLE", "").strip() ) - if not sample.name: - sample.name = "SAMPLE" self.consumeWhitespace() # The number of files and period number are both stored # on the same line. @@ -980,7 +979,7 @@ def parseSample(self): while ( "to finish specifying wavelength range of resonance" not in line - ): + ): sample.resonanceValues.append( extract_floats_from_string(line) ) @@ -1028,9 +1027,9 @@ def parseSample(self): except Exception as e: raise ParserException( - "Whilst parsing Sample, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." + "Whilst parsing Sample, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." ) from e def parseContainer(self): @@ -1059,8 +1058,6 @@ def parseContainer(self): str(self.getNextToken()[:-2]).strip() .replace("CONTAINER", "").strip() ) - if not container.name: - container.name = "CONTAINER" self.consumeWhitespace() # The number of files and period number are both stored @@ -1173,9 +1170,9 @@ def parseContainer(self): except Exception as e: raise ParserException( - "Whilst parsing Container, an exception occured." - " The input file is most likely of an incorrect format, " - "and some attributes were missing." + "Whilst parsing Container, an exception occured." + " The input file is most likely of an incorrect format, " + "and some attributes were missing." ) from e def parseComponents(self): @@ -1651,9 +1648,9 @@ def iterativeOrganise(self, nTotal, nCurrent, head): def determineError(self, sample): gudPath = sample.dataFiles[0].replace( - self.instrument.dataFileType, - "gud" - ) + self.instrument.dataFileType, + "gud" + ) gudFile = GudFile( os.path.join( self.instrument.GudrunInputFileDir, gudPath From d78eb94a594026c81fa58e4f77b7b1a9c7df2736 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:02:23 +0100 Subject: [PATCH 014/165] Removed debugging print statements --- gudpy/core/output_file_handler.py | 6 +++--- gudpy/gui/widgets/core/main_window.py | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index ade9cf8c..9bdbd24c 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -68,10 +68,10 @@ def createSampleBgDir(self, outputDir, sampleBackground): for dataFile in sampleBackground.dataFiles: self.copyOutputs( dataFile, - uniquify(os.path.join( + os.path.join( outputDir, self.SAMPLE_BGS, self.SAMPLE_BG), - sep="", - incFirst=True) + sep="", + incFirst=True ) def createSampleDir(self, outputDir, samples, tree=""): diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index fa79724d..5b2d72b9 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1641,7 +1641,6 @@ def nextIteration(self): gudrunFile=self.gudrunFile ) if isinstance(self.iterator, WavelengthSubtractionIterator): - print(f"Q size: {self.queue.qsize()}") if self.queue.qsize() % 2 != 0: self.iterator.gudrunFile.iterativeOrganise( self.numberIterations + 1, From 3d2b9d7d3da38ca6c05acb1278bc1501780d24cf Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:03:17 +0100 Subject: [PATCH 015/165] Removed debugging print statements --- gudpy/core/output_file_handler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 9bdbd24c..00ca979c 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -127,9 +127,6 @@ def naiveOrganise(self): sampleBackground.samples) def iterativeOrganise(self, nTotal, nCurrent, head): - print(head) - print(f"Total {nTotal}") - print(f"Current {nCurrent}") for sampleBackground in self.gudrunFile.sampleBackgrounds: if nCurrent == 0: self.createNormDir(self.outputDir) From cc8522a46302cc1e3ec69b37a335ac9eddd56ca8 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:16:16 +0100 Subject: [PATCH 016/165] fixed duplication of sample background directory --- gudpy/core/output_file_handler.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 00ca979c..c72e6a41 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -64,15 +64,16 @@ def createNormDir(self, outputDir): self.copyOutputs(normBgFile, os.path.join(outputDir, self.NORM_BG)) - def createSampleBgDir(self, outputDir, sampleBackground): - for dataFile in sampleBackground.dataFiles: - self.copyOutputs( - dataFile, - os.path.join( - outputDir, self.SAMPLE_BGS, self.SAMPLE_BG), - sep="", - incFirst=True - ) + def createSampleBgDir(self, outputDir): + for count, sampleBackground in enumerate( + self.gudrunFile.sampleBackgrounds): + for dataFile in sampleBackground.dataFiles: + self.copyOutputs( + dataFile, + os.path.join( + outputDir, self.SAMPLE_BGS, + f"{self.SAMPLE_BG}{count + 1}") + ) def createSampleDir(self, outputDir, samples, tree=""): # Create sample folders within background folders @@ -119,18 +120,19 @@ def createSampleDir(self, outputDir, samples, tree=""): def naiveOrganise(self): # Create normalisation and sample background folders self.createNormDir(self.outputDir) + self.createSampleBgDir(self.outputDir) # Create sample folders for sampleBackground in self.gudrunFile.sampleBackgrounds: - self.createSampleBgDir(self.outputDir, sampleBackground) self.createSampleDir( self.outputDir, sampleBackground.samples) def iterativeOrganise(self, nTotal, nCurrent, head): + if nCurrent == 0: + self.createNormDir(self.outputDir) + self.createSampleBgDir( + self.outputDir) for sampleBackground in self.gudrunFile.sampleBackgrounds: - if nCurrent == 0: - self.createNormDir(self.outputDir) - self.createSampleBgDir(self.outputDir, sampleBackground) self.createSampleDir( self.gudrunDir, sampleBackground.samples, From 73db138adba0077ee042937fc55e87204202114f Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:29:40 +0100 Subject: [PATCH 017/165] Documentation and commenting --- gudpy/core/output_file_handler.py | 65 +++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 4 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index c72e6a41..3e8ab050 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -57,7 +57,16 @@ def __init__(self, gudrunFile): } def createNormDir(self, outputDir): - # Create normalisation folders + """ + Creates directories for normalisation background + and normalisation outputs. + + Parameters + ---------- + outputDir : str + Path to target output directory + """ + # Create normalisation folders and move datafiles for normFile in self.gudrunFile.normalisation.dataFiles: self.copyOutputs(normFile, os.path.join(outputDir, self.NORM)) for normBgFile in self.gudrunFile.normalisation.dataFilesBg: @@ -65,8 +74,19 @@ def createNormDir(self, outputDir): os.path.join(outputDir, self.NORM_BG)) def createSampleBgDir(self, outputDir): + """ + Creates output directory for sample backgrounds + + Parameters + ---------- + outputDir : str + Path to target output directory + """ + # Iterate through all sample backgrounds for count, sampleBackground in enumerate( self.gudrunFile.sampleBackgrounds): + # Move all datafiles into their sample background folder + # Creates the folder if there is none for dataFile in sampleBackground.dataFiles: self.copyOutputs( dataFile, @@ -76,6 +96,21 @@ def createSampleBgDir(self, outputDir): ) def createSampleDir(self, outputDir, samples, tree=""): + """ + Creates output directory for each sample + + Parameters + ---------- + outputDir : str + Path to target output directory + samples : Sample[] + List of samples in a sample background + tree : str, optional + Target basename if running iteratively, + is the root folder of the sample folders + by default "" + + """ # Create sample folders within background folders for sample in [ s for s in samples @@ -91,6 +126,7 @@ def createSampleDir(self, outputDir, samples, tree=""): outputDir, sample.name )) + # Move datafiles to sample folder for dataFile in sample.dataFiles: self.copySuffixedOutputs( dataFile, @@ -115,9 +151,10 @@ def createSampleDir(self, outputDir, samples, tree=""): dataFile, containerPath ) - return samplePath def naiveOrganise(self): + """Organises Gudrun outputs + """ # Create normalisation and sample background folders self.createNormDir(self.outputDir) self.createSampleBgDir(self.outputDir) @@ -128,6 +165,20 @@ def naiveOrganise(self): sampleBackground.samples) def iterativeOrganise(self, nTotal, nCurrent, head): + """ + Organises Gudrun outputs when it is run + iteratively + + Parameters + ---------- + nTotal : int + Total number of iterations + nCurrent : int + Current iteration + head : str + Intended basename for folders + which gets incremented per iteration + """ if nCurrent == 0: self.createNormDir(self.outputDir) self.createSampleBgDir( @@ -152,7 +203,7 @@ def iterativeOrganise(self, nTotal, nCurrent, head): def copyOutputs(self, fpath, targetDir): """ - Function to copy all files with the same basename + Copy all files with the same basename as the provided filepath, except the original file. Creates a folder in the target directory and all necessary directories. @@ -181,7 +232,7 @@ def copyOutputs(self, fpath, targetDir): def copySuffixedOutputs(self, fname, targetDir): """ - Function to copy all files with the same basename + Copy all files with the same basename as the provided filepath and splits them into outputs and diagnostics folders based on their extension. Creates a folder in the target directory and all necessary @@ -196,11 +247,16 @@ def copySuffixedOutputs(self, fname, targetDir): targetDir : str Directory for the files to be copied to """ + # Data filename fname = os.path.splitext(fname)[0] + # Path to folder which will hold all outputs from the run runDir = os.path.join(targetDir, fname) + # Path to folder which will hold Gudrun outputs outDir = os.path.join(runDir, self.OUTPUTS) + # Path to folder which will hold Gudrun diagnostic outputs diagDir = os.path.join(runDir, self.DIAGNOSTICS) for f in os.listdir(self.gudrunDir): + # Moving all files with output file extensions for suffix in self.Outputs["sampleOutputs"]: if f == f"{fname}.{suffix}": if not os.path.isdir(outDir): @@ -209,6 +265,7 @@ def copySuffixedOutputs(self, fname, targetDir): os.path.join(self.gudrunDir, f), os.path.join(outDir, f) ) + # Moving all files with diagnostic file extensions for suffix in self.Outputs["sampleDiagnostics"]: if f == f"{fname}.{suffix}": if not os.path.isdir(diagDir): From dee91b2091ba6359e5d2f14394d2ad15273e302c Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:32:03 +0100 Subject: [PATCH 018/165] Documentation and commenting --- gudpy/core/output_file_handler.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 3e8ab050..87110b4d 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -180,15 +180,20 @@ def iterativeOrganise(self, nTotal, nCurrent, head): which gets incremented per iteration """ if nCurrent == 0: + # Create the normalisation and sample background directories + # if this is the first iteration self.createNormDir(self.outputDir) self.createSampleBgDir( self.outputDir) + # Create the sample output folders for sampleBackground in self.gudrunFile.sampleBackgrounds: self.createSampleDir( self.gudrunDir, sampleBackground.samples, f"{head}_{nCurrent + 1}") if nCurrent == nTotal: + # If this is the final iteration, move root folder + # to output folder for sample in [ s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles) From 10cf48f84601925665e566ab7a210b655339c220 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 12:50:39 +0100 Subject: [PATCH 019/165] Fixed iteration counting --- gudpy/gui/widgets/core/main_window.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 5b2d72b9..f640fd83 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1611,7 +1611,7 @@ def iterateGudrun(self, dialog, name): else: self.queue = iterationDialog.queue self.iterator = iterationDialog.iterator - self.numberIterations = iterationDialog.queue.qsize() + self.numberIterations = iterationDialog.queue.qsize() - 1 self.currentIteration = 0 self.text = iterationDialog.text self.outputIterations = {} @@ -1687,7 +1687,7 @@ def nextIterableProc(self): def iterationStarted(self): self.mainWidget.currentTaskLabel.setText( f"{self.text}" - f" {self.currentIteration+1}/{self.numberIterations+1}" + f" {self.currentIteration+1}/{self.numberIterations + 1}" ) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() From f88cab1af2eda3bd909831c6be5a696d79ab0272 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 13:13:42 +0100 Subject: [PATCH 020/165] Fixed wavelength subtraction iterator --- .../core/iterators/wavelength_subtraction_iterator.py | 2 ++ gudpy/core/output_file_handler.py | 2 +- gudpy/gui/widgets/core/main_window.py | 11 +++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gudpy/core/iterators/wavelength_subtraction_iterator.py b/gudpy/core/iterators/wavelength_subtraction_iterator.py index d1e34509..fb16d1d7 100644 --- a/gudpy/core/iterators/wavelength_subtraction_iterator.py +++ b/gudpy/core/iterators/wavelength_subtraction_iterator.py @@ -57,6 +57,8 @@ class WavelengthSubtractionIterator(): Perform n iterations on the wavelength scale and Q scale. """ + name = "IterateByWavelengthSubtraction" + def __init__(self, gudrunFile): """ Constructs all the necessary attributes for the diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 87110b4d..055f8456 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -203,7 +203,7 @@ def iterativeOrganise(self, nTotal, nCurrent, head): uniquify( os.path.join( self.outputDir, - f"{sample.name}_{head}")) + sample.name)) ) def copyOutputs(self, fpath, targetDir): diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index f640fd83..0616bd42 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1647,13 +1647,19 @@ def nextIteration(self): self.currentIteration, "WavelengthIteration" ) - else: + elif self.queue.qsize(): self.iterator.gudrunFile.iterativeOrganise( self.numberIterations, self.currentIteration, "QIteration" ) self.currentIteration += 1 + else: + self.iterator.gudrunFile.iterativeOrganise( + self.currentIteration, + self.currentIteration, + "QIteration" + ) self.outputIterations[self.currentIteration + 1] = self.output else: self.currentIteration += 1 @@ -1687,7 +1693,8 @@ def nextIterableProc(self): def iterationStarted(self): self.mainWidget.currentTaskLabel.setText( f"{self.text}" - f" {self.currentIteration+1}/{self.numberIterations + 1}" + f" {(self.numberIterations + 1) - self.queue.qsize()}" + + f"/{self.numberIterations + 1}" ) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() From a324512ca7a8b7f529f83a62c57ca7531add3ed4 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 13:30:30 +0100 Subject: [PATCH 021/165] Applied changes to batch processing --- gudpy/core/run_batch_files.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index dccf283c..1bdad061 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -93,10 +93,10 @@ def writeDiagnosticsFile(self, path, batch, iterationMode): def propogateResults(self, current, next, iterationMode): for ( sampleBackgroundA, sampleBackgroundB - ) in zip(current.sampleBackgrounds, next.sampleBackgrounds): + ) in zip(current.sampleBackgrounds, next.sampleBackgrounds): for ( sampleA, sampleB - ) in zip(sampleBackgroundA.samples, sampleBackgroundB.samples): + ) in zip(sampleBackgroundA.samples, sampleBackgroundB.samples): if iterationMode == IterationModes.TWEAK_FACTOR: sampleB.sampleTweakFactor = sampleA.sampleTweakFactor elif iterationMode == IterationModes.THICKNESS: @@ -169,6 +169,8 @@ def process( initial.process(headless=headless) iterator.performIteration(i) initial.iterativeOrganise( + maxIterations - 1, + i, os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", @@ -199,6 +201,8 @@ def process( iterator.performIteration(i) self.batchedGudrunFile.iterativeOrganise( os.path.join( + maxIterations - 1, + i, self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", "REST", @@ -229,7 +233,7 @@ def process( tasks.append( [ self.batchedGudrunFile.iterativeOrganise, - [f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], + [0, 0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], ] ) tasks.append( @@ -264,6 +268,8 @@ def process( [ initial.iterativeOrganise, [ + maxIterations - 1, + i, os.path.join( initial.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE" @@ -318,6 +324,8 @@ def process( [ self.batchedGudrunFile.iterativeOrganise, [ + maxIterations - 1, + i, os.path.join( f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}", f"{dirText}_{i+1}", From ae2b3b255b82459c169edd993da066236579fb88 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 14:31:01 +0100 Subject: [PATCH 022/165] Attempting to fix windows build --- gudpy/core/output_file_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 055f8456..93adcd63 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -137,8 +137,10 @@ def createSampleDir(self, outputDir, samples, tree=""): self.gudrunDir, sample.pathName())): shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), - os.path.join(samplePath, sample.pathName()) + os.path.join(samplePath, sample.pathName()), + symlinks=True ) + # Create container folders within sample folder for container in sample.containers: containerPath = uniquify(os.path.join( From 9a027e19691210441f2e83d35c5f0e080af0a040 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 6 Oct 2023 15:58:19 +0100 Subject: [PATCH 023/165] Attempting to fix windows build --- gudpy/core/output_file_handler.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 93adcd63..a2624e56 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -135,10 +135,9 @@ def createSampleDir(self, outputDir, samples, tree=""): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): - shutil.copyfile( + shutil.copy( os.path.join(self.gudrunDir, sample.pathName()), - os.path.join(samplePath, sample.pathName()), - symlinks=True + os.path.join(samplePath, sample.pathName()) ) # Create container folders within sample folder From fe8edb576a3289cfabac2600fd9dbf34120befad Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 9 Oct 2023 10:06:23 +0100 Subject: [PATCH 024/165] Fix windows build? Make sure dir exists --- gudpy/core/output_file_handler.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index a2624e56..e1455cee 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -14,15 +14,6 @@ def __init__(self, gudrunFile): self.gudrunDir, os.path.splitext(self.gudrunFile.filename)[0] ) - # String constants - self.NORM = "Normalisation" - self.NORM_BG = "NormalisationBackground" - self.SAMPLE = "Sample" - self.SAMPLE_BG = "SampleBackground" - self.SAMPLE_BGS = "SampleBackgrounds" - self.CONTAINERS = "Containers" - self.OUTPUTS = "Outputs" - self.DIAGNOSTICS = "Diagnostics" self.Outputs = { "sampleOutputs": [ "dcs01", @@ -68,10 +59,13 @@ def createNormDir(self, outputDir): """ # Create normalisation folders and move datafiles for normFile in self.gudrunFile.normalisation.dataFiles: - self.copyOutputs(normFile, os.path.join(outputDir, self.NORM)) + self.copyOutputs( + normFile, os.path.join( + outputDir, "Normalisation")) for normBgFile in self.gudrunFile.normalisation.dataFilesBg: self.copyOutputs(normBgFile, - os.path.join(outputDir, self.NORM_BG)) + os.path.join(outputDir, + "NormalisationBackground")) def createSampleBgDir(self, outputDir): """ @@ -91,8 +85,8 @@ def createSampleBgDir(self, outputDir): self.copyOutputs( dataFile, os.path.join( - outputDir, self.SAMPLE_BGS, - f"{self.SAMPLE_BG}{count + 1}") + outputDir, "SampleBackgrounds", + f"SampleBackground{count + 1}") ) def createSampleDir(self, outputDir, samples, tree=""): @@ -135,7 +129,8 @@ def createSampleDir(self, outputDir, samples, tree=""): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): - shutil.copy( + makeDir(samplePath) + shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) ) @@ -258,9 +253,9 @@ def copySuffixedOutputs(self, fname, targetDir): # Path to folder which will hold all outputs from the run runDir = os.path.join(targetDir, fname) # Path to folder which will hold Gudrun outputs - outDir = os.path.join(runDir, self.OUTPUTS) + outDir = os.path.join(runDir, "Outputs") # Path to folder which will hold Gudrun diagnostic outputs - diagDir = os.path.join(runDir, self.DIAGNOSTICS) + diagDir = os.path.join(runDir, "Diagnostics") for f in os.listdir(self.gudrunDir): # Moving all files with output file extensions for suffix in self.Outputs["sampleOutputs"]: From baf79cf6ec7e98ed8341f4867b2da2f1070dd7da Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 11 Oct 2023 16:00:49 +0100 Subject: [PATCH 025/165] Creating gudrun file in temp directory --- gudpy/core/file_library.py | 9 ++++----- gudpy/core/gudrun_file.py | 1 + 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/gudpy/core/file_library.py b/gudpy/core/file_library.py index 6329a505..0296d31f 100644 --- a/gudpy/core/file_library.py +++ b/gudpy/core/file_library.py @@ -40,7 +40,6 @@ def __init__(self, gudrunFile): # Collect directories self.dirs = { - "Input file directory": gudrunFile.instrument.GudrunInputFileDir, "Data file directory": gudrunFile.instrument.dataFileDir, "Gudrun start folder": gudrunFile.instrument.GudrunStartFolder, "Startup file folder": gudrunFile.instrument.startupFileFolder, @@ -169,14 +168,14 @@ def exportMintData( ): if not exportTo: exportTo = os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, + self.gudrunFile.inputFileDir, Path(self.gudrunFile.path).stem + ".zip", ) with ZipFile(exportTo, "w", ZIP_DEFLATED) as zipFile: for sample in samples: if len(sample.dataFiles.dataFiles): path = os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, + self.gudrunFile.inputFileDir, sample.dataFiles.dataFiles[0].replace( self.gudrunFile.instrument.dataFileType, "mint01" ), @@ -192,12 +191,12 @@ def exportMintData( zipFile.write(path, arcname=os.path.basename(outpath)) if includeParams: path = os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, + self.gudrunFile.inputFileDir, safeSampleName + ".sample", ) if not os.path.exists(path): sample.write_out( - self.gudrunFile.instrument.GudrunInputFileDir + self.gudrunFile.inputFileDir ) zipFile.write(path, arcname=os.path.basename(path)) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 35972778..3617e4c8 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -146,6 +146,7 @@ def __init__(self, path=None, format=Format.YAML, config_=False): """ self.path = path + self.inputFileDir = os.path.dirname(path) self.filename = os.path.basename(path) self.yaml = YAML() self.format = format From 4c806001d96bca8a0f7ac7b116ba6199fe7855bd Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 11 Oct 2023 16:01:01 +0100 Subject: [PATCH 026/165] Comments --- gudpy/core/utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/gudpy/core/utils.py b/gudpy/core/utils.py index 30e23a6e..99eeed21 100644 --- a/gudpy/core/utils.py +++ b/gudpy/core/utils.py @@ -171,10 +171,17 @@ def makeDir(targetPath): ---------- targetPath : str Path where directory is to be made + + Returns + ------- + dirPath : str + Path of created directory """ if not os.path.isdir(targetPath): os.makedirs(targetPath) + return targetPath + def uniquify(path, sep="_", incFirst=False): """ From b586920877974828bfbc6449c5fe6a6bac556745 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 11 Oct 2023 16:01:28 +0100 Subject: [PATCH 027/165] Gudrun runs in temporary directory, files are copied over --- gudpy/core/gudrun_file.py | 7 +- gudpy/core/output_file_handler.py | 191 ++++++++++++++++---------- gudpy/gui/widgets/core/main_window.py | 81 +++++------ 3 files changed, 161 insertions(+), 118 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 3617e4c8..e3fa3d2c 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1651,8 +1651,11 @@ def naiveOrganise(self): outputFileHandler.naiveOrganise() def iterativeOrganise(self, nTotal, nCurrent, head): - outputFileHandler = OutputFileHandler(self) - outputFileHandler.iterativeOrganise(nTotal, nCurrent, head) + if nCurrent == 0: + self.outputFileHandler = OutputFileHandler(self) + self.outputFileHandler.iterativeOrganise(nTotal, nCurrent, head) + if nCurrent == nTotal: + del self.outputFileHandler def determineError(self, sample): gudPath = sample.dataFiles[0].replace( diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index e1455cee..edec2ffc 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -7,45 +7,55 @@ class OutputFileHandler(): def __init__(self, gudrunFile): self.gudrunFile = gudrunFile - # Directory where Gudrun files are outputted + # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir + # Temporary output dir + self.tempOutputDir = os.path.join(self.gudrunDir, "out") # Name the output directory as the input file self.outputDir = os.path.join( - self.gudrunDir, + self.gudrunFile.inputFileDir, os.path.splitext(self.gudrunFile.filename)[0] ) - self.Outputs = { - "sampleOutputs": [ - "dcs01", - "dcsd01", - "dcse01", - "dcst01", - "dscw01", - "mdcs01", - "mdcsd01", - "mdcse01", - "mdcsw01", - "mint01", - "mgor01", - "mdor01", - "gud", - "sample" - ], - "sampleDiagnostics": [ - "abs01", - "bak", - "gr1", - "gr2", - "mul01", - "mut01", - "pla01", - "rawmon", - "smomon", - "trans01" - ], - "containerOutputs": [ - ] - } + # Paths to sample output folers + self.sampleOutputPaths = [] + # Path to additional output folder + self.addOutputPath = uniquify( + os.path.join(self.tempOutputDir, "AdditionalOutputs") + ) + + # Files that have been copied + self.copiedFiles = [] + self.outputExts = [ + "dcs01", + "dcsd01", + "dcse01", + "dcst01", + "dscw01", + "mdcs01", + "mdcsd01", + "mdcse01", + "mdcsw01", + "mint01", + "mgor01", + "mdor01", + "gud", + "sample" + ] + + # List of run samples + self.samples = [] + for sampleBackground in self.gudrunFile.sampleBackgrounds: + for sample in [ + s for s in sampleBackground.samples + if s.runThisSample and len(s.dataFiles)]: + self.samples.append(sample) + # Generate paths for sample output directories + self.sampleOutputPaths.append( + uniquify(os.path.join( + self.tempOutputDir, + sample.name + )) + ) def createNormDir(self, outputDir): """ @@ -89,7 +99,7 @@ def createSampleBgDir(self, outputDir): f"SampleBackground{count + 1}") ) - def createSampleDir(self, outputDir, samples, tree=""): + def createSampleDir(self, outputDir, tree=""): """ Creates output directory for each sample @@ -106,10 +116,7 @@ def createSampleDir(self, outputDir, samples, tree=""): """ # Create sample folders within background folders - for sample in [ - s for s in samples - if s.runThisSample and len(s.dataFiles) - ]: + for sample in self.samples: if tree: samplePath = os.path.join( outputDir, @@ -122,7 +129,7 @@ def createSampleDir(self, outputDir, samples, tree=""): )) # Move datafiles to sample folder for dataFile in sample.dataFiles: - self.copySuffixedOutputs( + self.copyOutputsByExt( dataFile, samplePath ) @@ -134,6 +141,7 @@ def createSampleDir(self, outputDir, samples, tree=""): os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) ) + self.copiedFiles.append(sample.pathName()) # Create container folders within sample folder for container in sample.containers: @@ -155,10 +163,16 @@ def naiveOrganise(self): self.createNormDir(self.outputDir) self.createSampleBgDir(self.outputDir) # Create sample folders - for sampleBackground in self.gudrunFile.sampleBackgrounds: - self.createSampleDir( - self.outputDir, - sampleBackground.samples) + self.createSampleDir( + self.tempOutputDir) + # Copy remaining outputs + self.copyRemaining(self.addOutputPath) + # Move over sample & additional outputs to output directory + for folder in os.listdir(self.tempOutputDir): + shutil.move( + os.path.join(self.tempOutputDir, folder), + uniquify(os.path.join(self.outputDir, folder)) + ) def iterativeOrganise(self, nTotal, nCurrent, head): """ @@ -181,26 +195,33 @@ def iterativeOrganise(self, nTotal, nCurrent, head): self.createNormDir(self.outputDir) self.createSampleBgDir( self.outputDir) + for sampleDir in self.sampleOutputPaths: + makeDir(sampleDir) + # Create the sample output folders - for sampleBackground in self.gudrunFile.sampleBackgrounds: - self.createSampleDir( - self.gudrunDir, - sampleBackground.samples, - f"{head}_{nCurrent + 1}") - if nCurrent == nTotal: - # If this is the final iteration, move root folder - # to output folder - for sample in [ - s for s in sampleBackground.samples - if s.runThisSample and len(s.dataFiles) - ]: - shutil.move( - os.path.join(self.gudrunDir, sample.name), - uniquify( - os.path.join( - self.outputDir, - sample.name)) - ) + self.createSampleDir( + self.gudrunDir, + f"{head}_{nCurrent + 1}") + + self.copyRemaining(os.path.join( + self.addOutputPath, + f"{head}_{nCurrent + 1}")) + + # Copy organised folder to temporary sample output dir + for sample, sampleOutDir in zip(self.samples, self.sampleOutputPaths): + shutil.move( + os.path.join( + self.gudrunDir, + sample.name, + f"{head}_{nCurrent + 1}"), + sampleOutDir + ) + # Move over sample & additional outputs to output directory + for folder in os.listdir(self.tempOutputDir): + shutil.move( + os.path.join(self.tempOutputDir, folder), + uniquify(os.path.join(self.outputDir, folder)) + ) def copyOutputs(self, fpath, targetDir): """ @@ -222,7 +243,7 @@ def copyOutputs(self, fpath, targetDir): for f in os.listdir(self.gudrunDir): # Get files with the same filename but not the same # extension - if os.path.splitext(f)[0] == fname and f != fpath: + if os.path.splitext(f)[0] == fname: if not dirCreated: makeDir(runDir) dirCreated = True @@ -230,8 +251,9 @@ def copyOutputs(self, fpath, targetDir): os.path.join(self.gudrunDir, f), os.path.join(runDir, f) ) + self.copiedFiles.append(f) - def copySuffixedOutputs(self, fname, targetDir): + def copyOutputsByExt(self, fname, targetDir): """ Copy all files with the same basename as the provided filepath and splits them into outputs @@ -253,25 +275,42 @@ def copySuffixedOutputs(self, fname, targetDir): # Path to folder which will hold all outputs from the run runDir = os.path.join(targetDir, fname) # Path to folder which will hold Gudrun outputs - outDir = os.path.join(runDir, "Outputs") + outDir = makeDir(os.path.join(runDir, "Outputs")) # Path to folder which will hold Gudrun diagnostic outputs - diagDir = os.path.join(runDir, "Diagnostics") + diagDir = makeDir(os.path.join(runDir, "Diagnostics")) for f in os.listdir(self.gudrunDir): - # Moving all files with output file extensions - for suffix in self.Outputs["sampleOutputs"]: + for suffix in self.outputExts: + # Moving files with output file extensions if f == f"{fname}.{suffix}": - if not os.path.isdir(outDir): - makeDir(outDir) shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(outDir, f) ) - # Moving all files with diagnostic file extensions - for suffix in self.Outputs["sampleDiagnostics"]: - if f == f"{fname}.{suffix}": - if not os.path.isdir(diagDir): - makeDir(diagDir) + self.copiedFiles.append(f) + # Moving diagnostic files + elif os.path.splitext(f)[0] == fname: shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(diagDir, f) ) + self.copiedFiles.append(f) + + def copyRemaining(self, targetDir): + """ + Copy over all files that haven't been copied over, + as specified in `copiedFiles` + + Parameters + ---------- + targetDir : str + Directory for the files to be copied to + """ + makeDir(targetDir) + + for f in os.listdir(self.gudrunDir): + if f not in self.copiedFiles and os.path.isfile( + os.path.join(self.gudrunDir, f)): + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(targetDir, f) + ) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 44fa8217..3a57bf31 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -4,6 +4,7 @@ import time import math import traceback +import tempfile from queue import Queue from collections.abc import Sequence import re @@ -939,6 +940,9 @@ def makeProc( finished = self.procFinished if not dir_: dir_ = self.gudrunFile.instrument.GudrunInputFileDir + + dir_ = self.tmp.name + self.proc = cmd self.proc.readyReadStandardOutput.connect(slot) self.proc.started.connect(started) @@ -948,10 +952,26 @@ def makeProc( func(*args) self.proc.start() - def runPurge_(self): + def prepareRun(self): if not self.checkFilesExist_(): return self.setControlsEnabled(False) + + self.tmp = tempfile.TemporaryDirectory() + self.gudrunFile.instrument.GudrunInputFileDir = self.tmp.name + + def cleanupRun(self): + self.tmp.cleanup() + self.tmp = None + + self.setControlsEnabled(True) + self.mainWidget.progressBar.setValue(0) + self.mainWidget.currentTaskLabel.setText("No task running.") + self.queue = Queue() + + def runPurge_(self): + self.prepareRun() + purgeDialog = PurgeDialog(self.gudrunFile, self) result = purgeDialog.widget.exec_() purge = purgeDialog.purge_det @@ -975,9 +995,8 @@ def runPurge_(self): self.makeProc(purge, self.progressPurge, func=func, args=args) def runGudrun_(self): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) + self.prepareRun() + dcs = self.gudrunFile.dcs( path=os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -1024,9 +1043,8 @@ def runGudrun_(self): ) def runContainersAsSamples(self): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) + self.prepareRun() + runContainersAsSamples = RunContainersAsSamples(self.gudrunFile) dcs = runContainersAsSamples.runContainersAsSamples( path=os.path.join( @@ -1076,9 +1094,7 @@ def finished(ec, es): ) def runFilesIndividually(self): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) + self.prepareRun() runIndividualFiles = RunIndividualFiles(self.gudrunFile) dcs = runIndividualFiles.gudrunFile.dcs( path=os.path.join( @@ -1333,9 +1349,7 @@ def processPulseFinished(self): self.nexusProcessingFinished() def nexusProcessingFinished(self): - self.setControlsEnabled(True) - self.mainWidget.currentTaskLabel.setText("No task running.") - self.mainWidget.progressBar.setValue(0) + self.cleanupRun() self.proc = None self.outputSlots.setOutput( self.nexusProcessingOutput, @@ -1346,9 +1360,7 @@ def nexusProcessingFinished(self): self.gudrunFile.nexus_processing.tmp.cleanup() def batchProcessing(self): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) + self.prepareRun() batchProcessingDialog = BatchProcessingDialog( self.gudrunFile, self.mainWidget ) @@ -1455,10 +1467,7 @@ def finishedCompositionIterations(self): original.composition = new.composition if self.sampleSlots.sample == original: self.sampleSlots.setSample(original) - self.setControlsEnabled(True) - self.mainWidget.progressBar.setValue(0) - self.mainWidget.currentTaskLabel.setText("No task running.") - self.queue = Queue() + self.cleanupRun() def startedCompositionIteration(self, sample): self.mainWidget.currentTaskLabel.setText( @@ -1472,13 +1481,10 @@ def errorCompositionIteration(self, output): "An error occured whilst iterating by composition." " Please check the output to see what went wrong.", ) - self.setControlsEnabled(True) - self.mainWidget.currentTaskLabel.setText("No task running.") - self.mainWidget.progressBar.setValue(0) + self.cleanupRun() self.outputSlots.setOutput( output, "gudrun_dcs", gudrunFile=self.gudrunFile ) - self.queue = Queue() def progressCompositionIteration(self, currentIteration): progress = ( @@ -1539,9 +1545,7 @@ def iterateByComposition(self): self.nextCompositionIteration() def iterateGudrun(self, dialog, name): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) + self.prepareRun() iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) iterationDialog.widget.exec() if not iterationDialog.iterator: @@ -1962,22 +1966,13 @@ def procFinished(self, ec, es): self.sampleSlots.setSample(self.sampleSlots.sample) if self.iterator: output = self.outputIterations - self.iterator = None - + self.iterator = None if self.error: QMessageBox.critical( self.mainWidget, "GudPy Error", repr(self.error) ) self.error = "" - self.queue = Queue() - if self.queue.empty(): - if self.warning: - QMessageBox.warning( - self.mainWidget, "GudPy Warning", repr(self.warning) - ) - self.warning = "" - self.setControlsEnabled(True) - self.mainWidget.stopTaskButton.setEnabled(False) + self.cleanupRun() if "purge_det" not in self.mainWidget.currentTaskLabel.text(): try: self.updateResults() @@ -1997,8 +1992,13 @@ def procFinished(self, ec, es): ) self.outputIterations = {} self.output = "" - self.mainWidget.currentTaskLabel.setText("No task running.") - self.mainWidget.progressBar.setValue(0) + if self.queue.empty(): + if self.warning: + QMessageBox.warning( + self.mainWidget, "GudPy Warning", repr(self.warning) + ) + self.warning = "" + self.cleanupRun() if not self.queue.empty(): args, kwargs = self.queue.get() self.makeProc(*args, **kwargs) @@ -2008,6 +2008,7 @@ def stopProc(self): self.queue = Queue() if self.proc: if self.proc.state() == QProcess.Running: + self.cleanupRun() self.proc.kill() if self.workerThread: self.workerThread.requestInterruption() From c4834a59fe0cc463b839c680cb6ee3ce78af40eb Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:26:05 +0100 Subject: [PATCH 028/165] Organised and renamed, gave more responsibility to iterator objects --- ...composition_iterator.py => composition.py} | 0 .../{density_iterator.py => density.py} | 6 +- ...terator.py => inelasticity_subtraction.py} | 38 ++-- .../{single_param_iterator.py => iterator.py} | 40 +++-- .../{radius_iterator.py => radius.py} | 6 +- .../{thickness_iterator.py => thickness.py} | 6 +- ...eak_factor_iterator.py => tweak_factor.py} | 15 +- .../dialogs/iterate_composition_dialog.py | 162 ------------------ .../widgets/dialogs/iterate_density_dialog.py | 11 -- ...terate_inelasticity_subtractions_dialog.py | 26 --- .../widgets/dialogs/iterate_radius_dialog.py | 20 --- .../dialogs/iterate_thickness_dialog.py | 19 -- .../dialogs/iterate_tweak_factor_dialog.py | 11 -- 13 files changed, 61 insertions(+), 299 deletions(-) rename gudpy/core/iterators/{composition_iterator.py => composition.py} (100%) rename gudpy/core/iterators/{density_iterator.py => density.py} (84%) rename gudpy/core/iterators/{wavelength_subtraction_iterator.py => inelasticity_subtraction.py} (91%) rename gudpy/core/iterators/{single_param_iterator.py => iterator.py} (84%) rename gudpy/core/iterators/{radius_iterator.py => radius.py} (84%) rename gudpy/core/iterators/{thickness_iterator.py => thickness.py} (83%) rename gudpy/core/iterators/{tweak_factor_iterator.py => tweak_factor.py} (90%) delete mode 100644 gudpy/gui/widgets/dialogs/iterate_composition_dialog.py delete mode 100644 gudpy/gui/widgets/dialogs/iterate_density_dialog.py delete mode 100644 gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py delete mode 100644 gudpy/gui/widgets/dialogs/iterate_radius_dialog.py delete mode 100644 gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py delete mode 100644 gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py diff --git a/gudpy/core/iterators/composition_iterator.py b/gudpy/core/iterators/composition.py similarity index 100% rename from gudpy/core/iterators/composition_iterator.py rename to gudpy/core/iterators/composition.py diff --git a/gudpy/core/iterators/density_iterator.py b/gudpy/core/iterators/density.py similarity index 84% rename from gudpy/core/iterators/density_iterator.py rename to gudpy/core/iterators/density.py index 4e37e745..32e1b33c 100644 --- a/gudpy/core/iterators/density_iterator.py +++ b/gudpy/core/iterators/density.py @@ -1,9 +1,9 @@ -from core.iterators.single_param_iterator import SingleParamIterator +from core.iterators.iterator import Iterator -class DensityIterator(SingleParamIterator): +class DensityIterator(Iterator): """ - Class to represent a Density Iterator. Inherits SingleParamIterator. + Class to represent a Density Iterator. Inherits Iterator. This class is used for iteratively tweaking the density. This means running gudrun_dcs iteratively, and adjusting the density of each sample across iterations. The new density is determined by diff --git a/gudpy/core/iterators/wavelength_subtraction_iterator.py b/gudpy/core/iterators/inelasticity_subtraction.py similarity index 91% rename from gudpy/core/iterators/wavelength_subtraction_iterator.py rename to gudpy/core/iterators/inelasticity_subtraction.py index fb16d1d7..70a7b18a 100644 --- a/gudpy/core/iterators/wavelength_subtraction_iterator.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -3,11 +3,12 @@ from copy import deepcopy from core.enums import Scales +from core.iterators.iterator import Iterator -class WavelengthSubtractionIterator(): +class InelasticitySubtraction(Iterator): """ - Class to represent a WavelengthSubtractionIterator. + Class to represent a InelasticitySubtraction iterator. This class is used for iteratively subtracting wavelength. Each iteration comprises of a wavelength run and a Q binning run. @@ -57,12 +58,12 @@ class WavelengthSubtractionIterator(): Perform n iterations on the wavelength scale and Q scale. """ - name = "IterateByWavelengthSubtraction" + name = "IterateByWavelengthInelasticitySubtraction" def __init__(self, gudrunFile): """ Constructs all the necessary attributes for the - WavelengthSubtractionIterator object. + InelasticitySubtraction object. Parameters ---------- @@ -70,6 +71,7 @@ def __init__(self, gudrunFile): Input GudrunFile that we will be using for iterating. """ self.gudrunFile = deepcopy(gudrunFile) + self.iterationType = "WavelengthIteration" self.topHatWidths = [] self.QMax = 0. self.QMin = 0. @@ -179,7 +181,7 @@ def setSelfScatteringFiles(self, scale): str(Path(filename).stem) + '.' + suffix ) - def wavelengthIteration(self, i): + def wavelengthIteration(self): """ Performs one iteration on the wavelength scale. If the iteration is the first iteration, @@ -195,7 +197,7 @@ def wavelengthIteration(self, i): Then, write out the GudrunFile and call gudrun_dcs. """ # First iteration - if i == 0: + if self.nCurrent == 0: # Disable subtracting of wavelength binned data. # Collect the top hat widths and Q range and step size. self.gudrunFile.instrument.subWavelengthBinnedData = False @@ -217,7 +219,7 @@ def wavelengthIteration(self, i): self.zeroTopHatWidths() self.setSelfScatteringFiles(Scales.WAVELENGTH) - def QIteration(self, i): + def QIteration(self): """ Performs one iteration on the Q scale. Enables subtracting of wavelength-binned data. @@ -239,19 +241,25 @@ def QIteration(self, i): self.resetTopHatWidths() self.setSelfScatteringFiles(Scales.Q) - def iterate(self, n): + def performIteration(self): + if self.nCurrent % 2 != 0: + self.wavelengthIteration() + self.iterationType = "WavelengthIteration" + else: + self.QIteration() + self.iterationType = "QIteration" + self.nCurrent += 1 + + def iterate(self): """ Perform n iterations on both the wavelength scale and Q scale. """ - for i in range(n): + for _ in range(self.nTotal): - self.wavelengthIteration(i) - self.gudrunFile.process(iterative=True) - time.sleep(1) - self.gudrunFile.iterativeOrganise(n, i, "WavelengthIteration") - self.QIteration(i) + self.performIteration() self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.iterativeOrganise(n, i, "QIteration") + self.gudrunFile.iterativeOrganise( + self.nTotal, self.nCurrent, self.iterationType) diff --git a/gudpy/core/iterators/single_param_iterator.py b/gudpy/core/iterators/iterator.py similarity index 84% rename from gudpy/core/iterators/single_param_iterator.py rename to gudpy/core/iterators/iterator.py index 48300a37..6b1220cf 100644 --- a/gudpy/core/iterators/single_param_iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -1,11 +1,12 @@ -from core.gud_file import GudFile import os import time +from core.gud_file import GudFile + -class SingleParamIterator(): +class Iterator(): """ - Class to represent a Single Param Iterator. + Class to represent an Iterator. This class is used for iteratively tweaking a parameter by a coefficient. This means running gudrun_dcs iteratively, and adjusting parameter of each sample across iterations. The new coefficient @@ -20,36 +21,36 @@ class SingleParamIterator(): Input GudrunFile that we will be using for iterating. Methods ---------- - performIteration(_n) + performIteration() Performs a single iteration. applyCoefficientToAttribute(object, coefficient) To be overriden by sub-classes. - iterate(n) + iterate() Perform n iterations of iterating by tweak factor. organiseOutput To be overriden by sub-classes. """ - def __init__(self, gudrunFile): + def __init__(self, gudrunFile, nTotal): """ Constructs all the necessary attributes for the - SingleParamIterator object. + Iterator object. Parameters ---------- gudrunFile : GudrunFile Input GudrunFile that we will be using for iterating. + nTotal : int + Total number of iterations to be run """ self.gudrunFile = gudrunFile + self.nTotal = nTotal + self.nCurrent = 0 - def performIteration(self, _n): + def performIteration(self): """ Performs a single iteration of the current workflow. - Parameters - ---------- - _n : int - Iteration number. """ # Iterate through all samples that are being run, # applying the coefficient to the target parameter. @@ -74,6 +75,7 @@ def performIteration(self, _n): ) # Apply the coefficient. self.applyCoefficientToAttribute(sample, coefficient) + self.nCurrent += 1 def applyCoefficientToAttribute(self, object, coefficient): """ @@ -90,7 +92,7 @@ def applyCoefficientToAttribute(self, object, coefficient): """ pass - def organiseOutput(self, nTotal, nCurrent): + def organiseOutput(self): """ This should organises the output of the iteration. @@ -102,11 +104,11 @@ def organiseOutput(self, nTotal, nCurrent): Current iteration """ self.gudrunFile.iterativeOrganise( - nTotal, nCurrent, self.name) + self.nTotal, self.nCurrent, self.name) - def iterate(self, n): + def iterate(self): """ - This method is the core of the SingleParamIterator. + This method is the core of the Iterator. It performs n iterations of tweaking by a class-specific parameter. Namely, it performs gudrun_dcs n times, adjusting said parameter for each sample before each iteration, after the first one, @@ -117,8 +119,8 @@ def iterate(self, n): n : int Number of iterations to perform. """ - for i in range(n): + for _ in range(self.nTotal): self.gudrunFile.process() time.sleep(1) - self.performIteration(i) - self.organiseOutput(n, i) + self.performIteration() + self.organiseOutput() diff --git a/gudpy/core/iterators/radius_iterator.py b/gudpy/core/iterators/radius.py similarity index 84% rename from gudpy/core/iterators/radius_iterator.py rename to gudpy/core/iterators/radius.py index 9776537d..001a6149 100644 --- a/gudpy/core/iterators/radius_iterator.py +++ b/gudpy/core/iterators/radius.py @@ -1,9 +1,9 @@ -from core.iterators.single_param_iterator import SingleParamIterator +from core.iterators.iterator import Iterator -class RadiusIterator(SingleParamIterator): +class RadiusIterator(Iterator): """ - Class to represent a Radius Iterator. Inherits SingleParamIterator. + Class to represent a Radius Iterator. Inherits Iterator. This class is used for iteratively tweaking the thickness of a flatplate sample. This means running gudrun_dcs iteratively, and adjusting the inner/outer diff --git a/gudpy/core/iterators/thickness_iterator.py b/gudpy/core/iterators/thickness.py similarity index 83% rename from gudpy/core/iterators/thickness_iterator.py rename to gudpy/core/iterators/thickness.py index 7a5b8550..4d2b109a 100644 --- a/gudpy/core/iterators/thickness_iterator.py +++ b/gudpy/core/iterators/thickness.py @@ -1,9 +1,9 @@ -from core.iterators.single_param_iterator import SingleParamIterator +from core.iterators.iterator import Iterator -class ThicknessIterator(SingleParamIterator): +class ThicknessIterator(Iterator): """ - Class to represent a Thickness Iterator. Inherits SingleParamIterator. + Class to represent a Thickness Iterator. Inherits Iterator. This class is used for iteratively tweaking the thickness of a flatplate sample. This means running gudrun_dcs iteratively, and adjusting the thickness diff --git a/gudpy/core/iterators/tweak_factor_iterator.py b/gudpy/core/iterators/tweak_factor.py similarity index 90% rename from gudpy/core/iterators/tweak_factor_iterator.py rename to gudpy/core/iterators/tweak_factor.py index 5aadca3f..b93c0fc9 100644 --- a/gudpy/core/iterators/tweak_factor_iterator.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -2,10 +2,10 @@ import time from core.gud_file import GudFile -from core.iterators.single_param_iterator import SingleParamIterator +from core.iterators.iterator import Iterator -class TweakFactorIterator(SingleParamIterator): +class TweakFactorIterator(Iterator): """ Class to represent a Tweak Factor Iterator. This class is used for iteratively tweaking by the tweak factor. @@ -30,7 +30,7 @@ class TweakFactorIterator(SingleParamIterator): name = "IterateByTweakFactor" - def performIteration(self, _n): + def performIteration(self): """ Performs a single iteration of the current workflow. @@ -58,8 +58,9 @@ def performIteration(self, _n): ) tweakFactor = float(gudFile.suggestedTweakFactor) sample.sampleTweakFactor = tweakFactor + self.nCurrent += 1 - def iterate(self, n): + def iterate(self): """ This method is the core of the TweakFactorIterator. It performs n iterations of tweaking by the tweak factor. @@ -75,11 +76,11 @@ def iterate(self, n): Number of iterations to perform. """ # Perform n iterations of tweaking by tweak factor. - for i in range(n): + for _ in range(self.nTotal): # Write out what we currently have, # and run gudrun_dcs on that file. self.gudrunFile.process(iterative=True) time.sleep(1) - self.performIteration(i) - self.organiseOutput(n, i) + self.performIteration() + self.organiseOutput() diff --git a/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py b/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py deleted file mode 100644 index e57216a3..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_composition_dialog.py +++ /dev/null @@ -1,162 +0,0 @@ -from queue import Queue -from copy import deepcopy -from PySide6.QtCore import Qt - -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.composition_iterator import ( - CompositionIterator, calculateTotalMolecules -) - - -class CompositionIterationDialog(IterationDialog): - - def __init__(self, name, gudrunFile, parent): - self.components = [None, None] - self.rtol = 0. - super().__init__(name, gudrunFile, parent) - - def loadFirstComponentsComboBox(self): - self.widget.firstComponentComboBox.clear() - for component in self.gudrunFile.components.components: - self.widget.firstComponentComboBox.addItem( - component.name, component - ) - self.components[0] = self.gudrunFile.components.components[0] - - def loadSecondComponentsComboBox(self): - self.widget.secondComponentComboBox.clear() - for component in self.gudrunFile.components.components: - self.widget.secondComponentComboBox.addItem( - component.name, component - ) - - def firstComponentChanged(self, index): - self.components[0] = self.widget.firstComponentComboBox.itemData(index) - other = self.widget.secondComponentComboBox.model().item(index) - self.setItemDisabled( - self.widget.secondComponentComboBox, - other - ) - - def secondComponentChanged(self, index): - self.components[1] = ( - self.widget.secondComponentComboBox.itemData(index) - ) - other = self.widget.firstComponentComboBox.model().item(index) - self.setItemDisabled( - self.widget.firstComponentComboBox, - other - ) - - def compositionRtolChanged(self, value): - self.rtol = value - - def enableItems(self, comboBox): - for i in range(len(self.gudrunFile.components.components)): - item = comboBox.model().item(i) - if item: - item.setFlags( - item.flags() | Qt.ItemIsEnabled - ) - - def setItemDisabled(self, comboBox, item): - self.enableItems(comboBox) - if item: - item.setFlags(item.flags() & ~Qt.ItemIsEnabled) - - def toggleUseSingleComponent(self, state): - if state: - self.enableItems(self.widget.firstComponentComboBox) - self.components[1] = None - else: - other = self.widget.secondComponentComboBox.model().item( - self.widget.firstComponentComboBox.currentIndex() - ) - self.setItemDisabled( - self.widget.secondComponentComboBox, - other - ) - self.widget.secondComponentComboBox.setEnabled(not state) - self.widget.secondComponentComboBox.setCurrentIndex(-1) - - def initComponents(self): - super().initComponents() - self.widget.firstComponentComboBox.currentIndexChanged.connect( - self.firstComponentChanged - ) - self.widget.secondComponentComboBox.currentIndexChanged.connect( - self.secondComponentChanged - ) - self.widget.secondComponentComboBox.setCurrentIndex(-1) - - self.widget.compositionToleranceSpinBox.valueChanged.connect( - self.compositionRtolChanged - ) - self.widget.singleComponentCheckBox.toggled.connect( - self.toggleUseSingleComponent - ) - if len(self.gudrunFile.components.components): - - self.loadFirstComponentsComboBox() - self.loadSecondComponentsComboBox() - self.toggleUseSingleComponent(True) - else: - self.widget.iterateButton.setEnabled(False) - - def iterate(self): - self.iterator = CompositionIterator(self.gudrunFile) - self.iterator.setComponents(self.components) - self.queue = Queue() - for sampleBackground in self.gudrunFile.sampleBackgrounds: - for sample in sampleBackground.samples: - if sample.runThisSample: - if [ - wc for wc in sample.composition.weightedComponents - if self.components[0].eq(wc.component) - ]: - sb = deepcopy(sampleBackground) - sb.samples = [deepcopy(sample)] - if len(self.iterator.components) == 1: - self.queue.put( - ( - ( - [1e-2, self.iterator.ratio, 10], - 0, - self.numberIterations, - self.rtol - ), - { - "args": ( - self.gudrunFile, - sb, - self.iterator.components - ) - }, - sample - ) - ) - elif len(self.iterator.components) == 2: - self.queue.put( - ( - ( - [1e-2, self.iterator.ratio, 10], - 0, - self.numberIterations, - self.rtol - ), - { - "args": ( - self.gudrunFile, - sb, - self.iterator.components, - calculateTotalMolecules( - self.iterator.components, - sample - ) - ) - }, - sample - ) - ) - self.text = "Iterate by Composition" - self.widget.close() diff --git a/gudpy/gui/widgets/dialogs/iterate_density_dialog.py b/gudpy/gui/widgets/dialogs/iterate_density_dialog.py deleted file mode 100644 index ad677fba..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_density_dialog.py +++ /dev/null @@ -1,11 +0,0 @@ -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.density_iterator import DensityIterator - - -class DensityIterationDialog(IterationDialog): - - def iterate(self): - self.iterator = DensityIterator(self.gudrunFile) - self.enqueueTasks() - self.text = "Iterate by Density" - self.widget.close() diff --git a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py b/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py deleted file mode 100644 index 1e3fda0c..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_inelasticity_subtractions_dialog.py +++ /dev/null @@ -1,26 +0,0 @@ -import os -from queue import Queue -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.wavelength_subtraction_iterator import ( - WavelengthSubtractionIterator -) - - -class WavelengthInelasticitySubtractionsIterationDialog(IterationDialog): - - def iterate(self): - self.iterator = WavelengthSubtractionIterator(self.gudrunFile) - self.enqueueTasks() - self.text = "Inelasticity subtractions" - self.widget.close() - - def enqueueTasks(self): - self.queue = Queue() - for _ in range((self.numberIterations * 2)): - self.queue.put( - self.iterator.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "gudpy.txt" - ), headless=False) - ) diff --git a/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py b/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py deleted file mode 100644 index 187583a3..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_radius_dialog.py +++ /dev/null @@ -1,20 +0,0 @@ -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.radius_iterator import RadiusIterator -from core.enums import Geometry -from core import config - - -class RadiusIterationDialog(IterationDialog): - - def initComponents(self): - super().initComponents() - self.widget.iterateButton.setEnabled( - config.geometry == Geometry.CYLINDRICAL - ) - - def iterate(self): - self.iterator = RadiusIterator(self.gudrunFile) - self.iterator.setTargetRadius("inner") - self.enqueueTasks() - self.text = "Iterate by Radius" - self.widget.close() diff --git a/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py b/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py deleted file mode 100644 index 57540b7f..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_thickness_dialog.py +++ /dev/null @@ -1,19 +0,0 @@ -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.thickness_iterator import ThicknessIterator -from core.enums import Geometry -from core import config - - -class ThicknessIterationDialog(IterationDialog): - - def initComponents(self): - super().initComponents() - self.widget.iterateButton.setEnabled( - config.geometry == Geometry.FLATPLATE - ) - - def iterate(self): - self.iterator = ThicknessIterator(self.gudrunFile) - self.enqueueTasks() - self.text = "Iterate by Thickness" - self.widget.close() diff --git a/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py b/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py deleted file mode 100644 index 0c6b6bdb..00000000 --- a/gudpy/gui/widgets/dialogs/iterate_tweak_factor_dialog.py +++ /dev/null @@ -1,11 +0,0 @@ -from gui.widgets.dialogs.iteration_dialog import IterationDialog -from core.iterators.tweak_factor_iterator import TweakFactorIterator - - -class TweakFactorIterationDialog(IterationDialog): - - def iterate(self): - self.iterator = TweakFactorIterator(self.gudrunFile) - self.enqueueTasks() - self.text = "Iterate by Tweak Factor" - self.widget.close() From f69c654dc6754bb750d64505b2205025c7021e0e Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:26:50 +0100 Subject: [PATCH 029/165] Fixed output handler resetting --- gudpy/core/gudrun_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index e3fa3d2c..32c2c34b 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1654,7 +1654,7 @@ def iterativeOrganise(self, nTotal, nCurrent, head): if nCurrent == 0: self.outputFileHandler = OutputFileHandler(self) self.outputFileHandler.iterativeOrganise(nTotal, nCurrent, head) - if nCurrent == nTotal: + if nCurrent == nTotal - 1: del self.outputFileHandler def determineError(self, sample): From d4846a1a60bf2cbac75f0f7c2afa29ceaf520c77 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:27:20 +0100 Subject: [PATCH 030/165] Refactored and fixed output handler to work with new system --- gudpy/core/output_file_handler.py | 125 ++++++++++++++++-------------- 1 file changed, 66 insertions(+), 59 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index edec2ffc..0f2626d9 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -7,55 +7,64 @@ class OutputFileHandler(): def __init__(self, gudrunFile): self.gudrunFile = gudrunFile + # List of run samples + self.samples = [] # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir - # Temporary output dir - self.tempOutputDir = os.path.join(self.gudrunDir, "out") + # Temporary output dir paths + self.tempOutDir = { + "root": os.path.join(self.gudrunDir, "out"), + "samps": [], + "add": "" + } # Name the output directory as the input file self.outputDir = os.path.join( self.gudrunFile.inputFileDir, os.path.splitext(self.gudrunFile.filename)[0] ) - # Paths to sample output folers - self.sampleOutputPaths = [] - # Path to additional output folder - self.addOutputPath = uniquify( - os.path.join(self.tempOutputDir, "AdditionalOutputs") - ) - # Files that have been copied self.copiedFiles = [] self.outputExts = [ - "dcs01", - "dcsd01", - "dcse01", - "dcst01", - "dscw01", - "mdcs01", - "mdcsd01", - "mdcse01", - "mdcsw01", - "mint01", - "mgor01", - "mdor01", - "gud", - "sample" + ".dcs01", + ".dcsd01", + ".dcse01", + ".dcst01", + ".dscw01", + ".mdcs01", + ".mdcsd01", + ".mdcse01", + ".mdcsw01", + ".mint01", + ".mgor01", + ".mdor01", + ".gud", + ".sample" ] - # List of run samples - self.samples = [] + # Generating paths for sampleBackground in self.gudrunFile.sampleBackgrounds: for sample in [ s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles)]: self.samples.append(sample) - # Generate paths for sample output directories - self.sampleOutputPaths.append( - uniquify(os.path.join( - self.tempOutputDir, - sample.name - )) + # Generate unique paths for sample output directories + self.tempOutDir["samps"].append( + os.path.join( + self.tempOutDir["root"], + uniquify(os.path.join( + self.outputDir, + sample.name + )).partition(self.outputDir + "/")[-1] + ) ) + # Generate unique path for Additional Outputs folder + self.tempOutDir["add"] = os.path.join( + self.tempOutDir["root"], + uniquify(os.path.join( + self.outputDir, + "AdditionalOutputs" + )).partition(self.outputDir + "/")[-1] + ) def createNormDir(self, outputDir): """ @@ -164,13 +173,13 @@ def naiveOrganise(self): self.createSampleBgDir(self.outputDir) # Create sample folders self.createSampleDir( - self.tempOutputDir) + self.tempOutDir["root"]) # Copy remaining outputs - self.copyRemaining(self.addOutputPath) + self.copyRemaining(self.tempOutDir["add"]) # Move over sample & additional outputs to output directory - for folder in os.listdir(self.tempOutputDir): + for folder in os.listdir(self.tempOutDir["root"]): shutil.move( - os.path.join(self.tempOutputDir, folder), + os.path.join(self.tempOutDir["root"], folder), uniquify(os.path.join(self.outputDir, folder)) ) @@ -189,38 +198,41 @@ def iterativeOrganise(self, nTotal, nCurrent, head): Intended basename for folders which gets incremented per iteration """ + iterName = f"{head}_{nCurrent + 1}" + if nCurrent == 0: # Create the normalisation and sample background directories # if this is the first iteration self.createNormDir(self.outputDir) self.createSampleBgDir( self.outputDir) - for sampleDir in self.sampleOutputPaths: + for sampleDir in self.tempOutDir["samps"]: makeDir(sampleDir) # Create the sample output folders self.createSampleDir( self.gudrunDir, - f"{head}_{nCurrent + 1}") + iterName) self.copyRemaining(os.path.join( - self.addOutputPath, - f"{head}_{nCurrent + 1}")) + self.tempOutDir["add"], + iterName)) # Copy organised folder to temporary sample output dir - for sample, sampleOutDir in zip(self.samples, self.sampleOutputPaths): + for sample, sampleOutDir in zip( + self.samples, self.tempOutDir["samps"]): shutil.move( os.path.join( self.gudrunDir, sample.name, - f"{head}_{nCurrent + 1}"), + iterName), sampleOutDir ) # Move over sample & additional outputs to output directory - for folder in os.listdir(self.tempOutputDir): + for folder in os.listdir(self.tempOutDir["root"]): shutil.move( - os.path.join(self.tempOutputDir, folder), - uniquify(os.path.join(self.outputDir, folder)) + os.path.join(self.tempOutDir["root"], folder, iterName), + os.path.join(self.outputDir, folder, iterName) ) def copyOutputs(self, fpath, targetDir): @@ -279,21 +291,16 @@ def copyOutputsByExt(self, fname, targetDir): # Path to folder which will hold Gudrun diagnostic outputs diagDir = makeDir(os.path.join(runDir, "Diagnostics")) for f in os.listdir(self.gudrunDir): - for suffix in self.outputExts: - # Moving files with output file extensions - if f == f"{fname}.{suffix}": - shutil.copyfile( - os.path.join(self.gudrunDir, f), - os.path.join(outDir, f) - ) - self.copiedFiles.append(f) - # Moving diagnostic files - elif os.path.splitext(f)[0] == fname: - shutil.copyfile( - os.path.join(self.gudrunDir, f), - os.path.join(diagDir, f) - ) - self.copiedFiles.append(f) + # If the file has the same name as requested filename + fn, ext = os.path.splitext(f) + if fn == fname: + # Set dir depending on file extension + dir = outDir if ext in self.outputExts else diagDir + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(dir, f) + ) + self.copiedFiles.append(f) def copyRemaining(self, targetDir): """ From 7e316dd727cb9bc0c129226123bfebf48cb26b9b Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:27:32 +0100 Subject: [PATCH 031/165] updated imports --- gudpy/core/run_batch_files.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index 1bdad061..4d8ff98a 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -1,10 +1,10 @@ from copy import deepcopy import os from core.enums import IterationModes -from core.iterators.tweak_factor_iterator import TweakFactorIterator -from core.iterators.thickness_iterator import ThicknessIterator -from core.iterators.radius_iterator import RadiusIterator -from core.iterators.density_iterator import DensityIterator +from core.iterators.tweak_factor import TweakFactorIterator +from core.iterators.thickness import ThicknessIterator +from core.iterators.radius import RadiusIterator +from core.iterators.density import DensityIterator class BatchProcessor: From 34d6e82970873bde40d713058e5d260f75baf632 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:28:48 +0100 Subject: [PATCH 032/165] updated imports --- gudpy/gui/widgets/core/main_window.py | 25 ++++++++----------- gudpy/gui/widgets/core/worker.py | 2 +- gudpy/gui/widgets/dialogs/iteration_dialog.py | 16 +++++++++++- gudpy/test/test_gudpy_workflows.py | 14 +++++------ 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 3a57bf31..aa822e1a 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -36,26 +36,21 @@ ) from PySide6.QtCharts import QChartView -from core.iterators.single_param_iterator import SingleParamIterator -from core.iterators.composition_iterator import CompositionIterator -from core.iterators.density_iterator import DensityIterator -from core.iterators.radius_iterator import RadiusIterator +from core.iterators.iterator import Iterator +from core.iterators.composition import CompositionIterator +from core.iterators.density import DensityIterator +from core.iterators.radius import RadiusIterator from core.sample import Sample from core.container import Container -from core.iterators.thickness_iterator import ThicknessIterator +from core.iterators.thickness import ThicknessIterator from gui.widgets.dialogs.export_dialog import ExportDialog -from gui.widgets.dialogs.iterate_composition_dialog import ( + +from gui.widgets.dialogs.iteration_dialog import ( CompositionIterationDialog, -) -from gui.widgets.dialogs.iterate_density_dialog import DensityIterationDialog -from gui.widgets.dialogs.iterate_inelasticity_subtractions_dialog import ( - WavelengthInelasticitySubtractionsIterationDialog, -) -from gui.widgets.dialogs.iterate_radius_dialog import RadiusIterationDialog -from gui.widgets.dialogs.iterate_thickness_dialog import ( + DensityIterationDialog, + InelasticitySubtractionIterationDialog, + RadiusIterationDialog, ThicknessIterationDialog, -) -from gui.widgets.dialogs.iterate_tweak_factor_dialog import ( TweakFactorIterationDialog, ) from gui.widgets.dialogs.purge_dialog import PurgeDialog diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index 7fcc36c6..b14dfa5a 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -4,7 +4,7 @@ from core.gud_file import GudFile from core.sample import Sample -from core.iterators.composition_iterator import gss +from core.iterators.composition import gss class CompositionWorker(QObject): diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index 3edce932..bd478b98 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -1,10 +1,24 @@ import os from queue import Queue import sys +from copy import deepcopy from PySide6.QtWidgets import QDialog -from PySide6.QtCore import QFile +from PySide6.QtCore import QFile, Qt from PySide6.QtUiTools import QUiLoader +from core.enums import Geometry +from core import config +from core.iterators.composition import ( + CompositionIterator, calculateTotalMolecules +) +from core.iterators.density import DensityIterator +from core.iterators.inelasticity_subtraction import ( + InelasticitySubtraction +) +from core.iterators.radius import RadiusIterator +from core.iterators.thickness import ThicknessIterator +from core.iterators.tweak_factor import TweakFactorIterator + class IterationDialog(QDialog): diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 0b117b21..c3157f82 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -6,15 +6,15 @@ import math from core.composition import Composition, Component -from core.gudrun_file import GudrunFile -from core.iterators.thickness_iterator import ThicknessIterator -from core.iterators.density_iterator import DensityIterator -from core.iterators.tweak_factor_iterator import TweakFactorIterator -from core.iterators.composition_iterator import CompositionIterator from core.gud_file import GudFile -from core.iterators.wavelength_subtraction_iterator import ( - WavelengthSubtractionIterator +from core.gudrun_file import GudrunFile +from core.iterators.composition import CompositionIterator +from core.iterators.density import DensityIterator +from core.iterators.inelasticity_subtraction import ( + InelasticitySubtraction ) +from core.iterators.thickness import ThicknessIterator +from core.iterators.tweak_factor import TweakFactorIterator from core.enums import Format From 0998ff1395c8451e1298e8c177b377408ab9bd87 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:34:41 +0100 Subject: [PATCH 033/165] updated imports --- gudpy/gui/widgets/core/main_window.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index aa822e1a..32b9990c 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -36,13 +36,9 @@ ) from PySide6.QtCharts import QChartView -from core.iterators.iterator import Iterator +from core.container import Container from core.iterators.composition import CompositionIterator -from core.iterators.density import DensityIterator -from core.iterators.radius import RadiusIterator from core.sample import Sample -from core.container import Container -from core.iterators.thickness import ThicknessIterator from gui.widgets.dialogs.export_dialog import ExportDialog from gui.widgets.dialogs.iteration_dialog import ( @@ -98,10 +94,6 @@ from core.gudrun_file import GudrunFile from core.exception import ParserException from core import config -from core.iterators.tweak_factor_iterator import TweakFactorIterator -from core.iterators.wavelength_subtraction_iterator import ( - WavelengthSubtractionIterator -) from core.run_containers_as_samples import RunContainersAsSamples from core.run_individual_files import RunIndividualFiles from core.gud_file import GudFile @@ -122,7 +114,7 @@ class GudPyMainWindow(QMainWindow): GudrunFile object currently associated with the application. clipboard : SampleBackground | Sample | Container Stores copied objects. - iterator : TweakFactorIterator | WavelengthSubtractionIterator + iterator : Iterator | CompositionIterator Iterator to use in iterations. Methods ------- From a92781782132e9e35887959741687505506399bf Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:35:06 +0100 Subject: [PATCH 034/165] Refactored mainwindow.py and fixed process --- gudpy/gui/widgets/core/main_window.py | 73 +++++---------------------- 1 file changed, 14 insertions(+), 59 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 32b9990c..63498826 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -196,7 +196,7 @@ def initComponents(self): loader.registerCustomWidget(CompositionIterationDialog) loader.registerCustomWidget(DensityIterationDialog) loader.registerCustomWidget( - WavelengthInelasticitySubtractionsIterationDialog + InelasticitySubtractionIterationDialog ) loader.registerCustomWidget(RadiusIterationDialog) loader.registerCustomWidget(ThicknessIterationDialog) @@ -362,7 +362,7 @@ def initComponents(self): self.mainWidget.iterateInelasticitySubtractions.triggered.connect( lambda: self.iterateGudrun( - WavelengthInelasticitySubtractionsIterationDialog, + InelasticitySubtractionIterationDialog, "iterateInelasticitySubtractionsDialog", ) ) @@ -1475,7 +1475,7 @@ def errorCompositionIteration(self, output): def progressCompositionIteration(self, currentIteration): progress = ( - currentIteration / self.numberIterations + self.currentIteration / self.numberIterations ) * (self.currentIteration / self.totalIterations) self.mainWidget.progressBar.setValue(int(progress * 100)) @@ -1540,7 +1540,6 @@ def iterateGudrun(self, dialog, name): else: self.queue = iterationDialog.queue self.iterator = iterationDialog.iterator - self.numberIterations = iterationDialog.queue.qsize() - 1 self.currentIteration = 0 self.text = iterationDialog.text self.outputIterations = {} @@ -1554,43 +1553,13 @@ def nextIteration(self): if self.error: self.procFinished(9, QProcess.NormalExit) return - if isinstance(self.iterator, SingleParamIterator): - self.gudrunFile.iterativeOrganise( - self.numberIterations, - self.currentIteration, - self.iterator.name - ) - time.sleep(1) - self.iterator.performIteration(self.currentIteration) - self.gudrunFile.write_out() - self.outputIterations[self.currentIteration + 1] = self.output - self.outputSlots.setOutput( - self.outputIterations, "gudrun_dcs", gudrunFile=self.gudrunFile - ) - if isinstance(self.iterator, WavelengthSubtractionIterator): - if self.queue.qsize() % 2 != 0: - self.iterator.gudrunFile.iterativeOrganise( - self.numberIterations + 1, - self.currentIteration, - "WavelengthIteration" - ) - elif self.queue.qsize(): - self.iterator.gudrunFile.iterativeOrganise( - self.numberIterations, - self.currentIteration, - "QIteration" - ) - self.currentIteration += 1 - else: - self.iterator.gudrunFile.iterativeOrganise( - self.currentIteration, - self.currentIteration, - "QIteration" - ) - self.outputIterations[self.currentIteration + 1] = self.output - else: - self.currentIteration += 1 - + self.iterator.organiseOutput() + self.iterator.performIteration() + self.gudrunFile.write_out() + self.outputIterations[self.iterator.nCurrent] = self.output + self.outputSlots.setOutput( + self.outputIterations, "gudrun_dcs", gudrunFile=self.gudrunFile + ) if not self.queue.empty(): self.nextIterableProc() else: @@ -1608,11 +1577,6 @@ def nextIterableProc(self): self.proc.setWorkingDirectory( self.gudrunFile.instrument.GudrunInputFileDir ) - if isinstance(self.iterator, WavelengthSubtractionIterator): - if self.queue.qsize() % 2 == 0: - self.iterator.wavelengthIteration(self.currentIteration) - else: - self.iterator.QIteration(self.currentIteration) if func: func(*args) self.proc.start() @@ -1620,8 +1584,8 @@ def nextIterableProc(self): def iterationStarted(self): self.mainWidget.currentTaskLabel.setText( f"{self.text}" - f" {(self.numberIterations + 1) - self.queue.qsize()}" - + f"/{self.numberIterations + 1}" + f" {self.iterator.nCurrent + 1}" + + f"/{self.iterator.nTotal}" ) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() @@ -1633,7 +1597,7 @@ def progressIteration(self): f" from gudrun_dcs\n{self.error}" ) return - progress /= self.numberIterations + progress /= self.iterator.nTotal progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( progress if progress <= 100 else 100 @@ -1940,18 +1904,9 @@ def runGudrunFinished(self, ec, es, gudrunFile=None): def procFinished(self, ec, es): self.proc = None output = self.output - if isinstance( - self.iterator, - ( - TweakFactorIterator, - ThicknessIterator, - RadiusIterator, - DensityIterator, - ), - ): + if self.iterator: self.outputIterations[self.currentIteration + 1] = self.output self.sampleSlots.setSample(self.sampleSlots.sample) - if self.iterator: output = self.outputIterations self.iterator = None if self.error: From 7312f4c06894d9223917270b48e06bf559a84df5 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:35:31 +0100 Subject: [PATCH 035/165] Moved dialogs to one module --- gudpy/gui/widgets/dialogs/iteration_dialog.py | 226 ++++++++++++++++++ 1 file changed, 226 insertions(+) diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index bd478b98..cce8c462 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -77,3 +77,229 @@ def enqueueTasks(self): "gudpy.txt" ), headless=False) ) + + +class DensityIterationDialog(IterationDialog): + + def iterate(self): + self.iterator = DensityIterator(self.gudrunFile, self.numberIterations) + self.enqueueTasks() + self.text = "Iterate by Density" + self.widget.close() + + +class InelasticitySubtractionIterationDialog(IterationDialog): + + def iterate(self): + self.iterator = InelasticitySubtraction( + self.gudrunFile, self.numberIterations * 2) + self.enqueueTasks() + self.text = "Inelasticity subtractions" + self.widget.close() + + def enqueueTasks(self): + self.queue = Queue() + for _ in range((self.numberIterations * 2)): + self.queue.put( + self.iterator.gudrunFile.dcs( + path=os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + "gudpy.txt" + ), headless=False) + ) + + +class RadiusIterationDialog(IterationDialog): + + def initComponents(self): + super().initComponents() + self.widget.iterateButton.setEnabled( + config.geometry == Geometry.CYLINDRICAL + ) + + def iterate(self): + self.iterator = RadiusIterator(self.gudrunFile, self.numberIterations) + self.iterator.setTargetRadius("inner") + self.enqueueTasks() + self.text = "Iterate by Radius" + self.widget.close() + + +class ThicknessIterationDialog(IterationDialog): + + def initComponents(self): + super().initComponents() + self.widget.iterateButton.setEnabled( + config.geometry == Geometry.FLATPLATE + ) + + def iterate(self): + self.iterator = ThicknessIterator( + self.gudrunFile, self.numberIterations) + self.enqueueTasks() + self.text = "Iterate by Thickness" + self.widget.close() + + +class TweakFactorIterationDialog(IterationDialog): + + def iterate(self): + self.iterator = TweakFactorIterator( + self.gudrunFile, self.numberIterations) + self.enqueueTasks() + self.text = "Iterate by Tweak Factor" + self.widget.close() + + +class CompositionIterationDialog(IterationDialog): + + def __init__(self, name, gudrunFile, parent): + self.components = [None, None] + self.rtol = 0. + super().__init__(name, gudrunFile, parent) + + def loadFirstComponentsComboBox(self): + self.widget.firstComponentComboBox.clear() + for component in self.gudrunFile.components.components: + self.widget.firstComponentComboBox.addItem( + component.name, component + ) + self.components[0] = self.gudrunFile.components.components[0] + + def loadSecondComponentsComboBox(self): + self.widget.secondComponentComboBox.clear() + for component in self.gudrunFile.components.components: + self.widget.secondComponentComboBox.addItem( + component.name, component + ) + + def firstComponentChanged(self, index): + self.components[0] = self.widget.firstComponentComboBox.itemData(index) + other = self.widget.secondComponentComboBox.model().item(index) + self.setItemDisabled( + self.widget.secondComponentComboBox, + other + ) + + def secondComponentChanged(self, index): + self.components[1] = ( + self.widget.secondComponentComboBox.itemData(index) + ) + other = self.widget.firstComponentComboBox.model().item(index) + self.setItemDisabled( + self.widget.firstComponentComboBox, + other + ) + + def compositionRtolChanged(self, value): + self.rtol = value + + def enableItems(self, comboBox): + for i in range(len(self.gudrunFile.components.components)): + item = comboBox.model().item(i) + if item: + item.setFlags( + item.flags() | Qt.ItemIsEnabled + ) + + def setItemDisabled(self, comboBox, item): + self.enableItems(comboBox) + if item: + item.setFlags(item.flags() & ~Qt.ItemIsEnabled) + + def toggleUseSingleComponent(self, state): + if state: + self.enableItems(self.widget.firstComponentComboBox) + self.components[1] = None + else: + other = self.widget.secondComponentComboBox.model().item( + self.widget.firstComponentComboBox.currentIndex() + ) + self.setItemDisabled( + self.widget.secondComponentComboBox, + other + ) + self.widget.secondComponentComboBox.setEnabled(not state) + self.widget.secondComponentComboBox.setCurrentIndex(-1) + + def initComponents(self): + super().initComponents() + self.widget.firstComponentComboBox.currentIndexChanged.connect( + self.firstComponentChanged + ) + self.widget.secondComponentComboBox.currentIndexChanged.connect( + self.secondComponentChanged + ) + self.widget.secondComponentComboBox.setCurrentIndex(-1) + + self.widget.compositionToleranceSpinBox.valueChanged.connect( + self.compositionRtolChanged + ) + self.widget.singleComponentCheckBox.toggled.connect( + self.toggleUseSingleComponent + ) + if len(self.gudrunFile.components.components): + + self.loadFirstComponentsComboBox() + self.loadSecondComponentsComboBox() + self.toggleUseSingleComponent(True) + else: + self.widget.iterateButton.setEnabled(False) + + def iterate(self): + self.iterator = CompositionIterator(self.gudrunFile) + self.iterator.setComponents(self.components) + self.queue = Queue() + for sampleBackground in self.gudrunFile.sampleBackgrounds: + for sample in sampleBackground.samples: + if sample.runThisSample: + if [ + wc for wc in sample.composition.weightedComponents + if self.components[0].eq(wc.component) + ]: + sb = deepcopy(sampleBackground) + sb.samples = [deepcopy(sample)] + if len(self.iterator.components) == 1: + self.queue.put( + ( + ( + [1e-2, self.iterator.ratio, 10], + 0, + self.numberIterations, + self.rtol + ), + { + "args": ( + self.gudrunFile, + sb, + self.iterator.components + ) + }, + sample + ) + ) + elif len(self.iterator.components) == 2: + self.queue.put( + ( + ( + [1e-2, self.iterator.ratio, 10], + 0, + self.numberIterations, + self.rtol + ), + { + "args": ( + self.gudrunFile, + sb, + self.iterator.components, + calculateTotalMolecules( + self.iterator.components, + sample + ) + ) + }, + sample + ) + ) + self.text = "Iterate by Composition" + self.widget.close() From 0307a1137b0135ea60c04e4a69699543aec7a6a4 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:35:51 +0100 Subject: [PATCH 036/165] Applied new changes to test --- gudpy/test/test_gudpy_workflows.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index c3157f82..a5c0d750 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -6,15 +6,15 @@ import math from core.composition import Composition, Component -from core.gud_file import GudFile from core.gudrun_file import GudrunFile -from core.iterators.composition import CompositionIterator +from core.iterators.thickness import ThicknessIterator from core.iterators.density import DensityIterator +from core.iterators.tweak_factor import TweakFactorIterator +from core.iterators.composition import CompositionIterator +from core.gud_file import GudFile from core.iterators.inelasticity_subtraction import ( InelasticitySubtraction ) -from core.iterators.thickness import ThicknessIterator -from core.iterators.tweak_factor import TweakFactorIterator from core.enums import Format @@ -131,8 +131,8 @@ def testGudPyDCS(self): def testGudPyIterateByTweakFactor(self): self.g.purge() - tweakFactorIterator = TweakFactorIterator(self.g) - tweakFactorIterator.iterate(5) + tweakFactorIterator = TweakFactorIterator(self.g, 5) + tweakFactorIterator.iterate() gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') @@ -181,8 +181,8 @@ def testGudPyIterateByTweakFactor(self): def testGudPyIterateByThickness(self): self.g.purge() - thicknessIterator = ThicknessIterator(self.g) - thicknessIterator.iterate(5) + thicknessIterator = ThicknessIterator(self.g, 5) + thicknessIterator.iterate() gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') @@ -231,8 +231,8 @@ def testGudPyIterateByThickness(self): def testGudPyIterateByDensity(self): self.g.purge() - densityIterator = DensityIterator(self.g) - densityIterator.iterate(5) + densityIterator = DensityIterator(self.g, 5) + densityIterator.iterate() gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') @@ -281,8 +281,8 @@ def testGudPyIterateByDensity(self): def testIterateByThickness(self): self.g.purge() - thicknessIterator = ThicknessIterator(self.g) - thicknessIterator.iterate(5) + thicknessIterator = ThicknessIterator(self.g, 5) + thicknessIterator.iterate() gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') @@ -365,10 +365,10 @@ def testGudPyIterateBySubtractingWavelength(self): for i in range(1, 4): self.g.purge() - wavelengthSubtractionIterator = ( - WavelengthSubtractionIterator(self.g) + inelasitictyIterator = ( + InelasticitySubtraction(self.g, i) ) - wavelengthSubtractionIterator.iterate(i) + inelasitictyIterator.iterate() for sample in [ x From 8e8e4cd0cd705eb690a2f06b6bd10e0be35aeff3 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:38:26 +0100 Subject: [PATCH 037/165] Removed unecessary parameter --- gudpy/core/gudrun_file.py | 2 +- gudpy/core/output_file_handler.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 32c2c34b..72318b02 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1653,7 +1653,7 @@ def naiveOrganise(self): def iterativeOrganise(self, nTotal, nCurrent, head): if nCurrent == 0: self.outputFileHandler = OutputFileHandler(self) - self.outputFileHandler.iterativeOrganise(nTotal, nCurrent, head) + self.outputFileHandler.iterativeOrganise(nCurrent, head) if nCurrent == nTotal - 1: del self.outputFileHandler diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 0f2626d9..f4b9a13e 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -183,7 +183,7 @@ def naiveOrganise(self): uniquify(os.path.join(self.outputDir, folder)) ) - def iterativeOrganise(self, nTotal, nCurrent, head): + def iterativeOrganise(self, nCurrent, head): """ Organises Gudrun outputs when it is run iteratively From 23528c8fe967140720b04b8f2ee5337d73023e35 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 13:43:44 +0100 Subject: [PATCH 038/165] removed unecessary import --- gudpy/gui/widgets/core/main_window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 63498826..cdaeee08 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1,7 +1,6 @@ from abc import abstractmethod import os import sys -import time import math import traceback import tempfile From 8ff5281da3d6d2b6302b17b351c9207ea0950aeb Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 13 Oct 2023 16:26:25 +0100 Subject: [PATCH 039/165] Changed the way outputs work- directory now overwrites --- gudpy/core/gudrun_file.py | 5 +- gudpy/core/output_file_handler.py | 212 ++++++++++++------------------ 2 files changed, 88 insertions(+), 129 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 72318b02..cb19587a 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1651,11 +1651,8 @@ def naiveOrganise(self): outputFileHandler.naiveOrganise() def iterativeOrganise(self, nTotal, nCurrent, head): - if nCurrent == 0: - self.outputFileHandler = OutputFileHandler(self) + self.outputFileHandler = OutputFileHandler(self) self.outputFileHandler.iterativeOrganise(nCurrent, head) - if nCurrent == nTotal - 1: - del self.outputFileHandler def determineError(self, sample): gudPath = sample.dataFiles[0].replace( diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index f4b9a13e..f916d4d8 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -12,11 +12,9 @@ def __init__(self, gudrunFile): # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir # Temporary output dir paths - self.tempOutDir = { - "root": os.path.join(self.gudrunDir, "out"), - "samps": [], - "add": "" - } + self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( + self.gudrunFile.filename)[0]) + self.samplePaths = [] # Name the output directory as the input file self.outputDir = os.path.join( self.gudrunFile.inputFileDir, @@ -47,52 +45,77 @@ def __init__(self, gudrunFile): s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles)]: self.samples.append(sample) - # Generate unique paths for sample output directories - self.tempOutDir["samps"].append( - os.path.join( - self.tempOutDir["root"], - uniquify(os.path.join( - self.outputDir, - sample.name - )).partition(self.outputDir + "/")[-1] - ) - ) - # Generate unique path for Additional Outputs folder - self.tempOutDir["add"] = os.path.join( - self.tempOutDir["root"], - uniquify(os.path.join( - self.outputDir, - "AdditionalOutputs" - )).partition(self.outputDir + "/")[-1] - ) - def createNormDir(self, outputDir): + def naiveOrganise(self): + """Organises Gudrun outputs + """ + # Create normalisation and sample background folders + self.createNormDir(self.tempOutDir) + self.createSampleBgDir(self.tempOutDir) + # Create sample folders + self.createSampleDir(self.tempOutDir) + # Create additonal output folders + self.createAddOutDir(self.tempOutDir) + # Move over samples to output directory + self.exportTempDir() + + def iterativeOrganise(self, nCurrent, head): + """ + Organises Gudrun outputs when it is run + iteratively + + Parameters + ---------- + nTotal : int + Total number of iterations + nCurrent : int + Current iteration + head : str + Intended basename for folders + which gets incremented per iteration + """ + iterName = f"{head}_{nCurrent + 1}" + iterDir = os.path.join(self.tempOutDir, iterName) + + # Create the normalisation and sample background directories + # if this is the first iteration + self.createNormDir(iterDir) + self.createSampleBgDir(iterDir) + + # Create the sample output folders + self.createSampleDir(iterDir) + + self.createAddOutDir(iterDir) + + self.exportTempDir() + + def createNormDir(self, targetDir): """ Creates directories for normalisation background and normalisation outputs. Parameters ---------- - outputDir : str + targetDir : str Path to target output directory """ # Create normalisation folders and move datafiles for normFile in self.gudrunFile.normalisation.dataFiles: self.copyOutputs( normFile, os.path.join( - outputDir, "Normalisation")) + targetDir, "Normalisation")) for normBgFile in self.gudrunFile.normalisation.dataFilesBg: self.copyOutputs(normBgFile, - os.path.join(outputDir, + os.path.join(targetDir, "NormalisationBackground")) - def createSampleBgDir(self, outputDir): + def createSampleBgDir(self, targetDir): """ Creates output directory for sample backgrounds Parameters ---------- - outputDir : str + targetDir : str Path to target output directory """ # Iterate through all sample backgrounds @@ -104,17 +127,17 @@ def createSampleBgDir(self, outputDir): self.copyOutputs( dataFile, os.path.join( - outputDir, "SampleBackgrounds", + targetDir, "SampleBackgrounds", f"SampleBackground{count + 1}") ) - def createSampleDir(self, outputDir, tree=""): + def createSampleDir(self, targetDir): """ Creates output directory for each sample Parameters ---------- - outputDir : str + targetDir : str Path to target output directory samples : Sample[] List of samples in a sample background @@ -126,16 +149,10 @@ def createSampleDir(self, outputDir, tree=""): """ # Create sample folders within background folders for sample in self.samples: - if tree: - samplePath = os.path.join( - outputDir, - sample.name, - tree) - else: - samplePath = uniquify(os.path.join( - outputDir, - sample.name - )) + samplePath = uniquify(os.path.join( + targetDir, + sample.name + )) # Move datafiles to sample folder for dataFile in sample.dataFiles: self.copyOutputsByExt( @@ -145,7 +162,6 @@ def createSampleDir(self, outputDir, tree=""): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): - makeDir(samplePath) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) @@ -165,75 +181,41 @@ def createSampleDir(self, outputDir, tree=""): containerPath ) - def naiveOrganise(self): - """Organises Gudrun outputs + def createAddOutDir(self, targetDir): """ - # Create normalisation and sample background folders - self.createNormDir(self.outputDir) - self.createSampleBgDir(self.outputDir) - # Create sample folders - self.createSampleDir( - self.tempOutDir["root"]) - # Copy remaining outputs - self.copyRemaining(self.tempOutDir["add"]) - # Move over sample & additional outputs to output directory - for folder in os.listdir(self.tempOutDir["root"]): - shutil.move( - os.path.join(self.tempOutDir["root"], folder), - uniquify(os.path.join(self.outputDir, folder)) - ) - - def iterativeOrganise(self, nCurrent, head): - """ - Organises Gudrun outputs when it is run - iteratively + Copy over all files that haven't been copied over, + as specified in `copiedFiles` Parameters ---------- - nTotal : int - Total number of iterations - nCurrent : int - Current iteration - head : str - Intended basename for folders - which gets incremented per iteration + targetDir : str + Directory for the files to be copied to """ - iterName = f"{head}_{nCurrent + 1}" - - if nCurrent == 0: - # Create the normalisation and sample background directories - # if this is the first iteration - self.createNormDir(self.outputDir) - self.createSampleBgDir( - self.outputDir) - for sampleDir in self.tempOutDir["samps"]: - makeDir(sampleDir) - - # Create the sample output folders - self.createSampleDir( - self.gudrunDir, - iterName) + addDir = makeDir(os.path.join(targetDir, "AdditionalOutputs")) - self.copyRemaining(os.path.join( - self.tempOutDir["add"], - iterName)) + for f in os.listdir(self.gudrunDir): + if f == self.gudrunFile.outpath: + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(targetDir, f) + ) + elif f not in self.copiedFiles and os.path.isfile( + os.path.join(self.gudrunDir, f)): + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(addDir, f) + ) - # Copy organised folder to temporary sample output dir - for sample, sampleOutDir in zip( - self.samples, self.tempOutDir["samps"]): - shutil.move( - os.path.join( - self.gudrunDir, - sample.name, - iterName), - sampleOutDir - ) - # Move over sample & additional outputs to output directory - for folder in os.listdir(self.tempOutDir["root"]): - shutil.move( - os.path.join(self.tempOutDir["root"], folder, iterName), - os.path.join(self.outputDir, folder, iterName) - ) + def exportTempDir(self): + """ + Copy temp dir into user's directory + Overwrites if directory already exists + """ + shutil.copytree( + os.path.join(self.tempOutDir), + os.path.join(self.outputDir), + dirs_exist_ok=True + ) def copyOutputs(self, fpath, targetDir): """ @@ -301,23 +283,3 @@ def copyOutputsByExt(self, fname, targetDir): os.path.join(dir, f) ) self.copiedFiles.append(f) - - def copyRemaining(self, targetDir): - """ - Copy over all files that haven't been copied over, - as specified in `copiedFiles` - - Parameters - ---------- - targetDir : str - Directory for the files to be copied to - """ - makeDir(targetDir) - - for f in os.listdir(self.gudrunDir): - if f not in self.copiedFiles and os.path.isfile( - os.path.join(self.gudrunDir, f)): - shutil.copyfile( - os.path.join(self.gudrunDir, f), - os.path.join(targetDir, f) - ) From 8b7cc4cde60f898c9f8fc631c5800ebeda70a74d Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 16 Oct 2023 10:11:54 +0100 Subject: [PATCH 040/165] Removed uneeded parameter --- gudpy/core/iterators/inelasticity_subtraction.py | 2 +- gudpy/core/iterators/iterator.py | 2 +- gudpy/core/run_batch_files.py | 6 +----- gudpy/gui/widgets/core/main_window.py | 1 - 4 files changed, 3 insertions(+), 8 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 70a7b18a..f7bf0ceb 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -262,4 +262,4 @@ def iterate(self): self.gudrunFile.process(iterative=True) time.sleep(1) self.gudrunFile.iterativeOrganise( - self.nTotal, self.nCurrent, self.iterationType) + self.nCurrent, self.iterationType) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 6b1220cf..08b9cf97 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -104,7 +104,7 @@ def organiseOutput(self): Current iteration """ self.gudrunFile.iterativeOrganise( - self.nTotal, self.nCurrent, self.name) + self.nCurrent, self.name) def iterate(self): """ diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index 4d8ff98a..6545f082 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -169,7 +169,6 @@ def process( initial.process(headless=headless) iterator.performIteration(i) initial.iterativeOrganise( - maxIterations - 1, i, os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -201,7 +200,6 @@ def process( iterator.performIteration(i) self.batchedGudrunFile.iterativeOrganise( os.path.join( - maxIterations - 1, i, self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", @@ -233,7 +231,7 @@ def process( tasks.append( [ self.batchedGudrunFile.iterativeOrganise, - [0, 0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], + [0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], ] ) tasks.append( @@ -268,7 +266,6 @@ def process( [ initial.iterativeOrganise, [ - maxIterations - 1, i, os.path.join( initial.GudrunInputFileDir, @@ -324,7 +321,6 @@ def process( [ self.batchedGudrunFile.iterativeOrganise, [ - maxIterations - 1, i, os.path.join( f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}", diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index cdaeee08..2cae9412 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1492,7 +1492,6 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) self.gudrunFile.iterativeOrganise( - self.numberIterations - 1, self.currentIteration, self.iterator.name) self.currentIteration += 1 From e744d42de998755e20490864800eb8e7076350fa Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 16 Oct 2023 10:53:26 +0100 Subject: [PATCH 041/165] Removing previous output dir if exists --- gudpy/core/output_file_handler.py | 77 ++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 28 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index f916d4d8..b3d10973 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -1,6 +1,7 @@ import os import shutil from core.utils import makeDir, uniquify +import tempfile class OutputFileHandler(): @@ -46,6 +47,12 @@ def __init__(self, gudrunFile): if s.runThisSample and len(s.dataFiles)]: self.samples.append(sample) + # If output directory exists, move to a temp dir and clear it + # Avoids shutil.rmtree + if os.path.exists(self.outputDir): + with tempfile.TemporaryDirectory() as tmp: + shutil.move(self.outputDir, os.path.join(tmp.name, "prev")) + def naiveOrganise(self): """Organises Gudrun outputs """ @@ -89,33 +96,33 @@ def iterativeOrganise(self, nCurrent, head): self.exportTempDir() - def createNormDir(self, targetDir): + def createNormDir(self, dest): """ Creates directories for normalisation background and normalisation outputs. Parameters ---------- - targetDir : str + dest : str Path to target output directory """ # Create normalisation folders and move datafiles for normFile in self.gudrunFile.normalisation.dataFiles: self.copyOutputs( normFile, os.path.join( - targetDir, "Normalisation")) + dest, "Normalisation")) for normBgFile in self.gudrunFile.normalisation.dataFilesBg: self.copyOutputs(normBgFile, - os.path.join(targetDir, + os.path.join(dest, "NormalisationBackground")) - def createSampleBgDir(self, targetDir): + def createSampleBgDir(self, dest): """ Creates output directory for sample backgrounds Parameters ---------- - targetDir : str + dest : str Path to target output directory """ # Iterate through all sample backgrounds @@ -127,17 +134,17 @@ def createSampleBgDir(self, targetDir): self.copyOutputs( dataFile, os.path.join( - targetDir, "SampleBackgrounds", + dest, "SampleBackgrounds", f"SampleBackground{count + 1}") ) - def createSampleDir(self, targetDir): + def createSampleDir(self, dest): """ Creates output directory for each sample Parameters ---------- - targetDir : str + dest : str Path to target output directory samples : Sample[] List of samples in a sample background @@ -150,7 +157,7 @@ def createSampleDir(self, targetDir): # Create sample folders within background folders for sample in self.samples: samplePath = uniquify(os.path.join( - targetDir, + dest, sample.name )) # Move datafiles to sample folder @@ -181,23 +188,23 @@ def createSampleDir(self, targetDir): containerPath ) - def createAddOutDir(self, targetDir): + def createAddOutDir(self, dest): """ Copy over all files that haven't been copied over, as specified in `copiedFiles` Parameters ---------- - targetDir : str + dest : str Directory for the files to be copied to """ - addDir = makeDir(os.path.join(targetDir, "AdditionalOutputs")) + addDir = makeDir(os.path.join(dest, "AdditionalOutputs")) for f in os.listdir(self.gudrunDir): if f == self.gudrunFile.outpath: shutil.copyfile( os.path.join(self.gudrunDir, f), - os.path.join(targetDir, f) + os.path.join(dest, f) ) elif f not in self.copiedFiles and os.path.isfile( os.path.join(self.gudrunDir, f)): @@ -206,18 +213,32 @@ def createAddOutDir(self, targetDir): os.path.join(addDir, f) ) - def exportTempDir(self): + def exportDir(self, src, dest): """ - Copy temp dir into user's directory - Overwrites if directory already exists + Copy moves directory `src` to `dest` if it exists + + Parameters + ---------- + src : str + Path to target directory + dest : str + Directory for the directory to be moved to + + Returns + ------- + Path where `src` is now located """ - shutil.copytree( - os.path.join(self.tempOutDir), - os.path.join(self.outputDir), - dirs_exist_ok=True - ) - def copyOutputs(self, fpath, targetDir): + if os.path.exists(src): + shutil.move( + os.path.join(src), + os.path.join(dest) + ) + return dest + else: + return src + + def copyOutputs(self, fpath, dest): """ Copy all files with the same basename as the provided filepath, except the original file. @@ -228,11 +249,11 @@ def copyOutputs(self, fpath, targetDir): ---------- fpath : str Full filename of target file - targetDir : str + dest : str Directory for the files to be copied to """ fname = os.path.splitext(fpath)[0] - runDir = os.path.join(targetDir, fname) + runDir = os.path.join(dest, fname) dirCreated = False for f in os.listdir(self.gudrunDir): # Get files with the same filename but not the same @@ -247,7 +268,7 @@ def copyOutputs(self, fpath, targetDir): ) self.copiedFiles.append(f) - def copyOutputsByExt(self, fname, targetDir): + def copyOutputsByExt(self, fname, dest): """ Copy all files with the same basename as the provided filepath and splits them into outputs @@ -261,13 +282,13 @@ def copyOutputsByExt(self, fname, targetDir): Full filename of target file suffixes : str[] List of target file extenstions - targetDir : str + dest : str Directory for the files to be copied to """ # Data filename fname = os.path.splitext(fname)[0] # Path to folder which will hold all outputs from the run - runDir = os.path.join(targetDir, fname) + runDir = os.path.join(dest, fname) # Path to folder which will hold Gudrun outputs outDir = makeDir(os.path.join(runDir, "Outputs")) # Path to folder which will hold Gudrun diagnostic outputs From 0f6666d2fffac48f246c01df48b212db37f4a02a Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 16 Oct 2023 11:49:42 +0100 Subject: [PATCH 042/165] Combined naive organise and iterative into one function, changed the way files are moved over --- gudpy/core/gudrun_file.py | 12 +-- .../iterators/inelasticity_subtraction.py | 2 +- gudpy/core/iterators/iterator.py | 2 +- gudpy/core/output_file_handler.py | 93 +++++++------------ gudpy/core/run_batch_files.py | 10 +- gudpy/gui/widgets/core/main_window.py | 6 +- 6 files changed, 46 insertions(+), 79 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index cb19587a..d17cb9e4 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1561,7 +1561,7 @@ def dcs(self, path='', headless=True, iterative=False): os.chdir(cwd) return False if not iterative: - self.naiveOrganise() + self.organiseOutputs() return result else: if hasattr(sys, '_MEIPASS'): @@ -1646,13 +1646,9 @@ def convertToSample(self, container, persist=False): self.sampleBackgrounds[i].append(sample) return sample - def naiveOrganise(self): - outputFileHandler = OutputFileHandler(self) - outputFileHandler.naiveOrganise() - - def iterativeOrganise(self, nTotal, nCurrent, head): - self.outputFileHandler = OutputFileHandler(self) - self.outputFileHandler.iterativeOrganise(nCurrent, head) + def organiseOutput(self, nCurrent=0, head=""): + self.outputFileHandler = OutputFileHandler(self, nCurrent) + self.outputFileHandler.organiseOutput() def determineError(self, sample): gudPath = sample.dataFiles[0].replace( diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index f7bf0ceb..fe2c6f7f 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -261,5 +261,5 @@ def iterate(self): self.performIteration() self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.iterativeOrganise( + self.gudrunFile.organiseOutputs( self.nCurrent, self.iterationType) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 08b9cf97..e23aa58b 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -103,7 +103,7 @@ def organiseOutput(self): nCurrent : int Current iteration """ - self.gudrunFile.iterativeOrganise( + self.gudrunFile.organiseOutputs( self.nCurrent, self.name) def iterate(self): diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index b3d10973..f6f03060 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -6,7 +6,19 @@ class OutputFileHandler(): - def __init__(self, gudrunFile): + def __init__(self, gudrunFile, nCurrent=0, head=""): + """ + Initialise `OutputFileHandler` + + Parameters + ---------- + gudrunFile : GudrunFile + Gudrun file object that defines run parameters + nCurrent : int, optional + Current iteration number by default 0 + head : str, optional + Iterator type, by default "" + """ self.gudrunFile = gudrunFile # List of run samples self.samples = [] @@ -15,7 +27,10 @@ def __init__(self, gudrunFile): # Temporary output dir paths self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( self.gudrunFile.filename)[0]) - self.samplePaths = [] + if head: + self.tempOutDir = os.path.join( + self.tempOutDir, f"{head}_{nCurrent + 1}") + # Name the output directory as the input file self.outputDir = os.path.join( self.gudrunFile.inputFileDir, @@ -49,11 +64,11 @@ def __init__(self, gudrunFile): # If output directory exists, move to a temp dir and clear it # Avoids shutil.rmtree - if os.path.exists(self.outputDir): + if nCurrent == 0 and os.path.exists(self.outputDir): with tempfile.TemporaryDirectory() as tmp: shutil.move(self.outputDir, os.path.join(tmp.name, "prev")) - def naiveOrganise(self): + def organiseOutput(self): """Organises Gudrun outputs """ # Create normalisation and sample background folders @@ -63,38 +78,19 @@ def naiveOrganise(self): self.createSampleDir(self.tempOutDir) # Create additonal output folders self.createAddOutDir(self.tempOutDir) - # Move over samples to output directory - self.exportTempDir() - - def iterativeOrganise(self, nCurrent, head): - """ - Organises Gudrun outputs when it is run - iteratively - - Parameters - ---------- - nTotal : int - Total number of iterations - nCurrent : int - Current iteration - head : str - Intended basename for folders - which gets incremented per iteration - """ - iterName = f"{head}_{nCurrent + 1}" - iterDir = os.path.join(self.tempOutDir, iterName) - - # Create the normalisation and sample background directories - # if this is the first iteration - self.createNormDir(iterDir) - self.createSampleBgDir(iterDir) - - # Create the sample output folders - self.createSampleDir(iterDir) - - self.createAddOutDir(iterDir) - - self.exportTempDir() + # Move over folders to output directory + makeDir(self.outputDir) + for (root, dirs, files) in os.listdir(self.tempOutDir): + r = os.path.join( + self.gudrunFile.inputFileDir, + root.partition(self.gudrunDir)[-1]) + for d in dirs: + makeDir(os.path.join(r, d)) + for f in files: + shutil.copyfile( + os.path.join(root, f), + os.path.join(r, f) + ) def createNormDir(self, dest): """ @@ -213,31 +209,6 @@ def createAddOutDir(self, dest): os.path.join(addDir, f) ) - def exportDir(self, src, dest): - """ - Copy moves directory `src` to `dest` if it exists - - Parameters - ---------- - src : str - Path to target directory - dest : str - Directory for the directory to be moved to - - Returns - ------- - Path where `src` is now located - """ - - if os.path.exists(src): - shutil.move( - os.path.join(src), - os.path.join(dest) - ) - return dest - else: - return src - def copyOutputs(self, fpath, dest): """ Copy all files with the same basename diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index 6545f082..2873003a 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -168,7 +168,7 @@ def process( for i in range(maxIterations): initial.process(headless=headless) iterator.performIteration(i) - initial.iterativeOrganise( + initial.organiseOutputs( i, os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -198,7 +198,7 @@ def process( for i in range(maxIterations): self.batchedGudrunFile.process(headless=headless) iterator.performIteration(i) - self.batchedGudrunFile.iterativeOrganise( + self.batchedGudrunFile.organiseOutputs( os.path.join( i, self.gudrunFile.instrument.GudrunInputFileDir, @@ -230,7 +230,7 @@ def process( ) tasks.append( [ - self.batchedGudrunFile.iterativeOrganise, + self.batchedGudrunFile.organiseOutputs, [0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], ] ) @@ -264,7 +264,7 @@ def process( tasks.append([iterator.performIteration, [i]]) tasks.append( [ - initial.iterativeOrganise, + initial.organiseOutputs, [ i, os.path.join( @@ -319,7 +319,7 @@ def process( tasks.append([iterator.performIteration, [i]]) tasks.append( [ - self.batchedGudrunFile.iterativeOrganise, + self.batchedGudrunFile.organiseOutputs, [ i, os.path.join( diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 2cae9412..9396f779 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1491,7 +1491,7 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.gudrunFile.iterativeOrganise( + self.gudrunFile.organiseOutputs( self.currentIteration, self.iterator.name) self.currentIteration += 1 @@ -1894,9 +1894,9 @@ def procStarted(self): def runGudrunFinished(self, ec, es, gudrunFile=None): if gudrunFile: - gudrunFile.naiveOrganise() + gudrunFile.organiseOutputs() else: - self.gudrunFile.naiveOrganise() + self.gudrunFile.organiseOutputs() self.procFinished(ec, es) def procFinished(self, ec, es): From c77dff6698480e1861edd7767f527464e259c1b1 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 16 Oct 2023 11:55:21 +0100 Subject: [PATCH 043/165] Fixed spelling --- gudpy/core/gudrun_file.py | 2 +- gudpy/core/iterators/inelasticity_subtraction.py | 2 +- gudpy/core/iterators/iterator.py | 2 +- gudpy/core/run_batch_files.py | 10 +++++----- gudpy/gui/widgets/core/main_window.py | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index d17cb9e4..bf10da15 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1561,7 +1561,7 @@ def dcs(self, path='', headless=True, iterative=False): os.chdir(cwd) return False if not iterative: - self.organiseOutputs() + self.organiseOutput() return result else: if hasattr(sys, '_MEIPASS'): diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index fe2c6f7f..2779af83 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -261,5 +261,5 @@ def iterate(self): self.performIteration() self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.organiseOutputs( + self.gudrunFile.organiseOutput( self.nCurrent, self.iterationType) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index e23aa58b..1c48846e 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -103,7 +103,7 @@ def organiseOutput(self): nCurrent : int Current iteration """ - self.gudrunFile.organiseOutputs( + self.gudrunFile.organiseOutput( self.nCurrent, self.name) def iterate(self): diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index 2873003a..c1febe43 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -168,7 +168,7 @@ def process( for i in range(maxIterations): initial.process(headless=headless) iterator.performIteration(i) - initial.organiseOutputs( + initial.organiseOutput( i, os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, @@ -198,7 +198,7 @@ def process( for i in range(maxIterations): self.batchedGudrunFile.process(headless=headless) iterator.performIteration(i) - self.batchedGudrunFile.organiseOutputs( + self.batchedGudrunFile.organiseOutput( os.path.join( i, self.gudrunFile.instrument.GudrunInputFileDir, @@ -230,7 +230,7 @@ def process( ) tasks.append( [ - self.batchedGudrunFile.organiseOutputs, + self.batchedGudrunFile.organiseOutput, [0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], ] ) @@ -264,7 +264,7 @@ def process( tasks.append([iterator.performIteration, [i]]) tasks.append( [ - initial.organiseOutputs, + initial.organiseOutput, [ i, os.path.join( @@ -319,7 +319,7 @@ def process( tasks.append([iterator.performIteration, [i]]) tasks.append( [ - self.batchedGudrunFile.organiseOutputs, + self.batchedGudrunFile.organiseOutput, [ i, os.path.join( diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 9396f779..2ed6c46d 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1491,7 +1491,7 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.gudrunFile.organiseOutputs( + self.gudrunFile.organiseOutput( self.currentIteration, self.iterator.name) self.currentIteration += 1 @@ -1894,9 +1894,9 @@ def procStarted(self): def runGudrunFinished(self, ec, es, gudrunFile=None): if gudrunFile: - gudrunFile.organiseOutputs() + gudrunFile.organiseOutput() else: - self.gudrunFile.organiseOutputs() + self.gudrunFile.organiseOutput() self.procFinished(ec, es) def procFinished(self, ec, es): From ea85559c9d279b2c134eb50dc2014603756867e0 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 16 Oct 2023 14:23:38 +0100 Subject: [PATCH 044/165] Fixed issues, works as expected now --- gudpy/core/gudrun_file.py | 2 +- gudpy/core/output_file_handler.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index bf10da15..43db2f57 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1647,7 +1647,7 @@ def convertToSample(self, container, persist=False): return sample def organiseOutput(self, nCurrent=0, head=""): - self.outputFileHandler = OutputFileHandler(self, nCurrent) + self.outputFileHandler = OutputFileHandler(self, nCurrent, head) self.outputFileHandler.organiseOutput() def determineError(self, sample): diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index f6f03060..a89b65b5 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -66,7 +66,7 @@ def __init__(self, gudrunFile, nCurrent=0, head=""): # Avoids shutil.rmtree if nCurrent == 0 and os.path.exists(self.outputDir): with tempfile.TemporaryDirectory() as tmp: - shutil.move(self.outputDir, os.path.join(tmp.name, "prev")) + shutil.move(self.outputDir, os.path.join(tmp, "prev")) def organiseOutput(self): """Organises Gudrun outputs @@ -80,10 +80,10 @@ def organiseOutput(self): self.createAddOutDir(self.tempOutDir) # Move over folders to output directory makeDir(self.outputDir) - for (root, dirs, files) in os.listdir(self.tempOutDir): + for root, dirs, files in os.walk(self.tempOutDir): r = os.path.join( self.gudrunFile.inputFileDir, - root.partition(self.gudrunDir)[-1]) + root.partition(self.gudrunDir + "/")[-1]) for d in dirs: makeDir(os.path.join(r, d)) for f in files: From 626db93a839c7f1406a4a480b346f5c1dcc53c52 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 18 Oct 2023 15:06:49 +0100 Subject: [PATCH 045/165] Updated docstrings and output handling function --- gudpy/core/gud_file.py | 18 ++++++------ gudpy/core/gudrun_file.py | 5 ++-- gudpy/core/iterators/composition.py | 11 ++++++- gudpy/core/iterators/density.py | 2 -- .../iterators/inelasticity_subtraction.py | 29 ++++++++++++++----- gudpy/core/iterators/iterator.py | 7 +++-- gudpy/core/iterators/radius.py | 2 -- gudpy/core/output_file_handler.py | 6 ++-- gudpy/core/run_batch_files.py | 14 +++++---- 9 files changed, 61 insertions(+), 33 deletions(-) diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index 9fe490c5..82f5c690 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -1,7 +1,6 @@ from core.exception import ParserException import os -from os.path import isfile import re from decimal import Decimal, getcontext getcontext().prec = 5 @@ -80,6 +79,7 @@ class GudFile: write_out(overwrite=False) Writes out the string representation of the GudFile to a file. """ + def __init__(self, path): """ Constructs all the necessary attributes for the GudFile object. @@ -123,8 +123,8 @@ def __init__(self, path): if not self.path.endswith(".gud"): raise ParserException("Only .gud files can be parsed.") - if not isfile(self.path): - raise ParserException("Please provide a valid path.") + if not os.path.isfile(os.path.abspath(self.path)): + raise ParserException(f"{self.path} is not a valid path.") # Parse the GudFile self.parse() @@ -273,10 +273,10 @@ def parse(self): else: percentage = float(re.findall(floatRegex, output)[0]) if percentage < 100: - diff = float(Decimal(100.0)-Decimal(percentage)) + diff = float(Decimal(100.0) - Decimal(percentage)) self.output = f"-{diff}%" elif percentage > 100: - diff = float(Decimal(percentage)-Decimal(100.0)) + diff = float(Decimal(percentage) - Decimal(100.0)) self.output = f"+{diff}%" else: self.output = "0%" @@ -288,10 +288,10 @@ def parse(self): except Exception as e: raise ParserException( - f"Whilst parsing {self.path}, an exception occured." - " It's likely gudrun_dcs failed, and invalid values" - " were yielded. " - f"{str(e)}" + f"Whilst parsing {self.path}, an exception occured." + " It's likely gudrun_dcs failed, and invalid values" + " were yielded. " + f"{str(e)}" ) from e def __str__(self): diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 43db2f57..f22ab642 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1646,8 +1646,9 @@ def convertToSample(self, container, persist=False): self.sampleBackgrounds[i].append(sample) return sample - def organiseOutput(self, nCurrent=0, head=""): - self.outputFileHandler = OutputFileHandler(self, nCurrent, head) + def organiseOutput(self, nCurrent=0, head="", iterate=False): + self.outputFileHandler = OutputFileHandler( + self, iterate=iterate, nCurrent=nCurrent, head=head) self.outputFileHandler.organiseOutput() def determineError(self, sample): diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index 89eb27f2..973b230d 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -106,10 +106,12 @@ class CompositionIterator(): name = "IterateByComposition" - def __init__(self, gudrunFile): + def __init__(self, gudrunFile, nTotal): self.gudrunFile = gudrunFile self.components = [] self.ratio = 0 + self.nTotal = nTotal + self.nCurrent = 0 """ Sets component and ratio. @@ -180,6 +182,8 @@ def processSingleComponent(self, x, sampleBackground): ) ) + self.nCurrent += 1 + if gudFile.averageLevelMergedDCS == gudFile.expectedDCS: return 0 else: @@ -228,6 +232,8 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): ) ) + self.nCurrent += 1 + if gudFile.averageLevelMergedDCS == gudFile.expectedDCS: return 0 else: @@ -279,5 +285,8 @@ def iterate(self, n=10, rtol=10.): args=(sb, totalMolecules,) ) + self.gudrunFile.organiseOutput( + iterate=True, nCurrent=self.nCurrent, head=self.name) + def gss(self, f, bounds, n, args=()): return gss(f, bounds, n, self.maxIterations, self.rtol, args=args) diff --git a/gudpy/core/iterators/density.py b/gudpy/core/iterators/density.py index 32e1b33c..f6fd5834 100644 --- a/gudpy/core/iterators/density.py +++ b/gudpy/core/iterators/density.py @@ -15,8 +15,6 @@ class DensityIterator(Iterator): ---------- applyCoefficientToAttribute Multiplies a sample's density by a given coefficient. - organiseOutput - Organises the output of the iteration. """ name = "IterateByDensity" diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 2779af83..eaee10fc 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -33,6 +33,8 @@ class InelasticitySubtraction(Iterator): QStep : float Step size for corrections on Q scale. Stored, as we switch between scales this data needs to be held. + nSet : int + Number of completed iteration sets (one QIteration, one Wavelength) Methods ---------- enableLogarithmicBinning @@ -58,9 +60,9 @@ class InelasticitySubtraction(Iterator): Perform n iterations on the wavelength scale and Q scale. """ - name = "IterateByWavelengthInelasticitySubtraction" + name = "IterateByInelasticitySubtraction" - def __init__(self, gudrunFile): + def __init__(self, gudrunFile, nTotal): """ Constructs all the necessary attributes for the InelasticitySubtraction object. @@ -70,12 +72,15 @@ def __init__(self, gudrunFile): gudrunFile : GudrunFile Input GudrunFile that we will be using for iterating. """ + super().__init__(gudrunFile, nTotal) self.gudrunFile = deepcopy(gudrunFile) + # Does a default iteration first (no changes) self.iterationType = "WavelengthIteration" self.topHatWidths = [] self.QMax = 0. self.QMin = 0. self.QStep = 0. + self.nSet = 0 def enableLogarithmicBinning(self): """ @@ -196,6 +201,7 @@ def wavelengthIteration(self): the extensions of the self scattering files to .mint01. Then, write out the GudrunFile and call gudrun_dcs. """ + self.iterationType = "WavelengthIteration" # First iteration if self.nCurrent == 0: # Disable subtracting of wavelength binned data. @@ -229,6 +235,7 @@ def QIteration(self): the extensions of the self scattering files to .msubw01. Then, write out the GudrunFile and call gudrun_dcs. """ + self.iterationType = "QIteration" # Enable subtracting of wavelength binned data self.gudrunFile.instrument.subWavelengthBinnedData = True # Set the min, max and step size on the X scale @@ -242,13 +249,19 @@ def QIteration(self): self.setSelfScatteringFiles(Scales.Q) def performIteration(self): - if self.nCurrent % 2 != 0: + if self.nCurrent % 2 == 0: self.wavelengthIteration() - self.iterationType = "WavelengthIteration" + self.nSet += 1 else: self.QIteration() - self.iterationType = "QIteration" - self.nCurrent += 1 + self.nCurrent += 1 + + def organiseOutput(self): + """ + This organises the output of the iteration. + """ + self.gudrunFile.organiseOutput( + iterate=True, nCurrent=self.nSet, head=self.iterationType) def iterate(self): """ @@ -262,4 +275,6 @@ def iterate(self): self.gudrunFile.process(iterative=True) time.sleep(1) self.gudrunFile.organiseOutput( - self.nCurrent, self.iterationType) + iterate=True, + nCurrent=self.nCurrent, + head=self.iterationType) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 1c48846e..58b7bc18 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -104,7 +104,7 @@ def organiseOutput(self): Current iteration """ self.gudrunFile.organiseOutput( - self.nCurrent, self.name) + iterate=True, nCurrent=self.nCurrent, head=self.name) def iterate(self): """ @@ -123,4 +123,7 @@ def iterate(self): self.gudrunFile.process() time.sleep(1) self.performIteration() - self.organiseOutput() + self.organiseOutput( + iterate=True, + nCurrent=self.nCurrent, + head=self.name) diff --git a/gudpy/core/iterators/radius.py b/gudpy/core/iterators/radius.py index 001a6149..d346b6b9 100644 --- a/gudpy/core/iterators/radius.py +++ b/gudpy/core/iterators/radius.py @@ -18,8 +18,6 @@ class RadiusIterator(Iterator): Multiplies a sample's inner/outer radii by a given coefficient. setTargetRadius Sets the target radius attribute. - organiseOutput - Organises the output of the iteration. """ name = "IterateByRadius" diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index a89b65b5..b0baf28f 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -6,7 +6,7 @@ class OutputFileHandler(): - def __init__(self, gudrunFile, nCurrent=0, head=""): + def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): """ Initialise `OutputFileHandler` @@ -27,9 +27,9 @@ def __init__(self, gudrunFile, nCurrent=0, head=""): # Temporary output dir paths self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( self.gudrunFile.filename)[0]) - if head: + if iterate: self.tempOutDir = os.path.join( - self.tempOutDir, f"{head}_{nCurrent + 1}") + self.tempOutDir, f"{head}_{nCurrent}") # Name the output directory as the input file self.outputDir = os.path.join( diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index c1febe43..f59b50d3 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -169,8 +169,9 @@ def process( initial.process(headless=headless) iterator.performIteration(i) initial.organiseOutput( - i, - os.path.join( + iterate=True, + nCurrent=i, + head=os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", "FIRST_BATCH", @@ -199,8 +200,9 @@ def process( self.batchedGudrunFile.process(headless=headless) iterator.performIteration(i) self.batchedGudrunFile.organiseOutput( - os.path.join( - i, + iterate=True, + nCurrent=i, + head=os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", "REST", @@ -231,7 +233,7 @@ def process( tasks.append( [ self.batchedGudrunFile.organiseOutput, - [0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], + [True, 0, f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}"], ] ) tasks.append( @@ -266,6 +268,7 @@ def process( [ initial.organiseOutput, [ + True, i, os.path.join( initial.GudrunInputFileDir, @@ -321,6 +324,7 @@ def process( [ self.batchedGudrunFile.organiseOutput, [ + True, i, os.path.join( f"BATCH_PROCESSING_BATCH_SIZE_{batchSize}", From 87fa4b5fc5ac21efa4f4bb1c86a64e737cc41f99 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 18 Oct 2023 16:56:15 +0100 Subject: [PATCH 046/165] Changed inelasticity menu name to be consistent --- gudpy/gui/widgets/ui_files/mainWindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/gui/widgets/ui_files/mainWindow.ui b/gudpy/gui/widgets/ui_files/mainWindow.ui index a35390dc..33ad570d 100644 --- a/gudpy/gui/widgets/ui_files/mainWindow.ui +++ b/gudpy/gui/widgets/ui_files/mainWindow.ui @@ -7550,7 +7550,7 @@ - Inelasticity Subtractions + By Inelasticity Subtractions From e2d35fc5d11917eb04d52be0d25bfd73d2b783dc Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 18 Oct 2023 16:56:47 +0100 Subject: [PATCH 047/165] Better clarity of 'default' run, refactored code --- .../iterators/inelasticity_subtraction.py | 4 ++ gudpy/core/iterators/iterator.py | 5 +- gudpy/core/iterators/tweak_factor.py | 4 ++ gudpy/core/output_file_handler.py | 5 +- gudpy/gui/widgets/core/main_window.py | 52 ++++++++++++------- gudpy/gui/widgets/dialogs/iteration_dialog.py | 11 ++-- 6 files changed, 55 insertions(+), 26 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index eaee10fc..7cb663ef 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -249,6 +249,10 @@ def QIteration(self): self.setSelfScatteringFiles(Scales.Q) def performIteration(self): + if self.nCurrent == -1: + self.nCurrent += 1 + return + if self.nCurrent % 2 == 0: self.wavelengthIteration() self.nSet += 1 diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 58b7bc18..cd4540a7 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -45,13 +45,16 @@ def __init__(self, gudrunFile, nTotal): """ self.gudrunFile = gudrunFile self.nTotal = nTotal - self.nCurrent = 0 + self.nCurrent = -1 def performIteration(self): """ Performs a single iteration of the current workflow. """ + if self.nCurrent == -1: + self.nCurrent += 1 + return # Iterate through all samples that are being run, # applying the coefficient to the target parameter. for sampleBackground in self.gudrunFile.sampleBackgrounds: diff --git a/gudpy/core/iterators/tweak_factor.py b/gudpy/core/iterators/tweak_factor.py index b93c0fc9..edfa7d12 100644 --- a/gudpy/core/iterators/tweak_factor.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -39,6 +39,10 @@ def performIteration(self): _n : int Iteration number. """ + if self.nCurrent == -1: + self.nCurrent += 1 + return + # Iterate through all samples, # updating their tweak factor from the output of gudrun_dcs. for sampleBackground in self.gudrunFile.sampleBackgrounds: diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index b0baf28f..36251749 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -27,9 +27,12 @@ def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): # Temporary output dir paths self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( self.gudrunFile.filename)[0]) - if iterate: + if iterate and nCurrent != 0: self.tempOutDir = os.path.join( self.tempOutDir, f"{head}_{nCurrent}") + elif iterate: + self.tempOutDir = os.path.join( + self.tempOutDir, f"{head}_Default") # Name the output directory as the input file self.outputDir = os.path.join( diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 2ed6c46d..e82b6cf0 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1474,8 +1474,8 @@ def errorCompositionIteration(self, output): def progressCompositionIteration(self, currentIteration): progress = ( - self.currentIteration / self.numberIterations - ) * (self.currentIteration / self.totalIterations) + self.iterator.nCurrent / self.iterator.nTotal + ) * (self.iterator.nCurrent / self.totalIterations) self.mainWidget.progressBar.setValue(int(progress * 100)) def nextCompositionIteration(self): @@ -1492,8 +1492,9 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) self.gudrunFile.organiseOutput( - self.currentIteration, - self.iterator.name) + iterate=True, + nCurrent=self.currentIteration, + head=self.iterator.name) self.currentIteration += 1 def iterateByComposition(self): @@ -1527,9 +1528,22 @@ def iterateByComposition(self): ) ] ) + self.iterator.nTotal = self.totalIterations self.nextCompositionIteration() def iterateGudrun(self, dialog, name): + """ + Iteratively runs Gudrun dcs and applies a change depending on which + parameter is iterated. The first iteration is a default iteration in + which no parameters are altered. + + Parameters + ---------- + dialog : IterationDialog + Dialog to be run to get user information + name : str + Name of dialog + """ self.prepareRun() iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) iterationDialog.widget.exec() @@ -1552,11 +1566,10 @@ def nextIteration(self): self.procFinished(9, QProcess.NormalExit) return self.iterator.organiseOutput() - self.iterator.performIteration() - self.gudrunFile.write_out() - self.outputIterations[self.iterator.nCurrent] = self.output + self.outputIterations[self.iterator.nCurrent + 1] = self.output self.outputSlots.setOutput( - self.outputIterations, "gudrun_dcs", gudrunFile=self.gudrunFile + self.outputIterations, "gudrun_dcs", + gudrunFile=self.iterator.gudrunFile ) if not self.queue.empty(): self.nextIterableProc() @@ -1567,26 +1580,25 @@ def nextIteration(self): def nextIterableProc(self): if self.queue.empty(): return + iterInfo = f" {self.iterator.nCurrent + 1}/{self.iterator.nTotal}" if ( + self.iterator.nCurrent != -1 + ) else "- Default run" + # Set progress bar + self.mainWidget.currentTaskLabel.setText(f"{self.text} {iterInfo}") + self.previousProcTitle = self.mainWidget.currentTaskLabel.text() + # If this is not the first iteration, run the iterator + self.iterator.performIteration() + self.iterator.gudrunFile.write_out() self.proc, func, args = self.queue.get() - self.proc.started.connect(self.iterationStarted) self.proc.finished.connect(self.nextIteration) self.proc.readyReadStandardOutput.connect(self.progressIteration) - self.proc.started.connect(self.iterationStarted) self.proc.setWorkingDirectory( - self.gudrunFile.instrument.GudrunInputFileDir + self.iterator.gudrunFile.instrument.GudrunInputFileDir ) if func: func(*args) self.proc.start() - def iterationStarted(self): - self.mainWidget.currentTaskLabel.setText( - f"{self.text}" - f" {self.iterator.nCurrent + 1}" - + f"/{self.iterator.nTotal}" - ) - self.previousProcTitle = self.mainWidget.currentTaskLabel.text() - def progressIteration(self): progress = self.progressIncrementDCS(self.gudrunFile) if progress == -1: @@ -1903,7 +1915,7 @@ def procFinished(self, ec, es): self.proc = None output = self.output if self.iterator: - self.outputIterations[self.currentIteration + 1] = self.output + self.outputIterations[self.iterator.nCurrent + 1] = self.output self.sampleSlots.setSample(self.sampleSlots.sample) output = self.outputIterations self.iterator = None diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index cce8c462..2651718f 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -69,7 +69,7 @@ def numberIterationsChanged(self, value): def enqueueTasks(self): self.queue = Queue() - for _ in range(self.numberIterations): + for _ in range(self.numberIterations + 1): self.queue.put( self.iterator.gudrunFile.dcs( path=os.path.join( @@ -90,16 +90,19 @@ def iterate(self): class InelasticitySubtractionIterationDialog(IterationDialog): + def numberIterationsChanged(self, value): + self.numberIterations = value + def iterate(self): self.iterator = InelasticitySubtraction( - self.gudrunFile, self.numberIterations * 2) + self.gudrunFile, (self.numberIterations * 2)) self.enqueueTasks() self.text = "Inelasticity subtractions" self.widget.close() def enqueueTasks(self): self.queue = Queue() - for _ in range((self.numberIterations * 2)): + for _ in range((self.numberIterations * 2) + 1): self.queue.put( self.iterator.gudrunFile.dcs( path=os.path.join( @@ -247,7 +250,7 @@ def initComponents(self): self.widget.iterateButton.setEnabled(False) def iterate(self): - self.iterator = CompositionIterator(self.gudrunFile) + self.iterator = CompositionIterator(self.gudrunFile, 10) self.iterator.setComponents(self.components) self.queue = Queue() for sampleBackground in self.gudrunFile.sampleBackgrounds: From e89df85ec93972edb02beec4a222e98b4a5691fb Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:03:08 +0100 Subject: [PATCH 048/165] Changed function naming to be private, updated to not require nCurrent --- gudpy/core/output_file_handler.py | 56 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 36251749..ff8ab9b0 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -6,7 +6,7 @@ class OutputFileHandler(): - def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): + def __init__(self, gudrunFile, head="", overwrite=True): """ Initialise `OutputFileHandler` @@ -14,10 +14,11 @@ def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): ---------- gudrunFile : GudrunFile Gudrun file object that defines run parameters - nCurrent : int, optional - Current iteration number by default 0 head : str, optional - Iterator type, by default "" + Where to branch outputs, if desired, by default "" + overwrite : bool, optional + Whether or not to overwrite previous output directiory, + by default True """ self.gudrunFile = gudrunFile # List of run samples @@ -27,12 +28,9 @@ def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): # Temporary output dir paths self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( self.gudrunFile.filename)[0]) - if iterate and nCurrent != 0: + if head: self.tempOutDir = os.path.join( - self.tempOutDir, f"{head}_{nCurrent}") - elif iterate: - self.tempOutDir = os.path.join( - self.tempOutDir, f"{head}_Default") + self.tempOutDir, f"{head}") # Name the output directory as the input file self.outputDir = os.path.join( @@ -67,7 +65,7 @@ def __init__(self, gudrunFile, iterate=False, nCurrent=0, head=""): # If output directory exists, move to a temp dir and clear it # Avoids shutil.rmtree - if nCurrent == 0 and os.path.exists(self.outputDir): + if overwrite is True and os.path.exists(self.outputDir): with tempfile.TemporaryDirectory() as tmp: shutil.move(self.outputDir, os.path.join(tmp, "prev")) @@ -75,12 +73,12 @@ def organiseOutput(self): """Organises Gudrun outputs """ # Create normalisation and sample background folders - self.createNormDir(self.tempOutDir) - self.createSampleBgDir(self.tempOutDir) + self._createNormDir(self.tempOutDir) + self._createSampleBgDir(self.tempOutDir) # Create sample folders - self.createSampleDir(self.tempOutDir) + self._createSampleDir(self.tempOutDir) # Create additonal output folders - self.createAddOutDir(self.tempOutDir) + self._createAddOutDir(self.tempOutDir) # Move over folders to output directory makeDir(self.outputDir) for root, dirs, files in os.walk(self.tempOutDir): @@ -95,7 +93,7 @@ def organiseOutput(self): os.path.join(r, f) ) - def createNormDir(self, dest): + def _createNormDir(self, dest): """ Creates directories for normalisation background and normalisation outputs. @@ -107,15 +105,15 @@ def createNormDir(self, dest): """ # Create normalisation folders and move datafiles for normFile in self.gudrunFile.normalisation.dataFiles: - self.copyOutputs( + self._copyOutputs( normFile, os.path.join( dest, "Normalisation")) for normBgFile in self.gudrunFile.normalisation.dataFilesBg: - self.copyOutputs(normBgFile, - os.path.join(dest, - "NormalisationBackground")) + self._copyOutputs(normBgFile, + os.path.join(dest, + "NormalisationBackground")) - def createSampleBgDir(self, dest): + def _createSampleBgDir(self, dest): """ Creates output directory for sample backgrounds @@ -130,14 +128,14 @@ def createSampleBgDir(self, dest): # Move all datafiles into their sample background folder # Creates the folder if there is none for dataFile in sampleBackground.dataFiles: - self.copyOutputs( + self._copyOutputs( dataFile, os.path.join( dest, "SampleBackgrounds", f"SampleBackground{count + 1}") ) - def createSampleDir(self, dest): + def _createSampleDir(self, dest): """ Creates output directory for each sample @@ -155,13 +153,13 @@ def createSampleDir(self, dest): """ # Create sample folders within background folders for sample in self.samples: - samplePath = uniquify(os.path.join( + samplePath = os.path.join( dest, sample.name - )) + ) # Move datafiles to sample folder for dataFile in sample.dataFiles: - self.copyOutputsByExt( + self._copyOutputsByExt( dataFile, samplePath ) @@ -182,12 +180,12 @@ def createSampleDir(self, dest): if container.name != "CONTAINER" else "Container"))) for dataFile in container.dataFiles: - self.copyOutputs( + self._copyOutputs( dataFile, containerPath ) - def createAddOutDir(self, dest): + def _createAddOutDir(self, dest): """ Copy over all files that haven't been copied over, as specified in `copiedFiles` @@ -212,7 +210,7 @@ def createAddOutDir(self, dest): os.path.join(addDir, f) ) - def copyOutputs(self, fpath, dest): + def _copyOutputs(self, fpath, dest): """ Copy all files with the same basename as the provided filepath, except the original file. @@ -242,7 +240,7 @@ def copyOutputs(self, fpath, dest): ) self.copiedFiles.append(f) - def copyOutputsByExt(self, fname, dest): + def _copyOutputsByExt(self, fname, dest): """ Copy all files with the same basename as the provided filepath and splits them into outputs From e5de80cce315f50d2643ece1e749fca579c0b2f5 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:03:22 +0100 Subject: [PATCH 049/165] Added assertions and set run dir function --- gudpy/core/gudrun_file.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index f22ab642..6801418a 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1525,6 +1525,10 @@ def write_out(self, path='', overwrite=False, writeParameters=True): writeParameters=False ) + def setGudrunDir(self, dir): + assert (os.path.isdir(os.path.abspath(dir))) + self.instrument.GudrunInputFileDir = dir + def dcs(self, path='', headless=True, iterative=False): """ Call gudrun_dcs on the path supplied. @@ -1546,6 +1550,8 @@ def dcs(self, path='', headless=True, iterative=False): The result of calling gudrun_dcs using subprocess.run. Can access stdout/stderr from this. """ + assert (self.instrument.GudrunInputFileDir) + if not path: path = os.path.basename(self.path) if headless: @@ -1646,10 +1652,11 @@ def convertToSample(self, container, persist=False): self.sampleBackgrounds[i].append(sample) return sample - def organiseOutput(self, nCurrent=0, head="", iterate=False): - self.outputFileHandler = OutputFileHandler( - self, iterate=iterate, nCurrent=nCurrent, head=head) - self.outputFileHandler.organiseOutput() + def organiseOutput(self, head="", overwrite=True): + outputHandler = OutputFileHandler( + self, head=head, overwrite=overwrite + ) + outputHandler.organiseOutput() def determineError(self, sample): gudPath = sample.dataFiles[0].replace( From c3433a852c5025c3360eaa84c2cc62df76536c8e Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:04:04 +0100 Subject: [PATCH 050/165] Updated parameters for new organiseoutput --- gudpy/core/iterators/composition.py | 3 +-- gudpy/core/iterators/iterator.py | 20 ++++++-------------- gudpy/core/run_batch_files.py | 4 ---- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index 973b230d..a3fc3074 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -285,8 +285,7 @@ def iterate(self, n=10, rtol=10.): args=(sb, totalMolecules,) ) - self.gudrunFile.organiseOutput( - iterate=True, nCurrent=self.nCurrent, head=self.name) + self.gudrunFile.organiseOutput() def gss(self, f, bounds, n, args=()): return gss(f, bounds, n, self.maxIterations, self.rtol, args=args) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index cd4540a7..c2180bf7 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -31,6 +31,8 @@ class Iterator(): To be overriden by sub-classes. """ + name = "" + def __init__(self, gudrunFile, nTotal): """ Constructs all the necessary attributes for the @@ -46,6 +48,7 @@ def __init__(self, gudrunFile, nTotal): self.gudrunFile = gudrunFile self.nTotal = nTotal self.nCurrent = -1 + self.iterationType = self.name def performIteration(self): """ @@ -97,17 +100,9 @@ def applyCoefficientToAttribute(self, object, coefficient): def organiseOutput(self): """ - This should organises the output of the iteration. - - Parameters - ---------- - nTotal : int - Total number of requested iterations - nCurrent : int - Current iteration + This organises the output of the iteration. """ - self.gudrunFile.organiseOutput( - iterate=True, nCurrent=self.nCurrent, head=self.name) + self.gudrunFile.organiseOutput() def iterate(self): """ @@ -126,7 +121,4 @@ def iterate(self): self.gudrunFile.process() time.sleep(1) self.performIteration() - self.organiseOutput( - iterate=True, - nCurrent=self.nCurrent, - head=self.name) + self.organiseOutput() diff --git a/gudpy/core/run_batch_files.py b/gudpy/core/run_batch_files.py index f59b50d3..c7f46883 100644 --- a/gudpy/core/run_batch_files.py +++ b/gudpy/core/run_batch_files.py @@ -169,8 +169,6 @@ def process( initial.process(headless=headless) iterator.performIteration(i) initial.organiseOutput( - iterate=True, - nCurrent=i, head=os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", @@ -200,8 +198,6 @@ def process( self.batchedGudrunFile.process(headless=headless) iterator.performIteration(i) self.batchedGudrunFile.organiseOutput( - iterate=True, - nCurrent=i, head=os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, f"BATCH_PROCESSING_BATCH_SIZE{batchSize}", From d544235a005113c24b3417575a9a0ae530736e3e Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:04:37 +0100 Subject: [PATCH 051/165] Fixed and modified output tree --- gudpy/gui/widgets/core/gudpy_tree.py | 33 ++++++++------ gudpy/gui/widgets/core/output_tree.py | 66 +++++++++++++++------------ 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/gudpy/gui/widgets/core/gudpy_tree.py b/gudpy/gui/widgets/core/gudpy_tree.py index ce1462df..c1aba142 100644 --- a/gudpy/gui/widgets/core/gudpy_tree.py +++ b/gudpy/gui/widgets/core/gudpy_tree.py @@ -17,6 +17,7 @@ from core.sample_background import SampleBackground from core.container import Container from core.config import NUM_GUDPY_CORE_OBJECTS +from core.utils import uniquifyName class GudPyTreeModel(QAbstractItemModel): @@ -123,14 +124,14 @@ def index(self, row, column, parent=QModelIndex()): obj = rows[row] else: obj = self.gudrunFile.sampleBackgrounds[ - row-NUM_GUDPY_CORE_OBJECTS + row - NUM_GUDPY_CORE_OBJECTS ] elif parent.isValid() and not parent.parent().isValid(): # Valid parent and invalid grandparent, means that the index # corresponds to a sample. obj = ( self.gudrunFile.sampleBackgrounds[ - parent.row()-NUM_GUDPY_CORE_OBJECTS + parent.row() - NUM_GUDPY_CORE_OBJECTS ] .samples[row] ) @@ -139,7 +140,7 @@ def index(self, row, column, parent=QModelIndex()): # corresponds to a container. obj = ( self.gudrunFile.sampleBackgrounds[ - parent.parent().row()-NUM_GUDPY_CORE_OBJECTS + parent.parent().row() - NUM_GUDPY_CORE_OBJECTS ].samples[parent.row()].containers[row] ) else: @@ -284,7 +285,11 @@ def setData(self, index, value, role): role == Qt.EditRole and (self.isSample(index) or self.isContainer(index)) ): - index.internalPointer().name = value + index.internalPointer().name = uniquifyName( + value, + [s.name for s in self.gudrunFile.sampleBackground.samples], + sep="", + incFirst=True) self.dataChanged.emit(index, index) return True else: @@ -333,7 +338,7 @@ def rowCount(self, parent=QModelIndex()): ): return len( self.gudrunFile.sampleBackgrounds[ - parent.row()-NUM_GUDPY_CORE_OBJECTS + parent.row() - NUM_GUDPY_CORE_OBJECTS ].samples ) else: @@ -347,7 +352,7 @@ def rowCount(self, parent=QModelIndex()): # containers for the sample. return len( self.gudrunFile.sampleBackgrounds[ - parent.parent().row()-NUM_GUDPY_CORE_OBJECTS + parent.parent().row() - NUM_GUDPY_CORE_OBJECTS ].samples[parent.row()].containers ) else: @@ -474,13 +479,13 @@ def insertRow(self, obj, parent): parent = QModelIndex() setter = self.gudrunFile.sampleBackgrounds.append if isinstance(obj, Sample): - targetIndex = parent.row()-NUM_GUDPY_CORE_OBJECTS + targetIndex = parent.row() - NUM_GUDPY_CORE_OBJECTS setter = ( self.gudrunFile.sampleBackgrounds[targetIndex] .samples.append ) elif isinstance(obj, Container): - targetIndex = parent.parent().row()-NUM_GUDPY_CORE_OBJECTS + targetIndex = parent.parent().row() - NUM_GUDPY_CORE_OBJECTS setter = ( self.gudrunFile.sampleBackgrounds[targetIndex] .samples[parent.row()].containers.append @@ -505,7 +510,7 @@ def insertRow(self, obj, parent): parent = QModelIndex() setter = self.gudrunFile.sampleBackgrounds.insert elif isinstance(obj, Sample): - targetIndex = parent.parent().row()-NUM_GUDPY_CORE_OBJECTS + targetIndex = parent.parent().row() - NUM_GUDPY_CORE_OBJECTS index = ( self.gudrunFile.sampleBackgrounds[targetIndex] .samples.index(parentObj) @@ -516,7 +521,7 @@ def insertRow(self, obj, parent): ) elif isinstance(obj, Container): targetIndex = ( - parent.parent().parent().row()-NUM_GUDPY_CORE_OBJECTS + parent.parent().parent().row() - NUM_GUDPY_CORE_OBJECTS ) index = ( self.gudrunFile.sampleBackgrounds[targetIndex]. @@ -532,7 +537,7 @@ def insertRow(self, obj, parent): self.beginInsertRows(parent.parent(), start, end) # Call the setter. # index+1 to insert after the current index. - setter(index+1, obj) + setter(index + 1, obj) # End inserting rows. self.endInsertRows() self.dataChanged.emit( @@ -556,12 +561,12 @@ def removeRow(self, index): if isinstance(obj, SampleBackground): remove = self.gudrunFile.sampleBackgrounds.remove elif isinstance(obj, Sample): - targetIndex = parent.row()-NUM_GUDPY_CORE_OBJECTS + targetIndex = parent.row() - NUM_GUDPY_CORE_OBJECTS remove = ( self.gudrunFile.sampleBackgrounds[targetIndex].samples.remove ) elif isinstance(obj, Container): - targetIndex = parent.parent().row()-NUM_GUDPY_CORE_OBJECTS + targetIndex = parent.parent().row() - NUM_GUDPY_CORE_OBJECTS remove = ( self.gudrunFile.sampleBackgrounds[targetIndex] .samples[parent.row()].containers.remove @@ -805,7 +810,7 @@ def insertRow(self, obj): currentIndex = self.currentIndex() self.model().insertRow(obj, currentIndex) newIndex = self.model().index( - currentIndex.row()+1, 0, + currentIndex.row() + 1, 0, self.model().parent(currentIndex) ) self.expandRecursively(newIndex, 0) diff --git a/gudpy/gui/widgets/core/output_tree.py b/gudpy/gui/widgets/core/output_tree.py index e9f98c7a..1e4a544e 100644 --- a/gudpy/gui/widgets/core/output_tree.py +++ b/gudpy/gui/widgets/core/output_tree.py @@ -18,24 +18,27 @@ class OutputTreeModel(QAbstractItemModel): def __init__(self, output, gudrunFile, keyMap=None, parent=None): super().__init__(parent) if isinstance(output, str): - output = {1: output} + output = {0: output} self.keyMap = keyMap self.output = output self.gudrunFile = gudrunFile self.map = {} self.refs = [] - self.data_ = OrderedDict( - sorted( - {i: [] for i in output.keys()}.items() - ) - ) + self.data_ = {} + + for idx, key in enumerate(output.keys()): + self.data_[idx] = { + "name": key, + "outputs": [] + } + self.persistentIndexes = {} self.setupData() def setupData(self): - for iteration, output in self.output.items(): + for idx, [name, output] in enumerate(self.output.items()): gf = deepcopy(self.gudrunFile) - gf.iteration = iteration + gf.name = name gf.output = output self.refs.append(gf) offsets = [ @@ -48,12 +51,12 @@ def setupData(self): i = deepcopy(self.gudrunFile.instrument) i.output = output i.name = "General" - self.data_[iteration].append(i) + self.data_[idx]["outputs"].append(i) return sbindicies = [] - for i in range(len(offsets)-1): - sbindicies.append([offsets[i], offsets[i+1]-1]) + for i in range(len(offsets) - 1): + sbindicies.append([offsets[i], offsets[i + 1] - 1]) sbindicies.append( [ @@ -67,7 +70,7 @@ def setupData(self): [0: sbindicies[0][0]] ) i.name = "General" - self.data_[iteration].append(i) + self.data_[idx]["outputs"].append(i) prev = None for start, end in sbindicies: splicedOutput = ( @@ -85,19 +88,17 @@ def setupData(self): if s.runThisSample ], indices ): - if len(self.data_[iteration]) == 1: - s = deepcopy(sample) - s.output = index+start - prev = s - else: - s = deepcopy(sample) + s = deepcopy(sample) + s.output = index + start + + if len(self.data_[idx]["outputs"]) != 1: prev.output = "".join( output.splitlines(keepends=True) - [prev.output:index+start-1] + [prev.output:index + start - 1] ) - s.output = index + start - prev = s - self.data_[iteration].append(s) + + prev = s + self.data_[idx]["outputs"].append(s) if prev: prev.output = "".join( output.splitlines(keepends=True) @@ -110,7 +111,7 @@ def index(self, row, column, parent=QModelIndex()): return QModelIndex() elif not parent.isValid(): if len(self.data_.keys()) == 1: - obj = self.data_[1][row] + obj = self.data_[0]["outputs"][row] elif len(self.data_.keys()) > 1: try: obj = self.refs[row] @@ -119,15 +120,17 @@ def index(self, row, column, parent=QModelIndex()): else: return QModelIndex() elif parent.isValid(): - obj = self.data_[self.refs.index(parent.internalPointer())+1][row] + obj = self.data_[ + self.refs.index( + parent.internalPointer())]["outputs"][row] index = self.createIndex(row, 0, obj) self.persistentIndexes[obj] = QPersistentModelIndex(index) return index def findParent(self, obj): for parent, items in self.data_.items(): - if obj in items: - return self.refs[parent-1] + if obj in items["outputs"]: + return self.refs[parent] def parent(self, index): if not index.isValid(): @@ -146,7 +149,8 @@ def parent(self, index): def rowCount(self, parent=QModelIndex()): if not parent.isValid(): if len(self.data_.keys()) == 1: - return len(self.data_[1]) + # get length of first value + return len(self.data_[0]["outputs"]) elif len(self.data_.keys()) > 1: return len(self.data_.keys()) else: @@ -154,7 +158,9 @@ def rowCount(self, parent=QModelIndex()): parentObj = parent.internalPointer() if isinstance(parentObj, GudrunFile): return len( - self.data_[self.refs.index(parent.internalPointer())+1] + self.data_[ + self.refs.index( + parent.internalPointer())]["outputs"] ) else: return 0 @@ -169,9 +175,9 @@ def data(self, index, role=Qt.DisplayRole): obj = index.internalPointer() if isinstance(obj, GudrunFile): if self.keyMap: - return self.keyMap[obj.iteration] + return self.keyMap[obj.name] else: - return obj.iteration + return obj.name elif isinstance(obj, (Instrument, Sample)): return obj.name else: From 4c38ac2c7aceac7d7c575d83f049f8204458a812 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:05:08 +0100 Subject: [PATCH 052/165] Updated inelasticity to be the only one that saves all iter outputs --- .../iterators/inelasticity_subtraction.py | 25 +++++++------------ gudpy/gui/widgets/core/main_window.py | 20 +++++++++------ gudpy/gui/widgets/dialogs/iteration_dialog.py | 4 +-- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 7cb663ef..611d3e07 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -33,8 +33,6 @@ class InelasticitySubtraction(Iterator): QStep : float Step size for corrections on Q scale. Stored, as we switch between scales this data needs to be held. - nSet : int - Number of completed iteration sets (one QIteration, one Wavelength) Methods ---------- enableLogarithmicBinning @@ -75,12 +73,12 @@ def __init__(self, gudrunFile, nTotal): super().__init__(gudrunFile, nTotal) self.gudrunFile = deepcopy(gudrunFile) # Does a default iteration first (no changes) - self.iterationType = "WavelengthIteration" + self.iterationType = "QIteration" + self.nCurrent = 0 self.topHatWidths = [] self.QMax = 0. self.QMin = 0. self.QStep = 0. - self.nSet = 0 def enableLogarithmicBinning(self): """ @@ -249,23 +247,21 @@ def QIteration(self): self.setSelfScatteringFiles(Scales.Q) def performIteration(self): - if self.nCurrent == -1: - self.nCurrent += 1 - return - - if self.nCurrent % 2 == 0: + if self.iterationType == "QIteration": self.wavelengthIteration() - self.nSet += 1 + self.nCurrent += 1 else: self.QIteration() - self.nCurrent += 1 def organiseOutput(self): """ This organises the output of the iteration. """ + overwrite = (self.nCurrent == 1 and + self.iterationType == "WavelengthIteration") self.gudrunFile.organiseOutput( - iterate=True, nCurrent=self.nSet, head=self.iterationType) + head=f"{self.iterationType}_{self.nCurrent}", + overwrite=overwrite) def iterate(self): """ @@ -278,7 +274,4 @@ def iterate(self): self.performIteration() self.gudrunFile.process(iterative=True) time.sleep(1) - self.gudrunFile.organiseOutput( - iterate=True, - nCurrent=self.nCurrent, - head=self.iterationType) + self.organiseOutput() diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index e82b6cf0..6d43b6dd 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -944,7 +944,7 @@ def prepareRun(self): self.setControlsEnabled(False) self.tmp = tempfile.TemporaryDirectory() - self.gudrunFile.instrument.GudrunInputFileDir = self.tmp.name + self.gudrunFile.setGudrunDir(self.tmp.name) def cleanupRun(self): self.tmp.cleanup() @@ -1491,10 +1491,7 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.gudrunFile.organiseOutput( - iterate=True, - nCurrent=self.currentIteration, - head=self.iterator.name) + self.gudrunFile.organiseOutput() self.currentIteration += 1 def iterateByComposition(self): @@ -1566,7 +1563,13 @@ def nextIteration(self): self.procFinished(9, QProcess.NormalExit) return self.iterator.organiseOutput() - self.outputIterations[self.iterator.nCurrent + 1] = self.output + if self.iterator.nCurrent != -1: + # If this is not the default run + self.outputIterations[ + f"{self.iterator.iterationType} {self.iterator.nCurrent}" + ] = self.output + else: + self.outputIterations["Default"] = self.output self.outputSlots.setOutput( self.outputIterations, "gudrun_dcs", gudrunFile=self.iterator.gudrunFile @@ -1586,7 +1589,6 @@ def nextIterableProc(self): # Set progress bar self.mainWidget.currentTaskLabel.setText(f"{self.text} {iterInfo}") self.previousProcTitle = self.mainWidget.currentTaskLabel.text() - # If this is not the first iteration, run the iterator self.iterator.performIteration() self.iterator.gudrunFile.write_out() self.proc, func, args = self.queue.get() @@ -1915,7 +1917,9 @@ def procFinished(self, ec, es): self.proc = None output = self.output if self.iterator: - self.outputIterations[self.iterator.nCurrent + 1] = self.output + self.outputIterations[ + f"{self.iterator.iterationType} {self.iterator.nCurrent}" + ] = self.output self.sampleSlots.setSample(self.sampleSlots.sample) output = self.outputIterations self.iterator = None diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index 2651718f..acb49e7b 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -95,14 +95,14 @@ def numberIterationsChanged(self, value): def iterate(self): self.iterator = InelasticitySubtraction( - self.gudrunFile, (self.numberIterations * 2)) + self.gudrunFile, self.numberIterations) self.enqueueTasks() self.text = "Inelasticity subtractions" self.widget.close() def enqueueTasks(self): self.queue = Queue() - for _ in range((self.numberIterations * 2) + 1): + for _ in range((self.numberIterations * 2)): self.queue.put( self.iterator.gudrunFile.dcs( path=os.path.join( From 019bfe3ad6dcabbb9aa054d2674302ea6a311ecc Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 11:11:06 +0100 Subject: [PATCH 053/165] removed unused import --- gudpy/gui/widgets/core/output_tree.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/gui/widgets/core/output_tree.py b/gudpy/gui/widgets/core/output_tree.py index 1e4a544e..5778908e 100644 --- a/gudpy/gui/widgets/core/output_tree.py +++ b/gudpy/gui/widgets/core/output_tree.py @@ -1,5 +1,4 @@ from copy import deepcopy -from typing import OrderedDict from PySide6.QtWidgets import QTreeView from PySide6.QtCore import ( QAbstractItemModel, From ac43ade77e3e17bf68ddaa850032111d0cf2138f Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 12:07:59 +0100 Subject: [PATCH 054/165] Creating and asserting gudrun is run in tempdir --- gudpy/core/gudrun_file.py | 17 ++++++++++------- gudpy/core/output_file_handler.py | 3 +++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 6801418a..fa15ee12 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -4,6 +4,7 @@ import subprocess import time import re +import tempfile from copy import deepcopy from core.utils import ( @@ -1556,13 +1557,15 @@ def dcs(self, path='', headless=True, iterative=False): path = os.path.basename(self.path) if headless: try: - gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) - result = subprocess.run( - [gudrun_dcs, path], capture_output=True, text=True - ) - os.chdir(cwd) + with tempfile.TemporaryDirectory() as tmp: + self.setGudrunDir(tmp) + gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") + cwd = os.getcwd() + os.chdir(self.instrument.GudrunInputFileDir) + result = subprocess.run( + [gudrun_dcs, path], capture_output=True, text=True + ) + os.chdir(cwd) except FileNotFoundError: os.chdir(cwd) return False diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index ff8ab9b0..64e98464 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -20,11 +20,14 @@ def __init__(self, gudrunFile, head="", overwrite=True): Whether or not to overwrite previous output directiory, by default True """ + self.gudrunFile = gudrunFile # List of run samples self.samples = [] # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir + # Make sure it is a temporary directory + assert (self.gudrunDir.startswith(tempfile.gettempdir())) # Temporary output dir paths self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( self.gudrunFile.filename)[0]) From a3f6d6591fca26858886426690d5920c5c34e842 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Fri, 20 Oct 2023 16:36:17 +0100 Subject: [PATCH 055/165] Fix bug --- gudpy/core/gudrun_file.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index fa15ee12..c0b7d666 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1556,8 +1556,8 @@ def dcs(self, path='', headless=True, iterative=False): if not path: path = os.path.basename(self.path) if headless: - try: - with tempfile.TemporaryDirectory() as tmp: + with tempfile.TemporaryDirectory() as tmp: + try: self.setGudrunDir(tmp) gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") cwd = os.getcwd() @@ -1566,12 +1566,12 @@ def dcs(self, path='', headless=True, iterative=False): [gudrun_dcs, path], capture_output=True, text=True ) os.chdir(cwd) - except FileNotFoundError: - os.chdir(cwd) - return False - if not iterative: - self.organiseOutput() - return result + except FileNotFoundError: + os.chdir(cwd) + return False + if not iterative: + self.organiseOutput() + return result else: if hasattr(sys, '_MEIPASS'): gudrun_dcs = os.path.join(sys._MEIPASS, f"gudrun_dcs{SUFFIX}") From 487e3dca5312e9a5dcacfd800fe8b426383c988e Mon Sep 17 00:00:00 2001 From: rhinoella Date: Mon, 23 Oct 2023 10:00:35 +0100 Subject: [PATCH 056/165] Bug fixes --- gudpy/core/gud_file.py | 2 +- gudpy/core/gudrun_file.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index 82f5c690..a5780939 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -123,7 +123,7 @@ def __init__(self, path): if not self.path.endswith(".gud"): raise ParserException("Only .gud files can be parsed.") - if not os.path.isfile(os.path.abspath(self.path)): + if not os.path.isfile(self.path): raise ParserException(f"{self.path} is not a valid path.") # Parse the GudFile diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index c0b7d666..27c68f5c 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1565,12 +1565,11 @@ def dcs(self, path='', headless=True, iterative=False): result = subprocess.run( [gudrun_dcs, path], capture_output=True, text=True ) + self.organiseOutput() os.chdir(cwd) except FileNotFoundError: os.chdir(cwd) return False - if not iterative: - self.organiseOutput() return result else: if hasattr(sys, '_MEIPASS'): From e287fc7967610a6976248f94bf75821d93d536ca Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:03:29 +0100 Subject: [PATCH 057/165] Output file handler returns path information --- gudpy/core/gudrun_file.py | 7 +- gudpy/core/output_file_handler.py | 78 +++++++++-- gudpy/test/test_gudpy_workflows.py | 200 +++++++++-------------------- 3 files changed, 134 insertions(+), 151 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 27c68f5c..9426deb4 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -146,15 +146,18 @@ def __init__(self, path=None, format=Format.YAML, config_=False): If a new input file should be constructed from a config """ + # Path and filename of initial input file self.path = path self.inputFileDir = os.path.dirname(path) self.filename = os.path.basename(path) self.yaml = YAML() self.format = format - # Construct the outpath. + # Construct the outpath of generated input file self.outpath = "gudpy.txt" + self.outputDir = "" self.components = Components(components=[]) + self.gudrunOutput = None if isinstance(path, type(None)): self.instrument = Instrument() @@ -1565,7 +1568,7 @@ def dcs(self, path='', headless=True, iterative=False): result = subprocess.run( [gudrun_dcs, path], capture_output=True, text=True ) - self.organiseOutput() + self.gudrunOutput = self.organiseOutput() os.chdir(cwd) except FileNotFoundError: os.chdir(cwd) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 64e98464..3ba9bfa6 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -1,9 +1,26 @@ import os import shutil +import typing +from dataclasses import dataclass from core.utils import makeDir, uniquify import tempfile +@dataclass +class SampleOutput: + sampleFile: str + gudFile: str + outputs: typing.Dict[str, str] + + +@dataclass +class GudrunOutput: + path: str + name: str + inputFile: str + sampleOutputs: typing.Dict[str, SampleOutput] + + class OutputFileHandler(): def __init__(self, gudrunFile, head="", overwrite=True): @@ -74,14 +91,19 @@ def __init__(self, gudrunFile, head="", overwrite=True): def organiseOutput(self): """Organises Gudrun outputs + + Returns + ------- + GudrunOutput : GudrunOutput + Dataclass containing information about important paths """ # Create normalisation and sample background folders self._createNormDir(self.tempOutDir) self._createSampleBgDir(self.tempOutDir) # Create sample folders - self._createSampleDir(self.tempOutDir) + sampleOutputs = self._createSampleDir(self.tempOutDir) # Create additonal output folders - self._createAddOutDir(self.tempOutDir) + inputFile = self._createAddOutDir(self.tempOutDir) # Move over folders to output directory makeDir(self.outputDir) for root, dirs, files in os.walk(self.tempOutDir): @@ -95,6 +117,12 @@ def organiseOutput(self): os.path.join(root, f), os.path.join(r, f) ) + + return GudrunOutput(path=self.outputDir, + name=os.path.splitext(self.gudrunFile.filename)[0], + inputFile=inputFile, + sampleOutputs=sampleOutputs + ) def _createNormDir(self, dest): """ @@ -152,8 +180,15 @@ def _createSampleDir(self, dest): Target basename if running iteratively, is the root folder of the sample folders by default "" + + Returns + -------- + sampleOutputs : Dict[str, SampleOutput] + Dictionary mapping sample names to the paths + of their useful outputs """ + sampleOutputs = {} # Create sample folders within background folders for sample in self.samples: samplePath = os.path.join( @@ -161,32 +196,40 @@ def _createSampleDir(self, dest): sample.name ) # Move datafiles to sample folder - for dataFile in sample.dataFiles: - self._copyOutputsByExt( + for idx, dataFile in enumerate(sample.dataFiles): + out = self._copyOutputsByExt( dataFile, samplePath ) + if idx == 0: + sampleOutput = out + gudFile = out[".gud"] # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): + sampleFile = os.path.join(samplePath, sample.pathName()) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), - os.path.join(samplePath, sample.pathName()) + sampleFile ) self.copiedFiles.append(sample.pathName()) + + sampleOutputs[sample.name] = SampleOutput( + sampleFile, gudFile, sampleOutput) # Create container folders within sample folder for container in sample.containers: - containerPath = uniquify(os.path.join( + containerPath = os.path.join( samplePath, (container.name.replace(" ", "_") if container.name != "CONTAINER" - else "Container"))) + else "Container")) for dataFile in container.dataFiles: self._copyOutputs( dataFile, containerPath ) + return sampleOutputs def _createAddOutDir(self, dest): """ @@ -197,14 +240,20 @@ def _createAddOutDir(self, dest): ---------- dest : str Directory for the files to be copied to + + Returns + ------- + inputFile : str + Path to the input file """ addDir = makeDir(os.path.join(dest, "AdditionalOutputs")) for f in os.listdir(self.gudrunDir): if f == self.gudrunFile.outpath: + inputFile = os.path.join(dest, f) shutil.copyfile( os.path.join(self.gudrunDir, f), - os.path.join(dest, f) + inputFile ) elif f not in self.copiedFiles and os.path.isfile( os.path.join(self.gudrunDir, f)): @@ -212,6 +261,7 @@ def _createAddOutDir(self, dest): os.path.join(self.gudrunDir, f), os.path.join(addDir, f) ) + return inputFile def _copyOutputs(self, fpath, dest): """ @@ -259,6 +309,11 @@ def _copyOutputsByExt(self, fname, dest): List of target file extenstions dest : str Directory for the files to be copied to + + Returns + ------- + outputs : Dict[str, str] + Dictionary mapping output extension to filepath """ # Data filename fname = os.path.splitext(fname)[0] @@ -268,14 +323,19 @@ def _copyOutputsByExt(self, fname, dest): outDir = makeDir(os.path.join(runDir, "Outputs")) # Path to folder which will hold Gudrun diagnostic outputs diagDir = makeDir(os.path.join(runDir, "Diagnostics")) + + outputs = {} for f in os.listdir(self.gudrunDir): # If the file has the same name as requested filename fn, ext = os.path.splitext(f) if fn == fname: # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir + outputs[ext] = os.path.join(dir, f) shutil.copyfile( os.path.join(self.gudrunDir, f), - os.path.join(dir, f) + outputs[ext] ) self.copiedFiles.append(f) + return outputs + diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index a5c0d750..53972039 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -49,46 +49,30 @@ def tearDown(self) -> None: def testGudPyDCS(self): self.g.dcs() - gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf1 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[0]].gudFile + gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 14.1, 0) - gfPath = self.g.sampleBackgrounds[0].samples[1].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf2 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[1]].gudFile + gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[2].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf3 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[2]].gudFile + gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 98.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[3].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf4 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[3]].gudFile + gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 13.0, 0) @@ -134,46 +118,30 @@ def testGudPyIterateByTweakFactor(self): tweakFactorIterator = TweakFactorIterator(self.g, 5) tweakFactorIterator.iterate() - gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf1 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[0]].gudFile + gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[1].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf2 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[1]].gudFile + gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[2].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf3 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[2]].gudFile + gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[3].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf4 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[3]].gudFile + gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) @@ -184,46 +152,30 @@ def testGudPyIterateByThickness(self): thicknessIterator = ThicknessIterator(self.g, 5) thicknessIterator.iterate() - gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf1 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[0]].gudFile + gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[1].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf2 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[1]].gudFile + gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[2].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf3 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[2]].gudFile + gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[3].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf4 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[3]].gudFile + gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) @@ -234,46 +186,30 @@ def testGudPyIterateByDensity(self): densityIterator = DensityIterator(self.g, 5) densityIterator.iterate() - gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf1 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[0]].gudFile + gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[1].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf2 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[1]].gudFile + gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[2].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf3 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[2]].gudFile + gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[3].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf4 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[3]].gudFile + gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) @@ -284,46 +220,30 @@ def testIterateByThickness(self): thicknessIterator = ThicknessIterator(self.g, 5) thicknessIterator.iterate() - gfPath = self.g.sampleBackgrounds[0].samples[0].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf1 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[0]].gudFile + gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[1].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf2 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[1]].gudFile + gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[2].dataFiles.dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf3 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[2]].gudFile + gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.sampleBackgrounds[0].samples[3].dataFiles[0] - gfPath = gfPath.replace(self.g.instrument.dataFileType, 'gud') - gf4 = GudFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, gfPath - ) - ) + gfPath = self.g.gudrunOutput.sampleOutputs[ + self.g.sampleBackgrounds[0].samples[3]].gudFile + gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) From 45f6dd0fbecb356eb00c3989c9887b9501462071 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:05:44 +0100 Subject: [PATCH 058/165] Fixing nTotal in init composition --- gudpy/core/iterators/composition.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index a3fc3074..a63e9f89 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -106,11 +106,11 @@ class CompositionIterator(): name = "IterateByComposition" - def __init__(self, gudrunFile, nTotal): + def __init__(self, gudrunFile): self.gudrunFile = gudrunFile self.components = [] self.ratio = 0 - self.nTotal = nTotal + self.nTotal = 0 self.nCurrent = 0 """ From 0ced5aadc03985330eeb20ab4cd8bc21343fa137 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:08:20 +0100 Subject: [PATCH 059/165] Fix tests --- gudpy/test/test_gudpy_workflows.py | 44 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 53972039..0659320a 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -50,28 +50,28 @@ def testGudPyDCS(self): self.g.dcs() gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0]].gudFile + self.g.sampleBackgrounds[0].samples[0].name].gudFile gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 14.1, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1]].gudFile + self.g.sampleBackgrounds[0].samples[1].name].gudFile gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2]].gudFile + self.g.sampleBackgrounds[0].samples[2].name].gudFile gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 98.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3]].gudFile + self.g.sampleBackgrounds[0].samples[3].name].gudFile gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -79,7 +79,7 @@ def testGudPyDCS(self): for sample in self.g.sampleBackgrounds[0].samples: - mintFilename = ( +.name mintFilename = ( sample.dataFiles[0].replace( self.g.instrument.dataFileType, "mint01" ) @@ -119,28 +119,28 @@ def testGudPyIterateByTweakFactor(self): tweakFactorIterator.iterate() gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0]].gudFile + self.g.sampleBackgrounds[0].samples[0].name].gudFile gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1]].gudFile + self.g.sampleBackgrounds[0].samples[1].name].gudFile gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2]].gudFile + self.g.sampleBackgrounds[0].samples[2].name].gudFile gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3]].gudFile + self.g.sampleBackgrounds[0].samples[3].name].gudFile gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -153,28 +153,28 @@ def testGudPyIterateByThickness(self): thicknessIterator.iterate() gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0]].gudFile + self.g.sampleBackgrounds[0].samples[0].name].gudFile gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1]].gudFile + self.g.sampleBackgrounds[0].samples[1].name].gudFile gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2]].gudFile + self.g.sampleBackgrounds[0].samples[2].name].gudFile gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3]].gudFile + self.g.sampleBackgrounds[0].samples[3].name].gudFile gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -187,28 +187,28 @@ def testGudPyIterateByDensity(self): densityIterator.iterate() gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0]].gudFile + self.g.sampleBackgrounds[0].samples[0].name].gudFile gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1]].gudFile + self.g.sampleBackgrounds[0].samples[1].name].gudFile gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2]].gudFile + self.g.sampleBackgrounds[0].samples[2].name].gudFile gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3]].gudFile + self.g.sampleBackgrounds[0].samples[3].name].gudFile gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -221,28 +221,28 @@ def testIterateByThickness(self): thicknessIterator.iterate() gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0]].gudFile + self.g.sampleBackgrounds[0].samples[0].name].gudFile gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1]].gudFile + self.g.sampleBackgrounds[0].samples[1].name].gudFile gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2]].gudFile + self.g.sampleBackgrounds[0].samples[2].name].gudFile gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3]].gudFile + self.g.sampleBackgrounds[0].samples[3].name].gudFile gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -293,7 +293,7 @@ def testGudPyIterateBySubtractingWavelength(self): for sample in [ x for x in self.g.sampleBackgrounds[0].samples - if x.runThisSample + .name if x.runThisSample ]: mintFilename = ( sample.dataFiles[0].replace( From dfc3e99fc840f08393c00ff7855dbe4bbd6dbc2c Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:19:47 +0100 Subject: [PATCH 060/165] Fixing tests --- gudpy/core/output_file_handler.py | 3 +++ gudpy/test/test_gud_file.py | 32 +++++++------------------------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 3ba9bfa6..d9daa100 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -20,6 +20,9 @@ class GudrunOutput: inputFile: str sampleOutputs: typing.Dict[str, SampleOutput] + def gudFiles(self) -> list[str]: + return list(self.sampleOutputs.values()) + class OutputFileHandler(): diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index b6d962bd..6da805ae 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -276,9 +276,7 @@ def testValidPath(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, "NIMROD00016608_H2O_in_N9.gud" - ) + g.gudrunOutput.gudFile(0) ) self.assertIsInstance(gf, GudFile) @@ -288,9 +286,7 @@ def testLoadGudFileA(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, "NIMROD00016608_H2O_in_N9.gud" - ) + g.gudrunOutput.gudFile(0) ) self.assertIsInstance(gf, GudFile) @@ -335,10 +331,7 @@ def testLoadGudFileB(self): g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, - "NIMROD00016609_D2O_in_N10.gud" - ) + g.gudrunOutput.gudFile(1) ) self.assertIsInstance(gf, GudFile) @@ -382,9 +375,7 @@ def testLoadGudFileC(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, "NIMROD00016741_HDO_in_N6.gud" - ) + g.gudrunOutput.gudFile(2) ) self.assertIsInstance(gf, GudFile) @@ -428,10 +419,7 @@ def testLoadGudFileD(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, - "NIMROD00016742_NullWater_in_N8.gud" - ) + g.gudrunOutput.gudFile(3) ) self.assertIsInstance(gf, GudFile) @@ -475,10 +463,7 @@ def testWriteGudFileA(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, - "NIMROD00016742_NullWater_in_N8.gud" - ) + g.gudrunOutput.gudFile(3) ) gf.write_out() gf1 = GudFile(gf.outpath) @@ -504,10 +489,7 @@ def testWriteGudFileB(self): format=Format.TXT) g.dcs() gf = GudFile( - os.path.join( - g.instrument.GudrunInputFileDir, - "NIMROD00016742_NullWater_in_N8.gud" - ) + g.gudrunOutput.gudFile(3) ) gf.write_out() gf1 = GudFile(gf.outpath) From ddcf49a378b94626b03ea781eb99c22811554a09 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:23:37 +0100 Subject: [PATCH 061/165] Fixing tests --- gudpy/core/output_file_handler.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index d9daa100..198b632a 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -23,6 +23,9 @@ class GudrunOutput: def gudFiles(self) -> list[str]: return list(self.sampleOutputs.values()) + def gudFile(self, idx: int) -> str: + return list(self.sampleOutputs.values())[idx] + class OutputFileHandler(): From dbaa9c04c85d468cf312e5c64bdf03363c80373c Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:26:05 +0100 Subject: [PATCH 062/165] Formatting --- gudpy/core/output_file_handler.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 198b632a..b3353436 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -2,7 +2,7 @@ import shutil import typing from dataclasses import dataclass -from core.utils import makeDir, uniquify +from core.utils import makeDir import tempfile @@ -123,7 +123,7 @@ def organiseOutput(self): os.path.join(root, f), os.path.join(r, f) ) - + return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], inputFile=inputFile, @@ -186,7 +186,7 @@ def _createSampleDir(self, dest): Target basename if running iteratively, is the root folder of the sample folders by default "" - + Returns -------- sampleOutputs : Dict[str, SampleOutput] @@ -219,7 +219,7 @@ def _createSampleDir(self, dest): sampleFile ) self.copiedFiles.append(sample.pathName()) - + sampleOutputs[sample.name] = SampleOutput( sampleFile, gudFile, sampleOutput) @@ -315,7 +315,7 @@ def _copyOutputsByExt(self, fname, dest): List of target file extenstions dest : str Directory for the files to be copied to - + Returns ------- outputs : Dict[str, str] From 0083fb47b505f74a01e04802ffdbbcb826193e4f Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:31:21 +0100 Subject: [PATCH 063/165] Formatting --- gudpy/core/output_file_handler.py | 1 - gudpy/test/test_gudpy_workflows.py | 9 ++++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index b3353436..6105b7ce 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -344,4 +344,3 @@ def _copyOutputsByExt(self, fname, dest): ) self.copiedFiles.append(f) return outputs - diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 0659320a..dba14957 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -78,8 +78,7 @@ def testGudPyDCS(self): self.assertAlmostEqual(dcsLevelPercentage, 13.0, 0) for sample in self.g.sampleBackgrounds[0].samples: - -.name mintFilename = ( + mintFilename = ( sample.dataFiles[0].replace( self.g.instrument.dataFileType, "mint01" ) @@ -291,9 +290,9 @@ def testGudPyIterateBySubtractingWavelength(self): inelasitictyIterator.iterate() for sample in [ - x - for x in self.g.sampleBackgrounds[0].samples - .name if x.runThisSample + x + for x in self.g.sampleBackgrounds[0].samples + if x.runThisSample ]: mintFilename = ( sample.dataFiles[0].replace( From ca26cd2af9853abbe9826116bc6699bf9708214f Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:42:27 +0100 Subject: [PATCH 064/165] Bug fix --- gudpy/core/output_file_handler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 6105b7ce..24543388 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -24,7 +24,10 @@ def gudFiles(self) -> list[str]: return list(self.sampleOutputs.values()) def gudFile(self, idx: int) -> str: - return list(self.sampleOutputs.values())[idx] + asList = list(self.sampleOutputs.values()) + if idx >= len(asList): + return "" + return asList[idx] class OutputFileHandler(): @@ -209,7 +212,7 @@ def _createSampleDir(self, dest): ) if idx == 0: sampleOutput = out - gudFile = out[".gud"] + gudFile = out[".gud"] if ".gud" in out else "" # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): From fa6dd59396aed114dfb791070daf5833ba01967e Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:54:24 +0100 Subject: [PATCH 065/165] Fixing undeclared var issue --- gudpy/core/output_file_handler.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 24543388..1b69d5f9 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -25,8 +25,7 @@ def gudFiles(self) -> list[str]: def gudFile(self, idx: int) -> str: asList = list(self.sampleOutputs.values()) - if idx >= len(asList): - return "" + assert (idx < len(asList)) return asList[idx] @@ -200,6 +199,10 @@ def _createSampleDir(self, dest): sampleOutputs = {} # Create sample folders within background folders for sample in self.samples: + sampleFile = "" + gudFile = "" + sampleOutput = {} + samplePath = os.path.join( dest, sample.name @@ -256,6 +259,7 @@ def _createAddOutDir(self, dest): Path to the input file """ addDir = makeDir(os.path.join(dest, "AdditionalOutputs")) + inputFile = "" for f in os.listdir(self.gudrunDir): if f == self.gudrunFile.outpath: From 27db47acdcc5177b0c10ed680f9ffa93256d56f2 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 14:58:18 +0100 Subject: [PATCH 066/165] Fix write_out --- gudpy/core/gudrun_file.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 9426deb4..c030ab84 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1501,10 +1501,8 @@ def write_out(self, path='', overwrite=False, writeParameters=True): ) elif not overwrite: f = open( - os.path.join( - self.instrument.GudrunInputFileDir, - self.outpath - ), "w", encoding="utf-8") + self.gudrunOutput.inputFile, + "w", encoding="utf-8") else: f = open(self.path, "w", encoding="utf-8") if os.path.basename(f.name) == self.outpath: @@ -1521,10 +1519,8 @@ def write_out(self, path='', overwrite=False, writeParameters=True): gf.sampleBackgrounds = [deepcopy(sb)] gf.sampleBackgrounds[0].samples = [deepcopy(s)] gf.write_out( - path=os.path.join( - self.instrument.GudrunInputFileDir, - s.pathName(), - ), + path=self.gudrunOutput.sampleOutputs[ + s.name].sampleFile, overwrite=True, writeParameters=False ) From 28781ce78cb9267dffad03f4b1fbc5daf4dffaaf Mon Sep 17 00:00:00 2001 From: rhinoella Date: Tue, 24 Oct 2023 16:45:35 +0100 Subject: [PATCH 067/165] Attempt to fix tests and improve iterators --- gudpy/core/gud_file.py | 2 +- gudpy/core/gudrun_file.py | 27 ++++--- .../iterators/inelasticity_subtraction.py | 2 +- gudpy/core/iterators/iterator.py | 13 +--- gudpy/core/iterators/tweak_factor.py | 4 +- gudpy/core/output_file_handler.py | 33 +++++---- gudpy/test/test_gudpy_io.py | 70 ++++++++----------- gudpy/test/test_purge_file.py | 5 +- 8 files changed, 79 insertions(+), 77 deletions(-) diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index a5780939..3e27d764 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -121,7 +121,7 @@ def __init__(self, path): # Handle edge cases - invalid extensions and paths. if not self.path.endswith(".gud"): - raise ParserException("Only .gud files can be parsed.") + raise ParserException(f"Attempted to parse {self.path}\nOnly .gud files can be parsed.") if not os.path.isfile(self.path): raise ParserException(f"{self.path} is not a valid path.") diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index c030ab84..fe8b1e28 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1501,8 +1501,10 @@ def write_out(self, path='', overwrite=False, writeParameters=True): ) elif not overwrite: f = open( - self.gudrunOutput.inputFile, - "w", encoding="utf-8") + os.path.join( + self.instrument.GudrunInputFileDir, + self.outpath + ), "w", encoding="utf-8") else: f = open(self.path, "w", encoding="utf-8") if os.path.basename(f.name) == self.outpath: @@ -1519,8 +1521,10 @@ def write_out(self, path='', overwrite=False, writeParameters=True): gf.sampleBackgrounds = [deepcopy(sb)] gf.sampleBackgrounds[0].samples = [deepcopy(s)] gf.write_out( - path=self.gudrunOutput.sampleOutputs[ - s.name].sampleFile, + path=os.path.join( + self.instrument.GudrunInputFileDir, + s.pathName(), + ), overwrite=True, writeParameters=False ) @@ -1529,7 +1533,7 @@ def setGudrunDir(self, dir): assert (os.path.isdir(os.path.abspath(dir))) self.instrument.GudrunInputFileDir = dir - def dcs(self, path='', headless=True, iterative=False): + def dcs(self, path='', headless=True, iterator=None): """ Call gudrun_dcs on the path supplied. If the path is its default value, @@ -1564,7 +1568,11 @@ def dcs(self, path='', headless=True, iterative=False): result = subprocess.run( [gudrun_dcs, path], capture_output=True, text=True ) - self.gudrunOutput = self.organiseOutput() + if iterator is not None: + self.gudrunOutput = iterator.organiseOutput() + else: + self.gudrunOutput = self.organiseOutput() + self.setGudrunDir(self.gudrunOutput.path) os.chdir(cwd) except FileNotFoundError: os.chdir(cwd) @@ -1594,7 +1602,7 @@ def dcs(self, path='', headless=True, iterative=False): ] ) - def process(self, headless=True, iterative=False): + def process(self, headless=True, iterator=None): """ Write out the current state of the file, and then call gudrun_dcs on the file that @@ -1616,7 +1624,7 @@ def process(self, headless=True, iterative=False): dcs = self.dcs( path=self.outpath, headless=headless, - iterative=iterative + iterator=iterator ) os.chdir(cwd) return dcs @@ -1657,7 +1665,8 @@ def organiseOutput(self, head="", overwrite=True): outputHandler = OutputFileHandler( self, head=head, overwrite=overwrite ) - outputHandler.organiseOutput() + gudrunOutput = outputHandler.organiseOutput() + return gudrunOutput def determineError(self, sample): gudPath = sample.dataFiles[0].replace( diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 611d3e07..1f6d99b3 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -272,6 +272,6 @@ def iterate(self): for _ in range(self.nTotal): self.performIteration() - self.gudrunFile.process(iterative=True) + self.gudrunFile.process(iterator=self) time.sleep(1) self.organiseOutput() diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index c2180bf7..7e9ce744 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -65,15 +65,8 @@ def performIteration(self): s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles) ]: - gudPath = sample.dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) gudFile = GudFile( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - gudPath - ) + self.gudrunFile.gudrunOutput.gudFile(sample.name) ) # Calculate coefficient: actualDCSLevel / expectedDCSLevel coefficient = ( @@ -117,8 +110,8 @@ def iterate(self): n : int Number of iterations to perform. """ + self.gudrunFile.process(iterator=self) for _ in range(self.nTotal): - self.gudrunFile.process() time.sleep(1) self.performIteration() - self.organiseOutput() + self.gudrunFile.process(iterator=self) diff --git a/gudpy/core/iterators/tweak_factor.py b/gudpy/core/iterators/tweak_factor.py index edfa7d12..1ae206d4 100644 --- a/gudpy/core/iterators/tweak_factor.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -79,12 +79,12 @@ def iterate(self): n : int Number of iterations to perform. """ + self.gudrunFile.process(iterator=self) # Perform n iterations of tweaking by tweak factor. for _ in range(self.nTotal): # Write out what we currently have, # and run gudrun_dcs on that file. - self.gudrunFile.process(iterative=True) time.sleep(1) self.performIteration() - self.organiseOutput() + self.gudrunFile.process(itertor=self) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 1b69d5f9..d70275c1 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -21,12 +21,16 @@ class GudrunOutput: sampleOutputs: typing.Dict[str, SampleOutput] def gudFiles(self) -> list[str]: - return list(self.sampleOutputs.values()) + return [so.gudFile for so in self.sampleOutputs.values()] - def gudFile(self, idx: int) -> str: - asList = list(self.sampleOutputs.values()) - assert (idx < len(asList)) - return asList[idx] + def gudFile(self, idx: int = None, sampName: str = None) -> str: + if idx is not None: + asList = list(self.sampleOutputs.values()) + assert (idx < len(asList)) + return asList[idx].gudFile + elif sampName is not None: + assert (sampName in self.sampleOutputs) + return self.sampleOutputs[sampName].gudFile class OutputFileHandler(): @@ -205,7 +209,7 @@ def _createSampleDir(self, dest): samplePath = os.path.join( dest, - sample.name + sample.name.replace(" ", "_") ) # Move datafiles to sample folder for idx, dataFile in enumerate(sample.dataFiles): @@ -213,9 +217,10 @@ def _createSampleDir(self, dest): dataFile, samplePath ) - if idx == 0: + if idx == 0 and out[dataFile]: sampleOutput = out - gudFile = out[".gud"] if ".gud" in out else "" + gudFile = (out[dataFile][".gud"] + if ".gud" in out[dataFile] else "") # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): @@ -306,7 +311,7 @@ def _copyOutputs(self, fpath, dest): ) self.copiedFiles.append(f) - def _copyOutputsByExt(self, fname, dest): + def _copyOutputsByExt(self, fpath, dest): """ Copy all files with the same basename as the provided filepath and splits them into outputs @@ -316,7 +321,7 @@ def _copyOutputsByExt(self, fname, dest): Parameters ---------- - fname : str + fpath : str Full filename of target file suffixes : str[] List of target file extenstions @@ -329,7 +334,7 @@ def _copyOutputsByExt(self, fname, dest): Dictionary mapping output extension to filepath """ # Data filename - fname = os.path.splitext(fname)[0] + fname = os.path.splitext(fpath)[0] # Path to folder which will hold all outputs from the run runDir = os.path.join(dest, fname) # Path to folder which will hold Gudrun outputs @@ -338,16 +343,18 @@ def _copyOutputsByExt(self, fname, dest): diagDir = makeDir(os.path.join(runDir, "Diagnostics")) outputs = {} + outputs[fpath] = {} for f in os.listdir(self.gudrunDir): # If the file has the same name as requested filename fn, ext = os.path.splitext(f) if fn == fname: # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir - outputs[ext] = os.path.join(dir, f) + if dir == outDir: + outputs[fpath][ext] = os.path.join(dir, f) shutil.copyfile( os.path.join(self.gudrunDir, f), - outputs[ext] + os.path.join(dir, f) ) self.copiedFiles.append(f) return outputs diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 927708d3..d3fd677f 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -758,16 +758,17 @@ def testLoadGudrunFile(self): def testWriteGudrunFile(self): self.g.write_out() - outlines = "\n".join(open( + with open( os.path.join( self.g.instrument.GudrunInputFileDir, self.g.outpath ), encoding="utf-8" - ).readlines()[:-5]) - self.assertEqual( - outlines, "\n".join(str(self.g).splitlines(keepends=True)[:-5]) - ) + ) as f: + outlines = "\n".join(f.readlines()[:-5]) + self.assertEqual( + outlines, "\n".join(str(self.g).splitlines(keepends=True)[:-5]) + ) def valueInLines(value, lines): if isinstance(value, str): @@ -821,8 +822,9 @@ def valueInLines(value, lines): valueInLines(val, outlines) else: valueInLines(value, outlines) - - inlines = open(self.g.path).read() + inlines = "" + with open(self.g.path) as f: + inlines = f.read() for dic in self.dicts: for value in dic.values(): if isinstance(value, list): @@ -854,48 +856,38 @@ def testRewriteGudrunFile(self): g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir g1.write_out() - self.assertEqual( - "\n".join(open( + with open( os.path.join( g1.instrument.GudrunInputFileDir, g1.outpath ), encoding="utf-8" - ).readlines()[:-5]), - "\n".join(str(self.g).splitlines(keepends=True)[:-5]) - ) + ) as f: + self.assertEqual( + "\n".join(f.readlines()[:-5]), + "\n".join(str(self.g).splitlines(keepends=True)[:-5]) + ) - self.assertEqual( - "\n".join(open( + self.assertEqual( + "\n".join(f.readlines()[:-5]), + "\n".join(str(g1).splitlines(keepends=True)[:-5]) + ) + + with open( os.path.join( - g1.instrument.GudrunInputFileDir, - g1.outpath + g.instrument.GudrunInputFileDir, + g.outpath ), encoding="utf-8" - ).readlines()[:-5]), - "\n".join(str(g1).splitlines(keepends=True)[:-5]) - ) - - self.assertEqual( - "\n".join( - open( - os.path.join( - g1.instrument.GudrunInputFileDir, - g1.outpath - ), - encoding="utf-8" - ).readlines()[:-5] - ), - "\n".join( - open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath + ) as fg: + self.assertEqual( + "\n".join( + fg.readlines()[:-5] ), - encoding="utf-8" - ).readlines()[:-5] - ) - ) + "\n".join( + f.readlines()[:-5] + ) + ) def testReloadGudrunFile(self): self.g.write_out() diff --git a/gudpy/test/test_purge_file.py b/gudpy/test/test_purge_file.py index 26f2de53..cf93fb73 100644 --- a/gudpy/test/test_purge_file.py +++ b/gudpy/test/test_purge_file.py @@ -61,5 +61,6 @@ def testWritePurgeFile(self): purge = PurgeFile(self.g) purge.write_out() - outlines = open("purge_det.dat", encoding="utf-8").read() - self.assertEqual(outlines, str(purge)) + with open("purge_det.dat", encoding="utf-8") as f: + outlines = f.read() + self.assertEqual(outlines, str(purge)) From 85f6555fa55b05304ccf5f0baf37a6199b4d1986 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 25 Oct 2023 11:53:43 +0100 Subject: [PATCH 068/165] Fixed errors --- gudpy/core/iterators/iterator.py | 5 +++-- gudpy/core/output_file_handler.py | 31 ++++++++++++++++++--------- gudpy/gui/widgets/core/main_window.py | 2 +- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 7e9ce744..934de44a 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -66,7 +66,7 @@ def performIteration(self): if s.runThisSample and len(s.dataFiles) ]: gudFile = GudFile( - self.gudrunFile.gudrunOutput.gudFile(sample.name) + self.gudrunFile.gudrunOutput.gudFile(name=sample.name) ) # Calculate coefficient: actualDCSLevel / expectedDCSLevel coefficient = ( @@ -95,7 +95,8 @@ def organiseOutput(self): """ This organises the output of the iteration. """ - self.gudrunFile.organiseOutput() + gudrunOutput = self.gudrunFile.organiseOutput() + return gudrunOutput def iterate(self): """ diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index d70275c1..f640348a 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -23,14 +23,14 @@ class GudrunOutput: def gudFiles(self) -> list[str]: return [so.gudFile for so in self.sampleOutputs.values()] - def gudFile(self, idx: int = None, sampName: str = None) -> str: + def gudFile(self, idx: int = None, *, name: str = None) -> str: if idx is not None: asList = list(self.sampleOutputs.values()) assert (idx < len(asList)) return asList[idx].gudFile - elif sampName is not None: - assert (sampName in self.sampleOutputs) - return self.sampleOutputs[sampName].gudFile + elif name is not None: + assert (name in self.sampleOutputs) + return self.sampleOutputs[name].gudFile class OutputFileHandler(): @@ -67,7 +67,8 @@ def __init__(self, gudrunFile, head="", overwrite=True): # Name the output directory as the input file self.outputDir = os.path.join( self.gudrunFile.inputFileDir, - os.path.splitext(self.gudrunFile.filename)[0] + os.path.splitext(self.gudrunFile.filename)[0], + f"{head}" ) # Files that have been copied self.copiedFiles = [] @@ -129,6 +130,9 @@ def organiseOutput(self): os.path.join(root, f), os.path.join(r, f) ) + + for key, val in sampleOutputs.items(): + print(f"{key} {val}") return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], @@ -224,13 +228,18 @@ def _createSampleDir(self, dest): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): - sampleFile = os.path.join(samplePath, sample.pathName()) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), - sampleFile + os.path.join(samplePath, sample.pathName()) ) self.copiedFiles.append(sample.pathName()) + # Path to sample file output + sampleFile = os.path.join( + self.outputDir, + sample.name.replace(" ", "_"), + sample.pathName()) + sampleOutputs[sample.name] = SampleOutput( sampleFile, gudFile, sampleOutput) @@ -268,10 +277,11 @@ def _createAddOutDir(self, dest): for f in os.listdir(self.gudrunDir): if f == self.gudrunFile.outpath: - inputFile = os.path.join(dest, f) + inputFile = os.path.join( + self.outputDir, "AdditionalOutputs", f) shutil.copyfile( os.path.join(self.gudrunDir, f), - inputFile + os.path.join(addDir, f) ) elif f not in self.copiedFiles and os.path.isfile( os.path.join(self.gudrunDir, f)): @@ -351,7 +361,8 @@ def _copyOutputsByExt(self, fpath, dest): # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir if dir == outDir: - outputs[fpath][ext] = os.path.join(dir, f) + outputs[fpath][ext] = os.path.join( + self.outputDir, "Outputs", f) shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(dir, f) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 6d43b6dd..cb4294d1 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1562,7 +1562,7 @@ def nextIteration(self): if self.error: self.procFinished(9, QProcess.NormalExit) return - self.iterator.organiseOutput() + self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() if self.iterator.nCurrent != -1: # If this is not the default run self.outputIterations[ From 437cd9568084e55904f6ac53721ddc5192892854 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 25 Oct 2023 13:24:56 +0100 Subject: [PATCH 069/165] Fixed linting --- gudpy/core/gud_file.py | 3 ++- gudpy/core/iterators/iterator.py | 1 - gudpy/test/test_gudpy_io.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index 3e27d764..b6267b2a 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -121,7 +121,8 @@ def __init__(self, path): # Handle edge cases - invalid extensions and paths. if not self.path.endswith(".gud"): - raise ParserException(f"Attempted to parse {self.path}\nOnly .gud files can be parsed.") + raise ParserException(f"Attempted to parse {self.path}" + + "\nOnly .gud files can be parsed.") if not os.path.isfile(self.path): raise ParserException(f"{self.path} is not a valid path.") diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 934de44a..188ce03a 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -1,4 +1,3 @@ -import os import time from core.gud_file import GudFile diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index d3fd677f..837bd2ed 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -875,8 +875,8 @@ def testRewriteGudrunFile(self): with open( os.path.join( - g.instrument.GudrunInputFileDir, - g.outpath + self.g.instrument.GudrunInputFileDir, + self.g.outpath ), encoding="utf-8" ) as fg: From 2f22aa3af99c394cd960b487039fbc8ea1866a1b Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 25 Oct 2023 13:27:30 +0100 Subject: [PATCH 070/165] Linting --- gudpy/core/output_file_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index f640348a..0e022ef0 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -130,7 +130,7 @@ def organiseOutput(self): os.path.join(root, f), os.path.join(r, f) ) - + for key, val in sampleOutputs.items(): print(f"{key} {val}") From 62775ef8d8eeda74c7cac234c23f17c788c1cdb1 Mon Sep 17 00:00:00 2001 From: rhinoella Date: Wed, 25 Oct 2023 13:55:28 +0100 Subject: [PATCH 071/165] WIP Fix --- gudpy/core/output_file_handler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 0e022ef0..bf29a7de 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -131,9 +131,6 @@ def organiseOutput(self): os.path.join(r, f) ) - for key, val in sampleOutputs.items(): - print(f"{key} {val}") - return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], inputFile=inputFile, From 6c191ba2e648a19e503261bb4e92b30b92820b92 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 26 Oct 2023 13:29:44 +0100 Subject: [PATCH 072/165] Changing temp directory control --- gudpy/core/gudrun_file.py | 40 ++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index fe8b1e28..cbf80032 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1559,25 +1559,27 @@ def dcs(self, path='', headless=True, iterator=None): if not path: path = os.path.basename(self.path) if headless: - with tempfile.TemporaryDirectory() as tmp: - try: - self.setGudrunDir(tmp) - gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) - result = subprocess.run( - [gudrun_dcs, path], capture_output=True, text=True - ) - if iterator is not None: - self.gudrunOutput = iterator.organiseOutput() - else: - self.gudrunOutput = self.organiseOutput() - self.setGudrunDir(self.gudrunOutput.path) - os.chdir(cwd) - except FileNotFoundError: - os.chdir(cwd) - return False - return result + tmp = tempfile.TemporaryDirectory() + try: + self.setGudrunDir(tmp.name) + gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") + cwd = os.getcwd() + os.chdir(self.instrument.GudrunInputFileDir) + result = subprocess.run( + [gudrun_dcs, path], capture_output=True, text=True + ) + if iterator is not None: + self.gudrunOutput = iterator.organiseOutput() + else: + self.gudrunOutput = self.organiseOutput() + self.setGudrunDir(self.gudrunOutput.path) + tmp.cleanup() + os.chdir(cwd) + except FileNotFoundError: + tmp.cleanup() + os.chdir(cwd) + return False + return result else: if hasattr(sys, '_MEIPASS'): gudrun_dcs = os.path.join(sys._MEIPASS, f"gudrun_dcs{SUFFIX}") From cc744b5c8096e74a37394add72554bd11efd3164 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 26 Oct 2023 13:39:05 +0100 Subject: [PATCH 073/165] Debug --- gudpy/core/gudrun_file.py | 2 ++ gudpy/core/iterators/inelasticity_subtraction.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index cbf80032..7a6599a6 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1568,6 +1568,8 @@ def dcs(self, path='', headless=True, iterator=None): result = subprocess.run( [gudrun_dcs, path], capture_output=True, text=True ) + for f in os.listdir(tmp.name): + print(f) if iterator is not None: self.gudrunOutput = iterator.organiseOutput() else: diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 1f6d99b3..09bd4db6 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -259,7 +259,7 @@ def organiseOutput(self): """ overwrite = (self.nCurrent == 1 and self.iterationType == "WavelengthIteration") - self.gudrunFile.organiseOutput( + return self.gudrunFile.organiseOutput( head=f"{self.iterationType}_{self.nCurrent}", overwrite=overwrite) From b443fb0a58aade293a25abb016d77d8f84d88bb6 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 26 Oct 2023 13:47:08 +0100 Subject: [PATCH 074/165] Cwd change --- gudpy/core/gudrun_file.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 7a6599a6..10ef944a 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1563,13 +1563,10 @@ def dcs(self, path='', headless=True, iterator=None): try: self.setGudrunDir(tmp.name) gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) result = subprocess.run( - [gudrun_dcs, path], capture_output=True, text=True + [gudrun_dcs, path], cwd=tmp.name, + capture_output=True, text=True ) - for f in os.listdir(tmp.name): - print(f) if iterator is not None: self.gudrunOutput = iterator.organiseOutput() else: From 737be49bec366018ea713fbd4c21481a2fcbc3da Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 26 Oct 2023 13:50:56 +0100 Subject: [PATCH 075/165] Fix prev commit --- gudpy/core/gudrun_file.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 10ef944a..b0d1cb4c 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1573,10 +1573,8 @@ def dcs(self, path='', headless=True, iterator=None): self.gudrunOutput = self.organiseOutput() self.setGudrunDir(self.gudrunOutput.path) tmp.cleanup() - os.chdir(cwd) except FileNotFoundError: tmp.cleanup() - os.chdir(cwd) return False return result else: From f08f6ee2fdf3b1481fbf4da297800c126947c289 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 26 Oct 2023 14:03:59 +0100 Subject: [PATCH 076/165] Debugging --- gudpy/core/gudrun_file.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index b0d1cb4c..5ac047f9 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1567,6 +1567,7 @@ def dcs(self, path='', headless=True, iterator=None): [gudrun_dcs, path], cwd=tmp.name, capture_output=True, text=True ) + print(result) if iterator is not None: self.gudrunOutput = iterator.organiseOutput() else: From a8ebc691cafd86ca343c548296144b61be54f5b8 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Fri, 27 Oct 2023 11:31:20 +0100 Subject: [PATCH 077/165] Attempt to fix test --- gudpy/test/test_gudpy_workflows.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index dba14957..c16745ec 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -21,15 +21,18 @@ class TestGudPyWorkflows(TestCase): def setUp(self) -> None: - path = os.path.abspath("test/TestData/NIMROD-water/water.txt") + testDir = os.path.dirname(__file__) + path = os.path.join( + testDir, "TestData/NIMROD-water/water.txt") - self.g = GudrunFile(os.path.abspath(path), format=Format.TXT) + self.g = GudrunFile(path, format=Format.TXT) self.keepsakes = os.listdir() - copyfile(self.g.path, "test/TestData/NIMROD-water/good_water.txt") + copyfile(self.g.path, os.path.join( + testDir, "TestData/NIMROD-water/good_water.txt") g = GudrunFile( - os.path.abspath("test/TestData/NIMROD-water/good_water.txt"), + os.path.join(testDir, "TestData/NIMROD-water/good_water.txt"), format=Format.TXT ) From 47115039d7052543df6b4410148f285504ef6415 Mon Sep 17 00:00:00 2001 From: Spitz Date: Thu, 16 Nov 2023 13:38:05 +0000 Subject: [PATCH 078/165] lint --- gudpy/test/test_gudpy_workflows.py | 1 + 1 file changed, 1 insertion(+) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index c16745ec..b6465b68 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -31,6 +31,7 @@ def setUp(self) -> None: copyfile(self.g.path, os.path.join( testDir, "TestData/NIMROD-water/good_water.txt") + ) g = GudrunFile( os.path.join(testDir, "TestData/NIMROD-water/good_water.txt"), format=Format.TXT From 789894ff1dfb0fbbf6878aadc29dceba75ec6628 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 10:26:56 +0000 Subject: [PATCH 079/165] Create base class for output handler --- gudpy/core/gudrun_file.py | 4 +-- gudpy/core/output_file_handler.py | 49 +++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 5ac047f9..cdb87940 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -29,7 +29,7 @@ from core.element import Element from core.data_files import DataFiles from core.purge_file import PurgeFile -from core.output_file_handler import OutputFileHandler +from core.output_file_handler import GudrunOutputHandler from core.enums import ( CrossSectionSource, Format, Instruments, FTModes, UnitsOfDensity, MergeWeights, Scales, NormalisationType, OutputUnits, @@ -1662,7 +1662,7 @@ def convertToSample(self, container, persist=False): return sample def organiseOutput(self, head="", overwrite=True): - outputHandler = OutputFileHandler( + outputHandler = GudrunOutputHandler( self, head=head, overwrite=overwrite ) gudrunOutput = outputHandler.organiseOutput() diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index bf29a7de..127c047a 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -33,11 +33,46 @@ def gudFile(self, idx: int = None, *, name: str = None) -> str: return self.sampleOutputs[name].gudFile -class OutputFileHandler(): +class OutputHandler: + """Class to organise purge output files + """ + + def __init__(self, gudrunFile, dirName, overwrite=True): + self.gudrunFile = gudrunFile + # Directory where files are outputted and process was run (temp) + self.procDir = self.gudrunFile.instrument.GudrunInputFileDir + # Make sure it is a temporary directory + assert (self.procDir.startswith(tempfile.gettempdir())) + # Name the output directory as the input file + self.outputDir = os.path.join( + self.gudrunFile.inputFileDir, + self.gudrunFile.projectDir, + dirName + ) + + # If output directory exists, move to a temp dir and clear it + # Avoids shutil.rmtree + if overwrite and os.path.exists(self.outputDir): + with tempfile.TemporaryDirectory() as tmp: + shutil.move(self.outputDir, os.path.join(tmp, "prev")) + + def organiseOutput(self): + """Function to move all files from the process directory to + the project directory + """ + makeDir(self.outputDir) + for f in os.listdir(self.procDir): + shutil.copyfile( + os.path.join(self.procDir, f), + os.path.join(self.outputDir, f) + ) + + +class GudrunOutputHandler(OutputHandler): def __init__(self, gudrunFile, head="", overwrite=True): """ - Initialise `OutputFileHandler` + Initialise `GudrunOutputHandler` Parameters ---------- @@ -50,7 +85,15 @@ def __init__(self, gudrunFile, head="", overwrite=True): by default True """ - self.gudrunFile = gudrunFile + super().__init__( + gudrunFile, + "Gudrun", + overwrite=overwrite + ) + + # Append head to path + self.outputDir = os.path.join(self.outputDir, f"{head}") + # List of run samples self.samples = [] # Directory where Gudrun files are outputted (temp) From eb084f473266e9c473a9dc09e2e2077276bd3d57 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 10:28:13 +0000 Subject: [PATCH 080/165] Run purge in temp dir --- gudpy/core/gudrun_file.py | 31 +++++++------- gudpy/core/purge_file.py | 28 +++++++----- gudpy/gui/widgets/core/main_window.py | 61 +++++++++++++++------------ 3 files changed, 67 insertions(+), 53 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index cdb87940..4bdab7af 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -155,7 +155,8 @@ def __init__(self, path=None, format=Format.YAML, config_=False): # Construct the outpath of generated input file self.outpath = "gudpy.txt" - self.outputDir = "" + self.projectDir = os.path.join( + self.inputFileDir, os.path.splitext(self.filename)[0]) self.components = Components(components=[]) self.gudrunOutput = None @@ -1558,24 +1559,22 @@ def dcs(self, path='', headless=True, iterator=None): if not path: path = os.path.basename(self.path) + if headless: - tmp = tempfile.TemporaryDirectory() try: - self.setGudrunDir(tmp.name) - gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - result = subprocess.run( - [gudrun_dcs, path], cwd=tmp.name, - capture_output=True, text=True - ) - print(result) - if iterator is not None: - self.gudrunOutput = iterator.organiseOutput() - else: - self.gudrunOutput = self.organiseOutput() - self.setGudrunDir(self.gudrunOutput.path) - tmp.cleanup() + with tempfile.TemporaryDirectory() as tmp: + self.setGudrunDir(tmp.name) + gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") + result = subprocess.run( + [gudrun_dcs, path], cwd=tmp.name, + capture_output=True, text=True + ) + if iterator is not None: + self.gudrunOutput = iterator.organiseOutput() + else: + self.gudrunOutput = self.organiseOutput() + self.setGudrunDir(self.gudrunOutput.path) except FileNotFoundError: - tmp.cleanup() return False return result else: diff --git a/gudpy/core/purge_file.py b/gudpy/core/purge_file.py index fc95f471..a4a3ef9e 100644 --- a/gudpy/core/purge_file.py +++ b/gudpy/core/purge_file.py @@ -1,11 +1,13 @@ import os import sys import subprocess +import tempfile from PySide6.QtCore import QProcess from core.enums import Instruments from core.utils import resolve, spacify, numifyBool from core import config +from core.output_file_handler import OutputHandler SUFFIX = ".exe" if os.name == "nt" else "" @@ -35,6 +37,7 @@ class PurgeFile(): purge() Writes out the file, and then calls purge_det on that file. """ + def __init__( self, gudrunFile @@ -248,16 +251,17 @@ def purge( self.excludeSampleAndCan = excludeSampleAndCan if headless: try: - cwd = os.getcwd() - purge_det = resolve("bin", f"purge_det{SUFFIX}") - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.write_out() - result = subprocess.run( - [purge_det, "purge_det.dat"], - capture_output=True, - text=True - ) - os.chdir(cwd) + with tempfile.TemporaryDirectory() as tmp: + self.setGudrunDir(tmp.name) + purge_det = resolve("bin", f"purge_det{SUFFIX}") + self.write_out(tmp.name) + result = subprocess.run( + [purge_det, "purge_det.dat"], + cwd=tmp.name, + capture_output=True, + text=True + ) + self.organiseOutput() except FileNotFoundError: return False return result @@ -285,3 +289,7 @@ def purge( ) ] ) + + def organiseOutput(self): + outputHandler = OutputHandler(self.gudrunFile, "Purge", overwrite=True) + outputHandler.organiseOutput() diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index cb4294d1..481e46ac 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -947,39 +947,15 @@ def prepareRun(self): self.gudrunFile.setGudrunDir(self.tmp.name) def cleanupRun(self): - self.tmp.cleanup() - self.tmp = None + if self.tmp: + self.tmp.cleanup() + self.tmp = None self.setControlsEnabled(True) self.mainWidget.progressBar.setValue(0) self.mainWidget.currentTaskLabel.setText("No task running.") self.queue = Queue() - def runPurge_(self): - self.prepareRun() - - purgeDialog = PurgeDialog(self.gudrunFile, self) - result = purgeDialog.widget.exec_() - purge = purgeDialog.purge_det - if isinstance(purge, Sequence): - purge, func, args = purge - if purgeDialog.cancelled or result == QDialogButtonBox.No: - self.setControlsEnabled(True) - self.queue = Queue() - elif isinstance(purge, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find purge_det binary.", - ) - self.setControlsEnabled(True) - elif not purge: - self.setControlsEnabled(True) - else: - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.gudrunFile.purgeFile.write_out() - self.makeProc(purge, self.progressPurge, func=func, args=args) - def runGudrun_(self): self.prepareRun() @@ -1160,6 +1136,7 @@ def purgeOptionsMessageBox(self, dcs, finished, func, args, text): def purgeBeforeRunning(self, default=True): self.setControlsEnabled(False) if default: + self.prepareRun() purge_det = self.gudrunFile.purge(headless=False) if isinstance(purge_det, Sequence): purge, func, args = purge_det @@ -1799,6 +1776,33 @@ def progressDCS(self): progress if progress <= 100 else 100 ) + def runPurge_(self): + self.prepareRun() + + purgeDialog = PurgeDialog(self.gudrunFile, self) + result = purgeDialog.widget.exec_() + purge = purgeDialog.purge_det + if isinstance(purge, Sequence): + purge, func, args = purge + if purgeDialog.cancelled or result == QDialogButtonBox.No: + self.setControlsEnabled(True) + self.queue = Queue() + elif isinstance(purge, FileNotFoundError): + QMessageBox.critical( + self.mainWidget, + "GudPy Error", + "Couldn't find purge_det binary.", + ) + self.setControlsEnabled(True) + elif not purge: + self.setControlsEnabled(True) + else: + os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) + self.gudrunFile.purgeFile.write_out() + self.makeProc(purge, self.progressPurge, func=func, + dir_=self.gudrunFile.instrument.GudrunInputFileDir, + args=args) + def progressIncrementPurge(self): if not self.proc: return 0 @@ -1880,6 +1884,7 @@ def progressPurge(self): f" from purge_det\n{self.error}" ) self.gudrunFile.purged = False + self.cleanupRun() return progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( @@ -1897,6 +1902,8 @@ def progressPurge(self): self.mainWidget.goodDetectorsLabel.setText( f"Number of Good Detectors: {detectors}" ) + self.gudrunFile.purgeFile.organiseOutput() + self.cleanupRun() def procStarted(self): self.mainWidget.currentTaskLabel.setText( From 18f472120a31e47eeb284970cf085371a2e654a1 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 10:29:31 +0000 Subject: [PATCH 081/165] Output organising fixes- proper gudfile path --- gudpy/core/output_file_handler.py | 70 +++++++++++---------------- gudpy/gui/widgets/core/main_window.py | 2 +- 2 files changed, 30 insertions(+), 42 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 127c047a..96e5ccaf 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -97,22 +97,16 @@ def __init__(self, gudrunFile, head="", overwrite=True): # List of run samples self.samples = [] # Directory where Gudrun files are outputted (temp) - self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir + self.gudrunDir = self.procDir + # Make sure it is a temporary directory assert (self.gudrunDir.startswith(tempfile.gettempdir())) # Temporary output dir paths - self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( - self.gudrunFile.filename)[0]) + self.tempOutDir = os.path.join(self.gudrunDir, "Gudrun") if head: self.tempOutDir = os.path.join( self.tempOutDir, f"{head}") - # Name the output directory as the input file - self.outputDir = os.path.join( - self.gudrunFile.inputFileDir, - os.path.splitext(self.gudrunFile.filename)[0], - f"{head}" - ) # Files that have been copied self.copiedFiles = [] self.outputExts = [ @@ -139,12 +133,6 @@ def __init__(self, gudrunFile, head="", overwrite=True): if s.runThisSample and len(s.dataFiles)]: self.samples.append(sample) - # If output directory exists, move to a temp dir and clear it - # Avoids shutil.rmtree - if overwrite is True and os.path.exists(self.outputDir): - with tempfile.TemporaryDirectory() as tmp: - shutil.move(self.outputDir, os.path.join(tmp, "prev")) - def organiseOutput(self): """Organises Gudrun outputs @@ -160,19 +148,9 @@ def organiseOutput(self): sampleOutputs = self._createSampleDir(self.tempOutDir) # Create additonal output folders inputFile = self._createAddOutDir(self.tempOutDir) + # Move over folders to output directory - makeDir(self.outputDir) - for root, dirs, files in os.walk(self.tempOutDir): - r = os.path.join( - self.gudrunFile.inputFileDir, - root.partition(self.gudrunDir + "/")[-1]) - for d in dirs: - makeDir(os.path.join(r, d)) - for f in files: - shutil.copyfile( - os.path.join(root, f), - os.path.join(r, f) - ) + shutil.move(self.tempOutDir, self.outputDir) return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], @@ -259,7 +237,8 @@ def _createSampleDir(self, dest): for idx, dataFile in enumerate(sample.dataFiles): out = self._copyOutputsByExt( dataFile, - samplePath + samplePath, + sample.name.replace(" ", "_") ) if idx == 0 and out[dataFile]: sampleOutput = out @@ -323,13 +302,17 @@ def _createAddOutDir(self, dest): os.path.join(self.gudrunDir, f), os.path.join(addDir, f) ) - elif f not in self.copiedFiles and os.path.isfile( - os.path.join(self.gudrunDir, f)): - shutil.copyfile( - os.path.join(self.gudrunDir, f), - os.path.join(addDir, f) - ) - return inputFile + + elif f not in self.copiedFiles: + try: + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(addDir, f) + ) + except IsADirectoryError: + # If it is a directory, move on to next file + continue + return inputFile def _copyOutputs(self, fpath, dest): """ @@ -361,7 +344,7 @@ def _copyOutputs(self, fpath, dest): ) self.copiedFiles.append(f) - def _copyOutputsByExt(self, fpath, dest): + def _copyOutputsByExt(self, fpath, dest, folderName): """ Copy all files with the same basename as the provided filepath and splits them into outputs @@ -377,6 +360,8 @@ def _copyOutputsByExt(self, fpath, dest): List of target file extenstions dest : str Directory for the files to be copied to + folderName : str + Name of the folder files gets copied to Returns ------- @@ -387,10 +372,8 @@ def _copyOutputsByExt(self, fpath, dest): fname = os.path.splitext(fpath)[0] # Path to folder which will hold all outputs from the run runDir = os.path.join(dest, fname) - # Path to folder which will hold Gudrun outputs - outDir = makeDir(os.path.join(runDir, "Outputs")) - # Path to folder which will hold Gudrun diagnostic outputs - diagDir = makeDir(os.path.join(runDir, "Diagnostics")) + # Has the run dir been created? + dirCreated = False outputs = {} outputs[fpath] = {} @@ -398,11 +381,16 @@ def _copyOutputsByExt(self, fpath, dest): # If the file has the same name as requested filename fn, ext = os.path.splitext(f) if fn == fname: + if not dirCreated: + # Path to folder which will hold Gudrun outputs + outDir = makeDir(os.path.join(runDir, "Outputs")) + # Path to folder which will hold Gudrun diagnostic outputs + diagDir = makeDir(os.path.join(runDir, "Diagnostics")) # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir if dir == outDir: outputs[fpath][ext] = os.path.join( - self.outputDir, "Outputs", f) + self.outputDir, folderName, fname, "Outputs", f) shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(dir, f) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 481e46ac..8e6362ce 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -976,7 +976,7 @@ def runGudrun_(self): ) elif not self.gudrunFile.purged and os.path.exists( os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" + self.gudrunFile.projectDir, "Purge", "purge_det.dat" ) ): self.purgeOptionsMessageBox( From a8c5aadf060b279f28d182595bbffae3a30e4bb4 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 10:29:45 +0000 Subject: [PATCH 082/165] Iterator fixes --- gudpy/core/iterators/inelasticity_subtraction.py | 12 ++++++++---- gudpy/gui/widgets/dialogs/iteration_dialog.py | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 09bd4db6..67dbff70 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -74,6 +74,7 @@ def __init__(self, gudrunFile, nTotal): self.gudrunFile = deepcopy(gudrunFile) # Does a default iteration first (no changes) self.iterationType = "QIteration" + self.iterationCount = 0 self.nCurrent = 0 self.topHatWidths = [] self.QMax = 0. @@ -201,7 +202,7 @@ def wavelengthIteration(self): """ self.iterationType = "WavelengthIteration" # First iteration - if self.nCurrent == 0: + if self.iterationCount == 0: # Disable subtracting of wavelength binned data. # Collect the top hat widths and Q range and step size. self.gudrunFile.instrument.subWavelengthBinnedData = False @@ -247,20 +248,23 @@ def QIteration(self): self.setSelfScatteringFiles(Scales.Q) def performIteration(self): + print(self.iterationType) + print(self.iterationCount) if self.iterationType == "QIteration": self.wavelengthIteration() - self.nCurrent += 1 + self.iterationCount += 1 else: self.QIteration() + self.nCurrent += 1 def organiseOutput(self): """ This organises the output of the iteration. """ - overwrite = (self.nCurrent == 1 and + overwrite = (self.iterationCount == 1 and self.iterationType == "WavelengthIteration") return self.gudrunFile.organiseOutput( - head=f"{self.iterationType}_{self.nCurrent}", + head=f"{self.iterationType}_{self.iterationCount}", overwrite=overwrite) def iterate(self): diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index acb49e7b..2a81030d 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -250,7 +250,7 @@ def initComponents(self): self.widget.iterateButton.setEnabled(False) def iterate(self): - self.iterator = CompositionIterator(self.gudrunFile, 10) + self.iterator = CompositionIterator(self.gudrunFile) self.iterator.setComponents(self.components) self.queue = Queue() for sampleBackground in self.gudrunFile.sampleBackgrounds: From 90bdd0e526da6b6bd0f217d395ee029f3273b1c7 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 11:17:05 +0000 Subject: [PATCH 083/165] Make each iteration run in new temp dir --- gudpy/gui/widgets/core/main_window.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 8e6362ce..966cca5f 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1518,7 +1518,6 @@ def iterateGudrun(self, dialog, name): name : str Name of dialog """ - self.prepareRun() iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) iterationDialog.widget.exec() if not iterationDialog.iterator: @@ -1536,6 +1535,7 @@ def iterateGudrun(self, dialog, name): self.mainWidget.stopTaskButton.setEnabled(True) def nextIteration(self): + self.cleanupRun if self.error: self.procFinished(9, QProcess.NormalExit) return @@ -1558,6 +1558,7 @@ def nextIteration(self): self.output = "" def nextIterableProc(self): + self.prepareRun() if self.queue.empty(): return iterInfo = f" {self.iterator.nCurrent + 1}/{self.iterator.nTotal}" if ( From 734aeb0bc30aed833576bf3fc21badc09d04e194 Mon Sep 17 00:00:00 2001 From: Spitz Date: Tue, 28 Nov 2023 15:27:18 +0000 Subject: [PATCH 084/165] Composition iterator --- gudpy/core/iterators/composition.py | 7 +++++++ gudpy/gui/widgets/core/main_window.py | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index a63e9f89..641fd9cd 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -289,3 +289,10 @@ def iterate(self, n=10, rtol=10.): def gss(self, f, bounds, n, args=()): return gss(f, bounds, n, self.maxIterations, self.rtol, args=args) + + def organiseOutput(self): + """ + This organises the output of the iteration. + """ + gudrunOutput = self.gudrunFile.organiseOutput() + return gudrunOutput diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 966cca5f..8ee5afcc 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1414,8 +1414,10 @@ def batchProcessingFinished(self): def finishedCompositionIteration(self, originalSample, updatedSample): self.compositionMap[originalSample] = updatedSample self.mainWidget.progressBar.setValue( - int((self.currentIteration / self.totalIterations) * 100) + int((self.iterator.nCurrent / self.totalIterations) * 100) ) + self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() + self.cleanupRun() if not self.queue.empty(): self.nextCompositionIteration() else: @@ -1430,9 +1432,9 @@ def finishedCompositionIterations(self): original.composition = new.composition if self.sampleSlots.sample == original: self.sampleSlots.setSample(original) - self.cleanupRun() def startedCompositionIteration(self, sample): + self.prepareRun() self.mainWidget.currentTaskLabel.setText( f"{self.text}" f" ({sample.name})" ) @@ -1468,7 +1470,6 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.gudrunFile.organiseOutput() self.currentIteration += 1 def iterateByComposition(self): From ecaa9b809faf9db12f53c367621977ec35e58b98 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 29 Nov 2023 15:52:09 +0000 Subject: [PATCH 085/165] Iterate by composition --- gudpy/core/iterators/composition.py | 8 +++--- gudpy/gui/widgets/core/main_window.py | 39 ++++++++++++++++++--------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index 641fd9cd..b6c9bfc3 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -112,6 +112,7 @@ def __init__(self, gudrunFile): self.ratio = 0 self.nTotal = 0 self.nCurrent = 0 + self.iterationType = self.name """ Sets component and ratio. @@ -222,13 +223,10 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): self.gudrunFile.process() time.sleep(1) - gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + gudFile = GudFile( os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, gudPath + self.gudrunFile.gudrunOutput.gudFile(name=sampleBackground.samples[0].name) ) ) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 8ee5afcc..b911512f 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -576,6 +576,8 @@ def loadInputFile_(self): f"{list(filters.keys())[2]};;" ) if filename: + if not filter: + filter = "YAML (*.yaml)" fmt = filters[filter] try: if self.gudrunFile: @@ -940,12 +942,14 @@ def makeProc( def prepareRun(self): if not self.checkFilesExist_(): - return + return False self.setControlsEnabled(False) self.tmp = tempfile.TemporaryDirectory() self.gudrunFile.setGudrunDir(self.tmp.name) + return True + def cleanupRun(self): if self.tmp: self.tmp.cleanup() @@ -957,7 +961,8 @@ def cleanupRun(self): self.queue = Queue() def runGudrun_(self): - self.prepareRun() + if not self.prepareRun(): + return False dcs = self.gudrunFile.dcs( path=os.path.join( @@ -1003,9 +1008,12 @@ def runGudrun_(self): args=args, finished=self.runGudrunFinished, ) + + return True def runContainersAsSamples(self): - self.prepareRun() + if not self.prepareRun(): + return False runContainersAsSamples = RunContainersAsSamples(self.gudrunFile) dcs = runContainersAsSamples.runContainersAsSamples( @@ -1056,7 +1064,8 @@ def finished(ec, es): ) def runFilesIndividually(self): - self.prepareRun() + if not self.prepareRun(): + return False runIndividualFiles = RunIndividualFiles(self.gudrunFile) dcs = runIndividualFiles.gudrunFile.dcs( path=os.path.join( @@ -1136,7 +1145,8 @@ def purgeOptionsMessageBox(self, dcs, finished, func, args, text): def purgeBeforeRunning(self, default=True): self.setControlsEnabled(False) if default: - self.prepareRun() + if not self.prepareRun(): + return False purge_det = self.gudrunFile.purge(headless=False) if isinstance(purge_det, Sequence): purge, func, args = purge_det @@ -1323,7 +1333,8 @@ def nexusProcessingFinished(self): self.gudrunFile.nexus_processing.tmp.cleanup() def batchProcessing(self): - self.prepareRun() + if not self.prepareRun(): + return False batchProcessingDialog = BatchProcessingDialog( self.gudrunFile, self.mainWidget ) @@ -1434,7 +1445,6 @@ def finishedCompositionIterations(self): self.sampleSlots.setSample(original) def startedCompositionIteration(self, sample): - self.prepareRun() self.mainWidget.currentTaskLabel.setText( f"{self.text}" f" ({sample.name})" ) @@ -1452,12 +1462,12 @@ def errorCompositionIteration(self, output): ) def progressCompositionIteration(self, currentIteration): - progress = ( - self.iterator.nCurrent / self.iterator.nTotal - ) * (self.iterator.nCurrent / self.totalIterations) + progress = (self.iterator.nCurrent / self.totalIterations) self.mainWidget.progressBar.setValue(int(progress * 100)) def nextCompositionIteration(self): + if not self.prepareRun(): + return False args, kwargs, sample = self.queue.get() self.worker = CompositionWorker(args, kwargs, sample, self.gudrunFile) self.worker.started.connect(self.startedCompositionIteration) @@ -1504,6 +1514,9 @@ def iterateByComposition(self): ] ) self.iterator.nTotal = self.totalIterations + # Run default iteration + #if not self.runGudrun_(): + # return self.nextCompositionIteration() def iterateGudrun(self, dialog, name): @@ -1559,7 +1572,8 @@ def nextIteration(self): self.output = "" def nextIterableProc(self): - self.prepareRun() + if not self.prepareRun(): + return False if self.queue.empty(): return iterInfo = f" {self.iterator.nCurrent + 1}/{self.iterator.nTotal}" if ( @@ -1779,7 +1793,8 @@ def progressDCS(self): ) def runPurge_(self): - self.prepareRun() + if not self.prepareRun(): + return False purgeDialog = PurgeDialog(self.gudrunFile, self) result = purgeDialog.widget.exec_() From 0aaac01ea8fbbfd247cada71db3e2bf1ccd6d415 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 30 Nov 2023 08:52:47 +0000 Subject: [PATCH 086/165] Iterate by composition --- gudpy/core/iterators/composition.py | 1 + gudpy/gui/widgets/core/main_window.py | 29 ++++++--------------------- gudpy/gui/widgets/core/worker.py | 1 - 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index b6c9bfc3..e8acde34 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -113,6 +113,7 @@ def __init__(self, gudrunFile): self.nTotal = 0 self.nCurrent = 0 self.iterationType = self.name + self.nWeightedComponents = 0 """ Sets component and ratio. diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index b911512f..a1386aa2 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1425,7 +1425,7 @@ def batchProcessingFinished(self): def finishedCompositionIteration(self, originalSample, updatedSample): self.compositionMap[originalSample] = updatedSample self.mainWidget.progressBar.setValue( - int((self.iterator.nCurrent / self.totalIterations) * 100) + int((self.iterator.nCurrent / self.iterator.nTotal) * 100) ) self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() self.cleanupRun() @@ -1462,7 +1462,10 @@ def errorCompositionIteration(self, output): ) def progressCompositionIteration(self, currentIteration): - progress = (self.iterator.nCurrent / self.totalIterations) + self.iterator.nCurrent += 1 + print(self.iterator.nCurrent) + print(self.iterator.nTotal) + progress = (self.iterator.nCurrent / self.iterator.nTotal) self.mainWidget.progressBar.setValue(int(progress * 100)) def nextCompositionIteration(self): @@ -1480,7 +1483,6 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.currentIteration += 1 def iterateByComposition(self): if not self.iterator.components: @@ -1497,26 +1499,6 @@ def iterateByComposition(self): self.setControlsEnabled(True) else: self.compositionMap = {} - self.totalIterations = len( - [ - s - for sb in self.gudrunFile.sampleBackgrounds - for s in sb.samples - if s.runThisSample - and len( - [ - wc - for c in self.iterator.components - for wc in s.composition.weightedComponents - if wc.component.eq(c) - ] - ) - ] - ) - self.iterator.nTotal = self.totalIterations - # Run default iteration - #if not self.runGudrun_(): - # return self.nextCompositionIteration() def iterateGudrun(self, dialog, name): @@ -1543,6 +1525,7 @@ def iterateGudrun(self, dialog, name): self.text = iterationDialog.text self.outputIterations = {} if isinstance(self.iterator, CompositionIterator): + self.iterator.nTotal = self.iterationDialog.rtol + 1 self.iterateByComposition() else: self.nextIterableProc() diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index b14dfa5a..704832e9 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -19,7 +19,6 @@ def __init__(self, args, kwargs, sample, gudrunFile): self.sample = sample self.updatedSample = None self.errored = False - self.currentIteration = 0 self.gudrunFile = gudrunFile super(CompositionWorker, self).__init__() From 1a2c090e9e3eb8bf7bff6e85874a9f1ba8153ad2 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 1 Dec 2023 12:01:46 +0000 Subject: [PATCH 087/165] Formatting --- gudpy/core/iterators/composition.py | 3 ++- gudpy/gui/widgets/core/main_window.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index e8acde34..2d9b082b 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -227,7 +227,8 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): gudFile = GudFile( os.path.join( - self.gudrunFile.gudrunOutput.gudFile(name=sampleBackground.samples[0].name) + self.gudrunFile.gudrunOutput.gudFile( + name=sampleBackground.samples[0].name) ) ) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index a1386aa2..bcb1f1ae 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1008,7 +1008,7 @@ def runGudrun_(self): args=args, finished=self.runGudrunFinished, ) - + return True def runContainersAsSamples(self): From d7d016b9ac8f4194982002bfbeff802583c5f60f Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 1 Dec 2023 12:38:29 +0000 Subject: [PATCH 088/165] Fix progress bar --- .../iterators/inelasticity_subtraction.py | 2 -- gudpy/gui/widgets/core/main_window.py | 26 +++++-------------- gudpy/gui/widgets/dialogs/iteration_dialog.py | 1 + 3 files changed, 7 insertions(+), 22 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 67dbff70..b68cc7fc 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -248,8 +248,6 @@ def QIteration(self): self.setSelfScatteringFiles(Scales.Q) def performIteration(self): - print(self.iterationType) - print(self.iterationCount) if self.iterationType == "QIteration": self.wavelengthIteration() self.iterationCount += 1 diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index bcb1f1ae..281a40a8 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -944,7 +944,7 @@ def prepareRun(self): if not self.checkFilesExist_(): return False self.setControlsEnabled(False) - + self.mainWidget.progressBar.setValue(0) self.tmp = tempfile.TemporaryDirectory() self.gudrunFile.setGudrunDir(self.tmp.name) @@ -1463,8 +1463,6 @@ def errorCompositionIteration(self, output): def progressCompositionIteration(self, currentIteration): self.iterator.nCurrent += 1 - print(self.iterator.nCurrent) - print(self.iterator.nTotal) progress = (self.iterator.nCurrent / self.iterator.nTotal) self.mainWidget.progressBar.setValue(int(progress * 100)) @@ -1525,7 +1523,7 @@ def iterateGudrun(self, dialog, name): self.text = iterationDialog.text self.outputIterations = {} if isinstance(self.iterator, CompositionIterator): - self.iterator.nTotal = self.iterationDialog.rtol + 1 + self.iterator.nTotal = iterationDialog.numberIterations self.iterateByComposition() else: self.nextIterableProc() @@ -1569,7 +1567,7 @@ def nextIterableProc(self): self.iterator.gudrunFile.write_out() self.proc, func, args = self.queue.get() self.proc.finished.connect(self.nextIteration) - self.proc.readyReadStandardOutput.connect(self.progressIteration) + self.proc.readyReadStandardOutput.connect(self.progressDCS) self.proc.setWorkingDirectory( self.iterator.gudrunFile.instrument.GudrunInputFileDir ) @@ -1577,20 +1575,6 @@ def nextIterableProc(self): func(*args) self.proc.start() - def progressIteration(self): - progress = self.progressIncrementDCS(self.gudrunFile) - if progress == -1: - self.error = ( - f"An error occurred. See the following traceback" - f" from gudrun_dcs\n{self.error}" - ) - return - progress /= self.iterator.nTotal - progress += self.mainWidget.progressBar.value() - self.mainWidget.progressBar.setValue( - progress if progress <= 100 else 100 - ) - def checkFilesExist_(self): result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() if not all(r[0] for r in result[0]) or not all(r[0] @@ -1613,7 +1597,9 @@ def autosave(self): and not self.proc and not self.workerThread ): - autosavePath = self.gudrunFile.path + ".autosave" + autosavePath = os.path.join( + self.gudrunFile.inputFileDir, + self.gudrunFile.filename + ".autosave") self.gudrunFile.write_out(path=autosavePath) def setModified(self): diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index 2a81030d..301cf31b 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -195,6 +195,7 @@ def secondComponentChanged(self, index): ) def compositionRtolChanged(self, value): + print(self.numberIterations) self.rtol = value def enableItems(self, comboBox): From 989cdc5a15154f4c2f82277fac9db0e2f36f16cf Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 1 Dec 2023 12:53:33 +0000 Subject: [PATCH 089/165] Fix merge --- gudpy/gui/widgets/core/main_window.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 695ef6f9..c5b3428a 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1579,7 +1579,7 @@ def nextIterableProc(self): func(*args) self.proc.start() - def checkFilesExist_(self): + def checkFilesExist_(self, showSuccessDialog: bool = False): result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() if not all(r[0] for r in result[0]) or not all(r[0] for r in result[1]): @@ -1623,7 +1623,6 @@ def progressIteration(self): progress if progress <= 100 else 100 ) - def autosave(self): if ( self.gudrunFile From ced7477fd945a5e0e37fdcc49cc57f240325ad35 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Mon, 4 Dec 2023 18:25:27 +0000 Subject: [PATCH 090/165] Fixing tests --- gudpy/core/gudrun_file.py | 63 ++++++------------- gudpy/core/iterators/composition.py | 7 ++- .../iterators/inelasticity_subtraction.py | 5 +- gudpy/core/iterators/iterator.py | 4 +- gudpy/core/iterators/tweak_factor.py | 13 +--- gudpy/core/output_file_handler.py | 4 +- gudpy/core/purge_file.py | 9 ++- gudpy/test/test_gudpy_workflows.py | 16 +++-- gudpy/test/test_utils.py | 14 ++--- 9 files changed, 52 insertions(+), 83 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 4bdab7af..b7eec897 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1532,6 +1532,8 @@ def write_out(self, path='', overwrite=False, writeParameters=True): def setGudrunDir(self, dir): assert (os.path.isdir(os.path.abspath(dir))) + print( + f"Gudrun dir set to: {dir} was initially: {self.instrument.GudrunInputFileDir}") self.instrument.GudrunInputFileDir = dir def dcs(self, path='', headless=True, iterator=None): @@ -1555,27 +1557,27 @@ def dcs(self, path='', headless=True, iterator=None): The result of calling gudrun_dcs using subprocess.run. Can access stdout/stderr from this. """ - assert (self.instrument.GudrunInputFileDir) - if not path: path = os.path.basename(self.path) if headless: - try: - with tempfile.TemporaryDirectory() as tmp: - self.setGudrunDir(tmp.name) - gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - result = subprocess.run( - [gudrun_dcs, path], cwd=tmp.name, - capture_output=True, text=True - ) - if iterator is not None: - self.gudrunOutput = iterator.organiseOutput() - else: - self.gudrunOutput = self.organiseOutput() - self.setGudrunDir(self.gudrunOutput.path) - except FileNotFoundError: - return False + with tempfile.TemporaryDirectory() as tmp: + self.setGudrunDir(tmp) + path = os.path.join( + tmp, + path + ) + self.write_out(path) + gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") + result = subprocess.run( + [gudrun_dcs, path], cwd=tmp, + capture_output=True, text=True + ) + if iterator is not None: + self.gudrunOutput = iterator.organiseOutput() + else: + self.gudrunOutput = self.organiseOutput() + self.setGudrunDir(self.gudrunOutput.path) return result else: if hasattr(sys, '_MEIPASS'): @@ -1601,33 +1603,6 @@ def dcs(self, path='', headless=True, iterator=None): ] ) - def process(self, headless=True, iterator=None): - """ - Write out the current state of the file, - and then call gudrun_dcs on the file that - was written out. - - Parameters - ---------- - purge : bool, optional - Should detectors be purged? - Returns - ------- - subprocess.CompletedProcess - The result of calling gudrun_dcs using subprocess.run. - Can access stdout/stderr from this. - """ - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) - self.write_out() - dcs = self.dcs( - path=self.outpath, - headless=headless, - iterator=iterator - ) - os.chdir(cwd) - return dcs - def purge(self, *args, **kwargs): """ Call Purge.purge() to purge the detectors. diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index 2d9b082b..0b75221e 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -171,7 +171,7 @@ def processSingleComponent(self, x, sampleBackground): component.ratio = x sampleBackground.samples[0].composition.translate() - self.gudrunFile.process() + self.gudrunFile.dcs() time.sleep(1) gudPath = sampleBackground.samples[0].dataFiles[0].replace( @@ -180,7 +180,8 @@ def processSingleComponent(self, x, sampleBackground): ) gudFile = GudFile( os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, gudPath + self.gudrunFile.gudrunOutput.gudFile( + name=sampleBackground.samples[0].name) ) ) @@ -221,7 +222,7 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): wcB.ratio = abs(totalMolecules - x) sampleBackground.samples[0].composition.translate() - self.gudrunFile.process() + self.gudrunFile.dcs() time.sleep(1) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index b68cc7fc..88cb1e40 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -270,10 +270,9 @@ def iterate(self): Perform n iterations on both the wavelength scale and Q scale. """ - + print("ITERATING WAVELENGTH") for _ in range(self.nTotal): - self.performIteration() - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) time.sleep(1) self.organiseOutput() diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 188ce03a..4e3ba159 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -110,8 +110,8 @@ def iterate(self): n : int Number of iterations to perform. """ - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) for _ in range(self.nTotal): time.sleep(1) self.performIteration() - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) diff --git a/gudpy/core/iterators/tweak_factor.py b/gudpy/core/iterators/tweak_factor.py index 1ae206d4..6eb24169 100644 --- a/gudpy/core/iterators/tweak_factor.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -50,15 +50,8 @@ def performIteration(self): s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles) ]: - gudPath = sample.dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) gudFile = GudFile( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - gudPath - ) + self.gudrunFile.gudrunOutput.gudFile(name=sample.name) ) tweakFactor = float(gudFile.suggestedTweakFactor) sample.sampleTweakFactor = tweakFactor @@ -79,7 +72,7 @@ def iterate(self): n : int Number of iterations to perform. """ - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) # Perform n iterations of tweaking by tweak factor. for _ in range(self.nTotal): @@ -87,4 +80,4 @@ def iterate(self): # and run gudrun_dcs on that file. time.sleep(1) self.performIteration() - self.gudrunFile.process(itertor=self) + self.gudrunFile.dcs(iterator=self) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 96e5ccaf..a6ff5198 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -10,7 +10,7 @@ class SampleOutput: sampleFile: str gudFile: str - outputs: typing.Dict[str, str] + outputs: typing.Dict[str, typing.Dict[str, str]] @dataclass @@ -42,6 +42,7 @@ def __init__(self, gudrunFile, dirName, overwrite=True): # Directory where files are outputted and process was run (temp) self.procDir = self.gudrunFile.instrument.GudrunInputFileDir # Make sure it is a temporary directory + print(self.procDir) assert (self.procDir.startswith(tempfile.gettempdir())) # Name the output directory as the input file self.outputDir = os.path.join( @@ -247,6 +248,7 @@ def _createSampleDir(self, dest): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): + makeDir(samplePath) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) diff --git a/gudpy/core/purge_file.py b/gudpy/core/purge_file.py index a4a3ef9e..443bf392 100644 --- a/gudpy/core/purge_file.py +++ b/gudpy/core/purge_file.py @@ -252,12 +252,15 @@ def purge( if headless: try: with tempfile.TemporaryDirectory() as tmp: - self.setGudrunDir(tmp.name) + self.gudrunFile.setGudrunDir(tmp) purge_det = resolve("bin", f"purge_det{SUFFIX}") - self.write_out(tmp.name) + self.write_out(os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + "purge_det.dat" + )) result = subprocess.run( [purge_det, "purge_det.dat"], - cwd=tmp.name, + cwd=tmp, capture_output=True, text=True ) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index b6465b68..c2b5453a 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -83,17 +83,15 @@ def testGudPyDCS(self): for sample in self.g.sampleBackgrounds[0].samples: mintFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "mint01" - ) + os.path.splitext(sample.dataFiles[0])[0] ) - actualMintFile = f'test/TestData/water-ref/plain/{mintFilename}' - - actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, mintFilename - ), + actualMintFile = ("test/TestData/water-ref/plain/" + f"{mintFilename}.mint01") + print(self.g.gudrunOutput.sampleOutputs[ + sample.name].outputs[sample.dataFiles[0]][".mint01"]) + actualData = open(self.g.gudrunOutput.sampleOutputs[ + sample.name].outputs[sample.dataFiles[0]][".mint01"], "r", encoding="utf-8" ).readlines()[10:] expectedData = open( diff --git a/gudpy/test/test_utils.py b/gudpy/test/test_utils.py index 2fba74cf..6cd1705f 100644 --- a/gudpy/test/test_utils.py +++ b/gudpy/test/test_utils.py @@ -1,13 +1,11 @@ from unittest import TestCase - - from core.utils import ( - iteristype, - firstword, boolifyNum, - numifyBool, spacify, - extract_ints_from_string, - extract_floats_from_string, - count_occurrences) + iteristype, + firstword, boolifyNum, + numifyBool, spacify, + extract_ints_from_string, + extract_floats_from_string, + count_occurrences) class TestUtils(TestCase): From 357de84e73958d238d9d9d27ea4a01aae7b826b3 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 8 Dec 2023 15:17:31 +0000 Subject: [PATCH 091/165] Fix wavelength iterator --- gudpy/core/output_file_handler.py | 78 ++++++++++++++++++------------ gudpy/test/test_gudpy_workflows.py | 37 ++++++-------- 2 files changed, 62 insertions(+), 53 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index a6ff5198..d5f3624e 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -11,13 +11,14 @@ class SampleOutput: sampleFile: str gudFile: str outputs: typing.Dict[str, typing.Dict[str, str]] + diagnostics: typing.Dict[str, typing.Dict[str, str]] @dataclass class GudrunOutput: path: str name: str - inputFile: str + inputFilePath: str sampleOutputs: typing.Dict[str, SampleOutput] def gudFiles(self) -> list[str]: @@ -26,18 +27,22 @@ def gudFiles(self) -> list[str]: def gudFile(self, idx: int = None, *, name: str = None) -> str: if idx is not None: asList = list(self.sampleOutputs.values()) - assert (idx < len(asList)) return asList[idx].gudFile elif name is not None: - assert (name in self.sampleOutputs) return self.sampleOutputs[name].gudFile + def output(self, name: str, dataFile: str, type: str) -> str: + if type in GudrunOutputHandler.outputExts: + return (self.sampleOutputs[name].outputs[dataFile][type]) + else: + return (self.sampleOutputs[name].diagnostics[dataFile][type]) + class OutputHandler: """Class to organise purge output files """ - def __init__(self, gudrunFile, dirName, overwrite=True): + def __init__(self, gudrunFile, dirName: str, overwrite=True): self.gudrunFile = gudrunFile # Directory where files are outputted and process was run (temp) self.procDir = self.gudrunFile.instrument.GudrunInputFileDir @@ -71,6 +76,23 @@ def organiseOutput(self): class GudrunOutputHandler(OutputHandler): + outputExts = [ + ".dcs01", + ".dcsd01", + ".dcse01", + ".dcst01", + ".dscw01", + ".mdcs01", + ".mdcsd01", + ".mdcse01", + ".mdcsw01", + ".mint01", + ".mgor01", + ".mdor01", + ".gud", + ".sample" + ] + def __init__(self, gudrunFile, head="", overwrite=True): """ Initialise `GudrunOutputHandler` @@ -100,6 +122,9 @@ def __init__(self, gudrunFile, head="", overwrite=True): # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.procDir + for f in os.listdir(self.gudrunDir): + print(f) + # Make sure it is a temporary directory assert (self.gudrunDir.startswith(tempfile.gettempdir())) # Temporary output dir paths @@ -110,22 +135,6 @@ def __init__(self, gudrunFile, head="", overwrite=True): # Files that have been copied self.copiedFiles = [] - self.outputExts = [ - ".dcs01", - ".dcsd01", - ".dcse01", - ".dcst01", - ".dscw01", - ".mdcs01", - ".mdcsd01", - ".mdcse01", - ".mdcsw01", - ".mint01", - ".mgor01", - ".mdor01", - ".gud", - ".sample" - ] # Generating paths for sampleBackground in self.gudrunFile.sampleBackgrounds: @@ -148,14 +157,16 @@ def organiseOutput(self): # Create sample folders sampleOutputs = self._createSampleDir(self.tempOutDir) # Create additonal output folders - inputFile = self._createAddOutDir(self.tempOutDir) + inputFilePath = self._createAddOutDir(self.tempOutDir) # Move over folders to output directory shutil.move(self.tempOutDir, self.outputDir) + print(f"MOVING OUTPUTS FROM {self.tempOutDir} TO {self.outputDir}") + return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], - inputFile=inputFile, + inputFilePath=inputFilePath, sampleOutputs=sampleOutputs ) @@ -229,6 +240,7 @@ def _createSampleDir(self, dest): sampleFile = "" gudFile = "" sampleOutput = {} + sampleDiag = {} samplePath = os.path.join( dest, @@ -236,15 +248,16 @@ def _createSampleDir(self, dest): ) # Move datafiles to sample folder for idx, dataFile in enumerate(sample.dataFiles): - out = self._copyOutputsByExt( + out, diag = self._copyOutputsByExt( dataFile, samplePath, sample.name.replace(" ", "_") ) - if idx == 0 and out[dataFile]: - sampleOutput = out - gudFile = (out[dataFile][".gud"] - if ".gud" in out[dataFile] else "") + sampleOutput[dataFile] = out + sampleDiag[dataFile] = diag + if idx == 0: + gudFile = (out[".gud"] + if ".gud" in out else "") # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): @@ -262,7 +275,7 @@ def _createSampleDir(self, dest): sample.pathName()) sampleOutputs[sample.name] = SampleOutput( - sampleFile, gudFile, sampleOutput) + sampleFile, gudFile, sampleOutput, sampleDiag) # Create container folders within sample folder for container in sample.containers: @@ -378,7 +391,7 @@ def _copyOutputsByExt(self, fpath, dest, folderName): dirCreated = False outputs = {} - outputs[fpath] = {} + diagnostics = {} for f in os.listdir(self.gudrunDir): # If the file has the same name as requested filename fn, ext = os.path.splitext(f) @@ -391,11 +404,14 @@ def _copyOutputsByExt(self, fpath, dest, folderName): # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir if dir == outDir: - outputs[fpath][ext] = os.path.join( + outputs[ext] = os.path.join( self.outputDir, folderName, fname, "Outputs", f) + else: + diagnostics[ext] = os.path.join( + self.outputDir, folderName, fname, "Diagnostics", f) shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(dir, f) ) self.copiedFiles.append(f) - return outputs + return (outputs, diagnostics) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index c2b5453a..ac208e11 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -88,8 +88,6 @@ def testGudPyDCS(self): actualMintFile = ("test/TestData/water-ref/plain/" f"{mintFilename}.mint01") - print(self.g.gudrunOutput.sampleOutputs[ - sample.name].outputs[sample.dataFiles[0]][".mint01"]) actualData = open(self.g.gudrunOutput.sampleOutputs[ sample.name].outputs[sample.dataFiles[0]][".mint01"], "r", encoding="utf-8" @@ -296,22 +294,21 @@ def testGudPyIterateBySubtractingWavelength(self): for x in self.g.sampleBackgrounds[0].samples if x.runThisSample ]: - mintFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "mint01" - ) + dataFilename = ( + os.path.splitext(sample.dataFiles[0])[0] ) actualMintFile = ( f'test/TestData/water-ref/wavelength{i}/' - f'{mintFilename}' + f'{dataFilename}.mint01' ) actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - mintFilename - ), "r", encoding="utf-8" + inelasitictyIterator.gudrunOutputs[ + len(inelasitictyIterator.gudrunOutputs) - 1 + ].output( + sample.name, sample.dataFiles[0], ".mint01"), + "r", encoding="utf-8" ).readlines()[10:] expectedData = open( actualMintFile, "r", encoding="utf-8" @@ -332,21 +329,17 @@ def testGudPyIterateBySubtractingWavelength(self): close += 1 self.assertTrue((close / total) >= 0.95) - msubFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "msubw01" - ) - ) - actualMsubFilename = ( - f'test/TestData/water-ref/wavelength{i}/{msubFilename}' + f'test/TestData/water-ref/wavelength{i}/' + f'{dataFilename}.msubw01' ) actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - msubFilename - ), "r", encoding="utf-8" + inelasitictyIterator.gudrunOutputs[ + len(inelasitictyIterator.gudrunOutputs) - 2 + ].output( + sample.name, sample.dataFiles[0], ".msubw01"), + "r", encoding="utf-8" ).readlines()[10:] expectedData = open( actualMsubFilename, "r", encoding="utf-8" From 798f08402dd9b6637be7ea5655bd8fe8f3d79225 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:34:29 +0000 Subject: [PATCH 092/165] Fix asserion- invalid use of try except --- gudpy/test/test_gud_file.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index 6da805ae..c4749a46 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -356,18 +356,18 @@ def testLoadGudFileB(self): ) else: try: + float(self.expectedGudFileB[key]) + except ValueError: self.assertEqual( - self.expectedGudFileB[key], gudAttrsDict[key] + self.expectedGudFileB[key], + gudAttrsDict[key] + ) + else: + self.assertAlmostEqual( + float(self.expectedGudFileB[key]), + float(gudAttrsDict[key]), + 1, ) - except AssertionError as e: - try: - self.assertAlmostEqual( - float(self.expectedGudFileB[key]), - float(gudAttrsDict[key]), - 1, - ) - except Exception: - raise e def testLoadGudFileC(self): g = GudrunFile( From 39dc94872a41d765adabbfa484028c6faa96b1ba Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:35:37 +0000 Subject: [PATCH 093/165] Use POpen instead of run --- gudpy/core/gudrun_file.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index b7eec897..4c6a1a07 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1473,7 +1473,8 @@ def save(self, path='', format=None): if not format: format = self.format if format == Format.TXT: - self.write_out(path=path.replace(path.split(".")[-1], "txt")) + self.write_out(path=path.replace( + path.split(".")[-1], "txt"), overwrite=True) elif format == Format.YAML: self.write_yaml(path=path.replace(path.split(".")[-1], "yaml")) @@ -1497,10 +1498,16 @@ def write_out(self, path='', overwrite=False, writeParameters=True): None """ if path: + if not overwrite: + assert (not os.path.exists(path)) f = open( path, "w", encoding="utf-8" ) elif not overwrite: + assert (not os.path.exists(os.path.join( + self.instrument.GudrunInputFileDir, + self.outpath) + )) f = open( os.path.join( self.instrument.GudrunInputFileDir, @@ -1557,8 +1564,8 @@ def dcs(self, path='', headless=True, iterator=None): The result of calling gudrun_dcs using subprocess.run. Can access stdout/stderr from this. """ - if not path: - path = os.path.basename(self.path) + + path = f"./{self.outpath}" if headless: with tempfile.TemporaryDirectory() as tmp: @@ -1569,10 +1576,15 @@ def dcs(self, path='', headless=True, iterator=None): ) self.write_out(path) gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - result = subprocess.run( + with subprocess.Popen( [gudrun_dcs, path], cwd=tmp, - capture_output=True, text=True - ) + stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) as gudrun: + gudrun.wait() + result = gudrun + _, stderr = gudrun.communicate() + result.stderr = stderr.decode("utf8") + if iterator is not None: self.gudrunOutput = iterator.organiseOutput() else: @@ -1598,7 +1610,7 @@ def dcs(self, path='', headless=True, iterator=None): proc, self.write_out, [ - path, + '', False ] ) From 36f8fbd95726a5955314583a5e915b31462ea93a Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:35:52 +0000 Subject: [PATCH 094/165] Remove print --- gudpy/core/output_file_handler.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index d5f3624e..6c13514d 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -122,9 +122,6 @@ def __init__(self, gudrunFile, head="", overwrite=True): # Directory where Gudrun files are outputted (temp) self.gudrunDir = self.procDir - for f in os.listdir(self.gudrunDir): - print(f) - # Make sure it is a temporary directory assert (self.gudrunDir.startswith(tempfile.gettempdir())) # Temporary output dir paths From 055759debc9def8553ee6e7a65dac4f1058b2b85 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:38:52 +0000 Subject: [PATCH 095/165] Refactor purge file --- gudpy/core/purge_file.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/gudpy/core/purge_file.py b/gudpy/core/purge_file.py index 443bf392..d334a973 100644 --- a/gudpy/core/purge_file.py +++ b/gudpy/core/purge_file.py @@ -250,23 +250,22 @@ def purge( self.ignoreBad = ignoreBad self.excludeSampleAndCan = excludeSampleAndCan if headless: - try: - with tempfile.TemporaryDirectory() as tmp: - self.gudrunFile.setGudrunDir(tmp) - purge_det = resolve("bin", f"purge_det{SUFFIX}") - self.write_out(os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "purge_det.dat" - )) - result = subprocess.run( - [purge_det, "purge_det.dat"], - cwd=tmp, - capture_output=True, - text=True - ) - self.organiseOutput() - except FileNotFoundError: - return False + with tempfile.TemporaryDirectory() as tmp: + self.gudrunFile.setGudrunDir(tmp) + purge_det = resolve("bin", f"purge_det{SUFFIX}") + self.write_out(os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + "purge_det.dat" + )) + result = subprocess.run( + [purge_det, "purge_det.dat"], + cwd=tmp, + capture_output=True, + text=True + ) + self.organiseOutput() + self.gudrunFile.setGudrunDir( + self.gudrunFile.projectDir) return result else: if hasattr(sys, '_MEIPASS'): @@ -287,7 +286,8 @@ def purge( self.write_out, [ os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, + self.gudrunFile.projectDir, + "Purge", "purge_det.dat" ) ] From d22e9a36221d6c373951ac58af92030118ef1481 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:39:14 +0000 Subject: [PATCH 096/165] Fix composition iterator --- gudpy/core/iterators/composition.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index 0b75221e..2a8071ca 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -171,13 +171,10 @@ def processSingleComponent(self, x, sampleBackground): component.ratio = x sampleBackground.samples[0].composition.translate() - self.gudrunFile.dcs() + self.gudrunFile.dcs(iterator=self) time.sleep(1) - gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + gudFile = GudFile( os.path.join( self.gudrunFile.gudrunOutput.gudFile( @@ -222,7 +219,7 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): wcB.ratio = abs(totalMolecules - x) sampleBackground.samples[0].composition.translate() - self.gudrunFile.dcs() + self.gudrunFile.dcs(iterator=self) time.sleep(1) @@ -286,8 +283,6 @@ def iterate(self, n=10, rtol=10.): args=(sb, totalMolecules,) ) - self.gudrunFile.organiseOutput() - def gss(self, f, bounds, n, args=()): return gss(f, bounds, n, self.maxIterations, self.rtol, args=args) From 0ed0096344d477385923d42e9fb389f143421fca Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:39:58 +0000 Subject: [PATCH 097/165] Fix wavelength iteration process --- .../iterators/inelasticity_subtraction.py | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 88cb1e40..96cb5836 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -1,6 +1,6 @@ from pathlib import Path import time -from copy import deepcopy +import os from core.enums import Scales from core.iterators.iterator import Iterator @@ -71,15 +71,17 @@ def __init__(self, gudrunFile, nTotal): Input GudrunFile that we will be using for iterating. """ super().__init__(gudrunFile, nTotal) - self.gudrunFile = deepcopy(gudrunFile) # Does a default iteration first (no changes) self.iterationType = "QIteration" + # Individual iterations self.iterationCount = 0 + # Iteration pair self.nCurrent = 0 self.topHatWidths = [] self.QMax = 0. self.QMin = 0. self.QStep = 0. + self.gudrunOutputs = [] def enableLogarithmicBinning(self): """ @@ -171,7 +173,7 @@ def setSelfScatteringFiles(self, scale): then set self scattering file extensions to mint01. """ # Dict to pick suffix based on scale - suffix = {Scales.Q: "msubw01", Scales.WAVELENGTH: "mint01"}[scale] + suffix = {Scales.Q: ".msubw01", Scales.WAVELENGTH: ".mint01"}[scale] # Iterate through all of the samples, and set the suffixes of # all of their data files to the suffix @@ -181,8 +183,15 @@ def setSelfScatteringFiles(self, scale): if sample.runThisSample and len(sample.dataFiles): target = sample filename = target.dataFiles[0] + prevOutput = ( + self.gudrunFile.gudrunOutput.output( + sample.name, filename, suffix) + if self.gudrunFile.gudrunOutput else "" + ) target.fileSelfScattering = ( - str(Path(filename).stem) + '.' + suffix + os.path.join( + prevOutput, + ) ) def wavelengthIteration(self): @@ -198,7 +207,7 @@ def wavelengthIteration(self): the x-scale, enable logarithmic binning, set the scale to the wavelength scale, zero the top hat widths, change the extensions of the self scattering files to .mint01. - Then, write out the GudrunFile and call gudrun_dcs. + Then, write out the gudrunFile and call gudrun_dcs. """ self.iterationType = "WavelengthIteration" # First iteration @@ -232,7 +241,7 @@ def QIteration(self): the x-scale, disable logarithmic binning, set the scale to the Q scale, reset the top hat widths, change the extensions of the self scattering files to .msubw01. - Then, write out the GudrunFile and call gudrun_dcs. + Then, write out the gudrunFile and call gudrun_dcs. """ self.iterationType = "QIteration" # Enable subtracting of wavelength binned data @@ -271,8 +280,8 @@ def iterate(self): the wavelength scale and Q scale. """ print("ITERATING WAVELENGTH") - for _ in range(self.nTotal): + for _ in range(self.nTotal * 2): self.performIteration() self.gudrunFile.dcs(iterator=self) + self.gudrunOutputs.append(self.gudrunFile.gudrunOutput) time.sleep(1) - self.organiseOutput() From 3819b2c4afe0b443020bc25114e41034a67fc654 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:40:51 +0000 Subject: [PATCH 098/165] Create gudrun worker --- gudpy/gui/widgets/core/worker.py | 54 ++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index 704832e9..6575af32 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -1,11 +1,65 @@ import os +import tempfile from copy import deepcopy from PySide6.QtCore import QObject, Signal, QThread +import subprocess +import sys +from core import config from core.gud_file import GudFile +import core.utils as utils from core.sample import Sample from core.iterators.composition import gss +SUFFIX = ".exe" if os.name == "nt" else "" + + +class GudrunWorker(QObject): + started = Signal(int) + nextIteration = Signal(int) + errorOccured = Signal(str) + finished = Signal(int) + + def __init__(self): + super().__init__() + + def work(self, gudrunFile, iterator=None): + self.started.emit(1) + + if hasattr(sys, '_MEIPASS'): + gudrun_dcs = os.path.join(sys._MEIPASS, f"gudrun_dcs{SUFFIX}") + else: + gudrun_dcs = utils.resolve( + os.path.join( + config.__rootdir__, "bin" + ), f"gudrun_dcs{SUFFIX}" + ) + + with tempfile.TemporaryDirectory() as tmp: + path = gudrunFile.outpath + gudrunFile.setGudrunDir(tmp) + path = os.path.join( + tmp, + path + ) + gudrunFile.write_out(path) + with subprocess.Popen( + [gudrun_dcs, path], cwd=tmp, + stdout=subprocess.PIPE + ) as gudrun: + for line in gudrun.stdout: + print(line.decode("utf8").rstrip("\n")) + + if iterator is not None: + print("ORGANISE") + gudrunFile.gudrunOutput = iterator.organiseOutput() + else: + gudrunFile.gudrunOutput = gudrunFile.organiseOutput() + print("REVERTING DIR") + gudrunFile.setGudrunDir(gudrunFile.gudrunOutput.path) + + self.finished.emit(1) + class CompositionWorker(QObject): finished = Signal(Sample, Sample) From e82e0eb03ce9b6ce58a1c2eca318d996715cde25 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:40:59 +0000 Subject: [PATCH 099/165] Create gudrun worker --- gudpy/gui/widgets/core/worker.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index 6575af32..bcc8ce43 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -51,11 +51,9 @@ def work(self, gudrunFile, iterator=None): print(line.decode("utf8").rstrip("\n")) if iterator is not None: - print("ORGANISE") gudrunFile.gudrunOutput = iterator.organiseOutput() else: gudrunFile.gudrunOutput = gudrunFile.organiseOutput() - print("REVERTING DIR") gudrunFile.setGudrunDir(gudrunFile.gudrunOutput.path) self.finished.emit(1) From 561946d648f49306dac55cb632fc373fec850ee7 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:41:21 +0000 Subject: [PATCH 100/165] Fix iterator --- gudpy/gui/widgets/dialogs/iteration_dialog.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index 301cf31b..c5036713 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -71,11 +71,7 @@ def enqueueTasks(self): self.queue = Queue() for _ in range(self.numberIterations + 1): self.queue.put( - self.iterator.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "gudpy.txt" - ), headless=False) + self.iterator.gudrunFile.dcs(headless=False) ) @@ -104,11 +100,7 @@ def enqueueTasks(self): self.queue = Queue() for _ in range((self.numberIterations * 2)): self.queue.put( - self.iterator.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "gudpy.txt" - ), headless=False) + self.iterator.gudrunFile.dcs(headless=False) ) @@ -195,7 +187,6 @@ def secondComponentChanged(self, index): ) def compositionRtolChanged(self, value): - print(self.numberIterations) self.rtol = value def enableItems(self, comboBox): From 8891b07e4963744b3662aa8a74e97594c4ab0326 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:41:36 +0000 Subject: [PATCH 101/165] Fix assertions --- gudpy/test/test_gudpy_io.py | 41 ++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 837bd2ed..7af91b77 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -757,7 +757,7 @@ def testLoadGudrunFile(self): ) def testWriteGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) with open( os.path.join( self.g.instrument.GudrunInputFileDir, @@ -845,7 +845,11 @@ def valueInLines(value, lines): valueInLines(value, inlines) def testRewriteGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) + copyPath = os.path.join( + self.g.instrument.GudrunInputFileDir, + "copyGF.txt" + ) g1 = GudrunFile( os.path.join( self.g.instrument.GudrunInputFileDir, @@ -854,23 +858,30 @@ def testRewriteGudrunFile(self): format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir - g1.write_out() + g1.write_out(copyPath, overwrite=True) + + def compareString(string1, string2): + return string1 == string2 with open( - os.path.join( - g1.instrument.GudrunInputFileDir, - g1.outpath - ), + copyPath, + "r", encoding="utf-8" ) as f: + fileContent = "\n".join(f.readlines()[:-5]) self.assertEqual( - "\n".join(f.readlines()[:-5]), - "\n".join(str(self.g).splitlines(keepends=True)[:-5]) + compareString( + fileContent, + "\n".join( + str(self.g).splitlines(keepends=True)[:-5])), + True ) - self.assertEqual( - "\n".join(f.readlines()[:-5]), - "\n".join(str(g1).splitlines(keepends=True)[:-5]) + compareString( + fileContent, + "\n".join( + str(g1).splitlines(keepends=True)[:-5])), + True ) with open( @@ -884,13 +895,11 @@ def testRewriteGudrunFile(self): "\n".join( fg.readlines()[:-5] ), - "\n".join( - f.readlines()[:-5] - ) + fileContent ) def testReloadGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) g1 = GudrunFile( os.path.join( self.g.instrument.GudrunInputFileDir, From b87289ad290781362b5ba1814532ab37f48ff03c Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 13 Dec 2023 16:42:26 +0000 Subject: [PATCH 102/165] Improve purge running and fix issue --- gudpy/gui/widgets/core/main_window.py | 44 ++++++++++++++++----------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index c5b3428a..8d8bbdf5 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1789,23 +1789,32 @@ def progressDCS(self): f" from gudrun_dcs\n{self.error}" ) return + if isinstance(self.iterator, InelasticitySubtraction): + progress /= 2 progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( progress if progress <= 100 else 100 ) - def runPurge_(self): - if not self.prepareRun(): - return False + def runPurge_(self, dialog: bool = False) -> bool: + self.setControlsEnabled(False) + if (dialog): + purgeDialog = PurgeDialog(self.gudrunFile, self) + result = purgeDialog.widget.exec_() + purge = purgeDialog.purge_det + + if purgeDialog.cancelled or result == QDialogButtonBox.No or not purge: + self.setControlsEnabled(True) + self.queue = Queue() + return False + + else: + purge_det = self.gudrunFile.purge(headless=False) + if isinstance(purge_det, Sequence): + purge, func, args = purge_det - purgeDialog = PurgeDialog(self.gudrunFile, self) - result = purgeDialog.widget.exec_() - purge = purgeDialog.purge_det if isinstance(purge, Sequence): purge, func, args = purge - if purgeDialog.cancelled or result == QDialogButtonBox.No: - self.setControlsEnabled(True) - self.queue = Queue() elif isinstance(purge, FileNotFoundError): QMessageBox.critical( self.mainWidget, @@ -1813,14 +1822,15 @@ def runPurge_(self): "Couldn't find purge_det binary.", ) self.setControlsEnabled(True) - elif not purge: - self.setControlsEnabled(True) - else: - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.gudrunFile.purgeFile.write_out() - self.makeProc(purge, self.progressPurge, func=func, - dir_=self.gudrunFile.instrument.GudrunInputFileDir, - args=args) + return False + + if not self.prepareRun(): + return False + os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) + self.gudrunFile.purgeFile.write_out() + self.makeProc(purge, self.progressPurge, func=func, + dir_=self.gudrunFile.instrument.GudrunInputFileDir, + args=args) def progressIncrementPurge(self): if not self.proc: From 2b2522707f834812fe44ed637a217f2f52176f9a Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 14 Dec 2023 10:53:07 +0000 Subject: [PATCH 103/165] Removing unecessary organise output --- gudpy/gui/widgets/core/main_window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 8d8bbdf5..7b1de296 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1538,7 +1538,6 @@ def nextIteration(self): if self.error: self.procFinished(9, QProcess.NormalExit) return - self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() if self.iterator.nCurrent != -1: # If this is not the default run self.outputIterations[ From 212cbd4e1f4eb7e817a26e44b39825cf34d43259 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:49:43 +0700 Subject: [PATCH 104/165] Used threading instead of qprocess, altered purge dialog, secured temp dir --- gudpy/gui/widgets/core/main_window.py | 472 ++++++++------------------ gudpy/gui/widgets/core/worker.py | 93 ++++- 2 files changed, 225 insertions(+), 340 deletions(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 7b1de296..55cc900b 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -37,6 +37,7 @@ from core.container import Container from core.iterators.composition import CompositionIterator +from core.iterators.inelasticity_subtraction import InelasticitySubtraction from core.sample import Sample from gui.widgets.dialogs.export_dialog import ExportDialog @@ -97,7 +98,7 @@ from core.run_individual_files import RunIndividualFiles from core.gud_file import GudFile from core.utils import breplace, nthint -from gui.widgets.core.worker import CompositionWorker +from gui.widgets.core.worker import CompositionWorker, GudrunWorker, PurgeWorker class GudPyMainWindow(QMainWindow): @@ -356,8 +357,12 @@ def initComponents(self): self.sampleSlots = SampleSlots(self.mainWidget, self) self.containerSlots = ContainerSlots(self.mainWidget, self) self.outputSlots = OutputSlots(self.mainWidget, self) - self.mainWidget.runPurge.triggered.connect(self.runPurge_) - self.mainWidget.runGudrun.triggered.connect(self.runGudrun_) + self.mainWidget.runPurge.triggered.connect( + lambda: self.runPurge_(self.gudrunFile, dialog=True) + ) + self.mainWidget.runGudrun.triggered.connect( + lambda: self.runGudrun(self.gudrunFile, self.procFinished) + ) self.mainWidget.iterateInelasticitySubtractions.triggered.connect( lambda: self.iterateGudrun( @@ -506,7 +511,7 @@ def tryLoadAutosaved(self, path): messageBox.addButton(QMessageBox.No) messageBox.addButton(QMessageBox.Yes) result = messageBox.exec() - if result == messageBox.Yes: + if result == QMessageBox.Yes: return os.path.abspath(f) else: return path @@ -630,19 +635,19 @@ def saveInputFileAs(self): os.path.abspath(filename) ) self.gudrunFile.path = filename - self.gudrunFile.save(path=filename, format=fmt) - self.setUnModified() + self.gudrunFile.save(path=filename, format=fmt) + self.setUnModified() def newInputFile(self): if self.gudrunFile: self.gudrunFile = None - self.gudrunFile = GudrunFile() configurationDialog = ConfigurationDialog(self) result = configurationDialog.widget.exec() if not configurationDialog.cancelled and result: - self.gudrunFile.instrument = GudrunFile( - configurationDialog.configuration, config_=True - ).instrument + self.gudrunFile = GudrunFile( + configurationDialog.configuration, format=Format.TXT, + config_=True + ) self.gudrunFile.instrument.dataFileType = ( configurationDialog.dataFileType ) @@ -913,285 +918,149 @@ def exit_(self): self.gudrunFile.write_out(overwrite=True) sys.exit(0) - def makeProc( - self, - cmd, - slot, - dir_=None, - func=None, - args=None, - started=None, - finished=None, - ): - if not started: - started = self.procStarted - if not finished: - finished = self.procFinished - if not dir_: - dir_ = self.gudrunFile.instrument.GudrunInputFileDir - - dir_ = self.tmp.name + def checkFilesExist_(self, showSuccessDialog: bool = False): + result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() + if not all(r[0] for r in result[0]) or not all(r[0] + for r in result[1]): + undefined = [ + r[1] for r in result[0] if not r[0] + ] + unresolved = [r[2] for r in result[1] if not r[0] and r[2]] + missingFilesDialog = MissingFilesDialog( + undefined, unresolved, self.mainWidget + ) + missingFilesDialog.widget.exec_() + return False - self.proc = cmd - self.proc.readyReadStandardOutput.connect(slot) - self.proc.started.connect(started) - self.proc.finished.connect(finished) - self.proc.setWorkingDirectory(dir_) - if func: - func(*args) - self.proc.start() + if showSuccessDialog: + QMessageBox.information( + self.mainWidget, + "GudPy Information", + "All files found!", + ) + return True def prepareRun(self): if not self.checkFilesExist_(): return False + + if not self.gudrunFile.checkSaveLocation(): + dirname = QFileDialog.getSaveFileName( + self.mainWidget, + "Choose save location", + ) + self.gudrunFile.setSaveLocation(dirname) + self.setControlsEnabled(False) self.mainWidget.progressBar.setValue(0) - self.tmp = tempfile.TemporaryDirectory() - self.gudrunFile.setGudrunDir(self.tmp.name) - return True def cleanupRun(self): - if self.tmp: - self.tmp.cleanup() - self.tmp = None - self.setControlsEnabled(True) self.mainWidget.progressBar.setValue(0) self.mainWidget.currentTaskLabel.setText("No task running.") self.queue = Queue() - def runGudrun_(self): - if not self.prepareRun(): - return False - - dcs = self.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - self.setControlsEnabled(True) - elif not self.gudrunFile.purged and os.path.exists( + def checkPurge(self): + if not self.gudrunFile.purged and os.path.exists( os.path.join( self.gudrunFile.projectDir, "Purge", "purge_det.dat" ) ): - self.purgeOptionsMessageBox( - dcs, - self.runGudrunFinished, - func, - args, + purgeResult = self.purgeOptionsMessageBox( "purge_det.dat found, but wasn't run in this session. " - "Continue?", + "Run Purge?", ) elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - self.runGudrunFinished, - func, - args, - "It looks like you may not have purged detectors. Continue?", + purgeResult = self.purgeOptionsMessageBox( + "It looks like you may not have purged detectors. Run Purge?", ) else: - self.makeProc( - dcs, - self.progressDCS, - func=func, - args=args, - finished=self.runGudrunFinished, - ) + purgeResult = True - return True + return purgeResult + + def runGudrun(self, gudrunFile, finished, iterator=None): + if not self.prepareRun() or not self.checkPurge(): + return False + + self.worker = GudrunWorker(gudrunFile, iterator) + self.workerThread = QThread() + self.worker.moveToThread(self.workerThread) + self.workerThread.started.connect(self.worker.gudrun) + self.worker.started.connect(self.procStarted) + self.worker.outputChanged.connect(self.progressDCS) + self.worker.finished.connect(self.workerThread.quit) + self.worker.finished.connect(finished) + self.worker.finished.connect(self.cleanupRun) + self.workerThread.start() + + def makeProc( + self, + cmd, + slot, + dir_=None, + func=None, + args=None, + started=None, + finished=None, + ): + if not started: + started = self.procStarted + if not finished: + finished = self.procFinished + if not dir_: + dir_ = self.gudrunFile.instrument.GudrunInputFileDir + + self.proc = cmd + self.proc.readyReadStandardOutput.connect(slot) + self.proc.started.connect(started) + self.proc.finished.connect(finished) + self.proc.setWorkingDirectory(dir_) + if func: + func(*args) + self.proc.start() def runContainersAsSamples(self): if not self.prepareRun(): return False runContainersAsSamples = RunContainersAsSamples(self.gudrunFile) - dcs = runContainersAsSamples.runContainersAsSamples( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - - def finished(ec, es): - self.runGudrunFinished( - gudrunFile=runContainersAsSamples.gudrunFile - ) + runContainersAsSamples.convertContainers() - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - self.setControlsEnabled(True) - elif not self.gudrunFile.purged and os.path.exists( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" - ) - ): - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "purge_det.dat found, but wasn't run in this session. " - "Continue?", - ) - elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "It looks like you may not have purged detectors. Continue?", - ) - else: - self.makeProc( - dcs, self.progressDCS, finished=finished, func=func, args=args - ) + self.runGudrun( + runContainersAsSamples.gudrunFile, + self.procFinished) def runFilesIndividually(self): if not self.prepareRun(): return False runIndividualFiles = RunIndividualFiles(self.gudrunFile) - dcs = runIndividualFiles.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - - def finished(ec, es): - self.runGudrunFinished(gudrunFile=runIndividualFiles.gudrunFile) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - self.setControlsEnabled(True) - elif not self.gudrunFile.purged and os.path.exists( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" - ) - ): - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "purge_det.dat found, but wasn't run in this session. " - "Continue?", - ) - elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "It looks like you may not have purged detectors. Continue?", - ) - else: - self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished - ) + self.runGudrun( + runIndividualFiles.gudrunFile, + self.procFinished) - def purgeOptionsMessageBox(self, dcs, finished, func, args, text): + def purgeOptionsMessageBox(self, text): messageBox = QMessageBox(self.mainWidget) messageBox.setWindowTitle("GudPy Warning") messageBox.setText(text) + messageBox.addButton(QMessageBox.Yes) messageBox.addButton(QMessageBox.No) - openPurgeDialog = QPushButton("Open purge dialog", messageBox) - purgeDefault = QPushButton("Purge with default parameters", messageBox) - - messageBox.addButton(openPurgeDialog, QMessageBox.ApplyRole) - messageBox.addButton(purgeDefault, QMessageBox.ApplyRole) - + messageBox.addButton(QMessageBox.Cancel) messageBox.addButton(QMessageBox.Yes) result = messageBox.exec() - if messageBox.clickedButton() == openPurgeDialog: - self.purgeBeforeRunning(default=False) - elif messageBox.clickedButton() == purgeDefault: - self.purgeBeforeRunning() - elif result == QMessageBox.Yes: - self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished - ) - else: - messageBox.close() - self.setControlsEnabled(True) - - def purgeBeforeRunning(self, default=True): - self.setControlsEnabled(False) - if default: - if not self.prepareRun(): - return False - purge_det = self.gudrunFile.purge(headless=False) - if isinstance(purge_det, Sequence): - purge, func, args = purge_det - self.makeProc(purge, self.progressPurge, func=func, args=args) - elif isinstance(purge_det, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find purge_det binary.", - ) - self.setControlsEnabled(True) - return + if result == QMessageBox.Yes: + # Run Purge and queue Gudrun after + self.runPurge_(dialog=True, finished=lambda: self.runGudrun( + self.gudrunFile, self.procFinished + )) + return False + elif result == QMessageBox.No: + return True else: - self.runPurge_() - dcs = self.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - elif isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - self.setControlsEnabled(True) - return - self.queue.put( - ( - (dcs, self.progressDCS), - { - "func": func, - "args": args, - "finished": self.runGudrunFinished, - }, - ) - ) + return False def nexusProcessing(self): if not self.checkFilesExist_(): @@ -1327,6 +1196,8 @@ def processPulseFinished(self): def nexusProcessingFinished(self): self.cleanupRun() + self.worker = None + self.workerThread = None self.proc = None self.outputSlots.setOutput( self.nexusProcessingOutput, @@ -1356,7 +1227,7 @@ def batchProcessing(self): self.mainWidget.stopTaskButton.setEnabled(True) self.nextBatchProcess() - def batchProcessFinished(self, ec, es): + def batchProcessFinished(self): self.outputBatches[self.currentIteration + 1] = self.output self.output = "" self.currentIteration += 1 @@ -1410,7 +1281,7 @@ def progressBatchProcess(self): progress if progress <= 100 else 100 ) - def batchProcessingFinished(self): + def batchProcessingFinished(self, ec, es): self.setControlsEnabled(True) self.queue = Queue() self.proc = None @@ -1567,38 +1438,8 @@ def nextIterableProc(self): self.mainWidget.currentTaskLabel.setText(f"{self.text} {iterInfo}") self.previousProcTitle = self.mainWidget.currentTaskLabel.text() self.iterator.performIteration() - self.iterator.gudrunFile.write_out() - self.proc, func, args = self.queue.get() - self.proc.finished.connect(self.nextIteration) - self.proc.readyReadStandardOutput.connect(self.progressDCS) - self.proc.setWorkingDirectory( - self.iterator.gudrunFile.instrument.GudrunInputFileDir - ) - if func: - func(*args) - self.proc.start() - - def checkFilesExist_(self, showSuccessDialog: bool = False): - result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() - if not all(r[0] for r in result[0]) or not all(r[0] - for r in result[1]): - undefined = [ - r[1] for r in result[0] if not r[0] - ] - unresolved = [r[2] for r in result[1] if not r[0] and r[2]] - missingFilesDialog = MissingFilesDialog( - undefined, unresolved, self.mainWidget - ) - missingFilesDialog.widget.exec_() - return False - - if showSuccessDialog: - QMessageBox.information( - self.mainWidget, - "GudPy Information", - "All files found!", - ) - return True + self.runGudrun(self.iterator.gudrunFile, + self.nextIteration, self.iterator) def iterationStarted(self): self.mainWidget.currentTaskLabel.setText( @@ -1727,13 +1568,9 @@ def setTreeActionsEnabled(self, state): self.mainWidget.paste.setEnabled(state) self.mainWidget.delete_.setEnabled(state) - def progressIncrementDCS(self, gudrunFile=None): + def progressIncrementDCS(self, gudrunFile=None, stdout=""): if not gudrunFile: gudrunFile = self.gudrunFile - if not self.proc: - return 0 - data = self.proc.readAllStandardOutput() - stdout = bytes(data).decode("utf8") self.output += stdout ERROR_KWDS = ["does not exist", "error", "Error"] if [KWD for KWD in ERROR_KWDS if KWD in stdout]: @@ -1779,8 +1616,8 @@ def progressIncrementDCS(self, gudrunFile=None): ) return progress - def progressDCS(self): - progress = self.progressIncrementDCS(self.gudrunFile) + def progressDCS(self, stdout): + progress = self.progressIncrementDCS(self.gudrunFile, stdout) if progress == -1: self.queue = Queue() self.error = ( @@ -1795,51 +1632,41 @@ def progressDCS(self): progress if progress <= 100 else 100 ) - def runPurge_(self, dialog: bool = False) -> bool: - self.setControlsEnabled(False) - if (dialog): + def runPurge_(self, finished=None, dialog=False) -> bool: + if dialog: + self.setControlsEnabled(False) purgeDialog = PurgeDialog(self.gudrunFile, self) result = purgeDialog.widget.exec_() - purge = purgeDialog.purge_det - if purgeDialog.cancelled or result == QDialogButtonBox.No or not purge: + if (purgeDialog.cancelled or result == QDialogButtonBox.No): self.setControlsEnabled(True) self.queue = Queue() return False - else: - purge_det = self.gudrunFile.purge(headless=False) - if isinstance(purge_det, Sequence): - purge, func, args = purge_det - - if isinstance(purge, Sequence): - purge, func, args = purge - elif isinstance(purge, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find purge_det binary.", - ) - self.setControlsEnabled(True) - return False - if not self.prepareRun(): return False - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.gudrunFile.purgeFile.write_out() - self.makeProc(purge, self.progressPurge, func=func, - dir_=self.gudrunFile.instrument.GudrunInputFileDir, - args=args) - def progressIncrementPurge(self): - if not self.proc: - return 0 - data = self.proc.readAllStandardOutput() - stdout = bytes(data).decode("utf8") + self.worker = PurgeWorker(self.gudrunFile) + self.workerThread = QThread() + self.worker.moveToThread(self.workerThread) + self.workerThread.started.connect(self.worker.purge) + self.worker.started.connect(self.procStarted) + self.worker.outputChanged.connect(self.progressPurge) + self.worker.finished.connect(self.cleanupRun) + self.worker.finished.connect(self.workerThread.quit) + + if finished: + self.worker.finished.connect(finished) + + self.workerThread.start() + + def progressIncrementPurge(self, stdout=""): self.output += stdout dataFiles = [self.gudrunFile.instrument.groupFileName] def appendDfs(dfs): + if isinstance(dfs, str): + dfs = [dfs] for df in dfs: dataFiles.append( df.replace(self.gudrunFile.instrument.dataFileType, "grp") @@ -1904,8 +1731,8 @@ def appendDfs(dfs): else: return progress, False, -1 - def progressPurge(self): - progress, finished, detectors = self.progressIncrementPurge() + def progressPurge(self, stdout): + progress, finished, detectors = self.progressIncrementPurge(stdout) if progress == -1: self.error = ( f"An error occurred. See the following traceback" @@ -1920,6 +1747,7 @@ def progressPurge(self): ) if finished: + self.gudrunFile.purged = True thresh = self.gudrunFile.instrument.goodDetectorThreshold if thresh and detectors < thresh: self.warning = ( @@ -1930,25 +1758,17 @@ def progressPurge(self): self.mainWidget.goodDetectorsLabel.setText( f"Number of Good Detectors: {detectors}" ) - self.gudrunFile.purgeFile.organiseOutput() self.cleanupRun() def procStarted(self): self.mainWidget.currentTaskLabel.setText( - self.proc.program().split(os.path.sep)[-1] + self.worker.PROCESS ) self.mainWidget.stopTaskButton.setEnabled(True) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() self.output = "" - def runGudrunFinished(self, ec, es, gudrunFile=None): - if gudrunFile: - gudrunFile.organiseOutput() - else: - self.gudrunFile.organiseOutput() - self.procFinished(ec, es) - - def procFinished(self, ec, es): + def procFinished(self): self.proc = None output = self.output if self.iterator: diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index bcc8ce43..e76cc2f2 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -14,47 +14,112 @@ SUFFIX = ".exe" if os.name == "nt" else "" +class PurgeWorker(QObject): + started = Signal(int) + errorOccured = Signal(str) + outputChanged = Signal(str) + finished = Signal(int) + + def __init__(self, gudrunFile): + super().__init__() + self.gudrunFile = gudrunFile + self.PROCESS = "purge_det" + + def purge(self): + self.started.emit(1) + + if hasattr(sys, '_MEIPASS'): + purge_det = os.path.join(sys._MEIPASS, f"{self.PROCESS}{SUFFIX}") + else: + purge_det = utils.resolve( + os.path.join( + config.__rootdir__, "bin" + ), f"{self.PROCESS}{SUFFIX}" + ) + if not os.path.exists(purge_det): + self.errorOccured.emit("MISSING_BINARY") + return + + with tempfile.TemporaryDirectory() as tmp: + self.gudrunFile.setGudrunDir(tmp) + self.gudrunFile.purgeFile.write_out(os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + f"{self.PROCESS}.dat" + )) + + with subprocess.Popen( + [purge_det, f"{self.PROCESS}.dat"], cwd=tmp, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) as purge: + for line in purge.stdout: + self.outputChanged.emit(line.decode("utf8").rstrip("\n")) + if purge.stderr: + self.errorOccured.emit( + purge.stderr.decode("utf8").rstrip("\n")) + return + + self.gudrunFile.purgeFile.organiseOutput() + + self.gudrunFile.setGudrunDir( + self.gudrunFile.projectDir) + + self.finished.emit(1) + + class GudrunWorker(QObject): started = Signal(int) + outputChanged = Signal(str) nextIteration = Signal(int) errorOccured = Signal(str) finished = Signal(int) - def __init__(self): + def __init__(self, gudrunFile, iterator): super().__init__() + self.gudrunFile = gudrunFile + self.iterator = iterator + self.PROCESS = "gudrun_dcs" - def work(self, gudrunFile, iterator=None): + def gudrun(self): self.started.emit(1) if hasattr(sys, '_MEIPASS'): - gudrun_dcs = os.path.join(sys._MEIPASS, f"gudrun_dcs{SUFFIX}") + gudrun_dcs = os.path.join(sys._MEIPASS, f"{self.PROCESS}{SUFFIX}") else: gudrun_dcs = utils.resolve( os.path.join( config.__rootdir__, "bin" - ), f"gudrun_dcs{SUFFIX}" + ), f"{self.PROCESS}{SUFFIX}" ) + if not os.path.exists(gudrun_dcs): + self.errorOccured.emit("MISSING_BINARY") + return with tempfile.TemporaryDirectory() as tmp: - path = gudrunFile.outpath - gudrunFile.setGudrunDir(tmp) + path = self.gudrunFile.outpath + self.gudrunFile.setGudrunDir(tmp) path = os.path.join( tmp, path ) - gudrunFile.write_out(path) + self.gudrunFile.write_out(path) with subprocess.Popen( [gudrun_dcs, path], cwd=tmp, - stdout=subprocess.PIPE + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT ) as gudrun: for line in gudrun.stdout: - print(line.decode("utf8").rstrip("\n")) - - if iterator is not None: - gudrunFile.gudrunOutput = iterator.organiseOutput() + self.outputChanged.emit(line.decode("utf8").rstrip("\n")) + if gudrun.stderr: + self.errorOccured.emit( + gudrun.stderr.decode("utf8").rstrip("\n")) + return + + if self.iterator is not None: + self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() else: - gudrunFile.gudrunOutput = gudrunFile.organiseOutput() - gudrunFile.setGudrunDir(gudrunFile.gudrunOutput.path) + self.gudrunFile.gudrunOutput = self.gudrunFile.organiseOutput() + self.gudrunFile.setGudrunDir(self.gudrunFile.gudrunOutput.path) self.finished.emit(1) From a1cb695da801b64058f719a4c8ef452808e0544b Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:50:04 +0700 Subject: [PATCH 105/165] Refactor --- gudpy/gui/widgets/dialogs/purge_dialog.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/gudpy/gui/widgets/dialogs/purge_dialog.py b/gudpy/gui/widgets/dialogs/purge_dialog.py index 5933e1e1..01c7cc79 100644 --- a/gudpy/gui/widgets/dialogs/purge_dialog.py +++ b/gudpy/gui/widgets/dialogs/purge_dialog.py @@ -4,6 +4,8 @@ from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QDialog +from core.purge_file import PurgeFile + class PurgeDialog(QDialog): """ @@ -21,6 +23,7 @@ class PurgeDialog(QDialog): initComponents() Loads the UI file for the IterationDialog """ + def __init__(self, gudrunFile, parent): super(PurgeDialog, self).__init__(parent=parent) self.gudrunFile = gudrunFile @@ -38,12 +41,13 @@ def purge(self): Purge with the specified configuration. Called when an accepted signal is emmited from the buttonBox. """ - self.purge_det = self.gudrunFile.purge( - headless=False, - standardDeviation=( - self.stdDeviationsAcceptanceOffset, - self.stdsAroundMeanDeviation - ), + self.gudrunFile.purgeFilestandardDeviation = ( + self.stdDeviationsAcceptanceOffset, + self.stdsAroundMeanDeviation + ) + self.gudrunFile.purgeFile = PurgeFile( + self.gudrunFile, + standardDeviation=self.gudrunFile.purgeFilestandardDeviation, ignoreBad=self.ignoreBad, excludeSampleAndCan=self.excludeSampleAndCan ) From d33497f5b8b82cab2e0a62f2931781efb48ff32b Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:50:19 +0700 Subject: [PATCH 106/165] Refactor --- gudpy/core/purge_file.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/gudpy/core/purge_file.py b/gudpy/core/purge_file.py index d334a973..a77ddbe7 100644 --- a/gudpy/core/purge_file.py +++ b/gudpy/core/purge_file.py @@ -40,7 +40,10 @@ class PurgeFile(): def __init__( self, - gudrunFile + gudrunFile, + standardDeviation=(10, 10), + ignoreBad=True, + excludeSampleAndCan=True, ): """ Constructs all the necessary attributes for the PurgeFile object. @@ -51,9 +54,9 @@ def __init__( Parent GudrunFile that we are creating the PurgeFile from. """ self.gudrunFile = gudrunFile - self.excludeSampleAndCan = True - self.standardDeviation = (10, 10) - self.ignoreBad = True + self.excludeSampleAndCan = excludeSampleAndCan + self.standardDeviation = standardDeviation + self.ignoreBad = ignoreBad def write_out(self, path=""): """ @@ -294,5 +297,5 @@ def purge( ) def organiseOutput(self): - outputHandler = OutputHandler(self.gudrunFile, "Purge", overwrite=True) + outputHandler = OutputHandler(self.gudrunFile, "Purge") outputHandler.organiseOutput() From 5b4de4d7bdfac790a0219bacd6ffbefa8e028b15 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:50:35 +0700 Subject: [PATCH 107/165] Fixes for new changes --- gudpy/core/output_file_handler.py | 61 +++++++++++++++++-------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index 6c13514d..b7cbfb3c 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -2,7 +2,7 @@ import shutil import typing from dataclasses import dataclass -from core.utils import makeDir +import core.utils as utils import tempfile @@ -42,36 +42,39 @@ class OutputHandler: """Class to organise purge output files """ - def __init__(self, gudrunFile, dirName: str, overwrite=True): + def __init__(self, gudrunFile, dirName: str): self.gudrunFile = gudrunFile + self.dirName = dirName # Directory where files are outputted and process was run (temp) self.procDir = self.gudrunFile.instrument.GudrunInputFileDir # Make sure it is a temporary directory - print(self.procDir) assert (self.procDir.startswith(tempfile.gettempdir())) - # Name the output directory as the input file + # Get the output directory self.outputDir = os.path.join( - self.gudrunFile.inputFileDir, self.gudrunFile.projectDir, - dirName + self.dirName ) - # If output directory exists, move to a temp dir and clear it - # Avoids shutil.rmtree - if overwrite and os.path.exists(self.outputDir): - with tempfile.TemporaryDirectory() as tmp: - shutil.move(self.outputDir, os.path.join(tmp, "prev")) - def organiseOutput(self): """Function to move all files from the process directory to the project directory """ - makeDir(self.outputDir) - for f in os.listdir(self.procDir): - shutil.copyfile( - os.path.join(self.procDir, f), - os.path.join(self.outputDir, f) - ) + + # If output directory exists, move to a temp dir and clear it + # Avoids shutil.rmtree + + with tempfile.TemporaryDirectory() as tmp: + newDir = utils.makeDir(os.path.join(tmp, self.dirName)) + + for f in os.listdir(self.procDir): + shutil.copyfile( + os.path.join(self.procDir, f), + os.path.join(newDir, f) + ) + + if os.path.exists(self.outputDir): + shutil.move(self.outputDir, os.path.join(tmp, "prev")) + shutil.move(newDir, self.outputDir) class GudrunOutputHandler(OutputHandler): @@ -111,9 +114,9 @@ def __init__(self, gudrunFile, head="", overwrite=True): super().__init__( gudrunFile, "Gudrun", - overwrite=overwrite ) + self.overwrite = overwrite # Append head to path self.outputDir = os.path.join(self.outputDir, f"{head}") @@ -156,10 +159,13 @@ def organiseOutput(self): # Create additonal output folders inputFilePath = self._createAddOutDir(self.tempOutDir) - # Move over folders to output directory - shutil.move(self.tempOutDir, self.outputDir) + # If overwrite, move previous directory + if self.overwrite and os.path.exists(self.outputDir): + with tempfile.TemporaryDirectory() as tmp: + shutil.move(self.outputDir, os.path.join(tmp, "prev")) - print(f"MOVING OUTPUTS FROM {self.tempOutDir} TO {self.outputDir}") + # Move over folders to output directory + shutil.move(self.tempOutDir, utils.uniquify(self.outputDir)) return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], @@ -258,7 +264,7 @@ def _createSampleDir(self, dest): # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): - makeDir(samplePath) + utils.makeDir(samplePath) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) @@ -303,7 +309,7 @@ def _createAddOutDir(self, dest): inputFile : str Path to the input file """ - addDir = makeDir(os.path.join(dest, "AdditionalOutputs")) + addDir = utils.makeDir(os.path.join(dest, "AdditionalOutputs")) inputFile = "" for f in os.listdir(self.gudrunDir): @@ -348,7 +354,7 @@ def _copyOutputs(self, fpath, dest): # extension if os.path.splitext(f)[0] == fname: if not dirCreated: - makeDir(runDir) + utils.makeDir(runDir) dirCreated = True shutil.copyfile( os.path.join(self.gudrunDir, f), @@ -395,9 +401,10 @@ def _copyOutputsByExt(self, fpath, dest, folderName): if fn == fname: if not dirCreated: # Path to folder which will hold Gudrun outputs - outDir = makeDir(os.path.join(runDir, "Outputs")) + outDir = utils.makeDir(os.path.join(runDir, "Outputs")) # Path to folder which will hold Gudrun diagnostic outputs - diagDir = makeDir(os.path.join(runDir, "Diagnostics")) + diagDir = utils.makeDir( + os.path.join(runDir, "Diagnostics")) # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir if dir == outDir: From f039a59c5b302ec3d952bf5dbfa77f6e6131a768 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:50:43 +0700 Subject: [PATCH 108/165] Fixes for new changes --- gudpy/core/gudrun_file.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 4c6a1a07..7b5b3126 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -147,37 +147,48 @@ def __init__(self, path=None, format=Format.YAML, config_=False): """ # Path and filename of initial input file - self.path = path - self.inputFileDir = os.path.dirname(path) - self.filename = os.path.basename(path) + self.yaml = YAML() self.format = format # Construct the outpath of generated input file self.outpath = "gudpy.txt" - self.projectDir = os.path.join( - self.inputFileDir, os.path.splitext(self.filename)[0]) + self.components = Components(components=[]) self.gudrunOutput = None - if isinstance(path, type(None)): - self.instrument = Instrument() + if path: + self.path = path + self.inputFileDir = os.path.dirname(path) + self.filename = os.path.basename(path) + self.projectDir = os.path.join( + self.inputFileDir, os.path.splitext(self.filename)[0]) + self.instrument = None self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] else: - self.instrument = None + self.instrument = Instrument() self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] - self.parse(config_=config_) + self.parse(config_=config_) self.purged = False # Parse the GudrunFile. self.stream = None self.purgeFile = PurgeFile(self) self.nexus_processing = NexusProcessing(self) + def checkSaveLocation(self): + return self.path is not None + + def setSaveLocation(self, projectDir): + self.projectDir = projectDir + self.inputFileDir = projectDir + self.filename = os.path.basename(projectDir) + self.path = os.path.join(self.projectDir, self.filename) + def __deepcopy__(self, memo): result = self.__class__.__new__(self.__class__) memo[id(self)] = result @@ -1539,8 +1550,6 @@ def write_out(self, path='', overwrite=False, writeParameters=True): def setGudrunDir(self, dir): assert (os.path.isdir(os.path.abspath(dir))) - print( - f"Gudrun dir set to: {dir} was initially: {self.instrument.GudrunInputFileDir}") self.instrument.GudrunInputFileDir = dir def dcs(self, path='', headless=True, iterator=None): From 98b49d384127c887f81f5e51df96f31f5bb53de3 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:50:57 +0700 Subject: [PATCH 109/165] Fixes for new changes --- gudpy/core/nexus_processing.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gudpy/core/nexus_processing.py b/gudpy/core/nexus_processing.py index d786ad2a..e426dfc0 100644 --- a/gudpy/core/nexus_processing.py +++ b/gudpy/core/nexus_processing.py @@ -251,7 +251,7 @@ def __init__(self, gudrunFile): self.period = Period() self.extrapolationMode = ExtrapolationModes.FORWARDS self.startLabel = "" - self.dataFileDir = self.gudrunFile.instrument.dataFileDir + self.dataFileDir = self.ref.instrument.dataFileDir self.outputDir = "" self.sample = None self.useTempDataFileDir = False @@ -272,6 +272,8 @@ def isConfigurationValid(self): Checks if the current configuration is valid. """ + self.dataFileDir = self.ref.instrument.dataFileDir + # Check for valid directories. if not self.outputDir: return False, "Output Directory not specified" @@ -640,7 +642,6 @@ def interpolateData(self, files): files : str[] List of files to interpolate. """ - print("Using good frame threshold: ", str(self.goodFrameThreshold)) # Sort the files beforehand, # so they should be in ascending order by start time. files = sorted( From eba3a549d95c7c337abb7eff84d126c0c149706c Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 27 Dec 2023 15:51:07 +0700 Subject: [PATCH 110/165] Remove print --- gudpy/core/iterators/inelasticity_subtraction.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 96cb5836..8a24298e 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -279,7 +279,6 @@ def iterate(self): Perform n iterations on both the wavelength scale and Q scale. """ - print("ITERATING WAVELENGTH") for _ in range(self.nTotal * 2): self.performIteration() self.gudrunFile.dcs(iterator=self) From 1f05fff93b457676055a20b6a533c28cf23ef2da Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 07:26:33 +0000 Subject: [PATCH 111/165] Linting --- gudpy/core/iterators/inelasticity_subtraction.py | 1 - gudpy/core/iterators/tweak_factor.py | 1 - gudpy/gui/widgets/core/main_window.py | 9 +++++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 8a24298e..903fe644 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -1,4 +1,3 @@ -from pathlib import Path import time import os diff --git a/gudpy/core/iterators/tweak_factor.py b/gudpy/core/iterators/tweak_factor.py index 6eb24169..040373b5 100644 --- a/gudpy/core/iterators/tweak_factor.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -1,4 +1,3 @@ -import os import time from core.gud_file import GudFile diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 3ed13a8f..367d5584 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -3,9 +3,7 @@ import sys import math import traceback -import tempfile from queue import Queue -from collections.abc import Sequence import re from PySide6.QtCore import ( QFile, @@ -26,7 +24,6 @@ QMainWindow, QMessageBox, QProgressBar, - QPushButton, QSizePolicy, QStatusBar, QWidget, @@ -98,7 +95,11 @@ from core.run_individual_files import RunIndividualFiles from core.gud_file import GudFile from core.utils import breplace, nthint -from gui.widgets.core.worker import CompositionWorker, GudrunWorker, PurgeWorker +from gui.widgets.core.worker import ( + CompositionWorker, + GudrunWorker, + PurgeWorker +) class GudPyMainWindow(QMainWindow): From 0c870667d0be42622c1de80e2087288c09737c85 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 09:06:42 +0000 Subject: [PATCH 112/165] Verbose test --- .github/workflows/test/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 03a0da1d..3f0c2854 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -32,7 +32,7 @@ runs: shell: bash run: | cd gudpy - nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml test + nose2 --verbose --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml test mkdir ../results mv nose2-junit.xml ../results/nose2-junit-${{ runner.os }}.xml From 64451f43025d38c39372d1a001bfe4bbbc3bde62 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 10:00:58 +0000 Subject: [PATCH 113/165] Verbose test --- .github/workflows/test/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 3f0c2854..42984554 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -32,7 +32,7 @@ runs: shell: bash run: | cd gudpy - nose2 --verbose --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml test + nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test mkdir ../results mv nose2-junit.xml ../results/nose2-junit-${{ runner.os }}.xml From 621f4863285390562d17c46c79bee9932a635db3 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 10:33:00 +0000 Subject: [PATCH 114/165] Verbose test --- .github/workflows/test/action.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 42984554..13a9b3c5 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -1,5 +1,8 @@ name: Test +env: + ACTIONS_STEP_DEBUG: true + runs: using: "composite" steps: From 36917161dd91361a5b9fb591234931d2988cc99c Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 11:48:12 +0000 Subject: [PATCH 115/165] Fix hanging tests by manually error checking gudrun and stop using popen.wait() --- gudpy/core/gudrun_file.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 7b5b3126..8e0be74f 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1587,12 +1587,23 @@ def dcs(self, path='', headless=True, iterator=None): gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") with subprocess.Popen( [gudrun_dcs, path], cwd=tmp, - stdout=subprocess.PIPE, stderr=subprocess.PIPE + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT ) as gudrun: - gudrun.wait() result = gudrun - _, stderr = gudrun.communicate() - result.stderr = stderr.decode("utf8") + + ERROR_KWDS = ["does not exist", "error", "Error"] + + for line in gudrun.stdout: + if [KWD for KWD in ERROR_KWDS if KWD + in line.decode("utf8").rstrip("\n")]: + result.error = line + result.returncode = 1 + return result + + if gudrun.stderr: + result.stderr = gudrun.stderr + return result if iterator is not None: self.gudrunOutput = iterator.organiseOutput() From 99a3a22b6a033f45750ec159906749fbcd7d5f72 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 11:48:28 +0000 Subject: [PATCH 116/165] Fix hanging tests by manually error checking gudrun and stop using popen.wait() --- gudpy/core/gud_file.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index b6267b2a..806d2d7a 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -90,6 +90,18 @@ def __init__(self, path): path : str Path to the file. """ + + # Handle edge cases - invalid extensions and paths. + if not path: + raise ParserException("Please supply a valid path.") + + if not path.endswith(".gud"): + raise ParserException(f"Attempted to parse {path}" + + "\nOnly .gud files can be parsed.") + + if not os.path.isfile(path): + raise ParserException(f"{path} is not a valid path.") + self.path = path # Construct the outpath @@ -119,14 +131,6 @@ def __init__(self, path): self.stream = [] self.output = "" - # Handle edge cases - invalid extensions and paths. - if not self.path.endswith(".gud"): - raise ParserException(f"Attempted to parse {self.path}" + - "\nOnly .gud files can be parsed.") - - if not os.path.isfile(self.path): - raise ParserException(f"{self.path} is not a valid path.") - # Parse the GudFile self.parse() From ac72fdc62efdb61d5e99ea82d81cd15dadb48023 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 12:04:13 +0000 Subject: [PATCH 117/165] Fix exception for windows --- gudpy/core/output_file_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index b7cbfb3c..befb738f 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -327,7 +327,7 @@ def _createAddOutDir(self, dest): os.path.join(self.gudrunDir, f), os.path.join(addDir, f) ) - except IsADirectoryError: + except (IsADirectoryError, PermissionError): # If it is a directory, move on to next file continue return inputFile From c1aa7e2e418a7423dc4c92983a6edbc8624f315b Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 12:31:15 +0000 Subject: [PATCH 118/165] Fixing tests --- gudpy/core/gudrun_file.py | 5 +++-- gudpy/test/test_gudpy_io.py | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 8e0be74f..58a4e88b 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -157,8 +157,9 @@ def __init__(self, path=None, format=Format.YAML, config_=False): self.components = Components(components=[]) self.gudrunOutput = None - if path: - self.path = path + self.path = path + + if self.path: self.inputFileDir = os.path.dirname(path) self.filename = os.path.basename(path) self.projectDir = os.path.join( diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 7af91b77..779344f9 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -1543,7 +1543,7 @@ def testLoadMissingContainerAttributesRand(self): ) def testZeroExitGudrun(self): - g = GudrunFile("test/TestData/NIMROD-water/good_water.txt", + g = GudrunFile(path="test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) result = g.dcs() - self.assertEqual(result.stderr, "") + self.assertEqual(result.stderr, None) From acae80de1e1ce01c2cec56f50c9b019c80f6757f Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 15:12:00 +0000 Subject: [PATCH 119/165] Debugging --- gudpy/core/gudrun_file.py | 4 ++++ gudpy/test/test_gudpy_io.py | 7 +++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 58a4e88b..6b861b55 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1526,6 +1526,10 @@ def write_out(self, path='', overwrite=False, writeParameters=True): self.outpath ), "w", encoding="utf-8") else: + if not self.path: + self.path = os.path.join( + self.instrument.GudrunInputFileDir, + self.outpath) f = open(self.path, "w", encoding="utf-8") if os.path.basename(f.name) == self.outpath: for sampleBackground in self.sampleBackgrounds: diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 779344f9..e6d25e32 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -900,11 +900,10 @@ def compareString(string1, string2): def testReloadGudrunFile(self): self.g.write_out(overwrite=True) + for f in os.listdir(self.g.instrument.GudrunInputFileDir): + print(f) g1 = GudrunFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir From c74ec044ee296c3817af55121a6f716d29cfaf06 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 11 Jan 2024 15:47:08 +0000 Subject: [PATCH 120/165] Fix test error --- gudpy/test/test_gudpy_io.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index e6d25e32..d99c2f18 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -759,10 +759,7 @@ def testLoadGudrunFile(self): def testWriteGudrunFile(self): self.g.write_out(overwrite=True) with open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, encoding="utf-8" ) as f: outlines = "\n".join(f.readlines()[:-5]) @@ -851,10 +848,7 @@ def testRewriteGudrunFile(self): "copyGF.txt" ) g1 = GudrunFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir From eb6239a35008b39306cf2109f0d35468715540a8 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 12 Jan 2024 08:24:19 +0000 Subject: [PATCH 121/165] Fix test error --- gudpy/test/test_gudpy_io.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index d99c2f18..82ab9ada 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -880,8 +880,7 @@ def compareString(string1, string2): with open( os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath + self.g.path ), encoding="utf-8" ) as fg: @@ -894,8 +893,6 @@ def compareString(string1, string2): def testReloadGudrunFile(self): self.g.write_out(overwrite=True) - for f in os.listdir(self.g.instrument.GudrunInputFileDir): - print(f) g1 = GudrunFile( self.g.path, format=Format.TXT From 041572cdb783cec7213d7ff0ef6156134e491d9f Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Fri, 12 Jan 2024 09:03:29 +0000 Subject: [PATCH 122/165] Outputs fix 2.5 (#461) * Changed window title to only show filename (#456) * Changing temp directory control * Debug * Cwd change * Fix prev commit * Debugging * Attempt to fix test * Upgrade PySide version to 6.6.0 (#463) Co-authored-by: Spitz * lint * Fix IDAaaS Setup Script (#471) * Install XCB cursor lib. * More RPM requirements. * Fixes November 2023 (#473) * Add window title modification placeholder. * Add detectorCalibrationFileName to GudPyFileLibray and harmonise name capitalisation to reflect UI. * Notify user that all files were found. * Fix file types for input file dialog. * Be more careful about raising that dialog. * Don't forget to re-enable GUI after failing to find gudrun_dcs binary. * Formatting. * Create base class for output handler * Run purge in temp dir * Output organising fixes- proper gudfile path * Iterator fixes * Make each iteration run in new temp dir * Composition iterator * Iterate by composition * Iterate by composition * Formatting * Fix progress bar * Fix merge * Fixing tests * Display live output from running processes (#474) * Live output of processes * Change 'setText' to append for smoother experience + remove unecessary code * Remove comment --------- Co-authored-by: Spitz * Fix wavelength iterator * Fix asserion- invalid use of try except * Use POpen instead of run * Remove print * Refactor purge file * Fix composition iterator * Fix wavelength iteration process * Create gudrun worker * Create gudrun worker * Fix iterator * Fix assertions * Improve purge running and fix issue * Removing unecessary organise output * Used threading instead of qprocess, altered purge dialog, secured temp dir * Refactor * Refactor * Fixes for new changes * Fixes for new changes * Fixes for new changes * Remove print * Linting * Verbose test * Verbose test * Verbose test * Fix hanging tests by manually error checking gudrun and stop using popen.wait() * Fix hanging tests by manually error checking gudrun and stop using popen.wait() * Fix exception for windows * Fixing tests * Debugging * Fix test error * Fix test error --------- Co-authored-by: Spitz Co-authored-by: Tristan Youngs --- .github/workflows/test/action.yml | 5 +- gudpy/core/file_library.py | 13 +- gudpy/core/gud_file.py | 20 +- gudpy/core/gudrun_file.py | 131 +++-- gudpy/core/iterators/composition.py | 31 +- .../iterators/inelasticity_subtraction.py | 42 +- gudpy/core/iterators/iterator.py | 4 +- gudpy/core/iterators/tweak_factor.py | 14 +- gudpy/core/nexus_processing.py | 5 +- gudpy/core/output_file_handler.py | 209 ++++--- gudpy/core/purge_file.py | 38 +- gudpy/gui/widgets/core/main_window.py | 552 +++++++----------- gudpy/gui/widgets/core/output_tree.py | 2 +- gudpy/gui/widgets/core/worker.py | 118 +++- gudpy/gui/widgets/dialogs/iteration_dialog.py | 14 +- gudpy/gui/widgets/dialogs/purge_dialog.py | 16 +- gudpy/gui/widgets/slots/output_slots.py | 9 + gudpy/gui/widgets/ui_files/mainWindow.ui | 2 +- gudpy/test/test_gud_file.py | 20 +- gudpy/test/test_gudpy_io.py | 63 +- gudpy/test/test_gudpy_workflows.py | 61 +- gudpy/test/test_utils.py | 14 +- requirements.txt | 2 +- scripts/setup-idaaas-dev.sh | 6 + 24 files changed, 733 insertions(+), 658 deletions(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 03a0da1d..13a9b3c5 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -1,5 +1,8 @@ name: Test +env: + ACTIONS_STEP_DEBUG: true + runs: using: "composite" steps: @@ -32,7 +35,7 @@ runs: shell: bash run: | cd gudpy - nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml test + nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test mkdir ../results mv nose2-junit.xml ../results/nose2-junit-${{ runner.os }}.xml diff --git a/gudpy/core/file_library.py b/gudpy/core/file_library.py index 0296d31f..197225c1 100644 --- a/gudpy/core/file_library.py +++ b/gudpy/core/file_library.py @@ -47,14 +47,17 @@ def __init__(self, gudrunFile): # Collect files of static objects self.files = { - "Groups file": gudrunFile.instrument.groupFileName, - "Deadtime constants file": ( + "Detector Calibration File": ( + gudrunFile.instrument.detectorCalibrationFileName + ), + "Groups File": gudrunFile.instrument.groupFileName, + "Deadtime Constants File": ( gudrunFile.instrument.deadtimeConstantsFileName ), - "Scattering lengths file": ( + "Scattering Lengths File": ( gudrunFile.instrument.neutronScatteringParametersFile ), - "Incident beam spectrum parameters": ( + "Incident Beam Spectrum Parameters": ( gudrunFile.beam.filenameIncidentBeamSpectrumParams ), } @@ -68,7 +71,7 @@ def __init__(self, gudrunFile): # then we also need the nexus definition file. if dataFileType.lower() == "nxs": self.files[ - "NeXus definition file" + "NeXus Definition File" ] = gudrunFile.instrument.nxsDefinitionFile # If the Total Cross Section Source of any object uses a file, diff --git a/gudpy/core/gud_file.py b/gudpy/core/gud_file.py index b6267b2a..806d2d7a 100644 --- a/gudpy/core/gud_file.py +++ b/gudpy/core/gud_file.py @@ -90,6 +90,18 @@ def __init__(self, path): path : str Path to the file. """ + + # Handle edge cases - invalid extensions and paths. + if not path: + raise ParserException("Please supply a valid path.") + + if not path.endswith(".gud"): + raise ParserException(f"Attempted to parse {path}" + + "\nOnly .gud files can be parsed.") + + if not os.path.isfile(path): + raise ParserException(f"{path} is not a valid path.") + self.path = path # Construct the outpath @@ -119,14 +131,6 @@ def __init__(self, path): self.stream = [] self.output = "" - # Handle edge cases - invalid extensions and paths. - if not self.path.endswith(".gud"): - raise ParserException(f"Attempted to parse {self.path}" + - "\nOnly .gud files can be parsed.") - - if not os.path.isfile(self.path): - raise ParserException(f"{self.path} is not a valid path.") - # Parse the GudFile self.parse() diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index fe8b1e28..6b861b55 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -29,7 +29,7 @@ from core.element import Element from core.data_files import DataFiles from core.purge_file import PurgeFile -from core.output_file_handler import OutputFileHandler +from core.output_file_handler import GudrunOutputHandler from core.enums import ( CrossSectionSource, Format, Instruments, FTModes, UnitsOfDensity, MergeWeights, Scales, NormalisationType, OutputUnits, @@ -147,36 +147,49 @@ def __init__(self, path=None, format=Format.YAML, config_=False): """ # Path and filename of initial input file - self.path = path - self.inputFileDir = os.path.dirname(path) - self.filename = os.path.basename(path) + self.yaml = YAML() self.format = format # Construct the outpath of generated input file self.outpath = "gudpy.txt" - self.outputDir = "" + self.components = Components(components=[]) self.gudrunOutput = None - if isinstance(path, type(None)): - self.instrument = Instrument() + self.path = path + + if self.path: + self.inputFileDir = os.path.dirname(path) + self.filename = os.path.basename(path) + self.projectDir = os.path.join( + self.inputFileDir, os.path.splitext(self.filename)[0]) + self.instrument = None self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] else: - self.instrument = None + self.instrument = Instrument() self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] - self.parse(config_=config_) + self.parse(config_=config_) self.purged = False # Parse the GudrunFile. self.stream = None self.purgeFile = PurgeFile(self) self.nexus_processing = NexusProcessing(self) + def checkSaveLocation(self): + return self.path is not None + + def setSaveLocation(self, projectDir): + self.projectDir = projectDir + self.inputFileDir = projectDir + self.filename = os.path.basename(projectDir) + self.path = os.path.join(self.projectDir, self.filename) + def __deepcopy__(self, memo): result = self.__class__.__new__(self.__class__) memo[id(self)] = result @@ -1472,7 +1485,8 @@ def save(self, path='', format=None): if not format: format = self.format if format == Format.TXT: - self.write_out(path=path.replace(path.split(".")[-1], "txt")) + self.write_out(path=path.replace( + path.split(".")[-1], "txt"), overwrite=True) elif format == Format.YAML: self.write_yaml(path=path.replace(path.split(".")[-1], "yaml")) @@ -1496,16 +1510,26 @@ def write_out(self, path='', overwrite=False, writeParameters=True): None """ if path: + if not overwrite: + assert (not os.path.exists(path)) f = open( path, "w", encoding="utf-8" ) elif not overwrite: + assert (not os.path.exists(os.path.join( + self.instrument.GudrunInputFileDir, + self.outpath) + )) f = open( os.path.join( self.instrument.GudrunInputFileDir, self.outpath ), "w", encoding="utf-8") else: + if not self.path: + self.path = os.path.join( + self.instrument.GudrunInputFileDir, + self.outpath) f = open(self.path, "w", encoding="utf-8") if os.path.basename(f.name) == self.outpath: for sampleBackground in self.sampleBackgrounds: @@ -1554,30 +1578,44 @@ def dcs(self, path='', headless=True, iterator=None): The result of calling gudrun_dcs using subprocess.run. Can access stdout/stderr from this. """ - assert (self.instrument.GudrunInputFileDir) - if not path: - path = os.path.basename(self.path) + path = f"./{self.outpath}" + if headless: with tempfile.TemporaryDirectory() as tmp: - try: - self.setGudrunDir(tmp) - gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) - result = subprocess.run( - [gudrun_dcs, path], capture_output=True, text=True - ) - if iterator is not None: - self.gudrunOutput = iterator.organiseOutput() - else: - self.gudrunOutput = self.organiseOutput() - self.setGudrunDir(self.gudrunOutput.path) - os.chdir(cwd) - except FileNotFoundError: - os.chdir(cwd) - return False - return result + self.setGudrunDir(tmp) + path = os.path.join( + tmp, + path + ) + self.write_out(path) + gudrun_dcs = resolve("bin", f"gudrun_dcs{SUFFIX}") + with subprocess.Popen( + [gudrun_dcs, path], cwd=tmp, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) as gudrun: + result = gudrun + + ERROR_KWDS = ["does not exist", "error", "Error"] + + for line in gudrun.stdout: + if [KWD for KWD in ERROR_KWDS if KWD + in line.decode("utf8").rstrip("\n")]: + result.error = line + result.returncode = 1 + return result + + if gudrun.stderr: + result.stderr = gudrun.stderr + return result + + if iterator is not None: + self.gudrunOutput = iterator.organiseOutput() + else: + self.gudrunOutput = self.organiseOutput() + self.setGudrunDir(self.gudrunOutput.path) + return result else: if hasattr(sys, '_MEIPASS'): gudrun_dcs = os.path.join(sys._MEIPASS, f"gudrun_dcs{SUFFIX}") @@ -1597,38 +1635,11 @@ def dcs(self, path='', headless=True, iterator=None): proc, self.write_out, [ - path, + '', False ] ) - def process(self, headless=True, iterator=None): - """ - Write out the current state of the file, - and then call gudrun_dcs on the file that - was written out. - - Parameters - ---------- - purge : bool, optional - Should detectors be purged? - Returns - ------- - subprocess.CompletedProcess - The result of calling gudrun_dcs using subprocess.run. - Can access stdout/stderr from this. - """ - cwd = os.getcwd() - os.chdir(self.instrument.GudrunInputFileDir) - self.write_out() - dcs = self.dcs( - path=self.outpath, - headless=headless, - iterator=iterator - ) - os.chdir(cwd) - return dcs - def purge(self, *args, **kwargs): """ Call Purge.purge() to purge the detectors. @@ -1662,7 +1673,7 @@ def convertToSample(self, container, persist=False): return sample def organiseOutput(self, head="", overwrite=True): - outputHandler = OutputFileHandler( + outputHandler = GudrunOutputHandler( self, head=head, overwrite=overwrite ) gudrunOutput = outputHandler.organiseOutput() diff --git a/gudpy/core/iterators/composition.py b/gudpy/core/iterators/composition.py index a63e9f89..2a8071ca 100644 --- a/gudpy/core/iterators/composition.py +++ b/gudpy/core/iterators/composition.py @@ -112,6 +112,8 @@ def __init__(self, gudrunFile): self.ratio = 0 self.nTotal = 0 self.nCurrent = 0 + self.iterationType = self.name + self.nWeightedComponents = 0 """ Sets component and ratio. @@ -169,16 +171,14 @@ def processSingleComponent(self, x, sampleBackground): component.ratio = x sampleBackground.samples[0].composition.translate() - self.gudrunFile.process() + self.gudrunFile.dcs(iterator=self) time.sleep(1) - gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + gudFile = GudFile( os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, gudPath + self.gudrunFile.gudrunOutput.gudFile( + name=sampleBackground.samples[0].name) ) ) @@ -219,16 +219,14 @@ def processTwoComponents(self, x, sampleBackground, totalMolecules): wcB.ratio = abs(totalMolecules - x) sampleBackground.samples[0].composition.translate() - self.gudrunFile.process() + self.gudrunFile.dcs(iterator=self) time.sleep(1) - gudPath = sampleBackground.samples[0].dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) + gudFile = GudFile( os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, gudPath + self.gudrunFile.gudrunOutput.gudFile( + name=sampleBackground.samples[0].name) ) ) @@ -285,7 +283,12 @@ def iterate(self, n=10, rtol=10.): args=(sb, totalMolecules,) ) - self.gudrunFile.organiseOutput() - def gss(self, f, bounds, n, args=()): return gss(f, bounds, n, self.maxIterations, self.rtol, args=args) + + def organiseOutput(self): + """ + This organises the output of the iteration. + """ + gudrunOutput = self.gudrunFile.organiseOutput() + return gudrunOutput diff --git a/gudpy/core/iterators/inelasticity_subtraction.py b/gudpy/core/iterators/inelasticity_subtraction.py index 1f6d99b3..903fe644 100644 --- a/gudpy/core/iterators/inelasticity_subtraction.py +++ b/gudpy/core/iterators/inelasticity_subtraction.py @@ -1,6 +1,5 @@ -from pathlib import Path import time -from copy import deepcopy +import os from core.enums import Scales from core.iterators.iterator import Iterator @@ -71,14 +70,17 @@ def __init__(self, gudrunFile, nTotal): Input GudrunFile that we will be using for iterating. """ super().__init__(gudrunFile, nTotal) - self.gudrunFile = deepcopy(gudrunFile) # Does a default iteration first (no changes) self.iterationType = "QIteration" + # Individual iterations + self.iterationCount = 0 + # Iteration pair self.nCurrent = 0 self.topHatWidths = [] self.QMax = 0. self.QMin = 0. self.QStep = 0. + self.gudrunOutputs = [] def enableLogarithmicBinning(self): """ @@ -170,7 +172,7 @@ def setSelfScatteringFiles(self, scale): then set self scattering file extensions to mint01. """ # Dict to pick suffix based on scale - suffix = {Scales.Q: "msubw01", Scales.WAVELENGTH: "mint01"}[scale] + suffix = {Scales.Q: ".msubw01", Scales.WAVELENGTH: ".mint01"}[scale] # Iterate through all of the samples, and set the suffixes of # all of their data files to the suffix @@ -180,8 +182,15 @@ def setSelfScatteringFiles(self, scale): if sample.runThisSample and len(sample.dataFiles): target = sample filename = target.dataFiles[0] + prevOutput = ( + self.gudrunFile.gudrunOutput.output( + sample.name, filename, suffix) + if self.gudrunFile.gudrunOutput else "" + ) target.fileSelfScattering = ( - str(Path(filename).stem) + '.' + suffix + os.path.join( + prevOutput, + ) ) def wavelengthIteration(self): @@ -197,11 +206,11 @@ def wavelengthIteration(self): the x-scale, enable logarithmic binning, set the scale to the wavelength scale, zero the top hat widths, change the extensions of the self scattering files to .mint01. - Then, write out the GudrunFile and call gudrun_dcs. + Then, write out the gudrunFile and call gudrun_dcs. """ self.iterationType = "WavelengthIteration" # First iteration - if self.nCurrent == 0: + if self.iterationCount == 0: # Disable subtracting of wavelength binned data. # Collect the top hat widths and Q range and step size. self.gudrunFile.instrument.subWavelengthBinnedData = False @@ -231,7 +240,7 @@ def QIteration(self): the x-scale, disable logarithmic binning, set the scale to the Q scale, reset the top hat widths, change the extensions of the self scattering files to .msubw01. - Then, write out the GudrunFile and call gudrun_dcs. + Then, write out the gudrunFile and call gudrun_dcs. """ self.iterationType = "QIteration" # Enable subtracting of wavelength binned data @@ -249,18 +258,19 @@ def QIteration(self): def performIteration(self): if self.iterationType == "QIteration": self.wavelengthIteration() - self.nCurrent += 1 + self.iterationCount += 1 else: self.QIteration() + self.nCurrent += 1 def organiseOutput(self): """ This organises the output of the iteration. """ - overwrite = (self.nCurrent == 1 and + overwrite = (self.iterationCount == 1 and self.iterationType == "WavelengthIteration") - self.gudrunFile.organiseOutput( - head=f"{self.iterationType}_{self.nCurrent}", + return self.gudrunFile.organiseOutput( + head=f"{self.iterationType}_{self.iterationCount}", overwrite=overwrite) def iterate(self): @@ -268,10 +278,8 @@ def iterate(self): Perform n iterations on both the wavelength scale and Q scale. """ - - for _ in range(self.nTotal): - + for _ in range(self.nTotal * 2): self.performIteration() - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) + self.gudrunOutputs.append(self.gudrunFile.gudrunOutput) time.sleep(1) - self.organiseOutput() diff --git a/gudpy/core/iterators/iterator.py b/gudpy/core/iterators/iterator.py index 188ce03a..4e3ba159 100644 --- a/gudpy/core/iterators/iterator.py +++ b/gudpy/core/iterators/iterator.py @@ -110,8 +110,8 @@ def iterate(self): n : int Number of iterations to perform. """ - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) for _ in range(self.nTotal): time.sleep(1) self.performIteration() - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) diff --git a/gudpy/core/iterators/tweak_factor.py b/gudpy/core/iterators/tweak_factor.py index 1ae206d4..040373b5 100644 --- a/gudpy/core/iterators/tweak_factor.py +++ b/gudpy/core/iterators/tweak_factor.py @@ -1,4 +1,3 @@ -import os import time from core.gud_file import GudFile @@ -50,15 +49,8 @@ def performIteration(self): s for s in sampleBackground.samples if s.runThisSample and len(s.dataFiles) ]: - gudPath = sample.dataFiles[0].replace( - self.gudrunFile.instrument.dataFileType, - "gud" - ) gudFile = GudFile( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - gudPath - ) + self.gudrunFile.gudrunOutput.gudFile(name=sample.name) ) tweakFactor = float(gudFile.suggestedTweakFactor) sample.sampleTweakFactor = tweakFactor @@ -79,7 +71,7 @@ def iterate(self): n : int Number of iterations to perform. """ - self.gudrunFile.process(iterator=self) + self.gudrunFile.dcs(iterator=self) # Perform n iterations of tweaking by tweak factor. for _ in range(self.nTotal): @@ -87,4 +79,4 @@ def iterate(self): # and run gudrun_dcs on that file. time.sleep(1) self.performIteration() - self.gudrunFile.process(itertor=self) + self.gudrunFile.dcs(iterator=self) diff --git a/gudpy/core/nexus_processing.py b/gudpy/core/nexus_processing.py index d786ad2a..e426dfc0 100644 --- a/gudpy/core/nexus_processing.py +++ b/gudpy/core/nexus_processing.py @@ -251,7 +251,7 @@ def __init__(self, gudrunFile): self.period = Period() self.extrapolationMode = ExtrapolationModes.FORWARDS self.startLabel = "" - self.dataFileDir = self.gudrunFile.instrument.dataFileDir + self.dataFileDir = self.ref.instrument.dataFileDir self.outputDir = "" self.sample = None self.useTempDataFileDir = False @@ -272,6 +272,8 @@ def isConfigurationValid(self): Checks if the current configuration is valid. """ + self.dataFileDir = self.ref.instrument.dataFileDir + # Check for valid directories. if not self.outputDir: return False, "Output Directory not specified" @@ -640,7 +642,6 @@ def interpolateData(self, files): files : str[] List of files to interpolate. """ - print("Using good frame threshold: ", str(self.goodFrameThreshold)) # Sort the files beforehand, # so they should be in ascending order by start time. files = sorted( diff --git a/gudpy/core/output_file_handler.py b/gudpy/core/output_file_handler.py index bf29a7de..befb738f 100644 --- a/gudpy/core/output_file_handler.py +++ b/gudpy/core/output_file_handler.py @@ -2,7 +2,7 @@ import shutil import typing from dataclasses import dataclass -from core.utils import makeDir +import core.utils as utils import tempfile @@ -10,14 +10,15 @@ class SampleOutput: sampleFile: str gudFile: str - outputs: typing.Dict[str, str] + outputs: typing.Dict[str, typing.Dict[str, str]] + diagnostics: typing.Dict[str, typing.Dict[str, str]] @dataclass class GudrunOutput: path: str name: str - inputFile: str + inputFilePath: str sampleOutputs: typing.Dict[str, SampleOutput] def gudFiles(self) -> list[str]: @@ -26,18 +27,78 @@ def gudFiles(self) -> list[str]: def gudFile(self, idx: int = None, *, name: str = None) -> str: if idx is not None: asList = list(self.sampleOutputs.values()) - assert (idx < len(asList)) return asList[idx].gudFile elif name is not None: - assert (name in self.sampleOutputs) return self.sampleOutputs[name].gudFile + def output(self, name: str, dataFile: str, type: str) -> str: + if type in GudrunOutputHandler.outputExts: + return (self.sampleOutputs[name].outputs[dataFile][type]) + else: + return (self.sampleOutputs[name].diagnostics[dataFile][type]) -class OutputFileHandler(): + +class OutputHandler: + """Class to organise purge output files + """ + + def __init__(self, gudrunFile, dirName: str): + self.gudrunFile = gudrunFile + self.dirName = dirName + # Directory where files are outputted and process was run (temp) + self.procDir = self.gudrunFile.instrument.GudrunInputFileDir + # Make sure it is a temporary directory + assert (self.procDir.startswith(tempfile.gettempdir())) + # Get the output directory + self.outputDir = os.path.join( + self.gudrunFile.projectDir, + self.dirName + ) + + def organiseOutput(self): + """Function to move all files from the process directory to + the project directory + """ + + # If output directory exists, move to a temp dir and clear it + # Avoids shutil.rmtree + + with tempfile.TemporaryDirectory() as tmp: + newDir = utils.makeDir(os.path.join(tmp, self.dirName)) + + for f in os.listdir(self.procDir): + shutil.copyfile( + os.path.join(self.procDir, f), + os.path.join(newDir, f) + ) + + if os.path.exists(self.outputDir): + shutil.move(self.outputDir, os.path.join(tmp, "prev")) + shutil.move(newDir, self.outputDir) + + +class GudrunOutputHandler(OutputHandler): + + outputExts = [ + ".dcs01", + ".dcsd01", + ".dcse01", + ".dcst01", + ".dscw01", + ".mdcs01", + ".mdcsd01", + ".mdcse01", + ".mdcsw01", + ".mint01", + ".mgor01", + ".mdor01", + ".gud", + ".sample" + ] def __init__(self, gudrunFile, head="", overwrite=True): """ - Initialise `OutputFileHandler` + Initialise `GudrunOutputHandler` Parameters ---------- @@ -50,44 +111,30 @@ def __init__(self, gudrunFile, head="", overwrite=True): by default True """ - self.gudrunFile = gudrunFile + super().__init__( + gudrunFile, + "Gudrun", + ) + + self.overwrite = overwrite + # Append head to path + self.outputDir = os.path.join(self.outputDir, f"{head}") + # List of run samples self.samples = [] # Directory where Gudrun files are outputted (temp) - self.gudrunDir = self.gudrunFile.instrument.GudrunInputFileDir + self.gudrunDir = self.procDir + # Make sure it is a temporary directory assert (self.gudrunDir.startswith(tempfile.gettempdir())) # Temporary output dir paths - self.tempOutDir = os.path.join(self.gudrunDir, os.path.splitext( - self.gudrunFile.filename)[0]) + self.tempOutDir = os.path.join(self.gudrunDir, "Gudrun") if head: self.tempOutDir = os.path.join( self.tempOutDir, f"{head}") - # Name the output directory as the input file - self.outputDir = os.path.join( - self.gudrunFile.inputFileDir, - os.path.splitext(self.gudrunFile.filename)[0], - f"{head}" - ) # Files that have been copied self.copiedFiles = [] - self.outputExts = [ - ".dcs01", - ".dcsd01", - ".dcse01", - ".dcst01", - ".dscw01", - ".mdcs01", - ".mdcsd01", - ".mdcse01", - ".mdcsw01", - ".mint01", - ".mgor01", - ".mdor01", - ".gud", - ".sample" - ] # Generating paths for sampleBackground in self.gudrunFile.sampleBackgrounds: @@ -96,12 +143,6 @@ def __init__(self, gudrunFile, head="", overwrite=True): if s.runThisSample and len(s.dataFiles)]: self.samples.append(sample) - # If output directory exists, move to a temp dir and clear it - # Avoids shutil.rmtree - if overwrite is True and os.path.exists(self.outputDir): - with tempfile.TemporaryDirectory() as tmp: - shutil.move(self.outputDir, os.path.join(tmp, "prev")) - def organiseOutput(self): """Organises Gudrun outputs @@ -116,24 +157,19 @@ def organiseOutput(self): # Create sample folders sampleOutputs = self._createSampleDir(self.tempOutDir) # Create additonal output folders - inputFile = self._createAddOutDir(self.tempOutDir) + inputFilePath = self._createAddOutDir(self.tempOutDir) + + # If overwrite, move previous directory + if self.overwrite and os.path.exists(self.outputDir): + with tempfile.TemporaryDirectory() as tmp: + shutil.move(self.outputDir, os.path.join(tmp, "prev")) + # Move over folders to output directory - makeDir(self.outputDir) - for root, dirs, files in os.walk(self.tempOutDir): - r = os.path.join( - self.gudrunFile.inputFileDir, - root.partition(self.gudrunDir + "/")[-1]) - for d in dirs: - makeDir(os.path.join(r, d)) - for f in files: - shutil.copyfile( - os.path.join(root, f), - os.path.join(r, f) - ) + shutil.move(self.tempOutDir, utils.uniquify(self.outputDir)) return GudrunOutput(path=self.outputDir, name=os.path.splitext(self.gudrunFile.filename)[0], - inputFile=inputFile, + inputFilePath=inputFilePath, sampleOutputs=sampleOutputs ) @@ -207,6 +243,7 @@ def _createSampleDir(self, dest): sampleFile = "" gudFile = "" sampleOutput = {} + sampleDiag = {} samplePath = os.path.join( dest, @@ -214,17 +251,20 @@ def _createSampleDir(self, dest): ) # Move datafiles to sample folder for idx, dataFile in enumerate(sample.dataFiles): - out = self._copyOutputsByExt( + out, diag = self._copyOutputsByExt( dataFile, - samplePath + samplePath, + sample.name.replace(" ", "_") ) - if idx == 0 and out[dataFile]: - sampleOutput = out - gudFile = (out[dataFile][".gud"] - if ".gud" in out[dataFile] else "") + sampleOutput[dataFile] = out + sampleDiag[dataFile] = diag + if idx == 0: + gudFile = (out[".gud"] + if ".gud" in out else "") # Copy over .sample file if os.path.exists(os.path.join( self.gudrunDir, sample.pathName())): + utils.makeDir(samplePath) shutil.copyfile( os.path.join(self.gudrunDir, sample.pathName()), os.path.join(samplePath, sample.pathName()) @@ -238,7 +278,7 @@ def _createSampleDir(self, dest): sample.pathName()) sampleOutputs[sample.name] = SampleOutput( - sampleFile, gudFile, sampleOutput) + sampleFile, gudFile, sampleOutput, sampleDiag) # Create container folders within sample folder for container in sample.containers: @@ -269,7 +309,7 @@ def _createAddOutDir(self, dest): inputFile : str Path to the input file """ - addDir = makeDir(os.path.join(dest, "AdditionalOutputs")) + addDir = utils.makeDir(os.path.join(dest, "AdditionalOutputs")) inputFile = "" for f in os.listdir(self.gudrunDir): @@ -280,13 +320,17 @@ def _createAddOutDir(self, dest): os.path.join(self.gudrunDir, f), os.path.join(addDir, f) ) - elif f not in self.copiedFiles and os.path.isfile( - os.path.join(self.gudrunDir, f)): - shutil.copyfile( - os.path.join(self.gudrunDir, f), - os.path.join(addDir, f) - ) - return inputFile + + elif f not in self.copiedFiles: + try: + shutil.copyfile( + os.path.join(self.gudrunDir, f), + os.path.join(addDir, f) + ) + except (IsADirectoryError, PermissionError): + # If it is a directory, move on to next file + continue + return inputFile def _copyOutputs(self, fpath, dest): """ @@ -310,7 +354,7 @@ def _copyOutputs(self, fpath, dest): # extension if os.path.splitext(f)[0] == fname: if not dirCreated: - makeDir(runDir) + utils.makeDir(runDir) dirCreated = True shutil.copyfile( os.path.join(self.gudrunDir, f), @@ -318,7 +362,7 @@ def _copyOutputs(self, fpath, dest): ) self.copiedFiles.append(f) - def _copyOutputsByExt(self, fpath, dest): + def _copyOutputsByExt(self, fpath, dest, folderName): """ Copy all files with the same basename as the provided filepath and splits them into outputs @@ -334,6 +378,8 @@ def _copyOutputsByExt(self, fpath, dest): List of target file extenstions dest : str Directory for the files to be copied to + folderName : str + Name of the folder files gets copied to Returns ------- @@ -344,25 +390,32 @@ def _copyOutputsByExt(self, fpath, dest): fname = os.path.splitext(fpath)[0] # Path to folder which will hold all outputs from the run runDir = os.path.join(dest, fname) - # Path to folder which will hold Gudrun outputs - outDir = makeDir(os.path.join(runDir, "Outputs")) - # Path to folder which will hold Gudrun diagnostic outputs - diagDir = makeDir(os.path.join(runDir, "Diagnostics")) + # Has the run dir been created? + dirCreated = False outputs = {} - outputs[fpath] = {} + diagnostics = {} for f in os.listdir(self.gudrunDir): # If the file has the same name as requested filename fn, ext = os.path.splitext(f) if fn == fname: + if not dirCreated: + # Path to folder which will hold Gudrun outputs + outDir = utils.makeDir(os.path.join(runDir, "Outputs")) + # Path to folder which will hold Gudrun diagnostic outputs + diagDir = utils.makeDir( + os.path.join(runDir, "Diagnostics")) # Set dir depending on file extension dir = outDir if ext in self.outputExts else diagDir if dir == outDir: - outputs[fpath][ext] = os.path.join( - self.outputDir, "Outputs", f) + outputs[ext] = os.path.join( + self.outputDir, folderName, fname, "Outputs", f) + else: + diagnostics[ext] = os.path.join( + self.outputDir, folderName, fname, "Diagnostics", f) shutil.copyfile( os.path.join(self.gudrunDir, f), os.path.join(dir, f) ) self.copiedFiles.append(f) - return outputs + return (outputs, diagnostics) diff --git a/gudpy/core/purge_file.py b/gudpy/core/purge_file.py index fc95f471..a77ddbe7 100644 --- a/gudpy/core/purge_file.py +++ b/gudpy/core/purge_file.py @@ -1,11 +1,13 @@ import os import sys import subprocess +import tempfile from PySide6.QtCore import QProcess from core.enums import Instruments from core.utils import resolve, spacify, numifyBool from core import config +from core.output_file_handler import OutputHandler SUFFIX = ".exe" if os.name == "nt" else "" @@ -35,9 +37,13 @@ class PurgeFile(): purge() Writes out the file, and then calls purge_det on that file. """ + def __init__( self, - gudrunFile + gudrunFile, + standardDeviation=(10, 10), + ignoreBad=True, + excludeSampleAndCan=True, ): """ Constructs all the necessary attributes for the PurgeFile object. @@ -48,9 +54,9 @@ def __init__( Parent GudrunFile that we are creating the PurgeFile from. """ self.gudrunFile = gudrunFile - self.excludeSampleAndCan = True - self.standardDeviation = (10, 10) - self.ignoreBad = True + self.excludeSampleAndCan = excludeSampleAndCan + self.standardDeviation = standardDeviation + self.ignoreBad = ignoreBad def write_out(self, path=""): """ @@ -247,19 +253,22 @@ def purge( self.ignoreBad = ignoreBad self.excludeSampleAndCan = excludeSampleAndCan if headless: - try: - cwd = os.getcwd() + with tempfile.TemporaryDirectory() as tmp: + self.gudrunFile.setGudrunDir(tmp) purge_det = resolve("bin", f"purge_det{SUFFIX}") - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.write_out() + self.write_out(os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + "purge_det.dat" + )) result = subprocess.run( [purge_det, "purge_det.dat"], + cwd=tmp, capture_output=True, text=True ) - os.chdir(cwd) - except FileNotFoundError: - return False + self.organiseOutput() + self.gudrunFile.setGudrunDir( + self.gudrunFile.projectDir) return result else: if hasattr(sys, '_MEIPASS'): @@ -280,8 +289,13 @@ def purge( self.write_out, [ os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, + self.gudrunFile.projectDir, + "Purge", "purge_det.dat" ) ] ) + + def organiseOutput(self): + outputHandler = OutputHandler(self.gudrunFile, "Purge") + outputHandler.organiseOutput() diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index cb4294d1..367d5584 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -3,9 +3,7 @@ import sys import math import traceback -import tempfile from queue import Queue -from collections.abc import Sequence import re from PySide6.QtCore import ( QFile, @@ -26,7 +24,6 @@ QMainWindow, QMessageBox, QProgressBar, - QPushButton, QSizePolicy, QStatusBar, QWidget, @@ -37,6 +34,7 @@ from core.container import Container from core.iterators.composition import CompositionIterator +from core.iterators.inelasticity_subtraction import InelasticitySubtraction from core.sample import Sample from gui.widgets.dialogs.export_dialog import ExportDialog @@ -97,7 +95,11 @@ from core.run_individual_files import RunIndividualFiles from core.gud_file import GudFile from core.utils import breplace, nthint -from gui.widgets.core.worker import CompositionWorker +from gui.widgets.core.worker import ( + CompositionWorker, + GudrunWorker, + PurgeWorker +) class GudPyMainWindow(QMainWindow): @@ -356,8 +358,12 @@ def initComponents(self): self.sampleSlots = SampleSlots(self.mainWidget, self) self.containerSlots = ContainerSlots(self.mainWidget, self) self.outputSlots = OutputSlots(self.mainWidget, self) - self.mainWidget.runPurge.triggered.connect(self.runPurge_) - self.mainWidget.runGudrun.triggered.connect(self.runGudrun_) + self.mainWidget.runPurge.triggered.connect( + lambda: self.runPurge_(self.gudrunFile, dialog=True) + ) + self.mainWidget.runGudrun.triggered.connect( + lambda: self.runGudrun(self.gudrunFile, self.procFinished) + ) self.mainWidget.iterateInelasticitySubtractions.triggered.connect( lambda: self.iterateGudrun( @@ -407,7 +413,7 @@ def initComponents(self): self.mainWidget.batchProcessing.triggered.connect(self.batchProcessing) self.mainWidget.checkFilesExist.triggered.connect( - self.checkFilesExist_ + lambda: self.checkFilesExist_(True) ) self.mainWidget.save.triggered.connect(self.saveInputFile) @@ -506,7 +512,7 @@ def tryLoadAutosaved(self, path): messageBox.addButton(QMessageBox.No) messageBox.addButton(QMessageBox.Yes) result = messageBox.exec() - if result == messageBox.Yes: + if result == QMessageBox.Yes: return os.path.abspath(f) else: return path @@ -573,9 +579,11 @@ def loadInputFile_(self): ".", f"{list(filters.keys())[0]};;" + f"{list(filters.keys())[1]};;" + - f"{list(filters.keys())[2]};;" + f"{list(filters.keys())[2]}" ) if filename: + if not filter: + filter = "YAML (*.yaml)" fmt = filters[filter] try: if self.gudrunFile: @@ -583,7 +591,8 @@ def loadInputFile_(self): path = self.tryLoadAutosaved(filename) self.gudrunFile = GudrunFile(path=path, format=fmt) self.updateWidgets() - self.mainWidget.setWindowTitle(self.gudrunFile.path + " [*]") + self.mainWidget.setWindowTitle( + f"GudPy - {self.gudrunFile.filename}[*]") except ParserException as e: QMessageBox.critical(self.mainWidget, "GudPy Error", str(e)) except IOError: @@ -627,19 +636,19 @@ def saveInputFileAs(self): os.path.abspath(filename) ) self.gudrunFile.path = filename - self.gudrunFile.save(path=filename, format=fmt) - self.setUnModified() + self.gudrunFile.save(path=filename, format=fmt) + self.setUnModified() def newInputFile(self): if self.gudrunFile: self.gudrunFile = None - self.gudrunFile = GudrunFile() configurationDialog = ConfigurationDialog(self) result = configurationDialog.widget.exec() if not configurationDialog.cancelled and result: - self.gudrunFile.instrument = GudrunFile( - configurationDialog.configuration, config_=True - ).instrument + self.gudrunFile = GudrunFile( + configurationDialog.configuration, format=Format.TXT, + config_=True + ) self.gudrunFile.instrument.dataFileType = ( configurationDialog.dataFileType ) @@ -910,6 +919,83 @@ def exit_(self): self.gudrunFile.write_out(overwrite=True) sys.exit(0) + def checkFilesExist_(self, showSuccessDialog: bool = False): + result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() + if not all(r[0] for r in result[0]) or not all(r[0] + for r in result[1]): + undefined = [ + r[1] for r in result[0] if not r[0] + ] + unresolved = [r[2] for r in result[1] if not r[0] and r[2]] + missingFilesDialog = MissingFilesDialog( + undefined, unresolved, self.mainWidget + ) + missingFilesDialog.widget.exec_() + return False + + if showSuccessDialog: + QMessageBox.information( + self.mainWidget, + "GudPy Information", + "All files found!", + ) + return True + + def prepareRun(self): + if not self.checkFilesExist_(): + return False + + if not self.gudrunFile.checkSaveLocation(): + dirname = QFileDialog.getSaveFileName( + self.mainWidget, + "Choose save location", + ) + self.gudrunFile.setSaveLocation(dirname) + + self.setControlsEnabled(False) + self.mainWidget.progressBar.setValue(0) + return True + + def cleanupRun(self): + self.setControlsEnabled(True) + self.mainWidget.progressBar.setValue(0) + self.mainWidget.currentTaskLabel.setText("No task running.") + self.queue = Queue() + + def checkPurge(self): + if not self.gudrunFile.purged and os.path.exists( + os.path.join( + self.gudrunFile.projectDir, "Purge", "purge_det.dat" + ) + ): + purgeResult = self.purgeOptionsMessageBox( + "purge_det.dat found, but wasn't run in this session. " + "Run Purge?", + ) + elif not self.gudrunFile.purged: + purgeResult = self.purgeOptionsMessageBox( + "It looks like you may not have purged detectors. Run Purge?", + ) + else: + purgeResult = True + + return purgeResult + + def runGudrun(self, gudrunFile, finished, iterator=None): + if not self.prepareRun() or not self.checkPurge(): + return False + + self.worker = GudrunWorker(gudrunFile, iterator) + self.workerThread = QThread() + self.worker.moveToThread(self.workerThread) + self.workerThread.started.connect(self.worker.gudrun) + self.worker.started.connect(self.procStarted) + self.worker.outputChanged.connect(self.progressDCS) + self.worker.finished.connect(self.workerThread.quit) + self.worker.finished.connect(finished) + self.worker.finished.connect(self.cleanupRun) + self.workerThread.start() + def makeProc( self, cmd, @@ -927,8 +1013,6 @@ def makeProc( if not dir_: dir_ = self.gudrunFile.instrument.GudrunInputFileDir - dir_ = self.tmp.name - self.proc = cmd self.proc.readyReadStandardOutput.connect(slot) self.proc.started.connect(started) @@ -938,269 +1022,46 @@ def makeProc( func(*args) self.proc.start() - def prepareRun(self): - if not self.checkFilesExist_(): - return - self.setControlsEnabled(False) - - self.tmp = tempfile.TemporaryDirectory() - self.gudrunFile.setGudrunDir(self.tmp.name) - - def cleanupRun(self): - self.tmp.cleanup() - self.tmp = None - - self.setControlsEnabled(True) - self.mainWidget.progressBar.setValue(0) - self.mainWidget.currentTaskLabel.setText("No task running.") - self.queue = Queue() - - def runPurge_(self): - self.prepareRun() - - purgeDialog = PurgeDialog(self.gudrunFile, self) - result = purgeDialog.widget.exec_() - purge = purgeDialog.purge_det - if isinstance(purge, Sequence): - purge, func, args = purge - if purgeDialog.cancelled or result == QDialogButtonBox.No: - self.setControlsEnabled(True) - self.queue = Queue() - elif isinstance(purge, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find purge_det binary.", - ) - self.setControlsEnabled(True) - elif not purge: - self.setControlsEnabled(True) - else: - os.chdir(self.gudrunFile.instrument.GudrunInputFileDir) - self.gudrunFile.purgeFile.write_out() - self.makeProc(purge, self.progressPurge, func=func, args=args) - - def runGudrun_(self): - self.prepareRun() - - dcs = self.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - elif not self.gudrunFile.purged and os.path.exists( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" - ) - ): - self.purgeOptionsMessageBox( - dcs, - self.runGudrunFinished, - func, - args, - "purge_det.dat found, but wasn't run in this session. " - "Continue?", - ) - elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - self.runGudrunFinished, - func, - args, - "It looks like you may not have purged detectors. Continue?", - ) - else: - self.makeProc( - dcs, - self.progressDCS, - func=func, - args=args, - finished=self.runGudrunFinished, - ) - def runContainersAsSamples(self): - self.prepareRun() + if not self.prepareRun(): + return False runContainersAsSamples = RunContainersAsSamples(self.gudrunFile) - dcs = runContainersAsSamples.runContainersAsSamples( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) + runContainersAsSamples.convertContainers() - def finished(ec, es): - self.runGudrunFinished( - gudrunFile=runContainersAsSamples.gudrunFile - ) - - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - elif not self.gudrunFile.purged and os.path.exists( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" - ) - ): - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "purge_det.dat found, but wasn't run in this session. " - "Continue?", - ) - elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "It looks like you may not have purged detectors. Continue?", - ) - else: - self.makeProc( - dcs, self.progressDCS, finished=finished, func=func, args=args - ) + self.runGudrun( + runContainersAsSamples.gudrunFile, + self.procFinished) def runFilesIndividually(self): - self.prepareRun() + if not self.prepareRun(): + return False runIndividualFiles = RunIndividualFiles(self.gudrunFile) - dcs = runIndividualFiles.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - def finished(ec, es): - self.runGudrunFinished(gudrunFile=runIndividualFiles.gudrunFile) + self.runGudrun( + runIndividualFiles.gudrunFile, + self.procFinished) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - if isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - elif not self.gudrunFile.purged and os.path.exists( - os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, "purge_det.dat" - ) - ): - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "purge_det.dat found, but wasn't run in this session. " - "Continue?", - ) - elif not self.gudrunFile.purged: - self.purgeOptionsMessageBox( - dcs, - finished, - func, - args, - "It looks like you may not have purged detectors. Continue?", - ) - else: - self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished - ) - - def purgeOptionsMessageBox(self, dcs, finished, func, args, text): + def purgeOptionsMessageBox(self, text): messageBox = QMessageBox(self.mainWidget) messageBox.setWindowTitle("GudPy Warning") messageBox.setText(text) + messageBox.addButton(QMessageBox.Yes) messageBox.addButton(QMessageBox.No) - openPurgeDialog = QPushButton("Open purge dialog", messageBox) - purgeDefault = QPushButton("Purge with default parameters", messageBox) - - messageBox.addButton(openPurgeDialog, QMessageBox.ApplyRole) - messageBox.addButton(purgeDefault, QMessageBox.ApplyRole) - + messageBox.addButton(QMessageBox.Cancel) messageBox.addButton(QMessageBox.Yes) result = messageBox.exec() - if messageBox.clickedButton() == openPurgeDialog: - self.purgeBeforeRunning(default=False) - elif messageBox.clickedButton() == purgeDefault: - self.purgeBeforeRunning() - elif result == QMessageBox.Yes: - self.makeProc( - dcs, self.progressDCS, - func=func, args=args, - finished=finished - ) - else: - messageBox.close() - self.setControlsEnabled(True) - - def purgeBeforeRunning(self, default=True): - self.setControlsEnabled(False) - if default: - purge_det = self.gudrunFile.purge(headless=False) - if isinstance(purge_det, Sequence): - purge, func, args = purge_det - self.makeProc(purge, self.progressPurge, func=func, args=args) - elif isinstance(purge_det, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find purge_det binary.", - ) - self.setControlsEnabled(True) - return + if result == QMessageBox.Yes: + # Run Purge and queue Gudrun after + self.runPurge_(dialog=True, finished=lambda: self.runGudrun( + self.gudrunFile, self.procFinished + )) + return False + elif result == QMessageBox.No: + return True else: - self.runPurge_() - dcs = self.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - self.gudrunFile.outpath, - ), - headless=False, - ) - if isinstance(dcs, Sequence): - dcs, func, args = dcs - elif isinstance(dcs, FileNotFoundError): - QMessageBox.critical( - self.mainWidget, - "GudPy Error", - "Couldn't find gudrun_dcs binary.", - ) - self.setControlsEnabled(True) - return - self.queue.put( - ( - (dcs, self.progressDCS), - { - "func": func, - "args": args, - "finished": self.runGudrunFinished, - }, - ) - ) + return False def nexusProcessing(self): if not self.checkFilesExist_(): @@ -1336,6 +1197,8 @@ def processPulseFinished(self): def nexusProcessingFinished(self): self.cleanupRun() + self.worker = None + self.workerThread = None self.proc = None self.outputSlots.setOutput( self.nexusProcessingOutput, @@ -1346,7 +1209,8 @@ def nexusProcessingFinished(self): self.gudrunFile.nexus_processing.tmp.cleanup() def batchProcessing(self): - self.prepareRun() + if not self.prepareRun(): + return False batchProcessingDialog = BatchProcessingDialog( self.gudrunFile, self.mainWidget ) @@ -1364,7 +1228,7 @@ def batchProcessing(self): self.mainWidget.stopTaskButton.setEnabled(True) self.nextBatchProcess() - def batchProcessFinished(self, ec, es): + def batchProcessFinished(self): self.outputBatches[self.currentIteration + 1] = self.output self.output = "" self.currentIteration += 1 @@ -1418,7 +1282,7 @@ def progressBatchProcess(self): progress if progress <= 100 else 100 ) - def batchProcessingFinished(self): + def batchProcessingFinished(self, ec, es): self.setControlsEnabled(True) self.queue = Queue() self.proc = None @@ -1437,8 +1301,10 @@ def batchProcessingFinished(self): def finishedCompositionIteration(self, originalSample, updatedSample): self.compositionMap[originalSample] = updatedSample self.mainWidget.progressBar.setValue( - int((self.currentIteration / self.totalIterations) * 100) + int((self.iterator.nCurrent / self.iterator.nTotal) * 100) ) + self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() + self.cleanupRun() if not self.queue.empty(): self.nextCompositionIteration() else: @@ -1453,7 +1319,6 @@ def finishedCompositionIterations(self): original.composition = new.composition if self.sampleSlots.sample == original: self.sampleSlots.setSample(original) - self.cleanupRun() def startedCompositionIteration(self, sample): self.mainWidget.currentTaskLabel.setText( @@ -1473,12 +1338,13 @@ def errorCompositionIteration(self, output): ) def progressCompositionIteration(self, currentIteration): - progress = ( - self.iterator.nCurrent / self.iterator.nTotal - ) * (self.iterator.nCurrent / self.totalIterations) + self.iterator.nCurrent += 1 + progress = (self.iterator.nCurrent / self.iterator.nTotal) self.mainWidget.progressBar.setValue(int(progress * 100)) def nextCompositionIteration(self): + if not self.prepareRun(): + return False args, kwargs, sample = self.queue.get() self.worker = CompositionWorker(args, kwargs, sample, self.gudrunFile) self.worker.started.connect(self.startedCompositionIteration) @@ -1491,8 +1357,6 @@ def nextCompositionIteration(self): self.worker.errorOccured.connect(self.errorCompositionIteration) self.worker.errorOccured.connect(self.workerThread.quit) self.worker.finished.connect(self.finishedCompositionIteration) - self.gudrunFile.organiseOutput() - self.currentIteration += 1 def iterateByComposition(self): if not self.iterator.components: @@ -1509,23 +1373,6 @@ def iterateByComposition(self): self.setControlsEnabled(True) else: self.compositionMap = {} - self.totalIterations = len( - [ - s - for sb in self.gudrunFile.sampleBackgrounds - for s in sb.samples - if s.runThisSample - and len( - [ - wc - for c in self.iterator.components - for wc in s.composition.weightedComponents - if wc.component.eq(c) - ] - ) - ] - ) - self.iterator.nTotal = self.totalIterations self.nextCompositionIteration() def iterateGudrun(self, dialog, name): @@ -1541,7 +1388,6 @@ def iterateGudrun(self, dialog, name): name : str Name of dialog """ - self.prepareRun() iterationDialog = dialog(name, self.gudrunFile, self.mainWidget) iterationDialog.widget.exec() if not iterationDialog.iterator: @@ -1553,16 +1399,17 @@ def iterateGudrun(self, dialog, name): self.text = iterationDialog.text self.outputIterations = {} if isinstance(self.iterator, CompositionIterator): + self.iterator.nTotal = iterationDialog.numberIterations self.iterateByComposition() else: self.nextIterableProc() self.mainWidget.stopTaskButton.setEnabled(True) def nextIteration(self): + self.cleanupRun if self.error: self.procFinished(9, QProcess.NormalExit) return - self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() if self.iterator.nCurrent != -1: # If this is not the default run self.outputIterations[ @@ -1581,6 +1428,8 @@ def nextIteration(self): self.output = "" def nextIterableProc(self): + if not self.prepareRun(): + return False if self.queue.empty(): return iterInfo = f" {self.iterator.nCurrent + 1}/{self.iterator.nTotal}" if ( @@ -1590,16 +1439,16 @@ def nextIterableProc(self): self.mainWidget.currentTaskLabel.setText(f"{self.text} {iterInfo}") self.previousProcTitle = self.mainWidget.currentTaskLabel.text() self.iterator.performIteration() - self.iterator.gudrunFile.write_out() - self.proc, func, args = self.queue.get() - self.proc.finished.connect(self.nextIteration) - self.proc.readyReadStandardOutput.connect(self.progressIteration) - self.proc.setWorkingDirectory( - self.iterator.gudrunFile.instrument.GudrunInputFileDir + self.runGudrun(self.iterator.gudrunFile, + self.nextIteration, self.iterator) + + def iterationStarted(self): + self.mainWidget.currentTaskLabel.setText( + f"{self.text}" + f" {(self.numberIterations + 1) - self.queue.qsize()}" + + f"/{self.numberIterations + 1}" ) - if func: - func(*args) - self.proc.start() + self.previousProcTitle = self.mainWidget.currentTaskLabel.text() def progressIteration(self): progress = self.progressIncrementDCS(self.gudrunFile) @@ -1609,27 +1458,12 @@ def progressIteration(self): f" from gudrun_dcs\n{self.error}" ) return - progress /= self.iterator.nTotal + progress /= self.numberIterations progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( progress if progress <= 100 else 100 ) - def checkFilesExist_(self): - result = GudPyFileLibrary(self.gudrunFile).checkFilesExist() - if not all(r[0] for r in result[0]) or not all(r[0] - for r in result[1]): - undefined = [ - r[1] for r in result[0] if not r[0] - ] - unresolved = [r[2] for r in result[1] if not r[0] and r[2]] - missingFilesDialog = MissingFilesDialog( - undefined, unresolved, self.mainWidget - ) - missingFilesDialog.widget.exec_() - return False - return True - def autosave(self): if ( self.gudrunFile @@ -1637,7 +1471,9 @@ def autosave(self): and not self.proc and not self.workerThread ): - autosavePath = self.gudrunFile.path + ".autosave" + autosavePath = os.path.join( + self.gudrunFile.inputFileDir, + self.gudrunFile.filename + ".autosave") self.gudrunFile.write_out(path=autosavePath) def setModified(self): @@ -1733,14 +1569,14 @@ def setTreeActionsEnabled(self, state): self.mainWidget.paste.setEnabled(state) self.mainWidget.delete_.setEnabled(state) - def progressIncrementDCS(self, gudrunFile=None): + def progressIncrementDCS(self, gudrunFile=None, stdout=""): if not gudrunFile: gudrunFile = self.gudrunFile - if not self.proc: - return 0 - data = self.proc.readAllStandardOutput() - stdout = bytes(data).decode("utf8") - self.output += stdout + if stdout: + self.output += stdout + self.outputSlots.setOutputStream( + stdout + ) ERROR_KWDS = ["does not exist", "error", "Error"] if [KWD for KWD in ERROR_KWDS if KWD in stdout]: self.error = stdout @@ -1785,8 +1621,8 @@ def progressIncrementDCS(self, gudrunFile=None): ) return progress - def progressDCS(self): - progress = self.progressIncrementDCS(self.gudrunFile) + def progressDCS(self, stdout): + progress = self.progressIncrementDCS(self.gudrunFile, stdout) if progress == -1: self.queue = Queue() self.error = ( @@ -1794,20 +1630,52 @@ def progressDCS(self): f" from gudrun_dcs\n{self.error}" ) return + if isinstance(self.iterator, InelasticitySubtraction): + progress /= 2 progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( progress if progress <= 100 else 100 ) - def progressIncrementPurge(self): - if not self.proc: - return 0 - data = self.proc.readAllStandardOutput() - stdout = bytes(data).decode("utf8") - self.output += stdout + def runPurge_(self, finished=None, dialog=False) -> bool: + if dialog: + self.setControlsEnabled(False) + purgeDialog = PurgeDialog(self.gudrunFile, self) + result = purgeDialog.widget.exec_() + + if (purgeDialog.cancelled or result == QDialogButtonBox.No): + self.setControlsEnabled(True) + self.queue = Queue() + return False + + if not self.prepareRun(): + return False + + self.worker = PurgeWorker(self.gudrunFile) + self.workerThread = QThread() + self.worker.moveToThread(self.workerThread) + self.workerThread.started.connect(self.worker.purge) + self.worker.started.connect(self.procStarted) + self.worker.outputChanged.connect(self.progressPurge) + self.worker.finished.connect(self.cleanupRun) + self.worker.finished.connect(self.workerThread.quit) + + if finished: + self.worker.finished.connect(finished) + + self.workerThread.start() + + def progressIncrementPurge(self, stdout=""): + if stdout: + self.output += stdout + self.outputSlots.setOutputStream( + stdout + ) dataFiles = [self.gudrunFile.instrument.groupFileName] def appendDfs(dfs): + if isinstance(dfs, str): + dfs = [dfs] for df in dfs: dataFiles.append( df.replace(self.gudrunFile.instrument.dataFileType, "grp") @@ -1872,14 +1740,15 @@ def appendDfs(dfs): else: return progress, False, -1 - def progressPurge(self): - progress, finished, detectors = self.progressIncrementPurge() + def progressPurge(self, stdout): + progress, finished, detectors = self.progressIncrementPurge(stdout) if progress == -1: self.error = ( f"An error occurred. See the following traceback" f" from purge_det\n{self.error}" ) self.gudrunFile.purged = False + self.cleanupRun() return progress += self.mainWidget.progressBar.value() self.mainWidget.progressBar.setValue( @@ -1887,6 +1756,7 @@ def progressPurge(self): ) if finished: + self.gudrunFile.purged = True thresh = self.gudrunFile.instrument.goodDetectorThreshold if thresh and detectors < thresh: self.warning = ( @@ -1897,23 +1767,17 @@ def progressPurge(self): self.mainWidget.goodDetectorsLabel.setText( f"Number of Good Detectors: {detectors}" ) + self.cleanupRun() def procStarted(self): self.mainWidget.currentTaskLabel.setText( - self.proc.program().split(os.path.sep)[-1] + self.worker.PROCESS ) self.mainWidget.stopTaskButton.setEnabled(True) self.previousProcTitle = self.mainWidget.currentTaskLabel.text() self.output = "" - def runGudrunFinished(self, ec, es, gudrunFile=None): - if gudrunFile: - gudrunFile.organiseOutput() - else: - self.gudrunFile.organiseOutput() - self.procFinished(ec, es) - - def procFinished(self, ec, es): + def procFinished(self): self.proc = None output = self.output if self.iterator: diff --git a/gudpy/gui/widgets/core/output_tree.py b/gudpy/gui/widgets/core/output_tree.py index 5778908e..9804a11d 100644 --- a/gudpy/gui/widgets/core/output_tree.py +++ b/gudpy/gui/widgets/core/output_tree.py @@ -186,7 +186,7 @@ def data(self, index, role=Qt.DisplayRole): class OutputTreeView(QTreeView): def __init__(self, parent): - super(OutputTreeView, self).__init__(parent) + super().__init__(parent) def buildTree(self, gudrunFile, output, parent, keyMap=None): self.gudrunFile = gudrunFile diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index b14dfa5a..e76cc2f2 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -1,11 +1,128 @@ import os +import tempfile from copy import deepcopy from PySide6.QtCore import QObject, Signal, QThread +import subprocess +import sys +from core import config from core.gud_file import GudFile +import core.utils as utils from core.sample import Sample from core.iterators.composition import gss +SUFFIX = ".exe" if os.name == "nt" else "" + + +class PurgeWorker(QObject): + started = Signal(int) + errorOccured = Signal(str) + outputChanged = Signal(str) + finished = Signal(int) + + def __init__(self, gudrunFile): + super().__init__() + self.gudrunFile = gudrunFile + self.PROCESS = "purge_det" + + def purge(self): + self.started.emit(1) + + if hasattr(sys, '_MEIPASS'): + purge_det = os.path.join(sys._MEIPASS, f"{self.PROCESS}{SUFFIX}") + else: + purge_det = utils.resolve( + os.path.join( + config.__rootdir__, "bin" + ), f"{self.PROCESS}{SUFFIX}" + ) + if not os.path.exists(purge_det): + self.errorOccured.emit("MISSING_BINARY") + return + + with tempfile.TemporaryDirectory() as tmp: + self.gudrunFile.setGudrunDir(tmp) + self.gudrunFile.purgeFile.write_out(os.path.join( + self.gudrunFile.instrument.GudrunInputFileDir, + f"{self.PROCESS}.dat" + )) + + with subprocess.Popen( + [purge_det, f"{self.PROCESS}.dat"], cwd=tmp, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) as purge: + for line in purge.stdout: + self.outputChanged.emit(line.decode("utf8").rstrip("\n")) + if purge.stderr: + self.errorOccured.emit( + purge.stderr.decode("utf8").rstrip("\n")) + return + + self.gudrunFile.purgeFile.organiseOutput() + + self.gudrunFile.setGudrunDir( + self.gudrunFile.projectDir) + + self.finished.emit(1) + + +class GudrunWorker(QObject): + started = Signal(int) + outputChanged = Signal(str) + nextIteration = Signal(int) + errorOccured = Signal(str) + finished = Signal(int) + + def __init__(self, gudrunFile, iterator): + super().__init__() + self.gudrunFile = gudrunFile + self.iterator = iterator + self.PROCESS = "gudrun_dcs" + + def gudrun(self): + self.started.emit(1) + + if hasattr(sys, '_MEIPASS'): + gudrun_dcs = os.path.join(sys._MEIPASS, f"{self.PROCESS}{SUFFIX}") + else: + gudrun_dcs = utils.resolve( + os.path.join( + config.__rootdir__, "bin" + ), f"{self.PROCESS}{SUFFIX}" + ) + if not os.path.exists(gudrun_dcs): + self.errorOccured.emit("MISSING_BINARY") + return + + with tempfile.TemporaryDirectory() as tmp: + path = self.gudrunFile.outpath + self.gudrunFile.setGudrunDir(tmp) + path = os.path.join( + tmp, + path + ) + self.gudrunFile.write_out(path) + with subprocess.Popen( + [gudrun_dcs, path], cwd=tmp, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT + ) as gudrun: + for line in gudrun.stdout: + self.outputChanged.emit(line.decode("utf8").rstrip("\n")) + if gudrun.stderr: + self.errorOccured.emit( + gudrun.stderr.decode("utf8").rstrip("\n")) + return + + if self.iterator is not None: + self.gudrunFile.gudrunOutput = self.iterator.organiseOutput() + else: + self.gudrunFile.gudrunOutput = self.gudrunFile.organiseOutput() + self.gudrunFile.setGudrunDir(self.gudrunFile.gudrunOutput.path) + + self.finished.emit(1) + class CompositionWorker(QObject): finished = Signal(Sample, Sample) @@ -19,7 +136,6 @@ def __init__(self, args, kwargs, sample, gudrunFile): self.sample = sample self.updatedSample = None self.errored = False - self.currentIteration = 0 self.gudrunFile = gudrunFile super(CompositionWorker, self).__init__() diff --git a/gudpy/gui/widgets/dialogs/iteration_dialog.py b/gudpy/gui/widgets/dialogs/iteration_dialog.py index acb49e7b..c5036713 100644 --- a/gudpy/gui/widgets/dialogs/iteration_dialog.py +++ b/gudpy/gui/widgets/dialogs/iteration_dialog.py @@ -71,11 +71,7 @@ def enqueueTasks(self): self.queue = Queue() for _ in range(self.numberIterations + 1): self.queue.put( - self.iterator.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "gudpy.txt" - ), headless=False) + self.iterator.gudrunFile.dcs(headless=False) ) @@ -104,11 +100,7 @@ def enqueueTasks(self): self.queue = Queue() for _ in range((self.numberIterations * 2)): self.queue.put( - self.iterator.gudrunFile.dcs( - path=os.path.join( - self.gudrunFile.instrument.GudrunInputFileDir, - "gudpy.txt" - ), headless=False) + self.iterator.gudrunFile.dcs(headless=False) ) @@ -250,7 +242,7 @@ def initComponents(self): self.widget.iterateButton.setEnabled(False) def iterate(self): - self.iterator = CompositionIterator(self.gudrunFile, 10) + self.iterator = CompositionIterator(self.gudrunFile) self.iterator.setComponents(self.components) self.queue = Queue() for sampleBackground in self.gudrunFile.sampleBackgrounds: diff --git a/gudpy/gui/widgets/dialogs/purge_dialog.py b/gudpy/gui/widgets/dialogs/purge_dialog.py index 5933e1e1..01c7cc79 100644 --- a/gudpy/gui/widgets/dialogs/purge_dialog.py +++ b/gudpy/gui/widgets/dialogs/purge_dialog.py @@ -4,6 +4,8 @@ from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QDialog +from core.purge_file import PurgeFile + class PurgeDialog(QDialog): """ @@ -21,6 +23,7 @@ class PurgeDialog(QDialog): initComponents() Loads the UI file for the IterationDialog """ + def __init__(self, gudrunFile, parent): super(PurgeDialog, self).__init__(parent=parent) self.gudrunFile = gudrunFile @@ -38,12 +41,13 @@ def purge(self): Purge with the specified configuration. Called when an accepted signal is emmited from the buttonBox. """ - self.purge_det = self.gudrunFile.purge( - headless=False, - standardDeviation=( - self.stdDeviationsAcceptanceOffset, - self.stdsAroundMeanDeviation - ), + self.gudrunFile.purgeFilestandardDeviation = ( + self.stdDeviationsAcceptanceOffset, + self.stdsAroundMeanDeviation + ) + self.gudrunFile.purgeFile = PurgeFile( + self.gudrunFile, + standardDeviation=self.gudrunFile.purgeFilestandardDeviation, ignoreBad=self.ignoreBad, excludeSampleAndCan=self.excludeSampleAndCan ) diff --git a/gudpy/gui/widgets/slots/output_slots.py b/gudpy/gui/widgets/slots/output_slots.py index 048b8e4c..e437fa7e 100644 --- a/gudpy/gui/widgets/slots/output_slots.py +++ b/gudpy/gui/widgets/slots/output_slots.py @@ -4,6 +4,11 @@ def __init__(self, widget, parent): self.widget = widget self.parent = parent + def setOutputStream(self, stdout): + self.widget.outputTextEdit.append( + stdout + ) + def setOutput(self, output, task, gudrunFile=None, keyMap=None): if not gudrunFile: gudrunFile = self.parent.gudrunFile @@ -12,3 +17,7 @@ def setOutput(self, output, task, gudrunFile=None, keyMap=None): self.widget.outputTree.buildTree( gudrunFile, output, self, keyMap=keyMap ) + self.widget.outputTextEdit.verticalScrollBar().setValue( + self.widget.outputTextEdit.verticalScrollBar( + ).maximum() + ) diff --git a/gudpy/gui/widgets/ui_files/mainWindow.ui b/gudpy/gui/widgets/ui_files/mainWindow.ui index 33ad570d..3ef46884 100644 --- a/gudpy/gui/widgets/ui_files/mainWindow.ui +++ b/gudpy/gui/widgets/ui_files/mainWindow.ui @@ -420,7 +420,7 @@ - NeXus definition file + NeXus Definition File diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index 6da805ae..c4749a46 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -356,18 +356,18 @@ def testLoadGudFileB(self): ) else: try: + float(self.expectedGudFileB[key]) + except ValueError: self.assertEqual( - self.expectedGudFileB[key], gudAttrsDict[key] + self.expectedGudFileB[key], + gudAttrsDict[key] + ) + else: + self.assertAlmostEqual( + float(self.expectedGudFileB[key]), + float(gudAttrsDict[key]), + 1, ) - except AssertionError as e: - try: - self.assertAlmostEqual( - float(self.expectedGudFileB[key]), - float(gudAttrsDict[key]), - 1, - ) - except Exception: - raise e def testLoadGudFileC(self): g = GudrunFile( diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 837bd2ed..82ab9ada 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -757,12 +757,9 @@ def testLoadGudrunFile(self): ) def testWriteGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) with open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, encoding="utf-8" ) as f: outlines = "\n".join(f.readlines()[:-5]) @@ -845,38 +842,45 @@ def valueInLines(value, lines): valueInLines(value, inlines) def testRewriteGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) + copyPath = os.path.join( + self.g.instrument.GudrunInputFileDir, + "copyGF.txt" + ) g1 = GudrunFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir - g1.write_out() + g1.write_out(copyPath, overwrite=True) + + def compareString(string1, string2): + return string1 == string2 with open( - os.path.join( - g1.instrument.GudrunInputFileDir, - g1.outpath - ), + copyPath, + "r", encoding="utf-8" ) as f: + fileContent = "\n".join(f.readlines()[:-5]) self.assertEqual( - "\n".join(f.readlines()[:-5]), - "\n".join(str(self.g).splitlines(keepends=True)[:-5]) + compareString( + fileContent, + "\n".join( + str(self.g).splitlines(keepends=True)[:-5])), + True ) - self.assertEqual( - "\n".join(f.readlines()[:-5]), - "\n".join(str(g1).splitlines(keepends=True)[:-5]) + compareString( + fileContent, + "\n".join( + str(g1).splitlines(keepends=True)[:-5])), + True ) with open( os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath + self.g.path ), encoding="utf-8" ) as fg: @@ -884,18 +888,13 @@ def testRewriteGudrunFile(self): "\n".join( fg.readlines()[:-5] ), - "\n".join( - f.readlines()[:-5] - ) + fileContent ) def testReloadGudrunFile(self): - self.g.write_out() + self.g.write_out(overwrite=True) g1 = GudrunFile( - os.path.join( - self.g.instrument.GudrunInputFileDir, - self.g.outpath - ), + self.g.path, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir @@ -1534,7 +1533,7 @@ def testLoadMissingContainerAttributesRand(self): ) def testZeroExitGudrun(self): - g = GudrunFile("test/TestData/NIMROD-water/good_water.txt", + g = GudrunFile(path="test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) result = g.dcs() - self.assertEqual(result.stderr, "") + self.assertEqual(result.stderr, None) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index dba14957..ac208e11 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -21,15 +21,19 @@ class TestGudPyWorkflows(TestCase): def setUp(self) -> None: - path = os.path.abspath("test/TestData/NIMROD-water/water.txt") + testDir = os.path.dirname(__file__) + path = os.path.join( + testDir, "TestData/NIMROD-water/water.txt") - self.g = GudrunFile(os.path.abspath(path), format=Format.TXT) + self.g = GudrunFile(path, format=Format.TXT) self.keepsakes = os.listdir() - copyfile(self.g.path, "test/TestData/NIMROD-water/good_water.txt") + copyfile(self.g.path, os.path.join( + testDir, "TestData/NIMROD-water/good_water.txt") + ) g = GudrunFile( - os.path.abspath("test/TestData/NIMROD-water/good_water.txt"), + os.path.join(testDir, "TestData/NIMROD-water/good_water.txt"), format=Format.TXT ) @@ -79,17 +83,13 @@ def testGudPyDCS(self): for sample in self.g.sampleBackgrounds[0].samples: mintFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "mint01" - ) + os.path.splitext(sample.dataFiles[0])[0] ) - actualMintFile = f'test/TestData/water-ref/plain/{mintFilename}' - - actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, mintFilename - ), + actualMintFile = ("test/TestData/water-ref/plain/" + f"{mintFilename}.mint01") + actualData = open(self.g.gudrunOutput.sampleOutputs[ + sample.name].outputs[sample.dataFiles[0]][".mint01"], "r", encoding="utf-8" ).readlines()[10:] expectedData = open( @@ -294,22 +294,21 @@ def testGudPyIterateBySubtractingWavelength(self): for x in self.g.sampleBackgrounds[0].samples if x.runThisSample ]: - mintFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "mint01" - ) + dataFilename = ( + os.path.splitext(sample.dataFiles[0])[0] ) actualMintFile = ( f'test/TestData/water-ref/wavelength{i}/' - f'{mintFilename}' + f'{dataFilename}.mint01' ) actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - mintFilename - ), "r", encoding="utf-8" + inelasitictyIterator.gudrunOutputs[ + len(inelasitictyIterator.gudrunOutputs) - 1 + ].output( + sample.name, sample.dataFiles[0], ".mint01"), + "r", encoding="utf-8" ).readlines()[10:] expectedData = open( actualMintFile, "r", encoding="utf-8" @@ -330,21 +329,17 @@ def testGudPyIterateBySubtractingWavelength(self): close += 1 self.assertTrue((close / total) >= 0.95) - msubFilename = ( - sample.dataFiles[0].replace( - self.g.instrument.dataFileType, "msubw01" - ) - ) - actualMsubFilename = ( - f'test/TestData/water-ref/wavelength{i}/{msubFilename}' + f'test/TestData/water-ref/wavelength{i}/' + f'{dataFilename}.msubw01' ) actualData = open( - os.path.join( - self.g.instrument.GudrunInputFileDir, - msubFilename - ), "r", encoding="utf-8" + inelasitictyIterator.gudrunOutputs[ + len(inelasitictyIterator.gudrunOutputs) - 2 + ].output( + sample.name, sample.dataFiles[0], ".msubw01"), + "r", encoding="utf-8" ).readlines()[10:] expectedData = open( actualMsubFilename, "r", encoding="utf-8" diff --git a/gudpy/test/test_utils.py b/gudpy/test/test_utils.py index 2fba74cf..6cd1705f 100644 --- a/gudpy/test/test_utils.py +++ b/gudpy/test/test_utils.py @@ -1,13 +1,11 @@ from unittest import TestCase - - from core.utils import ( - iteristype, - firstword, boolifyNum, - numifyBool, spacify, - extract_ints_from_string, - extract_floats_from_string, - count_occurrences) + iteristype, + firstword, boolifyNum, + numifyBool, spacify, + extract_ints_from_string, + extract_floats_from_string, + count_occurrences) class TestUtils(TestCase): diff --git a/requirements.txt b/requirements.txt index f875af7e..a1536c20 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -PySide6==6.2.0 +PySide6==6.6.0 chardet ruamel.yaml h5py \ No newline at end of file diff --git a/scripts/setup-idaaas-dev.sh b/scripts/setup-idaaas-dev.sh index a1897394..c82f080e 100755 --- a/scripts/setup-idaaas-dev.sh +++ b/scripts/setup-idaaas-dev.sh @@ -10,6 +10,9 @@ git clone https://github.com/disorderedmaterials/GudPy git clone https://github.com/disorderedmaterials/ModEx git clone https://github.com/disorderedmaterials/Gudrun +# Install some extra RPM stuff (otherwise the HDF5 FC will fail as it seems to need it) +sudo dnf install redhat-rpm-config + # Upgrade compiler sudo yum install -y gcc-toolset-10 @@ -30,6 +33,9 @@ sudo ln -s /usr/lib64/libxcb-util.so.1 /usr/lib64/libxcb-render-util.so.0 # Fix broken gcc sudo ln -s /opt/rh/gcc-toolset-10/root/usr/lib/gcc/x86_64-redhat-linux/10/plugin/annobin.so /opt/rh/gcc-toolset-10/root/usr/lib/gcc/x86_64-redhat-linux/10/plugin/gcc-annobin.so +# Install missing xcb lib +sudo dnf install xcb-util-cursor.x86_64 + # Upgrade Python sudo dnf module -y install python39 sudo alternatives --set python3 /usr/bin/python3.9 From 3051a21188ee7eb490bd6c3542538a7edae8161e Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 12 Jan 2024 12:12:22 +0000 Subject: [PATCH 123/165] Fix purge and bugs --- gudpy/core/gudrun_file.py | 51 ++++++++++++++------------- gudpy/gui/widgets/core/main_window.py | 18 +++++++--- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 6b861b55..11bd1a7b 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -158,29 +158,41 @@ def __init__(self, path=None, format=Format.YAML, config_=False): self.gudrunOutput = None self.path = path + if config_: + self.path = None if self.path: + self.instrument = Instrument() + self.beam = Beam() + self.normalisation = Normalisation() + self.sampleBackgrounds = [] self.inputFileDir = os.path.dirname(path) + self.setGudrunDir(self.inputFileDir) self.filename = os.path.basename(path) self.projectDir = os.path.join( self.inputFileDir, os.path.splitext(self.filename)[0]) - self.instrument = None - self.beam = Beam() - self.normalisation = Normalisation() - self.sampleBackgrounds = [] else: self.instrument = Instrument() self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] - self.parse(config_=config_) + self.parse(path, config_=config_) self.purged = False # Parse the GudrunFile. self.stream = None self.purgeFile = PurgeFile(self) self.nexus_processing = NexusProcessing(self) + def __deepcopy__(self, memo): + result = self.__class__.__new__(self.__class__) + memo[id(self)] = result + for k, v in self.__dict__.items(): + if k == "yaml": + continue + setattr(result, k, deepcopy(v, memo)) + return result + def checkSaveLocation(self): return self.path is not None @@ -190,14 +202,9 @@ def setSaveLocation(self, projectDir): self.filename = os.path.basename(projectDir) self.path = os.path.join(self.projectDir, self.filename) - def __deepcopy__(self, memo): - result = self.__class__.__new__(self.__class__) - memo[id(self)] = result - for k, v in self.__dict__.items(): - if k == "yaml": - continue - setattr(result, k, deepcopy(v, memo)) - return result + def checkNormDataFiles(self): + return (len(self.normalisation.dataFiles) + and len(self.normalisation.dataFilesBg)) def getNextToken(self): """ @@ -288,15 +295,11 @@ def parseInstrument(self): """ try: # Initialise instrument attribute to a new instance of Instrument. - self.instrument = Instrument() self.consumeWhitespace() # For string attributes, # we simply extract the firstword in the line. self.instrument.name = Instruments[firstword(self.getNextToken())] - self.instrument.GudrunInputFileDir = ( - os.path.dirname(os.path.abspath(self.path)) - ) self.consumeTokens(1) self.instrument.dataFileDir = firstword(self.getNextToken()) self.instrument.dataFileType = firstword(self.getNextToken()) @@ -1315,7 +1318,7 @@ def sampleBackgroundHelper(self): line = self.peekNextToken() return sampleBackground - def parse(self, config_=False): + def parse(self, path, config_=False): """ Parse the GudrunFile from its path. Assign objects from the file to the attributes of the class. @@ -1331,14 +1334,14 @@ def parse(self, config_=False): """ self.config = config_ # Ensure only valid files are given. - if not self.path: + if not path: raise ParserException( "Path not supplied. Cannot parse from an empty path!" ) - if not os.path.exists(self.path): + if not os.path.exists(path): raise ParserException( "The path supplied is invalid.\ - Cannot parse from an invalid path" + self.path + Cannot parse from an invalid path" + path ) if self.format == Format.YAML: # YAML Files @@ -1350,7 +1353,7 @@ def parse(self, config_=False): self.normalisation, self.sampleBackgrounds, config.GUI - ) = self.yaml.parseYaml(self.path) + ) = self.yaml.parseYaml(path) except YAMLException as e: raise ParserException(e) else: @@ -1364,11 +1367,11 @@ def parse(self, config_=False): # Decide the encoding import chardet - with open(self.path, 'rb') as fp: + with open(path, 'rb') as fp: encoding = chardet.detect(fp.read())['encoding'] # Read the input stream into our attribute. - with open(self.path, encoding=encoding) as fp: + with open(path, encoding=encoding) as fp: self.stream = fp.readlines() # Here we go! Get the first token and begin parsing. diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 367d5584..8ea6daad 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -359,7 +359,7 @@ def initComponents(self): self.containerSlots = ContainerSlots(self.mainWidget, self) self.outputSlots = OutputSlots(self.mainWidget, self) self.mainWidget.runPurge.triggered.connect( - lambda: self.runPurge_(self.gudrunFile, dialog=True) + lambda: self.runPurge(self.gudrunFile, dialog=True) ) self.mainWidget.runGudrun.triggered.connect( lambda: self.runGudrun(self.gudrunFile, self.procFinished) @@ -945,8 +945,16 @@ def prepareRun(self): if not self.checkFilesExist_(): return False + if not self.gudrunFile.checkNormDataFiles(): + QMessageBox.warning( + self.mainWidget, + "GudPy Warning", + "Please specify normalisation data files." + ) + return False + if not self.gudrunFile.checkSaveLocation(): - dirname = QFileDialog.getSaveFileName( + dirname, _ = QFileDialog.getSaveFileName( self.mainWidget, "Choose save location", ) @@ -1054,7 +1062,7 @@ def purgeOptionsMessageBox(self, text): if result == QMessageBox.Yes: # Run Purge and queue Gudrun after - self.runPurge_(dialog=True, finished=lambda: self.runGudrun( + self.runPurge(dialog=True, finished=lambda: self.runGudrun( self.gudrunFile, self.procFinished )) return False @@ -1637,7 +1645,7 @@ def progressDCS(self, stdout): progress if progress <= 100 else 100 ) - def runPurge_(self, finished=None, dialog=False) -> bool: + def runPurge(self, finished=None, dialog=False) -> bool: if dialog: self.setControlsEnabled(False) purgeDialog = PurgeDialog(self.gudrunFile, self) @@ -1661,7 +1669,7 @@ def runPurge_(self, finished=None, dialog=False) -> bool: self.worker.finished.connect(self.workerThread.quit) if finished: - self.worker.finished.connect(finished) + self.workerThread.finished.connect(finished) self.workerThread.start() From 0151319d7dcc17a4dcc86045de5bddf0d578c209 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 12 Jan 2024 14:53:42 +0000 Subject: [PATCH 124/165] Output YAML file to project directory --- gudpy/core/gudrun_file.py | 10 ++++++---- gudpy/gui/widgets/core/worker.py | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 11bd1a7b..9a8caf24 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -199,7 +199,7 @@ def checkSaveLocation(self): def setSaveLocation(self, projectDir): self.projectDir = projectDir self.inputFileDir = projectDir - self.filename = os.path.basename(projectDir) + self.filename = f"{os.path.basename(projectDir)}.yaml" self.path = os.path.join(self.projectDir, self.filename) def checkNormDataFiles(self): @@ -1482,16 +1482,18 @@ def __str__(self): def save(self, path='', format=None): + print(f"saving to {path}") + if not path: path = self.path if not format: format = self.format if format == Format.TXT: - self.write_out(path=path.replace( - path.split(".")[-1], "txt"), overwrite=True) + self.write_out( + path=f"{os.path.splitext(path)[0]}.txt", overwrite=True) elif format == Format.YAML: - self.write_yaml(path=path.replace(path.split(".")[-1], "yaml")) + self.write_yaml(path=f"{os.path.splitext(path)[0]}.yaml") def write_yaml(self, path): self.yaml.writeYAML(self, path) diff --git a/gudpy/gui/widgets/core/worker.py b/gudpy/gui/widgets/core/worker.py index e76cc2f2..a6944df4 100644 --- a/gudpy/gui/widgets/core/worker.py +++ b/gudpy/gui/widgets/core/worker.py @@ -9,6 +9,7 @@ from core.gud_file import GudFile import core.utils as utils from core.sample import Sample +from core import enums from core.iterators.composition import gss SUFFIX = ".exe" if os.name == "nt" else "" @@ -102,6 +103,13 @@ def gudrun(self): tmp, path ) + self.gudrunFile.save( + path=os.path.join( + self.gudrunFile.projectDir, + f"{self.gudrunFile.filename}" + ), + format=enums.Format.YAML + ) self.gudrunFile.write_out(path) with subprocess.Popen( [gudrun_dcs, path], cwd=tmp, From 3735a43a1499f1ce4f97af9f5ebe8e6cb5ac3bd9 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Tue, 16 Jan 2024 10:51:19 +0000 Subject: [PATCH 125/165] Update main_window.py --- gudpy/gui/widgets/core/main_window.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 23d31261..367d5584 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1464,7 +1464,6 @@ def progressIteration(self): progress if progress <= 100 else 100 ) - def autosave(self): if ( self.gudrunFile From f02fa0c4853e026cf8005669a650fb1c5b3cd769 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Tue, 16 Jan 2024 15:47:29 +0000 Subject: [PATCH 126/165] Fix export dialog and remove inputfiledir var --- gudpy/core/file_library.py | 6 ++-- gudpy/core/gudrun_file.py | 37 ++++++++++------------ gudpy/gui/widgets/core/main_window.py | 2 +- gudpy/gui/widgets/dialogs/export_dialog.py | 10 ++++-- 4 files changed, 28 insertions(+), 27 deletions(-) diff --git a/gudpy/core/file_library.py b/gudpy/core/file_library.py index 197225c1..8d3af418 100644 --- a/gudpy/core/file_library.py +++ b/gudpy/core/file_library.py @@ -171,14 +171,14 @@ def exportMintData( ): if not exportTo: exportTo = os.path.join( - self.gudrunFile.inputFileDir, + self.gudrunFile.projectDir, Path(self.gudrunFile.path).stem + ".zip", ) with ZipFile(exportTo, "w", ZIP_DEFLATED) as zipFile: for sample in samples: if len(sample.dataFiles.dataFiles): path = os.path.join( - self.gudrunFile.inputFileDir, + self.gudrunFile.projectDir, sample.dataFiles.dataFiles[0].replace( self.gudrunFile.instrument.dataFileType, "mint01" ), @@ -199,7 +199,7 @@ def exportMintData( ) if not os.path.exists(path): sample.write_out( - self.gudrunFile.inputFileDir + self.gudrunFile.projectDir ) zipFile.write(path, arcname=os.path.basename(path)) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 9a8caf24..223dd68c 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -156,33 +156,31 @@ def __init__(self, path=None, format=Format.YAML, config_=False): self.components = Components(components=[]) self.gudrunOutput = None - + self.instrument = Instrument() + self.beam = Beam() + self.normalisation = Normalisation() + self.sampleBackgrounds = [] self.path = path + + self.projectDir = None + self.filename = None + self.purged = False + self.stream = None + self.purgeFile = PurgeFile(self) + self.nexus_processing = NexusProcessing(self) + if config_: self.path = None if self.path: - self.instrument = Instrument() - self.beam = Beam() - self.normalisation = Normalisation() - self.sampleBackgrounds = [] - self.inputFileDir = os.path.dirname(path) - self.setGudrunDir(self.inputFileDir) - self.filename = os.path.basename(path) + self.setGudrunDir(os.path.dirname(path)) self.projectDir = os.path.join( - self.inputFileDir, os.path.splitext(self.filename)[0]) - else: - self.instrument = Instrument() - self.beam = Beam() - self.normalisation = Normalisation() - self.sampleBackgrounds = [] + os.path.dirname(path), + os.path.splitext(os.path.basename(path))[0] + ) + self.setSaveLocation(self.projectDir) self.parse(path, config_=config_) - self.purged = False - # Parse the GudrunFile. - self.stream = None - self.purgeFile = PurgeFile(self) - self.nexus_processing = NexusProcessing(self) def __deepcopy__(self, memo): result = self.__class__.__new__(self.__class__) @@ -198,7 +196,6 @@ def checkSaveLocation(self): def setSaveLocation(self, projectDir): self.projectDir = projectDir - self.inputFileDir = projectDir self.filename = f"{os.path.basename(projectDir)}.yaml" self.path = os.path.join(self.projectDir, self.filename) diff --git a/gudpy/gui/widgets/core/main_window.py b/gudpy/gui/widgets/core/main_window.py index 8ea6daad..b7850259 100644 --- a/gudpy/gui/widgets/core/main_window.py +++ b/gudpy/gui/widgets/core/main_window.py @@ -1480,7 +1480,7 @@ def autosave(self): and not self.workerThread ): autosavePath = os.path.join( - self.gudrunFile.inputFileDir, + self.gudrunFile.projectDir, self.gudrunFile.filename + ".autosave") self.gudrunFile.write_out(path=autosavePath) diff --git a/gudpy/gui/widgets/dialogs/export_dialog.py b/gudpy/gui/widgets/dialogs/export_dialog.py index 4c83f5cb..51435069 100644 --- a/gudpy/gui/widgets/dialogs/export_dialog.py +++ b/gudpy/gui/widgets/dialogs/export_dialog.py @@ -33,12 +33,16 @@ class ExportDialog(QDialog): exportAs() Allows exporting to a specific file. """ + def __init__(self, gudrunFile, parent): super(ExportDialog, self).__init__(parent=parent) self.gudrunFile = gudrunFile self.initComponents() self.loadFilesList() + if not self.gudrunFile.checkSaveLocation(): + self.widget.exportButton.setEnabled(False) + def initComponents(self): """ Loads the UI file for the ExportDialog object. @@ -89,8 +93,8 @@ def loadFilesList(self, rename=False): ) ) namedAfterSample = sample.name.replace(" ", "_").translate( - {ord(x): '' for x in r'/\!*~,&|[]'} - ) + ".mint01" + {ord(x): '' for x in r'/\!*~,&|[]'} + ) + ".mint01" if os.path.exists(os.path.join( self.gudrunFile.instrument.GudrunInputFileDir, mintFile @@ -133,7 +137,7 @@ def exportAs(self): dialog.setDefaultSuffix("zip") dialog.setWindowTitle("Export to..") dialog.setDirectory(".") - dialog.setAcceptMode(dialog.AcceptSave) + dialog.setAcceptMode(QFileDialog.AcceptSave) if dialog.exec() == dialog.Accepted: filename = dialog.selectedFiles()[0] From b0b83b8507aad8f0098153ece9a8fb4584a6333a Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 11:00:49 +0000 Subject: [PATCH 127/165] Create loadFile variable-GudrunFile --- gudpy/core/gudrun_file.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 223dd68c..e4e5037f 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -160,7 +160,8 @@ def __init__(self, path=None, format=Format.YAML, config_=False): self.beam = Beam() self.normalisation = Normalisation() self.sampleBackgrounds = [] - self.path = path + self.loadFile = path + self.path = None self.projectDir = None self.filename = None @@ -169,18 +170,15 @@ def __init__(self, path=None, format=Format.YAML, config_=False): self.purgeFile = PurgeFile(self) self.nexus_processing = NexusProcessing(self) - if config_: - self.path = None - - if self.path: - self.setGudrunDir(os.path.dirname(path)) + if self.loadFile: + self.setGudrunDir(os.path.dirname(self.loadFile)) self.projectDir = os.path.join( - os.path.dirname(path), - os.path.splitext(os.path.basename(path))[0] + os.path.dirname(self.loadFile), + os.path.splitext(os.path.basename(self.loadFile))[0] ) self.setSaveLocation(self.projectDir) - self.parse(path, config_=config_) + self.parse(self.loadFile, config_=config_) def __deepcopy__(self, memo): result = self.__class__.__new__(self.__class__) From 816fd0333a06eda11ea8948c8ba16c9523ec28e9 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 11:02:45 +0000 Subject: [PATCH 128/165] Fix incorrect var name --- gudpy/core/file_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/core/file_library.py b/gudpy/core/file_library.py index 8d3af418..4fd96b0d 100644 --- a/gudpy/core/file_library.py +++ b/gudpy/core/file_library.py @@ -194,7 +194,7 @@ def exportMintData( zipFile.write(path, arcname=os.path.basename(outpath)) if includeParams: path = os.path.join( - self.gudrunFile.inputFileDir, + self.gudrunFile.projectDir, safeSampleName + ".sample", ) if not os.path.exists(path): From c029092d0f034a3216cdf05df8baa5f73ccfdbec Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 11:23:59 +0000 Subject: [PATCH 129/165] Fix tests with new loadFile variable --- gudpy/test/test_gud_file.py | 2 +- gudpy/test/test_gudpy_io.py | 2 +- gudpy/test/test_gudpy_workflows.py | 2 +- gudpy/test/test_purge_file.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index c4749a46..4daa962e 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -235,7 +235,7 @@ def setUp(self) -> None: self.keepsakes = os.listdir() - copyfile(self.g.path, "test/TestData/NIMROD-water/good_water.txt") + copyfile(self.g.loadFile, "test/TestData/NIMROD-water/good_water.txt") g = GudrunFile( os.path.abspath("test/TestData/NIMROD-water/good_water.txt"), format=Format.TXT diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 82ab9ada..e1e41479 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -650,7 +650,7 @@ def setUp(self) -> None: self.keepsakes = os.listdir() - copyfile(self.g.path, "test/TestData/NIMROD-water/good_water.txt") + copyfile(self.g.loadFile, "test/TestData/NIMROD-water/good_water.txt") g = GudrunFile( "test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index ac208e11..89db5555 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -29,7 +29,7 @@ def setUp(self) -> None: self.keepsakes = os.listdir() - copyfile(self.g.path, os.path.join( + copyfile(self.g.loadFile, os.path.join( testDir, "TestData/NIMROD-water/good_water.txt") ) g = GudrunFile( diff --git a/gudpy/test/test_purge_file.py b/gudpy/test/test_purge_file.py index cf93fb73..3cf897a0 100644 --- a/gudpy/test/test_purge_file.py +++ b/gudpy/test/test_purge_file.py @@ -26,7 +26,7 @@ def setUp(self) -> None: self.keepsakes = os.listdir() - copyfile(self.g.path, "test/TestData/NIMROD-water/good_water.txt") + copyfile(self.g.loadFile, "test/TestData/NIMROD-water/good_water.txt") g = GudrunFile( "test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) From 6599fc4a4a47a02885f5ee038ca4fe1beda96be6 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 11:25:11 +0000 Subject: [PATCH 130/165] Print dicts --- gudpy/test/test_gudpy_yaml.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/gudpy/test/test_gudpy_yaml.py b/gudpy/test/test_gudpy_yaml.py index 1b8bb494..91b7ab14 100644 --- a/gudpy/test/test_gudpy_yaml.py +++ b/gudpy/test/test_gudpy_yaml.py @@ -13,6 +13,9 @@ def testYAML(self): gf1.write_yaml("test/TestData/NIMROD-water/water.yaml") gf2 = GudrunFile("test/TestData/NIMROD-water/water.yaml") + print(gf1.instrument.__dict__) + print(gf2.instrument.__dict__) + self.assertDictEqual(gf1.instrument.__dict__, gf2.instrument.__dict__) self.assertDictEqual(gf2.beam.__dict__, gf2.beam.__dict__) From 3e3d6049342c70ce710f669217e425156c43eca9 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 11:41:33 +0000 Subject: [PATCH 131/165] Retrieve gudfile using function --- gudpy/test/test_gudpy_workflows.py | 65 +++++++++++------------------- 1 file changed, 24 insertions(+), 41 deletions(-) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 89db5555..cb2e1eb4 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -50,32 +50,31 @@ def tearDown(self) -> None: [os.remove(f) for f in os.listdir() if f not in self.keepsakes] return super().tearDown() + def getGudFile(self, gudrunFile, sampleIndex): + return gudrunFile.gudrunOutput.sampleOutputs[ + gudrunFile.sampleBackgrounds[0].samples[sampleIndex].name].gudFile + def testGudPyDCS(self): - self.g.dcs() - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0].name].gudFile + gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 14.1, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1].name].gudFile + gfPath = self.getGudFile(self.g, 1) gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2].name].gudFile + gfPath = self.getGudFile(self.g, 2) gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 98.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3].name].gudFile + gfPath = self.getGudFile(self.g, 3) gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.err)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -117,29 +116,25 @@ def testGudPyIterateByTweakFactor(self): tweakFactorIterator = TweakFactorIterator(self.g, 5) tweakFactorIterator.iterate() - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0].name].gudFile + gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1].name].gudFile + gfPath = self.getGudFile(self.g, 1) gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2].name].gudFile + gfPath = self.getGudFile(self.g, 2) gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3].name].gudFile + gfPath = self.getGudFile(self.g, 3) gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -151,29 +146,25 @@ def testGudPyIterateByThickness(self): thicknessIterator = ThicknessIterator(self.g, 5) thicknessIterator.iterate() - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0].name].gudFile + gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1].name].gudFile + gfPath = self.getGudFile(self.g, 1) gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2].name].gudFile + gfPath = self.getGudFile(self.g, 2) gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3].name].gudFile + gfPath = self.getGudFile(self.g, 3) gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -185,29 +176,25 @@ def testGudPyIterateByDensity(self): densityIterator = DensityIterator(self.g, 5) densityIterator.iterate() - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0].name].gudFile + gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1].name].gudFile + gfPath = self.getGudFile(self.g, 1) gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2].name].gudFile + gfPath = self.getGudFile(self.g, 2) gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3].name].gudFile + gfPath = self.getGudFile(self.g, 3) gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) @@ -219,29 +206,25 @@ def testIterateByThickness(self): thicknessIterator = ThicknessIterator(self.g, 5) thicknessIterator.iterate() - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[0].name].gudFile + gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[1].name].gudFile + gfPath = self.getGudFile(self.g, 1) gf2 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf2.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[2].name].gudFile + gfPath = self.getGudFile(self.g, 2) gf3 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf3.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) self.assertAlmostEqual(dcsLevelPercentage, 100.0, 0) - gfPath = self.g.gudrunOutput.sampleOutputs[ - self.g.sampleBackgrounds[0].samples[3].name].gudFile + gfPath = self.getGudFile(self.g, 3) gf4 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf4.result)[0] dcsLevelPercentage = float(dcsLevelPercentage.replace('%', '')) From 9362ae7fc03d898fccc0d3c082d98d76d12db40f Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:44:53 +0000 Subject: [PATCH 132/165] Apply suggestions from code review --- gudpy/core/gudrun_file.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index e4e5037f..10bb8e17 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -146,7 +146,6 @@ def __init__(self, path=None, format=Format.YAML, config_=False): If a new input file should be constructed from a config """ - # Path and filename of initial input file self.yaml = YAML() self.format = format @@ -289,7 +288,6 @@ def parseInstrument(self): None """ try: - # Initialise instrument attribute to a new instance of Instrument. self.consumeWhitespace() # For string attributes, @@ -1477,8 +1475,6 @@ def __str__(self): def save(self, path='', format=None): - print(f"saving to {path}") - if not path: path = self.path From 5db54b4d6f7896d72cdeeeb6cb08d541ce141b44 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Wed, 17 Jan 2024 11:48:11 +0000 Subject: [PATCH 133/165] Remove blank line --- gudpy/core/gudrun_file.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 10bb8e17..defbaa1a 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -146,7 +146,6 @@ def __init__(self, path=None, format=Format.YAML, config_=False): If a new input file should be constructed from a config """ - self.yaml = YAML() self.format = format From 477c0b89b3f6b306a3c83f777d5d8c8ce2915004 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 14:11:31 +0000 Subject: [PATCH 134/165] Fix tests --- gudpy/core/gudrun_file.py | 2 +- gudpy/test/test_gud_file.py | 2 +- gudpy/test/test_gudpy_io.py | 7 ++++--- gudpy/test/test_gudpy_workflows.py | 2 +- gudpy/test/test_purge_file.py | 2 +- 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index defbaa1a..1f09721b 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1550,7 +1550,7 @@ def write_out(self, path='', overwrite=False, writeParameters=True): def setGudrunDir(self, dir): assert (os.path.isdir(os.path.abspath(dir))) - self.instrument.GudrunInputFileDir = dir + self.instrument.GudrunInputFileDir = os.path.abspath(dir) def dcs(self, path='', headless=True, iterator=None): """ diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index 4daa962e..01acaac6 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -245,7 +245,7 @@ def setUp(self) -> None: dataFileDir = Path("test/TestData/NIMROD-water/raw").absolute() g.instrument.dataFileDir = str(dataFileDir) + "/" - g.write_out(overwrite=True) + g.write_out(self.g.loadFile, overwrite=True) self.g = g g.write_out(overwrite=True) return super().setUp() diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index e1e41479..a8c54fbf 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -655,7 +655,8 @@ def setUp(self) -> None: "test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) - g.write_out(overwrite=True) + g.write_out(self.g.loadFile, + overwrite=True) return super().setUp() def tearDown(self) -> None: @@ -757,9 +758,9 @@ def testLoadGudrunFile(self): ) def testWriteGudrunFile(self): - self.g.write_out(overwrite=True) + self.g.write_out(self.g.loadFile, overwrite=True) with open( - self.g.path, + self.g.loadFile, encoding="utf-8" ) as f: outlines = "\n".join(f.readlines()[:-5]) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index cb2e1eb4..24660691 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -41,7 +41,7 @@ def setUp(self) -> None: dataFileDir = Path("test/TestData/NIMROD-water/raw").absolute() g.instrument.dataFileDir = str(dataFileDir) + "/" - g.write_out(overwrite=True) + g.write_out(self.g.loadFile, overwrite=True) self.g = g return super().setUp() diff --git a/gudpy/test/test_purge_file.py b/gudpy/test/test_purge_file.py index 3cf897a0..0a96d133 100644 --- a/gudpy/test/test_purge_file.py +++ b/gudpy/test/test_purge_file.py @@ -31,7 +31,7 @@ def setUp(self) -> None: "test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) - g.write_out(overwrite=True) + g.write_out(self.g.loadFile, overwrite=True) self.g = g self.expectedPurgeFile = { "standardDeviation": (10, 10), From e0c92952535ec8d3e2353c8eed4a1b1ebf631abb Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 16:52:46 +0000 Subject: [PATCH 135/165] Fix write-out paths --- gudpy/test/test_gud_file.py | 2 +- gudpy/test/test_gudpy_io.py | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/gudpy/test/test_gud_file.py b/gudpy/test/test_gud_file.py index 01acaac6..6c01c9d7 100644 --- a/gudpy/test/test_gud_file.py +++ b/gudpy/test/test_gud_file.py @@ -247,7 +247,7 @@ def setUp(self) -> None: g.write_out(self.g.loadFile, overwrite=True) self.g = g - g.write_out(overwrite=True) + g.write_out(self.g.loadFile, overwrite=True) return super().setUp() def tearDown(self) -> None: diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index a8c54fbf..0ca5afe9 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -655,8 +655,7 @@ def setUp(self) -> None: "test/TestData/NIMROD-water/good_water.txt", format=Format.TXT) - g.write_out(self.g.loadFile, - overwrite=True) + g.write_out(self.g.loadFile, overwrite=True) return super().setUp() def tearDown(self) -> None: @@ -843,7 +842,7 @@ def valueInLines(value, lines): valueInLines(value, inlines) def testRewriteGudrunFile(self): - self.g.write_out(overwrite=True) + self.g.write_out(self.g.loadFile, overwrite=True) copyPath = os.path.join( self.g.instrument.GudrunInputFileDir, "copyGF.txt" @@ -893,7 +892,7 @@ def compareString(string1, string2): ) def testReloadGudrunFile(self): - self.g.write_out(overwrite=True) + self.g.write_out(self.g.loadFile, overwrite=True) g1 = GudrunFile( self.g.path, format=Format.TXT From 8881d0768c63af69c9e9fa1381f3d6f13a5bb085 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 17:21:05 +0000 Subject: [PATCH 136/165] Fix path to loadfile --- gudpy/test/test_gudpy_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 0ca5afe9..6385f819 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -820,7 +820,7 @@ def valueInLines(value, lines): else: valueInLines(value, outlines) inlines = "" - with open(self.g.path) as f: + with open(self.g.loadFile) as f: inlines = f.read() for dic in self.dicts: for value in dic.values(): From 4eeb09970c925c60ca7f46b594fc65d617356a70 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 17:24:07 +0000 Subject: [PATCH 137/165] Fix test --- gudpy/test/test_gudpy_workflows.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_workflows.py b/gudpy/test/test_gudpy_workflows.py index 24660691..106524c2 100644 --- a/gudpy/test/test_gudpy_workflows.py +++ b/gudpy/test/test_gudpy_workflows.py @@ -55,7 +55,7 @@ def getGudFile(self, gudrunFile, sampleIndex): gudrunFile.sampleBackgrounds[0].samples[sampleIndex].name].gudFile def testGudPyDCS(self): - + self.g.dcs() gfPath = self.getGudFile(self.g, 0) gf1 = GudFile(gfPath) dcsLevelPercentage = re.findall(r'\d*[.]?\d*%', gf1.err)[0] From 28be0eff5124c5d9ef1e7e9fae20af79a436451b Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 17:25:09 +0000 Subject: [PATCH 138/165] Remove actions step debug --- .github/workflows/test/action.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 13a9b3c5..42984554 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -1,8 +1,5 @@ name: Test -env: - ACTIONS_STEP_DEBUG: true - runs: using: "composite" steps: From 870072fb272436402e1f96fb49eb2ddf5cd366f5 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 17:25:34 +0000 Subject: [PATCH 139/165] Remove print debugging --- gudpy/test/test_gudpy_yaml.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/gudpy/test/test_gudpy_yaml.py b/gudpy/test/test_gudpy_yaml.py index 91b7ab14..1b8bb494 100644 --- a/gudpy/test/test_gudpy_yaml.py +++ b/gudpy/test/test_gudpy_yaml.py @@ -13,9 +13,6 @@ def testYAML(self): gf1.write_yaml("test/TestData/NIMROD-water/water.yaml") gf2 = GudrunFile("test/TestData/NIMROD-water/water.yaml") - print(gf1.instrument.__dict__) - print(gf2.instrument.__dict__) - self.assertDictEqual(gf1.instrument.__dict__, gf2.instrument.__dict__) self.assertDictEqual(gf2.beam.__dict__, gf2.beam.__dict__) From 87504379b27c17ef8ab9da87e7f8f562bee77116 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 18:52:58 +0000 Subject: [PATCH 140/165] Fix test --- gudpy/test/test_gudpy_io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 6385f819..158c3733 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -848,7 +848,7 @@ def testRewriteGudrunFile(self): "copyGF.txt" ) g1 = GudrunFile( - self.g.path, + self.g.loadFile, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir @@ -894,7 +894,7 @@ def compareString(string1, string2): def testReloadGudrunFile(self): self.g.write_out(self.g.loadFile, overwrite=True) g1 = GudrunFile( - self.g.path, + self.g.loadFile, format=Format.TXT ) g1.instrument.GudrunInputFileDir = self.g.instrument.GudrunInputFileDir From 32fc88e32ad733c6d49ebc8ef377516bffa8ee96 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 20:36:43 +0000 Subject: [PATCH 141/165] Fix test --- gudpy/test/test_gudpy_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 158c3733..152a2b74 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -880,7 +880,7 @@ def compareString(string1, string2): with open( os.path.join( - self.g.path + self.g.loadFile ), encoding="utf-8" ) as fg: From c6d41d07d8be885574063c682eb584609fca4070 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 17 Jan 2024 20:38:58 +0000 Subject: [PATCH 142/165] Update ui --- gudpy/gui/widgets/ui_files/mainWindow.ui | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gudpy/gui/widgets/ui_files/mainWindow.ui b/gudpy/gui/widgets/ui_files/mainWindow.ui index 3ef46884..8e5dca93 100644 --- a/gudpy/gui/widgets/ui_files/mainWindow.ui +++ b/gudpy/gui/widgets/ui_files/mainWindow.ui @@ -7336,6 +7336,7 @@ File + @@ -7343,6 +7344,7 @@ + @@ -7405,6 +7407,11 @@ Ctrl+O + + + Load project + + Load configuration @@ -7447,6 +7454,11 @@ Save As.. + + + Export Input File + + Insert Sample From 40b02cc3553e2a26e3251c713887a54f2058edc0 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 10:44:08 +0000 Subject: [PATCH 143/165] Fix test to use abspath --- gudpy/test/test_gudpy_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 152a2b74..58285f5c 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -42,7 +42,7 @@ def setUp(self) -> None: "name": Instruments.NIMROD, "GudrunInputFileDir": os.path.abspath(os.path.dirname(os.path.abspath(dirpath))), - "dataFileDir": "NIMROD-water/raw/", + "dataFileDir": os.path.abspath("NIMROD-water/raw/"), "dataFileType": "raw", "detectorCalibrationFileName": ( 'StartupFiles/NIMROD/NIMROD84modules' From f271d58c937b9a1f3582aec46c37c019603fe37c Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 11:07:56 +0000 Subject: [PATCH 144/165] Use abspath --- gudpy/test/test_gudpy_io.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 58285f5c..6a1798fa 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -632,6 +632,10 @@ def setUp(self) -> None: ].__dict__ = self.expectedContainerA self.g = GudrunFile(dirpath, format=Format.TXT) + # Set to absolute path + self.g.instrument.dataFileDir = os.path.abspath( + self.g.instrument.dataFileDir + ) self.dicts = [ self.expectedInstrument, From 5016693da72a40bd0d258b3fa234d82e6253fe39 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 13:24:46 +0000 Subject: [PATCH 145/165] Remove abspath --- gudpy/core/gudrun_file.py | 4 ++-- gudpy/test/test_gudpy_io.py | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 1f09721b..149aec5a 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1549,8 +1549,8 @@ def write_out(self, path='', overwrite=False, writeParameters=True): ) def setGudrunDir(self, dir): - assert (os.path.isdir(os.path.abspath(dir))) - self.instrument.GudrunInputFileDir = os.path.abspath(dir) + assert (os.path.isdir(dir)) + self.instrument.GudrunInputFileDir = dir def dcs(self, path='', headless=True, iterator=None): """ diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 6a1798fa..152a2b74 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -42,7 +42,7 @@ def setUp(self) -> None: "name": Instruments.NIMROD, "GudrunInputFileDir": os.path.abspath(os.path.dirname(os.path.abspath(dirpath))), - "dataFileDir": os.path.abspath("NIMROD-water/raw/"), + "dataFileDir": "NIMROD-water/raw/", "dataFileType": "raw", "detectorCalibrationFileName": ( 'StartupFiles/NIMROD/NIMROD84modules' @@ -632,10 +632,6 @@ def setUp(self) -> None: ].__dict__ = self.expectedContainerA self.g = GudrunFile(dirpath, format=Format.TXT) - # Set to absolute path - self.g.instrument.dataFileDir = os.path.abspath( - self.g.instrument.dataFileDir - ) self.dicts = [ self.expectedInstrument, From 40f18fcc31fa58b59b36f2722bcd8aa249a8453e Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 14:22:08 +0000 Subject: [PATCH 146/165] Remove assertion --- gudpy/core/gudrun_file.py | 1 - 1 file changed, 1 deletion(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index 149aec5a..aa063ce7 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -1549,7 +1549,6 @@ def write_out(self, path='', overwrite=False, writeParameters=True): ) def setGudrunDir(self, dir): - assert (os.path.isdir(dir)) self.instrument.GudrunInputFileDir = dir def dcs(self, path='', headless=True, iterator=None): From 6f6e31235bfaa478a18ab58ee83194c1a1c958b9 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 14:58:46 +0000 Subject: [PATCH 147/165] Fix test --- gudpy/test/test_gudpy_yaml.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gudpy/test/test_gudpy_yaml.py b/gudpy/test/test_gudpy_yaml.py index 1b8bb494..d68118c9 100644 --- a/gudpy/test/test_gudpy_yaml.py +++ b/gudpy/test/test_gudpy_yaml.py @@ -1,4 +1,5 @@ from unittest import TestCase +import os from core.gudrun_file import GudrunFile from core.enums import Format @@ -13,6 +14,11 @@ def testYAML(self): gf1.write_yaml("test/TestData/NIMROD-water/water.yaml") gf2 = GudrunFile("test/TestData/NIMROD-water/water.yaml") + gf1.instrument.GudrunInputFileDir = os.path.abspath( + gf1.instrument.GudrunInputFileDir) + gf2.instrument.GudrunInputFileDir = os.path.abspath( + gf2.instrument.GudrunInputFileDir) + self.assertDictEqual(gf1.instrument.__dict__, gf2.instrument.__dict__) self.assertDictEqual(gf2.beam.__dict__, gf2.beam.__dict__) From 9599c7e715407b118094e4dd746f876d94adac9d Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 15:58:18 +0000 Subject: [PATCH 148/165] Do abspath --- gudpy/core/gudrun_file.py | 3 ++- gudpy/test/test_gudpy_io.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index aa063ce7..d74f7597 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -293,7 +293,8 @@ def parseInstrument(self): # we simply extract the firstword in the line. self.instrument.name = Instruments[firstword(self.getNextToken())] self.consumeTokens(1) - self.instrument.dataFileDir = firstword(self.getNextToken()) + self.instrument.dataFileDir = os.path.abspath( + firstword(self.getNextToken())) self.instrument.dataFileType = firstword(self.getNextToken()) self.instrument.detectorCalibrationFileName = ( firstword(self.getNextToken()) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 152a2b74..df372c7e 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -42,7 +42,7 @@ def setUp(self) -> None: "name": Instruments.NIMROD, "GudrunInputFileDir": os.path.abspath(os.path.dirname(os.path.abspath(dirpath))), - "dataFileDir": "NIMROD-water/raw/", + "dataFileDir": os.path.abspath("test/TestData/NIMROD-water/raw/"), "dataFileType": "raw", "detectorCalibrationFileName": ( 'StartupFiles/NIMROD/NIMROD84modules' From 84a2859534251721e5d92ecb042d7ffd2d6ee4a1 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 16:43:10 +0000 Subject: [PATCH 149/165] Fix --- gudpy/test/test_gudpy_io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 152a2b74..df372c7e 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -42,7 +42,7 @@ def setUp(self) -> None: "name": Instruments.NIMROD, "GudrunInputFileDir": os.path.abspath(os.path.dirname(os.path.abspath(dirpath))), - "dataFileDir": "NIMROD-water/raw/", + "dataFileDir": os.path.abspath("test/TestData/NIMROD-water/raw/"), "dataFileType": "raw", "detectorCalibrationFileName": ( 'StartupFiles/NIMROD/NIMROD84modules' From d7eed974af4f80464383abfb1579028199acef18 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 18 Jan 2024 16:44:29 +0000 Subject: [PATCH 150/165] Undo --- gudpy/core/gudrun_file.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index d74f7597..aa063ce7 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -293,8 +293,7 @@ def parseInstrument(self): # we simply extract the firstword in the line. self.instrument.name = Instruments[firstword(self.getNextToken())] self.consumeTokens(1) - self.instrument.dataFileDir = os.path.abspath( - firstword(self.getNextToken())) + self.instrument.dataFileDir = firstword(self.getNextToken()) self.instrument.dataFileType = firstword(self.getNextToken()) self.instrument.detectorCalibrationFileName = ( firstword(self.getNextToken()) From 87f7786ff31144e508de7f929b3a1b7293eac29f Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 19 Jan 2024 09:17:27 +0000 Subject: [PATCH 151/165] try fix again --- gudpy/test/test_gudpy_io.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index df372c7e..f0a26e96 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -670,6 +670,14 @@ def testLoadGudrunFile(self): instrumentAttrsDict = self.g.instrument.__dict__ for key in instrumentAttrsDict.keys(): + pathKeys = ["GudrunInputFileDir", "dataFileDir"] + if key in pathKeys: + self.expectedInstrument[key] = os.path.abspath( + self.expectedInstrument[key] + ) + instrumentAttrsDict[key] = os.path.abspath( + instrumentAttrsDict[key] + ) self.assertEqual( self.expectedInstrument[key], instrumentAttrsDict[key] ) From 7dc14ef90c19dc43814a859fdc649b8e12abc306 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 19 Jan 2024 13:08:37 +0000 Subject: [PATCH 152/165] Remove paths from assertion --- gudpy/test/test_gudpy_io.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index f0a26e96..527c7fd7 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -672,15 +672,12 @@ def testLoadGudrunFile(self): for key in instrumentAttrsDict.keys(): pathKeys = ["GudrunInputFileDir", "dataFileDir"] if key in pathKeys: - self.expectedInstrument[key] = os.path.abspath( - self.expectedInstrument[key] - ) - instrumentAttrsDict[key] = os.path.abspath( - instrumentAttrsDict[key] + # Ignore the paths as they vary + continue + else: + self.assertEqual( + self.expectedInstrument[key], instrumentAttrsDict[key] ) - self.assertEqual( - self.expectedInstrument[key], instrumentAttrsDict[key] - ) beamAttrsDict = self.g.beam.__dict__ From 33c84a15cba3cf6edee74db8440ca587d8ecdbea Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Fri, 19 Jan 2024 14:55:45 +0000 Subject: [PATCH 153/165] Debugging --- gudpy/test/test_gudpy_io.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 527c7fd7..b066142f 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -823,6 +823,8 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: + print(value) + print(outlines) valueInLines(value, outlines) inlines = "" with open(self.g.loadFile) as f: From 01ca823405a065d1bc00f6c945fa8dd4a3ad156b Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Mon, 22 Jan 2024 11:05:37 +0000 Subject: [PATCH 154/165] debug --- gudpy/test/test_gudpy_io.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index b066142f..5cab308c 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -774,6 +774,9 @@ def testWriteGudrunFile(self): def valueInLines(value, lines): if isinstance(value, str): + print(value) + print("Noella") + print(lines) self.assertTrue(value in lines) elif isinstance(value, (list, tuple)): if len(value) == 0: @@ -823,8 +826,6 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: - print(value) - print(outlines) valueInLines(value, outlines) inlines = "" with open(self.g.loadFile) as f: From a7da0ba0c2b92d481bda0d9788f6ff2c720aa9f7 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Mon, 22 Jan 2024 11:26:36 +0000 Subject: [PATCH 155/165] debug --- gudpy/test/test_gudpy_io.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 5cab308c..efca2ff1 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -774,9 +774,9 @@ def testWriteGudrunFile(self): def valueInLines(value, lines): if isinstance(value, str): - print(value) - print("Noella") - print(lines) + print(value) + print("Noella") + print(lines) self.assertTrue(value in lines) elif isinstance(value, (list, tuple)): if len(value) == 0: From 1dd6f4f4ab2c2021399a6df76ca259da95a38fee Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Mon, 22 Jan 2024 13:18:43 +0000 Subject: [PATCH 156/165] attempt to fix test --- gudpy/test/test_gudpy_io.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index efca2ff1..d38ed8c4 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -773,10 +773,7 @@ def testWriteGudrunFile(self): ) def valueInLines(value, lines): - if isinstance(value, str): - print(value) - print("Noella") - print(lines) + if isinstance(value, str) and value != "": self.assertTrue(value in lines) elif isinstance(value, (list, tuple)): if len(value) == 0: From 78e7ea9b75125f2d0e15d227bdcc024a94ffd899 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Mon, 22 Jan 2024 14:49:53 +0000 Subject: [PATCH 157/165] Specify encoding --- gudpy/test/test_gudpy_io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index d38ed8c4..98a6fcaa 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -773,7 +773,7 @@ def testWriteGudrunFile(self): ) def valueInLines(value, lines): - if isinstance(value, str) and value != "": + if isinstance(value, str): self.assertTrue(value in lines) elif isinstance(value, (list, tuple)): if len(value) == 0: @@ -825,7 +825,7 @@ def valueInLines(value, lines): else: valueInLines(value, outlines) inlines = "" - with open(self.g.loadFile) as f: + with open(self.g.loadFile, encoding="utf-8") as f: inlines = f.read() for dic in self.dicts: for value in dic.values(): From c8dfc3e302f3396f3d678d93f0b0e92b6d481898 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 24 Jan 2024 12:37:45 +0000 Subject: [PATCH 158/165] Debug --- gudpy/test/test_gudpy_io.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 98a6fcaa..c310f3b6 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -823,6 +823,10 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: + print("\n-----------------------") + print(f"VALUE: {value}") + print(f"OUTLINES: {outlines}") + print("-----------------------") valueInLines(value, outlines) inlines = "" with open(self.g.loadFile, encoding="utf-8") as f: From 3accada74597aa1e827ffc4a01a52def0cd5ca71 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 24 Jan 2024 14:14:40 +0000 Subject: [PATCH 159/165] Remove debugging and parse data file directory as abspath --- gudpy/core/gudrun_file.py | 3 ++- gudpy/test/test_gudpy_io.py | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index aa063ce7..d74f7597 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -293,7 +293,8 @@ def parseInstrument(self): # we simply extract the firstword in the line. self.instrument.name = Instruments[firstword(self.getNextToken())] self.consumeTokens(1) - self.instrument.dataFileDir = firstword(self.getNextToken()) + self.instrument.dataFileDir = os.path.abspath( + firstword(self.getNextToken())) self.instrument.dataFileType = firstword(self.getNextToken()) self.instrument.detectorCalibrationFileName = ( firstword(self.getNextToken()) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index c310f3b6..98a6fcaa 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -823,10 +823,6 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: - print("\n-----------------------") - print(f"VALUE: {value}") - print(f"OUTLINES: {outlines}") - print("-----------------------") valueInLines(value, outlines) inlines = "" with open(self.g.loadFile, encoding="utf-8") as f: From 521bbd3df7b92e52f6771a50b4aa965890ff2b15 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 24 Jan 2024 14:34:38 +0000 Subject: [PATCH 160/165] Include trailling slash to path --- gudpy/core/gudrun_file.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/core/gudrun_file.py b/gudpy/core/gudrun_file.py index d74f7597..aa929795 100644 --- a/gudpy/core/gudrun_file.py +++ b/gudpy/core/gudrun_file.py @@ -294,7 +294,7 @@ def parseInstrument(self): self.instrument.name = Instruments[firstword(self.getNextToken())] self.consumeTokens(1) self.instrument.dataFileDir = os.path.abspath( - firstword(self.getNextToken())) + firstword(self.getNextToken())) + os.path.sep self.instrument.dataFileType = firstword(self.getNextToken()) self.instrument.detectorCalibrationFileName = ( firstword(self.getNextToken()) From 1a7191718673b801de1c875a9ef7f9e69eb40585 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 24 Jan 2024 14:56:57 +0000 Subject: [PATCH 161/165] Include trailling slash to path --- gudpy/test/test_gudpy_io.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 98a6fcaa..e16b8bff 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -42,7 +42,10 @@ def setUp(self) -> None: "name": Instruments.NIMROD, "GudrunInputFileDir": os.path.abspath(os.path.dirname(os.path.abspath(dirpath))), - "dataFileDir": os.path.abspath("test/TestData/NIMROD-water/raw/"), + "dataFileDir": ( + os.path.abspath( + "test/TestData/NIMROD-water/raw/") + os.path.sep + ), "dataFileType": "raw", "detectorCalibrationFileName": ( 'StartupFiles/NIMROD/NIMROD84modules' From 30eebf626c1d7f6bfcd645f9fffb72aba94b84de Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Wed, 24 Jan 2024 15:56:48 +0000 Subject: [PATCH 162/165] Debug again --- .github/workflows/test/action.yml | 2 +- gudpy/test/test_gudpy_io.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 42984554..80a16056 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -32,7 +32,7 @@ runs: shell: bash run: | cd gudpy - nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test + nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test.test_gudpy_io.TestGudPyIO.testWriteGudrunFile mkdir ../results mv nose2-junit.xml ../results/nose2-junit-${{ runner.os }}.xml diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index e16b8bff..69df9100 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -826,6 +826,10 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: + print("\n---------------------") + print(f"VALUE: {value}") + print(f"OUTLINES {outlines}") + print("---------------------") valueInLines(value, outlines) inlines = "" with open(self.g.loadFile, encoding="utf-8") as f: From 07b9c0808264220570cc8f9ca2bdc0328f144bba Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Wed, 24 Jan 2024 16:23:31 +0000 Subject: [PATCH 163/165] Fix path on water.txt --- gudpy/test/TestData/NIMROD-water/water.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gudpy/test/TestData/NIMROD-water/water.txt b/gudpy/test/TestData/NIMROD-water/water.txt index db43419d..a6ecea35 100644 --- a/gudpy/test/TestData/NIMROD-water/water.txt +++ b/gudpy/test/TestData/NIMROD-water/water.txt @@ -4,7 +4,7 @@ INSTRUMENT { NIMROD Instrument name /home/test/gudpy-water/ Gudrun input file directory: -NIMROD-water/raw/ Data file directory +test/TestData/NIMROD-water/raw/ Data file directory raw Data file type StartupFiles/NIMROD/NIMROD84modules+9monitors+LAB5Oct2012Detector.dat Detector calibration file name 4 User table column number for phi values From 449aea013f19b10c6f77dd08b443ce36b3425e38 Mon Sep 17 00:00:00 2001 From: Noella Spitz Date: Thu, 25 Jan 2024 09:57:12 +0000 Subject: [PATCH 164/165] Remove debugging --- gudpy/test/test_gudpy_io.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/gudpy/test/test_gudpy_io.py b/gudpy/test/test_gudpy_io.py index 69df9100..e16b8bff 100644 --- a/gudpy/test/test_gudpy_io.py +++ b/gudpy/test/test_gudpy_io.py @@ -826,10 +826,6 @@ def valueInLines(value, lines): else: valueInLines(val, outlines) else: - print("\n---------------------") - print(f"VALUE: {value}") - print(f"OUTLINES {outlines}") - print("---------------------") valueInLines(value, outlines) inlines = "" with open(self.g.loadFile, encoding="utf-8") as f: From 8695d29bb8405966e34510769091a87907e81148 Mon Sep 17 00:00:00 2001 From: Noella Spitz <101950441+rhinoella@users.noreply.github.com> Date: Thu, 25 Jan 2024 10:03:34 +0000 Subject: [PATCH 165/165] Test everything --- .github/workflows/test/action.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/test/action.yml b/.github/workflows/test/action.yml index 80a16056..2d4d51c0 100644 --- a/.github/workflows/test/action.yml +++ b/.github/workflows/test/action.yml @@ -32,8 +32,7 @@ runs: shell: bash run: | cd gudpy - nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test.test_gudpy_io.TestGudPyIO.testWriteGudrunFile - + nose2 --with-coverage --coverage-report xml --plugin nose2.plugins.junitxml --junit-xml --verbose test mkdir ../results mv nose2-junit.xml ../results/nose2-junit-${{ runner.os }}.xml