-
Notifications
You must be signed in to change notification settings - Fork 95
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
Move invert3x3
out of general purpose utils.hxx
header
#3018
base: next
Are you sure you want to change the base?
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,80 @@ | ||||||||||||
/*!************************************************************************* | ||||||||||||
* \file invert3x3.hxx | ||||||||||||
* | ||||||||||||
* A mix of short utilities for memory management, strings, and some | ||||||||||||
* simple but common calculations | ||||||||||||
* | ||||||||||||
************************************************************************** | ||||||||||||
* Copyright 2010-2024 B.D.Dudson, BOUT++ Team | ||||||||||||
* | ||||||||||||
* Contact: Ben Dudson, [email protected] | ||||||||||||
* | ||||||||||||
* This file is part of BOUT++. | ||||||||||||
* | ||||||||||||
* BOUT++ is free software: you can redistribute it and/or modify | ||||||||||||
* it under the terms of the GNU Lesser General Public License as published by | ||||||||||||
* the Free Software Foundation, either version 3 of the License, or | ||||||||||||
* (at your option) any later version. | ||||||||||||
* | ||||||||||||
* BOUT++ 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 Lesser General Public License for more details. | ||||||||||||
* | ||||||||||||
* You should have received a copy of the GNU Lesser General Public License | ||||||||||||
* along with BOUT++. If not, see <http://www.gnu.org/licenses/>. | ||||||||||||
* | ||||||||||||
**************************************************************************/ | ||||||||||||
|
||||||||||||
#pragma once | ||||||||||||
|
||||||||||||
#include <bout/utils.hxx> | ||||||||||||
|
||||||||||||
/// Explicit inversion of a 3x3 matrix \p a | ||||||||||||
/// | ||||||||||||
/// The input \p small determines how small the determinant must be for | ||||||||||||
/// us to throw due to the matrix being singular (ill conditioned); | ||||||||||||
/// If small is less than zero then instead of throwing we return false. | ||||||||||||
/// This is ugly but can be used to support some use cases. | ||||||||||||
template <typename T> | ||||||||||||
bool invert3x3(Matrix<T>& a, T small = 1.0e-15) { | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
TRACE("invert3x3"); | ||||||||||||
|
||||||||||||
// Calculate the first co-factors | ||||||||||||
T A = a(1, 1) * a(2, 2) - a(1, 2) * a(2, 1); | ||||||||||||
T B = a(1, 2) * a(2, 0) - a(1, 0) * a(2, 2); | ||||||||||||
T C = a(1, 0) * a(2, 1) - a(1, 1) * a(2, 0); | ||||||||||||
|
||||||||||||
// Calculate the determinant | ||||||||||||
T det = a(0, 0) * A + a(0, 1) * B + a(0, 2) * C; | ||||||||||||
|
||||||||||||
if (std::abs(det) < std::abs(small)) { | ||||||||||||
if (small >= 0) { | ||||||||||||
throw BoutException("Determinant of matrix < {:e} --> Poorly conditioned", small); | ||||||||||||
} | ||||||||||||
return false; | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
} | ||||||||||||
|
||||||||||||
// Calculate the rest of the co-factors | ||||||||||||
T D = a(0, 2) * a(2, 1) - a(0, 1) * a(2, 2); | ||||||||||||
T E = a(0, 0) * a(2, 2) - a(0, 2) * a(2, 0); | ||||||||||||
T F = a(0, 1) * a(2, 0) - a(0, 0) * a(2, 1); | ||||||||||||
T G = a(0, 1) * a(1, 2) - a(0, 2) * a(1, 1); | ||||||||||||
T H = a(0, 2) * a(1, 0) - a(0, 0) * a(1, 2); | ||||||||||||
T I = a(0, 0) * a(1, 1) - a(0, 1) * a(1, 0); | ||||||||||||
|
||||||||||||
// Now construct the output, overwrites input | ||||||||||||
T detinv = 1.0 / det; | ||||||||||||
|
||||||||||||
a(0, 0) = A * detinv; | ||||||||||||
a(0, 1) = D * detinv; | ||||||||||||
a(0, 2) = G * detinv; | ||||||||||||
a(1, 0) = B * detinv; | ||||||||||||
a(1, 1) = E * detinv; | ||||||||||||
a(1, 2) = H * detinv; | ||||||||||||
a(2, 0) = C * detinv; | ||||||||||||
a(2, 1) = F * detinv; | ||||||||||||
a(2, 2) = I * detinv; | ||||||||||||
|
||||||||||||
return true; | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,88 @@ | ||||||||||||||||
#include "../../src/mesh/invert3x3.hxx" | ||||||||||||||||
|
||||||||||||||||
#include "gtest/gtest.h" | ||||||||||||||||
|
||||||||||||||||
TEST(Invert3x3Test, Identity) { | ||||||||||||||||
Matrix<BoutReal> input(3, 3); | ||||||||||||||||
input = 0; | ||||||||||||||||
for (int i = 0; i < 3; i++) { | ||||||||||||||||
input(i, i) = 1.0; | ||||||||||||||||
} | ||||||||||||||||
auto expected = input; | ||||||||||||||||
invert3x3(input); | ||||||||||||||||
|
||||||||||||||||
for (int j = 0; j < 3; j++) { | ||||||||||||||||
for (int i = 0; i < 3; i++) { | ||||||||||||||||
EXPECT_EQ(input(i, j), expected(i, j)); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
TEST(Invert3x3Test, InvertTwice) { | ||||||||||||||||
std::vector<BoutReal> rawDataMat = {0.05567105, 0.92458227, 0.19954631, | ||||||||||||||||
0.28581972, 0.54009039, 0.13234403, | ||||||||||||||||
0.8841194, 0.161224, 0.74853209}; | ||||||||||||||||
std::vector<BoutReal> rawDataInv = {-2.48021781, 4.27410022, -0.09449605, | ||||||||||||||||
0.6278449, 0.87275842, -0.32168092, | ||||||||||||||||
2.79424897, -5.23628123, 1.51684677}; | ||||||||||||||||
|
||||||||||||||||
Matrix<BoutReal> input(3, 3); | ||||||||||||||||
Matrix<BoutReal> expected(3, 3); | ||||||||||||||||
|
||||||||||||||||
int counter = 0; | ||||||||||||||||
for (int j = 0; j < 3; j++) { | ||||||||||||||||
for (int i = 0; i < 3; i++) { | ||||||||||||||||
input(i, j) = rawDataMat[counter]; | ||||||||||||||||
expected(i, j) = rawDataInv[counter]; | ||||||||||||||||
counter++; | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
// Invert twice to check if we get back to where we started | ||||||||||||||||
invert3x3(input); | ||||||||||||||||
|
||||||||||||||||
for (int j = 0; j < 3; j++) { | ||||||||||||||||
for (int i = 0; i < 3; i++) { | ||||||||||||||||
// Note we only check to single tolerance here | ||||||||||||||||
EXPECT_FLOAT_EQ(input(i, j), expected(i, j)); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
TEST(Invert3x3Test, Singular) { | ||||||||||||||||
Matrix<BoutReal> input(3, 3); | ||||||||||||||||
input = 0; | ||||||||||||||||
EXPECT_THROW(invert3x3(input), BoutException); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
TEST(Invert3x3Test, BadCondition) { | ||||||||||||||||
Matrix<BoutReal> input(3, 3); | ||||||||||||||||
|
||||||||||||||||
// Default small | ||||||||||||||||
input = 0.; | ||||||||||||||||
input(0, 0) = 1.0e-16; | ||||||||||||||||
input(1, 1) = 1.0; | ||||||||||||||||
input(2, 2) = 1.0; | ||||||||||||||||
EXPECT_THROW(invert3x3(input), BoutException); | ||||||||||||||||
|
||||||||||||||||
// Default small -- not quite bad enough condition | ||||||||||||||||
input = 0.; | ||||||||||||||||
input(0, 0) = 1.0e-12; | ||||||||||||||||
input(1, 1) = 1.0; | ||||||||||||||||
input(2, 2) = 1.0; | ||||||||||||||||
EXPECT_NO_THROW(invert3x3(input)); | ||||||||||||||||
|
||||||||||||||||
// Non-default small | ||||||||||||||||
input = 0.; | ||||||||||||||||
input(0, 0) = 1.0e-12; | ||||||||||||||||
input(1, 1) = 1.0; | ||||||||||||||||
input(2, 2) = 1.0; | ||||||||||||||||
EXPECT_THROW(invert3x3(input, 1.0e-10), BoutException); | ||||||||||||||||
|
||||||||||||||||
// Non-default small | ||||||||||||||||
input = 0.; | ||||||||||||||||
input(0, 0) = 1.0e-12; | ||||||||||||||||
input(1, 1) = 1.0; | ||||||||||||||||
input(2, 2) = 1.0; | ||||||||||||||||
EXPECT_NO_THROW(invert3x3(input, -1.0e-10)); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.