1 /* Ergo, version 3.8, a program for linear scaling electronic structure
2  * calculations.
3  * Copyright (C) 2019 Elias Rudberg, Emanuel H. Rubensson, Pawel Salek,
4  * and Anastasia Kruchinina.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Primary academic reference:
20  * Ergo: An open-source program for linear-scaling electronic structure
21  * calculations,
22  * Elias Rudberg, Emanuel H. Rubensson, Pawel Salek, and Anastasia
23  * Kruchinina,
24  * SoftwareX 7, 107 (2018),
25  * <http://dx.doi.org/10.1016/j.softx.2018.03.005>
26  *
27  * For further information about Ergo, see <http://www.ergoscf.org>.
28  */
29 
30 /** @file SCF_statistics.cc
31 
32     @brief Class for keeping timings and other statistics related to
33     self-consistent field (SCF) procedure.
34 
35     @author: Emanuel Rubensson <em>responsible</em>.
36 */
37 
38 #include <stdexcept>
39 #include <fstream>
40 #include "SCF_statistics.h"
41 
SCF_timer()42 SCF_timer::SCF_timer()
43   : stopped_already(false) {
44   startTimeWall = Util::TimeMeter::get_wall_seconds();
45   Util::TimeMeter::get_current_cpu_times(startTimeCPU_usr, startTimeCPU_sys);
46 }
47 
stop()48 void SCF_timer::stop() {
49   if (stopped_already)
50     throw std::runtime_error("Attempt to stop timer already stopped.");
51   elapsedTimeWall = Util::TimeMeter::get_wall_seconds() - startTimeWall;
52   double stopTimeCPU_sys, stopTimeCPU_usr;
53   Util::TimeMeter::get_current_cpu_times(stopTimeCPU_usr, stopTimeCPU_sys);
54   elapsedTimeCPU_sys = stopTimeCPU_sys - startTimeCPU_sys;
55   elapsedTimeCPU_usr = stopTimeCPU_usr - startTimeCPU_usr;
56   stopped_already = true;
57 }
58 
start_timer(std::string identifier)59 void SCF_statistics::start_timer(std::string identifier) {
60   timers[identifier] = SCF_timer();
61 }
stop_timer(std::string identifier)62 void SCF_statistics::stop_timer(std::string identifier) {
63   if ( timers.find(identifier) == timers.end() )
64     throw std::runtime_error("Attempt to stop timer not in timer map.");
65   timers[identifier].stop();
66 }
67 
add_value(std::string identifier,double value)68 void SCF_statistics::add_value(std::string identifier, double value) {
69   if ( values.find(identifier) != values.end() )
70     throw std::runtime_error("Attempt to add value already in value map.");
71   values[identifier] = value;
72 }
73 
add_values(ValueMap & values_to_add)74 void  SCF_statistics::add_values( ValueMap & values_to_add) {
75   ValueMap::const_iterator it;
76   for ( it=values_to_add.begin() ; it != values_to_add.end(); it++ )
77     values[it->first] = it->second;
78 }
79 
80 
output_mfile(std::string name)81 void SCF_statistics::output_mfile(std::string name) {
82   std::string m_name = name + ".m";
83   std::ofstream os(m_name.c_str());
84 
85   // First output the names of all variables as one big comment
86   os << "%% SCF_statistics, list of all variables " << std::endl;
87   {
88     os << "%% Timers: " << std::endl;
89     TimerMap::const_iterator it;
90     for ( it=timers.begin() ; it != timers.end(); it++ ) {
91       std::string s = (*it).first;
92       std::string s_wall = s + "_walltime";
93       std::string s_cpu_sys = s + "_cpu_sys";
94       std::string s_cpu_usr = s + "_cpu_usr";
95       os << "% " << s_wall    << std::endl;
96       os << "% " << s_cpu_sys << std::endl;
97       os << "% " << s_cpu_usr << std::endl;
98     }
99   }
100   {
101     os << "%% Other values: " << std::endl;
102     ValueMap::const_iterator it;
103     for ( it=values.begin() ; it != values.end(); it++ ) {
104       std::string s = (*it).first;
105       os << "% " << s << std::endl;
106     }
107   }
108   os << "%" << std::endl << std::endl;
109 
110   // Now output the values
111   os << "%% SCF_statistics timers " << std::endl;
112   {
113     TimerMap::const_iterator it;
114     for ( it=timers.begin() ; it != timers.end(); it++ ) {
115       std::string s = (*it).first;
116       std::string s_wall = s + "_walltime";
117       std::string s_cpu_sys = s + "_cpu_sys";
118       std::string s_cpu_usr = s + "_cpu_usr";
119       double time_cpu_sys = (*it).second.elapsedTimeCPU_sys;
120       double time_cpu_usr = (*it).second.elapsedTimeCPU_usr;
121       double time_wall = (*it).second.elapsedTimeWall;
122       output_value( os, s_wall   , time_wall    );
123       output_value( os, s_cpu_sys, time_cpu_sys );
124       output_value( os, s_cpu_usr, time_cpu_usr );
125     }
126   }
127   os << "%% SCF_statistics other values " << std::endl;
128   {
129     ValueMap::const_iterator it;
130     for ( it=values.begin() ; it != values.end(); it++ ) {
131       std::string s = (*it).first;
132       double value = (*it).second;
133       output_value( os, s, value );
134     }
135   }
136 }
137 
output_value(std::ofstream & os,std::string id,double value)138 void SCF_statistics::output_value( std::ofstream & os,
139 				   std::string id,
140 				   double value ) {
141   os << "if ( ~exist( '" << id << "' ) )" << std::endl;
142   os << "  " << id << " = [];" << std::endl;
143   os << "end" << std::endl;
144   os << id << " = [" << id << " " << value << "];"
145      << std::endl;
146 }
147