fab.magic
Automagic configuration and beamtime loading.
This module provides a convenient way to quickly set up the analyis
environment. It makes some assumptions on how you use fab
. If you prefer a more structured
setup or finer control over the configuration process, please refer to the fab.settings
,
fab.instruments
and fab.beamtime
modules.
There are three main actions that you can access from this module:
- Setting the configuration file
- Defining the beamtime and loading beamtime metadata
- Loading an instrument
If you are using multiple actions, the order of the actions is important. The configuration file should be set first, then the beamtime and finally the instrument imoprt.
Setting the configuration file
With the statement from fab.magic import config
, fab
will try to load a configuration file
from the current directory or any of its parent directories. The file name should match
fab_config*.toml
. E.g. fab_config.toml
and fab_config_musix.toml
are valid names.
Defining the beamtime and loading beamtime metadata
With the statement from fab.magic import beamtime
, fab
will try to load a beamtime object
giving access to the beamtime metadata created with the fablive
library. If no beamtime number
is provided in the configuration file, fab
will try to autodetect it from the current directory.
Loading an instrument
With the statement from fab.magic import <instrument>
, fab
will import and instantiate the
corresponding instrument as defined in the loaded configuration file.
Qiuckstart
In most cases, you will be running your analyis from within the beamtime folder (e.g. the
/shared/ directory on maxwell). In this case, you can simply create a fab_config.toml
file
in your working directory (or it's parent directories) and then simply use:
from fab.magic import config, beamtime, <instrument>
That's it! You can now access the configuration, the beamtime metadata and the instrument.
To load data, you can use the load
method of the instrument. For an instrument named musix,
this would look like:
from fab.magic import config, beamtime, musix
run = musix.load()
1""" 2Automagic configuration and beamtime loading. 3 4This module provides a convenient way to quickly set up the analyis 5environment. It makes some assumptions on how you use `fab`. If you prefer a more structured 6setup or finer control over the configuration process, please refer to the `fab.settings`, 7`fab.instruments` and `fab.beamtime` modules. 8 9There are three main actions that you can access from this module: 10- Setting the configuration file 11- Defining the beamtime and loading beamtime metadata 12- Loading an instrument 13 14If you are using multiple actions, the order of the actions is important. 15The configuration file should be set first, then the beamtime and finally the instrument imoprt. 16 17### Setting the configuration file 18With the statement `from fab.magic import config`, `fab` will try to load a configuration file 19from the current directory or any of its parent directories. The file name should match 20`fab_config*.toml`. E.g. `fab_config.toml` and `fab_config_musix.toml` are valid names. 21 22### Defining the beamtime and loading beamtime metadata 23With the statement `from fab.magic import beamtime`, `fab` will try to load a beamtime object 24giving access to the beamtime metadata created with the `fablive` library. If no beamtime number 25is provided in the configuration file, `fab` will try to autodetect it from the current directory. 26 27### Loading an instrument 28With the statement `from fab.magic import <instrument>`, `fab` will import and instantiate the 29corresponding instrument as defined in the loaded configuration file. 30 31## Qiuckstart 32In most cases, you will be running your analyis from within the beamtime folder (e.g. the 33/shared/ directory on maxwell). In this case, you can simply create a `fab_config.toml` file 34in your working directory (or it's parent directories) and then simply use: 35 36```python 37from fab.magic import config, beamtime, <instrument> 38``` 39 40That's it! You can now access the configuration, the beamtime metadata and the instrument. 41To load data, you can use the `load` method of the instrument. For an instrument named musix, 42this would look like: 43 44```python 45from fab.magic import config, beamtime, musix 46 47run = musix.load() 48``` 49""" 50import importlib 51import sys 52from pathlib import Path 53 54from .instruments import Instrument 55from .settings import cfg, update_context, update_config, maxwell_start_if_not_already 56from .beamtime import Beamtime, autodetect_beamtime, beamtime_basepath 57 58import logging 59logger = logging.getLogger(__name__) 60tele_log = logging.getLogger('fab.telemetry') 61 62 63 64 65def _find_upwards(cwd: Path, glob_pattern: str) -> Path | None: 66 """ Recursively search a file pattern in all parent directories. """ 67 if cwd == Path(cwd.root) or cwd == cwd.parent: 68 return None 69 70 try: 71 return list(cwd.glob(glob_pattern))[0] 72 except IndexError: 73 return _find_upwards(cwd.parent, glob_pattern) 74 75def _magic_config(): 76 """ Attemps to load the config from one of the parent directories. 77 The file name should match 'fab_config*.toml'. 78 79 E.g. fab_config.toml and fab_config_musix.toml are valid names. 80 Starting from the current directioy, the function will search 81 for the config file in the current directory and all parent directories. 82 """ 83 tele_log.info("Magic config") 84 85 config_file = _find_upwards(Path.cwd(), "fab_config*.toml") 86 if not config_file: 87 raise FileNotFoundError("Could not autodetect any matching config file") 88 89 update_config(config_file) 90 return cfg 91 92def _magic_beamtime(): 93 """ Return a beamtime object corresponding to the current configured beamtime. 94 If no beamtime is configured, try to autodetect it from the current directory. 95 96 """ 97 tele_log.info("Magic beamtime") 98 99 if not cfg.beamtime: 100 logger.debug("No beamtime configured. Attempting to autodetect it...") 101 beamtime = autodetect_beamtime() 102 cfg['beamtime'] = beamtime 103 104 return Beamtime(cfg.beamtime) 105 106def __getattr__(name): 107 logger.debug(f"Magic config: {name}") 108 109 match name: 110 case "__path__": 111 raise AttributeError 112 113 case 'config': 114 return _magic_config() 115 116 case 'beamtime': 117 return _magic_beamtime() 118 119 case _: 120 pass 121 122 # If loading an instrument, make sure that the dask cluster is running 123 # and that a beamtime is set 124 maxwell_start_if_not_already() 125 126 try: 127 return Instrument.from_name(name) 128 except Exception as e: 129 logger.exception(e) 130 raise AttributeError from e 131 132 return None