OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
LapackLinearAlgebra.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved. (BSD 3-clause; full text omitted in this sketch.)
4 *
5 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
6 * research, please cite:
7 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
8 */
9
10/*! \file math/LapackLinearAlgebra.hpp
11 \brief LAPACK-backed fast paths for the dynamic, double-precision dense
12 routines, dispatched by overload.
13
14 SKETCH / PROPOSAL -- conventions worked out, not yet build-tested.
15
16 The generic templates in LU.hpp and CholeskyDecomposition.hpp are kept as
17 the fallback for small fixed-size matrices (Mat3x3d, Mat6x6d in HydroProp,
18 ...) and for non-RealType element types, where the packing + call overhead
19 of going out to LAPACK would lose to the inlined VTK/Crout code. Here we add
20 *non-template overloads* for exactly DynamicRectMatrix<RealType>: a
21 non-template overload is preferred over a function template for an exact
22 type match, so any call invertMatrix(A, AI) / CholeskyDecomposition(A, L)
23 with A,L of that concrete type routes here, while every fixed-size caller
24 keeps the generic template unchanged. No edits to the generic headers.
25
26 Include this header instead of (or after) LU.hpp/CholeskyDecomposition.hpp
27 at the call site (e.g. in RPYMobility.cpp) so the overloads are visible.
28 With HAVE_LAPACK undefined it simply forwards to the generics.
29
30 ASSUMPTIONS to confirm against the tree:
31 - DynamicRectMatrix<RealType> stores its data contiguously and exposes a
32 raw pointer (assumed getArray() below); if the accessor differs, only
33 the two `a = ...getArray()` lines change.
34 - Storage is row-major (OpenMD convention). Since the matrices we factor
35 here (the RPY mobility M and resistance R) are symmetric, the row/column
36 major mismatch with LAPACK is harmless, and for the general inverse the
37 "invert the transpose, read back transposed" identity makes a plain
38 dgetrf/dgetri on the row-major buffer return the correct inverse.
39 - RealType is double. For a single-precision build (RealType == float),
40 dispatch the s* entry points instead (a thin if-constexpr or a pair of
41 overloaded extern "C" wrappers); only the BLAS/LAPACK names change.
42*/
43
44#ifndef MATH_LAPACKLINEARALGEBRA_HPP
45#define MATH_LAPACKLINEARALGEBRA_HPP
46
47#include <algorithm>
48#include <vector>
49
50#include "config.h" // provides HAVE_LAPACK
51#include "math/CholeskyDecomposition.hpp"
53#include "math/LU.hpp"
54
55#ifdef HAVE_LAPACK
56
57extern "C" {
58// LU factor / inverse (general)
59void dgetrf_(const int* m, const int* n, double* a, const int* lda, int* ipiv,
60 int* info);
61void dgetri_(const int* n, double* a, const int* lda, const int* ipiv,
62 double* work, const int* lwork, int* info);
63// Cholesky factor (symmetric positive definite)
64void dpotrf_(const char* uplo, const int* n, double* a, const int* lda,
65 int* info);
66}
67
68namespace OpenMD {
69
70 /**
71 * R = A^{-1} for a dynamic double matrix, via LAPACK LU.
72 * Non-template overload: chosen ahead of LU.hpp's invertMatrix template for
73 * this exact type. A is left intact; the result is written into AI. (Feeding
74 * the row-major buffer to column-major LAPACK factors A^T, whose inverse read
75 * back row-major is exactly A^{-1}, so no explicit transpose is needed.)
76 */
79 const int n = static_cast<int>(A.getNRow());
80 if (n != static_cast<int>(A.getNCol()) ||
81 n != static_cast<int>(AI.getNRow()) ||
82 n != static_cast<int>(AI.getNCol()))
83 return false;
84 if (n == 0) return true;
85
86 // factor/invert in AI's buffer, leaving A untouched
87 for (int i = 0; i < n; ++i)
88 for (int j = 0; j < n; ++j)
89 AI(i, j) = A(i, j);
90
91 RealType* a = AI.getArrayPointer(); // contiguous row-major
92 std::vector<int> ipiv(n);
93 int info = 0, lda = n;
94
95 dgetrf_(&n, &n, a, &lda, ipiv.data(), &info);
96 if (info != 0) return false; // singular (info>0) or bad arg (info<0)
97
98 // workspace query, then inversion
99 int lwork = -1;
100 RealType wq = 0.0;
101 dgetri_(&n, a, &lda, ipiv.data(), &wq, &lwork, &info);
102 lwork = std::max(1, static_cast<int>(wq));
103 std::vector<RealType> work(static_cast<std::size_t>(lwork));
104 dgetri_(&n, a, &lda, ipiv.data(), work.data(), &lwork, &info);
105 return info == 0;
106 }
107
108 /**
109 * L L^T = A for a dynamic, symmetric, double matrix, via LAPACK dpotrf.
110 * Returns the lower-triangular factor with the strict upper triangle zeroed,
111 * matching the generic CholeskyDecomposition contract (so a downstream S*Z
112 * may be a full matrix-vector product).
113 *
114 * Convention: our buffer is row-major; LAPACK reads it column-major, i.e. as
115 * A^T. A is symmetric here (A == A^T), so requesting the 'U' factor from
116 * LAPACK (column-major upper) yields, read back row-major, the lower factor
117 * we want.
118 */
119 inline void CholeskyDecomposition(DynamicRectMatrix<RealType>& A,
121 const int n = static_cast<int>(A.getNRow());
122 for (int i = 0; i < n; ++i)
123 for (int j = 0; j < n; ++j)
124 L(i, j) = A(i, j);
125 if (n == 0) return;
126
127 RealType* l = L.getArrayPointer(); // contiguous row-major
128 int info = 0, lda = n;
129 const char uplo = 'U'; // row-major lower factor <-> column-major upper
130 dpotrf_(&uplo, &n, l, &lda, &info);
131
132 if (info != 0) {
133 // not positive definite: zero the factor so the caller's pivot check
134 // (S(k,k) > eps) trips deterministically instead of reading partial data.
135 for (int i = 0; i < n; ++i)
136 for (int j = 0; j < n; ++j)
137 L(i, j) = 0.0;
138 return;
139 }
140 // dpotrf leaves the opposite triangle untouched; zero it to match the
141 // generic routine, which returns a clean lower-triangular factor.
142 for (int i = 0; i < n; ++i)
143 for (int j = i + 1; j < n; ++j)
144 L(i, j) = 0.0;
145 }
146
147} // namespace OpenMD
148
149#endif // HAVE_LAPACK
150#endif // MATH_LAPACKLINEARALGEBRA_HPP
Real * getArrayPointer()
Returns a pointer to the contiguous internal storage (row-major).
Rectangular matrix class with contiguous flat storage.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.
bool invertMatrix(MatrixType &A, MatrixType &AI)
Invert input square matrix A into matrix AI.
Definition LU.hpp:101