Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add error computation for partitioned-heat-conduction OpenFOAM solver #449

Merged
merged 2 commits into from
Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
69 changes: 67 additions & 2 deletions partitioned-heat-conduction/solver-openfoam/heatTransfer.C
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,46 @@
#include "simpleControl.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Some helper functions in order to investigate this case
namespace Functions {
double get_rhs(const double x, const double y, const double alpha, const double beta)
{
return beta - 2 - 2 * alpha;
}
double get_solution(const double x, const double y,
const double alpha, const double beta, const double time)
{
return 1 + std::pow(x, 2) + (alpha * std::pow(y, 2)) + (beta * time);
}

void compute_and_print_errors(const Foam::fvMesh &mesh, const double alpha,
const double beta, const double time)
{
double error = 0;
const Foam::volScalarField *T_(&mesh.lookupObject<volScalarField>("T"));

double max_error = std::numeric_limits<double>::min();

// Get the locations of the volume centered mesh vertices
const vectorField &CellCenters = mesh.C();
unsigned int numDataLocations = CellCenters.size();
for (int i = 0; i < CellCenters.size(); i++) {
const double coord_x = CellCenters[i].x();
const double coord_y = CellCenters[i].y();
const double exact_solution = Functions::get_solution(coord_x, coord_y, alpha, beta, time);
const auto result = (exact_solution - T_->internalField()[i]) *
(exact_solution - T_->internalField()[i]);
error += result;
max_error = std::max(result, max_error);
}

Info << "\nError metrics at t = " << time << "s:\n";
Info << "l2 error (sqrt(sum(err^2)/n)):\t\t" << std::sqrt(error / numDataLocations) << endl;
Info << "Maximum absolute error (max(err)):\t" << std::sqrt(max_error) << endl;
Info << "Global absolute error (sum(err^2)):\t" << error << "\n";
Info << endl;
}
} // namespace Functions

int main(int argc, char *argv[])
{
Expand All @@ -61,8 +101,8 @@ int main(int argc, char *argv[])

const double alpha = 3;
const double beta = 1.2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MakisH to help with archeology here: In #379 I changed everything to 1.2 according to the FEniCS book.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, then the OpenFOAM-preCICE publication is still in synch with the old tutorials, and the new tutorials are in sync with each other. All good, thanks!

const double rhs = beta - 2 - 2 * alpha;

// Initialize the RHS with zero
volScalarField f(
IOobject(
"RHS",
Expand All @@ -74,7 +114,32 @@ int main(int argc, char *argv[])
dimensionedScalar(
"Tdim",
dimensionSet(0, 0, -1, 1, 0, 0, 0),
Foam::scalar(rhs)));
Foam::scalar(0)));

// Now assign the respective values to the RHS
//(strictly speaking not required here, only for space-dependent RHS functions)
// Get the locations of the volume centered mesh vertices
const vectorField &CellCenters = mesh.C();
for (int i = 0; i < CellCenters.size(); i++) {
const double coord_x = CellCenters[i].x();
const double coord_y = CellCenters[i].y();
f.ref()[i] = Functions::get_rhs(coord_x, coord_y, alpha, beta);
}

for (int j = 0; j < mesh.boundaryMesh().size() - 1; ++j) {
// Get the face centers of the current patch
const vectorField faceCenters =
mesh.boundaryMesh()[j].faceCentres();

// Assign the (x,y,z) locations to the vertices
for (int i = 0; i < faceCenters.size(); i++) {
const double coord_x = faceCenters[i].x();
const double coord_y = faceCenters[i].y();
f.boundaryFieldRef()[j][i] = Functions::get_rhs(coord_x, coord_y, alpha, beta);
}
}

Functions::compute_and_print_errors(mesh, alpha, beta, runTime.value());

while (simple.loop()) {
Info << "Time = " << runTime.timeName() << nl << endl;
Expand Down
47 changes: 46 additions & 1 deletion partitioned-heat-conduction/solver-openfoam/write.H
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
if (runTime.writeTime()) {
// We need to disable the runTime.writeTime if condition for implicit coupling
// as the condition only returns true in the very first coupling iteration
// if (runTime.writeTime())
{
volVectorField gradT(fvc::grad(T));

volScalarField gradTx(
Expand Down Expand Up @@ -36,6 +39,48 @@ if (runTime.writeTime()) {
IOobject::NO_READ,
IOobject::AUTO_WRITE),
DT * gradT);
volScalarField error_total(
IOobject(
"error",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE),
DT * 0);

// Print error metrics
Functions::compute_and_print_errors(mesh, alpha, beta, runTime.value());

// compute and store the error also in a paraView field
{
const Foam::volScalarField *T_(&mesh.lookupObject<volScalarField>("T"));

// Get the locations of the volume centered mesh vertices
const vectorField &CellCenters = mesh.C();

for (int i = 0; i < CellCenters.size(); i++) {
const double coord_x = CellCenters[i].x();
const double coord_y = CellCenters[i].y();
const double exact_solution = Functions::get_solution(coord_x, coord_y, alpha, beta, runTime.value());

error_total.ref()[i] = std::abs((exact_solution - T_->internalField()[i]));
}

T.correctBoundaryConditions();
for (int j = 0; j < mesh.boundaryMesh().size() - 1; ++j) {
// Get the face centers of the current patch
const vectorField faceCenters =
mesh.boundaryMesh()[j].faceCentres();

// Assign the (x,y,z) locations to the vertices
for (int i = 0; i < faceCenters.size(); i++) {
const double coord_x = faceCenters[i].x();
const double coord_y = faceCenters[i].y();
const double exact_solution = Functions::get_solution(coord_x, coord_y, alpha, beta, runTime.value());
error_total.boundaryFieldRef()[j][i] = std::abs(exact_solution - T_->boundaryField()[j][i]);
}
}
}

runTime.write();
}
Loading