def testHarmonicOscillator(self): T, N = 10, 100 u0 = ad.array([1., 0.]) t = np.linspace(0, T, N) u1 = pdeint(lambda u : ad.hstack([u[1], -u[0]]), u0, t) u2 = pdeint(lambda u : ad.hstack([u[1], -u[0]]), u0, [0, T]) accuracy = np.linalg.norm(ad.value(u1[-1] - u2[-1])) self.assertLess(accuracy, 5E-4)
def qoi(self, x): # set the operator coefficients with the given x self.set_coeff(x) # solve the PDE u = npd.solve(self.residual, np.zeros([self.nx - 1, self.nx - 1]), verbose=False) # get the PDE solution on the boundary u_bnd = u[:, -1] # compute the average on the boundary q = 0.5 * self.dx * np.sum(u_bnd[1:] + u_bnd[:-1]) # return a number from numpad return npd.value(q)
def pdeint(f, u0, t, relTol=1E-4, absTol=1E-6, ret='array', disp=0): ''' To be used like ode23s, using numpad for Jacobian ''' def _roundTo2ToK(n): log2n = np.log2(max(1, n)) return 2**int(round(log2n)) u = ad.array(u0).copy() uHistory = [u] uTrajectory = Trajectory(f, ad.value(u)) dt = t[1] - t[0] for i in range(len(t) - 1): iSubdiv, nSubdiv = 0, _roundTo2ToK((t[i+1] - t[i]) / dt) dt = (t[i+1] - t[i]) / nSubdiv while iSubdiv < nSubdiv: uTmp1, uTmp2, u3rd, u2nd = step(f, u, dt) uNorm = np.linalg.norm(ad.value(u)) errNorm = np.linalg.norm(ad.value(u3rd) - ad.value(u2nd)) if errNorm > max(absTol, relTol * uNorm): dt, iSubdiv, nSubdiv = 0.5 * dt, 2 * iSubdiv, 2 * nSubdiv else: iSubdiv += 1 u = u3rd uTrajectory.append(ad.value(uTmp1), ad.value(uTmp2), ad.value(u), dt) if ret == 'array': u.obliviate() if disp: print(t[i] + (t[i+1] - t[i]) * iSubdiv / nSubdiv) if errNorm < 0.25 * max(absTol, relTol * uNorm) and \ iSubdiv % 2 == 0 and nSubdiv > 1: dt, iSubdiv, nSubdiv = 2 * dt, iSubdiv / 2, nSubdiv / 2 assert iSubdiv == nSubdiv uHistory.append(u) if ret == 'array': return np.array([ad.value(u) for u in uHistory]) elif ret == 'list': return uHistory elif ret == 'trajectory': return uTrajectory