155a74a43SLisandro Dalcin# Oregonator: stiff 3-variable oscillatory ODE system from chemical reactions, 255a74a43SLisandro Dalcin# problem OREGO in Hairer&Wanner volume 2 355a74a43SLisandro Dalcin# See also http://www.scholarpedia.org/article/Oregonator 455a74a43SLisandro Dalcin 5*69777137SStefano Zampiniimport sys 6*69777137SStefano Zampiniimport petsc4py 7*69777137SStefano Zampini 855a74a43SLisandro Dalcinpetsc4py.init(sys.argv) 955a74a43SLisandro Dalcin 1055a74a43SLisandro Dalcinfrom petsc4py import PETSc 1155a74a43SLisandro Dalcin 12*69777137SStefano Zampini 13*69777137SStefano Zampiniclass Orego: 1455a74a43SLisandro Dalcin n = 3 1555a74a43SLisandro Dalcin comm = PETSc.COMM_SELF 16*69777137SStefano Zampini 1755a74a43SLisandro Dalcin def evalSolution(self, t, x): 18*69777137SStefano Zampini if t != 0.0: 19*69777137SStefano Zampini raise ValueError('Only for t=0') 2055a74a43SLisandro Dalcin x.setArray([1, 2, 3]) 21*69777137SStefano Zampini 2255a74a43SLisandro Dalcin def evalFunction(self, ts, t, x, xdot, f): 23*69777137SStefano Zampini f.setArray( 24*69777137SStefano Zampini [ 25*69777137SStefano Zampini xdot[0] - 77.27 * (x[1] + x[0] * (1 - 8.375e-6 * x[0] - x[1])), 2655a74a43SLisandro Dalcin xdot[1] - 1 / 77.27 * (x[2] - (1 + x[0]) * x[1]), 27*69777137SStefano Zampini xdot[2] - 0.161 * (x[0] - x[2]), 28*69777137SStefano Zampini ] 29*69777137SStefano Zampini ) 30*69777137SStefano Zampini 3155a74a43SLisandro Dalcin def evalJacobian(self, ts, t, x, xdot, a, A, B): 32*69777137SStefano Zampini B[:, :] = [ 33*69777137SStefano Zampini [ 34*69777137SStefano Zampini a - 77.27 * ((1 - 8.375e-6 * x[0] - x[1]) - 8.375e-6 * x[0]), 35*69777137SStefano Zampini -77.27 * (1 - x[0]), 36*69777137SStefano Zampini 0, 37*69777137SStefano Zampini ], 3855a74a43SLisandro Dalcin [1 / 77.27 * x[1], a + 1 / 77.27 * (1 + x[0]), -1 / 77.27], 39*69777137SStefano Zampini [-0.161, 0, a + 0.161], 40*69777137SStefano Zampini ] 4155a74a43SLisandro Dalcin B.assemble() 42*69777137SStefano Zampini if A != B: 43*69777137SStefano Zampini A.assemble() 44*69777137SStefano Zampini 4555a74a43SLisandro Dalcin 4655a74a43SLisandro DalcinOptDB = PETSc.Options() 4755a74a43SLisandro Dalcinode = Orego() 4855a74a43SLisandro Dalcin 4955a74a43SLisandro DalcinJ = PETSc.Mat().createDense([ode.n, ode.n], comm=ode.comm) 5055a74a43SLisandro DalcinJ.setUp() 5155a74a43SLisandro Dalcinx = PETSc.Vec().createSeq(ode.n, comm=ode.comm) 5255a74a43SLisandro Dalcinf = x.duplicate() 5355a74a43SLisandro Dalcin 5455a74a43SLisandro Dalcints = PETSc.TS().create(comm=ode.comm) 5555a74a43SLisandro Dalcints.setType(ts.Type.ROSW) # Rosenbrock-W. ARKIMEX is a nonlinearly implicit alternative. 5655a74a43SLisandro Dalcin 5755a74a43SLisandro Dalcints.setIFunction(ode.evalFunction, f) 5855a74a43SLisandro Dalcints.setIJacobian(ode.evalJacobian, J) 5955a74a43SLisandro Dalcin 6055a74a43SLisandro Dalcinhistory = [] 61*69777137SStefano Zampini 62*69777137SStefano Zampini 6355a74a43SLisandro Dalcindef monitor(ts, i, t, x): 6455a74a43SLisandro Dalcin xx = x[:].tolist() 6555a74a43SLisandro Dalcin history.append((i, t, xx)) 66*69777137SStefano Zampini 67*69777137SStefano Zampini 6855a74a43SLisandro Dalcints.setMonitor(monitor) 6955a74a43SLisandro Dalcin 7055a74a43SLisandro Dalcints.setTime(0.0) 7155a74a43SLisandro Dalcints.setTimeStep(0.1) 7255a74a43SLisandro Dalcints.setMaxTime(360) 7355a74a43SLisandro Dalcints.setMaxSteps(2000) 7455a74a43SLisandro Dalcints.setExactFinalTime(PETSc.TS.ExactFinalTime.INTERPOLATE) 75*69777137SStefano Zampinits.setMaxSNESFailures( 76*69777137SStefano Zampini -1 77*69777137SStefano Zampini) # allow an unlimited number of failures (step will be rejected and retried) 7855a74a43SLisandro Dalcin 7955a74a43SLisandro Dalcin# Set a different tolerance on each variable. Can use a scalar or a vector for either or both atol and rtol. 8055a74a43SLisandro Dalcinvatol = x.duplicate(array=[1e-2, 1e-1, 1e-4]) 81*69777137SStefano Zampinits.setTolerances( 82*69777137SStefano Zampini atol=vatol, rtol=1e-3 83*69777137SStefano Zampini) # adaptive controller attempts to match this tolerance 8455a74a43SLisandro Dalcin 8555a74a43SLisandro Dalcinsnes = ts.getSNES() # Nonlinear solver 86*69777137SStefano Zampinisnes.setTolerances( 87*69777137SStefano Zampini max_it=10 88*69777137SStefano Zampini) # Stop nonlinear solve after 10 iterations (TS will retry with shorter step) 8955a74a43SLisandro Dalcinksp = snes.getKSP() # Linear solver 9055a74a43SLisandro Dalcinksp.setType(ksp.Type.PREONLY) # Just use the preconditioner without a Krylov method 9155a74a43SLisandro Dalcinpc = ksp.getPC() # Preconditioner 9255a74a43SLisandro Dalcinpc.setType(pc.Type.LU) # Use a direct solve 9355a74a43SLisandro Dalcin 9455a74a43SLisandro Dalcints.setFromOptions() # Apply run-time options, e.g. -ts_adapt_monitor -ts_type arkimex -snes_converged_reason 9555a74a43SLisandro Dalcinode.evalSolution(0.0, x) 9655a74a43SLisandro Dalcints.solve(x) 97*69777137SStefano Zampiniprint( 98*69777137SStefano Zampini 'steps %d (%d rejected, %d SNES fails), nonlinear its %d, linear its %d' 99*69777137SStefano Zampini % ( 100*69777137SStefano Zampini ts.getStepNumber(), 101*69777137SStefano Zampini ts.getStepRejections(), 102*69777137SStefano Zampini ts.getSNESFailures(), 103*69777137SStefano Zampini ts.getSNESIterations(), 104*69777137SStefano Zampini ts.getKSPIterations(), 105*69777137SStefano Zampini ) 106*69777137SStefano Zampini) 10755a74a43SLisandro Dalcin 10855a74a43SLisandro Dalcinif OptDB.getBool('plot_history', True): 10955a74a43SLisandro Dalcin from matplotlib import pylab 11055a74a43SLisandro Dalcin from matplotlib import rc 11155a74a43SLisandro Dalcin import numpy as np 112*69777137SStefano Zampini 11355a74a43SLisandro Dalcin ii = np.asarray([v[0] for v in history]) 11455a74a43SLisandro Dalcin tt = np.asarray([v[1] for v in history]) 11555a74a43SLisandro Dalcin xx = np.asarray([v[2] for v in history]) 11655a74a43SLisandro Dalcin 11755a74a43SLisandro Dalcin rc('text', usetex=True) 11855a74a43SLisandro Dalcin pylab.suptitle('Oregonator: TS \\texttt{%s}' % ts.getType()) 11955a74a43SLisandro Dalcin pylab.subplot(2, 2, 1) 12055a74a43SLisandro Dalcin pylab.subplots_adjust(wspace=0.3) 121*69777137SStefano Zampini pylab.semilogy( 122*69777137SStefano Zampini ii[:-1], 123*69777137SStefano Zampini np.diff(tt), 124*69777137SStefano Zampini ) 12555a74a43SLisandro Dalcin pylab.xlabel('step number') 12655a74a43SLisandro Dalcin pylab.ylabel('timestep') 12755a74a43SLisandro Dalcin 128*69777137SStefano Zampini for i in range(3): 12955a74a43SLisandro Dalcin pylab.subplot(2, 2, i + 2) 130*69777137SStefano Zampini pylab.semilogy(tt, xx[:, i], 'rgb'[i]) 13155a74a43SLisandro Dalcin pylab.xlabel('time') 13255a74a43SLisandro Dalcin pylab.ylabel('$x_%d$' % i) 13355a74a43SLisandro Dalcin 13455a74a43SLisandro Dalcin # pylab.savefig('orego-history.png') 13555a74a43SLisandro Dalcin pylab.show() 136