xref: /petsc/src/binding/petsc4py/demo/legacy/ode/orego.py (revision 55a74a43bb44613d95e937906bec3b8c3581b432)
1*55a74a43SLisandro Dalcin# Oregonator: stiff 3-variable oscillatory ODE system from chemical reactions,
2*55a74a43SLisandro Dalcin# problem OREGO in Hairer&Wanner volume 2
3*55a74a43SLisandro Dalcin# See also http://www.scholarpedia.org/article/Oregonator
4*55a74a43SLisandro Dalcin
5*55a74a43SLisandro Dalcinimport sys, petsc4py
6*55a74a43SLisandro Dalcinpetsc4py.init(sys.argv)
7*55a74a43SLisandro Dalcin
8*55a74a43SLisandro Dalcinfrom petsc4py import PETSc
9*55a74a43SLisandro Dalcin
10*55a74a43SLisandro Dalcinclass Orego(object):
11*55a74a43SLisandro Dalcin    n = 3
12*55a74a43SLisandro Dalcin    comm = PETSc.COMM_SELF
13*55a74a43SLisandro Dalcin    def evalSolution(self, t, x):
14*55a74a43SLisandro Dalcin        assert t == 0.0, "only for t=0.0"
15*55a74a43SLisandro Dalcin        x.setArray([1, 2, 3])
16*55a74a43SLisandro Dalcin    def evalFunction(self, ts, t, x, xdot, f):
17*55a74a43SLisandro Dalcin        f.setArray([xdot[0] - 77.27*(x[1] + x[0]*(1 - 8.375e-6*x[0] - x[1])),
18*55a74a43SLisandro Dalcin                    xdot[1] - 1/77.27*(x[2] - (1 + x[0])*x[1]),
19*55a74a43SLisandro Dalcin                    xdot[2] - 0.161*(x[0] - x[2])])
20*55a74a43SLisandro Dalcin    def evalJacobian(self, ts, t, x, xdot, a, A, B):
21*55a74a43SLisandro Dalcin        B[:,:] = [[a - 77.27*((1 - 8.375e-6*x[0] - x[1]) - 8.375e-6*x[0]),   -77.27*(1 - x[0]),               0],
22*55a74a43SLisandro Dalcin                  [1/77.27*x[1],                                             a + 1/77.27*(1 + x[0]),   -1/77.27],
23*55a74a43SLisandro Dalcin                  [-0.161,                                                           0,               a + 0.161]]
24*55a74a43SLisandro Dalcin        B.assemble()
25*55a74a43SLisandro Dalcin        if A != B: A.assemble()
26*55a74a43SLisandro Dalcin        return True # same nonzero pattern
27*55a74a43SLisandro Dalcin
28*55a74a43SLisandro DalcinOptDB = PETSc.Options()
29*55a74a43SLisandro Dalcinode = Orego()
30*55a74a43SLisandro Dalcin
31*55a74a43SLisandro DalcinJ = PETSc.Mat().createDense([ode.n, ode.n], comm=ode.comm)
32*55a74a43SLisandro DalcinJ.setUp()
33*55a74a43SLisandro Dalcinx = PETSc.Vec().createSeq(ode.n, comm=ode.comm)
34*55a74a43SLisandro Dalcinf = x.duplicate()
35*55a74a43SLisandro Dalcin
36*55a74a43SLisandro Dalcints = PETSc.TS().create(comm=ode.comm)
37*55a74a43SLisandro Dalcints.setType(ts.Type.ROSW)        # Rosenbrock-W. ARKIMEX is a nonlinearly implicit alternative.
38*55a74a43SLisandro Dalcin
39*55a74a43SLisandro Dalcints.setIFunction(ode.evalFunction, f)
40*55a74a43SLisandro Dalcints.setIJacobian(ode.evalJacobian, J)
41*55a74a43SLisandro Dalcin
42*55a74a43SLisandro Dalcinhistory = []
43*55a74a43SLisandro Dalcindef monitor(ts, i, t, x):
44*55a74a43SLisandro Dalcin    xx = x[:].tolist()
45*55a74a43SLisandro Dalcin    history.append((i, t, xx))
46*55a74a43SLisandro Dalcints.setMonitor(monitor)
47*55a74a43SLisandro Dalcin
48*55a74a43SLisandro Dalcints.setTime(0.0)
49*55a74a43SLisandro Dalcints.setTimeStep(0.1)
50*55a74a43SLisandro Dalcints.setMaxTime(360)
51*55a74a43SLisandro Dalcints.setMaxSteps(2000)
52*55a74a43SLisandro Dalcints.setExactFinalTime(PETSc.TS.ExactFinalTime.INTERPOLATE)
53*55a74a43SLisandro Dalcints.setMaxSNESFailures(-1)       # allow an unlimited number of failures (step will be rejected and retried)
54*55a74a43SLisandro Dalcin
55*55a74a43SLisandro Dalcin# Set a different tolerance on each variable. Can use a scalar or a vector for either or both atol and rtol.
56*55a74a43SLisandro Dalcinvatol = x.duplicate(array=[1e-2, 1e-1, 1e-4])
57*55a74a43SLisandro Dalcints.setTolerances(atol=vatol,rtol=1e-3) # adaptive controller attempts to match this tolerance
58*55a74a43SLisandro Dalcin
59*55a74a43SLisandro Dalcinsnes = ts.getSNES()             # Nonlinear solver
60*55a74a43SLisandro Dalcinsnes.setTolerances(max_it=10)   # Stop nonlinear solve after 10 iterations (TS will retry with shorter step)
61*55a74a43SLisandro Dalcinksp = snes.getKSP()             # Linear solver
62*55a74a43SLisandro Dalcinksp.setType(ksp.Type.PREONLY)   # Just use the preconditioner without a Krylov method
63*55a74a43SLisandro Dalcinpc = ksp.getPC()                # Preconditioner
64*55a74a43SLisandro Dalcinpc.setType(pc.Type.LU)          # Use a direct solve
65*55a74a43SLisandro Dalcin
66*55a74a43SLisandro Dalcints.setFromOptions()             # Apply run-time options, e.g. -ts_adapt_monitor -ts_type arkimex -snes_converged_reason
67*55a74a43SLisandro Dalcinode.evalSolution(0.0, x)
68*55a74a43SLisandro Dalcints.solve(x)
69*55a74a43SLisandro Dalcinprint('steps %d (%d rejected, %d SNES fails), nonlinear its %d, linear its %d'
70*55a74a43SLisandro Dalcin      % (ts.getStepNumber(), ts.getStepRejections(), ts.getSNESFailures(),
71*55a74a43SLisandro Dalcin         ts.getSNESIterations(), ts.getKSPIterations()))
72*55a74a43SLisandro Dalcin
73*55a74a43SLisandro Dalcinif OptDB.getBool('plot_history', True):
74*55a74a43SLisandro Dalcin    try:
75*55a74a43SLisandro Dalcin        from matplotlib import pylab
76*55a74a43SLisandro Dalcin        from matplotlib import rc
77*55a74a43SLisandro Dalcin    except ImportError:
78*55a74a43SLisandro Dalcin        print("matplotlib not available")
79*55a74a43SLisandro Dalcin        raise SystemExit
80*55a74a43SLisandro Dalcin
81*55a74a43SLisandro Dalcin    import numpy as np
82*55a74a43SLisandro Dalcin    ii = np.asarray([v[0] for v in history])
83*55a74a43SLisandro Dalcin    tt = np.asarray([v[1] for v in history])
84*55a74a43SLisandro Dalcin    xx = np.asarray([v[2] for v in history])
85*55a74a43SLisandro Dalcin
86*55a74a43SLisandro Dalcin    rc('text', usetex=True)
87*55a74a43SLisandro Dalcin    pylab.suptitle('Oregonator: TS \\texttt{%s}' % ts.getType())
88*55a74a43SLisandro Dalcin    pylab.subplot(2,2,1)
89*55a74a43SLisandro Dalcin    pylab.subplots_adjust(wspace=0.3)
90*55a74a43SLisandro Dalcin    pylab.semilogy(ii[:-1], np.diff(tt), )
91*55a74a43SLisandro Dalcin    pylab.xlabel('step number')
92*55a74a43SLisandro Dalcin    pylab.ylabel('timestep')
93*55a74a43SLisandro Dalcin
94*55a74a43SLisandro Dalcin    for i in range(0,3):
95*55a74a43SLisandro Dalcin        pylab.subplot(2,2,i+2)
96*55a74a43SLisandro Dalcin        pylab.semilogy(tt, xx[:,i], "rgb"[i])
97*55a74a43SLisandro Dalcin        pylab.xlabel('time')
98*55a74a43SLisandro Dalcin        pylab.ylabel('$x_%d$' % i)
99*55a74a43SLisandro Dalcin
100*55a74a43SLisandro Dalcin    # pylab.savefig('orego-history.png')
101*55a74a43SLisandro Dalcin    pylab.show()
102