swh:1:snp:f521c49ab17ef7db6ec70b2430e1ed203f50383f
Raw File
Tip revision: cb53e9247fa3c9142b71a51e89973703ef99a77f authored by wenqing on 19 February 2021, 14:44:27 UTC
Merge branch 'somerton_thermal_K' into 'master'
Tip revision: cb53e92
SimpleMatrixVectorProvider.cpp
/**
 * \file
 * \copyright
 * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
 *            Distributed under a Modified BSD License.
 *              See accompanying file LICENSE.txt or
 *              http://www.opengeosys.org/project/license
 *
 */

#include "SimpleMatrixVectorProvider.h"

#include <cassert>
#include "BaseLib/Logging.h"

#include "BaseLib/Error.h"
#include "MathLib/LinAlg/LinAlg.h"
#include "MathLib/LinAlg/MatrixVectorTraits.h"

namespace LinAlg = MathLib::LinAlg;

namespace detail
{

template<typename MatVec>
MatVec*
transfer(std::map<std::size_t, MatVec*>& from_unused,
         std::map<MatVec*, std::size_t>& to_used,
         typename std::map<std::size_t, MatVec*>::iterator it)
{
    auto const id = it->first;
    auto& ptr = it->second;

    auto res = to_used.emplace(ptr, id);
    assert(res.second && "Emplacement failed.");
    from_unused.erase(it);
    return res.first->first;
}

template<typename MatVec>
void
transfer(std::map<MatVec*, std::size_t>& from_used,
         std::map<std::size_t, MatVec*>& to_unused,
         typename std::map<MatVec*, std::size_t>::iterator it)
{
    auto& ptr = it->first;
    auto const id = it->second;

    auto res = to_unused.emplace(id, ptr);
    assert(res.second && "Emplacement failed.");
    (void) res; // res unused if NDEBUG
    from_used.erase(it);
}

}  // namespace detail

namespace NumLib
{

template<bool do_search, typename MatVec, typename... Args>
std::pair<MatVec*, bool>
SimpleMatrixVectorProvider::
get_(std::size_t& id,
     std::map<std::size_t, MatVec*>& unused_map,
     std::map<MatVec*, std::size_t>& used_map,
     Args&&... args)
{
    if (id >= _next_id) {
        OGS_FATAL("An obviously uninitialized id argument has been passed."
            " This might not be a serious error for the current implementation,"
            " but it might become one in the future."
            " Hence, I will abort now.");
    }

    if (do_search)
    {
        auto it = unused_map.find(id);
        if (it != unused_map.end())
        {  // unused matrix/vector found
            return {::detail::transfer(unused_map, used_map, it), false};
        }
    }

    // not searched or not found, so create a new one
    id = _next_id++;
    auto res = used_map.emplace(
        MathLib::MatrixVectorTraits<MatVec>::newInstance(std::forward<Args>(args)...).release(),
        id);
    assert(res.second && "Emplacement failed.");
    return { res.first->first, true };
}

template<bool do_search, typename... Args>
std::pair<GlobalMatrix*, bool>
SimpleMatrixVectorProvider::
getMatrix_(std::size_t& id, Args&&... args)
{
    return get_<do_search>(id, _unused_matrices, _used_matrices, std::forward<Args>(args)...);
}


GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix()
{
    std::size_t id = 0u;
    return *getMatrix_<false>(id).first;
}

GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix(std::size_t& id)
{
    return *getMatrix_<true>(id).first;
}

GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix(MathLib::MatrixSpecifications const& ms)
{
    std::size_t id = 0u;
    return *getMatrix_<false>(id, ms).first;
    // TODO assert that the returned object always is of the right size
}

GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix(MathLib::MatrixSpecifications const& ms, std::size_t& id)
{
    return *getMatrix_<true>(id, ms).first;
    // TODO assert that the returned object always is of the right size
}

GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix(GlobalMatrix const& A)
{
    std::size_t id = 0u;
    auto const& res = getMatrix_<false>(id, A);
    if (!res.second)
    {  // no new object has been created
        LinAlg::copy(A, *res.first);
    }
    return *res.first;
}

GlobalMatrix&
SimpleMatrixVectorProvider::
getMatrix(GlobalMatrix const& A, std::size_t& id)
{
    auto const& res = getMatrix_<true>(id, A);
    if (!res.second)
    {  // no new object has been created
        LinAlg::copy(A, *res.first);
    }
    return *res.first;
}

void
SimpleMatrixVectorProvider::
releaseMatrix(GlobalMatrix const& A)
{
    auto it = _used_matrices.find(const_cast<GlobalMatrix*>(&A));
    if (it == _used_matrices.end()) {
        OGS_FATAL("The given matrix has not been found. Cannot release it. Aborting.");
    } else {
        ::detail::transfer(_used_matrices, _unused_matrices, it);
    }
}

template<bool do_search, typename... Args>
std::pair<GlobalVector*, bool>
SimpleMatrixVectorProvider::
getVector_(std::size_t& id, Args&&... args)
{
    return get_<do_search>(id, _unused_vectors, _used_vectors, std::forward<Args>(args)...);
}


GlobalVector&
SimpleMatrixVectorProvider::
getVector()
{
    std::size_t id = 0u;
    return *getVector_<false>(id).first;
}

GlobalVector&
SimpleMatrixVectorProvider::
getVector(std::size_t& id)
{
    return *getVector_<true>(id).first;
}

GlobalVector&
SimpleMatrixVectorProvider::
getVector(MathLib::MatrixSpecifications const& ms)
{
    std::size_t id = 0u;
    return *getVector_<false>(id, ms).first;
    // TODO assert that the returned object always is of the right size
}

GlobalVector&
SimpleMatrixVectorProvider::
getVector(MathLib::MatrixSpecifications const& ms, std::size_t& id)
{
    return *getVector_<true>(id, ms).first;
    // TODO assert that the returned object always is of the right size
}

GlobalVector&
SimpleMatrixVectorProvider::
getVector(GlobalVector const& x)
{
    std::size_t id = 0u;
    auto const& res = getVector_<false>(id, x);
    if (!res.second)
    {  // no new object has been created
        LinAlg::copy(x, *res.first);
    }
    return *res.first;
}

GlobalVector&
SimpleMatrixVectorProvider::
getVector(GlobalVector const& x, std::size_t& id)
{
    auto const& res = getVector_<true>(id, x);
    if (!res.second)
    {  // no new object has been created
        LinAlg::copy(x, *res.first);
    }
    return *res.first;
}

void
SimpleMatrixVectorProvider::
releaseVector(GlobalVector const& x)
{
    auto it = _used_vectors.find(const_cast<GlobalVector*>(&x));
    if (it == _used_vectors.end()) {
        OGS_FATAL("The given vector has not been found. Cannot release it. Aborting.");
    } else {
        ::detail::transfer(_used_vectors, _unused_vectors, it);
    }
}

SimpleMatrixVectorProvider::
~SimpleMatrixVectorProvider()
{
    if (!_used_matrices.empty())
    {
        WARN(
            "There are still {:d} global matrices in use."
            " This might be an indicator of a possible waste of memory.",
            _used_matrices.size());
    }
    if (!_used_vectors.empty())
    {
        WARN(
            "There are still {:d} global vectors in use."
            " This might be an indicator of a possible waste of memory.",
            _used_vectors.size());
    }

    for (auto& id_ptr : _unused_matrices)
    {
        delete id_ptr.second;
    }

    for (auto& ptr_id : _used_matrices)
    {
        delete ptr_id.first;
    }

    for (auto& id_ptr : _unused_vectors)
    {
        delete id_ptr.second;
    }

    for (auto& ptr_id : _used_vectors)
    {
        delete ptr_id.first;
    }
}

}  // namespace NumLib
back to top