Commit ca698493 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

#1453 PetscVector: ad a method to load parallel vector from ascii files.

parent 2bb3755c
...@@ -95,17 +95,27 @@ BOOST_FIXTURE_TEST_SUITE(processor_wise, fixture_type) ...@@ -95,17 +95,27 @@ BOOST_FIXTURE_TEST_SUITE(processor_wise, fixture_type)
BOOST_CHECK(FilesystemNS::File::DoExist(binary_file) == true); // created in previous test! BOOST_CHECK(FilesystemNS::File::DoExist(binary_file) == true); // created in previous test!
decltype(auto) vector = model.GetVector(); decltype(auto) vector = model.GetVector();
std::vector<PetscInt> ghost_padding;
if (mpi.Nprocessor<int>() > 1)
ghost_padding = vector.GetGhostPadding();
Wrappers::Petsc::Vector from_file;
from_file.InitParallelFromProcessorWiseAsciiFile(mpi,
static_cast<unsigned int>(vector.GetProcessorWiseSize(__FILE__, __LINE__)),
static_cast<unsigned int>(vector.GetProgramWiseSize(__FILE__, __LINE__)),
ghost_padding,
binary_file,
__FILE__, __LINE__);
std::string inequality_description;
Wrappers::Petsc::AreEqual(from_file,
vector,
NumericNS::DefaultEpsilon<double>(),
inequality_description,
__FILE__, __LINE__);
// BOOST_CHECK_EQUAL(inequality_description, "");
//
// std::string inequality_description;
// Wrappers::Petsc::AreEqual(from_file,
// vector,
// NumericNS::DefaultEpsilon<double>(),
// inequality_description,
// __FILE__, __LINE__);
//
// BOOST_CHECK_EQUAL(inequality_description, "");
} }
BOOST_AUTO_TEST_CASE(load_binary) BOOST_AUTO_TEST_CASE(load_binary)
...@@ -175,10 +185,10 @@ BOOST_FIXTURE_TEST_SUITE(program_wise, fixture_type) ...@@ -175,10 +185,10 @@ BOOST_FIXTURE_TEST_SUITE(program_wise, fixture_type)
std::string inequality_description; std::string inequality_description;
Wrappers::Petsc::AreEqual(from_file, Wrappers::Petsc::AreEqual(from_file,
vector, vector,
NumericNS::DefaultEpsilon<double>(), NumericNS::DefaultEpsilon<double>(),
inequality_description, inequality_description,
__FILE__, __LINE__); __FILE__, __LINE__);
BOOST_CHECK_EQUAL(inequality_description, ""); BOOST_CHECK_EQUAL(inequality_description, "");
} }
...@@ -189,6 +199,51 @@ BOOST_FIXTURE_TEST_SUITE(program_wise, fixture_type) ...@@ -189,6 +199,51 @@ BOOST_FIXTURE_TEST_SUITE(program_wise, fixture_type)
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
BOOST_FIXTURE_TEST_SUITE(sequential_only, fixture_type)
BOOST_AUTO_TEST_CASE(load_ascii)
{
decltype(auto) model = GetModel();
decltype(auto) mpi = model.GetMpi();
if (mpi.Nprocessor<int>() == 1)
{
std::string ascii_file = model.GetProgramWiseAsciiFile();
std::cout << "ASC II FILE = " << ascii_file << std::endl;
BOOST_CHECK(FilesystemNS::File::DoExist(ascii_file) == true); // created in previous test!
decltype(auto) vector = model.GetVector();
Wrappers::Petsc::Vector from_file;
std::vector<PetscInt> ghost_padding;
BOOST_CHECK_EQUAL(vector.GetProcessorWiseSize(__FILE__, __LINE__),
vector.GetProgramWiseSize(__FILE__, __LINE__));
from_file.InitSequentialFromFile(mpi,
ascii_file,
__FILE__, __LINE__);
std::string inequality_description;
Wrappers::Petsc::AreEqual(from_file,
vector,
NumericNS::DefaultEpsilon<double>(),
inequality_description,
__FILE__, __LINE__);
BOOST_CHECK_EQUAL(inequality_description, "");
}
}
BOOST_AUTO_TEST_CASE(load_binary)
{
}
BOOST_AUTO_TEST_SUITE_END()
PRAGMA_DIAGNOSTIC(pop) PRAGMA_DIAGNOSTIC(pop)
......
...@@ -43,8 +43,6 @@ namespace MoReFEM ...@@ -43,8 +43,6 @@ namespace MoReFEM
const char* invoking_file, int invoking_line, const char* invoking_file, int invoking_line,
binary_or_ascii binary_or_ascii_choice) binary_or_ascii binary_or_ascii_choice)
{ {
::MoReFEM::Wrappers::Petsc ::MoReFEM::Wrappers::Petsc
::AccessVectorContent<Utilities::Access::read_only> content(vector, ::AccessVectorContent<Utilities::Access::read_only> content(vector,
invoking_file, invoking_line); invoking_file, invoking_line);
......
...@@ -219,8 +219,6 @@ namespace MoReFEM ...@@ -219,8 +219,6 @@ namespace MoReFEM
* *
* This file is assumed to have been created with Print() method for a sequential vector. * This file is assumed to have been created with Print() method for a sequential vector.
* *
* Parallel case is not handled at all at the moment!
*
* \param[in] file File from which vector content is read. * \param[in] file File from which vector content is read.
* \copydoc doxygen_hide_invoking_file_and_line * \copydoc doxygen_hide_invoking_file_and_line
* \copydetails doxygen_hide_mpi_param * \copydetails doxygen_hide_mpi_param
...@@ -229,6 +227,27 @@ namespace MoReFEM ...@@ -229,6 +227,27 @@ namespace MoReFEM
const std::string& file, const std::string& file,
const char* invoking_file, int invoking_line); const char* invoking_file, int invoking_line);
/*!
* \brief Init a vector from the data read in the file.
*
* This file is assumed to have been created with Print() method.
*
* Current method is in fact able to create a sequential vector as well, but use rather
* InitSequentialFromFile() with its more friendly API if you need only the sequential case.
*
* \param[in] file File from which vector content is read.
* \copydetails doxygen_hide_parallel_with_ghosts_arg
* \copydoc doxygen_hide_invoking_file_and_line
* \copydetails doxygen_hide_mpi_param
*/
void InitParallelFromProcessorWiseAsciiFile(const Mpi& mpi,
unsigned int processor_wise_size,
unsigned int program_wise_size,
const std::vector<PetscInt>& ghost_padding,
const std::string& file,
const char* invoking_file, int invoking_line);
/*! /*!
* \brief Init from a program-wise binary file: load a vector dumped with View() method. * \brief Init from a program-wise binary file: load a vector dumped with View() method.
* *
......
...@@ -26,208 +26,262 @@ ...@@ -26,208 +26,262 @@
#include "ThirdParty/Wrappers/Petsc/Print.hpp" #include "ThirdParty/Wrappers/Petsc/Print.hpp"
namespace MoReFEM namespace MoReFEM::Wrappers::Petsc
{ {
namespace Wrappers namespace // anonymous
{
//! Basic function to read content of a simple file and stores the values into a vector of double.
//! Two different types of files are processable by this function:
//! - Ad hoc files generated by Internal::Wrappers::Petsc::PrintPerProcessor()
//! - Matlab files generated directly by Petsc.
std::vector<double> ReadAsciiFileContent(const std::string& file,
const char* invoking_file, int invoking_line);
} // namespace anonymous
Vector::Vector()
: petsc_vector_(PETSC_NULL),
do_petsc_destroy_(false) // Nothing is assigned yet!
{ }
Vector::Vector(const Vec& petsc_vector, bool do_destroy_petsc)
: petsc_vector_(petsc_vector),
do_petsc_destroy_(do_destroy_petsc)
{
assert(petsc_vector != PETSC_NULL);
}
Vector::Vector(const Vector& rhs)
: petsc_vector_(PETSC_NULL),
do_petsc_destroy_(rhs.do_petsc_destroy_)
{ {
CompleteCopy(rhs, __FILE__, __LINE__);
}
namespace Petsc
void Vector::InitFromProgramWiseBinaryFile(const Mpi& mpi,
unsigned int processor_wise_size,
unsigned int program_wise_size,
const std::vector<PetscInt>& ghost_padding,
const std::string& binary_file,
const char* invoking_file, int invoking_line)
{
assert(petsc_vector_ == PETSC_NULL);
assert(processor_wise_size <= program_wise_size && "Detect easily invalid order in arguments...");
do_petsc_destroy_ = true;
Viewer viewer(mpi,
binary_file,
FILE_MODE_READ,
invoking_file, invoking_line);
if (mpi.Nprocessor<int>() > 1)
{ {
InitMpiVectorWithGhost(mpi,
processor_wise_size,
Vector::Vector() program_wise_size,
: petsc_vector_(PETSC_NULL), ghost_padding,
do_petsc_destroy_(false) // Nothing is assigned yet! invoking_file, invoking_line);
{ }
Vector::Vector(const Vec& petsc_vector, bool do_destroy_petsc)
: petsc_vector_(petsc_vector),
do_petsc_destroy_(do_destroy_petsc)
{
assert(petsc_vector != PETSC_NULL);
}
Vector::Vector(const Vector& rhs)
: petsc_vector_(PETSC_NULL),
do_petsc_destroy_(rhs.do_petsc_destroy_)
{
CompleteCopy(rhs, __FILE__, __LINE__);
}
void Vector::InitFromProgramWiseBinaryFile(const Mpi& mpi,
unsigned int processor_wise_size,
unsigned int program_wise_size,
const std::vector<PetscInt>& ghost_padding,
const std::string& binary_file,
const char* invoking_file, int invoking_line)
{
assert(petsc_vector_ == PETSC_NULL);
assert(processor_wise_size <= program_wise_size && "Detect easily invalid order in arguments...");
do_petsc_destroy_ = true;
Viewer viewer(mpi, int error_code = VecLoad(petsc_vector_, viewer.GetUnderlyingPetscObject());
binary_file,
FILE_MODE_READ,
invoking_file, invoking_line);
if (mpi.Nprocessor<int>() > 1) if (error_code)
{ throw ExceptionNS::Exception(error_code, "VecLoad", invoking_file, invoking_line);
InitMpiVectorWithGhost(mpi,
processor_wise_size,
program_wise_size,
ghost_padding,
invoking_file, invoking_line);
int error_code = VecLoad(petsc_vector_, viewer.GetUnderlyingPetscObject()); UpdateGhosts(invoking_file, invoking_line);
if (error_code) }
throw ExceptionNS::Exception(error_code, "VecLoad", invoking_file, invoking_line); else
{
assert(processor_wise_size == program_wise_size);
assert(ghost_padding.empty());
UpdateGhosts(invoking_file, invoking_line); InitSequentialVector(mpi,
processor_wise_size,
invoking_file, invoking_line);
} int error_code = VecLoad(petsc_vector_, viewer.GetUnderlyingPetscObject());
else
{
assert(processor_wise_size == program_wise_size);
assert(ghost_padding.empty());
InitSequentialVector(mpi, if (error_code)
processor_wise_size, throw ExceptionNS::Exception(error_code, "VecLoad", invoking_file, invoking_line);
invoking_file, invoking_line); }
}
int error_code = VecLoad(petsc_vector_, viewer.GetUnderlyingPetscObject());
if (error_code) Vector::~Vector()
throw ExceptionNS::Exception(error_code, "VecLoad", invoking_file, invoking_line); {
} if (do_petsc_destroy_)
} {
assert(petsc_vector_ != PETSC_NULL);
int error_code = VecDestroy(&petsc_vector_);
assert(!error_code && "Error in Vec destruction."); // no exception in destructors!
static_cast<void>(error_code); // to avoid arning in release compilation.
}
}
Vector::~Vector()
{
if (do_petsc_destroy_)
{
assert(petsc_vector_ != PETSC_NULL);
int error_code = VecDestroy(&petsc_vector_);
assert(!error_code && "Error in Vec destruction."); // no exception in destructors!
static_cast<void>(error_code); // to avoid arning in release compilation.
}
}
void Vector::InitSequentialVector(const Mpi& mpi,
void Vector::InitSequentialVector(const Mpi& mpi, unsigned int size,
unsigned int size, const char* invoking_file, int invoking_line)
const char* invoking_file, int invoking_line) {
{ assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!");
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!"); int error_code = VecCreateSeq(mpi.GetCommunicator(), static_cast<PetscInt>(size), &petsc_vector_);
int error_code = VecCreateSeq(mpi.GetCommunicator(), static_cast<PetscInt>(size), &petsc_vector_); if (error_code)
if (error_code) throw ExceptionNS::Exception(error_code, "VecCreateSeq", invoking_file, invoking_line);
throw ExceptionNS::Exception(error_code, "VecCreateSeq", invoking_file, invoking_line);
do_petsc_destroy_ = true;
do_petsc_destroy_ = true; }
}
void Vector::InitMpiVector(const Mpi& mpi,
void Vector::InitMpiVector(const Mpi& mpi, unsigned int local_size,
unsigned int local_size, unsigned int global_size,
unsigned int global_size, const char* invoking_file, int invoking_line)
const char* invoking_file, int invoking_line) {
{ assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!");
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!"); assert(local_size <= global_size && "If not, either sequential mode or the local and global were "
assert(local_size <= global_size && "If not, either sequential mode or the local and global were " "provided in the wrong order.");
"provided in the wrong order.");
int error_code = VecCreateMPI(mpi.GetCommunicator(),
int error_code = VecCreateMPI(mpi.GetCommunicator(), static_cast<PetscInt>(local_size),
static_cast<PetscInt>(local_size), static_cast<PetscInt>(global_size),
static_cast<PetscInt>(global_size), &petsc_vector_);
&petsc_vector_);
if (error_code)
if (error_code) throw ExceptionNS::Exception(error_code, "VecCreateMPI", invoking_file, invoking_line);
throw ExceptionNS::Exception(error_code, "VecCreateMPI", invoking_file, invoking_line);
do_petsc_destroy_ = true;
do_petsc_destroy_ = true; }
}
void Vector::InitMpiVectorWithGhost(const Mpi& mpi,
void Vector::InitMpiVectorWithGhost(const Mpi& mpi, unsigned int local_size,
unsigned int local_size, unsigned int global_size,
unsigned int global_size, const std::vector<PetscInt>& ghost_padding,
const std::vector<PetscInt>& ghost_padding, const char* invoking_file, int invoking_line)
const char* invoking_file, int invoking_line) {
{ assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!");
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!"); assert(local_size <= global_size && "If not, either sequential mode or the local and global were "
assert(local_size <= global_size && "If not, either sequential mode or the local and global were " "provided in the wrong order.");
"provided in the wrong order.");
const PetscInt Nghost = static_cast<PetscInt>(ghost_padding.size());
const PetscInt Nghost = static_cast<PetscInt>(ghost_padding.size());
ghost_padding_ = ghost_padding;
ghost_padding_ = ghost_padding;
int error_code = VecCreateGhost(mpi.GetCommunicator(),
int error_code = VecCreateGhost(mpi.GetCommunicator(), static_cast<PetscInt>(local_size),
static_cast<PetscInt>(local_size), static_cast<PetscInt>(global_size),
static_cast<PetscInt>(global_size), Nghost,
Nghost, ghost_padding.data(),
ghost_padding.data(), &petsc_vector_);
&petsc_vector_);
if (error_code)
if (error_code) throw ExceptionNS::Exception(error_code, "VecCreateGhost", invoking_file, invoking_line);
throw ExceptionNS::Exception(error_code, "VecCreateGhost", invoking_file, invoking_line);
do_petsc_destroy_ = true;
do_petsc_destroy_ = true; }
}
void Vector::InitSequentialFromFile(const Mpi& mpi,
void Vector::InitSequentialFromFile(const Mpi& mpi, const std::string& file,
const std::string& file, const char* invoking_file, int invoking_line)
const char* invoking_file, int invoking_line) {
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!");
assert(mpi.Nprocessor<int>() == 1 && "This method assumes sequential case!");
std::vector<double> value_list = ReadAsciiFileContent(file,
invoking_file, invoking_line);
// Now Init the vector with the appropriate size.
const unsigned int Nvalue = static_cast<unsigned int>(value_list.size());
InitSequentialVector(mpi, Nvalue, invoking_file, invoking_line);
// And fill it with the values.
AccessVectorContent<Utilities::Access::read_and_write> content(*this, invoking_file, invoking_line);
for (auto i = 0u; i < Nvalue; ++i)
content[i] = value_list[static_cast<std::size_t>(i)];
}
void Vector::InitParallelFromProcessorWiseAsciiFile(const Mpi& mpi,
unsigned int processor_wise_size,
unsigned int program_wise_size,
const std::vector<PetscInt>& ghost_padding,
const std::string& file,
const char* invoking_file, int invoking_line)
{
assert(processor_wise_size <= program_wise_size);
InitMpiVectorWithGhost(mpi,
processor_wise_size,
program_wise_size,
ghost_padding,
invoking_file, invoking_line);
const auto value_list = ReadAsciiFileContent(file, invoking_file, invoking_line);
assert(value_list.size() == static_cast<std::size_t>(processor_wise_size));
{
AccessVectorContent<Utilities::Access::read_and_write> content(*this, invoking_file, invoking_line);
const auto size = content.GetSize(invoking_file, invoking_line);
assert(size == processor_wise_size);
for (auto i = 0u; i < size; ++i)
content[i] = value_list[i];
}
mpi.Barrier();
UpdateGhosts(invoking_file, invoking_line);
}
namespace // anonymous
{
std::vector<double> ReadAsciiFileContent(const std::string& file, const char* invoking_file, int invoking_line)
{
std::ifstream stream;
FilesystemNS::File::Read(stream, file, invoking_file, invoking_line);
std::string line;
std::vector<double> ret;
while (getline(stream, line))
{ {
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!"); // 4 lines to ignore in PETSc Matlab format.
assert(mpi.Nprocessor<int>() == 1 && "This method assumes sequential case!"); if (Utilities::String::StartsWith(line, "%")
|| Utilities::String::StartsWith(line, "Vec_")
std::ifstream stream; || Utilities::String::StartsWith(line, "];"))
FilesystemNS::File::Read(stream, file, invoking_file, invoking_line); continue;
std::string line; // All lines are expected to be one value.
std::vector<double> value_list; ret.push_back(std::stod(line));
while (getline(stream, line))
{
// 4 lines to ignore in PETSc Matlab format.
if (Utilities::String::StartsWith(line, "%")
|| Utilities::String::StartsWith(line, "Vec_")
|| Utilities::String::StartsWith(line, "];"))
continue;