Skip to content

Commit

Permalink
add sample code for qmc
Browse files Browse the repository at this point in the history
  • Loading branch information
qzhu2017 committed Jul 28, 2024
1 parent ea73098 commit b161c02
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 2 deletions.
10 changes: 10 additions & 0 deletions pyxtal/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ def get_dof(self):

return self.lattice.dof + dof

def get_bounds(self, vec=(2.0, 50.0), ang=(30, 150)):
"""
Get the number of dof for the given structures:
"""
bounds = self.lattice.get_bounds(vec[0], vec[1], ang[0], ang[1])
sites = self.mol_sites if self.molecular else self.atom_sites
for site in sites:
bounds.extend(site.get_bounds())
return bounds

def get_site_labels(self):
"""
Get the site_labels as a dictionary
Expand Down
19 changes: 19 additions & 0 deletions pyxtal/lattice.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,24 @@ def _get_dof(self):
else:
self.dof = 1

def get_bounds(self, min_vec=2.0, max_vec=50.0, min_ang=30, max_ang=150):
"""
get the number of degree of freedom
"""
if self.ltype in ["triclinic"]:
self.bounds = [(min_vec, max_vec), (min_vec, max_vec), (min_vec, max_vec),
(min_ang, max_ang), (min_ang, max_ang), (min_ang, max_ang)]
elif self.ltype in ["monoclinic"]:
self.bounds = [(min_vec, max_vec), (min_vec, max_vec), (min_vec, max_vec),
(min_ang, max_ang)]
elif self.ltype in ["orthorhombic"]:
self.bounds = [(min_vec, max_vec), (min_vec, max_vec), (min_vec, max_vec)]
elif self.ltype in ["tetragonal", "hexagonal", "trigonal"]:
self.bounds = [(min_vec, max_vec), (min_vec, max_vec)]
else:
self.bounds = [(min_vec, max_vec)]
return self.bounds

@classmethod
def get_dofs(self, ltype):
"""
Expand Down Expand Up @@ -196,6 +214,7 @@ def get_lengths(self):
return mat, np.linalg.norm(mat, axis=1)

def scale(self, factor=1.1):

matrix = self.matrix
return Lattice.from_matrix(matrix * factor, ltype=self.ltype)

Expand Down
78 changes: 78 additions & 0 deletions pyxtal/optimize/qmc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""
global optimizer
ACSALA
81 11.38 6.48 11.24 96.9 1 0 0.23 0.43 0.03 -44.6 25.0 34.4 -76.6 -5.2 171.5 0 -70594.48
"""
# ACSALA has 13 variables (4 cell + 3 xyz + 3 ori + 3 torsions)
import os
from scipy.stats import qmc
from pyxtal.representation import representation
from pyxtal.optimize.common import optimizer
from pyxtal.db import database
from pyxtal.lattice import Lattice
import pymatgen.analysis.structure_matcher as sm

w_dir = "tmp"
if not os.path.exists(w_dir):
os.makedirs(w_dir)

db = database("pyxtal/database/test.db")
code = "ACSALA"
row = db.get_row(code)
xtal0 = db.get_pyxtal(code)
if xtal0.has_special_site():
xtal0 = xtal0.to_subgroup()
smiles = row.mol_smi; print(smiles)
pmg0 = xtal0.to_pymatgen()
pmg0.remove_species("H")

# Prepare prm
c_info = row.data["charmm_info"]
with open(w_dir + "/pyxtal.prm", "w") as prm:
prm.write(c_info["prm"])
with open(w_dir + "/pyxtal.rtf", "w") as rtf:
rtf.write(c_info["rtf"])


# Prepare the sampling.....
bounds = xtal0.get_bounds([2.5, 25])
lb = [b[0] for b in bounds]
ub = [b[1] for b in bounds]
sampler = qmc.Sobol(d=xtal0.get_dof(), scramble=False)
sample = sampler.random_base2(m=10)
sample = qmc.scale(sample, lb, ub)

l_dof = xtal0.lattice.dof
est_volume = sum(n*mol.volume for n, mol in zip(xtal0.numMols, xtal0.molecules))
min_vol, max_vol = 0.25*est_volume, 5.0*est_volume

for i, des in enumerate(sample):
cell = [xtal0.group.hall_number] + des[:l_dof].tolist()
lat = Lattice.from_1d_representation(cell[1:], xtal0.lattice.ltype)

if min_vol < lat.volume < max_vol:
#print('reset volume0', lat.encode(), lat.volume)
coef = (est_volume*0.5/lat.volume)**(1/3)
lat = lat.scale(coef)
cell = [xtal0.group.hall_number] + lat.encode()
#print('reset volume1', lat.encode(), coef, lat.volume)

x = [cell, [0] + des[l_dof:].tolist() + [False]]

rep0 = representation(x, [smiles])
xtal = rep0.to_pyxtal()
if len(xtal.check_short_distances(r=0.75)) == 0:
res = optimizer(xtal, c_info, w_dir, skip_ani=True)
if res is not None:
xtal, eng = res["xtal"], res["energy"]/sum(xtal.numMols)
if eng < 1e+3:
rep1 = xtal.get_1D_representation()
strs = f'Opt {i:4d} ' + rep1.to_string(eng) + f' Vol {lat.volume:7.1f} => {xtal.lattice.volume:7.1f}'
pmg1 = xtal.to_pymatgen()
pmg1.remove_species("H")
if sm.StructureMatcher().fit(pmg0, pmg1):
strs += '++++++'
print(strs)

if i % 10000 == 0:
print("Progress", i, lat.volume, xtal0.lattice.volume)
32 changes: 30 additions & 2 deletions pyxtal/wyckoff_site.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ def _get_dof(self):

self.dof = self.wp.get_dof()

def get_bounds(self):
"""
get the number of dof for the given structures:
"""
self.bounds = []
for i in range(self.dof):
self.bounds.append([0.0, 1.0])
return self.bounds

@classmethod
def load_dict(cls, dicts):
"""
Expand Down Expand Up @@ -363,6 +372,7 @@ def __init__(self, mol, position, orientation, wp, lattice=None, stype=0):
self.wp = wp
self.position = position # fractional coordinate of molecular center
self.orientation = orientation # pyxtal.molecule.orientation object
self._get_dof()
if isinstance(lattice, Lattice):
self.lattice = lattice
else:
Expand Down Expand Up @@ -409,11 +419,29 @@ def __repr__(self):
return str(self)

def _get_dof(self):
"""
get the number of dof for the given wyckoff site:
"""
dof = np.linalg.matrix_rank(self.wp.ops[0].rotation_matrix)
self.dof = dof + 3
if self.molecule.torsionlist is not None:
self.dof += len(self.molecule.torsionlist)

def get_bounds(self):
"""
get the number of dof for the given structures:
"""
freedom = np.trace(self.wp.ops[0].rotation_matrix) > 0
self.dof = len(freedom[freedom is True])
self.bounds = []
dof = np.linalg.matrix_rank(self.wp.ops[0].rotation_matrix)
for i in range(dof):
self.bounds.append([0.0, 1.0])
self.bounds.append([-180.0, 180.0])
self.bounds.append([-90.0, 90.0])
self.bounds.append([-180.0, 180.0])
if self.molecule.torsionlist is not None:
for i in range(len(self.molecule.torsionlist)):
self.bounds.append([0, 180.0])
return self.bounds

def save_dict(self):
dict0 = {
Expand Down

0 comments on commit b161c02

Please sign in to comment.