Background
Most data processing protocols in SciAnalysis/XSAnalysis/Protocols.py currently intermix scientific computation and file I/O within their run() methods. While this works for legacy file-based batch processing, it limits future extensibility, such as:
- API use (e.g., GUI, cloud batch jobs)
- AI-driven automation
- Integration with tiled data services, in-memory channels, etc.
Re-engineering is needed to improve reusability and maintainability for modern applications.
Identified Problems
- Protocols (e.g.,
circular_average, SectorAverage, GraininessAnalysis, etc.) combine core calculations and all saving/plotting/export in the same function. This prevents using results in non-file-based workflows.
- Many protocols require
output_dir even if no files will be written.
- Protocols read dependencies (e.g., fit results, 1D data) from disk, hard-wiring workflows to file-based outputs.
Proposed Solution
- Create a parallel set of new protocol classes (e.g., in
ProtocolsV2.py) that split the computation (pure in-memory results) from file I/O.
- New base class:
class ProtocolBase:
def compute(self, data, **kwargs) -> dict:
"""Pure computation; returns results dict (no I/O)."""
raise NotImplementedError
def run(self, data, output_dir, **run_args):
results = self.compute(data, **run_args)
self._save(results, data, output_dir, **run_args)
return results
def _save(self, results, data, output_dir, **run_args):
pass
- Rewrite key protocols with this pattern.
- Pass dependencies explicitly as arguments (not via disk reads).
Example: CircularAverage
class CircularAverage(ProtocolBase):
def compute(self, data, bins_relative=1.0, trim_range=None, **kwargs) -> dict:
line = data.circular_average_q_bin(error=True, bins_relative=bins_relative)
if trim_range is not None:
line.trim(trim_range[0], trim_range[1])
return {'line': line}
def _save(self, results, data, output_dir, save_results=(), **run_args):
line = results['line']
if 'txt' in save_results:
line.save_data(self.get_outfile(data.name, output_dir, ext='.dat'))
if 'plots' in save_results:
line.plot(save=self.get_outfile(data.name, output_dir), **run_args)
Tasks
Not In Scope
- Modifying/renaming/deleting any existing protocol or code in
Protocols.py
- Breaking legacy batch processing interfaces
- Refactoring data source/result abstractions (separate issue)
Related
- Future: data source/result sink abstraction
- Future: composable protocol pipelines
This refactor will enable new use cases (APIs, GUIs, AI/auto-processing) without breaking existing scripts.
Background
Most data processing protocols in
SciAnalysis/XSAnalysis/Protocols.pycurrently intermix scientific computation and file I/O within theirrun()methods. While this works for legacy file-based batch processing, it limits future extensibility, such as:Re-engineering is needed to improve reusability and maintainability for modern applications.
Identified Problems
circular_average,SectorAverage,GraininessAnalysis, etc.) combine core calculations and all saving/plotting/export in the same function. This prevents using results in non-file-based workflows.output_direven if no files will be written.Proposed Solution
ProtocolsV2.py) that split the computation (pure in-memory results) from file I/O.Example:
CircularAverageTasks
ProtocolsV2.py(or equivalent module)ProtocolBaseclasscompute()(no file I/O)Not In Scope
Protocols.pyRelated
This refactor will enable new use cases (APIs, GUIs, AI/auto-processing) without breaking existing scripts.