14#ifndef CHEMISTRY_SPARSE_LU_H
15#define CHEMISTRY_SPARSE_LU_H
23#include <Kokkos_Core.hpp>
45template <
typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
48 using View1 = Kokkos::View<T *, MemorySpace>;
55 using Pairs = Kokkos::View<uint32_t *[2], Kokkos::LayoutRight, MemorySpace>;
60 Kokkos::View<uint32_t *[3], Kokkos::LayoutRight, MemorySpace>
pivot_update;
101template <
typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
105 using Bits = std::vector<uint64_t>;
107 auto test = [&](
const Bits & row,
const uint32_t c) {
return (row[
c / 64] >> (
c % 64)) & 1; };
112 std::vector<double>
net(
ns, 0.0);
113 for (
const auto & [k,
nu] :
r.products)
net[k] +=
nu;
114 for (
const auto & [k,
nu] :
r.reactants)
net[k] -=
nu;
116 if (
net[k] == 0.0)
continue;
117 for (
const auto & term :
r.orders)
set(P[k],
static_cast<uint32_t>(term.first));
119 for (
const auto & term :
r.products)
set(P[k],
static_cast<uint32_t>(term.first));
121 for (
const auto & term :
r.efficiencies)
set(P[k],
static_cast<uint32_t>(term.first));
125 std::vector<int64_t>
compact(
static_cast<size_t>(n) * n, -1);
128 if (!
test(P[k],
j))
continue;
137 std::vector<uint32_t> column_offset(
ns + 1, 0), column_entry(n_entries);
139 for (
uint32_t j = 0;
j <
ns;
j++) column_offset[
j + 1] += column_offset[
j];
141 std::vector<uint32_t> fill(column_offset.begin(), column_offset.end() - 1);
159 std::vector<uint32_t> perm;
160 std::vector<char>
done(
ns, 0);
169 if (
done[
a])
continue;
177 perm.push_back(
best);
179 std::vector<uint32_t> neighbors;
181 if (
test(
G[
best], b)) neighbors.push_back(b);
183 for (
const uint32_t b : neighbors) {
185 G[b][b / 64] &= ~(
uint64_t(1) << (b % 64));
190 if (
done[b])
continue;
209 if (!
test(
F[
r], k))
continue;
216 std::vector<uint32_t>
stage_of(n, 0);
226 while (
q > 0 &&
stage_of[
q - 1] + (n -
q) + 1 == n_stages) {
233 const std::vector<Bits> fill =
F;
237 std::vector<int64_t>
entry(
static_cast<size_t>(n) * n, -1);
238 std::vector<uint32_t> source, diagonal(n);
239 std::vector<int32_t> jacobian_source;
241 entry[
static_cast<size_t>(
r) * n +
c] =
static_cast<int64_t>(source.size());
242 if (
r ==
c) diagonal[
r] =
static_cast<uint32_t>(source.size());
243 source.push_back(perm[
r] * n + perm[
c]);
244 jacobian_source.push_back(
static_cast<int32_t>(
compact[
static_cast<size_t>(perm[
r]) * n + perm[
c]]));
259 std::vector<std::vector<uint32_t>>
scale(n_stages);
260 std::vector<std::vector<std::array<uint32_t, 3>>>
updates(source.size());
262 std::vector<uint32_t> pivot_lower_offset{0}, pivot_lower_entry, pivot_update_offset{0}, pivot_update;
265 if (at(
r, k) < 0)
continue;
268 if (real(
r, k)) pivot_lower_entry.push_back(
l);
270 if (at(k,
c) < 0)
continue;
272 if (real(
r, k) && real(k,
c)) pivot_update.insert(pivot_update.end(), {t,
l, u});
273 if (k >=
q)
continue;
276 list.push_back({
s,
l, u});
279 pivot_lower_offset.push_back(
static_cast<uint32_t>(pivot_lower_entry.size()));
280 pivot_update_offset.push_back(
static_cast<uint32_t>(pivot_update.size() / 3));
282 std::vector<uint32_t> scale_offset{0}, scale_entry, target_offset{0}, target, target_update{0}, update;
287 for (
size_t a = 0;
a <
list.size();) {
296 scale_entry.insert(scale_entry.end(),
scale[
s].begin(),
scale[
s].end());
297 scale_offset.push_back(
static_cast<uint32_t>(scale_entry.size() / 2));
304 target_update.push_back(
static_cast<uint32_t>(update.size() / 2));
306 target_offset.push_back(
static_cast<uint32_t>(target.size()));
310 std::vector<uint32_t> lower_offset{0}, lower_entry, upper_offset{0}, upper_entry;
313 if (at(
r,
c) < 0)
continue;
314 lower_entry.insert(lower_entry.end(), {
static_cast<uint32_t>(at(
r,
c)),
c});
317 lower_offset.push_back(
static_cast<uint32_t>(lower_entry.size() / 2));
321 if (at(
r,
c) < 0)
continue;
327 if (at(
r,
c) >= 0) upper_entry.insert(upper_entry.end(), {static_cast<uint32_t>(at(r, c)), c});
329 upper_offset.push_back(
static_cast<uint32_t>(upper_entry.size() / 2));
332 std::vector<uint32_t> column_lower_offset{0}, column_lower_entry, column_upper_offset{0}, column_upper_entry;
335 if (real(
r, k)) column_lower_entry.insert(column_lower_entry.end(), {static_cast<uint32_t>(at(r, k)), r});
337 column_lower_offset.push_back(
static_cast<uint32_t>(column_lower_entry.size() / 2));
339 if (real(
r, k)) column_upper_entry.insert(column_upper_entry.end(), {static_cast<uint32_t>(at(r, k)), r});
341 column_upper_offset.push_back(
static_cast<uint32_t>(column_upper_entry.size() / 2));
344 std::vector<uint32_t> chain_upper_offset{0}, chain_upper_entry;
347 if (at(
r, k) >= 0) chain_upper_entry.insert(chain_upper_entry.end(), {static_cast<uint32_t>(at(r, k)), r});
349 chain_upper_offset.push_back(
static_cast<uint32_t>(chain_upper_entry.size() / 2));
353 std::vector<uint32_t> & offset, std::vector<uint32_t> &
rows) {
366 std::vector<uint32_t> lower_level_offset, lower_level_row, upper_level_offset, upper_level_row;
369 std::vector<double> v(n, 0.0);
370 for (
uint32_t k = 0; k <
ns; k++) v[k] = 1.0 / mechanism.
species[k].molecular_weight;
375 auto copy = [](
const auto & h,
const char *
label) {
376 using T =
typename std::decay_t<
decltype(h)>::value_type;
377 Kokkos::View<T *, MemorySpace> d(
label, h.size());
378 auto mirror = Kokkos::create_mirror_view(d);
379 for (
size_t a = 0;
a < h.size();
a++)
mirror(
a) = h[
a];
380 Kokkos::deep_copy(d,
mirror);
386 auto copy2 = [](
const std::vector<uint32_t> & h,
const char *
label) {
387 Kokkos::View<uint32_t *[2], Kokkos::LayoutRight, MemorySpace> d(
label, h.size() / 2);
388 auto mirror = Kokkos::create_mirror_view(d);
389 for (
size_t a = 0;
a < h.size() / 2;
a++) {
393 Kokkos::deep_copy(d,
mirror);
399 p.
pivot_update = Kokkos::View<uint32_t *[3], Kokkos::LayoutRight, MemorySpace>(
"lu_pivot_update", pivot_update.size() / 3);
402 for (
size_t a = 0;
a < pivot_update.size() / 3;
a++) {
403 for (
size_t b = 0; b < 3; b++)
mirror(
a, b) = pivot_update[3 *
a + b];
432 p.
v =
copy(v,
"lu_v");
448template <
typename MemorySpace = Kokkos::DefaultExecutionSpace::memory_space>
461 template <
typename Pairs>
466 for (;
e +
B <= end;
e +=
B) {
485 template <
typename Lanes>
489 lanes.for_each(n, [&](
const uint32_t i) {
x[
i] = b[
p.perm(
i)]; });
491 if constexpr (!Lanes::parallel) {
493 const double x_k =
x[k];
494 const uint32_t first =
p.column_lower_offset(k);
495 lanes.for_each(
p.column_lower_offset(k + 1) - first, [&](
const uint32_t a) {
496 x[
p.column_lower_entry(first +
a, 1)] -=
values[
p.column_lower_entry(first +
a, 0)] *
x_k;
503 lanes.single([&]() {
x[k] =
x_k; });
504 const uint32_t first =
p.column_upper_offset(k);
505 lanes.for_each(
p.column_upper_offset(k + 1) - first, [&](
const uint32_t a) {
506 x[
p.column_upper_entry(first +
a, 1)] -=
values[
p.column_upper_entry(first +
a, 0)] *
x_k;
512 const uint32_t first =
p.lower_level_offset(
l);
513 lanes.for_each(
p.lower_level_offset(
l + 1) - first, [&](
const uint32_t m) {
521 const double * block =
values +
p.chain_offset;
525 const double *
column = block +
j *
m;
530 const double *
column = block +
j *
m;
534 const uint32_t first =
p.chain_upper_offset(
j),
before =
p.chain_upper_offset(
j + 1) - first;
539 x[
p.chain_upper_entry(first +
i -
j, 1)] -=
values[
p.chain_upper_entry(first +
i -
j, 0)] *
x_j;
545 const uint32_t first =
p.upper_level_offset(
l);
546 lanes.for_each(
p.upper_level_offset(
l + 1) - first, [&](
const uint32_t i) {
554 lanes.for_each(n, [&](
const uint32_t i) { b[
p.perm(
i)] =
x[
i]; });
564 template <
typename Lanes>
568 const int32_t src = p.jacobian_source(e);
569 const uint32_t r = p.source(e) / n, c = p.source(e) % n;
570 values[e] = (src >= 0 ? -J[src] : 0.0) + (r == c ? diagonal : 0.0);
573 constexpr bool staged = Lanes::parallel;
575 const double inv = 1.0 /
values[
p.diagonal(k)];
577 lanes.for_each(
p.pivot_lower_offset(k + 1) -
first_lower,
578 [&](
const uint32_t a) { values[p.pivot_lower_entry(first_lower + a)] *= inv; });
582 const uint32_t e = first_update + a;
583 values[p.pivot_update(e, 0)] -= values[p.pivot_update(e, 1)] * values[p.pivot_update(e, 2)];
591 const uint32_t a = first_scale + i;
592 const double inv = 1.0 / values[p.scale_entry(a, 1)];
593 values[p.scale_entry(a, 0)] *= inv;
598 const uint32_t t = first_target + i;
599 values[p.target(t)] =
600 subtract(values[p.target(t)], p.update, p.target_update(t), p.target_update(t + 1), values, values);
606 double * block =
values +
p.chain_offset;
615 lanes.for_each(
L, [&](
const uint32_t lane) {
616 for (
uint32_t first = lane; first < w * w; first +=
B *
L) {
620 const uint32_t i = Kokkos::min(first + b *
L, w * w - 1);
628 if (first + b *
L < w * w) block[at[b]] =
a[b] -
l[b] *
upper[b];
635 const double bad = lanes.sum(n, [&](
const uint32_t k) {
636 const double pivot =
values[
p.diagonal(k)];
637 return !(Kokkos::fabs(pivot) > 0.0) || !Kokkos::isfinite(pivot) ? 1.0 : 0.0;
639 if (
bad > 0.0)
return false;
644 const double b = 1.0 - lanes.sum(n, [&](
const uint32_t i) {
return p.v(
i) *
z[
i]; });
645 if (!(Kokkos::fabs(b) > 1
e-12) || !Kokkos::isfinite(b))
return false;
646 lanes.single([&]() { *
beta = b; });
651 template <
typename Lanes>
654 const double s = lanes.sum(
p.n, [&](
const uint32_t i) { return p.v(i) * b[i]; }) / *
beta;
655 lanes.for_each(
p.n, [&](
const uint32_t i) { b[i] += z[i] * s; });
KOKKOS_INLINE_FUNCTION rtype dot(const rtype *a, const rtype *b)
Compute the dot product of two arrays.
Definition common_math.h:32
Device tables of a mechanism's reactions: rates of progress, production rates and their analytical de...
Execution of one cell's chemistry by one thread or by the vector lanes of a team: loops over species,...
Gas-phase mechanisms read from Cantera YAML files.
SparseLUPattern< MemorySpace > make_sparse_lu_pattern(const Mechanism &mechanism)
Build the pattern for a mechanism's reactor Jacobian (see SparseLUPattern).
Definition sparse_lu.h:102
One ideal-gas phase of a Cantera YAML file: its elements, species and reactions.
Definition mechanism.h:145
std::vector< Species > species
Definition mechanism.h:149
uint32_t n_species() const
Definition mechanism.h:152
std::vector< Reaction > reactions
Definition mechanism.h:150
A gas-phase reaction: elementary, three-body or falloff (Lindemann, Troe, SRI), reversible (reverse r...
Definition mechanism.h:122
The pattern of a reactor Jacobian in (Y_1 .. Y_Ns, T) without its rank-one part, an elimination order...
Definition sparse_lu.h:46
Pairs upper_entry
Definition sparse_lu.h:84
Kokkos::View< uint32_t *[3], Kokkos::LayoutRight, MemorySpace > pivot_update
Definition sparse_lu.h:60
View1< uint32_t > entry_row
Definition sparse_lu.h:90
Kokkos::View< uint32_t *[2], Kokkos::LayoutRight, MemorySpace > Pairs
Definition sparse_lu.h:55
View1< int32_t > jacobian_source
Definition sparse_lu.h:91
View1< uint32_t > entry_column
Definition sparse_lu.h:90
View1< uint32_t > upper_level_offset
Definition sparse_lu.h:81
View1< double > v
Definition sparse_lu.h:86
View1< uint32_t > diagonal
Definition sparse_lu.h:54
KOKKOS_INLINE_FUNCTION uint32_t jacobian_size() const
Doubles of a cell's compact Jacobian.
Definition sparse_lu.h:94
uint32_t n_entries
Definition sparse_lu.h:89
View1< uint32_t > source
Definition sparse_lu.h:53
Kokkos::View< T *, MemorySpace > View1
Definition sparse_lu.h:48
View1< uint32_t > pivot_lower_offset
Definition sparse_lu.h:59
uint32_t nnz
Definition sparse_lu.h:51
uint32_t chain
Definition sparse_lu.h:77
View1< uint32_t > scale_offset
Definition sparse_lu.h:67
Pairs lower_entry
Definition sparse_lu.h:83
uint32_t n_lower_levels
Definition sparse_lu.h:80
Pairs scale_entry
Definition sparse_lu.h:68
Pairs column_lower_entry
Definition sparse_lu.h:62
Pairs update
Definition sparse_lu.h:72
View1< uint32_t > column_lower_offset
Definition sparse_lu.h:61
uint32_t n
Definition sparse_lu.h:50
View1< uint32_t > lower_level_offset
Definition sparse_lu.h:81
View1< uint32_t > column_offset
Definition sparse_lu.h:90
Pairs column_upper_entry
Definition sparse_lu.h:62
View1< uint32_t > column_upper_offset
Definition sparse_lu.h:61
View1< uint32_t > target_offset
Definition sparse_lu.h:69
View1< uint32_t > chain_upper_offset
Definition sparse_lu.h:78
View1< uint32_t > perm
Definition sparse_lu.h:52
View1< uint32_t > lower_level_row
Definition sparse_lu.h:81
View1< uint32_t > target_update
Definition sparse_lu.h:71
View1< uint32_t > target
Definition sparse_lu.h:70
uint32_t chain_offset
Definition sparse_lu.h:77
View1< uint32_t > pivot_lower_entry
Definition sparse_lu.h:59
View1< uint32_t > column_entry
Definition sparse_lu.h:90
uint32_t n_upper_levels
Definition sparse_lu.h:80
Pairs chain_upper_entry
Definition sparse_lu.h:79
View1< uint32_t > upper_offset
Definition sparse_lu.h:82
View1< uint32_t > pivot_update_offset
Definition sparse_lu.h:59
KOKKOS_INLINE_FUNCTION uint32_t work_size() const
Doubles of a cell's work memory: values, z = A_s^-1 u, u and one vector.
Definition sparse_lu.h:97
View1< uint32_t > lower_offset
Definition sparse_lu.h:82
View1< uint32_t > upper_level_row
Definition sparse_lu.h:81
uint32_t n_stages
Definition sparse_lu.h:66
The linear solver of integrate() for SparseLUPattern: factor() gathers diagonal I - J_s from the comp...
Definition sparse_lu.h:449
KOKKOS_INLINE_FUNCTION bool factor(const Lanes &lanes, const double *J, const double diagonal) const
Factor diagonal I - J_s (see SparseLU): one thread pivot by pivot; lanes stage by stage,...
Definition sparse_lu.h:565
double * x
Definition sparse_lu.h:454
KOKKOS_INLINE_FUNCTION void solve_s(const Lanes &lanes, double *b) const
A_s^-1 b in place, with every entry's terms in the order of the elimination column by column (so the ...
Definition sparse_lu.h:486
const double * u
Definition sparse_lu.h:453
static KOKKOS_INLINE_FUNCTION double subtract(double a, const Pairs &entry, const uint32_t begin, const uint32_t end, const double *values, const double *x)
a - sum_e values[entry(e, 0)] x[entry(e, 1)] for e in [begin, end), in order; the loads of a few term...
Definition sparse_lu.h:462
double * beta
Definition sparse_lu.h:455
const SparseLUPattern< MemorySpace > & p
Definition sparse_lu.h:450
KOKKOS_INLINE_FUNCTION void solve(const Lanes &lanes, double *b) const
Definition sparse_lu.h:652
double * values
Definition sparse_lu.h:451
double * z
Definition sparse_lu.h:452
uint32_t rows
Definition teno_setup.cpp:455
CellSetup< ExecSpace > c
Definition teno_setup.cpp:1810
uint8_t r
Definition teno_setup.cpp:687
Geometry< Space > g
Definition teno_setup.cpp:678
uint16_t ns
Definition teno_setup.cpp:688
Lane< rtype > scale
Definition teno_setup.cpp:531