2 Highly Optimized Object-oriented Many-particle Dynamics -- Blue Edition
3 (HOOMD-blue) Open Source Software License Copyright 2009-2014 The Regents of
4 the University of Michigan All rights reserved.
6 HOOMD-blue may contain modifications ("Contributions") provided, and to which
7 copyright is held, by various Contributors who have granted The Regents of the
8 University of Michigan the right to modify and/or distribute such Contributions.
10 You may redistribute, use, and create derivate works of HOOMD-blue, in source
11 and binary forms, provided you abide by the following conditions:
13 * Redistributions of source code must retain the above copyright notice, this
14 list of conditions, and the following disclaimer both in the code and
15 prominently in any materials provided with the distribution.
17 * Redistributions in binary form must reproduce the above copyright notice, this
18 list of conditions, and the following disclaimer in the documentation and/or
19 other materials provided with the distribution.
21 * All publications and presentations based on HOOMD-blue, including any reports
22 or published results obtained, in whole or in part, with HOOMD-blue, will
23 acknowledge its use according to the terms posted at the time of submission on:
24 http://codeblue.umich.edu/hoomd-blue/citations.html
26 * Any electronic documents citing HOOMD-Blue will link to the HOOMD-Blue website:
27 http://codeblue.umich.edu/hoomd-blue/
29 * Apart from the above required attributions, neither the name of the copyright
30 holder nor the names of HOOMD-blue's contributors may be used to endorse or
31 promote products derived from this software without specific prior written
36 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS'' AND
37 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
38 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND/OR ANY
39 WARRANTIES THAT THIS SOFTWARE IS FREE OF INFRINGEMENT ARE DISCLAIMED.
41 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
42 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
43 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
46 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
47 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50 // Maintainer: joaander
55 #include "Integrator.h"
62 #include <boost/python.hpp>
68 //! Forward declarations
73 \brief Declares the System class and associated helper classes
77 #error This header cannot be compiled by nvcc
80 //! Ties Analyzers, Updaters, and Computes together to run a full MD simulation
81 /*! The System class is responsible for making all the time steps in an MD simulation.
82 It brings Analyzers, Updaters, and Computes all in one place to implement the full
83 simulation. Any number of Analyzers and Updaters can be added, but only one Integrator.
85 Usage: Add the Analyzers and Updaters, along with an Integrator to the System.
86 Then call run() with the desired number of time steps to execute.
87 Any added Analyzers or Updaters can be removed as desired and run()
88 can be called multiple times if a multiple stage simulation is needed.
90 Calling run() will step forward the specified number of time steps.
91 During each time step, the Analyzers added have their Analyzer::analyze()
92 methods called first, in the order in which they were added. A period
93 can be specified when adding the Analyzer so that it only runs every so
94 often. Then, all Updaters have their Updater::update() methods called,
95 in order and with a specified period as with the anlalyzers. Finally, the
96 Integrator::update() method is called to advance the simulation forward
97 one step and the process is repeated again.
99 \note Adding/removing/accessing analyzers, updaters, and computes by name
100 is meant to be a once per simulation operation. In other words, the accesses
103 See \ref page_system_class_design for more info.
111 System(boost::shared_ptr
<SystemDefinition
> sysdef
, unsigned int initial_tstep
);
113 // -------------- Analyzer get/set methods
116 void addAnalyzer(boost::shared_ptr
<Analyzer
> analyzer
, const std::string
& name
, unsigned int period
);
118 //! Removes an Analyzer
119 void removeAnalyzer(const std::string
& name
);
121 //! Access a stored Analyzer by name
122 boost::shared_ptr
<Analyzer
> getAnalyzer(const std::string
& name
);
124 //! Change the period of an Analyzer
125 void setAnalyzerPeriod(const std::string
& name
, unsigned int period
);
127 //! Change the period of an Analyzer to be variable
128 void setAnalyzerPeriodVariable(const std::string
& name
, boost::python::object update_func
);
130 //! Get the period of an Analyzer
131 unsigned int getAnalyzerPeriod(const std::string
& name
);
133 // -------------- Updater get/set methods
136 void addUpdater(boost::shared_ptr
<Updater
> updater
, const std::string
& name
, unsigned int period
);
138 //! Removes an Updater
139 void removeUpdater(const std::string
& name
);
141 //! Access a stored Updater by name
142 boost::shared_ptr
<Updater
> getUpdater(const std::string
& name
);
144 //! Change the period of an Updater
145 void setUpdaterPeriod(const std::string
& name
, unsigned int period
);
147 //! Change the period of an Updater to be variable
148 void setUpdaterPeriodVariable(const std::string
& name
, boost::python::object update_func
);
150 //! Get the period of on Updater
151 unsigned int getUpdaterPeriod(const std::string
& name
);
153 // -------------- Compute get/set methods
156 void addCompute(boost::shared_ptr
<Compute
> compute
, const std::string
& name
);
158 //! Removes a Compute
159 void removeCompute(const std::string
& name
);
161 //! Access a stored Compute by name
162 boost::shared_ptr
<Compute
> getCompute(const std::string
& name
);
164 // -------------- Integrator methods
166 //! Sets the current Integrator
167 void setIntegrator(boost::shared_ptr
<Integrator
> integrator
);
169 //! Gets the current Integrator
170 boost::shared_ptr
<Integrator
> getIntegrator();
173 // -------------- Methods for communication
175 //! Sets the communicator
176 void setCommunicator(boost::shared_ptr
<Communicator
> comm
);
178 //! Returns the communicator
179 boost::shared_ptr
<Communicator
> getCommunicator()
185 // -------------- Methods for running the simulation
187 //! Runs the simulation for a number of time steps
188 void run(unsigned int nsteps
, unsigned int cb_frequency
,
189 boost::python::object callback
, double limit_hours
=0.0f
,
190 unsigned int limit_multiple
=1);
192 //! Configures profiling of runs
193 void enableProfiler(bool enable
);
195 //! Toggle whether or not to print the status line and TPS for each run
196 void enableQuietRun(bool enable
)
198 m_quiet_run
= enable
;
202 void registerLogger(boost::shared_ptr
<Logger
> logger
);
204 //! Sets the statistics period
205 void setStatsPeriod(unsigned int seconds
);
207 //! Get the average TPS from the last run
208 Scalar
getLastTPS() const
213 //! Get the current time step
214 unsigned int getCurrentTimeStep()
219 // -------------- Misc methods
221 //! Get the system definition
222 boost::shared_ptr
<SystemDefinition
> getSystemDefinition()
227 //! Set autotuner parameters
228 void setAutotunerParams(bool enable
, unsigned int period
);
231 //! Holds an item in the list of analyzers
235 /*! \param analyzer the Analyzer shared pointer to store
236 \param name user defined name of the analyzer
237 \param period number of time steps between calls to Analyzer::analyze() for this analyzer
238 \param created_tstep time step the analyzer was created on
240 analyzer_item(boost::shared_ptr
<Analyzer
> analyzer
, const std::string
& name
, unsigned int period
,
241 unsigned int created_tstep
)
242 : m_analyzer(analyzer
), m_name(name
), m_period(period
), m_created_tstep(created_tstep
), m_next_execute_tstep(created_tstep
), m_is_variable_period(false), m_n(1)
246 //! Tets if this analyzer should be executed
247 /*! \param tstep Current simulation step
248 \returns true if the Analyzer should be executed this \a tstep
249 \note This function maintains state and should only be called once per time step
251 bool shouldExecute(unsigned int tstep
)
253 if (tstep
== m_next_execute_tstep
)
255 if (m_is_variable_period
)
257 boost::python::object pynext
= m_update_func(m_n
);
258 int next
= (int)boost::python::extract
<float>(pynext
) + m_created_tstep
;
262 cout
<< "***Warning! Variable period returned a negative value. Increasing to 1 to prevent inconsistancies" << endl
;
266 if ((unsigned int)next
<= tstep
)
268 cout
<< "***Warning! Variable period returned a value equal to the current timestep. Increasing by 1 to prevent inconsistancies" << endl
;
272 m_next_execute_tstep
= next
;
277 m_next_execute_tstep
+= m_period
;
285 //! Peek if this analyzer will execute on the given step
286 /*! \param tstep Requested simulation step
287 \returns true if the Analyze will be executed on \a tstep
289 peekExecute will return true for the same step that shouldExecute will. However, peekExecute does not
290 update any internal state. It offers a way to peek and determine if a given step will be the very next
291 step that the anlyzer is to be called.
293 bool peekExecute(unsigned int tstep
)
295 return (tstep
== m_next_execute_tstep
);
299 //! Changes the period
300 /*! \param period New period to set
301 \param tstep current time step
303 void setPeriod(unsigned int period
, unsigned int tstep
)
306 m_next_execute_tstep
= tstep
;
307 m_is_variable_period
= false;
310 //! Changes to a variable period
311 /*! \param update_func A python callable function. \a update_func(n) should return a positive integer which is the time step to update at frame n
312 \param tstep current time step
314 \a n is initialized to 1 when the period func is changed. Each time a new output is made, \a period_func is evaluated to
315 calculate the period to the next time step to make an output. \a n is then incremented by one.
317 void setVariablePeriod(boost::python::object update_func
, unsigned int tstep
)
319 m_update_func
= update_func
;
320 m_next_execute_tstep
= tstep
;
321 m_is_variable_period
= true;
324 boost::shared_ptr
<Analyzer
> m_analyzer
; //!< The analyzer
325 std::string m_name
; //!< Its name
326 unsigned int m_period
; //!< The period between analyze() calls
327 unsigned int m_created_tstep
; //!< The timestep when the analyzer was added
328 unsigned int m_next_execute_tstep
; //!< The next time step we will execute on
329 bool m_is_variable_period
; //!< True if the variable period should be used
331 unsigned int m_n
; //!< Current value of n for the variable period func
332 boost::python::object m_update_func
; //!< Python lambda function to evaluate time steps to update at
335 std::vector
<analyzer_item
> m_analyzers
; //!< List of analyzers belonging to this System
337 //! Holds an item in the list of updaters
341 /*! \param updater the Updater shared pointer to store
342 \param name user defined name of the updater
343 \param period number of time steps between calls to Updater::update() for this updater
344 \param created_tstep time step the analyzer was created on
346 updater_item(boost::shared_ptr
<Updater
> updater
, const std::string
& name
, unsigned int period
,
347 unsigned int created_tstep
)
348 : m_updater(updater
), m_name(name
), m_period(period
), m_created_tstep(created_tstep
), m_next_execute_tstep(created_tstep
), m_is_variable_period(false), m_n(1)
352 //! Tets if this updater should be executed
353 /*! \param tstep Current simulation step
354 \returns true if the Updater should be executed this \a tstep
355 \note This function maintains state and should only be called once per time step
357 bool shouldExecute(unsigned int tstep
)
359 if (tstep
== m_next_execute_tstep
)
361 if (m_is_variable_period
)
363 boost::python::object pynext
= m_update_func(m_n
);
364 int next
= (int)boost::python::extract
<float>(pynext
) + m_created_tstep
;
368 cout
<< "***Warning! Variable period returned a negative value. Increasing to 1 to prevent inconsistancies" << endl
;
372 if ((unsigned int)next
<= tstep
)
374 cout
<< "***Warning! Variable period returned a value equal to the current timestep. Increasing by 1 to prevent inconsistancies" << endl
;
378 m_next_execute_tstep
= next
;
383 m_next_execute_tstep
+= m_period
;
391 //! Peek if this updater will execute on the given step
392 /*! \param tstep Requested simulation step
393 \returns true if the Analyze will be executed on \a tstep
395 peekExecute will return true for the same step that shouldExecute will. However, peekExecute does not
396 update any internal state. It offers a way to peek and determine if a given step will be the very next
397 step that the anlyzer is to be called.
399 bool peekExecute(unsigned int tstep
)
401 return (tstep
== m_next_execute_tstep
);
404 //! Changes the period
405 /*! \param period New period to set
406 \param tstep current time step
408 void setPeriod(unsigned int period
, unsigned int tstep
)
411 m_next_execute_tstep
= tstep
;
412 m_is_variable_period
= false;
415 //! Changes to a variable period
416 /*! \param update_func A python callable function. \a update_func(n) should return a positive integer which is the time step to update at frame n
417 \param tstep current time step
419 \a n is initialized to 1 when the period func is changed. Each time a new output is made, \a period_func is evaluated to
420 calculate the period to the next time step to make an output. \a n is then incremented by one.
422 void setVariablePeriod(boost::python::object update_func
, unsigned int tstep
)
424 m_update_func
= update_func
;
425 m_next_execute_tstep
= tstep
;
426 m_is_variable_period
= true;
429 boost::shared_ptr
<Updater
> m_updater
; //!< The analyzer
430 std::string m_name
; //!< Its name
431 unsigned int m_period
; //!< The period between analyze() calls
432 unsigned int m_created_tstep
; //!< The timestep when the analyzer was added
433 unsigned int m_next_execute_tstep
; //!< The next time step we will execute on
434 bool m_is_variable_period
; //!< True if the variable period should be used
436 unsigned int m_n
; //!< Current value of n for the variable period func
437 boost::python::object m_update_func
; //!< Python lambda function to evaluate time steps to update at
440 std::vector
<updater_item
> m_updaters
; //!< List of updaters belonging to this System
442 std::map
< std::string
, boost::shared_ptr
<Compute
> > m_computes
; //!< Named list of Computes belonging to this System
444 boost::shared_ptr
<Integrator
> m_integrator
; //!< Integrator that advances time in this System
445 boost::shared_ptr
<SystemDefinition
> m_sysdef
; //!< SystemDefinition for this System
446 boost::shared_ptr
<Profiler
> m_profiler
; //!< Profiler to profile runs
449 boost::shared_ptr
<Communicator
> m_comm
; //!< Communicator to use
451 unsigned int m_start_tstep
; //!< Intial time step of the current run
452 unsigned int m_end_tstep
; //!< Final time step of the current run
453 unsigned int m_cur_tstep
; //!< Current time step
455 ClockSource m_clk
; //!< A clock counting time from the beginning of the run
456 uint64_t m_last_status_time
; //!< Time (measured by m_clk) of the last time generateStatusLine() was called
457 unsigned int m_last_status_tstep
; //!< Time step last time generateStatusLine() was called
459 bool m_quiet_run
; //!< True to suppress the status line and TPS from being printed to stdout for each run
460 bool m_profile
; //!< True if runs should be profiled
461 unsigned int m_stats_period
; //!< Number of seconds between statistics output lines
463 // --------- Steps in the simulation run implemented in helper functions
464 //! Sets up m_profiler and attaches/detaches to/from all computes, updaters, and analyzers
465 void setupProfiling();
467 //! Prints detailed statistics for all attached computes, updaters, and integrators
470 //! Resets stats for all contained classes
473 //! Prints out a formatted status line
474 void generateStatusLine();
476 //! Get the flags needed for a particular step
477 PDataFlags
determineFlags(unsigned int tstep
);
479 // --------- Helper function for handling lists
480 //! Search for an Analyzer by name
481 std::vector
<analyzer_item
>::iterator
findAnalyzerItem(const std::string
&name
);
482 //! Search for an Updater by name
483 std::vector
<updater_item
>::iterator
findUpdaterItem(const std::string
&name
);
485 Scalar m_last_TPS
; //!< Stores the average TPS from the last run
486 boost::shared_ptr
<const ExecutionConfiguration
> m_exec_conf
; //!< Stored shared ptr to the execution configuration
489 //! Exports the System class to python
490 void export_System();