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
53 \brief Defines the Logger class
57 #pragma warning( push )
58 #pragma warning( disable : 4244 )
63 #include <boost/python.hpp>
64 #include <boost/filesystem/operations.hpp>
65 #include <boost/filesystem/convenience.hpp>
66 using namespace boost::python
;
67 using namespace boost::filesystem
;
74 #include "Communicator.h"
77 /*! \param sysdef Specified for Analyzer, but not used directly by Logger
78 \param fname File name to write the log to
79 \param header_prefix String to write before the header
80 \param overwrite Will overwite an exiting file if true (default is to append)
82 Constructing a logger will open the file \a fname, overwriting it if it exists.
84 Logger::Logger(boost::shared_ptr
<SystemDefinition
> sysdef
,
85 const std::string
& fname
,
86 const std::string
& header_prefix
,
88 : Analyzer(sysdef
), m_delimiter("\t"), m_filename(fname
), m_header_prefix(header_prefix
), m_appending(!overwrite
), m_is_initialized(false)
90 m_exec_conf
->msg
->notice(5) << "Constructing Logger: " << fname
<< " " << header_prefix
<< " " << overwrite
<< endl
;
93 void Logger::openOutputFiles()
96 // only output to file on root processor
98 if (! m_exec_conf
->isRoot())
102 if (exists(m_filename
) && m_appending
)
104 m_exec_conf
->msg
->notice(3) << "analyze.log: Appending log to existing file \"" << m_filename
<< "\"" << endl
;
105 m_file
.open(m_filename
.c_str(), ios_base::in
| ios_base::out
| ios_base::ate
);
109 m_exec_conf
->msg
->notice(3) << "analyze.log: Creating new log in file \"" << m_filename
<< "\"" << endl
;
110 m_file
.open(m_filename
.c_str(), ios_base::out
);
116 m_exec_conf
->msg
->error() << "analyze.log: Error opening log file " << m_filename
<< endl
;
117 throw runtime_error("Error initializing Logger");
123 m_exec_conf
->msg
->notice(5) << "Destroying Logger" << endl
;
126 /*! \param compute The Compute to register
128 After the compute is registered, all of the compute's provided log quantities are available for
131 void Logger::registerCompute(boost::shared_ptr
<Compute
> compute
)
133 vector
< string
> provided_quantities
= compute
->getProvidedLogQuantities();
135 // loop over all log quantities
136 for (unsigned int i
= 0; i
< provided_quantities
.size(); i
++)
138 // first check if this quantity is already set, printing a warning if so
139 if (m_compute_quantities
.count(provided_quantities
[i
]) || m_updater_quantities
.count(provided_quantities
[i
]))
140 m_exec_conf
->msg
->warning() << "analyze.log: The log quantity " << provided_quantities
[i
] <<
141 " has been registered more than once. Only the most recent registration takes effect" << endl
;
142 m_compute_quantities
[provided_quantities
[i
]] = compute
;
143 m_exec_conf
->msg
->notice(6) << "analyze.log: Registering log quantity " << provided_quantities
[i
] << endl
;
147 /*! \param updater The Updater to register
149 After the updater is registered, all of the updater's provided log quantities are available for
152 void Logger::registerUpdater(boost::shared_ptr
<Updater
> updater
)
154 vector
< string
> provided_quantities
= updater
->getProvidedLogQuantities();
156 // loop over all log quantities
157 for (unsigned int i
= 0; i
< provided_quantities
.size(); i
++)
159 // first check if this quantity is already set, printing a warning if so
160 if (m_compute_quantities
.count(provided_quantities
[i
]) || m_updater_quantities
.count(provided_quantities
[i
]))
161 m_exec_conf
->msg
->warning() << "analyze.log: The log quantity " << provided_quantities
[i
] <<
162 " has been registered more than once. Only the most recent registration takes effect" << endl
;
163 m_updater_quantities
[provided_quantities
[i
]] = updater
;
167 /*! After calling removeAll(), no quantities are registered for logging
169 void Logger::removeAll()
171 m_compute_quantities
.clear();
172 m_updater_quantities
.clear();
175 /*! \param quantities A list of quantities to log
177 When analyze() is called, each quantitiy in the list will, in order, be requested
178 from the matching registered compute or updtaer and written to the file separated
179 by delimiters. After all quantities are written to the file a newline is written.
181 Each time setLoggedQuantities is called, a header listing the column names is also written.
183 void Logger::setLoggedQuantities(const std::vector
< std::string
>& quantities
)
185 m_logged_quantities
= quantities
;
187 // prepare or adjust storage for caching the logger properties.
188 cached_timestep
= -1;
189 cached_quantities
.resize(quantities
.size());
192 // only output to file on root processor
193 if (m_pdata
->getDomainDecomposition())
194 if (! m_exec_conf
->isRoot())
198 // open output files for writing
199 if (! m_is_initialized
)
202 m_is_initialized
= true;
204 // only write the header if this is a new file
207 // write out the header prefix
208 m_file
<< m_header_prefix
;
210 // timestep is always output
211 m_file
<< "timestep";
214 if (quantities
.size() == 0)
216 m_exec_conf
->msg
->warning() << "analyze.log: No quantities specified for logging" << endl
;
220 // only write the header if this is a new file
223 // only print the delimiter after the timestep if there are more quantities logged
224 m_file
<< m_delimiter
;
226 // write all but the last of the quantities separated by the delimiter
227 for (unsigned int i
= 0; i
< quantities
.size()-1; i
++)
228 m_file
<< quantities
[i
] << m_delimiter
;
229 // write the last one with no delimiter after it
230 m_file
<< quantities
[quantities
.size()-1] << endl
;
236 /*! \param delimiter Delimiter to place between columns in the output file
238 void Logger::setDelimiter(const std::string
& delimiter
)
240 m_delimiter
= delimiter
;
243 /*! \param timestep Time step to write out data for
245 Writes a single line of output to the log file with each specified quantity separated by
248 void Logger::analyze(unsigned int timestep
)
250 if (m_prof
) m_prof
->push("Log");
252 // update info in cache for later use and for immediate output.
253 for (unsigned int i
= 0; i
< m_logged_quantities
.size(); i
++)
254 cached_quantities
[i
] = getValue(m_logged_quantities
[i
], timestep
);
257 // only output to file on root processor
259 if (! m_exec_conf
->isRoot())
261 if (m_prof
) m_prof
->pop();
266 // The timestep is always output
267 m_file
<< setprecision(10) << timestep
;
268 cached_timestep
= timestep
;
270 // quit now if there is nothing to log
271 if (m_logged_quantities
.size() == 0)
276 // only print the delimiter after the timestep if there are more quantities logged
277 m_file
<< m_delimiter
;
279 // write all but the last of the quantities separated by the delimiter
280 for (unsigned int i
= 0; i
< m_logged_quantities
.size()-1; i
++)
281 m_file
<< setprecision(10) << cached_quantities
[i
] << m_delimiter
;
282 // write the last one with no delimiter after it
283 m_file
<< setprecision(10) << cached_quantities
[m_logged_quantities
.size()-1] << endl
;
288 m_exec_conf
->msg
->error() << "analyze.log: I/O error while writing log file" << endl
;
289 throw runtime_error("Error writting log file");
292 if (m_prof
) m_prof
->pop();
295 /*! \param quantity Quantity to get
297 Scalar
Logger::getCachedQuantity(const std::string
&quantity
)
299 // first see if it is the timestep number
300 if (quantity
== "timestep")
302 return Scalar(cached_timestep
);
305 // check to see if the quantity exists in the compute list
306 for (unsigned int i
= 0; i
< m_logged_quantities
.size(); i
++)
307 if (m_logged_quantities
[i
] == quantity
)
308 return cached_quantities
[i
];
310 m_exec_conf
->msg
->warning() << "analyze.log: Log quantity " << quantity
<< " is not registered, returning a value of 0" << endl
;
314 /*! \param quantity Quantity to get
315 \param timestep Time step to compute value for (needed for Compute classes)
317 Scalar
Logger::getValue(const std::string
&quantity
, int timestep
)
319 // first see if it is the built-in time quantity
320 if (quantity
== "time")
322 return Scalar(double(m_clk
.getTime())/1e9
);
324 // check to see if the quantity exists in the compute list
325 else if (m_compute_quantities
.count(quantity
))
327 // update the compute
328 m_compute_quantities
[quantity
]->compute(timestep
);
330 return m_compute_quantities
[quantity
]->getLogValue(quantity
, timestep
);
332 // check to see if the quantity exists in the updaters list
333 else if (m_updater_quantities
.count(quantity
))
336 return m_updater_quantities
[quantity
]->getLogValue(quantity
, timestep
);
340 m_exec_conf
->msg
->warning() << "analyze.log: Log quantity " << quantity
<< " is not registered, logging a value of 0" << endl
;
348 class_
<Logger
, boost::shared_ptr
<Logger
>, bases
<Analyzer
>, boost::noncopyable
>
349 ("Logger", init
< boost::shared_ptr
<SystemDefinition
>, const std::string
&, const std::string
&, bool >())
350 .def("registerCompute", &Logger::registerCompute
)
351 .def("registerUpdater", &Logger::registerUpdater
)
352 .def("removeAll", &Logger::removeAll
)
353 .def("setLoggedQuantities", &Logger::setLoggedQuantities
)
354 .def("setDelimiter", &Logger::setDelimiter
)
355 .def("getCachedQuantity", &Logger::getCachedQuantity
)
360 #pragma warning( pop )