Solver logic finished.

Methods isClose(), computeFromTri() and computeFromLine() are still dummies.
This commit is contained in:
Atgeirr Flø Rasmussen 2014-11-24 15:31:12 +01:00
parent c0fbb8ea03
commit 89b4ecb193
2 changed files with 142 additions and 23 deletions

View File

@ -35,7 +35,6 @@ namespace Opm
}
cell_neighbours_ = vertexNeighbours(grid);
orderCounterClockwise(grid, cell_neighbours_);
considered_.reserve(100);
}
/// Solve the eikonal equation.
@ -69,18 +68,21 @@ namespace Opm
const double inf = 1e100;
solution.clear();
solution.resize(num_cells, inf);
is_accepted_.clear();
is_accepted_.resize(num_cells, false);
accepted_front_.clear();
considered_.clear();
considered_handles_.clear();
is_considered_.clear();
is_considered_.resize(num_cells, false);
// 2. Move the startcells to Accepted. U_i = q(x_i)
std::vector<char> accepted(num_cells, false);
const int num_startcells = startcells.size();
for (int ii = 0; ii < num_startcells; ++ii) {
accepted[startcells[ii]] = true;
is_accepted_[startcells[ii]] = true;
solution[startcells[ii]] = 0.0;
}
std::set<int> accepted_front(startcells.begin(), startcells.end());
accepted_front_.insert(startcells.begin(), startcells.end());
// 3. Move cells adjacent to startcells to Considered, evaluate
// U_i = min_{(x_j,x_k) \in NF(x_i)} G_{j,k}
@ -89,24 +91,69 @@ namespace Opm
const int num_nb = cell_neighbours_[scell].size();
for (int nb = 0; nb < num_nb; ++nb) {
const int nb_cell = cell_neighbours_[scell][nb];
if (!is_considered_[nb_cell]) {
const double value = computeValue(nb_cell);
if (!is_accepted_[nb_cell] && !is_considered_[nb_cell]) {
const double value = computeValue(nb_cell, metric);
pushConsidered(std::make_pair(value, nb_cell));
is_considered_[nb_cell] = true;
}
}
}
// 4. Find the Considered cell with the smallest value: r.
while (!considered_.empty()) {
// 4. Find the Considered cell with the smallest value: r.
const ValueAndCell r = topConsidered();
// 5. Move cell r to Accepted. Update AcceptedFront.
// 5. Move cell r to Accepted. Update AcceptedFront.
const int rcell = r.second;
is_accepted_[rcell] = true;
solution[rcell] = r.first;
popConsidered();
accepted_front_.insert(rcell);
for (auto it = accepted_front_.begin(); it != accepted_front_.end();) {
// Note that loop increment happens in the body of this loop.
const int cell = *it;
bool on_front = false;
for (auto it2 = cell_neighbours_[cell].begin(); it2 != cell_neighbours_[cell].end(); ++it2) {
if (!is_accepted_[*it2]) {
on_front = true;
break;
}
}
if (!on_front) {
accepted_front_.erase(it++);
} else {
++it;
}
}
// 6. Move cells adjacent to r from Far to Considered.
// 6. Move cells adjacent to r from Far to Considered.
for (auto it = cell_neighbours_[rcell].begin(); it != cell_neighbours_[rcell].end(); ++it) {
const int nb_cell = *it;
if (!is_accepted_[nb_cell] && !is_considered_[nb_cell]) {
assert(solution[nb_cell] == inf);
const double value = computeValue(nb_cell, metric);
pushConsidered(std::make_pair(value, nb_cell));
}
}
// 7. Recompute the value for all Considered cells within
// distance h * F_2/F1 from x_r. Use min of previous and new.
// 7. Recompute the value for all Considered cells within
// distance h * F_2/F1 from x_r. Use min of previous and new.
for (auto it = considered_.begin(); it != considered_.end(); ++it) {
const int ccell = it->second;
if (isClose(rcell, ccell, metric)) {
const double value = computeValue(ccell, metric);
if (value < it->first) {
// Update value for considered cell.
// Note that as solution values decrease, their
// goodness w.r.t. the heap comparator increase,
// therefore we may safely call the increase()
// modificator below.
considered_.increase(considered_handles_[ccell], std::make_pair(value, ccell));
}
}
}
// 8. If Considered is not empty, go to step 4.
// 8. If Considered is not empty, go to step 4.
}
}
@ -114,15 +161,42 @@ namespace Opm
double AnisotropicEikonal2d::computeValue(const int cell) const
bool AnisotropicEikonal2d::isClose(const int c1,
const int c2,
const double* metric) const
{
return true;
}
double AnisotropicEikonal2d::computeValue(const int cell,
const double* metric) const
{
const auto& nbs = cell_neighbours_[cell];
const int num_nbs = nbs.size();
double val = 1e100;
const double inf = 1e100;
double val = inf;
for (int ii = 0; ii < num_nbs; ++ii) {
const int n[2] = { nbs[ii], nbs[(ii+1) % num_nbs] };
// if ... accepted front
if (accepted_front_.count(n[0]) && accepted_front_.count(n[1])) {
const double cand_val = computeFromTri(cell, n[0], n[1], metric);
val = std::min(val, cand_val);
}
}
if (val == inf) {
// Failed to find two accepted front nodes adjacent to this,
// so we go for a single-neighbour update.
for (int ii = 0; ii < num_nbs; ++ii) {
if (accepted_front_.count(nbs[ii])) {
const double cand_val = computeFromLine(cell, nbs[ii], metric);
val = std::min(val, cand_val);
}
}
}
assert(val != inf);
return val;
}
@ -130,9 +204,37 @@ namespace Opm
double AnisotropicEikonal2d::computeFromLine(const int cell,
const int from,
const double* metric) const
{
assert(!is_accepted_[cell]);
assert(is_accepted_[from]);
return 2.0;
}
double AnisotropicEikonal2d::computeFromTri(const int cell,
const int n0,
const int n1,
const double* metric) const
{
assert(!is_accepted_[cell]);
assert(is_accepted_[n0]);
assert(is_accepted_[n1]);
return 1.0;
}
const AnisotropicEikonal2d::ValueAndCell& AnisotropicEikonal2d::topConsidered() const
{
return considered_.front();
return considered_.top();
}
@ -141,8 +243,9 @@ namespace Opm
void AnisotropicEikonal2d::pushConsidered(const ValueAndCell& vc)
{
considered_.push_back(vc);
std::push_heap(considered_.begin(), considered_.end());
HeapHandle h = considered_.push(vc);
considered_handles_[vc.second] = h;
is_considered_[vc.second] = true;
}
@ -151,8 +254,9 @@ namespace Opm
void AnisotropicEikonal2d::popConsidered()
{
std::pop_heap(considered_.begin(), considered_.end());
considered_.pop_back();
is_considered_[considered_.top().second] = false;
considered_handles_.erase(considered_.top().second);
considered_.pop();
}

View File

@ -22,6 +22,7 @@
#include <opm/core/utility/SparseTable.hpp>
#include <vector>
#include <boost/heap/fibonacci_heap.hpp>
struct UnstructuredGrid;
@ -47,13 +48,27 @@ namespace Opm
const std::vector<int>& startcells,
std::vector<double>& solution);
private:
// Grid and topology.
const UnstructuredGrid& grid_;
SparseTable<int> cell_neighbours_;
// Keep track of accepted cells.
std::vector<char> is_accepted_;
std::set<int> accepted_front_;
// Keep track of considered cells.
typedef std::pair<double, int> ValueAndCell;
std::vector<ValueAndCell> considered_;
typedef boost::heap::compare<std::greater<ValueAndCell>> Comparator;
typedef boost::heap::fibonacci_heap<ValueAndCell, Comparator> Heap;
Heap considered_;
typedef Heap::handle_type HeapHandle;
std::map<int, HeapHandle> considered_handles_;
std::vector<char> is_considered_;
double computeValue(const int cell) const;
bool isClose(const int c1, const int c2, const double* metric) const;
double computeValue(const int cell, const double* metric) const;
double computeFromLine(const int cell, const int from, const double* metric) const;
double computeFromTri(const int cell, const int n0, const int n1, const double* metric) const;
const ValueAndCell& topConsidered() const;
void pushConsidered(const ValueAndCell& vc);