blob: 22e4bf3189222cc85f8c78629bda450cc56fa101 [file] [log] [blame]
//@HEADER
// ************************************************************************
//
// MiniFE: Simple Finite Element Assembly and Solve
// Copyright (2006-2013) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA
//
// ************************************************************************
//@HEADER
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
#ifdef MINIFE_REPORT_RUSAGE
#include <sys/time.h>
#include <sys/resource.h>
#endif
#include <miniFE_version.h>
#include <outstream.hpp>
#ifdef HAVE_MPI
#include <mpi.h>
#endif
#include <Box.hpp>
#include <BoxPartition.hpp>
#include <box_utils.hpp>
#include <Parameters.hpp>
#include <utils.hpp>
#include <driver.hpp>
#include <YAML_Doc.hpp>
#if MINIFE_INFO != 0
#include <miniFE_info.hpp>
#else
#include <miniFE_no_info.hpp>
#endif
//The following macros should be specified as compile-macros in the
//makefile. They are defaulted here just in case...
#ifndef MINIFE_SCALAR
#define MINIFE_SCALAR double
#endif
#ifndef MINIFE_LOCAL_ORDINAL
#define MINIFE_LOCAL_ORDINAL int
#endif
#ifndef MINIFE_GLOBAL_ORDINAL
#define MINIFE_GLOBAL_ORDINAL int
#endif
// ************************************************************************
void add_params_to_yaml(YAML_Doc& doc, miniFE::Parameters& params);
void add_configuration_to_yaml(YAML_Doc& doc, int numprocs, int numthreads);
void add_timestring_to_yaml(YAML_Doc& doc);
//
//We will create a 'box' of size nx X ny X nz, partition it among processors,
//then call miniFE::driver which will use the partitioned box as the domain
//from which to assemble finite-element matrices into a global matrix and
//vector, then solve the linear-system using Conjugate Gradients.
//
int main(int argc, char** argv) {
miniFE::Parameters params;
miniFE::get_parameters(argc, argv, params);
int numprocs = 1, myproc = 0;
miniFE::initialize_mpi(argc, argv, numprocs, myproc);
#ifdef HAVE_MPI
#ifdef USE_MPI_PCONTROL
MPI_Pcontrol(0);
#endif
#endif
miniFE::timer_type start_time = miniFE::mytimer();
#ifdef MINIFE_DEBUG
outstream(numprocs, myproc);
#endif
//make sure each processor has the same parameters:
miniFE::broadcast_parameters(params);
Box global_box = { 0, params.nx, 0, params.ny, 0, params.nz };
std::vector<Box> local_boxes(numprocs);
box_partition(0, numprocs, 2, global_box, &local_boxes[0]);
Box& my_box = local_boxes[myproc];
MINIFE_GLOBAL_ORDINAL num_my_ids = miniFE::get_num_ids<MINIFE_GLOBAL_ORDINAL>(my_box);
MINIFE_GLOBAL_ORDINAL min_ids = num_my_ids;
#ifdef HAVE_MPI
MPI_Datatype mpi_dtype = miniFE::TypeTraits<MINIFE_GLOBAL_ORDINAL>::mpi_type();
MPI_Allreduce(&num_my_ids, &min_ids, 1, mpi_dtype, MPI_MIN, MPI_COMM_WORLD);
#endif
if (min_ids == 0) {
std::cout<<"One or more processors have 0 equations. Not currently supported. Exiting."<<std::endl;
miniFE::finalize_mpi();
return 1;
}
std::ostringstream osstr;
osstr << "miniFE." << params.nx << "x" << params.ny << "x" << params.nz;
#ifdef HAVE_MPI
osstr << ".P"<<numprocs;
#endif
osstr << ".";
if (params.name != "") osstr << params.name << ".";
YAML_Doc doc("miniFE", MINIFE_VERSION, ".", osstr.str());
if (myproc == 0) {
add_params_to_yaml(doc, params);
add_configuration_to_yaml(doc, numprocs, params.numthreads);
add_timestring_to_yaml(doc);
}
//Most of the program is performed in the 'driver' function, which is
//templated on < Scalar, LocalOrdinal, GlobalOrdinal >.
//To run miniFE with float instead of double, or 'long long' instead of int,
//etc., change these template-parameters by changing the macro definitions in
//the makefile or on the make command-line.
int return_code =
miniFE::driver< MINIFE_SCALAR, MINIFE_LOCAL_ORDINAL, MINIFE_GLOBAL_ORDINAL>(global_box, my_box, params, doc);
miniFE::timer_type total_time = miniFE::mytimer() - start_time;
#ifdef MINIFE_REPORT_RUSAGE
struct rusage get_mem;
getrusage(RUSAGE_SELF, &get_mem);
long long int rank_rss = get_mem.ru_maxrss;
long long int global_rss = 0;
long long int max_rss = 0;
#ifdef HAVE_MPI
MPI_Reduce(&rank_rss, &global_rss, 1,
MPI_LONG_LONG, MPI_SUM, 0, MPI_COMM_WORLD);
MPI_Reduce(&rank_rss, &max_rss, 1,
MPI_LONG_LONG, MPI_MAX, 0, MPI_COMM_WORLD);
if (myproc == 0) {
doc.add("Global All-RSS (kB)", global_rss);
doc.add("Global Max-RSS (kB)", max_rss);
}
#else
doc.add("RSS (kB)", rank_rss);
#endif
#endif
if (myproc == 0) {
doc.add("Total Program Time",total_time);
doc.generateYAML();
}
miniFE::finalize_mpi();
return return_code;
}
void add_params_to_yaml(YAML_Doc& doc, miniFE::Parameters& params)
{
doc.add("Global Run Parameters","");
doc.get("Global Run Parameters")->add("dimensions","");
doc.get("Global Run Parameters")->get("dimensions")->add("nx",params.nx);
doc.get("Global Run Parameters")->get("dimensions")->add("ny",params.ny);
doc.get("Global Run Parameters")->get("dimensions")->add("nz",params.nz);
doc.get("Global Run Parameters")->add("load_imbalance", params.load_imbalance);
if (params.mv_overlap_comm_comp == 1) {
std::string val("1 (yes)");
doc.get("Global Run Parameters")->add("mv_overlap_comm_comp", val);
}
else {
std::string val("0 (no)");
doc.get("Global Run Parameters")->add("mv_overlap_comm_comp", val);
}
}
void add_configuration_to_yaml(YAML_Doc& doc, int numprocs, int numthreads)
{
doc.get("Global Run Parameters")->add("number of processors", numprocs);
doc.add("Platform","");
doc.get("Platform")->add("hostname",MINIFE_HOSTNAME);
doc.get("Platform")->add("kernel name",MINIFE_KERNEL_NAME);
doc.get("Platform")->add("kernel release",MINIFE_KERNEL_RELEASE);
doc.get("Platform")->add("processor",MINIFE_PROCESSOR);
doc.add("Build","");
doc.get("Build")->add("CXX",MINIFE_CXX);
#if MINIFE_INFO != 0
doc.get("Build")->add("compiler version",MINIFE_CXX_VERSION);
#endif
doc.get("Build")->add("CXXFLAGS",MINIFE_CXXFLAGS);
std::string using_mpi("no");
#ifdef HAVE_MPI
using_mpi = "yes";
#endif
doc.get("Build")->add("using MPI",using_mpi);
}
void add_timestring_to_yaml(YAML_Doc& doc)
{
std::time_t rawtime;
struct tm * timeinfo;
std::time(&rawtime);
timeinfo = std::localtime(&rawtime);
std::ostringstream osstr;
osstr.fill('0');
osstr << timeinfo->tm_year+1900 << "-";
osstr.width(2); osstr << timeinfo->tm_mon+1 << "-";
osstr.width(2); osstr << timeinfo->tm_mday << ", ";
osstr.width(2); osstr << timeinfo->tm_hour << "-";
osstr.width(2); osstr << timeinfo->tm_min << "-";
osstr.width(2); osstr << timeinfo->tm_sec;
std::string timestring = osstr.str();
doc.add("Run Date/Time",timestring);
}