Merge branch 'develop' into lint/strict_ruff

This commit is contained in:
Justus Kuhlmann 2026-07-07 12:14:56 +02:00
commit f01f705af2
Signed by: jkuhl
GPG key ID: 00ED992DD79B85A6
11 changed files with 72 additions and 15 deletions

1
.gitignore vendored
View file

@ -6,3 +6,4 @@ test.ipynb
.venv .venv
.pytest_cache .pytest_cache
.coverage .coverage
build

9
LICENSE Normal file
View file

@ -0,0 +1,9 @@
MIT License
Copyright (c) 2026 Justus Kuhlmann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -71,6 +71,7 @@ def _create_config(path: Path, tracker: str, cached: bool) -> ConfigParser:
'db': 'backlogger.db', 'db': 'backlogger.db',
'projects_path': 'projects', 'projects_path': 'projects',
'archive_path': 'archive', 'archive_path': 'archive',
'plot_path': 'plots',
'toml_imports_path': 'toml_imports', 'toml_imports_path': 'toml_imports',
'import_scripts_path': 'import_scripts', 'import_scripts_path': 'import_scripts',
} }
@ -113,6 +114,7 @@ def create(path: Path, tracker: str = 'datalad', cached: bool = True) -> None:
os.chmod(path / config['paths']['db'], 0o666) os.chmod(path / config['paths']['db'], 0o666)
os.makedirs(path / config['paths']['projects_path']) os.makedirs(path / config['paths']['projects_path'])
os.makedirs(path / config['paths']['archive_path']) os.makedirs(path / config['paths']['archive_path'])
os.makedirs(path / config['paths']['plot_path'])
os.makedirs(path / config['paths']['toml_imports_path']) os.makedirs(path / config['paths']['toml_imports_path'])
os.makedirs(path / config['paths']['import_scripts_path'] / 'template.py') os.makedirs(path / config['paths']['import_scripts_path'] / 'template.py')
with open(path / ".gitignore", "w") as fp: with open(path / ".gitignore", "w") as fp:

View file

@ -4,8 +4,10 @@ import os
import fnmatch import fnmatch
from typing import Any, Optional from typing import Any, Optional
from pathlib import Path from pathlib import Path
import matplotlib.pyplot as plt
from ..pars.openQCD import ms1 from ..pars.openQCD import ms1
from ..pars.openQCD import qcd2 from ..pars.openQCD import qcd2
from ..tools import get_plot_dir
@ -29,6 +31,8 @@ def load_ms1_infile(path: Path, project: str, file_in_project: str) -> dict[str,
""" """
file = os.path.join(path, "projects", project, file_in_project) file = os.path.join(path, "projects", project, file_in_project)
if not os.path.exists(file):
raise IOError(f"File {file} does not exist.")
ds = os.path.join(path, "projects", project) ds = os.path.join(path, "projects", project)
dl.get(file, dataset=ds) dl.get(file, dataset=ds)
with open(file, 'r') as fp: with open(file, 'r') as fp:
@ -164,7 +168,7 @@ def read_rwms(path: Path, project: str, dir_in_project: str, param: dict[str, An
return rw_dict return rw_dict
def extract_t0(path: Path, project: str, dir_in_project: str, param: dict[str, Any], prefix: str, dtr_read: int, xmin: int, spatial_extent: int, fit_range: int = 5, postfix: str="", names: Optional[list[str]]=None, files: Optional[list[str]]=None, def extract_t0(path: Path, project: str, dir_in_project: str, ensemble: str, param: dict[str, Any], prefix: str, dtr_read: int, xmin: int, spatial_extent: int, fit_range: int = 5, postfix: str="", names: Optional[list[str]]=None, files: Optional[list[str]]=None,
r_start: list[int]=[], r_stop: list[int]=[], r_step:int=1) -> dict[str, Any]: r_start: list[int]=[], r_stop: list[int]=[], r_step:int=1) -> dict[str, Any]:
""" """
Extract t0 measurements from the project. Extract t0 measurements from the project.
@ -224,7 +228,7 @@ def extract_t0(path: Path, project: str, dir_in_project: str, param: dict[str, A
if not r_stop == []: if not r_stop == []:
kwargs['r_stop'] = r_stop kwargs['r_stop'] = r_stop
kwargs['r_step'] = r_step kwargs['r_step'] = r_step
kwargs['plot_fit'] = True
t0 = input.extract_t0(directory, t0 = input.extract_t0(directory,
prefix, prefix,
dtr_read, dtr_read,
@ -234,6 +238,10 @@ def extract_t0(path: Path, project: str, dir_in_project: str, param: dict[str, A
c=0.3, c=0.3,
**kwargs **kwargs
) )
plot_dir = path / get_plot_dir(path) / ensemble / project
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
plt.savefig(plot_dir / "t0.pdf")
par_list= [] par_list= []
for k in ["integrator", "eps", "ntot", "dnms"]: for k in ["integrator", "eps", "ntot", "dnms"]:
par_list.append(str(param[k])) par_list.append(str(param[k]))
@ -244,7 +252,7 @@ def extract_t0(path: Path, project: str, dir_in_project: str, param: dict[str, A
return t0_dict return t0_dict
def extract_t1(path: Path, project: str, dir_in_project: str, param: dict[str, Any], prefix: str, dtr_read: int, xmin: int, spatial_extent: int, fit_range: int = 5, postfix: str = "", names: Optional[list[str]]=None, files: Optional[list[str]]=None, def extract_t1(path: Path, project: str, dir_in_project: str, ensemble: str, param: dict[str, Any], prefix: str, dtr_read: int, xmin: int, spatial_extent: int, fit_range: int = 5, postfix: str = "", names: Optional[list[str]]=None, files: Optional[list[str]]=None,
r_start: list[int]=[], r_stop: list[int]=[], r_step:int=1) -> dict[str, Any]: r_start: list[int]=[], r_stop: list[int]=[], r_step:int=1) -> dict[str, Any]:
""" """
Extract t1 measurements from the project. Extract t1 measurements from the project.
@ -302,6 +310,7 @@ def extract_t1(path: Path, project: str, dir_in_project: str, param: dict[str, A
if not r_stop == []: if not r_stop == []:
kwargs['r_stop'] = r_stop kwargs['r_stop'] = r_stop
kwargs['r_step'] = r_step kwargs['r_step'] = r_step
kwargs['plot_fit'] = True
t0 = input.extract_t0(directory, t0 = input.extract_t0(directory,
prefix, prefix,
dtr_read, dtr_read,
@ -311,6 +320,10 @@ def extract_t1(path: Path, project: str, dir_in_project: str, param: dict[str, A
c=2./3, c=2./3,
**kwargs **kwargs
) )
plot_dir = path / get_plot_dir(path) / ensemble / project
if not os.path.exists(plot_dir):
os.makedirs(plot_dir)
plt.savefig(plot_dir / "t1.pdf")
par_list= [] par_list= []
for k in ["integrator", "eps", "ntot", "dnms"]: for k in ["integrator", "eps", "ntot", "dnms"]:
par_list.append(str(param[k])) par_list.append(str(param[k]))

View file

@ -258,7 +258,7 @@ def get_specs(key: str, parameters: dict[str, Any], sep: str = '/') -> str:
return s return s
def read_data(path: Path, project: str, dir_in_project: str, prefix: str, param: dict[str, Any], version: str = '1.0c', cfg_seperator: str = 'n', sep: str = '/', **kwargs: Any) -> dict[str, Any]: def read_data(path: Path, project: str, dir_in_project: str, prefix: str, param: dict[str, Any], version: str = '1.0c', cfg_separator: str = 'n', sep: str = '/', **kwargs: Any) -> dict[str, Any]:
""" """
Extract the data from the sfcf file. Extract the data from the sfcf file.
@ -274,7 +274,7 @@ def read_data(path: Path, project: str, dir_in_project: str, prefix: str, param:
The parameter dictionary, as given by read_param. The parameter dictionary, as given by read_param.
version: str version: str
Version of sfcf. Version of sfcf.
cfg_seperator: str cfg_separator: str
Separator of the configuration number. Needed for reading. default: "n" Separator of the configuration number. Needed for reading. default: "n"
sep: str sep: str
Seperator for the key in return dict. (default: "/) Seperator for the key in return dict. (default: "/)
@ -321,10 +321,10 @@ def read_data(path: Path, project: str, dir_in_project: str, prefix: str, param:
if not param['crr'] == []: if not param['crr'] == []:
if names is not None: if names is not None:
data_crr = pe.input.sfcf.read_sfcf_multi(directory, prefix, param['crr'], param['mrr'], corr_type_list, range(len(param['wf_offsets'])), data_crr = pe.input.sfcf.read_sfcf_multi(directory, prefix, param['crr'], param['mrr'], corr_type_list, range(len(param['wf_offsets'])),
range(len(param['wf_basis'])), range(len(param['wf_basis'])), version, cfg_seperator, keyed_out=True, silent=True, names=names) range(len(param['wf_basis'])), range(len(param['wf_basis'])), version, cfg_separator, keyed_out=True, silent=True, names=names)
else: else:
data_crr = pe.input.sfcf.read_sfcf_multi(directory, prefix, param['crr'], param['mrr'], corr_type_list, range(len(param['wf_offsets'])), data_crr = pe.input.sfcf.read_sfcf_multi(directory, prefix, param['crr'], param['mrr'], corr_type_list, range(len(param['wf_offsets'])),
range(len(param['wf_basis'])), range(len(param['wf_basis'])), version, cfg_seperator, keyed_out=True, silent=True) range(len(param['wf_basis'])), range(len(param['wf_basis'])), version, cfg_separator, keyed_out=True, silent=True)
for key in data_crr.keys(): for key in data_crr.keys():
data[key] = data_crr[key] data[key] = data_crr[key]

View file

@ -6,7 +6,7 @@ import json
from typing import Union from typing import Union
from pyerrors import Obs, Corr, dump_object, load_object from pyerrors import Obs, Corr, dump_object, load_object
from hashlib import sha256 from hashlib import sha256
from .tools import get_db_file, cache_enabled from .tools import get_db_file, cache_enabled, get_plot_dir
from .tracker import get, save, unlock from .tracker import get, save, unlock
import shutil import shutil
from typing import Any from typing import Any
@ -104,6 +104,8 @@ def write_measurement(path: Path, ensemble: str, measurement: dict[str, dict[str
subkeys.append(subkey) subkeys.append(subkey)
pars[subkey] = json.dumps(parameters["rw_fcts"][i]) pars[subkey] = json.dumps(parameters["rw_fcts"][i])
elif ms_type in ['t0', 't1']: elif ms_type in ['t0', 't1']:
plot_file = path / get_plot_dir(path) / ensemble / uuid / (ms_type + ".pdf")
files_to_save.append(plot_file)
if parameter_file is not None: if parameter_file is not None:
parameters = openQCD.load_ms3_infile(path, uuid, parameter_file) parameters = openQCD.load_ms3_infile(path, uuid, parameter_file)
else: else:

View file

@ -116,7 +116,7 @@ def check_measurement_data(measurements: dict[str, dict[str, str]], code: str) -
""" """
var_names: list[str] = [] var_names: list[str] = []
if code == "sfcf": if code == "sfcf":
var_names = ["path", "ensemble", "param_file", "version", "prefix", "cfg_seperator", "names"] var_names = ["path", "ensemble", "param_file", "version", "prefix", "cfg_separator", "names"]
elif code == "openQCD": elif code == "openQCD":
var_names = ["path", "ensemble", "measurement", "prefix"] # , "param_file" var_names = ["path", "ensemble", "measurement", "prefix"] # , "param_file"
for mname, md in measurements.items(): for mname, md in measurements.items():
@ -191,10 +191,10 @@ def import_toml(path: Path, file: str, copy_file: bool=True) -> None:
param = sfcf.read_param(path, uuid, md['param_file']) param = sfcf.read_param(path, uuid, md['param_file'])
if 'names' in md.keys(): if 'names' in md.keys():
measurement = sfcf.read_data(path, uuid, md['path'], md['prefix'], param, measurement = sfcf.read_data(path, uuid, md['path'], md['prefix'], param,
version=md['version'], cfg_seperator=md['cfg_seperator'], sep='/', names=md['names']) version=md['version'], cfg_separator=md['cfg_separator'], sep='/', names=md['names'])
else: else:
measurement = sfcf.read_data(path, uuid, md['path'], md['prefix'], param, measurement = sfcf.read_data(path, uuid, md['path'], md['prefix'], param,
version=md['version'], cfg_seperator=md['cfg_seperator'], sep='/') version=md['version'], cfg_separator=md['cfg_separator'], sep='/')
elif project['code'] == 'openQCD': elif project['code'] == 'openQCD':
if md['measurement'] == 'ms1': if md['measurement'] == 'ms1':
@ -229,14 +229,14 @@ def import_toml(path: Path, file: str, copy_file: bool=True) -> None:
for rwp in ["integrator", "eps", "ntot", "dnms"]: for rwp in ["integrator", "eps", "ntot", "dnms"]:
param[rwp] = "Unknown" param[rwp] = "Unknown"
param['type'] = 't0' param['type'] = 't0'
measurement = openQCD.extract_t0(path, uuid, md['path'], param, str(md["prefix"]), int(md["dtr_read"]), int(md["xmin"]), int(md["spatial_extent"]), measurement = openQCD.extract_t0(path, uuid, md['path'], ensemble, param, str(md["prefix"]), int(md["dtr_read"]), int(md["xmin"]), int(md["spatial_extent"]),
fit_range=int(md.get('fit_range', 5)), postfix=str(md.get('postfix', '')), names=md.get('names', []), files=md.get('files', []), fit_range=int(md.get('fit_range', 5)), postfix=str(md.get('postfix', '')), names=md.get('names', []), files=md.get('files', []),
r_start=md.get('r_start', []), r_stop=md.get('r_stop', []), r_step=md.get('r_step', 1)) r_start=md.get('r_start', []), r_stop=md.get('r_stop', []), r_step=md.get('r_step', 1))
elif md['measurement'] == 't1': elif md['measurement'] == 't1':
if 'param_file' in md: if 'param_file' in md:
param = openQCD.load_ms3_infile(path, uuid, md['param_file']) param = openQCD.load_ms3_infile(path, uuid, md['param_file'])
param['type'] = 't1' param['type'] = 't1'
measurement = openQCD.extract_t1(path, uuid, md['path'], param, str(md["prefix"]), int(md["dtr_read"]), int(md["xmin"]), int(md["spatial_extent"]), measurement = openQCD.extract_t1(path, uuid, md['path'], ensemble, param, str(md["prefix"]), int(md["dtr_read"]), int(md["xmin"]), int(md["spatial_extent"]),
fit_range=int(md.get('fit_range', 5)), postfix=str(md.get('postfix', '')), names=md.get('names', []), files=md.get('files', []), fit_range=int(md.get('fit_range', 5)), postfix=str(md.get('postfix', '')), names=md.get('names', []), files=md.get('files', []),
r_start=md.get('r_start', []), r_stop=md.get('r_stop', []), r_step=md.get('r_step', 1)) r_start=md.get('r_start', []), r_stop=md.get('r_stop', []), r_step=md.get('r_step', 1))
write_measurement(path, ensemble, measurement, uuid, project['code'], (md['param_file'] if 'param_file' in md else None)) write_measurement(path, ensemble, measurement, uuid, project['code'], (md['param_file'] if 'param_file' in md else None))

View file

@ -129,6 +129,33 @@ def get_db_file(path: Path) -> Path:
return db_file return db_file
def get_plot_dir(path: Path) -> Path:
"""
Get the plots directory associated with the library at the given path.
Parameters
----------
path: str
The path of the library.
Returns
-------
db_file: str
The file holding the database.
"""
path = Path(path)
if not os.path.exists(path):
raise FileNotFoundError(f"Corrlib path {path} does not exist.")
config_path = path / CONFIG_FILENAME
config = ConfigParser()
if os.path.exists(config_path):
config.read(config_path)
else:
raise FileNotFoundError("Configuration file not found.")
plot_dir = Path(config.get('paths', 'plot_dir', fallback='plots'))
return plot_dir
def cache_enabled(path: Path) -> bool: def cache_enabled(path: Path) -> bool:
""" """
Check, whether the library is cached. Check, whether the library is cached.

View file

@ -144,7 +144,7 @@ def clone(path: Path, source: str, target: str) -> None:
path = Path(path) path = Path(path)
tracker = get_tracker(path) tracker = get_tracker(path)
if tracker == 'datalad': if tracker == 'datalad':
dl.clone(target=target, source=source, dataset=path) dl.clone(path=target, source=source, dataset=path)
elif tracker == 'None': elif tracker == 'None':
os.makedirs(path, exist_ok=True) os.makedirs(path, exist_ok=True)
# Implement a simple clone by copying files # Implement a simple clone by copying files

View file

@ -11,6 +11,7 @@ dependencies = [
'pyerrors>=2.11.1', 'pyerrors>=2.11.1',
"datalad>=1.1.0", "datalad>=1.1.0",
'typer>=0.12.5', 'typer>=0.12.5',
"matplotlib>=3.10.7",
] ]
description = "Python correlation library" description = "Python correlation library"
authors = [ authors = [

2
uv.lock generated
View file

@ -409,6 +409,7 @@ source = { editable = "." }
dependencies = [ dependencies = [
{ name = "datalad" }, { name = "datalad" },
{ name = "gitpython" }, { name = "gitpython" },
{ name = "matplotlib" },
{ name = "pyerrors" }, { name = "pyerrors" },
{ name = "typer" }, { name = "typer" },
] ]
@ -427,6 +428,7 @@ dev = [
requires-dist = [ requires-dist = [
{ name = "datalad", specifier = ">=1.1.0" }, { name = "datalad", specifier = ">=1.1.0" },
{ name = "gitpython", specifier = ">=3.1.45" }, { name = "gitpython", specifier = ">=3.1.45" },
{ name = "matplotlib", specifier = ">=3.10.7" },
{ name = "pyerrors", specifier = ">=2.11.1" }, { name = "pyerrors", specifier = ">=2.11.1" },
{ name = "typer", specifier = ">=0.12.5" }, { name = "typer", specifier = ">=0.12.5" },
] ]