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