Skip to content
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
7c53477
mixed: matrix now supports 4x4 blocks
Jun 1, 2026
4d5b892
mixed: matrix now supports 2x2 blocks
Jun 2, 2026
1549a3e
mixed: matrix now has fallback for blocks larger than 4x4
Jun 2, 2026
5ed2e45
mixed: replace binary literals with hex counterparts
Jun 2, 2026
ef37609
mixed: preconditioner checks block size
Jun 3, 2026
ea06d8a
mixed: inverse and matrix multiplications for 4x4 blocks
Jun 4, 2026
2edec27
mixed: ilu0 and dilu now supports 4x4 blocks
Jun 4, 2026
405cf26
mixed: ilu0 and dilu now supports 2x2 blocks
Jun 4, 2026
1a02413
mixed: avx2 version of 4x4 inverse
Jun 8, 2026
d674391
mixed: legacy implementation now supports 4x4 blocks
Jun 8, 2026
84485e2
mixed: ilu0/dilu apply supports blocks larger than 4x4
Jun 9, 2026
ba6e3f4
mixed: ilu0/dilu update supports blocks larger than 4x4
Jun 9, 2026
216368b
mixed: support WellModelMatrixAdapter
Jun 17, 2026
6fade30
mixed: custom MixedGhostLastMatrixAdapter
Jun 22, 2026
2416dff
mixed: verify local cell count in GhostLastScalarProduct
Jun 23, 2026
0f3200a
mixed: custom WellModelMixedGhostLastMatrixAdapter
Jul 8, 2026
4cd3122
mixed: post-rebase fixes
Jul 9, 2026
56decac
mixed: move scalar products to separate file
Jul 15, 2026
51fa7a0
mixed: scalar products documentation
Jul 15, 2026
23a8b9d
mixed: matrix wrapper documentation
Jul 16, 2026
03c65b0
mixed: move linear operators to separate file
Jul 16, 2026
461e279
mixed: preconditioner documentation
Jul 16, 2026
7803766
mixed: solver adapter documentation
Jul 16, 2026
0c39c2d
mixed: improved naming convention
Jul 16, 2026
8c828ac
mixed: update README file
Jul 16, 2026
74888b2
mixed: replace project calls in linear operators
Jul 25, 2026
6d47f52
mixed: move scalar product to c for avx2 support
Jul 25, 2026
fed6fae
mixed: enable mixed-cprw solver option
Jul 28, 2026
a8d00e1
mixed: update README file
Jul 28, 2026
e62acf5
mixed: documentation and clean-up
Aug 21, 2026
fc2c2db
mixed: delete unnecessary virtual keywords
Aug 21, 2026
0bd0e8d
mixed: minor improvements
Aug 21, 2026
3e599ec
mixed: more clean-up
Aug 22, 2026
e9687bc
mixed: aligned and buffered allocations
Aug 22, 2026
185232c
mixed: consolidate ilu0 and dilu factorization
Aug 24, 2026
88770b7
mixed: generic legacy bicgstab implementation
Aug 25, 2026
3413cb8
mixed: removing vec_bdot, i.e. buffered dot product
Aug 25, 2026
a0d2fd7
mixed: match declaration and init order
Aug 31, 2026
5764124
mixed: update README file
Sep 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists_files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ list(APPEND PRIVATE_HEADER_FILES

if (HAVE_AVX2_EXTENSION)
set (AVX2_SOURCE_FILES
opm/simulators/linalg/mixed/dot.c
opm/simulators/linalg/mixed/bsr.c
opm/simulators/linalg/mixed/prec.c
opm/simulators/linalg/mixed/bslv.c)
Expand Down
14 changes: 7 additions & 7 deletions opm/simulators/linalg/FlexibleSolver_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,13 @@ namespace Dune
maxiter, // maximum number of iterations
verbosity);
#if HAVE_AVX2_EXTENSION
} else if (solver_type == "mixed-bicgstab") {
} else if (solver_type == "mixed-legacy") {
if constexpr (Opm::is_gpu_operator_v<Operator>) {
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for GPU operators");
OPM_THROW(std::invalid_argument, "legacy mixed-bicgstab solver not supported for GPU operators");
} else if constexpr (Opm::detail::is_multi_type_block_vector_v<VectorType>) {
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for multi-type block vectors.");
OPM_THROW(std::invalid_argument, "legacy mixed-bicgstab solver not supported for multi-type block vectors.");
} else if constexpr (std::is_same_v<typename VectorType::field_type, float>){
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for single precision.");
OPM_THROW(std::invalid_argument, "legacy mixed-bicgstab solver not supported for single precision.");
} else {
const std::string prec_type = prm.get<std::string>("preconditioner.type", "error");
bool use_mixed_dilu= (prec_type=="legacy-mixed-dilu");
Expand All @@ -238,13 +238,13 @@ namespace Dune
);
}
// MixedBiCGSTABSolver starts here
} else if (solver_type == "mixed-precision") {
} else if (solver_type == "mixed-bicgstab") {
if constexpr (Opm::is_gpu_operator_v<Operator>) {
OPM_THROW(std::invalid_argument, "mixed-precision solver not supported for GPU operators");
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for GPU operators");
} else if constexpr (Opm::detail::is_multi_type_block_vector_v<VectorType>) {
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for multi-type block vectors.");
} else if constexpr (std::is_same_v<typename VectorType::field_type, float>){
OPM_THROW(std::invalid_argument, "mixed-precision solver not supported for single precision.");
OPM_THROW(std::invalid_argument, "mixed-bicgstab solver not supported for single precision.");
} else {
linsolver_ = std::make_shared<Dune::MixedBiCGSTABSolver<Comm,Operator,VectorType>>(linearoperator_for_solver_,
scalarproduct_,
Expand Down
194 changes: 194 additions & 0 deletions opm/simulators/linalg/ScalarProducts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
#ifndef OPM_SCALAR_PRODUCTS_HEADER_INCLUDED
#define OPM_SCALAR_PRODUCTS_HEADER_INCLUDED

#include <opm/simulators/linalg/mixed/dot.h>

namespace Dune
{

/// A parallel scalar product that takes advantage of the fact that all
/// elements associated with ghost cells are located at the end of the
/// vector. This allows us to ignore the block structure of the vector
/// and eliminate the use of a mask to exclude ghost entries from being
/// included in the scalar product
template<class Vector, class Comm>
class GhostLastScalarProduct : public ScalarProduct<Vector>
Comment thread
blattms marked this conversation as resolved.
{
public:

///Exctract block size from vector type
static constexpr auto block_size = Vector::block_type::dimension;

/*! \brief constructor
* \param com The communication object for syncing overlap and copy
* data points.
* \param cat parallel solver category (nonoverlapping or overlapping)
*/
GhostLastScalarProduct (std::shared_ptr<const Comm> com, SolverCategory::Category cat)
: _communication(com), _category(cat)
{
count_ = getLocalCount(); // number or local cells
int verify = verifyLocalCount(); // redundant check on numbef of local cells
if (count_ != verify) OPM_THROW(std::runtime_error, "Inconsistent local node count!!\n");
}

/*! \brief constructor
* \param com The communication object for syncing overlap and copy
* data points.
* \param cat parallel solver category (nonoverlapping or overlapping)
* \note if you use this constructor you have to make sure com stays alive
*/
GhostLastScalarProduct (const Comm& com, SolverCategory::Category cat)
: GhostLastScalarProduct(stackobject_to_shared_ptr(com), cat)
{}

/*! \brief Dot product of two vectors.
* \param vx first input vector
* \param vy second input vector
*/
virtual double dot (const Vector& vx, const Vector& vy) const override
{

// access underlying data
double const *x = &vx[0][0];
double const *y = &vy[0][0];

// total array length
int NN = block_size*count_;
#if 0
// unroll loop in multiples of 8
int n=NN/8;
int N=8*n;
double agg[8];
for(int i=0;i<8;i++) agg[i]=0.0;
for(int i=0;i<N;i+=8) for(int j=0;j<8;j++) agg[j]+=x[i+j]*y[i+j];
for(int j=0;j<4;j++) agg[j]+=agg[j+4];
for(int j=0;j<2;j++) agg[j]+=agg[j+2];
for(int j=0;j<1;j++) agg[j]+=agg[j+1];

// loop-peeling of trailing end
for(int j=N;j<NN;j++) agg[0]+=x[j]*y[j];

// Global summation
auto cc = _communication->communicator();
double result = cc.sum(agg[0]);
return result;
#else
auto cc = _communication->communicator();
return cc.sum(vec_dot(x,y,NN));
#endif
//return cc.sum(vec_dot(x,y,NN));
}

/*! \brief Vector L2-norm.
* \param vx input vector
*/
virtual double norm (const Vector& vx) const override
{
return sqrt(dot(vx,vx));
}

//! Category of the scalar product (see SolverCategory::Category)
virtual SolverCategory::Category category() const override
{
return _category;
}

private:
std::shared_ptr<const Comm> _communication;
SolverCategory::Category _category;
int count_;

/*! \brief Count number of local cells.
*/
int getLocalCount() const
{
int count = 0;
// Loop over index set
auto indexSet = _communication->indexSet();
for (auto idx = indexSet.begin(); idx!=indexSet.end(); ++idx) {
if (idx->local().attribute()==1) count++; // count non-local indices
}
return count;
}

/*! \brief Infer number of local cells from largest local index.
*/
int verifyLocalCount() const
{
auto indexSet = _communication->indexSet();

size_t is = 0;
// Loop over index set
for (auto idx = indexSet.begin(); idx!=indexSet.end(); ++idx) {
//Only take "owner" indices
if (idx->local().attribute()==1) {
//get local index
auto loc = idx->local().local();
// if loc is higher than "old interior size", update it
if (loc > is) {
is = loc;
}
}
}
return is + 1; //size is plus 1 since we start at 0
}

};



/// A sequential scalar product that ignores block structure of the vector
/// to facilitate well-known optimization techniques
template<class Vector>
class SeqOptmizedProduct : public Dune::SeqScalarProduct<Vector>
{
public:

// extract block size
static constexpr auto block_size = Vector::block_type::dimension;

/*! \brief Dot product of two vectors.
* \param vx first input vector
* \param vy second input vector
*/
virtual double dot(const Vector& vx, const Vector& vy) const override
{
// access underlying data
double const *x = &vx[0][0];
double const *y = &vy[0][0];

// total array length
int NN = block_size*vx.N();
#if 1
// unroll loop in multiples of 8
int n=NN/8;
int N=8*n;
double agg[8];
for(int i=0;i<8;i++) agg[i]=0.0;
for(int i=0;i<N;i+=8) for(int j=0;j<8;j++) agg[j]+=x[i+j]*y[i+j];
for(int j=0;j<4;j++) agg[j]+=agg[j+4];
for(int j=0;j<2;j++) agg[j]+=agg[j+2];
for(int j=0;j<1;j++) agg[j]+=agg[j+1];

// loop-peeling of trailing end
for(int j=N;j<NN;j++) agg[0]+=x[j]*y[j];

return agg[0];
#else
return vec_dot(x,y,NN);
#endif
}

/*! \brief Vector L2-norm.
* \param vx input vector
*/
virtual double norm(const Vector& vx) const override {
return std::sqrt(this->dot(vx, vx));
}
};

}

#endif //OPM_SCALAR_PRODUCTS_HEADER_INCLUDED

4 changes: 4 additions & 0 deletions opm/simulators/linalg/WellOperators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ class WellModelMatrixAdapter : public Dune::AssembledLinearOperator<M,X,Y>

const matrix_type& getmat() const override { return A_; }

const LinearOperatorExtra<X, Y>& getwellOper() const { return wellOper_; }

void addWellPressureEquations(PressureMatrix& jacobian,
const X& weights,
const bool use_well_weights) const
Expand Down Expand Up @@ -357,6 +359,8 @@ class WellModelGhostLastMatrixAdapter : public Dune::AssembledLinearOperator<M,X

const matrix_type& getmat() const override { return A_; }

const LinearOperatorExtra<X, Y>& getwellOper() const { return wellOper_; }

void addWellPressureEquations(PressureMatrix& jacobian,
const X& weights,
const bool use_well_weights) const
Expand Down
Loading