# Path: flare/utils/learner.py
# def get_max_cutoff(cell: np.ndarray) -> float:
#     """Compute the maximum cutoff compatible with a 3x3x3 supercell of a
#         structure. Called in the Structure constructor when
#         setting the max_cutoff attribute, which is used to create local
#         environments with arbitrarily large cutoff radii.
# 
#     Args:
#         cell (np.ndarray): Bravais lattice vectors of the structure stored as
#             rows of a 3x3 Numpy array.
# 
#     Returns:
#         float: Maximum cutoff compatible with a 3x3x3 supercell of the
#             structure.
#     """
# 
#     # Retrieve the lattice vectors.
#     a_vec = cell[0]
#     b_vec = cell[1]
#     c_vec = cell[2]
# 
#     # Compute dot products and norms of lattice vectors.
#     a_dot_b = np.dot(a_vec, b_vec)
#     a_dot_c = np.dot(a_vec, c_vec)
#     b_dot_c = np.dot(b_vec, c_vec)
# 
#     a_norm = np.linalg.norm(a_vec)
#     b_norm = np.linalg.norm(b_vec)
#     c_norm = np.linalg.norm(c_vec)
# 
#     # Compute the six independent altitudes of the cell faces.
#     # The smallest is the maximum atomic environment cutoff that can be
#     # used with sweep=1.
#     max_candidates = np.zeros(6)
#     max_candidates[0] = a_norm * np.sqrt(1 - (a_dot_b / (a_norm * b_norm)) ** 2)
#     max_candidates[1] = b_norm * np.sqrt(1 - (a_dot_b / (a_norm * b_norm)) ** 2)
#     max_candidates[2] = a_norm * np.sqrt(1 - (a_dot_c / (a_norm * c_norm)) ** 2)
#     max_candidates[3] = c_norm * np.sqrt(1 - (a_dot_c / (a_norm * c_norm)) ** 2)
#     max_candidates[4] = b_norm * np.sqrt(1 - (b_dot_c / (b_norm * c_norm)) ** 2)
#     max_candidates[5] = c_norm * np.sqrt(1 - (b_dot_c / (b_norm * c_norm)) ** 2)
# 
#     return np.min(max_candidates)


import os
import sys
import inspect
import numpy as np
from time import time
from copy import deepcopy
from ase import Atoms
from ase.io import read, write
from flare.utils.learner import get_max_cutoff

    @property
    def stress(self):
        return self.get_stress()

    @property
    def stress_stds(self):
        return None  # TODO: to implement

    @property
    def local_energy_stds(self):
        return None  # TODO: to implement

    @property
    def stds(self):
        try:  # when self.calc is not FLARE, there's no get_uncertainties()
            stds = self.calc.results["stds"]
        except:
            stds = np.zeros_like(self.positions)
        return stds

    def wrap_positions(self):
        return self.get_positions(wrap=True)

    @property
    def wrapped_positions(self):
        return self.get_positions(wrap=True)

    @property
    def max_cutoff(self):

# Path: flare/utils/learner.py
# def get_max_cutoff(cell: np.ndarray) -> float:
#     """Compute the maximum cutoff compatible with a 3x3x3 supercell of a
#         structure. Called in the Structure constructor when
#         setting the max_cutoff attribute, which is used to create local
#         environments with arbitrarily large cutoff radii.
# 
#     Args:
#         cell (np.ndarray): Bravais lattice vectors of the structure stored as
#             rows of a 3x3 Numpy array.
# 
#     Returns:
#         float: Maximum cutoff compatible with a 3x3x3 supercell of the
#             structure.
#     """
# 
#     # Retrieve the lattice vectors.
#     a_vec = cell[0]
#     b_vec = cell[1]
#     c_vec = cell[2]
# 
#     # Compute dot products and norms of lattice vectors.
#     a_dot_b = np.dot(a_vec, b_vec)
#     a_dot_c = np.dot(a_vec, c_vec)
#     b_dot_c = np.dot(b_vec, c_vec)
# 
#     a_norm = np.linalg.norm(a_vec)
#     b_norm = np.linalg.norm(b_vec)
#     c_norm = np.linalg.norm(c_vec)
# 
#     # Compute the six independent altitudes of the cell faces.
#     # The smallest is the maximum atomic environment cutoff that can be
#     # used with sweep=1.
#     max_candidates = np.zeros(6)
#     max_candidates[0] = a_norm * np.sqrt(1 - (a_dot_b / (a_norm * b_norm)) ** 2)
#     max_candidates[1] = b_norm * np.sqrt(1 - (a_dot_b / (a_norm * b_norm)) ** 2)
#     max_candidates[2] = a_norm * np.sqrt(1 - (a_dot_c / (a_norm * c_norm)) ** 2)
#     max_candidates[3] = c_norm * np.sqrt(1 - (a_dot_c / (a_norm * c_norm)) ** 2)
#     max_candidates[4] = b_norm * np.sqrt(1 - (b_dot_c / (b_norm * c_norm)) ** 2)
#     max_candidates[5] = c_norm * np.sqrt(1 - (b_dot_c / (b_norm * c_norm)) ** 2)
# 
#     return np.min(max_candidates)


# Path: flare/ase/atoms.py
import os
import sys
import inspect
import numpy as np
from time import time
from copy import deepcopy
from ase import Atoms
from ase.io import read, write
from flare.utils.learner import get_max_cutoff


    @property
    def stress(self):
        return self.get_stress()

    @property
    def stress_stds(self):
        return None  # TODO: to implement

    @property
    def local_energy_stds(self):
        return None  # TODO: to implement

    @property
    def stds(self):
        try:  # when self.calc is not FLARE, there's no get_uncertainties()
            stds = self.calc.results["stds"]
        except:
            stds = np.zeros_like(self.positions)
        return stds

    def wrap_positions(self):
        return self.get_positions(wrap=True)

    @property
    def wrapped_positions(self):
        return self.get_positions(wrap=True)

    @property
    def max_cutoff(self):

        return get_max_cutoff(self.cell)