Commit 7664fd39 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

#1535 PETSc Vector and Matrix: refine the Internal() method to improve the...

#1535 PETSc Vector and Matrix: refine the Internal() method to improve the safety upon const calls to Matrix and Vector class.
parent 4b537cf3
......@@ -76,7 +76,7 @@ namespace MoReFEM
{
assert(petsc_matrix_ == PETSC_NULL && "Should not be initialized when this method is called!");
int error_code = MatDuplicate(original.Internal(), option, &petsc_matrix_);
int error_code = MatDuplicate(original.InternalForReadOnly(), option, &petsc_matrix_);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatDuplicate", invoking_file, invoking_line);
......@@ -315,7 +315,7 @@ namespace MoReFEM
bool Matrix::IsAssembled(const char* invoking_file, int invoking_line) const
{
const Mat& internal = Internal();
const Mat& internal = InternalForReadOnly();
PetscBool value;
......@@ -400,7 +400,7 @@ namespace MoReFEM
{
PetscScalar ret;
int error_code = MatGetValues(Internal(),
int error_code = MatGetValues(InternalForReadOnly(),
1, &row_index,
1, &column_index,
&ret);
......@@ -416,7 +416,7 @@ namespace MoReFEM
void Matrix::Copy(const Matrix& source, const char* invoking_file, int invoking_line,
const MatStructure& structure)
{
int error_code = MatCopy(source.Internal(), Internal(), structure);
int error_code = MatCopy(source.InternalForReadOnly(), Internal(), structure);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatCopy", invoking_file, invoking_line);
}
......@@ -443,7 +443,7 @@ namespace MoReFEM
{
std::pair<PetscInt, PetscInt> ret;
int error_code = MatGetLocalSize(Internal(), &ret.first, &ret.second);
int error_code = MatGetLocalSize(InternalForReadOnly(), &ret.first, &ret.second);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatGetLocalSize", invoking_file, invoking_line);
......@@ -455,7 +455,7 @@ namespace MoReFEM
{
std::pair<PetscInt, PetscInt> ret;
int error_code = MatGetSize(Internal(), &ret.first, &ret.second);
int error_code = MatGetSize(InternalForReadOnly(), &ret.first, &ret.second);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatGetSize", invoking_file, invoking_line);
......@@ -466,7 +466,7 @@ namespace MoReFEM
void Matrix::View(const Mpi& mpi, const char* invoking_file, int invoking_line) const
{
int error_code = MatView(Internal(), PETSC_VIEWER_STDOUT_(mpi.GetCommunicator()));
int error_code = MatView(InternalForReadOnly(), PETSC_VIEWER_STDOUT_(mpi.GetCommunicator()));
if (error_code)
throw ExceptionNS::Exception(error_code, "MatView", invoking_file, invoking_line);
......@@ -481,7 +481,7 @@ namespace MoReFEM
{
Viewer viewer(mpi, output_file, format, file_mode, invoking_file, invoking_line);
int error_code = MatView(Internal(), viewer.GetUnderlyingPetscObject());
int error_code = MatView(InternalForReadOnly(), viewer.GetUnderlyingPetscObject());
if (error_code)
throw ExceptionNS::Exception(error_code, "MatView", invoking_file, invoking_line);
}
......@@ -520,10 +520,10 @@ namespace MoReFEM
// Petsc MatGetRow() crashed if row index is not in the interval given below, so I have added
// this very crude test to return nothing in this case.
if (row_index < Internal()->rmap->rstart || row_index > Internal()->rmap->rend)
if (row_index < InternalForReadOnly()->rmap->rstart || row_index > InternalForReadOnly()->rmap->rend)
return;
int error_code = MatGetRow(Internal(),
int error_code = MatGetRow(InternalForReadOnly(),
row_index,
&Nnon_zero_cols,
&columns,
......@@ -544,8 +544,7 @@ namespace MoReFEM
const auto size = static_cast<std::size_t>(Nnon_zero_cols);
row_content_position_list.resize(size);
row_content_value_list.resize(size);
for (auto i = 0ul; i < size; ++i)
{
row_content_position_list[i] = columns[i];
......@@ -553,7 +552,7 @@ namespace MoReFEM
}
}
error_code = MatRestoreRow(Internal(),
error_code = MatRestoreRow(InternalForReadOnly(),
row_index,
&Nnon_zero_cols,
&columns,
......@@ -590,7 +589,7 @@ namespace MoReFEM
Vector& column,
const char* invoking_file, int invoking_line) const
{
int error_code = MatGetColumnVector(Internal(), column.Internal(), column_index);
int error_code = MatGetColumnVector(InternalForReadOnly(), column.Internal(), column_index);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatGetColumnVector", invoking_file, invoking_line);
}
......@@ -611,7 +610,7 @@ namespace MoReFEM
assert(type == NORM_1 || type == NORM_FROBENIUS || type == NORM_INFINITY);
int error_code = MatNorm(Internal(), type, &norm);
int error_code = MatNorm(InternalForReadOnly(), type, &norm);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatNorm", invoking_file, invoking_line);
......@@ -658,7 +657,7 @@ namespace MoReFEM
const char* invoking_file, int invoking_line)
{
PetscBool value;
int error_code = MatEqual(lhs.Internal(), rhs.Internal(), &value);
int error_code = MatEqual(lhs.InternalForReadOnly(), rhs.InternalForReadOnly(), &value);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatEqual", invoking_file, invoking_line);
......
......@@ -204,9 +204,19 @@ namespace MoReFEM
* \return Internal Mat object, which is indeed a pointer in Petsc.
*
* Ideally it shouldn't be used at all except in the implementation of the Petsc Wrapper: a wrapper
* method should be implemented over the function that might need access to the Vec internal object.
* method should be implemented over the function that might need access to the \a Mat internal object.
*/
Mat Internal() const noexcept;
Mat Internal() noexcept;
/*!
* \brief Handle over the internal Mat object - when you can guarantee the call is only to read the value, not act upon it.
*
* \return Internal Mat object, which is indeed a pointer in Petsc.
*
* Ideally it shouldn't be used at all except in the implementation of the Petsc Wrapper: a wrapper
* method should be implemented over the function that might need access to the \a Mat internal object.
*/
Mat InternalForReadOnly() const noexcept;
/*!
......
......@@ -29,7 +29,14 @@ namespace MoReFEM
{
inline Mat Matrix::Internal() const noexcept
inline Mat Matrix::Internal() noexcept
{
assert(petsc_matrix_ != PETSC_NULL);
return petsc_matrix_;
}
inline Mat Matrix::InternalForReadOnly() const noexcept
{
assert(petsc_matrix_ != PETSC_NULL);
return petsc_matrix_;
......
......@@ -39,14 +39,14 @@ namespace MoReFEM
{
MatInfo infos;
int error_code = MatGetInfo(matrix.Internal(), MAT_LOCAL, &infos);
int error_code = MatGetInfo(matrix.InternalForReadOnly(), MAT_LOCAL, &infos);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatGetInfo", invoking_file, invoking_line);
MatType type;
error_code = MatGetType(matrix.Internal(), &type);
error_code = MatGetType(matrix.InternalForReadOnly(), &type);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatGetType", invoking_file, invoking_line);
......
......@@ -325,18 +325,20 @@ namespace MoReFEM
/*!
* \brief Creates a new matrix object that behaves like A'.
*
* The transpose A' is NOT actually formed! Rather the new matrix object performs the matrix-vector product
* by using the MatMultTranspose() on the original matrix.
*
* \param[in] A matrix to transpose.
* \param[out] transpose The matrix that figuratively represents A'. This matrix must not have been
* allocated!
* \copydoc doxygen_hide_invoking_file_and_line
*
* \attention The transpose A' is NOT actually formed! Rather the new matrix object performs the matrix-vector product
* by using the MatMultTranspose() on the original matrix.
*
*/
template
<
class MatrixT,
class MatrixU
class MatrixT,
class MatrixU
>
std::enable_if_t
<
......
......@@ -36,7 +36,9 @@ namespace MoReFEM
const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = ::MatMultTranspose(matrix.Internal(), v1.Internal(), v2.Internal());
int error_code = ::MatMultTranspose(matrix.InternalForReadOnly(),
v1.InternalForReadOnly(),
v2.Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "MatMultTranspose", invoking_file, invoking_line);
......@@ -53,7 +55,10 @@ namespace MoReFEM
const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = ::MatMultTransposeAdd(matrix.Internal(), v1.Internal(), v2.Internal(), v3.Internal());
int error_code = ::MatMultTransposeAdd(matrix.InternalForReadOnly(),
v1.InternalForReadOnly(),
v2.InternalForReadOnly(),
v3.Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "MatMultTransposeAdd", invoking_file, invoking_line);
......@@ -88,8 +93,8 @@ namespace MoReFEM
case DoReuseMatrix::yes:
{
result = out.Internal();
error_code = ::MatMatMult(matrix1.Internal(),
matrix2.Internal(),
error_code = ::MatMatMult(matrix1.InternalForReadOnly(),
matrix2.InternalForReadOnly(),
MAT_REUSE_MATRIX,
PETSC_DEFAULT,
&result);
......@@ -97,8 +102,8 @@ namespace MoReFEM
}
case DoReuseMatrix::no:
{
error_code = ::MatMatMult(matrix1.Internal(),
matrix2.Internal(),
error_code = ::MatMatMult(matrix1.InternalForReadOnly(),
matrix2.InternalForReadOnly(),
MAT_INITIAL_MATRIX,
PETSC_DEFAULT,
&result);
......@@ -204,7 +209,7 @@ namespace MoReFEM
{
int error_code = ::MatAXPY(Y.Internal(),
a,
X.Internal(),
X.InternalForReadOnly(),
Internal::Wrappers::Petsc::NonZeroPatternPetsc<NonZeroPatternT>());
if (error_code)
......@@ -232,7 +237,7 @@ namespace MoReFEM
const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = ::MatMult(matrix.Internal(), v1.Internal(), v2.Internal());
int error_code = ::MatMult(matrix.InternalForReadOnly(), v1.InternalForReadOnly(), v2.Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "MatMult", invoking_file, invoking_line);
......@@ -297,7 +302,10 @@ namespace MoReFEM
const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = ::MatMultAdd(matrix.Internal(), v1.Internal(), v2.Internal(), v3.Internal());
int error_code = ::MatMultAdd(matrix.InternalForReadOnly(),
v1.InternalForReadOnly(),
v2.InternalForReadOnly(),
v3.Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "MatMultAdd", invoking_file, invoking_line);
......@@ -323,7 +331,7 @@ namespace MoReFEM
{
Mat result;
int error_code = ::MatCreateTranspose(A.Internal(), &result);
int error_code = ::MatCreateTranspose(A.InternalForReadOnly(), &result);
if (error_code)
throw ExceptionNS::Exception(error_code, "MatCreateTranspose", invoking_file, invoking_line);
......@@ -481,8 +489,8 @@ namespace MoReFEM
case DoReuseMatrix::yes:
{
result = out.Internal();
error_code = ::MatPtAP(A.Internal(),
P.Internal(),
error_code = ::MatPtAP(A.InternalForReadOnly(),
P.InternalForReadOnly(),
MAT_REUSE_MATRIX,
PETSC_DEFAULT,
&result);
......@@ -490,8 +498,8 @@ namespace MoReFEM
}
case DoReuseMatrix::no:
{
error_code = ::MatPtAP(A.Internal(),
P.Internal(),
error_code = ::MatPtAP(A.InternalForReadOnly(),
P.InternalForReadOnly(),
MAT_INITIAL_MATRIX,
PETSC_DEFAULT,
&result);
......
......@@ -183,13 +183,13 @@ namespace MoReFEM
int invoking_line,
check_convergence do_check_convergence)
{
int error_code = SNESSetFunction(snes_, rhs.Internal(), GetSnesFunction(), context);
int error_code = SNESSetFunction(snes_, rhs.InternalForReadOnly(), GetSnesFunction(), context);
if (error_code)
throw ExceptionNS::Exception(error_code, "SNESSetFunction", invoking_file, invoking_line);
error_code = SNESSetJacobian(snes_,
jacobian_matrix.Internal(),
preconditioner_matrix.Internal(),
jacobian_matrix.InternalForReadOnly(),
preconditioner_matrix.InternalForReadOnly(),
GetSnesJacobian(),
context);
......@@ -278,7 +278,7 @@ namespace MoReFEM
KSPView(ksp, PETSC_VIEWER_STDOUT_WORLD);
}*/
int error_code = ::KSPSolve(ksp, rhs.Internal(), solution.Internal());
int error_code = ::KSPSolve(ksp, rhs.InternalForReadOnly(), solution.Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "KSPSolve", invoking_file, invoking_line);
......
......@@ -82,7 +82,8 @@ namespace MoReFEM
{
KSP ksp = GetKsp(invoking_file, invoking_line);
int error_code = KSPSetOperators(ksp, matrix.Internal(), preconditioner.Internal());
int error_code = KSPSetOperators(ksp, matrix.InternalForReadOnly(),
preconditioner.InternalForReadOnly());
if (error_code)
throw ExceptionNS::Exception(error_code, "KSPSetOperators", invoking_file, invoking_line);
......
......@@ -33,7 +33,7 @@ namespace MoReFEM
: vector_without_ghost_(vector)
// local_content_(nullptr)
{
int error_code = VecGhostGetLocalForm(vector_without_ghost_.Internal(),
int error_code = VecGhostGetLocalForm(vector_without_ghost_.InternalForReadOnly(),
&petsc_vector_with_ghost_);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGhostGetLocalForm", invoking_file, invoking_line);
......@@ -43,9 +43,10 @@ namespace MoReFEM
AccessGhostContent::~AccessGhostContent()
{
assert(petsc_vector_with_ghost_ != PETSC_NULL);
assert(vector_without_ghost_.Internal() != PETSC_NULL);
assert(vector_without_ghost_.InternalForReadOnly() != PETSC_NULL);
int error_code = VecGhostRestoreLocalForm(vector_without_ghost_.Internal(), &petsc_vector_with_ghost_);
int error_code = VecGhostRestoreLocalForm(vector_without_ghost_.InternalForReadOnly(),
&petsc_vector_with_ghost_);
static_cast<void>(error_code); // avoid warning in release mode
assert(error_code == 0); // error code should be 0; exception can't be thrown in a destructor!
}
......
......@@ -58,6 +58,10 @@ namespace MoReFEM
ret.push_back(ghost_vector_content.GetValue(static_cast<unsigned int>(global_index)));
* }
*
* \attention This class assumes the purpose to access it is for read-only purpose. If you want to
* modifying it, you probably seek \a AccessVectorContent, which doesn't get to access ghost values (as they
* shouldn't be modified directly - it is the task of \a Vector::UpdateGhosts() ).
*
* \endcode
*
*/
......
......@@ -47,7 +47,7 @@ namespace MoReFEM
const char* invoking_file, int invoking_line)
: vector_(vector)
{
int error_code = VecGetArrayRead(vector.Internal(), &values_);
int error_code = VecGetArrayRead(vector.InternalForReadOnly(), &values_);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGetArrayRead", invoking_file, invoking_line);
}
......@@ -56,7 +56,7 @@ namespace MoReFEM
template<>
AccessVectorContent<Utilities::Access::read_and_write>::~AccessVectorContent()
{
assert(vector_.InternalWithoutCheck() != NULL);
assert(vector_.Internal<Vector::check_non_null_ptr::no>() != PETSC_NULL);
int error_code = VecRestoreArray(vector_.Internal(), &values_);
......@@ -83,9 +83,9 @@ namespace MoReFEM
template<>
AccessVectorContent<Utilities::Access::read_only>::~AccessVectorContent()
{
assert(vector_.InternalWithoutCheck() != NULL);
assert(vector_.InternalForReadOnly<Vector::check_non_null_ptr::no>() != PETSC_NULL);
int error_code = VecRestoreArrayRead(vector_.Internal(), &values_);
int error_code = VecRestoreArrayRead(vector_.InternalForReadOnly(), &values_);
assert(error_code == 0); // error code should be 0; exception can't be thrown in a destructor!
static_cast<void>(error_code); // avoid warning in release mode
}
......
......@@ -47,7 +47,7 @@ namespace MoReFEM
template<Utilities::Access AccessT>
inline unsigned int AccessVectorContent<AccessT>::GetSize(const char* invoking_file, int invoking_line) const
{
assert(vector_.InternalWithoutCheck() != NULL);
assert(vector_.template InternalForReadOnly<Vector::check_non_null_ptr::no>() != PETSC_NULL);
return static_cast<unsigned int>(vector_.GetProcessorWiseSize(invoking_file, invoking_line));
}
......
......@@ -67,7 +67,7 @@ namespace MoReFEM
void Vector::DuplicateLayout(const Vector& original, const char* invoking_file, int invoking_line)
{
assert(petsc_vector_ == PETSC_NULL && "Should not be initialized when this method is called!");
int error_code = VecDuplicate(original.Internal(), &petsc_vector_);
int error_code = VecDuplicate(original.InternalForReadOnly(), &petsc_vector_);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecDuplicate", invoking_file, invoking_line);
......@@ -78,7 +78,7 @@ namespace MoReFEM
PetscInt Vector::GetProcessorWiseSize(const char* invoking_file, int invoking_line) const
{
PetscInt ret;
int error_code = VecGetLocalSize(Internal(), &ret);
int error_code = VecGetLocalSize(InternalForReadOnly(), &ret);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGetLocalSize", invoking_file, invoking_line);
......@@ -90,7 +90,7 @@ namespace MoReFEM
PetscInt Vector::GetProgramWiseSize(const char* invoking_file, int invoking_line) const
{
PetscInt ret;
int error_code = VecGetSize(Internal(), &ret);
int error_code = VecGetSize(InternalForReadOnly(), &ret);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGetSize", invoking_file, invoking_line);
......@@ -146,7 +146,10 @@ namespace MoReFEM
{
std::vector<PetscScalar> ret(indexing.size());
int error_code = VecGetValues(Internal(), static_cast<PetscInt>(indexing.size()), indexing.data(), ret.data());
int error_code = VecGetValues(InternalForReadOnly(),
static_cast<PetscInt>(indexing.size()),
indexing.data(),
ret.data());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGetValues", invoking_file, invoking_line);
......@@ -160,7 +163,10 @@ namespace MoReFEM
{
assert(values.size() == indexing.size());
int error_code = VecGetValues(Internal(), static_cast<PetscInt>(indexing.size()), indexing.data(), values.data());
int error_code = VecGetValues(InternalForReadOnly(),
static_cast<PetscInt>(indexing.size()),
indexing.data(),
values.data());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecGetValues", invoking_file, invoking_line);
......@@ -196,7 +202,7 @@ namespace MoReFEM
void Vector::Copy(const Vector& source, const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = VecCopy(source.Internal(),
int error_code = VecCopy(source.InternalForReadOnly(),
Internal());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecCopy", invoking_file, invoking_line);
......@@ -351,7 +357,7 @@ namespace MoReFEM
const char* invoking_file, int invoking_line,
update_ghost do_update_ghost)
{
int error_code = VecAXPY(y.Internal(), alpha, x.Internal());
int error_code = VecAXPY(y.Internal(), alpha, x.InternalForReadOnly());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecAXPY", invoking_file, invoking_line);
......@@ -363,7 +369,7 @@ namespace MoReFEM
{
PetscScalar ret;
int error_code = VecDot(x.Internal(), y.Internal(), &ret);
int error_code = VecDot(x.InternalForReadOnly(), y.InternalForReadOnly(), &ret);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecDot", invoking_file, invoking_line);
......@@ -376,7 +382,7 @@ namespace MoReFEM
PetscInt position;
PetscReal value;
int error_code = VecMin(Internal(), &position, &value);
int error_code = VecMin(InternalForReadOnly(), &position, &value);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecMin", invoking_file, invoking_line);
......@@ -389,7 +395,7 @@ namespace MoReFEM
PetscInt position;
PetscReal value;
int error_code = VecMax(Internal(), &position, &value);
int error_code = VecMax(InternalForReadOnly(), &position, &value);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecMax", invoking_file, invoking_line);
......@@ -403,7 +409,7 @@ namespace MoReFEM
assert(type == NORM_1 || type == NORM_2 || type == NORM_INFINITY);
int error_code = VecNorm(Internal(), type, &norm);
int error_code = VecNorm(InternalForReadOnly(), type, &norm);
if (error_code)
throw ExceptionNS::Exception(error_code, "VecNorm", invoking_file, invoking_line);
......@@ -414,7 +420,7 @@ namespace MoReFEM
void Vector::View(const Mpi& mpi, const char* invoking_file, int invoking_line) const
{
int error_code = VecView(Internal(), PETSC_VIEWER_STDOUT_(mpi.GetCommunicator()));
int error_code = VecView(InternalForReadOnly(), PETSC_VIEWER_STDOUT_(mpi.GetCommunicator()));
if (error_code)
throw ExceptionNS::Exception(error_code, "VecView", invoking_file, invoking_line);
}
......@@ -426,7 +432,7 @@ namespace MoReFEM
{
Viewer viewer(mpi, output_file, format, FILE_MODE_WRITE, invoking_file, invoking_line);
int error_code = VecView(Internal(), viewer.GetUnderlyingPetscObject());
int error_code = VecView(InternalForReadOnly(), viewer.GetUnderlyingPetscObject());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecView", invoking_file, invoking_line);
}
......@@ -439,7 +445,7 @@ namespace MoReFEM
Viewer viewer(mpi, output_file, PETSC_VIEWER_BINARY_MATLAB, FILE_MODE_WRITE,
invoking_file, invoking_line);
int error_code = VecView(Internal(), viewer.GetUnderlyingPetscObject());
int error_code = VecView(InternalForReadOnly(), viewer.GetUnderlyingPetscObject());
if (error_code)
throw ExceptionNS::Exception(error_code, "VecView", invoking_file, invoking_line);
......@@ -476,7 +482,7 @@ namespace MoReFEM
VecScatter vecscat;
Vec local_petsc_vector = local_parallel_vector.Internal();
Vec local_petsc_vector = local_parallel_vector.InternalForReadOnly();
Vec sequential_petsc_vector;
int error_code = VecScatterCreateToAll(local_petsc_vector, &vecscat, &sequential_petsc_vector);
......
......@@ -282,28 +282,41 @@ namespace MoReFEM
const std::string& binary_file,
const char* invoking_file, int invoking_line);
//! Convenient enum class for \a Internal() and \a InternalForReadOnly() template argument.
enum class check_non_null_ptr { no, yes };
/*!
* \brief Handle over the internal Vec object.
* \brief Handle over the internal \a Vec object.
*
* \tparam do_check_non_null_ptr If 'yes', check with an assert in debug mode whether the underlying pointer has been defined or
* not. 'yes' is really the go to value; 'no' is used only in some low level functions.
*
* \return Internal \a Vec object, which is indeed a pointer in Petsc.
*
* \return Internal Vec object, which is indeed a pointer in Petsc.
*
* Ideally it shouldn't be used at all except in the implementation of the Petsc Wrapper: a wrapper
* method should be implemented over the function that might need access to the Vec internal object.
* method should be implemented over the function that might need access to the \a Vec internal object.
*/
Vec Internal() const;
template<check_non_null_ptr do_check_non_null_ptr = check_non_null_ptr::yes>
Vec Internal() noexcept;