Added factory to construct the global representation of perf data.

Some of our computations are heavily serial and need a complete
representation of the data attached to all perforation no matter
whether a perforation lives on the local partition or not. This commit
adds a factory that allows to easily create such a representaion and
helps writing data back to the local representation.
This commit is contained in:
Markus Blatt
2020-12-18 14:48:19 +01:00
parent 53b51eeba7
commit 69fd6495c0
4 changed files with 414 additions and 21 deletions
+157 -6
View File
@@ -23,6 +23,9 @@
#include<string>
#include<tuple>
#include<ostream>
#include <random>
#include <algorithm>
#include <iterator>
#define BOOST_TEST_MODULE ParallelWellInfo
#include <boost/test/unit_test.hpp>
@@ -96,6 +99,8 @@ std::ostream& operator<<(std::ostream& os, const Opm::ParallelWellInfo& w)
}
}
constexpr int numPerProc = 3;
BOOST_AUTO_TEST_CASE(ParallelWellComparison)
{
int argc = 0;
@@ -232,7 +237,7 @@ std::vector<int> createGlobalEclIndex(const Communication& comm)
{
std::vector<int> globalEclIndex = {0, 1, 2, 3, 7 , 8, 10, 11};
auto oldSize = globalEclIndex.size();
std::size_t globalSize = 3 * comm.size();
std::size_t globalSize = numPerProc * comm.size();
auto lastIndex = globalEclIndex.back();
globalEclIndex.resize(globalSize);
if ( globalSize > oldSize)
@@ -251,14 +256,17 @@ template<class C>
std::vector<double> populateCommAbove(C& commAboveBelow,
const Communication& comm,
const std::vector<int>& globalEclIndex,
const std::vector<double> globalCurrent)
const std::vector<double> globalCurrent,
int num_component = 1,
bool local_consecutive = false)
{
std::vector<double> current(3);
auto size = numPerProc * num_component;
std::vector<double> current(size);
commAboveBelow.beginReset();
for (std::size_t i = 0; i < current.size(); ++i)
for (std::size_t i = 0; i < current.size()/num_component; i++)
{
auto gi = comm.rank() + comm.size() * i;
auto gi = local_consecutive ? comm.rank() * numPerProc + i : comm.rank() + comm.size() * i;
if (gi==0)
{
@@ -268,7 +276,8 @@ std::vector<double> populateCommAbove(C& commAboveBelow,
{
commAboveBelow.pushBackEclIndex(globalEclIndex[gi-1], globalEclIndex[gi]);
}
current[i] = globalCurrent[gi];
for(int c = 0; c < num_component; ++c)
current[i * num_component + c] = globalCurrent[gi * num_component + c];
}
commAboveBelow.endReset();
return current;
@@ -317,3 +326,145 @@ BOOST_AUTO_TEST_CASE(CommunicateAboveBelowParallel)
}
}
}
template<class Iter, class C>
void initRandomNumbers(Iter begin, Iter end, C comm)
{
// Initialize with random numbers.
std::random_device rndDevice;
std::mt19937 mersenneEngine {rndDevice()}; // Generates random integers
std::uniform_int_distribution<int> dist {1, 100};
auto gen = [&dist, &mersenneEngine](){
return dist(mersenneEngine);
};
std::generate(begin, end, gen);
comm.broadcast(&(*begin), end-begin, 0);
}
BOOST_AUTO_TEST_CASE(PartialSumself)
{
auto comm = Dune::MPIHelper::getLocalCommunicator();
Opm::CommunicateAboveBelow commAboveBelow{ comm };
std::vector<int> eclIndex = {0, 1, 2, 3, 7 , 8, 10, 11};
std::vector<double> current(eclIndex.size());
std::transform(eclIndex.begin(), eclIndex.end(), current.begin(),
[](double v){ return 1+10.0*v;});
commAboveBelow.beginReset();
for (std::size_t i = 0; i < current.size(); ++i)
{
if (i==0)
commAboveBelow.pushBackEclIndex(-1, eclIndex[i]);
else
commAboveBelow.pushBackEclIndex(eclIndex[i-1], eclIndex[i]);
}
commAboveBelow.endReset();
initRandomNumbers(std::begin(current), std::end(current),
Communication(comm));
auto stdCopy = current;
std::partial_sum(std::begin(stdCopy), std::end(stdCopy), std::begin(stdCopy));
commAboveBelow.partialSumPerfValues(std::begin(current), std::end(current));
BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(stdCopy), std::end(stdCopy),
std::begin(current), std::end(current));
}
BOOST_AUTO_TEST_CASE(PartialSumParallel)
{
auto comm = Communication(Dune::MPIHelper::getCommunicator());
Opm::CommunicateAboveBelow commAboveBelow{ comm };
auto globalEclIndex = createGlobalEclIndex(comm);
std::vector<double> globalCurrent(globalEclIndex.size());
initRandomNumbers(std::begin(globalCurrent), std::end(globalCurrent),
Communication(comm));
auto localCurrent = populateCommAbove(commAboveBelow, comm,
globalEclIndex, globalCurrent);
auto globalPartialSum = globalCurrent;
std::partial_sum(std::begin(globalPartialSum), std::end(globalPartialSum), std::begin(globalPartialSum));
commAboveBelow.partialSumPerfValues(std::begin(localCurrent), std::end(localCurrent));
for (std::size_t i = 0; i < localCurrent.size(); ++i)
{
auto gi = comm.rank() + comm.size() * i;
BOOST_CHECK(localCurrent[i]==globalPartialSum[gi]);
}
}
void testGlobalPerfFactoryParallel(int num_component, bool local_consecutive = false)
{
auto comm = Communication(Dune::MPIHelper::getCommunicator());
Opm::ParallelWellInfo wellInfo{ {"Test", true }, comm };
auto globalEclIndex = createGlobalEclIndex(comm);
std::vector<double> globalCurrent(globalEclIndex.size() * num_component);
std::vector<double> globalAdd(globalEclIndex.size() * num_component);
initRandomNumbers(std::begin(globalCurrent), std::end(globalCurrent),
comm);
initRandomNumbers(std::begin(globalAdd), std::end(globalAdd),
comm);
auto localCurrent = populateCommAbove(wellInfo, comm, globalEclIndex,
globalCurrent, num_component,
local_consecutive);
// A hack to get local values to add.
Opm::ParallelWellInfo dummy{ {"Test", true }, comm };
auto localAdd = populateCommAbove(dummy, comm, globalEclIndex,
globalAdd, num_component,
local_consecutive);
const auto& factory = wellInfo.getGlobalPerfContainerFactory();
auto globalCreated = factory.createGlobal(localCurrent, num_component);
BOOST_CHECK_EQUAL_COLLECTIONS(std::begin(globalCurrent), std::end(globalCurrent),
std::begin(globalCreated), std::end(globalCreated));
std::transform(std::begin(globalAdd), std::end(globalAdd),
std::begin(globalCreated), std::begin(globalCreated),
std::plus<double>());
auto globalSol = globalCurrent;
std::transform(std::begin(globalAdd), std::end(globalAdd),
std::begin(globalSol), std::begin(globalSol),
std::plus<double>());
auto localSol = localCurrent;
std::transform(std::begin(localAdd), std::end(localAdd),
std::begin(localSol), std::begin(localSol),
std::plus<double>());
factory.copyGlobalToLocal(globalCreated, localCurrent, num_component);
for (std::size_t i = 0; i < localCurrent.size() / num_component; ++i)
{
auto gi = local_consecutive ? comm.rank() * numPerProc + i :
comm.rank() + comm.size() * i;
for (int c = 0; c < num_component; ++c)
{
BOOST_CHECK(localCurrent[i * num_component + c]==globalSol[gi * num_component + c]);
BOOST_CHECK(localSol[i * num_component + c] == localCurrent[i * num_component + c]);
}
}
}
BOOST_AUTO_TEST_CASE(GlobalPerfFactoryParallel1)
{
testGlobalPerfFactoryParallel(1);
testGlobalPerfFactoryParallel(3);
}