Skip to content

Commit 4c632db

Browse files
committed
Revert "Remove fitsnap"
1 parent de4cc16 commit 4c632db

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

.ci_support/environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ dependencies:
1212
- pyiron-data =0.0.25
1313
- pyparsing =3.1.1
1414
- scipy =1.11.4
15+
- fitsnap3 =3.1.0.4
1516
- pip:
1617
- runnerase==0.3.3

pyiron_potentialfit/fitsnap/__init__.py

Whitespace-only changes.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import numpy as np
2+
from fitsnap3lib.scrapers.ase_funcs import get_apre, create_shared_arrays
3+
4+
5+
def calc_bispectrum_names(twojmax):
6+
lst = []
7+
for j1 in range(0, twojmax + 1):
8+
for j2 in range(0, j1 + 1):
9+
for j in range(j1 - j2, min(twojmax, j1 + j2) + 1, 2):
10+
if j >= j1:
11+
lst.append([j1 / 2.0, j2 / 2.0, j / 2.0])
12+
return lst
13+
14+
15+
def ase_scraper(
16+
s, frames, energies, forces, stresses=[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
17+
):
18+
"""
19+
Custom function to allocate shared arrays used in Calculator and build the internal list of
20+
dictionaries `data` of configuration info. Customized version of `fitsnap3lib.scrapers.ase_funcs`.
21+
22+
Args:
23+
s: fitsnap instance.
24+
frames: list or array of ASE atoms objects.
25+
energies: array of energies.
26+
forces: array of forces for all configurations.
27+
stresses: array of stresses for all configurations.
28+
29+
Creates a list of data dictionaries `s.data` suitable for fitsnap descriptor calculation.
30+
If running in parallel, this list will be distributed over procs, so that each proc will have a
31+
portion of the list.
32+
"""
33+
34+
create_shared_arrays(s, frames)
35+
s.data = [
36+
collate_data(a, e, f, s)
37+
for (a, e, f, s) in zip(frames, energies, forces, stresses)
38+
]
39+
40+
41+
def collate_data(atoms, energy, forces, stresses):
42+
"""
43+
Function to organize fitting data for FitSNAP from ASE atoms objects.
44+
45+
Args:
46+
atoms: ASE atoms object for a single configuration of atoms.
47+
energy: energy of a configuration.
48+
forces: numpy array of forces for a configuration.
49+
stresses: numpy array of stresses for a configuration.
50+
51+
Returns a fitsnap data dictionary for a single configuration.
52+
"""
53+
54+
# make a data dictionary for this config
55+
56+
apre = get_apre(cell=atoms.cell)
57+
R = np.dot(np.linalg.inv(atoms.cell), apre)
58+
59+
positions = np.matmul(atoms.get_positions(), R)
60+
cell = apre.T
61+
62+
data = {}
63+
data["PositionsStyle"] = "angstrom"
64+
data["AtomTypeStyle"] = "chemicalsymbol"
65+
data["StressStyle"] = "bar"
66+
data["LatticeStyle"] = "angstrom"
67+
data["EnergyStyle"] = "electronvolt"
68+
data["ForcesStyle"] = "electronvoltperangstrom"
69+
data["Group"] = "Displaced_BCC"
70+
data["File"] = None
71+
data["Stress"] = stresses
72+
data["Positions"] = positions
73+
data["Energy"] = energy
74+
data["AtomTypes"] = atoms.get_chemical_symbols()
75+
data["NumAtoms"] = len(atoms)
76+
data["Forces"] = forces
77+
data["QMLattice"] = cell
78+
data["test_bool"] = 0
79+
data["Lattice"] = cell
80+
data["Rotation"] = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
81+
data["Translation"] = np.zeros((len(atoms), 3))
82+
data["eweight"] = 1.0
83+
data["fweight"] = 1.0 / 150.0
84+
data["vweight"] = 0.0
85+
86+
return data
87+
88+
89+
def subsample_twojmax(total_bispect, twojmax_lst):
90+
bi_spect_names_str_lst = [str(lst) for lst in total_bispect]
91+
twojmax_master_str_lst = [
92+
[str(lst) for lst in calc_bispectrum_names(twojmax=tjm)] for tjm in twojmax_lst
93+
]
94+
ind_lst = [
95+
[desc in desc_lst for desc in bi_spect_names_str_lst]
96+
for desc_lst in twojmax_master_str_lst
97+
]
98+
return ind_lst

pyiron_potentialfit/fitsnap/job.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from mpi4py import MPI
2+
from fitsnap3lib.fitsnap import FitSnap
3+
from pyiron_base import PythonTemplateJob, DataContainer
4+
from pyiron_potentialfit.fitsnap.common import ase_scraper
5+
6+
7+
default_input = settings = {
8+
"BISPECTRUM": {
9+
"numTypes": 1,
10+
"twojmax": 8,
11+
"rcutfac": 4.812302818,
12+
"rfac0": 0.99363,
13+
"rmin0": 0.0,
14+
"wj": 1.0,
15+
"radelem": 0.5,
16+
"type": "Be",
17+
"wselfallflag": 0,
18+
"chemflag": 0,
19+
"bzeroflag": 0,
20+
"quadraticflag": 0,
21+
},
22+
"CALCULATOR": {
23+
"calculator": "LAMMPSSNAP",
24+
"energy": 1, # Calculate energy descriptors
25+
"force": 1, # Calculate force descriptors
26+
"stress": 0, # Calculate virial descriptors
27+
},
28+
"REFERENCE": {
29+
"units": "metal",
30+
"atom_style": "atomic",
31+
"pair_style": "hybrid/overlay zero 10.0 zbl 4.0 4.8",
32+
"pair_coeff1": "* * zero",
33+
"pair_coeff2": "1 1 zbl 74 74",
34+
},
35+
"SOLVER": {"solver": "SVD", "compute_testerrs": 1, "detailed_errors": 1},
36+
"EXTRAS": {
37+
"dump_descriptors": 0,
38+
"dump_truth": 0,
39+
"dump_weights": 0,
40+
"dump_dataframe": 0,
41+
},
42+
"MEMORY": {"override": 0},
43+
}
44+
45+
46+
class FitsnapJob(PythonTemplateJob):
47+
def __init__(self, project, job_name):
48+
super(FitsnapJob, self).__init__(project, job_name)
49+
self.__version__ = "0.1"
50+
self.__name__ = "FitsnapJob"
51+
self.input.update(default_input)
52+
self._lst_of_struct = []
53+
self._lst_of_energies = []
54+
self._lst_of_forces = []
55+
self._coefficients = []
56+
57+
@property
58+
def list_of_structures(self):
59+
return self._lst_of_struct
60+
61+
@list_of_structures.setter
62+
def list_of_structures(self, structure_lst):
63+
self._lst_of_struct = structure_lst
64+
65+
@property
66+
def list_of_energies(self):
67+
return self._lst_of_energies
68+
69+
@list_of_energies.setter
70+
def list_of_energies(self, energies):
71+
self._lst_of_energies = energies
72+
73+
@property
74+
def coefficients(self):
75+
return self._coefficients
76+
77+
@property
78+
def list_of_forces(self):
79+
return self._lst_of_forces
80+
81+
@list_of_forces.setter
82+
def list_of_forces(self, forces):
83+
self._lst_of_forces = forces
84+
85+
def run_static(self):
86+
comm = MPI.COMM_WORLD
87+
input_dict = self.input.to_builtin()
88+
snap = FitSnap(input_dict, comm=comm, arglist=["--overwrite"])
89+
ase_scraper(
90+
snap, self._lst_of_struct, self._lst_of_energies, self._lst_of_forces
91+
)
92+
snap.process_configs()
93+
snap.solver.perform_fit()
94+
self._coefficients = snap.solver.fit
95+
self.status.finished = True
96+
97+
def to_hdf(self, hdf=None, group_name=None):
98+
super(FitsnapJob, self).to_hdf(hdf=hdf, group_name=group_name)
99+
100+
def from_hdf(self, hdf=None, group_name=None):
101+
super(FitsnapJob, self).from_hdf(hdf=hdf, group_name=group_name)

setup.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@
3636
'numpy==1.26.2',
3737
'pyiron_base==0.6.9',
3838
'scipy==1.11.4',
39+
'fitsnap3==3.1.0.4',
3940
'runnerase==0.3.3',
4041
],
4142
cmdclass=versioneer.get_cmdclass(),
43+
4244
)

0 commit comments

Comments
 (0)