diff --git a/applications/test/PrecisionAdaptor/Make/files b/applications/test/PrecisionAdaptor/Make/files
new file mode 100644
index 0000000000..d1a36376f0
--- /dev/null
+++ b/applications/test/PrecisionAdaptor/Make/files
@@ -0,0 +1,3 @@
+Test-PrecisionAdaptor.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-PrecisionAdaptor
diff --git a/applications/test/PrecisionAdaptor/Make/options b/applications/test/PrecisionAdaptor/Make/options
new file mode 100644
index 0000000000..18e6fe47af
--- /dev/null
+++ b/applications/test/PrecisionAdaptor/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/PrecisionAdaptor/Test-PrecisionAdaptor.C b/applications/test/PrecisionAdaptor/Test-PrecisionAdaptor.C
new file mode 100644
index 0000000000..33462b909c
--- /dev/null
+++ b/applications/test/PrecisionAdaptor/Test-PrecisionAdaptor.C
@@ -0,0 +1,111 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+ This file is part of OpenFOAM.
+
+ OpenFOAM 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.
+
+ OpenFOAM 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 OpenFOAM. If not, see .
+
+Application
+ Test-PrecisionAdaptor
+
+Description
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "primitiveFields.H"
+#include "PrecisionAdaptor.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+ Field content1(8);
+ Field content2(8);
+
+ forAll(content1, i)
+ {
+ content1[i] = 10 * i;
+ content2[i] = 10 * i;
+ }
+
+ Foam::reverse(content2);
+
+ ConstPrecisionAdaptor cadaptor1;
+
+ cadaptor1.set(content1);
+ cadaptor1.commit(); // This is a no-op
+ Info<< "wrapped: " << cadaptor1() << nl;
+
+ cadaptor1.set(content2);
+ Info<< "wrapped: " << cadaptor1() << nl;
+
+ Info<< nl;
+
+ PrecisionAdaptor adaptor2;
+
+ adaptor2.set(content1);
+ adaptor2.ref() *= 2;
+ adaptor2.commit(); // Propagate changes back to input now
+
+ Info<< "modified wrapped: " << adaptor2() << nl;
+
+ adaptor2.set(content2);
+ adaptor2.ref() *= 2;
+ adaptor2.commit(); // Propagate changes back to input now
+
+ Info<< "modified wrapped: " << adaptor2() << nl;
+ Info<< "source: " << content1 << nl;
+ Info<< "source: " << content2 << nl;
+
+
+ content2 *= 2;
+ Info<< nl
+ << "set with " << content2 << nl;
+ Info<< "wrapped was " << adaptor2() << nl;
+ adaptor2.set(content2);
+ Info<< "wrapped now " << adaptor2() << nl;
+ Info<< "source: " << content2 << nl;
+
+ // Can even do this
+ Foam::reverse(adaptor2.ref());
+
+ adaptor2.ref() *= 2;
+ adaptor2.set(content1); // implicit commit
+ Info<< "updated: " << content2 << nl;
+
+ Info<< nl
+ << "input: " << content1 << nl;
+
+ adaptor2.ref() *= 2;
+ adaptor2.clear(); // discard
+ adaptor2.commit();
+
+ Info<< "unchanged: " << content1 << nl;
+
+ Info<< nl << "Done" << nl << endl;
+ return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
index a326c7a403..94372dab7b 100644
--- a/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
+++ b/src/OpenFOAM/fields/Fields/Field/PrecisionAdaptor/PrecisionAdaptor.H
@@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
- Copyright (C) 2019-2020 OpenCFD Ltd.
+ Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@@ -39,6 +39,8 @@ Description
#ifndef PrecisionAdaptor_H
#define PrecisionAdaptor_H
+#include // For std::copy
+#include // For std::is_same
#include "refPtr.H"
#include "Field.H"
@@ -47,6 +49,10 @@ Description
namespace Foam
{
+/*---------------------------------------------------------------------------*\
+ Class ConstPrecisionAdaptor Declaration
+\*---------------------------------------------------------------------------*/
+
//- A const Field/List wrapper with possible data conversion
template class Container = Field>
class ConstPrecisionAdaptor
@@ -55,107 +61,127 @@ class ConstPrecisionAdaptor
{
// Private Member Functions
- //- Copy in field
- void copyInput(const Container& input)
- {
- this->reset(new Container(input.size()));
- std::copy(input.cbegin(), input.cend(), this->ref().begin());
- }
-
- //- Construct from tmp Field, copy/move as required
- void moveInput(tmp>& input)
+ //- Set adaptor for different input, copying as required
+ void setInput(const Container& src)
{
if (std::is_same::value)
{
- auto& tinput = reinterpret_cast>&>(input);
-
- if (tinput.is_pointer())
- {
- // Acquire control of the managed pointer
- this->reset(tinput.ptr());
- }
- else
- {
- // Use const reference
- this->cref(tinput.cref());
- }
+ // Use reference directly
+ this->cref(reinterpret_cast&>(src));
}
else
{
- this->copyInput(input.cref());
+ // Need intermediate buffer
+ this->reset(new Container(src.size()));
+ std::copy(src.cbegin(), src.cend(), this->ref().begin());
}
- input.clear();
}
+ //- Set from tmp, steal pointer if possible
+ void tmpInput(tmp>& tsrc)
+ {
+ if (std::is_same::value && tsrc.is_pointer())
+ {
+ // Acquire control of the managed pointer
+ this->reset(reinterpret_cast*>(tsrc.ptr()));
+ }
+ else
+ {
+ this->setInput(tsrc.cref());
+ }
+ tsrc.clear();
+ }
public:
- //- The adapted field type
+ //- The adapted field type. Same as element_type
typedef Container FieldType;
// Constructors
- //- Construct from Container, copying on input as required
- ConstPrecisionAdaptor(const Container& input)
- :
- refPtr>()
+ //- Default construct, setting content later
+ ConstPrecisionAdaptor() = default;
+
+ //- Construct from Container of InputType, copying if required
+ explicit ConstPrecisionAdaptor(const Container& input)
{
- if (std::is_same::value)
- {
- // Use const reference directly
- this->cref(reinterpret_cast(input));
- }
- else
- {
- this->copyInput(input);
- }
+ this->setInput(input);
}
-
- //- Construct from tmp Container, copy/move as required
- ConstPrecisionAdaptor(tmp>&& input)
- :
- refPtr>()
+ //- Construct from tmp Container of InputType, copy/move as required
+ explicit ConstPrecisionAdaptor(tmp>&& input)
{
- this->moveInput(input);
+ this->tmpInput(input);
}
-
- //- Construct from tmp Container, copy/move as required
- ConstPrecisionAdaptor(const tmp>& input)
- :
- refPtr>()
+ //- Construct from tmp Container of InputType, copy/move as required
+ explicit ConstPrecisionAdaptor(const tmp>& input)
{
- this->moveInput(const_cast>&>(input));
+ this->tmpInput(const_cast>&>(input));
}
// Member Functions
- // May need in the future: using refPtr>::get;
+ //- Is precision adaption being used (non-passive adaptor)?
+ bool active() const noexcept
+ {
+ // Same as refPtr::movable()
+ return (this->is_pointer() && this->valid());
+ }
- //- Return the field
- static const Container& get
+ //- Commit adapted content changes (no-op for const adaptor)
+ void commit()
+ {}
+
+ //- Set adaptor for different input, copying input if required
+ void set(const Container& input)
+ {
+ this->setInput(input);
+ }
+
+ //- Set adaptor for tmp Container of InputType, copy/move as required
+ void set(tmp>&& input)
+ {
+ this->tmpInput(input);
+ }
+
+ //- Set adaptor for tmp Container of InputType, copy/move as required
+ void set(const tmp>& input)
+ {
+ this->tmpInput(const_cast>&>(input));
+ }
+
+
+ // Static Member Functions
+
+ //- Select a reference to the input (if types are identical),
+ //- or copy into other and return a reference to that
+ static const Container& select
(
const Container& input,
- Container& dst
+ Container& other
)
{
if (std::is_same::value)
{
- return reinterpret_cast(input);
+ return reinterpret_cast&>(input);
}
else
{
- dst.resize(input.size());
- std::copy(input.cbegin(), input.cend(), dst.begin());
- return dst;
+ other.resize(input.size());
+ std::copy(input.cbegin(), input.cend(), other.begin());
+ return other;
}
}
};
+/*---------------------------------------------------------------------------*\
+ Class PrecisionAdaptor Declaration
+\*---------------------------------------------------------------------------*/
+
//- A non-const Field/List wrapper with possible data conversion
template class Container = Field>
class PrecisionAdaptor
@@ -164,59 +190,94 @@ class PrecisionAdaptor
{
// Private Data
- //- Reference to underlying (input) data
- Container& ref_;
+ //- Reference to underlying external input data
+ refPtr> orig_;
// Private Member Functions
- //- Copy in field
- void copyInput(const Container& input, const bool copy)
+ //- Set adaptor for different input, copying as required
+ void setInput(Container& src, const bool doCopy)
{
- this->reset(new Container(input.size()));
- if (copy)
+ orig_.ref(src);
+ if (std::is_same::value)
{
- std::copy(input.cbegin(), input.cend(), this->ref().begin());
+ // Use reference directly
+ this->ref(reinterpret_cast&>(src));
+ }
+ else
+ {
+ // Need intermediate buffer
+ this->reset(new Container(src.size()));
+ if (doCopy)
+ {
+ std::copy(src.cbegin(), src.cend(), this->ref().begin());
+ }
}
}
-
public:
- //- The adapted field type
+ //- The adapted field type. Same as element_type
typedef Container FieldType;
// Constructors
- //- Construct from Container, copying on input if required
- PrecisionAdaptor(Container& input, const bool copy = true)
- :
- refPtr>(),
- ref_(input)
+ //- Default construct, setting content later
+ PrecisionAdaptor() = default;
+
+ //- Construct from Container,
+ //- copying input if required (and requested)
+ explicit PrecisionAdaptor
+ (
+ Container& input,
+ const bool doCopy = true
+ )
{
- if (std::is_same::value)
- {
- // Use non-const reference directly
- this->ref(reinterpret_cast(ref_));
- }
- else
- {
- this->copyInput(input, copy);
- }
+ this->setInput(input, doCopy);
}
- //- Destructor, copy back on destroy
+ //- Destructor, copies back content changes (as required)
~PrecisionAdaptor()
{
- if (this->is_pointer())
- {
- const FieldType& store = this->cref();
- ref_.resize(store.size()); // extra safety
- std::copy(store.cbegin(), store.cend(), ref_.begin());
- }
+ this->commit(); // Commit changes
+ this->clear();
}
+
+
+ // Member Functions
+
+ //- Is precision adaption being used (non-passive adaptor)?
+ bool active() const noexcept
+ {
+ // Same as refPtr::movable()
+ return (this->is_pointer() && this->valid());
+ }
+
+ //- Commit adapted content changes back to original input (as required)
+ void commit()
+ {
+ if (this->active() && orig_.valid())
+ {
+ const auto& stored = this->cref();
+ auto& input = orig_.ref();
+ input.resize(stored.size()); // Extra safety
+ std::copy(stored.cbegin(), stored.cend(), input.begin());
+ }
+ }
+
+ //- Set adaptor for different input, copying input as required
+ void set(Container& input, const bool doCopy = true)
+ {
+ if (orig_.get() != &input)
+ {
+ // Commit changes to old input first
+ this->commit();
+ }
+ this->setInput(input, doCopy);
+ }
};
@@ -224,7 +285,6 @@ public:
} // End namespace Foam
-
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
diff --git a/src/OpenFOAM/matrices/lduMatrix/preconditioners/GAMGPreconditioner/GAMGPreconditioner.C b/src/OpenFOAM/matrices/lduMatrix/preconditioners/GAMGPreconditioner/GAMGPreconditioner.C
index 40cebad6ea..4619815c81 100644
--- a/src/OpenFOAM/matrices/lduMatrix/preconditioners/GAMGPreconditioner/GAMGPreconditioner.C
+++ b/src/OpenFOAM/matrices/lduMatrix/preconditioners/GAMGPreconditioner/GAMGPreconditioner.C
@@ -118,15 +118,12 @@ void Foam::GAMGPreconditioner::precondition
finestCorrectionScratch
);
-
- // Storage area when solveScalar != scalar
- scalarField rA_s;
+ // Adapt solveScalarField back to scalarField (as required)
+ ConstPrecisionAdaptor rA_adaptor(rA_ss);
+ const scalarField& rA = rA_adaptor.cref();
for (label cycle=0; cycle::get(rA_ss, rA_s);
-
Vcycle
(
smoothers,