def test_with_dependents(self): """ Test the case in which the original object depends on another object. """ o1 = Adder(3) o2 = Adder(4) o1.set_dofs([10, 11, 12]) o2.set_dofs([101, 102, 103, 104]) o1.depends_on = ["o2"] o1.o2 = o2 dofs = Dofs([o1.J]) np.testing.assert_allclose(dofs.x, [10, 11, 12, 101, 102, 103, 104]) self.assertEqual(dofs.all_owners, [o1, o2]) self.assertEqual(dofs.dof_owners, [o1, o1, o1, o2, o2, o2, o2]) np.testing.assert_allclose(dofs.indices, [0, 1, 2, 0, 1, 2, 3]) f = dofs.f() # f must be evaluated before we know nvals_per_func self.assertEqual(list(dofs.nvals_per_func), [1]) self.assertEqual(dofs.nvals, 1) o1.fixed = [True, False, True] o2.fixed = [False, False, True, True] del o1.depends_on o2.depends_on = ["o1"] o2.o1 = o1 dofs = Dofs([o2.J]) np.testing.assert_allclose(dofs.x, [101, 102, 11]) self.assertEqual(dofs.all_owners, [o2, o1]) self.assertEqual(dofs.dof_owners, [o2, o2, o1]) np.testing.assert_allclose(dofs.indices, [0, 1, 1])
def test_failures(self): """ Verify that if ObjectiveFailure is raised during function evaluations, a vector is returned filled with the expected number. """ nvals = 3 fail_val = 1.0e8 o1 = Failer(nvals=nvals) d1 = Dofs([o1], fail=fail_val) # First eval should not fail: f = d1.f() np.testing.assert_allclose(f, np.full(nvals, 1.0)) # There should be a failure on the 2nd evaluation: f = d1.f() np.testing.assert_allclose(f, np.full(nvals, fail_val)) # Third eval should not fail: f = d1.f() np.testing.assert_allclose(f, np.full(nvals, 1.0)) # Try an example with >1 object in the dofs, and with NaN # instead of a finite value for the failure value. fail_val = np.NAN o2 = Failer(nvals=3) r2 = Rosenbrock() d2 = Dofs([o2, r2.terms], fail=fail_val) # First eval should not fail: f = d2.f() np.testing.assert_allclose(f, [1., 1., 1., -1., 0.]) # There should be a failure on the 2nd evaluation: f = d2.f() np.testing.assert_allclose(f, np.full(5, fail_val)) # Third eval should not fail: f = d2.f() np.testing.assert_allclose(f, [1., 1., 1., -1., 0.])
def test_gradient(self): for n in range(1, 20): v1 = np.random.rand() * 4 - 2 v2 = np.random.rand() * 4 - 2 o = TestObject2(v1, v2) o.adder.set_dofs(np.random.rand(2) * 4 - 2) o.t.set_dofs([np.random.rand() * 4 - 2]) o.t.adder1.set_dofs(np.random.rand(3) * 4 - 2) o.t.adder2.set_dofs(np.random.rand(2) - 0.5) # Randomly fix some of the degrees of freedom o.fixed = np.random.rand(2) > 0.5 o.adder.fixed = np.random.rand(2) > 0.5 o.t.adder1.fixed = np.random.rand(3) > 0.5 o.t.adder2.fixed = np.random.rand(2) > 0.5 rtol = 1e-4 atol = 1e-4 dofs = Dofs([o.J]) mask = np.logical_not(np.array(dofs.func_fixed[0])) # Supply a function to finite_difference(): fd_grad = Dofs([o.J]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, o.df[mask], rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, o.dJ()[mask], rtol=rtol, atol=atol) # Supply an object to finite_difference(): fd_grad = Dofs([o]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, o.df[mask], rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, o.dJ()[mask], rtol=rtol, atol=atol) # Supply an attribute to finite_difference(): fd_grad = Dofs([Target(o, "f")]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, o.df[mask], rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, o.dJ()[mask], rtol=rtol, atol=atol) print('Diff in TestObject2:', fd_grad - o.df[mask])
def test_gradient(self): for n in range(1, 10): r = Rosenbrock(b=np.random.rand() * 2) # Note b must be > 0. r.set_dofs(np.random.rand(2) * 4 - 2) rtol = 1e-6 atol = 1e-6 # Test gradient of term1 # Supply a function to finite_difference(): fd_grad = Dofs([r.term1]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, r.dterm1prop, rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, r.dterm1(), rtol=rtol, atol=atol) # Supply an attribute to finite_difference(): fd_grad = Dofs([Target(r, "term1prop")]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, r.dterm1prop, rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, r.dterm1(), rtol=rtol, atol=atol) # Test gradient of term2 # Supply a function to finite_difference(): fd_grad = Dofs([r.term2]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, r.dterm2prop, rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, r.dterm2(), rtol=rtol, atol=atol) # Supply an attribute to finite_difference(): fd_grad = Dofs([Target(r, "term2prop")]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, r.dterm2prop, rtol=rtol, atol=atol) np.testing.assert_allclose(fd_grad, r.dterm2(), rtol=rtol, atol=atol)
def test_gradient(self): for n in range(1, 10): a = Adder(n) a.set_dofs(np.random.rand(n) * 4 - 2) # Supply an object to finite_difference(): fd_grad = Dofs([a]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, a.df) np.testing.assert_allclose(fd_grad, a.dJ()) # Supply a function to finite_difference(): fd_grad = Dofs([a.J]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, a.df) np.testing.assert_allclose(fd_grad, a.dJ()) # Supply an attribute to finite_difference(): fd_grad = Dofs([Target(a, "f")]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, a.df) np.testing.assert_allclose(fd_grad, a.dJ())
def test_gradient(self): iden = Identity() for n in range(1, 10): iden.set_dofs([np.random.rand() * 4 - 2]) # Supply an object to finite_difference(): fd_grad = Dofs([iden]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, iden.df) np.testing.assert_allclose(fd_grad, iden.dJ()) # Supply a function to finite_difference(): fd_grad = Dofs([iden.J]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, iden.df) np.testing.assert_allclose(fd_grad, iden.dJ()) # Supply an attribute to finite_difference(): fd_grad = Dofs([Target(iden, "f")]).fd_jac().flatten() np.testing.assert_allclose(fd_grad, iden.df) np.testing.assert_allclose(fd_grad, iden.dJ())
def test_multiple_vector_valued(self): """ For a function that returns a vector rather than a scalar, make sure Dofs.f(), Dofs.jac(), and Dofs.fd_jac() behave correctly. """ for nparams1 in range(1, 5): for nvals1 in range(1, 5): nparams2 = np.random.randint(1, 6) nparams3 = np.random.randint(1, 6) nvals2 = np.random.randint(1, 6) nvals3 = np.random.randint(1, 6) o1 = Affine(nparams=nparams1, nvals=nvals1) o2 = Affine(nparams=nparams2, nvals=nvals2) o3 = Affine(nparams=nparams3, nvals=nvals3) dofs = Dofs([o1, o2, o3], diff_method="centered") dofs.set( (np.random.rand(nparams1 + nparams2 + nparams3) - 0.5) * 4) f1 = np.matmul(o1.A, o1.x) + o1.B f2 = np.matmul(o2.A, o2.x) + o2.B f3 = np.matmul(o3.A, o3.x) + o3.B np.testing.assert_allclose(dofs.f(), np.concatenate((f1, f2, f3)), \ rtol=1e-13, atol=1e-13) true_jac = np.zeros( (nvals1 + nvals2 + nvals3, nparams1 + nparams2 + nparams3)) true_jac[0:nvals1, 0:nparams1] = o1.A true_jac[nvals1:nvals1 + nvals2, nparams1:nparams1 + nparams2] = o2.A true_jac[nvals1 + nvals2:nvals1 + nvals2 + nvals3, \ nparams1 + nparams2:nparams1 + nparams2 + nparams3] = o3.A np.testing.assert_allclose(dofs.jac(), true_jac, rtol=1e-13, atol=1e-13) np.testing.assert_allclose(dofs.fd_jac(), \ true_jac, rtol=1e-7, atol=1e-7)
def test_no_dependents(self): """ Tests for an object that does not depend on other objects. """ obj = Adder(4) obj.set_dofs([101, 102, 103, 104]) dofs = Dofs([obj.J]) np.testing.assert_allclose(dofs.x, [101, 102, 103, 104]) self.assertEqual(dofs.all_owners, [obj]) self.assertEqual(dofs.dof_owners, [obj, obj, obj, obj]) np.testing.assert_allclose(dofs.indices, [0, 1, 2, 3]) dummy = dofs.f() # f must be evaluated before we know nvals_per_func self.assertEqual(list(dofs.nvals_per_func), [1]) self.assertEqual(dofs.nvals, 1) obj.fixed = [True, False, True, False] dofs = Dofs([obj.J]) np.testing.assert_allclose(dofs.x, [102, 104]) self.assertEqual(dofs.all_owners, [obj]) self.assertEqual(dofs.dof_owners, [obj, obj]) np.testing.assert_allclose(dofs.indices, [1, 3]) obj.fixed[0] = False dofs = Dofs([obj.J]) np.testing.assert_allclose(dofs.x, [101, 102, 104]) self.assertEqual(dofs.all_owners, [obj]) self.assertEqual(dofs.dof_owners, [obj, obj, obj]) np.testing.assert_allclose(dofs.indices, [0, 1, 3])
def test_vector_valued(self): """ For a function that returns a vector rather than a scalar, make sure Dofs.f(), Dofs.jac(), and Dofs.fd_jac() behave correctly. """ for nparams in range(1, 5): for nvals in range(1, 5): o = Affine(nparams=nparams, nvals=nvals) o.set_dofs((np.random.rand(nparams) - 0.5) * 4) dofs = Dofs([o], diff_method="centered") np.testing.assert_allclose(dofs.f(), np.matmul(o.A, o.x) + o.B, \ rtol=1e-13, atol=1e-13) np.testing.assert_allclose(dofs.jac(), o.A, rtol=1e-13, atol=1e-13) np.testing.assert_allclose(dofs.fd_jac(), \ o.A, rtol=1e-7, atol=1e-7)
def test_no_fixed(self): """ Test behavior when there is no 'fixed' attribute. """ obj = Adder(4) del obj.fixed self.assertFalse(hasattr(obj, 'fixed')) obj.set_dofs([101, 102, 103, 104]) dofs = Dofs([obj.J]) np.testing.assert_allclose(dofs.x, [101, 102, 103, 104]) self.assertEqual(dofs.all_owners, [obj]) self.assertEqual(dofs.dof_owners, [obj, obj, obj, obj]) np.testing.assert_allclose(dofs.indices, [0, 1, 2, 3])
def test_derivatives(self): """ Check the automatic differentiation for area and volume. """ for mpol in range(1, 3): for ntor in range(2): for nfp in range(1, 4): s = SurfaceRZFourier(nfp=nfp, mpol=mpol, ntor=ntor) x0 = s.get_dofs() x = np.random.rand(len(x0)) - 0.5 x[0] = np.random.rand() + 2 # This surface will probably self-intersect, but I # don't think this actually matters here. s.set_dofs(x) dofs = Dofs([s.area, s.volume]) jac = dofs.jac() fd_jac = dofs.fd_jac() print('difference for surface test_derivatives:', jac - fd_jac) np.testing.assert_allclose(jac, fd_jac, rtol=1e-4, atol=1e-4)
def test_mixed_vector_valued(self): """ For a mixture of functions that return a scalar vs return a vector, make sure Dofs.f(), Dofs.jac(), and Dofs.fd_jac() behave correctly. """ for nparams1 in range(1, 5): for nvals1 in range(1, 5): nparams2 = np.random.randint(1, 6) nparams3 = np.random.randint(1, 6) nvals2 = np.random.randint(1, 6) nvals3 = np.random.randint(1, 6) o1 = Affine(nparams=nparams1, nvals=nvals1) o2 = Affine(nparams=nparams2, nvals=nvals2) o3 = Affine(nparams=nparams3, nvals=nvals3) a1 = Adder(n=2) a2 = Adder(n=3) dofs = Dofs([o1, o2, a1, o3, a2], diff_method="centered") dofs.set( (np.random.rand(nparams1 + nparams2 + nparams3 + 5) - 0.5) * 4) f1 = np.matmul(o1.A, o1.x) + o1.B f2 = np.matmul(o2.A, o2.x) + o2.B f3 = np.array([a1.f]) f4 = np.matmul(o3.A, o3.x) + o3.B f5 = np.array([a2.f]) np.testing.assert_allclose(dofs.f(), np.concatenate((f1, f2, f3, f4, f5)), \ rtol=1e-13, atol=1e-13) true_jac = np.zeros((nvals1 + nvals2 + nvals3 + 2, nparams1 + nparams2 + nparams3 + 5)) true_jac[0:nvals1, 0:nparams1] = o1.A true_jac[nvals1:nvals1 + nvals2, nparams1:nparams1 + nparams2] = o2.A true_jac[nvals1 + nvals2:nvals1 + nvals2 + 1, \ nparams1 + nparams2:nparams1 + nparams2 + 2] = np.ones(2) true_jac[nvals1 + nvals2 + 1:nvals1 + nvals2 + 1 + nvals3, \ nparams1 + nparams2 + 2:nparams1 + nparams2 + 2 + nparams3] = o3.A true_jac[nvals1 + nvals2 + 1 + nvals3:nvals1 + nvals2 + nvals3 + 2, \ nparams1 + nparams2 + nparams3 + 2:nparams1 + nparams2 + nparams3 + 5] = np.ones(3) np.testing.assert_allclose(dofs.jac(), true_jac, rtol=1e-13, atol=1e-13) np.testing.assert_allclose(dofs.fd_jac(), \ true_jac, rtol=1e-7, atol=1e-7)
def test_fd_jac_abs_rel_steps(self): """ Confirm that the parallel finite difference gradient gives nearly the same result regardless of whether absolute or relative steps are used. """ rtol = 1e-6 atol = 1e-6 for ngroups in range(1, 4): for abs_step in [0, 1.0e-7]: # Only try rel_step=0 if abs_step is positive: rel_steps = [0, 1.0e-7] if abs_step == 0: rel_steps = [1.0e-7] for rel_step in rel_steps: for diff_method in ["forward", "centered"]: logger.debug(f'ngroups={ngroups} abs_step={abs_step} ' \ f'rel_step={rel_step} diff_method={diff_method}') mpi = MpiPartition(ngroups=ngroups) o = TestFunction1() d = Dofs([o], diff_method=diff_method, abs_step=abs_step, rel_step=rel_step) logger.debug('About to do worker loop 1') jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[5.865175337071982e-01, -6.010834789627051e-01, 2.250910093037906e-01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=rtol, atol=atol) # While we're at it, also test the serial FD Jacobian: jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=rtol, atol=atol) # Now try a case with different nparams and nfuncs. o = TestFunction2() d = Dofs([o.f0, o.f1, o.f2, o.f3], diff_method=diff_method, abs_step=abs_step, rel_step=rel_step) logger.debug('About to do worker loop 2') jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[8.657714037352271e-01, -8.872725151820582e-01], [2.353410674116319e+00, -2.411856754314101e+00], [6.397233469623842e+00, -6.556106388888594e+00], [1.738948351093228e+01, -1.782134486205678e+01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=rtol, atol=atol) # While we're at it, also test the serial FD Jacobian: jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=rtol, atol=atol)
def test_Jacobian(self): for n in range(1, 20): v1 = np.random.rand() * 4 - 2 v2 = np.random.rand() * 4 - 2 o = TestObject2(v1, v2) o.adder.set_dofs(np.random.rand(2) * 4 - 2) o.t.set_dofs([np.random.rand() * 4 - 2]) o.t.adder1.set_dofs(np.random.rand(3) * 4 - 2) o.t.adder2.set_dofs(np.random.rand(2) * 4 - 2) r = Rosenbrock(b=3.0) r.set_dofs(np.random.rand(2) * 3 - 1.5) a = Affine(nparams=3, nvals=3) # Randomly fix some of the degrees of freedom o.fixed = np.random.rand(2) > 0.5 o.adder.fixed = np.random.rand(2) > 0.5 o.t.adder1.fixed = np.random.rand(3) > 0.5 o.t.adder2.fixed = np.random.rand(2) > 0.5 r.fixed = np.random.rand(2) > 0.5 a.fixed = np.random.rand(3) > 0.5 rtol = 1e-6 atol = 1e-6 for j in range(4): # Try different sets of the objects: if j == 0: dofs = Dofs([o.J, r.terms, o.t.J]) nvals = 4 nvals_per_func = [1, 2, 1] elif j == 1: dofs = Dofs([r.term2, r.terms]) nvals = 3 nvals_per_func = [1, 2] elif j == 2: dofs = Dofs( [r.term2, Target(o.t, 'f'), r.term1, Target(o, 'f')]) nvals = 4 nvals_per_func = [1, 1, 1, 1] elif j == 3: dofs = Dofs([a, o]) nvals = 4 nvals_per_func = [3, 1] jac = dofs.jac() dofs.diff_method = "forward" fd_jac = dofs.fd_jac() dofs.diff_method = "centered" fd_jac_centered = dofs.fd_jac() #print('j=', j, ' Diff in Jacobians:', jac - fd_jac) #print('jac: ', jac) #print('fd_jac: ', fd_jac) #print('fd_jac_centered: ', fd_jac_centered) #print('shapes: jac=', jac.shape, ' fd_jac=', fd_jac.shape, ' fd_jac_centered=', fd_jac_centered.shape) np.testing.assert_allclose(jac, fd_jac, rtol=rtol, atol=atol) np.testing.assert_allclose(fd_jac, fd_jac_centered, rtol=rtol, atol=atol) self.assertEqual(dofs.nvals, nvals) self.assertEqual(list(dofs.nvals_per_func), nvals_per_func)
def test_fd_jac(self): """ Test the parallel finite-difference Jacobian calculation. """ abs_step = 1.0e-7 rel_step = 0 for ngroups in range(1, 4): logger.debug('ngroups={}'.format(ngroups)) mpi = MpiPartition(ngroups=ngroups) o = TestFunction1() d = Dofs([o], diff_method="forward", abs_step=abs_step, rel_step=rel_step) logger.debug('About to do worker loop 1') jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[5.865176283537110e-01, -6.010834349701177e-01, 2.250910244305793e-01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # While we're at it, also test the serial FD Jacobian: o.set_dofs(np.array([1.2, 0.9, -0.4])) jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # Repeat with centered differences o.set_dofs(np.array([1.2, 0.9, -0.4])) logger.debug('About to do worker loop 2') d.diff_method = "centered" jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[5.865175337071982e-01, -6.010834789627051e-01, 2.250910093037906e-01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # While we're at it, also test the serial FD Jacobian: o.set_dofs(np.array([1.2, 0.9, -0.4])) jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # Now try a case with different nparams and nfuncs. o = TestFunction2() d = Dofs([o.f0, o.f1, o.f2, o.f3], diff_method="forward", abs_step=abs_step, rel_step=rel_step) logger.debug('About to do worker loop 3') jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[8.657715439008840e-01, -8.872724499564555e-01], [2.353411054922816e+00, -2.411856577788640e+00], [6.397234502131255e+00, -6.556105911492693e+00], [1.738948636642590e+01, -1.782134355643450e+01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # While we're at it, also test the serial FD Jacobian: o.set_dofs(np.array([1.2, 0.9])) jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # Repeat with centered differences o.set_dofs(np.array([1.2, 0.9])) d.diff_method = "centered" logger.debug('About to do worker loop 4') jac, xs, evals = fd_jac_mpi(d, mpi) jac_reference = np.array([[8.657714037352271e-01, -8.872725151820582e-01], [2.353410674116319e+00, -2.411856754314101e+00], [6.397233469623842e+00, -6.556106388888594e+00], [1.738948351093228e+01, -1.782134486205678e+01]]) if mpi.proc0_world: np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13) # While we're at it, also test the serial FD Jacobian: o.set_dofs(np.array([1.2, 0.9])) jac = d.fd_jac() np.testing.assert_allclose(jac, jac_reference, rtol=1e-13, atol=1e-13)