1
// Copyright (C) 2005-2006 Anders Logg.
2
// Licensed under the GNU LGPL Version 2.1.
4
// First added: 2005-01-27
5
// Last changed: 2006-08-08
7
#include <dolfin/dolfin_math.h>
8
#include <dolfin/uBlasVector.h>
9
#include <dolfin/ODE.h>
10
#include <dolfin/Method.h>
11
#include <dolfin/MultiAdaptiveTimeSlab.h>
12
#include <dolfin/MultiAdaptiveNewtonSolver.h>
13
#include <dolfin/MultiAdaptiveJacobian.h>
15
using namespace dolfin;
17
//-----------------------------------------------------------------------------
18
MultiAdaptiveJacobian::MultiAdaptiveJacobian(MultiAdaptiveNewtonSolver& newton,
19
MultiAdaptiveTimeSlab& timeslab)
20
: TimeSlabJacobian(timeslab), newton(newton), ts(timeslab),
21
Jvalues(0), Jindices(0), Jlookup(0)
23
// Allocate Jacobian row indices
24
Jindices = new uint[ode.size()];
26
// Compute start of each row
28
for (uint i = 0; i < ode.size(); i++)
31
sum += ode.dependencies[i].size();
34
// Allocate Jacobian values
35
Jvalues = new real[sum];
36
for (uint pos = 0; pos < sum; pos++)
39
message("Generated Jacobian data structure for %d dependencies.", sum);
41
// Compute maximum number of dependencies
43
for (uint i = 0; i < ode.size(); i++)
45
const uint size = ode.dependencies[i].size();
50
// Allocate lookup table for dependencies to components with small time steps
51
Jlookup = new real[std::max(static_cast<unsigned int>(1), maxsize - 1)];
53
//-----------------------------------------------------------------------------
54
MultiAdaptiveJacobian::~MultiAdaptiveJacobian()
56
if ( Jvalues ) delete [] Jvalues;
57
if ( Jindices ) delete [] Jindices;
58
if ( Jlookup ) delete [] Jlookup;
60
//-----------------------------------------------------------------------------
61
dolfin::uint MultiAdaptiveJacobian::size(uint dim) const
65
//-----------------------------------------------------------------------------
66
void MultiAdaptiveJacobian::mult(const uBlasVector& x, uBlasVector& y) const
68
// We iterate over all degrees of freedom j in the time slab and compute
69
// y_j = (Ax)_j for each degree of freedom of the system.
71
// Start with y = x, accounting for the derivative dF_j/dx_j = 1
75
if ( method.type() == Method::cG )
80
//-----------------------------------------------------------------------------
81
void MultiAdaptiveJacobian::init()
83
// Compute Jacobian at the beginning of the slab
84
real t = ts.starttime();
85
//message("Recomputing Jacobian matrix at t = %f.", t);
88
for (uint i = 0; i < ode.size(); i++)
90
const Array<uint>& deps = ode.dependencies[i];
91
for (uint pos = 0; pos < deps.size(); pos++)
92
Jvalues[Jindices[i] + pos] = ode.dfdu(ts.u0, t, i, deps[pos]);
96
// Compute Jacobian at the end of the slab
97
real t = ts.endtime();
98
//message("Recomputing Jacobian matrix at t = %f.", t);
101
for (uint i = 0; i < ode.size(); i++)
103
const Array<uint>& deps = ode.dependencies[i];
104
for (uint pos = 0; pos < deps.size(); pos++)
105
Jvalues[Jindices[i] + pos] = ode.dfdu(ts.u, t, i, deps[pos]);
109
//-----------------------------------------------------------------------------
110
void MultiAdaptiveJacobian::cGmult(const uBlasVector& x, uBlasVector& y) const
112
// Reset current sub slab
116
for (uint i = 0; i < ts.N; i++)
119
// Iterate over all elements
120
for (uint e0 = 0; e0 < ts.ne; e0++)
122
// Cover all elements in current sub slab
123
s0 = ts.coverNext(s0, e0);
126
const uint i0 = ts.ei[e0];
127
const real a0 = ts.sa[s0];
128
const real b0 = ts.sb[s0];
129
const real k0 = b0 - a0;
130
const uint j0 = e0 * method.nsize();
132
// Add dependency on predecessor for all dofs of element
133
const int ep = ts.ee[e0];
136
const real xp = x(ep*method.nsize() + method.nsize() - 1);
137
for (uint n = 0; n < method.nsize(); n++)
144
// Iterate over dependencies for the current component
145
const Array<uint>& deps = ode.dependencies[i0];
146
for (uint pos = 0; pos < deps.size(); pos++)
149
const real dfdu = Jvalues[Jindices[i0] + pos];
151
// Skip elements which have not been covered
152
const uint i1 = deps[pos];
153
const int e1 = ts.elast[i1];
156
// Save dependency for later
157
Jlookup[Jpos++] = dfdu;
161
// Skip elements with smaller time steps
162
const uint s1 = ts.es[e1];
163
const real b1 = ts.sb[s1];
164
if ( b1 < (a0 + DOLFIN_EPS) )
166
// Save dependency for later
167
Jlookup[Jpos++] = dfdu;
169
// Add dependency to initial value for all dofs
170
const real tmp = k0 * dfdu * x(e1 * method.nsize() + method.nsize() - 1);
171
for (uint n = 0; n < method.nsize(); n++)
172
y(j0 + n) -= tmp * method.nweight(n, 0);
177
// Get first dof for other element
178
const uint j1 = e1 * method.nsize();
180
// Use fast evaluation for elements in the same sub slab
181
if ( s0 == static_cast<int>(s1) )
183
// Add dependency to dof of initial value if any
184
const int ep = ts.ee[e1];
185
const real tmp0 = k0 * dfdu;
188
const real tmp1 = tmp0 * x(ep * method.nsize() + method.nsize() - 1);
189
for (uint n = 0; n < method.nsize(); n++)
190
y(j0 + n) -= tmp1 * method.nweight(n, 0);
193
// Add dependencies to internal dofs
194
for (uint n = 0; n < method.nsize(); n++)
197
for (uint m = 0; m < method.nsize(); m++)
198
sum += method.nweight(n, m + 1) * x(j1 + m);
199
y(j0 + n) -= tmp0 * sum;
204
const real a1 = ts.sa[s1];
205
const real k1 = b1 - a1;
207
// Iterate over dofs of element
208
const real tmp0 = k0 * dfdu;
209
for (uint n = 0; n < method.nsize(); n++)
211
// Iterate over quadrature points
213
for (uint m = 0; m < method.qsize(); m++)
215
const real tau = (a0 + k0*method.qpoint(m) - a1) / k1;
216
const real tmp1 = method.nweight(n, m);
217
dolfin_assert(tau >= -DOLFIN_EPS);
218
dolfin_assert(tau <= 1.0 + DOLFIN_EPS);
220
// Add dependency to dof of initial value if any
221
const int ep = ts.ee[e1];
224
const real x0 = x(ep * method.nsize() + method.nsize() - 1);
225
sum += tmp1 * method.eval(0, tau) * x0;
228
// Iterate over dofs of other element and add dependencies
229
for (uint l = 0; l < method.nsize(); l++)
230
sum += tmp1 * method.eval(l + 1, tau) * x(j1 + l);
234
y(j0 + n) -= tmp0 * sum;
239
// At this point, we have added dependencies to the predecessor,
240
// to dofs in the same sub slab and to components with larger time
241
// steps. It remains to add dependencies to components with
242
// smaller time steps. We need to do this by iterating over
243
// quadrature points, since this is the order in which the
244
// dependencies are stored.
246
// Get first dependency to components with smaller time steps for element
249
// Compute number of such dependencies for each nodal point
250
const uint end = ( e0 < (ts.ne - 1) ? ts.ed[e0 + 1] : ts.nd );
251
const uint ndep = (end - d) / method.nsize();
252
dolfin_assert(ndep * method.nsize() == (end - d));
254
// Iterate over quadrature points of current element
255
for (uint m = 1; m < method.qsize(); m++)
257
// Compute quadrature point
258
const real t = a0 + k0*method.qpoint(m);
260
// Iterate over dependencies
261
for (uint dep = 0; dep < ndep; dep++)
264
const uint e1 = ts.de[d++];
265
const uint j1 = e1 * method.nsize();
266
const uint s1 = ts.es[e1];
267
//const uint i1 = ts.ei[e1];
268
const real a1 = ts.sa[s1];
269
const real b1 = ts.sb[s1];
270
const real k1 = b1 - a1;
271
const real tau = (t - a1) / k1;
273
// We don't know how to index Jvalues here and want to avoid
274
// searching, but we were clever enough to pick out the value
275
// before when we had the chance... :-)
276
const real dfdu = Jlookup[dep];
277
//message("Looks like df_%d/du_%d = %f", i0, i1, dfdu);
279
// Iterate over quadrature points of other element
280
const real tmp0 = k0 * dfdu;
281
for (uint l = 0; l < method.qsize(); l++)
283
real tmp1 = tmp0 * method.eval(l, tau);
286
const int ep = ts.ee[e1];
289
// Iterate over dofs of current element
290
tmp1 *= x(ep*method.nsize() + method.nsize() - 1);
291
for (uint n = 0; n < method.nsize(); n++)
292
y(j0 + n) -= tmp1 * method.nweight(n, m);
297
// Iterate over dofs of current element
298
tmp1 *= x(j1 + l - 1);
299
for (uint n = 0; n < method.nsize(); n++)
300
y(j0 + n) -= tmp1 * method.nweight(n, m);
307
//-----------------------------------------------------------------------------
308
void MultiAdaptiveJacobian::dGmult(const uBlasVector& x, uBlasVector& y) const
310
// Reset current sub slab
314
for (uint i = 0; i < ts.N; i++)
317
// Iterate over all elements
318
for (uint e0 = 0; e0 < ts.ne; e0++)
320
// Cover all elements in current sub slab
321
s0 = ts.coverNext(s0, e0);
324
const uint i0 = ts.ei[e0];
325
const real a0 = ts.sa[s0];
326
const real b0 = ts.sb[s0];
327
const real k0 = b0 - a0;
328
const uint j0 = e0 * method.nsize();
330
// Add dependency on predecessor for all dofs of element
331
const int ep = ts.ee[e0];
334
const real xp = x(ep*method.nsize() + method.nsize() - 1);
335
for (uint n = 0; n < method.nsize(); n++)
342
// Iterate over dependencies for the current component
343
const Array<uint>& deps = ode.dependencies[i0];
344
for (uint pos = 0; pos < deps.size(); pos++)
347
const real dfdu = Jvalues[Jindices[i0] + pos];
349
// Skip elements which have not been covered
350
const uint i1 = deps[pos];
351
const int e1 = ts.elast[i1];
354
// Save dependency for later
355
Jlookup[Jpos++] = dfdu;
359
// Skip elements with smaller time steps
360
const uint s1 = ts.es[e1];
361
const real b1 = ts.sb[s1];
362
if ( b1 < (a0 + DOLFIN_EPS) )
364
// Save dependency for later
365
Jlookup[Jpos++] = dfdu;
369
// Get first dof for other element
370
const uint j1 = e1 * method.nsize();
372
// Use fast evaluation for elements in the same sub slab
373
if ( s0 == static_cast<int>(s1) )
375
const real tmp = k0 * dfdu;
376
for (uint n = 0; n < method.nsize(); n++)
379
for (uint m = 0; m < method.qsize(); m++)
380
sum += method.nweight(n, m) * x(j1 + m);
381
y(j0 + n) -= tmp * sum;
386
const real a1 = ts.sa[s1];
387
const real k1 = b1 - a1;
389
// Iterate over dofs of element
390
const real tmp0 = k0 * dfdu;
391
for (uint n = 0; n < method.nsize(); n++)
393
// Iterate over quadrature points
395
for (uint m = 0; m < method.qsize(); m++)
397
const real tau = (a0 + k0*method.qpoint(m) - a1) / k1;
398
const real tmp1 = method.nweight(n, m);
400
// Iterate over dofs of other element and add dependencies
401
for (uint l = 0; l < method.nsize(); l++)
402
sum += tmp1 * method.eval(l, tau) * x(j1 + l);
406
y(j0 + n) -= tmp0 * sum;
411
// At this point, we have added dependencies to the predecessor,
412
// to dofs in the same sub slab and to components with larger time
413
// steps. It remains to add dependencies to components with
414
// smaller time steps. We need to do this by iterating over
415
// quadrature points, since this is the order in which the
416
// dependencies are stored.
418
// Get first dependency to components with smaller time steps for element
421
// Compute number of such dependencies for each nodal point
422
const uint end = ( e0 < (ts.ne - 1) ? ts.ed[e0 + 1] : ts.nd );
423
const uint ndep = (end - d) / method.nsize();
424
dolfin_assert(ndep * method.nsize() == (end - d));
426
// Iterate over quadrature points of current element
427
for (uint m = 0; m < method.qsize(); m++)
429
// Compute quadrature point
430
const real t = a0 + k0*method.qpoint(m);
432
// Iterate over dependencies
433
for (uint dep = 0; dep < ndep; dep++)
436
const uint e1 = ts.de[d++];
437
const uint j1 = e1 * method.nsize();
438
const uint s1 = ts.es[e1];
439
//const uint i1 = ts.ei[e1];
440
const real a1 = ts.sa[s1];
441
const real b1 = ts.sb[s1];
442
const real k1 = b1 - a1;
443
const real tau = (t - a1) / k1;
445
// We don't know how to index Jvalues here and want to avoid
446
// searching, but we were clever enough to pick out the value
447
// before when we had the chance... :-)
448
const real dfdu = Jlookup[dep];
449
//message("Looks like df_%d/du_%d = %f", i0, i1, dfdu);
451
// Iterate over quadrature points of other element
452
const real tmp0 = k0 * dfdu;
453
for (uint l = 0; l < method.qsize(); l++)
455
real tmp1 = tmp0 * method.eval(l, tau) * x(j1 + l);
456
for (uint n = 0; n < method.nsize(); n++)
457
y(j0 + n) -= tmp1 * method.nweight(n, m);
463
//-----------------------------------------------------------------------------