Coverage for pySDC / implementations / problem_classes / AllenCahn_2D_FD.py: 96%

201 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-27 07:06 +0000

1import numpy as np 

2import scipy.sparse as sp 

3from scipy.sparse.linalg import cg 

4 

5from pySDC.core.errors import ParameterError, ProblemError 

6from pySDC.core.problem import Problem, WorkCounter 

7from pySDC.helpers import problem_helper 

8from pySDC.implementations.datatype_classes.mesh import mesh, imex_mesh, comp2_mesh 

9 

10# http://www.personal.psu.edu/qud2/Res/Pre/dz09sisc.pdf 

11 

12 

13# noinspection PyUnusedLocal 

14class allencahn_fullyimplicit(Problem): 

15 r""" 

16 Example implementing the two-dimensional Allen-Cahn equation with periodic boundary conditions :math:`u \in [-1, 1]^2` 

17 

18 .. math:: 

19 \frac{\partial u}{\partial t} = \Delta u + \frac{1}{\varepsilon^2} u (1 - u^\nu) 

20 

21 for constant parameter :math:`\nu`. Initial condition are circles of the form 

22 

23 .. math:: 

24 u({\bf x}, 0) = \tanh\left(\frac{r - \sqrt{x_i^2 + y_j^2}}{\sqrt{2}\varepsilon}\right) 

25 

26 for :math:`i, j=0,..,N-1`, where :math:`N` is the number of spatial grid points. For time-stepping, the problem is 

27 treated *fully-implicitly*, i.e., the nonlinear system is solved by Newton. 

28 

29 Parameters 

30 ---------- 

31 nvars : tuple of int, optional 

32 Number of unknowns in the problem, e.g. ``nvars=(128, 128)``. 

33 nu : float, optional 

34 Problem parameter :math:`\nu`. 

35 eps : float, optional 

36 Scaling parameter :math:`\varepsilon`. 

37 newton_maxiter : int, optional 

38 Maximum number of iterations for the Newton solver. 

39 newton_tol : float, optional 

40 Tolerance for Newton's method to terminate. 

41 lin_tol : float, optional 

42 Tolerance for linear solver to terminate. 

43 lin_maxiter : int, optional 

44 Maximum number of iterations for the linear solver. 

45 radius : float, optional 

46 Radius of the circles. 

47 order : int, optional 

48 Order of the finite difference matrix. 

49 

50 Attributes 

51 ---------- 

52 A : scipy.spdiags 

53 Second-order FD discretization of the 2D laplace operator. 

54 dx : float 

55 Distance between two spatial nodes (same for both directions). 

56 xvalues : np.1darray 

57 Spatial grid points, here both dimensions have the same grid points. 

58 newton_itercount : int 

59 Number of iterations of Newton solver. 

60 lin_itercount 

61 Number of iterations of linear solver. 

62 newton_ncalls : int 

63 Number of calls of Newton solver. 

64 lin_ncalls : int 

65 Number of calls of linear solver. 

66 """ 

67 

68 dtype_u = mesh 

69 dtype_f = mesh 

70 

71 def __init__( 

72 self, 

73 nvars=(128, 128), 

74 nu=2, 

75 eps=0.04, 

76 newton_maxiter=200, 

77 newton_tol=1e-12, 

78 lin_tol=1e-8, 

79 lin_maxiter=100, 

80 inexact_linear_ratio=None, 

81 radius=0.25, 

82 order=2, 

83 ): 

84 """Initialization routine""" 

85 # we assert that nvars looks very particular here.. this will be necessary for coarsening in space later on 

86 if len(nvars) != 2: 

87 raise ProblemError('this is a 2d example, got %s' % nvars) 

88 if nvars[0] != nvars[1]: 

89 raise ProblemError('need a square domain, got %s' % nvars) 

90 if nvars[0] % 2 != 0: 

91 raise ProblemError('the setup requires nvars = 2^p per dimension') 

92 

93 # invoke super init, passing number of dofs, dtype_u and dtype_f 

94 super().__init__((nvars, None, np.dtype('float64'))) 

95 self._makeAttributeAndRegister( 

96 'nvars', 

97 'nu', 

98 'eps', 

99 'radius', 

100 'order', 

101 localVars=locals(), 

102 readOnly=True, 

103 ) 

104 self._makeAttributeAndRegister( 

105 'newton_maxiter', 

106 'newton_tol', 

107 'lin_tol', 

108 'lin_maxiter', 

109 'inexact_linear_ratio', 

110 localVars=locals(), 

111 readOnly=False, 

112 ) 

113 

114 # compute dx and get discretization matrix A 

115 self.dx = 1.0 / self.nvars[0] 

116 self.A, _ = problem_helper.get_finite_difference_matrix( 

117 derivative=2, 

118 order=self.order, 

119 stencil_type='center', 

120 dx=self.dx, 

121 size=self.nvars[0], 

122 dim=2, 

123 bc='periodic', 

124 ) 

125 self.xvalues = np.array([i * self.dx - 0.5 for i in range(self.nvars[0])]) 

126 

127 self.newton_itercount = 0 

128 self.lin_itercount = 0 

129 self.newton_ncalls = 0 

130 self.lin_ncalls = 0 

131 

132 self.work_counters['newton'] = WorkCounter() 

133 self.work_counters['rhs'] = WorkCounter() 

134 self.work_counters['linear'] = WorkCounter() 

135 

136 # noinspection PyTypeChecker 

137 def solve_system(self, rhs, factor, u0, t): 

138 """ 

139 Simple Newton solver. 

140 

141 Parameters 

142 ---------- 

143 rhs : dtype_f 

144 Right-hand side for the nonlinear system 

145 factor : float 

146 Abbrev. for the node-to-node stepsize (or any other factor required). 

147 u0 : dtype_u 

148 Initial guess for the iterative solver. 

149 t : float 

150 Current time (required here for the BC). 

151 

152 Returns 

153 ------- 

154 me : dtype_u 

155 The solution as mesh. 

156 """ 

157 

158 u = self.dtype_u(u0).flatten() 

159 z = self.dtype_u(self.init, val=0.0).flatten() 

160 nu = self.nu 

161 eps2 = self.eps**2 

162 

163 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

164 

165 # start newton iteration 

166 n = 0 

167 res = 99 

168 while n < self.newton_maxiter: 

169 # form the function g with g(u) = 0 

170 g = u - factor * (self.A.dot(u) + 1.0 / eps2 * u * (1.0 - u**nu)) - rhs.flatten() 

171 

172 # if g is close to 0, then we are done 

173 res = np.linalg.norm(g, np.inf) 

174 

175 # do inexactness in the linear solver 

176 if self.inexact_linear_ratio: 

177 self.lin_tol = res * self.inexact_linear_ratio 

178 

179 if res < self.newton_tol: 

180 break 

181 

182 # assemble dg 

183 dg = Id - factor * (self.A + 1.0 / eps2 * sp.diags((1.0 - (nu + 1) * u**nu), offsets=0)) 

184 

185 # newton update: u1 = u0 - g/dg 

186 # u -= spsolve(dg, g) 

187 u -= cg( 

188 dg, g, x0=z, rtol=self.lin_tol, maxiter=self.lin_maxiter, atol=0, callback=self.work_counters['linear'] 

189 )[0] 

190 # increase iteration count 

191 n += 1 

192 # print(n, res) 

193 

194 self.work_counters['newton']() 

195 

196 # if n == self.newton_maxiter: 

197 # raise ProblemError('Newton did not converge after %i iterations, error is %s' % (n, res)) 

198 

199 me = self.dtype_u(self.init) 

200 me[:] = u.reshape(self.nvars) 

201 

202 self.newton_ncalls += 1 

203 self.newton_itercount += n 

204 

205 return me 

206 

207 def eval_f(self, u, t): 

208 """ 

209 Routine to evaluate the right-hand side of the problem. 

210 

211 Parameters 

212 ---------- 

213 u : dtype_u 

214 Current values of the numerical solution. 

215 t : float 

216 Current time of the numerical solution is computed (not used here). 

217 

218 Returns 

219 ------- 

220 f : dtype_f 

221 The right-hand side of the problem. 

222 """ 

223 f = self.dtype_f(self.init) 

224 v = u.flatten() 

225 f[:] = (self.A.dot(v) + 1.0 / self.eps**2 * v * (1.0 - v**self.nu)).reshape(self.nvars) 

226 

227 self.work_counters['rhs']() 

228 return f 

229 

230 def u_exact(self, t, u_init=None, t_init=None): 

231 r""" 

232 Routine to compute the exact solution at time :math:`t`. 

233 

234 Parameters 

235 ---------- 

236 t : float 

237 Time of the exact solution. 

238 

239 Returns 

240 ------- 

241 me : dtype_u 

242 The exact solution. 

243 """ 

244 me = self.dtype_u(self.init, val=0.0) 

245 if t > 0: 

246 

247 def eval_rhs(t, u): 

248 return self.eval_f(u.reshape(self.init[0]), t).flatten() 

249 

250 me[:] = self.generate_scipy_reference_solution(eval_rhs, t, u_init, t_init) 

251 

252 else: 

253 X, Y = np.meshgrid(self.xvalues, self.xvalues) 

254 r2 = X**2 + Y**2 

255 me[:] = np.tanh((self.radius - np.sqrt(r2)) / (np.sqrt(2) * self.eps)) 

256 

257 return me 

258 

259 

260# noinspection PyUnusedLocal 

261class allencahn_semiimplicit(allencahn_fullyimplicit): 

262 r""" 

263 This class implements the two-dimensional Allen-Cahn equation with periodic boundary conditions :math:`u \in [-1, 1]^2` 

264 

265 .. math:: 

266 \frac{\partial u}{\partial t} = \Delta u + \frac{1}{\varepsilon^2} u (1 - u^\nu) 

267 

268 for constant parameter :math:`\nu`. Initial condition are circles of the form 

269 

270 .. math:: 

271 u({\bf x}, 0) = \tanh\left(\frac{r - \sqrt{x_i^2 + y_j^2}}{\sqrt{2}\varepsilon}\right) 

272 

273 for :math:`i, j=0,..,N-1`, where :math:`N` is the number of spatial grid points. For time-stepping, the problem is 

274 treated in a *semi-implicit* way, i.e., the linear system containing the Laplacian is solved by the conjugate gradients 

275 method, and the system containing the rest of the right-hand side is only evaluated at each time. 

276 """ 

277 

278 dtype_f = imex_mesh 

279 

280 def eval_f(self, u, t): 

281 """ 

282 Routine to evaluate the right-hand side of the problem. 

283 

284 Parameters 

285 ---------- 

286 u : dtype_u 

287 Current values of the numerical solution. 

288 t : float 

289 Current time of the numerical solution is computed (not used here). 

290 

291 Returns 

292 ------- 

293 f : dtype_f 

294 The right-hand side of the problem. 

295 """ 

296 f = self.dtype_f(self.init) 

297 v = u.flatten() 

298 f.impl[:] = self.A.dot(v).reshape(self.nvars) 

299 f.expl[:] = (1.0 / self.eps**2 * v * (1.0 - v**self.nu)).reshape(self.nvars) 

300 

301 self.work_counters['rhs']() 

302 return f 

303 

304 def solve_system(self, rhs, factor, u0, t): 

305 r""" 

306 Simple linear solver for :math:`(I-factor\cdot A)\vec{u}=\vec{rhs}`. 

307 

308 Parameters 

309 ---------- 

310 rhs : dtype_f 

311 Right-hand side for the linear system. 

312 factor : float 

313 Abbrev. for the local stepsize (or any other factor required). 

314 u0 : dtype_u 

315 Initial guess for the iterative solver. 

316 t : float 

317 Current time (e.g. for time-dependent BCs). 

318 

319 Returns 

320 ------- 

321 me : dtype_u 

322 The solution as mesh. 

323 """ 

324 

325 class context: 

326 num_iter = 0 

327 

328 def callback(xk): 

329 context.num_iter += 1 

330 self.work_counters['linear']() 

331 return context.num_iter 

332 

333 me = self.dtype_u(self.init) 

334 

335 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

336 

337 me[:] = cg( 

338 Id - factor * self.A, 

339 rhs.flatten(), 

340 x0=u0.flatten(), 

341 rtol=self.lin_tol, 

342 maxiter=self.lin_maxiter, 

343 atol=0, 

344 callback=callback, 

345 )[0].reshape(self.nvars) 

346 

347 self.lin_ncalls += 1 

348 self.lin_itercount += context.num_iter 

349 

350 return me 

351 

352 def u_exact(self, t, u_init=None, t_init=None): 

353 """ 

354 Routine to compute the exact solution at time t. 

355 

356 Parameters 

357 ---------- 

358 t : float 

359 Time of the exact solution. 

360 

361 Returns 

362 ------- 

363 me : dtype_u 

364 The exact solution. 

365 """ 

366 me = self.dtype_u(self.init, val=0.0) 

367 if t > 0: 

368 

369 def eval_rhs(t, u): 

370 f = self.eval_f(u.reshape(self.init[0]), t) 

371 return (f.impl + f.expl).flatten() 

372 

373 me[:] = self.generate_scipy_reference_solution(eval_rhs, t, u_init, t_init) 

374 else: 

375 me[:] = super().u_exact(t, u_init, t_init) 

376 return me 

377 

378 

379# noinspection PyUnusedLocal 

380class allencahn_semiimplicit_v2(allencahn_fullyimplicit): 

381 r""" 

382 This class implements the two-dimensional Allen-Cahn (AC) equation with periodic boundary conditions :math:`u \in [-1, 1]^2` 

383 

384 .. math:: 

385 \frac{\partial u}{\partial t} = \Delta u + \frac{1}{\varepsilon^2} u (1 - u^\nu) 

386 

387 for constant parameter :math:`\nu`. Initial condition are circles of the form 

388 

389 .. math:: 

390 u({\bf x}, 0) = \tanh\left(\frac{r - \sqrt{x_i^2 + y_j^2}}{\sqrt{2}\varepsilon}\right) 

391 

392 for :math:`i, j=0,..,N-1`, where :math:`N` is the number of spatial grid points. For time-stepping, a special AC-splitting 

393 is used to get a *semi-implicit* treatment of the problem: The term :math:`\Delta u - \frac{1}{\varepsilon^2} u^{\nu + 1}` 

394 is handled implicitly and the nonlinear system including this part will be solved by Newton. :math:`\frac{1}{\varepsilon^2} u` 

395 is only evaluated at each time. 

396 """ 

397 

398 dtype_f = imex_mesh 

399 

400 def eval_f(self, u, t): 

401 """ 

402 Routine to evaluate the right-hand side of the problem. 

403 

404 Parameters 

405 ---------- 

406 u : dtype_u 

407 Current values of the numerical solution. 

408 t : float 

409 Current time of the numerical solution is computed. 

410 

411 Returns 

412 ------- 

413 f : dtype_f 

414 The right-hand side of the problem. 

415 """ 

416 f = self.dtype_f(self.init) 

417 v = u.flatten() 

418 f.impl[:] = (self.A.dot(v) - 1.0 / self.eps**2 * v ** (self.nu + 1)).reshape(self.nvars) 

419 f.expl[:] = (1.0 / self.eps**2 * v).reshape(self.nvars) 

420 

421 return f 

422 

423 def solve_system(self, rhs, factor, u0, t): 

424 """ 

425 Simple Newton solver. 

426 

427 Parameters 

428 ---------- 

429 rhs : dtype_f 

430 Right-hand side for the nonlinear system. 

431 factor : float 

432 Abbrev. for the node-to-node stepsize (or any other factor required). 

433 u0 : dtype_u 

434 Initial guess for the iterative solver. 

435 t : float 

436 Current time (required here for the BC). 

437 

438 Returns 

439 ------- 

440 me : dtype_u 

441 The solution as mesh. 

442 """ 

443 

444 u = self.dtype_u(u0).flatten() 

445 z = self.dtype_u(self.init, val=0.0).flatten() 

446 nu = self.nu 

447 eps2 = self.eps**2 

448 

449 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

450 

451 # start newton iteration 

452 n = 0 

453 res = 99 

454 while n < self.newton_maxiter: 

455 # form the function g with g(u) = 0 

456 g = u - factor * (self.A.dot(u) - 1.0 / eps2 * u ** (nu + 1)) - rhs.flatten() 

457 

458 # if g is close to 0, then we are done 

459 # res = np.linalg.norm(g, np.inf) 

460 res = np.linalg.norm(g, np.inf) 

461 

462 if res < self.newton_tol: 

463 break 

464 

465 # assemble dg 

466 dg = Id - factor * (self.A - 1.0 / eps2 * sp.diags(((nu + 1) * u**nu), offsets=0)) 

467 

468 # newton update: u1 = u0 - g/dg 

469 # u -= spsolve(dg, g) 

470 u -= cg(dg, g, x0=z, rtol=self.lin_tol, atol=0)[0] 

471 # increase iteration count 

472 n += 1 

473 # print(n, res) 

474 

475 # if n == self.newton_maxiter: 

476 # raise ProblemError('Newton did not converge after %i iterations, error is %s' % (n, res)) 

477 

478 me = self.dtype_u(self.init) 

479 me[:] = u.reshape(self.nvars) 

480 

481 self.newton_ncalls += 1 

482 self.newton_itercount += n 

483 

484 return me 

485 

486 

487# noinspection PyUnusedLocal 

488class allencahn_multiimplicit(allencahn_fullyimplicit): 

489 r""" 

490 Example implementing the two-dimensional Allen-Cahn equation with periodic boundary conditions :math:`u \in [-1, 1]^2` 

491 

492 .. math:: 

493 \frac{\partial u}{\partial t} = \Delta u + \frac{1}{\varepsilon^2} u (1 - u^\nu) 

494 

495 for constant parameter :math:`\nu`. Initial condition are circles of the form 

496 

497 .. math:: 

498 u({\bf x}, 0) = \tanh\left(\frac{r - \sqrt{x_i^2 + y_j^2}}{\sqrt{2}\varepsilon}\right) 

499 

500 for :math:`i, j=0,..,N-1`, where :math:`N` is the number of spatial grid points. For time-stepping, the problem is 

501 treated in *multi-implicit* fashion, i.e., the linear system containing the Laplacian is solved by the conjugate gradients 

502 method, and the system containing the rest of the right-hand side will be solved by Newton's method. 

503 """ 

504 

505 dtype_f = comp2_mesh 

506 

507 def eval_f(self, u, t): 

508 """ 

509 Routine to evaluate the right-hand side of the problem. 

510 

511 Parameters 

512 ---------- 

513 u : dtype_u 

514 Current values of the numerical solution. 

515 t : float 

516 Current time of the numerical solution is computed. 

517 

518 Returns 

519 ------- 

520 f : dtype_f 

521 The right-hand side of the problem. 

522 """ 

523 f = self.dtype_f(self.init) 

524 v = u.flatten() 

525 f.comp1[:] = self.A.dot(v).reshape(self.nvars) 

526 f.comp2[:] = (1.0 / self.eps**2 * v * (1.0 - v**self.nu)).reshape(self.nvars) 

527 

528 return f 

529 

530 def solve_system_1(self, rhs, factor, u0, t): 

531 r""" 

532 Simple linear solver for :math:`(I-factor\cdot A)\vec{u}=\vec{rhs}`. 

533 

534 Parameters 

535 ---------- 

536 rhs : dtype_f 

537 Right-hand side for the linear system. 

538 factor : float 

539 Abbrev. for the local stepsize (or any other factor required). 

540 u0 : dtype_u 

541 Initial guess for the iterative solver. 

542 t : float 

543 Current time (e.g. for time-dependent BCs). 

544 

545 Returns 

546 ------- 

547 me : dtype_u 

548 The solution as mesh. 

549 """ 

550 

551 class context: 

552 num_iter = 0 

553 

554 def callback(xk): 

555 context.num_iter += 1 

556 return context.num_iter 

557 

558 me = self.dtype_u(self.init) 

559 

560 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

561 

562 me[:] = cg( 

563 Id - factor * self.A, 

564 rhs.flatten(), 

565 x0=u0.flatten(), 

566 rtol=self.lin_tol, 

567 maxiter=self.lin_maxiter, 

568 atol=0, 

569 callback=callback, 

570 )[0].reshape(self.nvars) 

571 

572 self.lin_ncalls += 1 

573 self.lin_itercount += context.num_iter 

574 

575 return me 

576 

577 def solve_system_2(self, rhs, factor, u0, t): 

578 """ 

579 Simple Newton solver. 

580 

581 Parameters 

582 ---------- 

583 rhs : dtype_f 

584 Right-hand side for the nonlinear system. 

585 factor : float 

586 Abbrev. for the node-to-node stepsize (or any other factor required). 

587 u0 : dtype_u 

588 Initial guess for the iterative solver. 

589 t : float 

590 Current time (required here for the BC). 

591 

592 Returns 

593 ------- 

594 me : dtype_u 

595 The solution as mesh. 

596 """ 

597 

598 u = self.dtype_u(u0).flatten() 

599 z = self.dtype_u(self.init, val=0.0).flatten() 

600 nu = self.nu 

601 eps2 = self.eps**2 

602 

603 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

604 

605 # start newton iteration 

606 n = 0 

607 res = 99 

608 while n < self.newton_maxiter: 

609 # form the function g with g(u) = 0 

610 g = u - factor * (1.0 / eps2 * u * (1.0 - u**nu)) - rhs.flatten() 

611 

612 # if g is close to 0, then we are done 

613 res = np.linalg.norm(g, np.inf) 

614 

615 if res < self.newton_tol: 

616 break 

617 

618 # assemble dg 

619 dg = Id - factor * (1.0 / eps2 * sp.diags((1.0 - (nu + 1) * u**nu), offsets=0)) 

620 

621 # newton update: u1 = u0 - g/dg 

622 # u -= spsolve(dg, g) 

623 u -= cg(dg, g, x0=z, rtol=self.lin_tol, atol=0)[0] 

624 # increase iteration count 

625 n += 1 

626 # print(n, res) 

627 

628 # if n == self.newton_maxiter: 

629 # raise ProblemError('Newton did not converge after %i iterations, error is %s' % (n, res)) 

630 

631 me = self.dtype_u(self.init) 

632 me[:] = u.reshape(self.nvars) 

633 

634 self.newton_ncalls += 1 

635 self.newton_itercount += n 

636 

637 return me 

638 

639 

640# noinspection PyUnusedLocal 

641class allencahn_multiimplicit_v2(allencahn_fullyimplicit): 

642 r""" 

643 This class implements the two-dimensional Allen-Cahn (AC) equation with periodic boundary conditions :math:`u \in [-1, 1]^2` 

644 

645 .. math:: 

646 \frac{\partial u}{\partial t} = \Delta u + \frac{1}{\varepsilon^2} u (1 - u^\nu) 

647 

648 for constant parameter :math:`\nu`. The initial condition has the form of circles 

649 

650 .. math:: 

651 u({\bf x}, 0) = \tanh\left(\frac{r - \sqrt{x_i^2 + y_j^2}}{\sqrt{2}\varepsilon}\right) 

652 

653 for :math:`i, j=0,..,N-1`, where :math:`N` is the number of spatial grid points. For time-stepping, a special AC-splitting 

654 is used here to get another kind of *semi-implicit* treatment of the problem: The term :math:`\Delta u - \frac{1}{\varepsilon^2} u^{\nu + 1}` 

655 is handled implicitly and the nonlinear system including this part will be solved by Newton. :math:`\frac{1}{\varepsilon^2} u` 

656 is solved by a linear solver provided by a ``SciPy`` routine. 

657 """ 

658 

659 dtype_f = comp2_mesh 

660 

661 def eval_f(self, u, t): 

662 """ 

663 Routine to evaluate the right-hand side of the problem. 

664 

665 Parameters 

666 ---------- 

667 u : dtype_u 

668 Current values of the numerical solution. 

669 t : float 

670 Current time of the numerical solution is computed. 

671 

672 Returns 

673 ------- 

674 f : dtype_f 

675 The right-hand side of the problem. 

676 """ 

677 f = self.dtype_f(self.init) 

678 v = u.flatten() 

679 f.comp1[:] = (self.A.dot(v) - 1.0 / self.eps**2 * v ** (self.nu + 1)).reshape(self.nvars) 

680 f.comp2[:] = (1.0 / self.eps**2 * v).reshape(self.nvars) 

681 

682 return f 

683 

684 def solve_system_1(self, rhs, factor, u0, t): 

685 """ 

686 Simple Newton solver. 

687 

688 Parameters 

689 ---------- 

690 rhs : dtype_f 

691 Right-hand side for the nonlinear system. 

692 factor : float 

693 Abbrev. for the node-to-node stepsize (or any other factor required). 

694 u0 : dtype_u 

695 Initial guess for the iterative solver. 

696 t : float 

697 Current time (required here for the BC). 

698 

699 Returns 

700 ------ 

701 me : dtype_u 

702 The solution as mesh. 

703 """ 

704 

705 u = self.dtype_u(u0).flatten() 

706 z = self.dtype_u(self.init, val=0.0).flatten() 

707 nu = self.nu 

708 eps2 = self.eps**2 

709 

710 Id = sp.eye(self.nvars[0] * self.nvars[1]) 

711 

712 # start newton iteration 

713 n = 0 

714 res = 99 

715 while n < self.newton_maxiter: 

716 # form the function g with g(u) = 0 

717 g = u - factor * (self.A.dot(u) - 1.0 / eps2 * u ** (nu + 1)) - rhs.flatten() 

718 

719 # if g is close to 0, then we are done 

720 res = np.linalg.norm(g, np.inf) 

721 

722 if res < self.newton_tol: 

723 break 

724 

725 # assemble dg 

726 dg = Id - factor * (self.A - 1.0 / eps2 * sp.diags(((nu + 1) * u**nu), offsets=0)) 

727 

728 # newton update: u1 = u0 - g/dg 

729 # u -= spsolve(dg, g) 

730 u -= cg( 

731 dg, 

732 g, 

733 x0=z, 

734 rtol=self.lin_tol, 

735 atol=0, 

736 )[0] 

737 # increase iteration count 

738 n += 1 

739 # print(n, res) 

740 

741 # if n == self.newton_maxiter: 

742 # raise ProblemError('Newton did not converge after %i iterations, error is %s' % (n, res)) 

743 

744 me = self.dtype_u(self.init) 

745 me[:] = u.reshape(self.nvars) 

746 

747 self.newton_ncalls += 1 

748 self.newton_itercount += n 

749 

750 return me 

751 

752 def solve_system_2(self, rhs, factor, u0, t): 

753 r""" 

754 Simple linear solver for :math:`(I-factor\cdot A)\vec{u}=\vec{rhs}`. 

755 

756 Parameters 

757 ---------- 

758 rhs : dtype_f 

759 Right-hand side for the linear system. 

760 factor : float 

761 Abbrev. for the local stepsize (or any other factor required). 

762 u0 : dtype_u 

763 Initial guess for the iterative solver. 

764 t : float 

765 Current time (e.g. for time-dependent BCs). 

766 

767 Returns 

768 ------- 

769 me : dtype_u 

770 The solution as mesh. 

771 """ 

772 

773 me = self.dtype_u(self.init) 

774 

775 me[:] = (1.0 / (1.0 - factor * 1.0 / self.eps**2) * rhs).reshape(self.nvars) 

776 return me