Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Include Gudrun dependencies in the run #513

Merged
merged 17 commits into from
Jun 28, 2024
4 changes: 4 additions & 0 deletions gudpy/core/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ def __init__(self, config=None):
if config:
self.parseFromConfig(config)

@property
def gudFile(self):
return None

def __str__(self):
"""
Returns the string representation of the Container object.
Expand Down
42 changes: 42 additions & 0 deletions gudpy/core/data_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,54 @@ def mintFile(self):
return None
return self._outputs.get(".mint01", None)

@property
def mdcsFile(self):
if not self.isSampleDataFile:
return None
mdcsFile = self._outputs.get(".mdcs01", None)
if mdcsFile:
return mdcsFile
# If units are d-spacing
mdcsdFile = self._outputs.get(".mdcsd01", None)
if mdcsdFile:
return mdcsdFile
# If units are energy
mdcseFile = self._outputs.get(".mdcse01", None)
if mdcseFile:
return mdcseFile
# If units are time-of-flight
mdcstFile = self._outputs.get(".mdcst01", None)
if mdcstFile:
return mdcstFile
# If units are wavelength
mdcswFile = self._outputs.get(".mdcsw01", None)
if mdcswFile:
return mdcswFile

@property
def msubwFile(self):
if not self.isSampleDataFile:
return None
return self._outputs.get(".msubw01", None)

@property
def mcdsFile(self):
if not self.isSampleDataFile:
return None
return self._outputs.get(".mcds01", None)

@property
def mdorFile(self):
if not self.isSampleDataFile:
return None
return self._outputs.get(".mdor01", None)

@property
def mgorFile(self):
if not self.isSampleDataFile:
return None
return self._outputs.get(".mgor01", None)


class DataFiles:
"""
Expand Down
2 changes: 1 addition & 1 deletion gudpy/core/gud_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def __init__(self, path):
raise ParserException(f"Attempted to parse {path}" +
"\nOnly .gud files can be parsed.")

if not os.path.isfile(path):
if not os.path.exists(path):
raise ParserException(f"{path} is not a valid path.")

self.path = path
Expand Down
96 changes: 48 additions & 48 deletions gudpy/core/gudpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ def __init__(
self.gudrunIterator: GudrunIterator = None
self.batchProcessor: BatchProcessing = None

self.gudrunOutput = None

@property
def gudrunFile(self):
return self._gudrunFile
Expand Down Expand Up @@ -229,7 +227,6 @@ def runGudrun(self, gudrunFile: GudrunFile = None):
"Gudrun failed to run with the following output:\n"
f"{self.gudrun.error}"
)
self.gudrunOutput = self.gudrun.gudrunOutput
self.save()

def iterateGudrun(self, iterator: iterators.Iterator):
Expand All @@ -256,7 +253,6 @@ def iterateGudrun(self, iterator: iterators.Iterator):
f"{error}"
)
self.gudrunFile = self.gudrunIterator.gudrunFile
self.gudrunOutput = self.gudrunIterator.gudrunOutput

def iterateComposition(self, iterator: iterators.Composition):
"""Runs gudrun_dcs iteratively while tweaking the composition
Expand Down Expand Up @@ -441,22 +437,38 @@ def organiseOutput(
self,
gudrunFile: GudrunFile,
exclude: list[str] = [],
head: str = "",
head: list[str] = [],
overwrite: bool = True
) -> handlers.GudrunOutput:
) -> None:

outputHandler = handlers.GudrunOutputHandler(
gudrunFile=gudrunFile, head=head, overwrite=overwrite
)
gudrunOutput = outputHandler.organiseOutput(exclude=exclude)
return gudrunOutput
outputHandler.organiseOutput(exclude=exclude)

def obtainDependencies(
fileSelfScattering,
self,
gudrunFile: GudrunFile
):
if gudrunFile.instrument.subWavelengthBinnedData:
return
) -> list[str]:
if not gudrunFile.instrument.subWavelengthBinnedData:
return []

if not GudPyIO.projectDir:
cli.echoWarning(
"Cannot source run dependencies - no previous GudPy"
" project referenced. Running without wavelength binning"
" data."
)

dependencies = []

for sample in gudrunFile.runSamples():
if sample.crossSectionFilename:
dependencies.append(sample.crossSectionFilename)
if sample.selfScatteringFilePath:
dependencies.append(sample.selfScatteringFilePath)

return dependencies

def gudrun(
self,
Expand All @@ -482,6 +494,16 @@ def gudrun(
tmp,
gudrunFile.OUTPATH
)

gudrunFile.clearOutputs()

deps = self.obtainDependencies(gudrunFile)
for dep in deps:
shutil.copyfile(
dep, os.path.join(
tmp, os.path.basename(dep)
))

GudPyIO.writeGudrunFile(gudrunFile, tmp)
with subprocess.Popen(
[self.BINARY_PATH, path], cwd=tmp,
Expand All @@ -490,21 +512,20 @@ def gudrun(
) as gudrun:
for line in gudrun.stdout:
line = "\n".join(line.decode("utf8").split("\n"))
self._outputChanged(line)
if self.checkError(line):
return self.exitcode
self._outputChanged(line)
if gudrun.stderr:
self.error = gudrun.stderr.decode("utf8")
self.exitcode = 1
return self.exitcode

if iterator:
self.gudrunOutput = iterator.organiseOutput(
iterator.organiseOutput(
gudrunFile, exclude=purgeFiles)
else:
self.gudrunOutput = self.organiseOutput(
self.organiseOutput(
gudrunFile, exclude=purgeFiles)
gudrunFile.setGudrunDir(self.gudrunOutput.path)

self.exitcode = 0
return self.exitcode
Expand All @@ -522,7 +543,6 @@ def __init__(
self.iterator = iterator
self.gudrunObjects = []
self.exitcode = (1, "Operation incomplete")
self.gudrunOutput = None
self.result = {}

for _ in range(
Expand All @@ -538,40 +558,33 @@ def singleIteration(
gudrunFile: GudrunFile,
gudrun: Gudrun,
purge: Purge,
prevOutput: handlers.GudrunOutput,
) -> typ.Tuple[int, str]: # (exitcode, error)
modGfFile = self.iterator.performIteration(gudrunFile, prevOutput)
modGfFile = self.iterator.performIteration(gudrunFile)
exitcode = gudrun.gudrun(modGfFile, purge, self.iterator)
if exitcode:
return exitcode
self.gudrunOutput = gudrun.gudrunOutput
return 0

def iterate(self, purge) -> typ.Tuple[int, str]:
prevOutput = None

# If the iterator requires a prelimenary run
if self.iterator.requireDefault:
exitcode = self.gudrunObjects[0].gudrun(
self.gudrunFile, purge, self.iterator)
if exitcode: # An exit code != 0 indicates failure
self.exitcode = (exitcode, self.gudrunObjects[0].error)
return self.exitcode
prevOutput = self.gudrunObjects[0].gudrunOutput

# Iterate through gudrun objects
for gudrun in self.gudrunObjects:
if gudrun.output:
# If object has already been run, skip
continue
exitcode = self.singleIteration(
self.gudrunFile, gudrun, purge, prevOutput)
self.gudrunFile, gudrun, purge)
if exitcode: # An exit code != 0 indicates failure
self.exitcode = (exitcode, gudrun.error)
return self.exitcode

prevOutput = gudrun.gudrunOutput

self.result = self.iterator.result

self.exitcode = (0, "")
Expand All @@ -590,48 +603,38 @@ def __init__(
iterator=iterator
)

def copyDCS(self, prevOutput):
return

def singleIteration(
self,
gudrunFile: GudrunFile,
gudrun: Gudrun,
purge: Purge,
prevOutput: handlers.GudrunOutput,
) -> typ.Tuple[int, str]: # (exitcode, error)
modGfFile = self.iterator.performIteration(gudrunFile, prevOutput)
modGfFile = self.iterator.performIteration(gudrunFile)
exitcode = gudrun.gudrun(modGfFile, purge, self.iterator)
if exitcode:
return exitcode
self.gudrunOutput = gudrun.gudrunOutput
return 0

def iterate(self, purge) -> typ.Tuple[int, str]:
prevOutput = None

# If the iterator requires a prelimenary run
if self.iterator.requireDefault:
exitcode = self.gudrunObjects[0].gudrun(
self.gudrunFile, purge, self.iterator)
if exitcode: # An exit code != 0 indicates failure
self.exitcode = (exitcode, self.gudrunObjects[0].error)
return self.exitcode
prevOutput = self.gudrunObjects[0].gudrunOutput

# Iterate through gudrun objects
for gudrun in self.gudrunObjects:
if gudrun.output:
# If object has already been run, skip
continue
exitcode = self.singleIteration(
self.gudrunFile, gudrun, purge, prevOutput)
self.gudrunFile, gudrun, purge)
if exitcode: # An exit code != 0 indicates failure
self.exitcode = (exitcode, gudrun.error)
return self.exitcode

prevOutput = gudrun.gudrunOutput

self.result = self.iterator.result

self.exitcode = (0, "")
Expand Down Expand Up @@ -666,6 +669,8 @@ def iterate(self, purge) -> typ.Tuple[int, str]:
self.exitcode = (exitcode, gudrunNC.error)
return self.exitcode

newCenterGudFile = self.gudrunFile.runSamples()[0].gudFile

# Run the current center
currentCenter = self.iterator.iterateCurrentCenter(
self.gudrunFile, sampleArg)
Expand All @@ -677,13 +682,13 @@ def iterate(self, purge) -> typ.Tuple[int, str]:
self.exitcode = (exitcode, gudrunCC.error)
return self.exitcode

currentCenterGudFile = self.gudrunFile.runSamples()[0].gudFile

# Compare the cost of the two centers
self.iterator.compareCost(
sampleArg=sampleArg,
currentCenterGudFile=gudrunCC.gudrunOutput.gudFile(
name=sampleArg["background"].samples[0].name),
newCenterGudFile=gudrunNC.gudrunOutput.gudFile(
name=sampleArg["background"].samples[0].name)
currentCenterGudFile=currentCenterGudFile,
newCenterGudFile=newCenterGudFile
)

# Check if result has been achieved
Expand Down Expand Up @@ -921,8 +926,6 @@ def iterate(
batchedFile: GudrunFile,
outputFolder: str,
) -> int:
prevOutput = None

batchedFile.projectDir = os.path.join(
batchedFile.projectDir,
f"BATCH_PROCESSING_BATCH_SIZE{self.BATCH_SIZE}",
Expand All @@ -937,7 +940,6 @@ def iterate(
if exitcode: # An exit code != 0 indicates failure
self.exitcode = (exitcode, error)
return self.exitcode
prevOutput = gudrunIterator.defaultRun.gudrunOutput

# Iterate through gudrun objects
for i, gudrun in enumerate(gudrunIterator.gudrunObjects):
Expand All @@ -948,7 +950,7 @@ def iterate(
return self.exitcode

exitcode = gudrunIterator.singleIteration(
batchedFile, gudrun, prevOutput)
batchedFile, gudrun)

self.writeDiagnosticsFile(
os.path.join(batchedFile.path(),
Expand All @@ -959,8 +961,6 @@ def iterate(
self.exitcode = (exitcode, gudrun.error)
return self.exitcode

prevOutput = gudrun.gudrunOutput

self.exitcode = (0, )
return self.exitcode

Expand Down
9 changes: 9 additions & 0 deletions gudpy/core/gudrun_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,15 @@ def __deepcopy__(self, memo):
setattr(result, k, deepcopy(v, memo))
return result

def clearOutputs(self):
self.outputFolder = ""
for sbg in self.sampleBackgrounds:
sbg.outputFolder = ""
for sample in self.runSamples():
for df in sample.dataFiles:
df._outputs = {}
df.outputFolder = ""

def setGudrunDir(self, dir):
self.instrument.GudrunInputFileDir = dir

Expand Down
2 changes: 2 additions & 0 deletions gudpy/core/io/gudpy_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ def _parseYamlSample(self, yamldict: any) -> Sample:
for k, v in yamldict.items():
if k == "dataFiles":
dataFiles = self._parseYamlDataFiles(v)
for dataFile in dataFiles:
dataFile.isSampleDataFile = True
setattr(sample, k, dataFiles)
elif k == "composition":
composition = self._parseYamlComposition(v)
Expand Down
Loading
Loading