Skip to content

Commit

Permalink
maint: use default rng in the script examples (fix where obvious)
Browse files Browse the repository at this point in the history
  • Loading branch information
CompRhys committed Jul 12, 2024
1 parent 08c9333 commit c81ca50
Show file tree
Hide file tree
Showing 11 changed files with 399 additions and 364 deletions.
23 changes: 23 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Install these hooks with `pre-commit install`.

ci:
autoupdate_schedule: quarterly

repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.5.0
hooks:
- id: ruff
args: [--fix]
- id: ruff-format

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: check-case-conflict
- id: check-symlinks
- id: check-yaml
- id: destroyed-symlinks
- id: end-of-file-fixer
- id: mixed-line-ending
- id: trailing-whitespace
38 changes: 18 additions & 20 deletions examples/example_00_LJ_simple.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from scipy.optimize import minimize
from scipy.spatial.distance import pdist, cdist
import numpy as np
"""This is a script to
1, generate random clusters.
2, perform optimization.
"""

from time import time

"""
This is a script to
1, generate random clusters
2, perform optimization
"""
import numpy as np
from scipy.optimize import minimize
from scipy.spatial.distance import cdist, pdist


def LJ(pos, dim=3):
"""
Calculate the total energy
"""Calculate the total energy.
Args:
pos: 1D array with N*dim numbers representing the atomic positions
dim: dimension of the hyper/normal space
Expand All @@ -26,14 +26,12 @@ def LJ(pos, dim=3):
distance = pdist(pos)
r6 = np.power(distance, 6)
r12 = np.multiply(r6, r6)
Eng = np.sum(4 * (1 / r12 - 1 / r6))

return Eng
return np.sum(4 * (1 / r12 - 1 / r6))


def LJ_force(pos, dim=3):
"""
Calculate the total energy
"""Calculate the LF Forces.
Args:
pos: 1D array with N*dim numbers representing the atomic positions
dim: dimension of the hyper/normal space
Expand All @@ -57,12 +55,11 @@ def LJ_force(pos, dim=3):


def single_optimize(pos):
"""
perform optimization for a given cluster
"""Perform optimization for a given cluster.
Args:
pos: N*dim0 array representing the atomic positions
dim: dimension of the hyper/normal space
pos: N*dim0 array representing the atomic positions.
dim: dimension of the hyper/normal space.
output:
energy: optmized energy
Expand All @@ -79,8 +76,9 @@ def single_optimize(pos):
if __name__ == "__main__":
N = 38
L = 10
rng = np.random.default_rng()
for i in range(20):
t0 = time()
pos0 = L * np.random.random_sample((N * 3,))
pos0 = L * rng.random((N * 3,))
eng, pos = single_optimize(pos0)
print(i, eng, time() - t0)
40 changes: 22 additions & 18 deletions examples/example_01_3D_VASP.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,40 @@
"""This is a script to
1, generate random structures.
2, perform multiple steps of optmization with ASE-VASP.
Requirement:
You must have ASE installed and can call vasp from ASE.
"""

import warnings
from time import time

import numpy as np
from ase.db import connect

from pyxtal import pyxtal
from pyxtal.interface.vasp import optimize
from ase.db import connect
from random import randint
from time import time
import warnings

warnings.filterwarnings("ignore")

"""
This is a script to
1, generate random structures
2, perform multiple steps of optmization with ASE-VASP

Requirement:
You must have ASE installed and can call vasp from ASE
"""
N = 10
elements = {"C": [2, 4]}
levels = [0, 2] # , 3]
dir1 = "Calc"
filename = "C-VASP.db"
rng = np.random.default_rng()

for i in range(N):
t0 = time()
while True:
sg = randint(2, 230)
sg = rng.integers(2, 230)
species = []
numIons = []
for ele in elements.keys():
for ele in elements:
species.append(ele)
if len(elements[ele]) == 2:
num = randint(elements[ele][0], elements[ele][1])
num = rng.integers(elements[ele][0], elements[ele][1])
numIons.append(num)
else:
numIons.append(elements[ele])
Expand All @@ -54,10 +58,10 @@
}
db.write(s, key_value_pairs=kvp)
cputime /= 60.0
strs = "{:3d}".format(i)
strs += " {:12s} -> {:12s}".format(crystal.group.symbol, struc.group.symbol)
strs += " {:6.3f} eV/atom".format(energy / len(s))
strs += " {:6.2f} min".format(cputime)
strs = f"{i:3d}"
strs += f" {crystal.group.symbol:12s} -> {struc.group.symbol:12s}"
strs += f" {energy / len(s):6.3f} eV/atom"
strs += f" {cputime:6.2f} min"
print(strs)

# from pyxtal.interface.vasp import single_point
Expand Down
106 changes: 46 additions & 60 deletions examples/example_02_LJ_cluster.py
Original file line number Diff line number Diff line change
@@ -1,124 +1,110 @@
from pyxtal import pyxtal
"""This is a script to:
1, generate random clusters.
2, perform optimization.
3, compare the efficiency of different algos (CG, BFGS).
"""

import logging
import warnings
from optparse import OptionParser
from random import randint, choice
from pyxtal.database.collection import Collection

import numpy as np

from pyxtal import pyxtal
from pyxtal.database.collection import Collection
from pyxtal.optimize.myscipy_optimize import (
_minimize_cg,
_minimize_bfgs,
_minimize_cg,
_minimize_tpgd,
)
from pyxtal.potentials.LJ_cluster import LJ, LJ_force

import logging
import warnings

warnings.filterwarnings("ignore")
logging.basicConfig(
format="%(asctime)s :: %(message)s", filename="results.log", level=logging.INFO
)

"""
This is a script to
1, generate random clusters
2, perform optimization
3, compare the efficiency of different algos (CG, BFGS)
"""
logging.basicConfig(format="%(asctime)s :: %(message)s", filename="results.log", level=logging.INFO)


def single_optimize(pos, dim=3, kt=0.5, mu=0.1, beta=1.001, shift=False, method="mycg"):
"""
perform optimization for a given cluster
"""Perform optimization for a given cluster.
Args:
pos: N*dim0 array representing the atomic positions
dim: dimension of the hyper/normal space
kt: perturbation factors
pos: N*dim0 array representing the atomic positions
dim: dimension of the hyper/normal space
kt: perturbation factors
mu: the weight for the punishing function
beta: the factor for the punishing function
shift: whether to shift the cluster to the center
method: the optimization method
output:
energy: optmized energy
pos: optimized positions
energy: optmized energy
pos: optimized positions
niter: number of iterations
"""
N_atom = len(pos)
pos = pos.flatten()
res = _minimize_tpgd(
LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4, maxiter=50
)
res = _minimize_tpgd(LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4, maxiter=50)
niter = res.nit
pos = res.x
if method == "mycg":
res = _minimize_cg(
LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4
)
res = _minimize_cg(LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4)
elif method == "mybfgs":
res = _minimize_bfgs(
LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4
)
res = _minimize_bfgs(LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4)
elif method == "mytpgd":
res = _minimize_tpgd(
LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4
)
res = _minimize_tpgd(LJ, pos, args=(dim, mu, shift), jac=LJ_force, beta=beta, gtol=1e-4)
niter += res.nit
energy = res.fun
pos = np.reshape(res.x, (N_atom, dim))
return energy, pos, niter


class LJ_prediction:
"""
A class to perform global optimization on LJ clusters
Args:
Attributes:
"""
"""A class to perform global optimization on LJ clusters."""

def __init__(self, numIons):
"""Initialize the class with the number of ions."""
self.numIons = numIons
ref = Collection("clusters")[str(numIons)]
print(
"\nReference for LJ {0:3d} is {1:12.3f} eV, PG: {2:4s}".format(
numIons, ref["energy"], ref["pointgroup"]
)
)
print(f"\nReference for LJ {numIons:3d} is {ref["energy"]:12.3f} eV, PG: {ref["pointgroup"]:4s}")

self.reference = ref

def generate_cluster(self, pgs=range(2, 33)):
def generate_cluster(self, pgs: tuple[int, int], cluster_factor=0.6, seed=None):
"""Generate a random cluster with a given point group and number of ions."""
rng = np.random.default_rng(seed)
run = True
while run:
pg = choice(pgs)
pg = rng.integers(pgs)
cluster = pyxtal()
cluster.from_random(0, pg, ["H"], [self.numIons], 0.6)
cluster.from_random(0, pg, ["H"], [self.numIons], cluster_factor)
if cluster.valid:
run = False
return cluster._get_coords_and_species(absolute=True)[0]

def predict(self, maxN=100, ncpu=2, pgs=range(2, 33)):
def predict(self, maxN: int = 100, ncpu: int = 2, pgs: tuple[int, int] = (2, 33)):
"""Predict the energy of LJ clusters."""
cycle = range(maxN)
if ncpu > 1:
from multiprocessing import Pool
from functools import partial
from multiprocessing import Pool

with Pool(ncpu) as p:
func = partial(self.relaxation, pgs)
res = p.map(func, cycle)
p.close()
p.join()
else:
res = []
for i in cycle:
res.append(self.relaxation(pgs, i))
res = [self.relaxation(pgs) for _ in cycle]

return res

def relaxation(self, pgs, ind):
def relaxation(self, pgs: tuple[int, int], **kwargs):
"""Perform relaxation for a given cluster."""
pos = self.generate_cluster(pgs)
res = []
for method in ["mycg", "mybfgs", "mytpgd"]:
pos1 = pos.copy()
energy1, pos1, it1 = single_optimize(pos1, method=method)
print(
"Optmization {:10s} 3D: {:10.4f} {:6d} ".format(method, energy1, it1)
)
print(f"Optmization {method:10s} 3D: {energy1:10.4f} {it1:6d} ")
res.append([energy1, it1])
res = np.array(res)
return res.flatten()
Expand Down
Loading

0 comments on commit c81ca50

Please sign in to comment.