//============================================================================ // Copyright (c) Kitware, Inc. // All rights reserved. // See LICENSE.txt for details. // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. // // Copyright 2015 Sandia Corporation. // Copyright 2015 UT-Battelle, LLC. // Copyright 2015 Los Alamos National Security. // // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, // the U.S. Government retains certain rights in this software. // // Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National // Laboratory (LANL), the U.S. Government retains certain rights in // this software. //============================================================================ #include #include namespace { // We will test Newton's method with the following three functions: // // f1(x,y,z) = x^2 + y^2 + z^2 // f2(x,y,z) = 2x - y + z // f3(x,y,z) = x + y - z // // If we want the result of all three equations to be 1, then there are two // valid solutions: (2/3, -1/3, -2/3) and (2/3, 2/3, 1/3). template struct EvaluateFunctions { typedef vtkm::Vec Vector3; VTKM_EXEC_CONT_EXPORT Vector3 operator()(Vector3 x) const { Vector3 fx; fx[0] = x[0]*x[0] + x[1]*x[1] + x[2]*x[2]; fx[1] = 2*x[0] - x[1] + x[2]; fx[2] = x[0] + x[1] - x[2]; return fx; } }; template struct EvaluateJacobian { typedef vtkm::Vec Vector3; typedef vtkm::Matrix Matrix3x3; VTKM_EXEC_CONT_EXPORT Matrix3x3 operator()(Vector3 x) const { Matrix3x3 jacobian; jacobian(0,0) = 2*x[0]; jacobian(0,1) = 2*x[1]; jacobian(0,2) = 2*x[2]; jacobian(1,0) = 2; jacobian(1,1) = -1; jacobian(1,2) = 1; jacobian(2,0) = 1; jacobian(2,1) = 1; jacobian(2,2) = -1; return jacobian; } }; template void TestNewtonsMethodTemplate() { std::cout << "Testing Newton's Method." << std::endl; typedef vtkm::Vec Vector3; Vector3 desiredOutput(1, 1, 1); Vector3 expected1(2.0f/3.0f, -1.0f/3.0f, -2.0f/3.0f); Vector3 expected2(2.0f/3.0f, 2.0f/3.0f, 1.0f/3.0f); Vector3 initialGuess; for (initialGuess[0] = 0.25f; initialGuess[0] <= 1; initialGuess[0] += 0.25f) { for (initialGuess[1] = 0.25f; initialGuess[1] <= 1; initialGuess[1] += 0.25f) { for (initialGuess[2] = 0.25f; initialGuess[2] <= 1; initialGuess[2] +=0.25f) { std::cout << " " << initialGuess << std::endl; Vector3 solution = vtkm::NewtonsMethod(EvaluateJacobian(), EvaluateFunctions(), desiredOutput, initialGuess, T(1e-6)); VTKM_TEST_ASSERT(test_equal(solution, expected1) || test_equal(solution, expected2), "Newton's method did not converge to expected result."); } } } } void TestNewtonsMethod() { std::cout << "*** Float32 *************************" << std::endl; TestNewtonsMethodTemplate(); std::cout << "*** Float64 *************************" << std::endl; TestNewtonsMethodTemplate(); } } // anonymous namespace int UnitTestNewtonsMethod(int, char *[]) { return vtkm::testing::Testing::Run(TestNewtonsMethod); }