madman.utilities

Utilities.

  1r"""Utilities."""
  2
  3import os
  4import sys
  5from collections.abc import Sequence
  6from contextlib import contextmanager
  7from math import ceil
  8from numbers import Real
  9from typing import Optional
 10
 11import numpy as np
 12from ase.parallel import paropen
 13
 14
 15def process_path(path: Optional[str]) -> Optional[str]:
 16    r"""Process path, creating tree if needed.
 17
 18    Args:
 19        path: Path to process.
 20
 21    Returns:
 22        Processed path.
 23    """
 24    if path is None:
 25        return None
 26    path = str(path)
 27    pathd = os.path.dirname(path)
 28    if pathd != "":
 29        os.makedirs(pathd, exist_ok=True)
 30    return path
 31
 32
 33@contextmanager
 34def redirect_to(prefix: Optional[str], *, mode: str = "w") -> None:
 35    r"""Redirect standard output/error to file.
 36
 37    Args:
 38        prefix: Prefix for output and error files.
 39        mode: Writing mode.
 40    """
 41    stdout_old = sys.stdout
 42    stderr_old = sys.stderr
 43
 44    prefix = process_path(prefix)
 45    if prefix is not None:
 46        sys.stdout = paropen(f"{prefix}.out", mode)
 47        sys.stderr = paropen(f"{prefix}.err", mode)
 48
 49    try:
 50        yield
 51
 52    finally:
 53        sys.stdout = stdout_old
 54        sys.stderr = stderr_old
 55
 56
 57def gen_regular_grid(xa: Real, xb: Real, dx: Real) -> np.ndarray[float]:
 58    """Generate regular grid.
 59
 60    Args:
 61        xa: Minimum value.
 62        xb: Maximum value.
 63        dx: Target increment.
 64
 65    Returns:
 66        Regular grid.
 67    """
 68    ndx = (xb - xa) / dx
 69    nx = ceil(ndx) + (1 if ndx % 1 == 0.0 else 0)
 70    return np.linspace(xa, xb, nx)
 71
 72
 73def correlate1d(
 74    x: Sequence[Real, ...],
 75    y1: Sequence[Real, ...],
 76    y2: Sequence[Real, ...],
 77) -> np.ndarray[float]:
 78    r"""Correlate two 1d signals.
 79
 80    Args:
 81        x: Independent variable values.
 82        y1: First signal dependent variable values.
 83        y2: Second signal dependent variable values.
 84
 85    Returns:
 86        Correlation independent and dependent variable values.
 87
 88    Raises:
 89        ValueError: If independent variable is not equally spaced.
 90        ValueError: If independent variable has duplicate values.
 91    """
 92    x = np.asarray(x, dtype=float).flatten()
 93    y1 = np.asarray(y1, dtype=float).flatten()
 94    y2 = np.asarray(y2, dtype=float).flatten()
 95
 96    i = np.argsort(x)
 97    x = x[i]
 98    y1 = y1[i]
 99    y2 = y2[i]
100
101    if not np.array_equal(x, np.unique(x)):
102        raise ValueError("Duplicate independent variable values!")
103
104    dx = np.diff(x)
105    xn = len(dx)
106    dxm = np.mean(dx)
107    if not np.all(np.isclose(dx, dxm)):
108        raise ValueError("Independent variable not equally spaced!")
109
110    x = dxm * np.arange(-xn, xn + 1)
111    z = dxm * np.correlate(y2, y1, mode="full")
112    return x, z
def process_path(path: Optional[str]) -> Optional[str]:
16def process_path(path: Optional[str]) -> Optional[str]:
17    r"""Process path, creating tree if needed.
18
19    Args:
20        path: Path to process.
21
22    Returns:
23        Processed path.
24    """
25    if path is None:
26        return None
27    path = str(path)
28    pathd = os.path.dirname(path)
29    if pathd != "":
30        os.makedirs(pathd, exist_ok=True)
31    return path

Process path, creating tree if needed.

Arguments:
  • path: Path to process.
Returns:

Processed path.

@contextmanager
def redirect_to(prefix: Optional[str], *, mode: str = 'w') -> None:
34@contextmanager
35def redirect_to(prefix: Optional[str], *, mode: str = "w") -> None:
36    r"""Redirect standard output/error to file.
37
38    Args:
39        prefix: Prefix for output and error files.
40        mode: Writing mode.
41    """
42    stdout_old = sys.stdout
43    stderr_old = sys.stderr
44
45    prefix = process_path(prefix)
46    if prefix is not None:
47        sys.stdout = paropen(f"{prefix}.out", mode)
48        sys.stderr = paropen(f"{prefix}.err", mode)
49
50    try:
51        yield
52
53    finally:
54        sys.stdout = stdout_old
55        sys.stderr = stderr_old

Redirect standard output/error to file.

Arguments:
  • prefix: Prefix for output and error files.
  • mode: Writing mode.
def gen_regular_grid( xa: numbers.Real, xb: numbers.Real, dx: numbers.Real) -> numpy.ndarray[float]:
58def gen_regular_grid(xa: Real, xb: Real, dx: Real) -> np.ndarray[float]:
59    """Generate regular grid.
60
61    Args:
62        xa: Minimum value.
63        xb: Maximum value.
64        dx: Target increment.
65
66    Returns:
67        Regular grid.
68    """
69    ndx = (xb - xa) / dx
70    nx = ceil(ndx) + (1 if ndx % 1 == 0.0 else 0)
71    return np.linspace(xa, xb, nx)

Generate regular grid.

Arguments:
  • xa: Minimum value.
  • xb: Maximum value.
  • dx: Target increment.
Returns:

Regular grid.

def correlate1d( x: collections.abc.Sequence[numbers.Real, ...], y1: collections.abc.Sequence[numbers.Real, ...], y2: collections.abc.Sequence[numbers.Real, ...]) -> numpy.ndarray[float]:
 74def correlate1d(
 75    x: Sequence[Real, ...],
 76    y1: Sequence[Real, ...],
 77    y2: Sequence[Real, ...],
 78) -> np.ndarray[float]:
 79    r"""Correlate two 1d signals.
 80
 81    Args:
 82        x: Independent variable values.
 83        y1: First signal dependent variable values.
 84        y2: Second signal dependent variable values.
 85
 86    Returns:
 87        Correlation independent and dependent variable values.
 88
 89    Raises:
 90        ValueError: If independent variable is not equally spaced.
 91        ValueError: If independent variable has duplicate values.
 92    """
 93    x = np.asarray(x, dtype=float).flatten()
 94    y1 = np.asarray(y1, dtype=float).flatten()
 95    y2 = np.asarray(y2, dtype=float).flatten()
 96
 97    i = np.argsort(x)
 98    x = x[i]
 99    y1 = y1[i]
100    y2 = y2[i]
101
102    if not np.array_equal(x, np.unique(x)):
103        raise ValueError("Duplicate independent variable values!")
104
105    dx = np.diff(x)
106    xn = len(dx)
107    dxm = np.mean(dx)
108    if not np.all(np.isclose(dx, dxm)):
109        raise ValueError("Independent variable not equally spaced!")
110
111    x = dxm * np.arange(-xn, xn + 1)
112    z = dxm * np.correlate(y2, y1, mode="full")
113    return x, z

Correlate two 1d signals.

Arguments:
  • x: Independent variable values.
  • y1: First signal dependent variable values.
  • y2: Second signal dependent variable values.
Returns:

Correlation independent and dependent variable values.

Raises:
  • ValueError: If independent variable is not equally spaced.
  • ValueError: If independent variable has duplicate values.