xref: /petsc/src/binding/petsc4py/demo/legacy/ode/vanderpol.py (revision 55a74a43bb44613d95e937906bec3b8c3581b432)
1*55a74a43SLisandro Dalcin# Testing TSAdjoint and matrix-free Jacobian
2*55a74a43SLisandro Dalcin# Basic usage:
3*55a74a43SLisandro Dalcin#     python vanderpol.py
4*55a74a43SLisandro Dalcin# Test implicit methods using implicit form:
5*55a74a43SLisandro Dalcin#     python -implicitform
6*55a74a43SLisandro Dalcin# Test explicit methods:
7*55a74a43SLisandro Dalcin#     python -implicitform 0
8*55a74a43SLisandro Dalcin# Test IMEX methods:
9*55a74a43SLisandro Dalcin#     python -imexform
10*55a74a43SLisandro Dalcin# Matrix-free implementations can be enabled with an additional option -mf
11*55a74a43SLisandro Dalcin
12*55a74a43SLisandro Dalcinimport sys, petsc4py
13*55a74a43SLisandro Dalcinpetsc4py.init(sys.argv)
14*55a74a43SLisandro Dalcin
15*55a74a43SLisandro Dalcinfrom petsc4py import PETSc
16*55a74a43SLisandro Dalcin
17*55a74a43SLisandro Dalcinclass VDP(object):
18*55a74a43SLisandro Dalcin    n = 2
19*55a74a43SLisandro Dalcin    comm = PETSc.COMM_SELF
20*55a74a43SLisandro Dalcin    def __init__(self, mu_=1.0e3, mf_=False, imex_=False):
21*55a74a43SLisandro Dalcin        self.mu_ = mu_
22*55a74a43SLisandro Dalcin        self.mf_ = mf_
23*55a74a43SLisandro Dalcin        self.imex_ = imex_
24*55a74a43SLisandro Dalcin        if self.mf_:
25*55a74a43SLisandro Dalcin            self.Jim_ = PETSc.Mat().createDense([self.n,self.n], comm=self.comm)
26*55a74a43SLisandro Dalcin            self.Jim_.setUp()
27*55a74a43SLisandro Dalcin            self.JimP_ = PETSc.Mat().createDense([self.n,1], comm=self.comm)
28*55a74a43SLisandro Dalcin            self.JimP_.setUp()
29*55a74a43SLisandro Dalcin            self.Jex_ = PETSc.Mat().createDense([self.n,self.n], comm=self.comm)
30*55a74a43SLisandro Dalcin            self.Jex_.setUp()
31*55a74a43SLisandro Dalcin            self.JexP_ = PETSc.Mat().createDense([self.n,1], comm=self.comm)
32*55a74a43SLisandro Dalcin            self.JexP_.setUp()
33*55a74a43SLisandro Dalcin    def initialCondition(self, u):
34*55a74a43SLisandro Dalcin        mu = self.mu_
35*55a74a43SLisandro Dalcin        u[0] = 2.0
36*55a74a43SLisandro Dalcin        u[1] = -2.0/3.0 + 10.0/(81.0*mu) - 292.0/(2187.0*mu*mu)
37*55a74a43SLisandro Dalcin        u.assemble()
38*55a74a43SLisandro Dalcin    def evalFunction(self, ts, t, u, f):
39*55a74a43SLisandro Dalcin        mu = self.mu_
40*55a74a43SLisandro Dalcin        f[0] = u[1]
41*55a74a43SLisandro Dalcin        if self.imex_:
42*55a74a43SLisandro Dalcin            f[1] = 0.0
43*55a74a43SLisandro Dalcin        else:
44*55a74a43SLisandro Dalcin            f[1] = mu*((1.-u[0]*u[0])*u[1]-u[0])
45*55a74a43SLisandro Dalcin        f.assemble()
46*55a74a43SLisandro Dalcin    def evalJacobian(self, ts, t, u, A, B):
47*55a74a43SLisandro Dalcin        if not self.mf_:
48*55a74a43SLisandro Dalcin            J = A
49*55a74a43SLisandro Dalcin        else :
50*55a74a43SLisandro Dalcin            J = self.Jex_
51*55a74a43SLisandro Dalcin        mu = self.mu_
52*55a74a43SLisandro Dalcin        J[0,0] = 0
53*55a74a43SLisandro Dalcin        J[0,1] = 1.0
54*55a74a43SLisandro Dalcin        if self.imex_:
55*55a74a43SLisandro Dalcin            J[1,0] = 0
56*55a74a43SLisandro Dalcin            J[1,1] = 0
57*55a74a43SLisandro Dalcin        else:
58*55a74a43SLisandro Dalcin            J[1,0] = -mu*(2.0*u[1]*u[0]+1.)
59*55a74a43SLisandro Dalcin            J[1,1] = mu*(1.0-u[0]*u[0])
60*55a74a43SLisandro Dalcin        J.assemble()
61*55a74a43SLisandro Dalcin        if A != B: B.assemble()
62*55a74a43SLisandro Dalcin        return True # same nonzero pattern
63*55a74a43SLisandro Dalcin    def evalJacobianP(self, ts, t, u, C):
64*55a74a43SLisandro Dalcin        if not self.mf_:
65*55a74a43SLisandro Dalcin            Jp = C
66*55a74a43SLisandro Dalcin        else:
67*55a74a43SLisandro Dalcin            Jp = self.JexP_
68*55a74a43SLisandro Dalcin        if not self.imex_:
69*55a74a43SLisandro Dalcin            Jp[0,0] = 0
70*55a74a43SLisandro Dalcin            Jp[1,0] = (1.-u[0]*u[0])*u[1]-u[0]
71*55a74a43SLisandro Dalcin            Jp.assemble()
72*55a74a43SLisandro Dalcin        return True
73*55a74a43SLisandro Dalcin    def evalIFunction(self, ts, t, u, udot, f):
74*55a74a43SLisandro Dalcin        mu = self.mu_
75*55a74a43SLisandro Dalcin        if self.imex_:
76*55a74a43SLisandro Dalcin            f[0] = udot[0]
77*55a74a43SLisandro Dalcin        else:
78*55a74a43SLisandro Dalcin            f[0] = udot[0]-u[1]
79*55a74a43SLisandro Dalcin        f[1] = udot[1]-mu*((1.-u[0]*u[0])*u[1]-u[0])
80*55a74a43SLisandro Dalcin        f.assemble()
81*55a74a43SLisandro Dalcin    def evalIJacobian(self, ts, t, u, udot, shift, A, B):
82*55a74a43SLisandro Dalcin        if not self.mf_:
83*55a74a43SLisandro Dalcin            J = A
84*55a74a43SLisandro Dalcin        else :
85*55a74a43SLisandro Dalcin            J = self.Jim_
86*55a74a43SLisandro Dalcin        mu = self.mu_
87*55a74a43SLisandro Dalcin        if self.imex_:
88*55a74a43SLisandro Dalcin            J[0,0] = shift
89*55a74a43SLisandro Dalcin            J[0,1] = 0.0
90*55a74a43SLisandro Dalcin        else:
91*55a74a43SLisandro Dalcin            J[0,0] = shift
92*55a74a43SLisandro Dalcin            J[0,1] = -1.0
93*55a74a43SLisandro Dalcin        J[1,0] = mu*(2.0*u[1]*u[0]+1.)
94*55a74a43SLisandro Dalcin        J[1,1] = shift-mu*(1.0-u[0]*u[0])
95*55a74a43SLisandro Dalcin        J.assemble()
96*55a74a43SLisandro Dalcin        if A != B: B.assemble()
97*55a74a43SLisandro Dalcin        return True # same nonzero pattern
98*55a74a43SLisandro Dalcin    def evalIJacobianP(self, ts, t, u, udot, shift, C):
99*55a74a43SLisandro Dalcin        if not self.mf_:
100*55a74a43SLisandro Dalcin            Jp = C
101*55a74a43SLisandro Dalcin        else:
102*55a74a43SLisandro Dalcin            Jp = self.JimP_
103*55a74a43SLisandro Dalcin        Jp[0,0] = 0
104*55a74a43SLisandro Dalcin        Jp[1,0] = u[0]-(1.-u[0]*u[0])*u[1]
105*55a74a43SLisandro Dalcin        Jp.assemble()
106*55a74a43SLisandro Dalcin        return True
107*55a74a43SLisandro Dalcin
108*55a74a43SLisandro Dalcinclass JacShell:
109*55a74a43SLisandro Dalcin    def __init__(self, ode):
110*55a74a43SLisandro Dalcin        self.ode_ = ode
111*55a74a43SLisandro Dalcin    def mult(self, A, x, y):
112*55a74a43SLisandro Dalcin        "y <- A * x"
113*55a74a43SLisandro Dalcin        self.ode_.Jex_.mult(x,y)
114*55a74a43SLisandro Dalcin    def multTranspose(self, A, x, y):
115*55a74a43SLisandro Dalcin        "y <- A' * x"
116*55a74a43SLisandro Dalcin        self.ode_.Jex_.multTranspose(x, y)
117*55a74a43SLisandro Dalcin
118*55a74a43SLisandro Dalcinclass JacPShell:
119*55a74a43SLisandro Dalcin    def __init__(self, ode):
120*55a74a43SLisandro Dalcin        self.ode_ = ode
121*55a74a43SLisandro Dalcin    def multTranspose(self, A, x, y):
122*55a74a43SLisandro Dalcin        "y <- A' * x"
123*55a74a43SLisandro Dalcin        self.ode_.JexP_.multTranspose(x, y)
124*55a74a43SLisandro Dalcin
125*55a74a43SLisandro Dalcinclass IJacShell:
126*55a74a43SLisandro Dalcin    def __init__(self, ode):
127*55a74a43SLisandro Dalcin        self.ode_ = ode
128*55a74a43SLisandro Dalcin    def mult(self, A, x, y):
129*55a74a43SLisandro Dalcin        "y <- A * x"
130*55a74a43SLisandro Dalcin        self.ode_.Jim_.mult(x,y)
131*55a74a43SLisandro Dalcin    def multTranspose(self, A, x, y):
132*55a74a43SLisandro Dalcin        "y <- A' * x"
133*55a74a43SLisandro Dalcin        self.ode_.Jim_.multTranspose(x, y)
134*55a74a43SLisandro Dalcin
135*55a74a43SLisandro Dalcinclass IJacPShell:
136*55a74a43SLisandro Dalcin    def __init__(self, ode):
137*55a74a43SLisandro Dalcin        self.ode_ = ode
138*55a74a43SLisandro Dalcin    def multTranspose(self, A, x, y):
139*55a74a43SLisandro Dalcin        "y <- A' * x"
140*55a74a43SLisandro Dalcin        self.ode_.JimP_.multTranspose(x, y)
141*55a74a43SLisandro Dalcin
142*55a74a43SLisandro DalcinOptDB = PETSc.Options()
143*55a74a43SLisandro Dalcin
144*55a74a43SLisandro Dalcinmu_ = OptDB.getScalar('mu', 1.0e3)
145*55a74a43SLisandro Dalcinmf_ = OptDB.getBool('mf', False)
146*55a74a43SLisandro Dalcin
147*55a74a43SLisandro Dalcinimplicitform_ = OptDB.getBool('implicitform', False)
148*55a74a43SLisandro Dalcinimexform_ = OptDB.getBool('imexform', False)
149*55a74a43SLisandro Dalcin
150*55a74a43SLisandro Dalcinode = VDP(mu_,mf_,imexform_)
151*55a74a43SLisandro Dalcin
152*55a74a43SLisandro Dalcinif not mf_:
153*55a74a43SLisandro Dalcin    Jim = PETSc.Mat().createDense([ode.n,ode.n], comm=ode.comm)
154*55a74a43SLisandro Dalcin    Jim.setUp()
155*55a74a43SLisandro Dalcin    JimP = PETSc.Mat().createDense([ode.n,1], comm=ode.comm)
156*55a74a43SLisandro Dalcin    JimP.setUp()
157*55a74a43SLisandro Dalcin    Jex = PETSc.Mat().createDense([ode.n,ode.n], comm=ode.comm)
158*55a74a43SLisandro Dalcin    Jex.setUp()
159*55a74a43SLisandro Dalcin    JexP = PETSc.Mat().createDense([ode.n,1], comm=ode.comm)
160*55a74a43SLisandro Dalcin    JexP.setUp()
161*55a74a43SLisandro Dalcinelse:
162*55a74a43SLisandro Dalcin    Jim = PETSc.Mat().create()
163*55a74a43SLisandro Dalcin    Jim.setSizes([ode.n,ode.n])
164*55a74a43SLisandro Dalcin    Jim.setType('python')
165*55a74a43SLisandro Dalcin    shell = IJacShell(ode)
166*55a74a43SLisandro Dalcin    Jim.setPythonContext(shell)
167*55a74a43SLisandro Dalcin    Jim.setUp()
168*55a74a43SLisandro Dalcin    Jim.assemble()
169*55a74a43SLisandro Dalcin    JimP = PETSc.Mat().create()
170*55a74a43SLisandro Dalcin    JimP.setSizes([ode.n,1])
171*55a74a43SLisandro Dalcin    JimP.setType('python')
172*55a74a43SLisandro Dalcin    shell = IJacPShell(ode)
173*55a74a43SLisandro Dalcin    JimP.setPythonContext(shell)
174*55a74a43SLisandro Dalcin    JimP.setUp()
175*55a74a43SLisandro Dalcin    JimP.assemble()
176*55a74a43SLisandro Dalcin    Jex = PETSc.Mat().create()
177*55a74a43SLisandro Dalcin    Jex.setSizes([ode.n,ode.n])
178*55a74a43SLisandro Dalcin    Jex.setType('python')
179*55a74a43SLisandro Dalcin    shell = JacShell(ode)
180*55a74a43SLisandro Dalcin    Jex.setPythonContext(shell)
181*55a74a43SLisandro Dalcin    Jex.setUp()
182*55a74a43SLisandro Dalcin    Jex.assemble()
183*55a74a43SLisandro Dalcin    JexP = PETSc.Mat().create()
184*55a74a43SLisandro Dalcin    JexP.setSizes([ode.n,1])
185*55a74a43SLisandro Dalcin    JexP.setType('python')
186*55a74a43SLisandro Dalcin    shell = JacPShell(ode)
187*55a74a43SLisandro Dalcin    JexP.setPythonContext(shell)
188*55a74a43SLisandro Dalcin    JexP.setUp()
189*55a74a43SLisandro Dalcin    JexP.zeroEntries()
190*55a74a43SLisandro Dalcin    JexP.assemble()
191*55a74a43SLisandro Dalcin
192*55a74a43SLisandro Dalcinu = PETSc.Vec().createSeq(ode.n, comm=ode.comm)
193*55a74a43SLisandro Dalcinf = u.duplicate()
194*55a74a43SLisandro Dalcinadj_u = []
195*55a74a43SLisandro Dalcinadj_u.append(PETSc.Vec().createSeq(ode.n, comm=ode.comm))
196*55a74a43SLisandro Dalcinadj_u.append(PETSc.Vec().createSeq(ode.n, comm=ode.comm))
197*55a74a43SLisandro Dalcinadj_p = []
198*55a74a43SLisandro Dalcinadj_p.append(PETSc.Vec().createSeq(1, comm=ode.comm))
199*55a74a43SLisandro Dalcinadj_p.append(PETSc.Vec().createSeq(1, comm=ode.comm))
200*55a74a43SLisandro Dalcin
201*55a74a43SLisandro Dalcints = PETSc.TS().create(comm=ode.comm)
202*55a74a43SLisandro Dalcints.setProblemType(ts.ProblemType.NONLINEAR)
203*55a74a43SLisandro Dalcin
204*55a74a43SLisandro Dalcinif imexform_:
205*55a74a43SLisandro Dalcin    ts.setType(ts.Type.ARKIMEX)
206*55a74a43SLisandro Dalcin    ts.setIFunction(ode.evalIFunction, f)
207*55a74a43SLisandro Dalcin    ts.setIJacobian(ode.evalIJacobian, Jim)
208*55a74a43SLisandro Dalcin    ts.setIJacobianP(ode.evalIJacobianP, JimP)
209*55a74a43SLisandro Dalcin    ts.setRHSFunction(ode.evalFunction, f)
210*55a74a43SLisandro Dalcin    ts.setRHSJacobian(ode.evalJacobian, Jex)
211*55a74a43SLisandro Dalcin    ts.setRHSJacobianP(ode.evalJacobianP, JexP)
212*55a74a43SLisandro Dalcinelse:
213*55a74a43SLisandro Dalcin    if implicitform_:
214*55a74a43SLisandro Dalcin        ts.setType(ts.Type.CN)
215*55a74a43SLisandro Dalcin        ts.setIFunction(ode.evalIFunction, f)
216*55a74a43SLisandro Dalcin        ts.setIJacobian(ode.evalIJacobian, Jim)
217*55a74a43SLisandro Dalcin        ts.setIJacobianP(ode.evalIJacobianP, JimP)
218*55a74a43SLisandro Dalcin    else:
219*55a74a43SLisandro Dalcin        ts.setType(ts.Type.RK)
220*55a74a43SLisandro Dalcin        ts.setRHSFunction(ode.evalFunction, f)
221*55a74a43SLisandro Dalcin        ts.setRHSJacobian(ode.evalJacobian, Jex)
222*55a74a43SLisandro Dalcin        ts.setRHSJacobianP(ode.evalJacobianP, JexP)
223*55a74a43SLisandro Dalcin
224*55a74a43SLisandro Dalcints.setSaveTrajectory()
225*55a74a43SLisandro Dalcints.setTime(0.0)
226*55a74a43SLisandro Dalcints.setTimeStep(0.001)
227*55a74a43SLisandro Dalcints.setMaxTime(0.5)
228*55a74a43SLisandro Dalcints.setMaxSteps(1000)
229*55a74a43SLisandro Dalcints.setExactFinalTime(PETSc.TS.ExactFinalTime.MATCHSTEP)
230*55a74a43SLisandro Dalcin
231*55a74a43SLisandro Dalcints.setFromOptions()
232*55a74a43SLisandro Dalcinode.initialCondition(u)
233*55a74a43SLisandro Dalcints.solve(u)
234*55a74a43SLisandro Dalcin
235*55a74a43SLisandro Dalcinadj_u[0][0] = 1
236*55a74a43SLisandro Dalcinadj_u[0][1] = 0
237*55a74a43SLisandro Dalcinadj_u[0].assemble()
238*55a74a43SLisandro Dalcinadj_u[1][0] = 0
239*55a74a43SLisandro Dalcinadj_u[1][1] = 1
240*55a74a43SLisandro Dalcinadj_u[1].assemble()
241*55a74a43SLisandro Dalcinadj_p[0][0] = 0
242*55a74a43SLisandro Dalcinadj_p[0].assemble()
243*55a74a43SLisandro Dalcinadj_p[1][0] = 0
244*55a74a43SLisandro Dalcinadj_p[1].assemble()
245*55a74a43SLisandro Dalcin
246*55a74a43SLisandro Dalcints.setCostGradients(adj_u,adj_p)
247*55a74a43SLisandro Dalcin
248*55a74a43SLisandro Dalcints.adjointSolve()
249*55a74a43SLisandro Dalcin
250*55a74a43SLisandro Dalcinadj_u[0].view()
251*55a74a43SLisandro Dalcinadj_u[1].view()
252*55a74a43SLisandro Dalcinadj_p[0].view()
253*55a74a43SLisandro Dalcinadj_p[1].view()
254*55a74a43SLisandro Dalcin
255*55a74a43SLisandro Dalcindef compute_derp(du,dp):
256*55a74a43SLisandro Dalcin    print(du[1]*(-10.0/(81.0*mu_*mu_)+2.0*292.0/(2187.0*mu_*mu_*mu_))+dp[0])
257*55a74a43SLisandro Dalcin
258*55a74a43SLisandro Dalcincompute_derp(adj_u[0],adj_p[0])
259*55a74a43SLisandro Dalcincompute_derp(adj_u[1],adj_p[1])
260*55a74a43SLisandro Dalcin
261*55a74a43SLisandro Dalcindel ode, Jim, JimP, Jex, JexP, u, f, ts, adj_u, adj_p
262