threed-beam-fea/src/summary.cpp

206 lines
8.5 KiB
C++

// Copyright 2015. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: ryan.latture@gmail.com (Ryan Latture)
#include <iomanip>
#include <algorithm>
#include <limits>
#include "summary.h"
#include "boost/format.hpp"
namespace fea {
namespace {
typedef std::pair<std::string, unsigned int> fe_param_pair;
typedef std::pair<std::string, long long> timing_param_pair;
struct Location2D {
Location2D() : row(0), col(0) { };
Location2D(size_t _row, size_t _col) : row(_row), col(_col) { };
size_t row;
size_t col;
};
template<typename T>
std::pair<Location2D, Location2D> findMinMax2D(std::vector<std::vector<T>> input) {
Location2D min_elem, max_elem;
T min_val = std::numeric_limits<T>::max();
T max_val = -std::numeric_limits<T>::max();
const size_t num_cols = input[0].size();
for (size_t i = 0; i < input.size(); ++i) {
for (size_t j = 0; j < num_cols; ++j) {
if (input[i][j] > max_val) {
max_elem.row = i;
max_elem.col = j;
max_val = input[i][j];
}
if (input[i][j] < min_val) {
min_elem.row = i;
min_elem.col = j;
min_val = input[i][j];
}
}
}
return std::pair<Location2D, Location2D>(min_elem, max_elem);
}
template<class T>
int numDigits(T number) {
int digits = 0;
if (number < 0) digits = 1; // remove this line if '-' counts as a digit
while (number) {
number /= 10;
digits++;
}
return digits;
}
}
Summary::Summary()
: total_time_in_ms(0),
assembly_time_in_ms(0),
preprocessing_time_in_ms(0),
factorization_time_in_ms(0),
solve_time_in_ms(0),
nodal_forces_solve_time_in_ms(0),
tie_forces_solve_time_in_ms(0),
file_save_time_in_ms(0),
num_nodes(0),
num_elems(0),
num_bcs(0),
num_forces(0),
num_ties(0),
num_eqns(0),
nodal_displacements(0),
nodal_forces(0),
tie_forces(0) {
}
std::string Summary::FullReport() const {
std::string report = std::string("\nFinite Element Analysis Summary\n\nModel parameters\n");
boost::format fe_params_fmt = boost::format("\t%s : %d\n");
std::vector<fe_param_pair> fe_params(6);
fe_params[0] = fe_param_pair("Nodes", num_nodes);
fe_params[1] = fe_param_pair("Elements", num_elems);
fe_params[2] = fe_param_pair("BCs", num_bcs);
fe_params[3] = fe_param_pair("Ties", num_ties);
fe_params[4] = fe_param_pair("Forces ", num_forces);
fe_params[5] = fe_param_pair("Equations ", num_eqns);
// get the maximum number of digits in the model parameters for formatting
int max_digits = 1;
int num_digits;
for (std::vector<fe_param_pair>::iterator it = fe_params.begin(); it != fe_params.end(); ++it) {
num_digits = numDigits(it->second);
if (num_digits > max_digits)
max_digits = num_digits;
}
// set format for key, value pairs
fe_params_fmt.modify_item(1, boost::io::group(std::setw(20), std::left));
fe_params_fmt.modify_item(2, boost::io::group(std::setw(max_digits), std::right));
// append all fe parameter key, value pairs to the report
for (std::vector<fe_param_pair>::iterator it = fe_params.begin(); it != fe_params.end(); ++it) {
report.append(
(fe_params_fmt % it->first % it->second).str()
);
}
// write the total time the analysis took
report.append((boost::format("\n%s %dms\n") % "Total time" % total_time_in_ms).str());
// define timing data to write to report
std::vector<timing_param_pair> timing_params;
timing_params.reserve(7);
timing_params.push_back(timing_param_pair("Assembly time", assembly_time_in_ms));
timing_params.push_back(timing_param_pair("Preprocessesing time", preprocessing_time_in_ms));
timing_params.push_back(timing_param_pair("Factorization time", factorization_time_in_ms));
timing_params.push_back(timing_param_pair("Linear solve time", solve_time_in_ms));
timing_params.push_back(timing_param_pair("Forces solve time", nodal_forces_solve_time_in_ms));
if (num_ties > 0) {
timing_params.push_back(timing_param_pair("Ties solve time", tie_forces_solve_time_in_ms));
}
timing_params.push_back(timing_param_pair("File save time", file_save_time_in_ms));
max_digits = 1;
for (std::vector<timing_param_pair>::iterator it = timing_params.begin(); it != timing_params.end(); ++it) {
num_digits = numDigits(it->second);
if (num_digits > max_digits)
max_digits = num_digits;
}
// create generic format for timing data
boost::format timing_params_fmt = boost::format("\t%s : %dms\n");
timing_params_fmt.modify_item(1, boost::io::group(std::setw(30), std::left));
timing_params_fmt.modify_item(2, boost::io::group(std::setw(max_digits), std::right));
// append timing data to report
for (std::vector<timing_param_pair>::iterator it = timing_params.begin(); it != timing_params.end(); ++it) {
report.append(
(timing_params_fmt % it->first % it->second).str()
);
}
auto minmax = findMinMax2D(nodal_displacements);
report.append(
(boost::format(
"\nNodal displacements\n\tMinimum : Node %d\tDOF %d\tValue %.3f\n\tMaximum : Node %d\tDOF %d\tValue %.3f\n")
% minmax.first.row % minmax.first.col % nodal_displacements[minmax.first.row][minmax.first.col]
% minmax.second.row % minmax.second.col %
nodal_displacements[minmax.second.row][minmax.second.col]).str()
);
minmax = findMinMax2D(nodal_forces);
report.append(
(boost::format(
"\nNodal Forces\n\tMinimum : Node %d\tDOF %d\tValue %.3f\n\tMaximum : Node %d\tDOF %d\tValue %.3f\n")
% minmax.first.row % minmax.first.col % nodal_forces[minmax.first.row][minmax.first.col]
% minmax.second.row % minmax.second.col % nodal_forces[minmax.second.row][minmax.second.col]).str()
);
if (num_ties > 0) {
minmax = findMinMax2D(tie_forces);
report.append(
(boost::format(
"\nTie Forces\n\tMinimum : Tie %d\tDOF %d\tValue %.3f\n\tMaximum : Tie %d\tDOF %d\tValue %.3f\n")
% minmax.first.row % minmax.first.col % tie_forces[minmax.first.row][minmax.first.col]
% minmax.second.row % minmax.second.col % tie_forces[minmax.second.row][minmax.second.col]).str()
);
}
return report;
}
} // namespace fea