Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 46 additions & 22 deletions pyaml/magnet/csvcurve.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,75 @@
from pathlib import Path

import numpy as np
from pydantic import BaseModel, ConfigDict
from numpy.typing import NDArray

from ..common.element import __pyaml_repr__
from ..common.exception import PyAMLException
from ..configuration.fileloader import ROOT
from ..validation import DynamicValidation, register_schema
from .curve import Curve

# Define the main class name for this module
PYAMLCLASS = "CSVCurve"


class ConfigModel(BaseModel):
@register_schema
class CSVCurve(Curve, DynamicValidation):
"""
Configuration model for CSV curve
Curve loaded from a CSV file.

Parameters
----------
file : str
CSV file that contains the curve (n rows, 2 columns)
"""
This class reads a CSV file containing a two-column numeric dataset
representing ``(x, y)`` coordinate pairs. The file is loaded during
initialization and stored internally as a NumPy array.

model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid")
The CSV file must:

file: str
- contain exactly two columns,
- use commas as the delimiter,
- contain values that can be converted to ``float``.

Parameters
----------
file : str
Path to the CSV file. Relative paths are resolved using the
project's configured root directory.

class CSVCurve(Curve):
"""
Class for load CSV (x,y) curve
Attributes
----------
file : str
Path to the CSV file provided during initialization.

Raises
------
PyAMLException
If the file cannot be parsed as a numeric CSV or if the loaded
data does not have shape ``(n, 2)``.

Notes
-----
The loaded curve is stored internally as a NumPy array with shape
``(n, 2)``, where the first column contains x-values and the second
column contains y-values. The data can be accessed using
:meth:`get_curve`.
"""

def __init__(self, cfg: ConfigModel):
self._cfg = cfg
def __init__(self, file: str):
self._file = file

# Load CSV curve
path = ROOT.expand_path(cfg.file)
path = ROOT.expand_path(self._file)
try:
self._curve = np.genfromtxt(path, delimiter=",", dtype=float, loose=False)
except ValueError as e:
raise PyAMLException(f"CSVCurve(file='{cfg.file}',dtype=float): {str(e)}") from None
raise PyAMLException(f"CSVCurve(file='{self._file}',dtype=float): {str(e)}") from None

_s = np.shape(self._curve)
if len(_s) != 2 or _s[1] != 2:
raise PyAMLException(f"CSVCurve(file='{cfg.file}',dtype=float):wrong shape (2,2) expected but got {str(_s)}")
raise PyAMLException(f"CSVCurve(file='{self._file}',dtype=float):wrong shape (2,2) expected but got {str(_s)}")

@property
def file(self):
return self._file

def get_curve(self) -> np.array:
def get_curve(self) -> NDArray[np.float64]:
"""
Get the curve data.

Expand All @@ -57,4 +81,4 @@ def get_curve(self) -> np.array:
return self._curve

def __repr__(self):
return repr(self._cfg).replace("ConfigModel", self.__class__.__name__)
return __pyaml_repr__(self)
47 changes: 26 additions & 21 deletions pyaml/magnet/csvmatrix.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,51 @@
from pathlib import Path

import numpy as np
from pydantic import BaseModel, ConfigDict
from numpy.typing import NDArray

from ..common.element import __pyaml_repr__
from ..common.exception import PyAMLException
from ..configuration.fileloader import ROOT
from ..validation import DynamicValidation, register_schema
from .matrix import Matrix

# Define the main class name for this module
PYAMLCLASS = "CSVMatrix"


class ConfigModel(BaseModel):
@register_schema
class CSVMatrix(Matrix, DynamicValidation):
"""
Configuration model for CSV matrix
Matrix loaded from a CSV file.

This class reads a CSV file containing numeric values and stores the
resulting matrix as a NumPy array.

Parameters
----------
file : str
CSV file that contains the matrix
"""

model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid")

file: str
Path to the CSV file. Relative paths are resolved using the
project's configured root directory.


class CSVMatrix(Matrix):
"""
Class for loading CSV matrix
Raises
------
PyAMLException
If the CSV file cannot be parsed as a numeric array.
"""

def __init__(self, cfg: ConfigModel):
self._cfg = cfg
def __init__(self, file: str):
self._file = file

# Load CSV matrix
path = ROOT.expand_path(cfg.file)
path = ROOT.expand_path(self._file)
try:
self._mat = np.genfromtxt(path, delimiter=",", dtype=float, loose=False)
except ValueError as e:
raise PyAMLException(f"CSVMatrix(file='{cfg.file}',dtype=float): {str(e)}") from None
raise PyAMLException(f"CSVMatrix(file='{self._file}',dtype=float): {str(e)}") from None

@property
def file(self):
return self._file

def get_matrix(self) -> np.array:
def get_matrix(self) -> NDArray[np.float64]:
"""
Get the matrix data.

Expand All @@ -52,4 +57,4 @@ def get_matrix(self) -> np.array:
return self._mat

def __repr__(self):
return repr(self._cfg).replace("ConfigModel", self.__class__.__name__)
return __pyaml_repr__(self)
49 changes: 28 additions & 21 deletions pyaml/magnet/inline_curve.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,52 @@
from pathlib import Path

import numpy as np
from pydantic import BaseModel, ConfigDict
from numpy.typing import NDArray

from ..common.element import __pyaml_repr__
from ..common.exception import PyAMLException
from ..validation import DynamicValidation, register_schema
from .curve import Curve

# Define the main class name for this module
PYAMLCLASS = "InlineCurve"


class ConfigModel(BaseModel):
@register_schema
class InlineCurve(Curve, DynamicValidation):
"""
Configuration model for inline curve
Curve defined directly from an in-memory matrix of (x, y) points.

This class stores curve data provided as a list of rows, where each row must
contain exactly two values: the x-coordinate and the y-coordinate. The data is
converted to a NumPy array and validated to ensure it has shape ``(n, 2)``.

Parameters
----------
mat : list[list[float]]
Curve data (n rows, 2 columns)
Curve data as a two-column matrix. Each row represents one point in the
curve, with ``mat[i][0]`` being the x-value and ``mat[i][1]`` being the
y-value.

Raises
------
PyAMLException
If the provided matrix does not have two columns.
"""

model_config = ConfigDict(arbitrary_types_allowed=True, extra="forbid")

mat: list[list[float]]

def __init__(self, mat: list[list[float]]):
self._mat = mat

class InlineCurve(Curve):
"""
Class for load CSV (x,y) curve
"""

def __init__(self, cfg: ConfigModel):
self._cfg = cfg
# Load the curve
self._curve = np.array(self._cfg.mat)
self._curve = np.array(self._mat)

_s = np.shape(self._curve)
if len(_s) != 2 or _s[1] != 2:
raise PyAMLException(f"InlineCurve(mat='{cfg.mat}',dtype=float): wrong shape (2,2) expected but got {str(_s)}")
raise PyAMLException(f"InlineCurve(mat='{self._mat}',dtype=float): wrong shape (2,2) expected but got {str(_s)}")

@property
def mat(self):
return self._mat

def get_curve(self) -> np.array:
def get_curve(self) -> NDArray[np.float64]:
"""
Get the curve data.

Expand All @@ -51,4 +58,4 @@ def get_curve(self) -> np.array:
return self._curve

def __repr__(self):
return repr(self._cfg).replace("ConfigModel", self.__class__.__name__)
return __pyaml_repr__(self)
3 changes: 1 addition & 2 deletions pyaml/magnet/linear_serialized_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from ..common.exception import PyAMLException
from ..control.deviceaccess import DeviceAccess
from .curve import Curve
from .inline_curve import ConfigModel as InlineCurveModel
from .inline_curve import InlineCurve
from .linear_model import ConfigModel as LinearConfigModel
from .linear_model import LinearMagnetModel
Expand Down Expand Up @@ -122,7 +121,7 @@ def __initialize(self):
else:
self.__curves: list[Curve] = []
for _ in range(self.__nbMagnets):
curve = InlineCurve(InlineCurveModel(mat=self._cfg.curves.get_curve()))
curve = InlineCurve(mat=self._cfg.curves.get_curve())
self.__curves.append(curve)

_check_len(self.__calibration_factors, "calibration_factors", self.__nbMagnets)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import numpy as np

from pyaml.configuration import ROOT
from pyaml.magnet.csvcurve import ConfigModel, CSVCurve
from pyaml.magnet.csvcurve import CSVCurve
from pyaml.magnet.curve import Curve


def curve_test(file: str, current: float, strength: float):
curveConfig = ConfigModel(file=file)
curve = CSVCurve(curveConfig)
curve = CSVCurve(file=file)
curveData = curve.get_curve()
icurveData = Curve.inverse(curveData)
x1 = np.interp(current, curveData[:, 0], curveData[:, 1])
Expand Down
Loading