def test_solve(self): testtimes = np.array([0.0, 1.0]) testparams = np.array([0.01, 0.03]) s = Solver([0.0, 1.0], [0.0, 1.0], 100, lambda X, Y: [X, Y]) u, v = s.solve(testtimes, testparams) self.assertTupleEqual(u.shape, (2, 100, 100)) self.assertTupleEqual(v.shape, (2, 100, 100))
def test_solve_oscillation(self): def uniform_initial_conditions(X, Y): """ Creates uniform initial conditions with u = 1, v = 0 """ return [np.ones_like(X), np.zeros_like(X)] def oscillation_reactionfunction(u, v, parameters): """ Reaction function with a sinusoidal exact solution. """ w = parameters[0] # angular speed return [w * v, -w * u] testtimes = np.linspace(0, 2 * np.pi, 20) for w in [1.0, 2.0, 3.0]: # angular speed testparams = np.array([0.01, 0.01, w]) s = Solver([0.0, 1.0], [0.0, 1.0], 20, uniform_initial_conditions) s.set_reactionFunction(oscillation_reactionfunction) s.set_timeStepLength(0.0001) u, v = s.solve(testtimes, testparams) for i in range(len(testtimes)): # solution remains uniform self.assertAlmostEqual(np.std(u[i]), 0) self.assertAlmostEqual(np.std(v[i]), 0) # solution is sine & cosine with given angular speed self.assertAlmostEqual(u[i, 10, 10], np.cos(w * testtimes[i]), places=3) self.assertAlmostEqual(v[i, 10, 10], -np.sin(w * testtimes[i]), places=3)
def test_set_grid(self): testxbounds = np.random.random(2) testybounds = np.random.random(2) testgridsize = 50 testfun = lambda X, Y: [ np.sin(4 * np.pi * X) * np.sin(2 * np.pi * Y), np.sin(4 * np.pi * X) * np.sin(2 * np.pi * Y) ] # Expected values expected_x = np.linspace(testxbounds[0], testxbounds[1], testgridsize + 1)[:-1] expected_y = np.linspace(testybounds[0], testybounds[1], testgridsize + 1)[:-1] expected_X, expected_Y = np.meshgrid(expected_x, expected_y) # Test s = Solver(np.random.random(2), np.random.random(2), np.random.randint(1, 100), testfun) s.set_grid(testxbounds, testybounds, testgridsize) # Checks self.assertTrue(np.array_equal(s.xBounds, testxbounds)) self.assertTrue(np.array_equal(s.yBounds, testybounds)) self.assertEqual(s.gridSize, testgridsize) self.assertEqual(s.xStepLength, (testxbounds[1] - testxbounds[0]) / (testgridsize)) self.assertEqual(s.yStepLength, (testybounds[1] - testybounds[0]) / (testgridsize)) self.assertTrue(np.array_equal(s.x, expected_x)) self.assertTrue(np.array_equal(s.y, expected_y)) self.assertTrue(np.array_equal(s.X, expected_X)) self.assertTrue(np.array_equal(s.Y, expected_Y)) self.assertTrue( np.array_equal(s.initialConditions, testfun(expected_X, expected_Y)))
def test_solve_exponential(self): t = np.linspace(0, 5.0, 6) testparams = np.array([1.0, 2.0]) k1, k2 = testparams def reaction_function(u, v, K): return [-K[0] * u, -K[1] * v] def exact(x, y, t): return [1.0 * np.exp(-k1 * t), 2.0 * np.exp(-k2 * t)] def initial_conditions(x, y): return exact(x, y, 0) solver = Solver([0.0, 1.0], [0.0, 1.0], 30, initial_conditions) solver.set_timeStepLength(0.0001) solver.set_reactionFunction(reaction_function) u, v = solver.solve(t, [5.0, 1.0, k1, k2]) T, Y, X = np.meshgrid(t, solver.y, solver.x, indexing='ij') solution = exact(X, Y, T) error_u = np.max(np.abs((u - solution[0]))) error_v = np.max(np.abs((v - solution[1]))) print(error_u) print(error_v) # Check Uniform for i in range(len(t)): self.assertAlmostEqual(np.std(u[i]), 0) self.assertAlmostEqual(np.std(v[i]), 0) self.assertLess(error_u, 1e-4) self.assertLess(error_v, 1e-4)
def test_solve_2dheatequation(self): def sinusoidal_initial_conditions(X, Y): """ Creates initial conditions with a sinusoidal wave in the x and y directions. """ return [ np.sin(4 * np.pi * X) * np.sin(2 * np.pi * Y), np.sin(4 * np.pi * X) * np.sin(2 * np.pi * Y) ] testtimes = np.linspace(0.0, 1.0, 20) testparams = [0.05, 0.01] # diffusion coefficients s = Solver([0.0, 1.0], [0.0, 1.0], 50, sinusoidal_initial_conditions) s.set_timeStepLength(0.0001) u, v = s.solve(testtimes, testparams) for i in range(len(testtimes)): for j in range(50): for k in range(50): self.assertAlmostEqual( u[i, j, k], np.sin(4 * np.pi * s.X[j, k]) * np.sin(2 * np.pi * s.Y[j, k]) * np.exp(-testparams[0] * 20 * np.pi**2 * testtimes[i]), places=2) self.assertAlmostEqual( v[i, j, k], np.sin(4 * np.pi * s.X[j, k]) * np.sin(2 * np.pi * s.Y[j, k]) * np.exp(-testparams[1] * 20 * np.pi**2 * testtimes[i]), places=2)
def test_set_model(self): testudata = np.zeros((2, 50, 50)) # doesn't matter testvdata = [0] # doesn't matter testtimes = [0] # doesn't matter infr = Inference(testudata, testvdata, testtimes) s = Solver(np.random.random(2), np.random.random(2), 50, lambda X, Y: [X, Y]) infr.set_model(s.xBounds, s.yBounds, s.initial_condition_function) #self.assertTrue(np.array_equal(s.xBounds, infr.solver.xBounds)) #self.assertTrue(np.array_equal(s.yBounds, infr.solver.yBounds)) #self.assertEqual(s.gridSize, infr.solver.gridSize) s_vars = vars(s) infr_vars = vars(infr.solver) self.assertTrue(s_vars.keys() == infr_vars.keys()) # Compare the two objects attribute by attribute for key in [ "initial_condition_function", "initialConditions_u", "initialConditions_v", "xBounds", "yBounds", "gridSize", "xStepLength", "yStepLength", "x", "y", "X", "Y", "initialConditions" ]: if isinstance(s_vars[key], (list, tuple, np.ndarray)): self.assertTrue(np.array_equal(s_vars[key], infr_vars[key])) else: self.assertTrue(s_vars[key] == infr_vars[key])
def test_set_reaction_function(self): testudata = np.zeros((2, 50, 50)) # doesn't matter testvdata = [0] # doesn't matter testtimes = [0] # doesn't matter testfun = lambda X: X * X infr = Inference(testudata, testvdata, testtimes) s = Solver(np.random.random(2), np.random.random(2), 50, lambda X, Y: [X, Y]) infr.solver = s infr.set_reaction_function(testfun) self.assertEqual(infr.solver.reactionFunction, testfun)
def test_set_initialConditions(self): testfun = lambda X, Y: [np.sin(X) * np.sin(Y), np.cos(X) * np.cos(Y)] s = Solver(np.random.random(2), np.random.random(2), np.random.randint(1, 100), lambda X, Y: [X, Y]) s.set_initialConditions(testfun) self.assertTrue( np.array_equal(s.initialConditions_u, testfun(s.X, s.Y)[0])) self.assertTrue( np.array_equal(s.initialConditions_v, testfun(s.X, s.Y)[1])) self.assertEqual(s.initial_condition_function, testfun)
def set_model(self, xBounds, yBounds, initial_conditions_function): ''' Sets up the reaction diffusion model we wish to consider. We determine the x and y boundaries for consideration and provide some initial conditions for our system. :param xBounds: x-range of the problem :type u_data: list of 2 floats :param yBounds: y-range of the problem :type u_data: list of 2 floats :param initial_condition_function: calculates the values of u and v at t=0 at each gridpoint :type initial_condition_function: function that takes two 2d numpy arrays and returns a list of two 2d numpy arrays ''' self.solver = Solver(xBounds, yBounds, self.gridsize, initial_conditions_function)
def test_solve_1ddiffusion(self): mode = 1.0 D1 = 0.05 D2 = 0.0 t = np.linspace(0, 1.0, 11) def exact(x, y, t): return [ np.sin(4 * np.pi * mode * x) * np.exp(-D1 * t * (4 * np.pi * mode)**2), 1 ] def initial_conditions(x, y): return exact(x, y, 0) solver = Solver([0.0, 1.0], [0.0, 1.0], 200, initial_conditions) solver.set_timeStepLength(0.0001) u, v = solver.solve(t, [D1, D2, 0]) T, Y, X = np.meshgrid(t, solver.y, solver.x, indexing='ij') solution = exact(X, Y, T) error_u = np.max(np.abs((u - solution[0]))) error_v = np.max(np.abs((v - solution[1]))) # Check Uniform for i in range(len(t)): for j in range(len(solver.x)): self.assertAlmostEqual(np.std(u[i, :, j]), 0) self.assertAlmostEqual(np.std(v), 0) self.assertAlmostEqual(v[1, 1, 1], 1) self.assertLess(error_u, 3 * 1e-4) self.assertLess(error_v, 1e-4)
def test_set_timeStepLength(self): testlen = np.random.random(1) s = Solver(np.random.random(2), np.random.random(2), np.random.randint(1, 100), lambda X, Y: [X, Y]) s.set_timeStepLength(testlen) self.assertAlmostEqual(s.timeStepLength, testlen)
def test_set_reactionFunction(self): testfun = lambda X: 2 * X s = Solver(np.random.random(2), np.random.random(2), np.random.randint(1, 100), lambda X, Y: [X, Y]) s.set_reactionFunction(testfun) self.assertEqual(s.reactionFunction, testfun)
# Rewrite diffusion coefficients to match the form of solver Du = 1 / eps Dv = dv # Define Reaction Function def fitzhugh_naguomo(u, v, parameters): e = parameters[0] d = parameters[1] return [(3 * u - u**3 - v) / e, u - d * v] # Initialise Solver # Set x, y bounds and grid size # Set initial condition function to obtain spiralling behavior solver = Solver(xbounds, ybounds, 256, initial_conditions_spiral) # Set reaction terms solver.set_reactionFunction(fitzhugh_naguomo) # Set time step lengths for backward Euler integration scheme solver.set_timeStepLength(0.01) # Define array of times at which to record solution t = np.linspace(0, 30, 100) # Run solve method of solver. # Input time array of times to record solution and list of parameters for the system. # First two parameters are diffusion coefficients, remaining parameters are passed to diffusion function # Return solution arrays for u, v u, v = solver.solve(t, [Du, Dv, eps, delta])