Source code for finchnmr.library
"""
Functions for defining a library of substances measured with HSQC NMR.
Authors: Nathan A. Mahynski, David A. Sheen
"""
import copy
import pickle
from . import substance
import numpy as np
from numpy.typing import NDArray
from typing import ClassVar
[docs]class Library:
"""Library of substances for fitting new unknowns."""
is_fitted_: ClassVar[bool]
_substances: ClassVar[list["substance.Substance"]]
_fit_to: "substance.Substance"
_X: ClassVar[NDArray[np.floating]]
def __init__(self, substances: list["substance.Substance"]) -> None:
"""
Instantiate the library.
Parameters
----------
substances : list(Substance)
List of substances in the library.
Example
-------
>>> substances = []
>>> head = '../../../spectra_directory/'
>>> for sample_ in os.listdir(head):
... pathname_ = os.path.join(
... os.path.abspath(
... os.path.join(
... head,
... sample_
... )
... ), 'pdata/1'
... )
>>> substances.append(finchnmr.substance.Substance(pathname_))
>>> L = finchnmr.library.Library(substances=substances)
"""
setattr(self, "_substances", substances)
setattr(self, "is_fitted_", False)
[docs] def fit(self, reference: "substance.Substance") -> "Library":
"""
Align all substances to another one which serves as a reference.
Parameters
----------
reference : Substance
Substance to align all substances in the library with (match extent, etc.).
Returns
-------
self
"""
aligned = []
for sub in self._substances:
aligned.append(sub.fit(reference).flatten())
setattr(self, "_X", np.array(aligned, dtype=np.float64).T)
setattr(self, "_fit_to", reference)
setattr(self, "is_fitted_", True)
return self
@property
def X(self) -> NDArray[np.floating]:
"""
Return a copy of the data in the library.
Returns
-------
X : ndarray(float, ndim=2)
This data is arranged in a 2D array, where each column is the flattened HSQC NMR spectrum of a different substance (row). The ordering follows that with which the library was instantiated.
Example
-------
>>> L = finchnmr.library.Library(substances=substances)
>>> L.fit(substance=new_compound)
>>> L.X
"""
if self.is_fitted_:
return self._X.copy()
else:
raise Exception(
"Library has not been fit to a reference substance yet."
)
[docs] def substance_by_index(self, idx: int) -> "substance.Substance":
"""
Retrieve a substance from the library by index.
Parameters
----------
idx : int
Index of the substance in the library.
Returns
-------
substance : Substance
Desired substance.
"""
return copy.copy(self._substances[idx])
[docs] def substance_by_name(self, name: str) -> "substance.Substance":
"""
Retrieve a substance from the library by name.
Parameters
----------
name : str
Name of the substance in the library.
Returns
-------
substance : Substance
Desired substance.
"""
for s in self._substances:
if s.name == name:
return copy.copy(s)
raise ValueError(f"No substance with name {name} in library.")
[docs] def save(self, filename: str) -> None:
"""
Pickle library to a file.
Parameters
----------
filename : str
Filename to write to.
"""
with open(filename, "wb") as f:
pickle.dump(self, f, protocol=4)