import logging
import sqlite3
from pathlib import Path
from typing import ClassVar, Optional
logger = logging.getLogger(__name__)
[docs]
class Database:
"""Interface to quantum defects SQL database."""
_global_instance: ClassVar[Optional["Database"]] = None
def __init__(self, database_file: Optional[str] = None) -> None:
"""Initialize database connection.
Args:
database_file: Optional path to SQLite database file. If None, use the default
database.sql in the same directory as this file.
"""
if database_file is None:
database_file = str(Path(__file__).parent / "database.sql")
self.conn = sqlite3.connect(":memory:")
with Path(database_file).open() as f:
self.conn.executescript(f.read())
[docs]
@classmethod
def get_global_instance(cls) -> "Database":
"""Return the global database instance."""
if cls._global_instance is None:
cls._global_instance = cls()
return cls._global_instance
[docs]
@classmethod
def set_global_instance(cls, instance: "Database") -> None:
"""Set the global database instance."""
cls._global_instance = instance
[docs]
def get_model_potential_parameters(
self, species: str, l: int
) -> tuple[float, int, float, float, float, float, float]:
"""Get model potential parameters.
Args:
species: Atomic species
l: Angular momentum quantum number
Returns:
The model potential parameters for the given species and l, i.e.:
ac, Z, a1, a2, a3, a4, rc
If no match is found for l, returns parameters for largest available l.
"""
cursor = self.conn.execute("SELECT * FROM model_potential WHERE species=? AND l=?", (species, l))
row = cursor.fetchone()
if row is None:
cursor = self.conn.execute("SELECT * FROM model_potential WHERE species=? ORDER BY l DESC", (species,))
row = cursor.fetchone()
if row is None:
raise ValueError(f"No model potential parameters found for {species}")
logger.debug(
"No model potential parameters found for %s with l=%d, using values for largest l=%d instead",
*(species, l, row[1]),
)
return float(row[2]), int(row[3]), float(row[4]), float(row[5]), float(row[6]), float(row[7]), float(row[8])
[docs]
def get_quantum_defect_parameters(
self, species: str, l: int, j: float
) -> tuple[float, float, float, float, float, float]:
"""Get Rydberg-Ritz parameters.
Args:
species: Atomic species
l: Angular momentum quantum number
j: Total angular momentum quantum number
Returns:
The quantum defect parameters for the given species, l and j, i.e.:
d0, d2, d4, d6, d8, Ry
If no match is found for l and j, returns d_i = 0 and the normal Ry.
"""
cursor = self.conn.execute("SELECT * FROM rydberg_ritz WHERE species=? AND l=? AND j=?", (species, l, j))
row = cursor.fetchone()
if row is None:
cursor = self.conn.execute("SELECT * FROM rydberg_ritz WHERE species=? ORDER BY l DESC, j DESC", (species,))
row = cursor.fetchone()
if row is None:
raise ValueError(f"No Rydberg-Ritz parameters found for {species}")
row = (row[0], row[1], row[2], 0.0, 0.0, 0.0, 0.0, 0.0, row[8])
logger.debug(
"No Rydberg-Ritz parameters found for %s with l=%d and j=%d, returning zero quantum defects.",
*(species, l, j),
)
return row[3], row[4], row[5], row[6], row[7], row[8]
def __del__(self) -> None:
"""Close database connection on object deletion."""
self.conn.close()