Print notice message when group.all() is updated
[hoomd-blue.git] / python-module / hoomd_script / external.py
blob897973ebfa26263bf746fbddbe18128fabe36090
1 # -- start license --
2 # Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 # (HOOMD-blue) Open Source Software License Copyright 2008-2011 Ames Laboratory
4 # Iowa State University and The Regents of the University of Michigan All rights
5 # reserved.
7 # HOOMD-blue may contain modifications ("Contributions") provided, and to which
8 # copyright is held, by various Contributors who have granted The Regents of the
9 # University of Michigan the right to modify and/or distribute such Contributions.
11 # You may redistribute, use, and create derivate works of HOOMD-blue, in source
12 # and binary forms, provided you abide by the following conditions:
14 # * Redistributions of source code must retain the above copyright notice, this
15 # list of conditions, and the following disclaimer both in the code and
16 # prominently in any materials provided with the distribution.
18 # * Redistributions in binary form must reproduce the above copyright notice, this
19 # list of conditions, and the following disclaimer in the documentation and/or
20 # other materials provided with the distribution.
22 # * All publications and presentations based on HOOMD-blue, including any reports
23 # or published results obtained, in whole or in part, with HOOMD-blue, will
24 # acknowledge its use according to the terms posted at the time of submission on:
25 # http://codeblue.umich.edu/hoomd-blue/citations.html
27 # * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
28 # http://codeblue.umich.edu/hoomd-blue/
30 # * Apart from the above required attributions, neither the name of the copyright
31 # holder nor the names of HOOMD-blue's contributors may be used to endorse or
32 # promote products derived from this software without specific prior written
33 # permission.
35 # Disclaimer
37 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
38 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
39 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
40 # WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
42 # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
43 # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
44 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
46 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
47 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
48 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49 # -- end license --
51 # Maintainer: joaander / All Developers are free to add commands for new features
53 ## \package hoomd_script.external
54 # \brief Commands that create external forces on particles
56 # Apply an %external force to all particles in the simulation. This module organizes all external forces.
57 # As an example, a force derived from a %periodic potential can be used to induce a concentration modulation
58 # in the system.
60 from hoomd_script import globals;
61 from hoomd_script import force;
62 import hoomd;
63 from hoomd_script import util;
64 from hoomd_script import init;
65 from hoomd_script import data;
66 from hoomd_script import tune;
68 import sys;
70 # \brief Defines external potential coefficients
71 # The coefficients for all %external force are specified using this class. Coefficients are specified per-particle
72 # type.
74 # There are two ways to set the coefficients for a particular %external %force.
75 # The first way is to save the %external %force in a variable and call set() directly.
76 # To see an example of this, see the documentation for the package.
78 # The second method is to build the coeff class first and then assign it to the
79 # %external %force. There are some advantages to this method in that you could specify a
80 # complicated set of %external %force coefficients in a separate python file and import it into
81 # your job script.
83 # Example:
84 # \code
85 # my_coeffs = external.coeff();
86 # my_external_force.force_coeff.set('A', A=1.0, i=1, w=0.02, p=3)
87 # my_external_force.force_coeff.set('B', A=-1.0, i=1, w=0.02, p=3)
88 # \endcode
89 class coeff:
91 ## \internal
92 # \brief Initializes the class
93 # \details
94 # The main task to be performed during initialization is just to init some variables
95 # \param self Python required class instance variable
96 def __init__(self):
97 self.values = {};
98 self.default_coeff = {}
100 ## \var values
101 # \internal
102 # \brief Contains the vector of set values in a dictionary
104 ## \var default_coeff
105 # \internal
106 # \brief default_coeff['coeff'] lists the default value for \a coeff, if it is set
108 ## \internal
109 # \brief Sets a default value for a given coefficient
110 # \details
111 # \param name Name of the coefficient to for which to set the default
112 # \param value Default value to set
114 # Some coefficients have reasonable default values and the user should not be burdened with typing them in
115 # all the time. set_default_coeff() sets
116 def set_default_coeff(self, name, value):
117 self.default_coeff[name] = value;
119 ## Sets parameters for one particle type
120 # \param type Type of particle
121 # \param coeff Named coefficients (see below for examples)
123 # Calling set() results in one or more parameters being set for a particle type. Types are identified
124 # by name, and parameters are also added by name. Which parameters you need to specify depends on the %external
125 # %force you are setting these coefficients for, see the corresponding documentation.
127 # All possible particle types as defined in the simulation box must be specified before executing run().
128 # You will receive an error if you fail to do so. It is not an error, however, to specify coefficients for
129 # particle types that do not exist in the simulation. This can be useful in defining a %force field for many
130 # different types of particles even when some simulations only include a subset.
132 # To set the same coefficients between many particle types, provide a list of type names instead of a single
133 # one. All types in the list will be set to the same parameters. A convenient wildcard that lists all types
134 # of particles in the simulation can be gotten from a saved \c system from the init command.
136 # \b Examples:
137 # \code
138 # coeff.set('A', A=1.0, i=1, w=0.02, p=3)
139 # coeff.set('B', A=-1.0, i=1, w=0.02, p=3)
140 # coeff.set(['A','B'], i=1, w=0.02, p=3)
141 # \endcode
143 # \note Single parameters can be updated. If both epsilon and sigma have already been set for a particle type,
144 # then executing coeff.set('A', A =1.0) will %update the value of A and leave the other parameters as they
145 # were previously set.
147 def set(self, type, **coeffs):
148 util.print_status_line();
150 # listify the input
151 if isinstance(type, str):
152 type = [type];
154 for typei in type:
155 self.set_single(typei, coeffs);
157 ## \internal
158 # \brief Sets a single parameter
159 def set_single(self, type, coeffs):
160 # create the type identifier if it hasn't been created yet
161 if (not type in self.values):
162 self.values[type] = {};
164 # update each of the values provided
165 if len(coeffs) == 0:
166 globals.msg.error("No coefficents specified\n");
167 for name, val in coeffs.items():
168 self.values[type][name] = val;
170 # set the default values
171 for name, val in self.default_coeff.items():
172 # don't override a coeff if it is already set
173 if not name in self.values[type]:
174 self.values[type][name] = val;
176 ## \internal
177 # \brief Verifies that all values are set
178 # \details
179 # \param self Python required self variable
180 # \param required_coeffs list of required variables
182 # This can only be run after the system has been initialized
183 def verify(self, required_coeffs):
184 # first, check that the system has been initialized
185 if not init.is_initialized():
186 globals.msg.error("Cannot verify force coefficients before initialization\n");
187 raise RuntimeError('Error verifying force coefficients');
189 # get a list of types from the particle data
190 ntypes = globals.system_definition.getParticleData().getNTypes();
191 type_list = [];
192 for i in range(0,ntypes):
193 type_list.append(globals.system_definition.getParticleData().getNameByType(i));
195 valid = True;
196 # loop over all possible types and verify that all required variables are set
197 for i in range(0,ntypes):
198 type = type_list[i];
200 # verify that all required values are set by counting the matches
201 count = 0;
202 for coeff_name in self.values[type].keys():
203 if not coeff_name in required_coeffs:
204 globals.msg.notice(3, "Possible typo? Force coeff " + str(coeff_name) + " is specified for type " + str(type) +\
205 ", but is not used by the external force");
206 else:
207 count += 1;
209 if count != len(required_coeffs):
210 globals.msg.error("Particle type", type, "is missing required coefficients\n");
211 valid = False;
213 return valid;
215 ## \internal
216 # \brief Gets the value of a single %external %force coefficient
217 # \detail
218 # \param type Name of particle type
219 # \param coeff_name Coefficient to get
220 def get(self, type, coeff_name):
221 if type not in self.values:
222 globals.msg.error("Bug detected in external.coeff. Please report\n");
223 raise RuntimeError("Error setting external coeff");
225 return self.values[type][coeff_name];
227 ## \internal
228 # \brief Base class for external forces
230 # An external_force in hoomd_script reflects a PotentialExternal in c++. It is responsible
231 # for all high-level management that happens behind the scenes for hoomd_script
232 # writers. 1) The instance of the c++ external force itself is tracked and added to the
233 # System 2) methods are provided for disabling the force from being added to the
234 # net force on each particle
235 class _external_force(force._force):
236 ## \internal
237 # \brief Constructs the external force
239 # \param name name of the external force instance
241 # Initializes the cpp_force to None.
242 # If specified, assigns a name to the instance
243 # Assigns a name to the force in force_name;
244 def __init__(self, name=None):
245 # initialize the base class
246 force._force.__init__(self, name);
248 self.cpp_force = None;
250 # setup the coefficient vector
251 self.force_coeff = coeff();
253 self.name = name
254 self.enabled = True;
256 # create force data iterator
257 self.external_forces = data.force_data(self);
259 def update_coeffs(self):
260 coeff_list = self.required_coeffs;
261 # check that the force coefficients are valid
262 if not self.force_coeff.verify(coeff_list):
263 globals.msg.error("Not all force coefficients are set\n");
264 raise RuntimeError("Error updating force coefficients");
266 # set all the params
267 ntypes = globals.system_definition.getParticleData().getNTypes();
268 type_list = [];
269 for i in range(0,ntypes):
270 type_list.append(globals.system_definition.getParticleData().getNameByType(i));
272 for i in range(0,ntypes):
273 # build a dict of the coeffs to pass to proces_coeff
274 coeff_dict = {};
275 for name in coeff_list:
276 coeff_dict[name] = self.force_coeff.get(type_list[i], name);
278 param = self.process_coeff(coeff_dict);
279 self.cpp_force.setParams(i, param);
281 ## One-dimension periodic potential
283 # The command %periodic specifies that an external %force should be
284 # added to every particle in the simulation to induce a periodic modulation
285 # in the particle concentration. The force parameters can be set on a per-particle
286 # type-basis. The potential can e.g. be used to induce an ordered phase in a block-copolymer melt.
288 # The external potential \f$V(\vec{r}) \f$ is implemented using the following formula:
290 # \f[
291 # V(\vec{r}) = A * \tanh\left[\frac{1}{2 \pi p w} \cos\left(p \vec{b}_i\cdot\vec{r}\right)\right]
292 # \f]
294 # where \f$A\f$ is the ordering parameter, \f$\vec{b}_i\f$ is the reciprocal lattice vector direction
295 # \f$i=0..2\f$, \f$p\f$ the periodicity and \f$w\f$ the interface width
296 # (relative to the distance \f$2\pi/|\mathbf{b_i}|\f$ between planes in the \f$i\f$-direction).
297 # The modulation is one-dimensional. It extends along the lattice vector \f$\mathbf{a}_i\f$ of the
298 # simulation cell.
300 # \MPI_SUPPORTED
301 class periodic(_external_force):
302 ## Apply a force derived from a %periodic potential to all particles
304 # \b Examples:
305 # \code
306 # # Apply a periodic composition modulation along the first lattice vector
307 # periodic = external.periodic()
308 # periodic.force_coeff.set('A', A=1.0, i=0, w=0.02, p=3)
309 # periodic.force_coeff.set('B', A=-1.0, i=0, w=0.02, p=3)
310 # \endcode
312 def __init__(self, name=""):
313 util.print_status_line();
315 # initialize the base class
316 _external_force.__init__(self, name);
318 # create the c++ mirror class
319 if not globals.exec_conf.isCUDAEnabled():
320 self.cpp_force = hoomd.PotentialExternalPeriodic(globals.system_definition,self.name);
321 else:
322 self.cpp_force = hoomd.PotentialExternalPeriodicGPU(globals.system_definition,self.name);
324 globals.system.addCompute(self.cpp_force, self.force_name);
326 # setup the coefficient options
327 self.required_coeffs = ['A','i','w','p'];
329 def process_coeff(self, coeff):
330 A = coeff['A'];
331 i = coeff['i'];
332 w = coeff['w'];
333 p = coeff['p'];
335 return hoomd.make_scalar4(hoomd.int_as_scalar(i), A, w, hoomd.int_as_scalar(p));