Add ConvergenceFailure class and test.

This commit is contained in:
Atgeirr Flø Rasmussen 2018-10-23 09:27:38 +02:00
parent 33da0aea09
commit 891912b04a
3 changed files with 251 additions and 0 deletions

View File

@ -131,6 +131,7 @@ list (APPEND TEST_SOURCE_FILES
tests/test_blackoil_amg.cpp
tests/test_block.cpp
tests/test_boprops_ad.cpp
tests/test_convergencestatus.cpp
tests/test_graphcoloring.cpp
tests/test_rateconverter.cpp
tests/test_span.cpp
@ -444,6 +445,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/timestepping/AdaptiveTimeStepping.hpp
opm/simulators/timestepping/AdaptiveTimeStepping_impl.hpp
opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp
opm/simulators/timestepping/ConvergenceStatus.hpp
opm/simulators/timestepping/TimeStepControl.hpp
opm/simulators/timestepping/TimeStepControlInterface.hpp
opm/simulators/timestepping/SimulatorTimer.hpp

View File

@ -0,0 +1,133 @@
/*
Copyright 2018 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2018 Equinor.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_CONVERGENCESTATUS_HEADER_INCLUDED
#define OPM_CONVERGENCESTATUS_HEADER_INCLUDED
#include <cassert>
#include <string>
#include <vector>
namespace Opm
{
/// Represents the convergence status of the whole simulator, to
/// make it possible to query and store the reasons for
/// convergence failures.
class ConvergenceStatus
{
public:
// ----------- Types -----------
enum Status { AllGood = 0,
ReservoirFailed = 1 << 0,
WellFailed = 1 << 1 };
struct ReservoirFailure
{
enum struct Type { Mb, Cnv };
Type type;
int phase;
int cell_index;
};
struct WellFailure
{
enum struct Type { Mb, Ctrl };
Type type;
int phase;
std::string well_name;
};
// ----------- Mutating member functions -----------
ConvergenceStatus()
: status_{AllGood}
, res_failures_{}
, well_failures_{}
{
}
void clear()
{
status_ = AllGood;
res_failures_.clear();
well_failures_.clear();
}
void setReservoirFailed(const ReservoirFailure& rf)
{
status_ = static_cast<Status>(status_ | ReservoirFailed);
res_failures_.push_back(rf);
}
void setWellFailed(const WellFailure& wf)
{
status_ = static_cast<Status>(status_ | WellFailed);
well_failures_.push_back(wf);
}
ConvergenceStatus& operator+=(const ConvergenceStatus& other)
{
status_ = static_cast<Status>(status_ | other.status_);
res_failures_.insert(res_failures_.end(), other.res_failures_.begin(), other.res_failures_.end());
well_failures_.insert(well_failures_.end(), other.well_failures_.begin(), other.well_failures_.end());
assert(reservoirFailed() != res_failures_.empty());
assert(wellFailed() != well_failures_.empty());
return *this;
}
// ----------- Const member functions (queries) -----------
bool converged() const
{
return status_ == AllGood;
}
bool reservoirFailed() const
{
return status_ & ReservoirFailed;
}
bool wellFailed() const
{
return status_ & WellFailed;
}
const std::vector<ReservoirFailure>& reservoirFailures() const
{
return res_failures_;
}
const std::vector<WellFailure>& wellFailures() const
{
return well_failures_;
}
private:
// ----------- Member variables -----------
Status status_;
std::vector<ReservoirFailure> res_failures_;
std::vector<WellFailure> well_failures_;
};
} // namespace Opm
#endif // OPM_CONVERGENCESTATUS_HEADER_INCLUDED

View File

@ -0,0 +1,116 @@
/*
Copyright 2018 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2018 Equinor.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#define BOOST_TEST_MODULE ConvergenceStatusTest
#include <boost/test/unit_test.hpp>
#include <opm/simulators/timestepping/ConvergenceStatus.hpp>
BOOST_AUTO_TEST_CASE(DefaultConstructor)
{
Opm::ConvergenceStatus s;
BOOST_CHECK(s.converged());
BOOST_CHECK(!s.reservoirFailed());
BOOST_CHECK(!s.wellFailed());
}
BOOST_AUTO_TEST_CASE(Failures)
{
using CS = Opm::ConvergenceStatus;
Opm::ConvergenceStatus s1;
s1.setReservoirFailed({CS::ReservoirFailure::Type::Cnv, 2, 100});
{
BOOST_CHECK(!s1.converged());
BOOST_CHECK(s1.reservoirFailed());
BOOST_CHECK(!s1.wellFailed());
BOOST_REQUIRE(s1.reservoirFailures().size() == 1);
const auto f = s1.reservoirFailures()[0];
BOOST_CHECK(f.type == CS::ReservoirFailure::Type::Cnv);
BOOST_CHECK(f.phase == 2);
BOOST_CHECK(f.cell_index == 100);
BOOST_CHECK(s1.wellFailures().empty());
}
Opm::ConvergenceStatus s2;
s2.setWellFailed({CS::WellFailure::Type::Ctrl, -1, "PRODUCER-123"});
s2.setWellFailed({CS::WellFailure::Type::Mb, 2, "INJECTOR-XYZ"});
{
BOOST_CHECK(!s2.converged());
BOOST_CHECK(!s2.reservoirFailed());
BOOST_CHECK(s2.wellFailed());
BOOST_CHECK(s2.reservoirFailures().empty());
BOOST_REQUIRE(s2.wellFailures().size() == 2);
const auto f0 = s2.wellFailures()[0];
BOOST_CHECK(f0.type == CS::WellFailure::Type::Ctrl);
BOOST_CHECK(f0.phase == -1);
BOOST_CHECK(f0.well_name == "PRODUCER-123");
const auto f1 = s2.wellFailures()[1];
BOOST_CHECK(f1.type == CS::WellFailure::Type::Mb);
BOOST_CHECK(f1.phase == 2);
BOOST_CHECK(f1.well_name == "INJECTOR-XYZ");
}
s1 += s2;
{
BOOST_CHECK(!s1.converged());
BOOST_CHECK(s1.reservoirFailed());
BOOST_CHECK(s1.wellFailed());
BOOST_REQUIRE(s1.reservoirFailures().size() == 1);
const auto f = s1.reservoirFailures()[0];
BOOST_CHECK(f.type == CS::ReservoirFailure::Type::Cnv);
BOOST_CHECK(f.phase == 2);
BOOST_CHECK(f.cell_index == 100);
BOOST_REQUIRE(s1.wellFailures().size() == 2);
const auto f0 = s1.wellFailures()[0];
BOOST_CHECK(f0.type == CS::WellFailure::Type::Ctrl);
BOOST_CHECK(f0.phase == -1);
BOOST_CHECK(f0.well_name == "PRODUCER-123");
const auto f1 = s1.wellFailures()[1];
BOOST_CHECK(f1.type == CS::WellFailure::Type::Mb);
BOOST_CHECK(f1.phase == 2);
BOOST_CHECK(f1.well_name == "INJECTOR-XYZ");
}
s1.clear();
{
BOOST_CHECK(s1.converged());
BOOST_CHECK(!s1.reservoirFailed());
BOOST_CHECK(!s1.wellFailed());
}
s1 += s2;
{
BOOST_CHECK(!s1.converged());
BOOST_CHECK(!s1.reservoirFailed());
BOOST_CHECK(s1.wellFailed());
BOOST_CHECK(s1.reservoirFailures().empty());
BOOST_REQUIRE(s1.wellFailures().size() == 2);
const auto f0 = s1.wellFailures()[0];
BOOST_CHECK(f0.type == CS::WellFailure::Type::Ctrl);
BOOST_CHECK(f0.phase == -1);
BOOST_CHECK(f0.well_name == "PRODUCER-123");
const auto f1 = s1.wellFailures()[1];
BOOST_CHECK(f1.type == CS::WellFailure::Type::Mb);
BOOST_CHECK(f1.phase == 2);
BOOST_CHECK(f1.well_name == "INJECTOR-XYZ");
}
}