-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathbgy3d-mat.c
172 lines (137 loc) · 4.21 KB
/
bgy3d-mat.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* -*- mode: c; c-basic-offset: 2; -*- vim: set sw=2 tw=70 et sta ai: */
/*
Copyright (c) 2007 Lukas Jager
Copyright (c) 2013, 2014 Alexei Matveev
*/
#include "bgy3d.h"
#include "bgy3d-mat.h"
/*
To create a matrix one needs the local and total size of the matrix
(section). This is how to get it from another matrix. See also
asizes() in bgy3d-dirichlet.c.
*/
static void
msizes (const Mat A, int *n3, int *N3)
{
int m, n;
MatGetLocalSize (A, &m, &n);
assert (m == n);
int M, N;
MatGetSize (A, &M, &N);
assert (M == N);
*n3 = n;
*N3 = N;
}
/*
* Implementation of the matrix inverse by an iterative solver.
*/
/* KSP stays for Krylov Sub-Space, used to solve systems of linear
equations: */
static KSP
ksp_create (Mat M)
{
KSP ksp;
/* Create ksp environment */
KSPCreate (comm_world_petsc, &ksp);
/* Set rtol, atol, dtol, maxits */
{
real rtol, abstol, dtol;
int maxits;
KSPGetTolerances (ksp, &rtol, &abstol, &dtol, &maxits);
/*
FIXME: literal numbers here, decide on how to control these
settings from the user side. Defaults are at the mercy of the
library: rtol = 1e-5, abstol = 1e-50, dtol = 1e+4, maxits =
10000.
This particular solver is used to find solutions of linear
equations A x = b. One has to assume the ultimate accuracy is
desired here. The default RTOL is too large though, decrease it.
Compare to the motivation and settings in bgy3d-snes.c:
*/
KSPSetTolerances (ksp, rtol / 1000, abstol, 10 * dtol, maxits / 10);
}
/* Set the matrix: */
KSPSetOperators (ksp, M, M, SAME_PRECONDITIONER);
/* Set preconditioner: PCLU, PCNONE, PCJACOBI, PCBJACOBI, ... */
{
PC pc;
KSPGetPC (ksp, &pc);
/*
This code is executed for explicit (bgy3d-dirichlet.c) and shell
matrices (bgy3d-snes.c). The shell matrix cannot use Jacobi
preconditioner. The symptom is an error message at the first
call to KSPSolve() mentioning
"MatGetSubMatrices() line ... in ... Mat type shell".
This error occurs with PETSC 3.2 but not with 3.1. See also
comments in bgy3d-snes.c.
*/
/* MatType values happen to be (immutable) strings: */
#if PETSC_VERSION != VERSION(3, 2) && PETSC_VERSION != VERSION(3, 1)
MatType mtype; /* typedef const char* MatType */
#else
const MatType mtype; /* typedef char* MatType */
#endif
MatGetType (M, &mtype);
/*
The MatType strings do not seem to be "interned" so that one
should compare values, not pointers. MATSHELL is #defined to
"shell" by PETSC:
*/
if (strcmp (mtype, MATSHELL) == 0)
PCSetType (pc, PCNONE);
else
PCSetType (pc, PCBJACOBI);
}
/* This is the place which is supposed to tell KSP solver to re-use
the supplied vector as initial guess: */
KSPSetInitialGuessNonzero (ksp, PETSC_TRUE);
/* Runtime options (including those in ~/.petscrc) will override
default parameters: */
KSPSetFromOptions (ksp);
return ksp;
}
/*
[Operation] Does y = A x where A = B^-1 and was constructed as A =
mat_inverse (B):
*/
static PetscErrorCode
mat_mult_inv (Mat A, Vec x, Vec y)
{
/* KSP solver was created on matrix construction time: */
KSP ksp = mat_shell_context (A);
KSPSolve (ksp, x, y);
/* If you think you need to know how many iteration were required to
solve the equation do this: */
if (verbosity > 0)
{
int iter;
KSPGetIterationNumber (ksp, &iter);
PRINTF ("ksp(%2d) ", iter);
}
return 0;
}
/*
[Destructor] Destroys internals of a matrix created by
mat_inverse().
*/
static PetscErrorCode
mat_destroy_inv (Mat A)
{
if (verbosity > 0)
printf ("mat_destroy_inv(%p)\n", A);
KSP ksp = mat_shell_context (A);
KSPDestroy (&ksp);
return 0;
}
/* [Constructor] Retuns an inverse matrix. */
Mat
mat_inverse (Mat A)
{
/* An inverse operator needs to solve linear equations with the
original matrix. Presumable KSP object will hold a reference: */
KSP ksp = ksp_create (A);
/* Get the shape of the future matrix: */
int n, N;
msizes (A, &n, &N);
return mat_shell_create (n, ksp, mat_mult_inv, mat_destroy_inv);
}