1pub fn set_fixed_bc<T, const N: usize, const NN: usize>(
4 val_dia: T,
5 bc_flag: &[[i32; N]],
6 row2val: &mut [[T; NN]],
7 idx2val: &mut [[T; NN]],
8 row2idx: &[usize],
9 idx2col: &[usize],
10) where
11 T: num_traits::Float,
12{
13 let num_blk = bc_flag.len();
14 assert_eq!(bc_flag.len(), row2val.len());
15 for i_blk in 0..num_blk {
16 for i_dim in 0..N {
18 if bc_flag[i_blk][i_dim] == 0 {
19 continue;
20 };
21 for j_dim in 0..N {
22 row2val[i_blk][i_dim + N * j_dim] = T::zero();
23 row2val[i_blk][j_dim + N * i_dim] = T::zero();
24 }
25 row2val[i_blk][i_dim + N * i_dim] = val_dia;
26 }
27 }
28 assert_eq!(bc_flag.len(), num_blk);
30 for i_blk in 0..num_blk {
31 for idx in row2idx[i_blk]..row2idx[i_blk + 1] {
33 for i_dim in 0..N {
34 if bc_flag[i_blk][i_dim] == 0 {
35 continue;
36 };
37 for j_dim in 0..N {
38 idx2val[idx][i_dim + N * j_dim] = T::zero();
39 }
40 }
41 }
42 }
43 for idx in 0..idx2col.len() {
45 let j_blk1 = idx2col[idx];
46 for j_dim in 0..N {
47 if bc_flag[j_blk1][j_dim] == 0 {
48 continue;
49 };
50 for i_dim in 0..N {
51 idx2val[idx][i_dim + N * j_dim] = T::zero();
52 }
53 }
54 }
55}
56
57pub fn set_fix_dof_to_rhs_vector<T, const N: usize>(blk2rhs: &mut [[T; N]], blk2isfix: &[[i32; N]])
58where
59 T: num_traits::Float,
60{
61 let num_vtx = blk2rhs.len();
62 for i_vtx in 0..num_vtx {
63 for i_dof in 0..N {
64 if blk2isfix[i_vtx][i_dof] == 0 {
65 continue;
66 }
67 blk2rhs[i_vtx][i_dof] = T::zero();
68 }
69 }
70}
71
72pub struct Matrix<MAT> {
76 pub num_blk: usize,
77 pub row2idx: Vec<usize>,
78 pub idx2col: Vec<usize>,
79 pub idx2val: Vec<MAT>,
80 pub row2val: Vec<MAT>,
81}
82
83impl<T, const NN: usize> Matrix<[T; NN]>
84where
85 T: num_traits::Float,
86{
87 pub fn new() -> Self {
88 Matrix {
89 num_blk: 0,
90 row2idx: vec![0],
91 idx2col: Vec::<usize>::new(),
92 idx2val: Vec::<[T; NN]>::new(),
93 row2val: Vec::<[T; NN]>::new(),
94 }
95 }
96
97 pub fn as_ref_mut(&mut self) -> MatrixRefMut<T, NN> {
98 MatrixRefMut {
99 num_blk: self.num_blk,
100 row2idx: &self.row2idx,
101 idx2col: &self.idx2col,
102 idx2val: &mut self.idx2val,
103 row2val: &mut self.row2val,
104 }
105 }
106
107 pub fn as_ref(&self) -> MatrixRef<T, NN> {
108 MatrixRef {
109 num_blk: self.num_blk,
110 row2idx: &self.row2idx,
111 idx2col: &self.idx2col,
112 idx2val: &self.idx2val,
113 row2val: &self.row2val,
114 }
115 }
116
117 pub fn from_vtx2vtx(vtx2idx: &[usize], idx2vtx: &[usize]) -> Self {
118 let num_blk = vtx2idx.len() - 1;
119 let num_idx = vtx2idx[num_blk];
120 Self {
121 num_blk,
122 row2idx: vtx2idx.to_vec(),
123 idx2col: idx2vtx.to_vec(),
124 idx2val: vec![[T::zero(); NN]; num_idx],
125 row2val: vec![[T::zero(); NN]; num_blk],
126 }
127 }
128
129 pub fn set_fixed_dof<const N: usize>(&mut self, val_dia: T, blk2isfix: &[[i32; N]]) {
130 set_fixed_bc(
131 val_dia,
132 blk2isfix,
133 &mut self.row2val,
134 &mut self.idx2val,
135 &self.row2idx,
136 &self.idx2col,
137 );
138 }
139
140 pub fn mult_vec<const N: usize>(
144 &self,
145 y_vec: &mut [[T; N]],
146 beta: T,
147 alpha: T,
148 x_vec: &[[T; N]],
149 ) where
150 T: num_traits::Float,
151 {
152 use del_geo_core::matn_col_major;
153 use del_geo_core::vecn::VecN;
154 assert_eq!(y_vec.len(), self.num_blk);
155 for m in y_vec.iter_mut() {
156 del_geo_core::vecn::scale_in_place(m, beta);
157 }
158 for i_blk in 0..self.num_blk {
159 for idx in self.row2idx[i_blk]..self.row2idx[i_blk + 1] {
160 assert!(idx < self.idx2col.len());
161 let j_blk = self.idx2col[idx];
162 assert!(j_blk < self.num_blk);
163 let a = matn_col_major::mult_vec(&self.idx2val[idx], &x_vec[j_blk]).scale(alpha);
164 del_geo_core::vecn::add_in_place(&mut y_vec[i_blk], &a);
165 }
166 {
167 let a = matn_col_major::mult_vec(&self.row2val[i_blk], &x_vec[i_blk]).scale(alpha);
168 del_geo_core::vecn::add_in_place(&mut y_vec[i_blk], &a);
169 }
170 }
171 }
172
173 pub fn set_zero(&mut self) {
175 assert_eq!(self.idx2val.len(), self.idx2col.len());
176 self.row2val.fill([T::zero(); NN]);
177 self.idx2val.fill([T::zero(); NN]);
178 }
179
180 pub fn merge_for_array_blk<const NNODE: usize>(
181 &mut self,
182 emat: &[[[T; NN]; NNODE]; NNODE],
183 node2vtx: &[usize; NNODE],
184 col2idx: &mut Vec<usize>,
185 ) {
186 col2idx.resize(self.num_blk, usize::MAX);
187 for i_node in 0..NNODE {
188 let i_vtx = node2vtx[i_node];
189 for idx in self.row2idx[i_vtx]..self.row2idx[i_vtx + 1] {
190 let j_vtx = self.idx2col[idx];
191 col2idx[j_vtx] = idx;
192 }
193 for j_node in 0..NNODE {
194 if i_node == j_node {
195 del_geo_core::matn_col_major::add_in_place(
196 &mut self.row2val[i_vtx],
197 &emat[i_node][j_node],
198 );
199 } else {
200 let j_vtx = node2vtx[j_node];
201 let idx0 = col2idx[j_vtx];
202 assert_ne!(idx0, usize::MAX);
203 del_geo_core::matn_col_major::add_in_place(
204 &mut self.idx2val[idx0],
205 &emat[i_node][j_node],
206 );
207 }
208 }
209 for idx in self.row2idx[i_vtx]..self.row2idx[i_vtx + 1] {
210 let j_vtx = self.idx2col[idx];
211 col2idx[j_vtx] = usize::MAX;
212 }
213 }
214 }
215}
216
217pub fn conjugate_gradient<T, const N: usize, const NN: usize>(
219 r_vec: &mut [[T; N]],
220 u_vec: &mut [[T; N]],
221 ap_vec: &mut [[T; N]],
222 p_vec: &mut [[T; N]],
223 conv_ratio_tol: T,
224 max_iteration: usize,
225 mat: MatrixRef<T, NN>,
226) -> Vec<T>
227where
228 T: num_traits::Float + std::fmt::Display + std::fmt::Debug,
229{
230 let _num_dim = r_vec.len() / mat.row2val.len();
231 let mut conv_hist = Vec::<T>::new();
233 crate::slice_of_array::set_zero(u_vec);
234 let mut sqnorm_res = crate::slice_of_array::dot(r_vec, r_vec);
235 if sqnorm_res < T::epsilon() {
236 return conv_hist;
237 }
238 let inv_sqnorm_res_ini = T::one() / sqnorm_res;
239 crate::slice_of_array::copy(p_vec, r_vec); for _iitr in 0..max_iteration {
241 mat.mult_vec::<N>(ap_vec, T::zero(), T::one(), p_vec); let pap = crate::slice_of_array::dot(p_vec, ap_vec);
244 let alpha = sqnorm_res / pap;
246 crate::slice_of_array::add_scaled_vector(u_vec, alpha, p_vec); crate::slice_of_array::add_scaled_vector(r_vec, -alpha, ap_vec); let sqnorm_res_new = crate::slice_of_array::dot(r_vec, r_vec);
249 let conv_ratio = (sqnorm_res_new * inv_sqnorm_res_ini).sqrt();
250 conv_hist.push(conv_ratio);
251 if conv_ratio < conv_ratio_tol {
252 return conv_hist;
253 }
254 {
255 let beta = sqnorm_res_new / sqnorm_res; sqnorm_res = sqnorm_res_new;
257 crate::slice_of_array::scale_and_add_vec(p_vec, beta, r_vec); }
259 }
260 conv_hist
261}
262
263#[allow(clippy::too_many_arguments)]
265pub fn preconditioned_conjugate_gradient<T, const N: usize, const NN: usize>(
266 r_vec: &mut [[T; N]],
267 x_vec: &mut Vec<[T; N]>,
268 pr_vec: &mut Vec<[T; N]>,
269 p_vec: &mut Vec<[T; N]>,
270 conv_ratio_tol: T,
271 max_nitr: usize,
272 mat: &Matrix<[T; NN]>,
273 ilu: &crate::sparse_ilu::Preconditioner<[T; NN]>,
274) -> Vec<T>
275where
276 T: num_traits::Float + std::fmt::Debug,
277{
278 use crate::slice_of_array::{add_scaled_vector, copy, dot, scale_and_add_vec, set_zero};
279 {
280 let n = r_vec.len();
281 x_vec.resize(n, [T::zero(); N]);
282 pr_vec.resize(n, [T::zero(); N]);
283 p_vec.resize(n, [T::zero(); N]);
284 }
285 assert_eq!(r_vec.len(), mat.num_blk);
286 let mut conv_hist = Vec::<T>::new();
287
288 set_zero(x_vec);
289
290 let inv_sqnorm_res0 = {
291 let sqnorm_res0 = dot(r_vec, r_vec); conv_hist.push(sqnorm_res0.sqrt());
293 if sqnorm_res0 < T::epsilon() {
294 return conv_hist;
295 }
296 T::one() / sqnorm_res0
297 };
298
299 copy(pr_vec, r_vec); crate::sparse_ilu::solve_preconditioning_vec(pr_vec, ilu); copy(p_vec, pr_vec);
306
307 let mut rpr = dot(r_vec, pr_vec); for _iitr in 0..max_nitr {
310 mat.mult_vec(pr_vec, T::zero(), T::one(), p_vec);
312 {
313 let pap = dot(p_vec, pr_vec);
315 let alpha = rpr / pap;
316 add_scaled_vector(r_vec, -alpha, pr_vec); add_scaled_vector(x_vec, alpha, p_vec); }
319 {
320 let sqnorm_res = dot(r_vec, r_vec); conv_hist.push(sqnorm_res.sqrt());
323 let conv_ratio = (sqnorm_res * inv_sqnorm_res0).sqrt();
324 if conv_ratio < conv_ratio_tol {
325 return conv_hist;
326 }
327 }
328 {
329 copy(pr_vec, r_vec);
331 crate::sparse_ilu::solve_preconditioning_vec(pr_vec, ilu);
333 let rpr1 = dot(r_vec, pr_vec);
335 let beta = rpr1 / rpr;
337 rpr = rpr1;
338 scale_and_add_vec(p_vec, beta, pr_vec);
340 }
341 }
342 {
343 let sq_norm_res = dot(r_vec, r_vec); conv_hist.push(sq_norm_res.sqrt());
346 }
347 conv_hist
348}
349
350pub struct MatrixRefMut<'a, T, const NN: usize> {
351 pub num_blk: usize,
352 pub row2idx: &'a [usize],
353 pub idx2col: &'a [usize],
354 pub idx2val: &'a mut [[T; NN]],
355 pub row2val: &'a mut [[T; NN]],
356}
357
358impl<'a, T, const NN: usize> MatrixRefMut<'a, T, NN>
359where
360 T: num_traits::Float,
361{
362 pub fn set_zero(&mut self) {
363 assert_eq!(self.idx2val.len(), self.idx2col.len());
364 self.row2val.fill([T::zero(); NN]);
365 self.idx2val.fill([T::zero(); NN]);
366 }
367
368 pub fn merge_for_array_blk<const NNODE: usize>(
369 &mut self,
370 emat: &[[[T; NN]; NNODE]; NNODE],
371 node2vtx: &[usize; NNODE],
372 col2idx: &mut Vec<usize>,
373 ) {
374 col2idx.resize(self.num_blk, usize::MAX);
375 for i_node in 0..NNODE {
376 let i_vtx = node2vtx[i_node];
377 for idx in self.row2idx[i_vtx]..self.row2idx[i_vtx + 1] {
378 let j_vtx = self.idx2col[idx];
379 col2idx[j_vtx] = idx;
380 }
381 for j_node in 0..NNODE {
382 if i_node == j_node {
383 del_geo_core::matn_col_major::add_in_place(
384 &mut self.row2val[i_vtx],
385 &emat[i_node][j_node],
386 );
387 } else {
388 let j_vtx = node2vtx[j_node];
389 let idx0 = col2idx[j_vtx];
390 assert_ne!(idx0, usize::MAX);
391 del_geo_core::matn_col_major::add_in_place(
392 &mut self.idx2val[idx0],
393 &emat[i_node][j_node],
394 );
395 }
396 }
397 for idx in self.row2idx[i_vtx]..self.row2idx[i_vtx + 1] {
398 let j_vtx = self.idx2col[idx];
399 col2idx[j_vtx] = usize::MAX;
400 }
401 }
402 }
403}
404
405pub struct MatrixRef<'a, T, const NN: usize> {
406 pub num_blk: usize,
407 pub row2idx: &'a [usize],
408 pub idx2col: &'a [usize],
409 pub idx2val: &'a [[T; NN]],
410 pub row2val: &'a [[T; NN]],
411}
412
413impl<'a, T, const NN: usize> MatrixRef<'a, T, NN>
414where
415 T: num_traits::Float,
416{
417 pub fn mult_vec<const N: usize>(
421 &self,
422 y_vec: &mut [[T; N]],
423 beta: T,
424 alpha: T,
425 x_vec: &[[T; N]],
426 ) where
427 T: num_traits::Float,
428 {
429 use del_geo_core::matn_col_major;
430 use del_geo_core::vecn::VecN;
431 assert_eq!(y_vec.len(), self.num_blk);
432 for m in y_vec.iter_mut() {
433 del_geo_core::vecn::scale_in_place(m, beta);
434 }
435 for i_blk in 0..self.num_blk {
436 for idx in self.row2idx[i_blk]..self.row2idx[i_blk + 1] {
437 assert!(idx < self.idx2col.len());
438 let j_blk = self.idx2col[idx];
439 assert!(j_blk < self.num_blk);
440 let a = matn_col_major::mult_vec(&self.idx2val[idx], &x_vec[j_blk]).scale(alpha);
441 del_geo_core::vecn::add_in_place(&mut y_vec[i_blk], &a);
442 }
443 {
444 let a = matn_col_major::mult_vec(&self.row2val[i_blk], &x_vec[i_blk]).scale(alpha);
445 del_geo_core::vecn::add_in_place(&mut y_vec[i_blk], &a);
446 }
447 }
448 }
449}