# coding: utf-8
# Copyright (c) Max-Planck-Institut für Eisenforschung GmbH - Computational Materials Design (CM) Department
# Distributed under the terms of "New BSD License", see the LICENSE file.
from __future__ import print_function
from pyiron_contrib.protocol.generic import CompoundVertex, Protocol
from pyiron_contrib.protocol.primitive.one_state import Counter, ExternalHamiltonian, GradientDescent, Max, Norm
from pyiron_contrib.protocol.primitive.two_state import IsGEq
from pyiron_contrib.protocol.utils import Pointer
"""
Protocol for minimizing forces.
"""
__author__ = "Liam Huber, Jan Janssen"
__copyright__ = "Copyright 2019, Max-Planck-Institut für Eisenforschung GmbH " \
"- Computational Materials Design (CM) Department"
__version__ = "0.0"
__maintainer__ = "Liam Huber"
__email__ = "huber@mpie.de"
__status__ = "development"
__date__ = "May 20, 2019"
[docs]class Minimize(CompoundVertex):
"""
Run minimization with Lammps. This isn't physically useful, since a regular lammps job is faster it's just a dummy
class for debugging new code and teaching ideas.
Input attributes:
ref_job_full_path (str): Path to the pyiron job to use for evaluating forces and energies.
structure (Atoms): The structure to minimize.
n_steps (int): How many steps to run for. (Default is 100.)
f_tol (float): Ionic force convergence (largest atomic force). (Default is 1e-4 eV/angstrom.)
gamma0 (float): Initial step size as a multiple of the force. (Default is 0.1.)
fix_com (bool): Whether the center of mass motion should be subtracted off of the position update. (Default is
True)
use_adagrad (bool): Whether to have the step size decay according to adagrad. (Default is False)
Output attributes:
energy_pot (float): Total potential energy of the system in eV.
max_force (float): The largest atomic force magnitude in eV/angstrom.
positions (numpy.ndarray): Atomic positions in angstroms.
forces (numpy.ndarray): Atomic forces in eV/angstrom. Note: These are the potential gradient forces; thermostat
forces (if any) are not saved.
"""
DefaultWhitelist = {
'calc_static': {
'output': {
'energy_pot': 1
}
},
'max_force': {
'output': {
'amax': 1
}
}
}
def __init__(self, **kwargs):
super(Minimize, self).__init__(**kwargs)
# Protocol defaults
id_ = self.input.default
id_.n_steps = 100
id_.f_tol = 1e-4
id_.gamma0 = 0.1
id_.fix_com = True
id_.use_adagrad = False
[docs] def define_vertices(self):
# Graph components
g = self.graph
g.calc_static = ExternalHamiltonian()
g.clock = Counter()
g.check_steps = IsGEq()
g.force_norm = Norm()
g.max_force = Max()
g.check_force = IsGEq()
g.gradient_descent = GradientDescent()
[docs] def define_execution_flow(self):
# Execution flow
g = self.graph
g.make_pipeline(
g.check_steps, 'false',
g.calc_static,
g.force_norm,
g.max_force,
g.gradient_descent,
g.check_force, 'true',
g.clock,
g.check_steps
)
g.starting_vertex = self.graph.check_steps
g.restarting_vertex = self.graph.check_steps
[docs] def get_output(self):
gp = Pointer(self.graph)
return {
'energy_pot': ~gp.calc_static.output.energy_pot[-1],
'max_force': ~gp.max_force.output.amax[-1],
'positions': ~gp.gradient_descent.output.positions[-1],
'forces': ~gp.calc_static.output.forces[-1]
}
[docs]class ProtoMinimGradDes(Protocol, Minimize):
pass