Source code for MDMC.resolution.resolution_factory

"""A factory pattern for instantiating Resolution objects."""
import warnings
from functools import singledispatchmethod
from pathlib import Path
from typing import Any

from MDMC.common.factory import ModuleFactory
from MDMC.resolution.resolution import Resolution


[docs] class ResolutionFactory(ModuleFactory[Resolution]): """ Factory class for resolution window functions. Any function in `MDMC.resolution` s can be instantiated using this factory. """ registry: dict[str, Resolution] = {} curr_path = Path(__file__).parent curr_pack = __package__ exclude = (curr_path / "__init__.py", curr_path / "resolution_factory.py")
[docs] @classmethod def create_instance(cls, resolution: dict | float | str | None, *args: Any) -> Resolution: """ Create a Resolution object from a dictionary. Parameters ---------- resolution : dict, float, or str A parameter specifying the resolution. Should be a one-line dict giving the resolution type and parameters, e.g. a Lorentzian resolution with FWHM of 3 is specified {'lorentzian': 3.0}. If a float is given, resolution is assumed to be Gaussian with FWHM of that float. If a str is given, the string is assumed to be a file path to a vanadium run used to define a resolution. Returns ------- ~MDMC.resolution.Resolution A resolution object with the desired properties. """ resolution = cls._standardise_input(resolution) function_name = list(resolution.keys())[0].title() + 'Resolution' function_res = list(resolution.values())[0] if function_name == "FileResolution": return cls.create(function_name, function_res, *args) return cls.create(function_name, function_res)
@singledispatchmethod @staticmethod def _standardise_input(resolution) -> dict: """ Ensure that resolution is a one-line dictionary. Fixes 'lazy' input, e.g. if resolution was input as a string or number. Parameters ---------- resolution: Any The input to the resolution factory. Returns ------- dict If ``resolution`` is a dict, returns the first item of the dict. If ``resolution`` was a float, returns ``{'gaussian': resolution}`` If ``resolution`` was a string, returns ``{'file': resolution}`` Raises ------ NotImplementedError If ``resolution`` is not a dict, string or float. Warns ----- SyntaxWarning If ``resolution`` is a dict with multiple lines, or a float. """ raise NotImplementedError("Format of resolution function not recognised." " It should be a one-line dictionary, but can also" " be a number (for Gaussian resolution), a string" " (for resolution from file), or explicitly stated as" " None if resolution application is not needed.") @_standardise_input.register @staticmethod def _(resolution: dict) -> dict: if len(resolution) > 1: warnings.warn("The resolution dict should only have one line; ignoring" " all lines except the first." " Dictionaries are technically unordered, so" " this may cause unintended behaviour!", SyntaxWarning) res = {list(resolution.keys())[0]: list(resolution.values())[0]} else: res = resolution if list(resolution.keys())[0].lower() == "from_file": res = {"file": list(resolution.values())[0]} return res @_standardise_input.register @staticmethod def _(resolution: str) -> dict: return {'file': resolution} @_standardise_input.register(int) @_standardise_input.register(float) @staticmethod def _(resolution: float) -> dict: warnings.warn("Assuming energy resolution is Gaussian. To change this," " input energy resolution as {'function': 'value'}, where" " 'function' is your desired resolution approximation function.", SyntaxWarning) return {'gaussian': float(resolution)} @_standardise_input.register @staticmethod def _(resolution: None) -> dict: return {'null': 0}
ResolutionFactory.scan()