Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import re
2import os
4from ase.data import atomic_masses, atomic_numbers
5from ase.calculators.lammpsrun import LAMMPS
6from ase.calculators.lammpslib import LAMMPSlib
7from ase.calculators.lammps import convert
9from .kimmodel import KIMModelCalculator
10from .exceptions import KIMCalculatorError
13def KIMCalculator(model_name, options, debug):
14 """
15 Used only for Portable Models
16 """
18 options_not_allowed = ["modelname", "debug"]
20 _check_conflict_options(options, options_not_allowed, simulator="kimmodel")
22 return KIMModelCalculator(model_name, debug=debug, **options)
25def LAMMPSRunCalculator(
26 model_name, model_type, supported_species, options, debug, **kwargs
27):
28 """
29 Used for Portable Models or LAMMPS Simulator Models if specifically requested
30 """
32 def get_params(model_name, supported_units, supported_species, atom_style):
33 """
34 Extract parameters for LAMMPS calculator from model definition lines.
35 Returns a dictionary with entries for "pair_style" and "pair_coeff".
36 Expects there to be only one "pair_style" line. There can be multiple
37 "pair_coeff" lines (result is returned as a list).
38 """
39 parameters = {}
41 # In case the SM supplied its own atom_style in its model-init -- only needed
42 # because lammpsrun writes data files and needs to know the proper format
43 if atom_style:
44 parameters["atom_style"] = atom_style
46 # Set units to prevent them from defaulting to metal
47 parameters["units"] = supported_units
49 parameters["model_init"] = [
50 "kim_init {} {}{}".format(model_name, supported_units, os.linesep)
51 ]
53 parameters["kim_interactions"] = "kim_interactions {}{}".format(
54 (" ").join(supported_species), os.linesep
55 )
57 # For every species in "supported_species", add an entry to the
58 # "masses" key in dictionary "parameters".
59 parameters["masses"] = []
60 for i, species in enumerate(supported_species):
61 if species not in atomic_numbers:
62 raise KIMCalculatorError(
63 "Could not determine mass of unknown species "
64 "{} listed as supported by model".format(species)
65 )
66 massstr = str(
67 convert(
68 atomic_masses[atomic_numbers[species]],
69 "mass",
70 "ASE",
71 supported_units,
72 )
73 )
74 parameters["masses"].append(str(i + 1) + " " + massstr)
76 return parameters
78 options_not_allowed = ["parameters", "files", "specorder", "keep_tmp_files"]
80 _check_conflict_options(options, options_not_allowed, simulator="lammpsrun")
82 # If no atom_style kwarg is passed, lammpsrun will default to atom_style atomic,
83 # which is what we want for KIM Portable Models
84 atom_style = kwargs.get("atom_style", None)
86 # Simulator Models will supply their own units from their metadata. For Portable
87 # Models, we use "metal" units.
88 supported_units = kwargs.get("supported_units", "metal")
90 # Set up kim_init and kim_interactions lines
91 parameters = get_params(model_name, supported_units, supported_species, atom_style)
93 return LAMMPS(
94 **parameters, specorder=supported_species, keep_tmp_files=debug, **options
95 )
98def LAMMPSLibCalculator(model_name, supported_species, supported_units, options):
99 """
100 Only used for LAMMPS Simulator Models
101 """
102 options_not_allowed = [
103 "lammps_header",
104 "lmpcmds",
105 "atom_types",
106 "log_file",
107 "keep_alive",
108 ]
110 _check_conflict_options(options, options_not_allowed, simulator="lammpslib")
111 # Set up LAMMPS header commands lookup table
113 # This units command actually has no effect, but is necessary because
114 # LAMMPSlib looks in the header lines for units in order to set them
115 # internally
116 model_init = ["units " + supported_units + os.linesep]
118 model_init.append(
119 "kim_init {} {}{}".format(model_name, supported_units, os.linesep)
120 )
121 model_init.append("atom_modify map array sort 0 0" + os.linesep)
123 # Assign atom types to species
124 atom_types = {}
125 for i_s, s in enumerate(supported_species):
126 atom_types[s] = i_s + 1
128 kim_interactions = ["kim_interactions {}".format((" ").join(supported_species))]
130 # Return LAMMPSlib calculator
131 return LAMMPSlib(
132 lammps_header=model_init,
133 lammps_name=None,
134 lmpcmds=kim_interactions,
135 post_changebox_cmds=kim_interactions,
136 atom_types=atom_types,
137 log_file="lammps.log",
138 keep_alive=True,
139 **options
140 )
143def ASAPCalculator(model_name, model_type, options, **kwargs):
144 """
145 Can be used with either Portable Models or Simulator Models
146 """
147 import asap3
149 options_not_allowed = {"pm": ["name", "verbose"], "sm": ["Params"]}
151 _check_conflict_options(options, options_not_allowed[model_type], simulator="asap")
153 if model_type == "pm":
155 return asap3.OpenKIMcalculator(
156 name=model_name, verbose=kwargs["verbose"], **options
157 )
159 elif model_type == "sm":
160 model_defn = kwargs["model_defn"]
161 supported_units = kwargs["supported_units"]
163 # Verify units (ASAP models are expected to work with "ase" units)
164 if supported_units != "ase":
165 raise KIMCalculatorError(
166 'KIM Simulator Model units are "{}", but expected to '
167 'be "ase" for ASAP.'.format(supported_units)
168 )
170 # Check model_defn to make sure there's only one element in it that is a
171 # non-empty string
172 if len(model_defn) == 0:
173 raise KIMCalculatorError(
174 "model-defn is an empty list in metadata file of Simulator Model {}"
175 "".format(model_name)
176 )
177 elif len(model_defn) > 1:
178 raise KIMCalculatorError(
179 "model-defn should contain only one entry for an ASAP model (found {} "
180 "lines)".format(len(model_defn))
181 )
183 if "" in model_defn:
184 raise KIMCalculatorError(
185 "model-defn contains an empty string in metadata file of Simulator "
186 "Model {}".format(model_name)
187 )
189 model_defn = model_defn[0].strip()
191 # Instantiate calculator from ASAP. Currently, this must be one of:
192 # (1) EMT
193 # (2) EMT(EMTRasmussenParameters)
194 # (3) EMT(EMTMetalGlassParameters)
195 model_defn_is_valid = False
196 if model_defn.startswith("EMT"):
197 # Pull out potential parameters
198 mobj = re.search(r"\(([A-Za-z0-9_\(\)]+)\)", model_defn)
199 if mobj is None:
200 asap_calc = asap3.EMT()
201 else:
202 pp = mobj.group(1)
204 # Currently we only supported two specific EMT models that are built
205 # into ASAP
206 if pp.startswith("EMTRasmussenParameters"):
207 asap_calc = asap3.EMT(parameters=asap3.EMTRasmussenParameters())
208 model_defn_is_valid = True
209 elif pp.startswith("EMTMetalGlassParameters"):
210 asap_calc = asap3.EMT(parameters=asap3.EMTMetalGlassParameters())
211 model_defn_is_valid = True
213 if not model_defn_is_valid:
214 raise KIMCalculatorError(
215 'Unknown model "{}" requested for simulator asap.'.format(model_defn)
216 )
218 # Disable undocumented feature for the EMT self.calculators to take the
219 # energy of an isolated atoms as zero. (Otherwise it is taken to be that of
220 # perfect FCC.)
221 asap_calc.set_subtractE0(False)
223 return asap_calc
226def _check_conflict_options(options, options_not_allowed, simulator):
227 """Check whether options intended to be passed to a given calculator are allowed.
228 Some options are not allowed because they must be set internally in this package.
229 """
230 s1 = set(options)
231 s2 = set(options_not_allowed)
232 common = s1.intersection(s2)
234 if common:
235 options_in_not_allowed = ", ".join(['"{}"'.format(s) for s in common])
237 msg = (
238 'Simulator "{}" does not support argument(s): {} provided in "options", '
239 "because it is (they are) determined internally within the KIM "
240 "calculator".format(simulator, options_in_not_allowed)
241 )
243 raise KIMCalculatorError(msg)