<commit_before>/*
 * Copyright 2018 Universidad Carlos III de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <atomic>

#include <gtest/gtest.h>
#include <iostream>

#include "mapreduce.h"
#include "dyn/dynamic_execution.h"

#include "supported_executions.h"

using namespace std;
using namespace grppi;

template <typename T>
class map_reduce_test : public ::testing::Test {
public:
  T execution_{};
  dynamic_execution dyn_execution_{execution_};

  // Variables
  int output{};

  // Vectors
  vector<int> v{};
  vector<int> v2{};

  // Invocation counter
  std::atomic<int> invocations_transformer{0};

  template <typename E>
  auto run_square_sum(const E & e) {
    return grppi::map_reduce(e, v.begin(), v.end(), 0,
      [this](int x) {
        invocations_transformer++;
        return x*x;
      },
      [](int x, int y) {
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_square_sum_range(const E & e) {
    return grppi::map_reduce(e, v, 0,
      [this](int x) {
        invocations_transformer++;
        return x*x;
      },
      [](int x, int y) {
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_iter(const E & e){
    return  grppi::map_reduce(e,
      make_tuple(v.begin(),v2.begin()), v.end(), 0,
      [this](int x1, int x2) {
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_size(const E & e){
    return  grppi::map_reduce(e,
      make_tuple(v.begin(),v2.begin()), v.size(), 0,
      [this](int x1, int x2){
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_range(const E & e){
    return  grppi::map_reduce(e,
      grppi::zip(v,v2), 0,
      [this](int x1, int x2) {
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  void setup_single() {
    v = vector<int>{1};
    output = 0;
  }

  void check_single() {
    EXPECT_EQ(1, invocations_transformer);
    EXPECT_EQ(1, this->output);
  }

  void setup_multiple() {
    v = vector<int>{1,2,3,4,5};
    output = 0;
  }

  void check_multiple() {
    EXPECT_EQ(5, this->invocations_transformer);
    EXPECT_EQ(55, this->output);
  }

  void setup_single_scalar_product() {
    v = vector<int>{5};
    v2 = vector<int>{6};
    output = 0;
  }

  void check_single_scalar_product(){
    EXPECT_EQ(1, this->invocations_transformer);
    EXPECT_EQ(30, this->output);
  }

  void setup_multiple_scalar_product() {
    v = vector<int>{1,2,3,4,5};
    v2 = vector<int>{2,4,6,8,10};
    output = 0;
  }

  void check_multiple_scalar_product() {
    EXPECT_EQ(5, this->invocations_transformer);
    EXPECT_EQ(110, this->output);
  }

};

// Test for execution policies defined in supported_executions.h
TYPED_TEST_CASE(map_reduce_test, executions);

TYPED_TEST(map_reduce_test, static_single_square_sum)
{
  this->setup_single();
  this->output = this->run_square_sum(this->execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, static_single_square_sum_range)
{
  this->setup_single();
  this->output = this->run_square_sum_range(this->execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, dyn_single_square_sum)
{
  this->setup_single();
  this->output = this->run_square_sum(this->dyn_execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, dyn_single_square_sum_range)
{
  this->setup_single();
  this->output = this->run_square_sum_range(this->dyn_execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, static_multiple_square_sum)
{
  this->setup_multiple();
  this->output = this->run_square_sum(this->execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, static_multiple_square_sum_range)
{
  this->setup_multiple();
  this->output = this->run_square_sum_range(this->execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, dyn_multiple_square_sum)
{
  this->setup_multiple();
  this->output = this->run_square_sum(this->dyn_execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, dyn_multiple_square_sum_range)
{
  this->setup_multiple();
  this->output = this->run_square_sum_range(this->dyn_execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_iter)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_size)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_range)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_iter)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_size)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_range)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_iter)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_size)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_range)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_iter)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->dyn_execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_size)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->dyn_execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_size_range)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->dyn_execution_);
  this->check_multiple_scalar_product();
}
<commit_msg>Added missing test cases to map-reduce<commit_after>/*
 * Copyright 2018 Universidad Carlos III de Madrid
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <atomic>

#include <gtest/gtest.h>
#include <iostream>

#include "mapreduce.h"
#include "dyn/dynamic_execution.h"

#include "supported_executions.h"

using namespace std;
using namespace grppi;

template <typename T>
class map_reduce_test : public ::testing::Test {
public:
  T execution_{};
  dynamic_execution dyn_execution_{execution_};

  // Variables
  int output{};

  // Vectors
  vector<int> v{};
  vector<int> v2{};

  // Invocation counter
  std::atomic<int> invocations_transformer{0};

  template <typename E>
  auto run_square_sum(const E & e) {
    return grppi::map_reduce(e, v.begin(), v.end(), 0,
      [this](int x) {
        invocations_transformer++;
        return x*x;
      },
      [](int x, int y) {
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_square_sum_size(const E & e) {
    return grppi::map_reduce(e, begin(v), v.size(), 0,
      [this](int x) {
        invocations_transformer++;
        return x*x;
      },
      [](int x, int y) {
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_square_sum_range(const E & e) {
    return grppi::map_reduce(e, v, 0,
      [this](int x) {
        invocations_transformer++;
        return x*x;
      },
      [](int x, int y) {
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_iter(const E & e){
    return  grppi::map_reduce(e,
      make_tuple(v.begin(),v2.begin()), v.end(), 0,
      [this](int x1, int x2) {
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_size(const E & e){
    return  grppi::map_reduce(e,
      make_tuple(v.begin(),v2.begin()), v.size(), 0,
      [this](int x1, int x2){
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  template <typename E>
  auto run_scalar_product_tuple_range(const E & e){
    return  grppi::map_reduce(e,
      grppi::zip(v,v2), 0,
      [this](int x1, int x2) {
        invocations_transformer++;
        return x1 * x2;
      },
      [](int x, int y){
        return x + y;
      }
    );
  }

  void setup_single() {
    v = vector<int>{1};
    output = 0;
  }

  void check_single() {
    EXPECT_EQ(1, invocations_transformer);
    EXPECT_EQ(1, this->output);
  }

  void setup_multiple() {
    v = vector<int>{1,2,3,4,5};
    output = 0;
  }

  void check_multiple() {
    EXPECT_EQ(5, this->invocations_transformer);
    EXPECT_EQ(55, this->output);
  }

  void setup_single_scalar_product() {
    v = vector<int>{5};
    v2 = vector<int>{6};
    output = 0;
  }

  void check_single_scalar_product(){
    EXPECT_EQ(1, this->invocations_transformer);
    EXPECT_EQ(30, this->output);
  }

  void setup_multiple_scalar_product() {
    v = vector<int>{1,2,3,4,5};
    v2 = vector<int>{2,4,6,8,10};
    output = 0;
  }

  void check_multiple_scalar_product() {
    EXPECT_EQ(5, this->invocations_transformer);
    EXPECT_EQ(110, this->output);
  }

};

// Test for execution policies defined in supported_executions.h
TYPED_TEST_CASE(map_reduce_test, executions);

TYPED_TEST(map_reduce_test, static_single_square_sum)
{
  this->setup_single();
  this->output = this->run_square_sum(this->execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, static_single_square_sum_size)
{
  this->setup_single();
  this->output = this->run_square_sum_size(this->execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, static_single_square_sum_range)
{
  this->setup_single();
  this->output = this->run_square_sum_range(this->execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, dyn_single_square_sum)
{
  this->setup_single();
  this->output = this->run_square_sum(this->dyn_execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, dyn_single_square_sum_size)
{
  this->setup_single();
  this->output = this->run_square_sum_size(this->dyn_execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, dyn_single_square_sum_range)
{
  this->setup_single();
  this->output = this->run_square_sum_range(this->dyn_execution_);
  this->check_single();
}

TYPED_TEST(map_reduce_test, static_multiple_square_sum)
{
  this->setup_multiple();
  this->output = this->run_square_sum(this->execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, static_multiple_square_sum_size)
{
  this->setup_multiple();
  this->output = this->run_square_sum_size(this->execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, static_multiple_square_sum_range)
{
  this->setup_multiple();
  this->output = this->run_square_sum_range(this->execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, dyn_multiple_square_sum)
{
  this->setup_multiple();
  this->output = this->run_square_sum(this->dyn_execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, dyn_multiple_square_sum_size)
{
  this->setup_multiple();
  this->output = this->run_square_sum_size(this->dyn_execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, dyn_multiple_square_sum_range)
{
  this->setup_multiple();
  this->output = this->run_square_sum_range(this->dyn_execution_);
  this->check_multiple();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_iter)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_size)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_single_scalar_product_tuple_range)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_iter)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_size)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_single_scalar_product_tuple_range)
{
  this->setup_single_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->dyn_execution_);
  this->check_single_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_iter)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_size)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, static_multiple_scalar_product_tuple_range)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_iter)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_iter(this->dyn_execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_size)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_size(this->dyn_execution_);
  this->check_multiple_scalar_product();
}

TYPED_TEST(map_reduce_test, dyn_multiple_scalar_product_tuple_size_range)
{
  this->setup_multiple_scalar_product();
  this->output = this->run_scalar_product_tuple_range(this->dyn_execution_);
  this->check_multiple_scalar_product();
}
<|endoftext|>


<commit_before><commit_msg>bustage fix - file moved<commit_after><|endoftext|>


<commit_before>
#include "cmath" // For isnan(), when it's defined

#include "diff_system.h"
#include "equation_systems.h"
#include "libmesh_logging.h"
#include "linear_solver.h"
#include "newton_solver.h"
#include "numeric_vector.h"
#include "sparse_matrix.h"
#include "dof_map.h"

NewtonSolver::NewtonSolver (sys_type& s)
  : Parent(s),
    require_residual_reduction(true),
    minsteplength(1e-5),
    linear_tolerance_multiplier(1e-3),
    linear_solver(LinearSolver<Number>::build())
{
}

NewtonSolver::~NewtonSolver ()
{
}

void NewtonSolver::reinit()
{
  Parent::reinit();

  linear_solver->clear();
}

void NewtonSolver::solve()
{
  START_LOG("solve()", "NewtonSolver");

//  NumericVector<Number> &newton_iterate =
//    _system.get_vector("_nonlinear_solution");
  NumericVector<Number> &newton_iterate = *(_system.solution);

//  NumericVector<Number> &linear_solution = *(_system.solution);
  AutoPtr<NumericVector<Number> > linear_solution_ptr = newton_iterate.clone();
  NumericVector<Number> &linear_solution = *linear_solution_ptr;

  newton_iterate.close();
  linear_solution.close();

//  solution = newton_iterate;
//  _system.get_dof_map().enforce_constraints_exactly(_system);
//  newton_iterate = solution;
  _system.get_dof_map().enforce_constraints_exactly(_system);

  NumericVector<Number> &rhs = *(_system.rhs);

  SparseMatrix<Number> &matrix = *(_system.matrix);

  // Prepare to take incomplete steps
  Real last_residual=0.;

  // Set starting linear tolerance
  Real current_linear_tolerance = initial_linear_tolerance;

  // Now we begin the nonlinear loop
  for (unsigned int l=0; l<max_nonlinear_iterations; ++l)
    {
      if (!quiet)
        std::cout << "Assembling System" << std::endl;

      PAUSE_LOG("solve()", "NewtonSolver");
      _system.assembly(true, true);
      RESTART_LOG("solve()", "NewtonSolver");
      rhs.close();
      Real current_residual = rhs.l2_norm();
      last_residual = current_residual;

// isnan() isn't standard C++ yet
#ifdef isnan
      if (isnan(current_residual))
        {
          std::cout << "  Nonlinear solver DIVERGED at step " << l
                    << " with norm Not-a-Number"
                    << std::endl;
          error();
          continue;
        }
#endif // isnan

      max_residual_norm = std::max (current_residual,
                                    max_residual_norm);

      // Compute the l2 norm of the whole solution
      Real norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      if (!quiet)
        std::cout << "Nonlinear Residual: "
                  << current_residual << std::endl;

      // Make sure our linear tolerance is low enough
      current_linear_tolerance = std::min (current_linear_tolerance,
        current_residual * linear_tolerance_multiplier);

      // But don't let it be too small
      if (current_linear_tolerance < minimum_linear_tolerance)
        {
          current_linear_tolerance = minimum_linear_tolerance;
        }

      // At this point newton_iterate is the current guess, and
      // linear_solution is now about to become the NEGATIVE of the next
      // Newton step.

      // Our best initial guess for the linear_solution is zero!
      linear_solution.zero();

      if (!quiet)
        std::cout << "Linear solve starting, tolerance "
                  << current_linear_tolerance << std::endl;

      PAUSE_LOG("solve()", "NewtonSolver");
      // Solve the linear system.  Two cases:
      const std::pair<unsigned int, Real> rval =
        (_system.have_matrix("Preconditioner")) ?
      // 1.) User-supplied preconditioner
        linear_solver->solve (matrix, _system.get_matrix("Preconditioner"),
                              linear_solution, rhs, current_linear_tolerance,
                              max_linear_iterations) :
      // 2.) Use system matrix for the preconditioner
        linear_solver->solve (matrix, linear_solution, rhs,
                              current_linear_tolerance,
                              max_linear_iterations);
      // We may need to localize a parallel solution
      _system.update ();
      RESTART_LOG("solve()", "NewtonSolver");
      // The linear solver may not have fit our constraints exactly
      _system.get_dof_map().enforce_constraints_exactly(_system, &linear_solution);

      const unsigned int linear_steps = rval.first;
      assert(linear_steps <= max_linear_iterations);
      const bool linear_solve_finished =
        !(linear_steps == max_linear_iterations);

      if (!quiet)
        std::cout << "Linear solve finished, step " << linear_steps
                  << ", residual " << rval.second
                  << std::endl;

      // Compute the l2 norm of the nonlinear update
      Real norm_delta = linear_solution.l2_norm();

      if (!quiet)
        std::cout << "Trying full Newton step" << std::endl;
      // Take a full Newton step
      newton_iterate.add (-1., linear_solution);
      newton_iterate.close();

      // Check residual with full Newton step
      Real steplength = 1.;
      PAUSE_LOG("solve()", "NewtonSolver");
      _system.assembly(true, false);
      RESTART_LOG("solve()", "NewtonSolver");

      rhs.close();
      current_residual = rhs.l2_norm();

// A potential method for avoiding oversolving?
/*
      Real predicted_absolute_error =
        current_residual * norm_delta / last_residual;

      Real predicted_relative_error =
        predicted_absolute_error / max_solution_norm;

      std::cout << "Predicted absolute error = " <<
        predicted_absolute_error << std::endl;

      std::cout << "Predicted relative error = " <<
        predicted_relative_error << std::endl;
*/

      // backtrack if necessary
      if (require_residual_reduction)
        {
          // but don't fiddle around if we've already converged
          if (test_convergence(current_residual, norm_delta,
                               linear_solve_finished))
            {
              if (!quiet)
		print_convergence(l, current_residual, norm_delta,
                                  linear_solve_finished);
              break;
            }

          while (current_residual > last_residual)
            {
              // Reduce step size to 1/2, 1/4, etc.
              steplength /= 2.;
              norm_delta /= 2.;
              if (!quiet)
                std::cout << "Shrinking Newton step to "
                          << steplength << std::endl;
              newton_iterate.add (steplength, linear_solution);
              newton_iterate.close();

              // Check residual with fractional Newton step
              PAUSE_LOG("solve()", "NewtonSolver");
              _system.assembly (true, false);
              RESTART_LOG("solve()", "NewtonSolver");

              rhs.close();
              current_residual = rhs.l2_norm();
              if (!quiet)
                std::cout << "Current Residual: "
                          << current_residual << std::endl;

              if (steplength/2. < minsteplength &&
                  current_residual > last_residual)
                {
                  std::cout << "Inexact Newton step FAILED at step "
                            << l << std::endl;

                  error();
                }
            }
        }

      // Compute the l2 norm of the whole solution
      norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      // Print out information for the
      // nonlinear iterations.
      if (!quiet)
        std::cout << "  Nonlinear step: |du|/|u| = "
                  << norm_delta / norm_total
                  << ", |du| = " << norm_delta
                  << std::endl;

      // Terminate the solution iteration if the difference between
      // this iteration and the last is sufficiently small.
      if (!quiet)
        print_convergence(l, current_residual,
                          norm_delta / steplength,
                          linear_solve_finished);
      if (test_convergence(current_residual, norm_delta / steplength,
                           linear_solve_finished))
        {
          break;
        }
      if (l >= max_nonlinear_iterations - 1)
        {
          std::cout << "  Nonlinear solver FAILED TO CONVERGE by step " << l
                    << " with norm " << norm_total
                    << std::endl;
          if (continue_after_max_iterations)
            std::cout << "  Continuing anyway..." << std::endl;
          else
            error();
          continue;
        }
    } // end nonlinear loop

  // Copy the final nonlinear iterate into the current_solution,
  // for other libMesh functions that expect it

//  solution = newton_iterate;
//  solution.close();

  // The linear solver may not have fit our constraints exactly
  _system.get_dof_map().enforce_constraints_exactly(_system);
//  newton_iterate = solution;
//  solution.close();

  // We may need to localize a parallel solution
  _system.update ();

  STOP_LOG("solve()", "NewtonSolver");
}

bool NewtonSolver::test_convergence(Real current_residual,
                                    Real step_norm,
                                    bool linear_solve_finished)
{
  // We haven't converged unless we pass a convergence test
  bool has_converged = false;

  // Is our absolute residual low enough?
  if (current_residual < absolute_residual_tolerance)
    has_converged = true;

  // Is our relative residual low enough?
  if ((current_residual / max_residual_norm) <
      relative_residual_tolerance)
    has_converged = true;

  // For incomplete linear solves, it's not safe to test step sizes
  if (!linear_solve_finished)
    return has_converged;

  // Is our absolute Newton step size small enough?
  if (step_norm < absolute_step_tolerance)
    has_converged = true;

  // Is our relative Newton step size small enough?
  if (step_norm / max_solution_norm <
      relative_step_tolerance)
    has_converged = true;

  return has_converged;
}

void NewtonSolver::print_convergence(unsigned int step_num,
                                     Real current_residual,
                                     Real step_norm,
                                     bool linear_solve_finished)
{
  // Is our absolute residual low enough?
  if (current_residual < absolute_residual_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", residual " << current_residual
                << std::endl;
    }
  else if (absolute_residual_tolerance)
    {
      std::cout << "  Nonlinear solver current_residual "
                << current_residual << " > "
                << (absolute_residual_tolerance) << std::endl;
    }

  // Is our relative residual low enough?
  if ((current_residual / max_residual_norm) <
      relative_residual_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", residual reduction "
                << current_residual / max_residual_norm
                << " < " << relative_residual_tolerance
                << std::endl;
    }
  else if (relative_residual_tolerance)
    {
      if (!quiet)
        std::cout << "  Nonlinear solver relative residual "
                  << (current_residual / max_residual_norm)
                  << " > " << relative_residual_tolerance
                  << std::endl;
    }

  // For incomplete linear solves, it's not safe to test step sizes
  if (!linear_solve_finished)
    return;

  // Is our absolute Newton step size small enough?
  if (step_norm < absolute_step_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", absolute step size "
                << step_norm
                << " < " << absolute_step_tolerance
                << std::endl;
    }
  else if (absolute_step_tolerance)
    {
      std::cout << "  Nonlinear solver absolute step size "
                << step_norm
                << " > " << absolute_step_tolerance
                << std::endl;
    }

  // Is our relative Newton step size small enough?
  if (step_norm / max_solution_norm <
      relative_step_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", relative step size "
                << (step_norm / max_solution_norm)
                << " < " << relative_step_tolerance
                << std::endl;
    }
  else if (relative_step_tolerance)
    {
      std::cout << "  Nonlinear solver relative step size "
                << (step_norm / max_solution_norm)
                << " > " << relative_step_tolerance
                << std::endl;
    }
}
<commit_msg>Print post-Newton-step residuals when solver.quiet is off<commit_after>
#include "cmath" // For isnan(), when it's defined

#include "diff_system.h"
#include "equation_systems.h"
#include "libmesh_logging.h"
#include "linear_solver.h"
#include "newton_solver.h"
#include "numeric_vector.h"
#include "sparse_matrix.h"
#include "dof_map.h"

NewtonSolver::NewtonSolver (sys_type& s)
  : Parent(s),
    require_residual_reduction(true),
    minsteplength(1e-5),
    linear_tolerance_multiplier(1e-3),
    linear_solver(LinearSolver<Number>::build())
{
}

NewtonSolver::~NewtonSolver ()
{
}

void NewtonSolver::reinit()
{
  Parent::reinit();

  linear_solver->clear();
}

void NewtonSolver::solve()
{
  START_LOG("solve()", "NewtonSolver");

//  NumericVector<Number> &newton_iterate =
//    _system.get_vector("_nonlinear_solution");
  NumericVector<Number> &newton_iterate = *(_system.solution);

//  NumericVector<Number> &linear_solution = *(_system.solution);
  AutoPtr<NumericVector<Number> > linear_solution_ptr = newton_iterate.clone();
  NumericVector<Number> &linear_solution = *linear_solution_ptr;

  newton_iterate.close();
  linear_solution.close();

//  solution = newton_iterate;
//  _system.get_dof_map().enforce_constraints_exactly(_system);
//  newton_iterate = solution;
  _system.get_dof_map().enforce_constraints_exactly(_system);

  NumericVector<Number> &rhs = *(_system.rhs);

  SparseMatrix<Number> &matrix = *(_system.matrix);

  // Prepare to take incomplete steps
  Real last_residual=0.;

  // Set starting linear tolerance
  Real current_linear_tolerance = initial_linear_tolerance;

  // Now we begin the nonlinear loop
  for (unsigned int l=0; l<max_nonlinear_iterations; ++l)
    {
      if (!quiet)
        std::cout << "Assembling System" << std::endl;

      PAUSE_LOG("solve()", "NewtonSolver");
      _system.assembly(true, true);
      RESTART_LOG("solve()", "NewtonSolver");
      rhs.close();
      Real current_residual = rhs.l2_norm();
      last_residual = current_residual;

// isnan() isn't standard C++ yet
#ifdef isnan
      if (isnan(current_residual))
        {
          std::cout << "  Nonlinear solver DIVERGED at step " << l
                    << " with norm Not-a-Number"
                    << std::endl;
          error();
          continue;
        }
#endif // isnan

      max_residual_norm = std::max (current_residual,
                                    max_residual_norm);

      // Compute the l2 norm of the whole solution
      Real norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      if (!quiet)
        std::cout << "Nonlinear Residual: "
                  << current_residual << std::endl;

      // Make sure our linear tolerance is low enough
      current_linear_tolerance = std::min (current_linear_tolerance,
        current_residual * linear_tolerance_multiplier);

      // But don't let it be too small
      if (current_linear_tolerance < minimum_linear_tolerance)
        {
          current_linear_tolerance = minimum_linear_tolerance;
        }

      // At this point newton_iterate is the current guess, and
      // linear_solution is now about to become the NEGATIVE of the next
      // Newton step.

      // Our best initial guess for the linear_solution is zero!
      linear_solution.zero();

      if (!quiet)
        std::cout << "Linear solve starting, tolerance "
                  << current_linear_tolerance << std::endl;

      PAUSE_LOG("solve()", "NewtonSolver");
      // Solve the linear system.  Two cases:
      const std::pair<unsigned int, Real> rval =
        (_system.have_matrix("Preconditioner")) ?
      // 1.) User-supplied preconditioner
        linear_solver->solve (matrix, _system.get_matrix("Preconditioner"),
                              linear_solution, rhs, current_linear_tolerance,
                              max_linear_iterations) :
      // 2.) Use system matrix for the preconditioner
        linear_solver->solve (matrix, linear_solution, rhs,
                              current_linear_tolerance,
                              max_linear_iterations);
      // We may need to localize a parallel solution
      _system.update ();
      RESTART_LOG("solve()", "NewtonSolver");
      // The linear solver may not have fit our constraints exactly
      _system.get_dof_map().enforce_constraints_exactly(_system, &linear_solution);

      const unsigned int linear_steps = rval.first;
      assert(linear_steps <= max_linear_iterations);
      const bool linear_solve_finished =
        !(linear_steps == max_linear_iterations);

      if (!quiet)
        std::cout << "Linear solve finished, step " << linear_steps
                  << ", residual " << rval.second
                  << std::endl;

      // Compute the l2 norm of the nonlinear update
      Real norm_delta = linear_solution.l2_norm();

      if (!quiet)
        std::cout << "Trying full Newton step" << std::endl;
      // Take a full Newton step
      newton_iterate.add (-1., linear_solution);
      newton_iterate.close();

      // Check residual with full Newton step
      Real steplength = 1.;
      PAUSE_LOG("solve()", "NewtonSolver");
      _system.assembly(true, false);
      RESTART_LOG("solve()", "NewtonSolver");

      rhs.close();
      current_residual = rhs.l2_norm();
      if (!quiet)
        std::cout << "  Current Residual: "
                  << current_residual << std::endl;

// A potential method for avoiding oversolving?
/*
      Real predicted_absolute_error =
        current_residual * norm_delta / last_residual;

      Real predicted_relative_error =
        predicted_absolute_error / max_solution_norm;

      std::cout << "Predicted absolute error = " <<
        predicted_absolute_error << std::endl;

      std::cout << "Predicted relative error = " <<
        predicted_relative_error << std::endl;
*/

      // backtrack if necessary
      if (require_residual_reduction)
        {
          // but don't fiddle around if we've already converged
          if (test_convergence(current_residual, norm_delta,
                               linear_solve_finished))
            {
              if (!quiet)
		print_convergence(l, current_residual, norm_delta,
                                  linear_solve_finished);
              break;
            }

          while (current_residual > last_residual)
            {
              // Reduce step size to 1/2, 1/4, etc.
              steplength /= 2.;
              norm_delta /= 2.;
              if (!quiet)
                std::cout << "  Shrinking Newton step to "
                          << steplength << std::endl;
              newton_iterate.add (steplength, linear_solution);
              newton_iterate.close();

              // Check residual with fractional Newton step
              PAUSE_LOG("solve()", "NewtonSolver");
              _system.assembly (true, false);
              RESTART_LOG("solve()", "NewtonSolver");

              rhs.close();
              current_residual = rhs.l2_norm();
              if (!quiet)
                std::cout << "  Current Residual: "
                          << current_residual << std::endl;

              if (steplength/2. < minsteplength &&
                  current_residual > last_residual)
                {
                  std::cout << "Inexact Newton step FAILED at step "
                            << l << std::endl;

                  error();
                }
            }
        }

      // Compute the l2 norm of the whole solution
      norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      // Print out information for the
      // nonlinear iterations.
      if (!quiet)
        std::cout << "  Nonlinear step: |du|/|u| = "
                  << norm_delta / norm_total
                  << ", |du| = " << norm_delta
                  << std::endl;

      // Terminate the solution iteration if the difference between
      // this iteration and the last is sufficiently small.
      if (!quiet)
        print_convergence(l, current_residual,
                          norm_delta / steplength,
                          linear_solve_finished);
      if (test_convergence(current_residual, norm_delta / steplength,
                           linear_solve_finished))
        {
          break;
        }
      if (l >= max_nonlinear_iterations - 1)
        {
          std::cout << "  Nonlinear solver FAILED TO CONVERGE by step " << l
                    << " with norm " << norm_total
                    << std::endl;
          if (continue_after_max_iterations)
            std::cout << "  Continuing anyway..." << std::endl;
          else
            error();
          continue;
        }
    } // end nonlinear loop

  // Copy the final nonlinear iterate into the current_solution,
  // for other libMesh functions that expect it

//  solution = newton_iterate;
//  solution.close();

  // The linear solver may not have fit our constraints exactly
  _system.get_dof_map().enforce_constraints_exactly(_system);
//  newton_iterate = solution;
//  solution.close();

  // We may need to localize a parallel solution
  _system.update ();

  STOP_LOG("solve()", "NewtonSolver");
}

bool NewtonSolver::test_convergence(Real current_residual,
                                    Real step_norm,
                                    bool linear_solve_finished)
{
  // We haven't converged unless we pass a convergence test
  bool has_converged = false;

  // Is our absolute residual low enough?
  if (current_residual < absolute_residual_tolerance)
    has_converged = true;

  // Is our relative residual low enough?
  if ((current_residual / max_residual_norm) <
      relative_residual_tolerance)
    has_converged = true;

  // For incomplete linear solves, it's not safe to test step sizes
  if (!linear_solve_finished)
    return has_converged;

  // Is our absolute Newton step size small enough?
  if (step_norm < absolute_step_tolerance)
    has_converged = true;

  // Is our relative Newton step size small enough?
  if (step_norm / max_solution_norm <
      relative_step_tolerance)
    has_converged = true;

  return has_converged;
}

void NewtonSolver::print_convergence(unsigned int step_num,
                                     Real current_residual,
                                     Real step_norm,
                                     bool linear_solve_finished)
{
  // Is our absolute residual low enough?
  if (current_residual < absolute_residual_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", residual " << current_residual
                << std::endl;
    }
  else if (absolute_residual_tolerance)
    {
      std::cout << "  Nonlinear solver current_residual "
                << current_residual << " > "
                << (absolute_residual_tolerance) << std::endl;
    }

  // Is our relative residual low enough?
  if ((current_residual / max_residual_norm) <
      relative_residual_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", residual reduction "
                << current_residual / max_residual_norm
                << " < " << relative_residual_tolerance
                << std::endl;
    }
  else if (relative_residual_tolerance)
    {
      if (!quiet)
        std::cout << "  Nonlinear solver relative residual "
                  << (current_residual / max_residual_norm)
                  << " > " << relative_residual_tolerance
                  << std::endl;
    }

  // For incomplete linear solves, it's not safe to test step sizes
  if (!linear_solve_finished)
    return;

  // Is our absolute Newton step size small enough?
  if (step_norm < absolute_step_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", absolute step size "
                << step_norm
                << " < " << absolute_step_tolerance
                << std::endl;
    }
  else if (absolute_step_tolerance)
    {
      std::cout << "  Nonlinear solver absolute step size "
                << step_norm
                << " > " << absolute_step_tolerance
                << std::endl;
    }

  // Is our relative Newton step size small enough?
  if (step_norm / max_solution_norm <
      relative_step_tolerance)
    {
      std::cout << "  Nonlinear solver converged, step " << step_num
                << ", relative step size "
                << (step_norm / max_solution_norm)
                << " < " << relative_step_tolerance
                << std::endl;
    }
  else if (relative_step_tolerance)
    {
      std::cout << "  Nonlinear solver relative step size "
                << (step_norm / max_solution_norm)
                << " > " << relative_step_tolerance
                << std::endl;
    }
}
<|endoftext|>


<commit_before>
#include "diff_system.h"
#include "equation_systems.h"
#include "linear_solver.h"
#include "newton_solver.h"
#include "numeric_vector.h"
#include "sparse_matrix.h"

NewtonSolver::NewtonSolver (sys_type& s) :
  Parent(s), linear_solver(LinearSolver<Number>::build())
{
}

NewtonSolver::~NewtonSolver ()
{
}

void NewtonSolver::solve()
{
// The number of steps and the stopping criterion
// for the nonlinear iterations.
const unsigned int max_nonlinear_steps = 100;
const unsigned int max_linear_iterations = 10000;

// Stopping criteria for nonlinear iterations
const Real nonlinear_abs_step_tolerance = 1.e-9;
const Real nonlinear_rel_step_tolerance = 1.e-6;
const Real nonlinear_abs_res_tolerance = 1.e-9;
const Real nonlinear_rel_res_tolerance = 1.e-6;
// Maximum amount by which to reduce Newton steps
const Real minsteplength = 0.1;
// Initial linear solver tolerance in main nonlinear solver
const Real linear_tolerance = 1.e-3;
// Amount by which nonlinear residual should exceed linear solver
// tolerance
const Real relative_tolerance = 1.e-3;
// We'll shut up eventually...
const bool verbose_convergence_chatter = true;
const bool require_residual_reduction = false;

  EquationSystems &equation_systems = _system.get_equation_systems();

  equation_systems.parameters.set<unsigned int>
                   ("linear solver maximum iterations") =
                   max_linear_iterations;

  NumericVector<Number> &solution = *(_system.solution);
  NumericVector<Number> &newton_iterate =
    _system.get_vector("_nonlinear_solution");
  NumericVector<Number> &rhs = *(_system.rhs);

  SparseMatrix<Number> &matrix = *(_system.matrix);

  // Now we begin the nonlinear loop
  newton_iterate.zero();
  newton_iterate.close();

  // Prepare to take incomplete steps
  Real last_residual, first_residual;

  // Set starting linear tolerance
  Real current_linear_tolerance = linear_tolerance;

  for (unsigned int l=0; l<max_nonlinear_steps; ++l)
    {
      _system.assembly(true, true);
      rhs.close();
      Real current_residual = rhs.l2_norm();
      if (!l)
        first_residual = current_residual;
      last_residual = current_residual;
std::cout << "Nonlinear Residual: " << current_residual << std::endl;

      // Make sure our linear tolerance is low enough
      if (current_linear_tolerance > current_residual * relative_tolerance)
        {
          current_linear_tolerance = current_residual * relative_tolerance;
          equation_systems.parameters.set<Real>
            ("linear solver tolerance") = current_linear_tolerance;
        }

      // At this point newton_iterate is the current guess, and
      // solution is now about to become the NEGATIVE of the next
      // Newton step

std::cout << "Linear solve starting" << std::endl;

      // Solve the linear system.  Two cases:
      const std::pair<unsigned int, Real> rval =
        (_system.have_matrix("Preconditioner")) ?
      // 1.) User-supplied preconditioner
        linear_solver->solve (matrix, _system.get_matrix("Preconditioner"),
                              solution, rhs, current_linear_tolerance,
                              max_linear_iterations) :
      // 2.) Use system matrix for the preconditioner
        linear_solver->solve (matrix, solution, rhs,
                              current_linear_tolerance,
                              max_linear_iterations);

std::cout << "Linear solve converged, step " << rval.first
          << ", residual " << rval.second
          << ", tolerance " << current_linear_tolerance << std::endl;

      // Compute the l2 norm of the nonlinear update
      Real norm_delta = solution.l2_norm();

std::cout << "Taking full Newton step" << std::endl;
          // Take a full Newton step
      newton_iterate.add (-1., solution);
      newton_iterate.close();

      // Check residual with full Newton step
      Real steplength = 1.;
      _system.assembly(true, false);

      // backtrack if necessary
      if (require_residual_reduction)
        {
          rhs.close();
          current_residual = rhs.l2_norm();
          while (current_residual > last_residual)
            {
              // Reduce step size to 1/2, 1/4, etc.
              steplength /= 2.;
              norm_delta /= 2.;
std::cout << "Shrinking Newton step to " << steplength << std::endl;
              newton_iterate.add (steplength, solution);
              newton_iterate.close();

              // Check residual with fractional Newton step
              std::cout << "          Checking " << std::flush;
              _system.assembly (true, false);
              current_residual = rhs.l2_norm();
              std::cout << "Current Residual: " << current_residual << std::endl;

              if (steplength/2. < minsteplength &&
                  current_residual > last_residual)
                {
std::cout << "Inexact Newton step FAILED at step " << l << std::endl;

                  error();
                }
            }
        }

      // Compute the l2 norm of the whole solution
      const Real norm_total = newton_iterate.l2_norm();

      // Print out information for the
      // nonlinear iterations.
      std::cout << "    Nonlinear step: |du|/|u| = "
                << norm_delta / norm_total
                << ", |du| = "
                << norm_delta
                << std::endl;

      // We haven't converged unless we pass a convergence test
      bool has_converged = false;

      // Is our absolute residual low enough?
      if (current_residual < nonlinear_abs_res_tolerance)
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", residual "
                    << current_residual
                    << std::endl;
          has_converged = true;
        }
      else if (verbose_convergence_chatter)
        {
          std::cout << "  Nonlinear solver current_residual "
                    << current_residual
                    << " > "
                    << (nonlinear_abs_res_tolerance)
                    << std::endl;
        }

      // Is our relative residual low enough?
      if ((current_residual / first_residual) < nonlinear_rel_res_tolerance)
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", residual reduction "
                    << current_residual / first_residual
                    << std::endl;
          has_converged = true;
        }
      else if (verbose_convergence_chatter)
        {
          std::cout << "  Nonlinear solver current/first residual "
                    << (current_residual / first_residual)
                    << " > "
                    << nonlinear_rel_res_tolerance
                    << std::endl;
        }

      // Is our absolute Newton step size small enough?
      if (l != 0 && (norm_delta / steplength <
          nonlinear_abs_step_tolerance))
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", absolute step size "
                    << norm_delta / steplength
                    << std::endl;
          has_converged = true;
        }

      // Is our relative Newton step size small enough?
      if (l != 0 && (norm_delta / steplength / norm_total <
          nonlinear_rel_step_tolerance))
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", relative step size "
                    << (norm_delta / steplength / norm_total)
                    << std::endl;
          has_converged = true;
        }

      // Terminate the solution iteration if the difference between
      // this iteration and the last is sufficiently small.
      if (has_converged)
        {
          break;
        }
      if (l >= max_nonlinear_steps - 1)
        {
          std::cout << "  Nonlinear solver DIVERGED at step "
                    << l
                    << std::endl;
          error();
          continue;
        }
    } // end nonlinear loop
}
<commit_msg>Initialized variables to get rid of overzealous GCC warning.<commit_after>
#include "diff_system.h"
#include "equation_systems.h"
#include "linear_solver.h"
#include "newton_solver.h"
#include "numeric_vector.h"
#include "sparse_matrix.h"

NewtonSolver::NewtonSolver (sys_type& s) :
  Parent(s), linear_solver(LinearSolver<Number>::build())
{
}

NewtonSolver::~NewtonSolver ()
{
}

void NewtonSolver::solve()
{
// The number of steps and the stopping criterion
// for the nonlinear iterations.
const unsigned int max_nonlinear_steps = 100;
const unsigned int max_linear_iterations = 10000;

// Stopping criteria for nonlinear iterations
const Real nonlinear_abs_step_tolerance = 1.e-9;
const Real nonlinear_rel_step_tolerance = 1.e-6;
const Real nonlinear_abs_res_tolerance = 1.e-9;
const Real nonlinear_rel_res_tolerance = 1.e-6;
// Maximum amount by which to reduce Newton steps
const Real minsteplength = 0.1;
// Initial linear solver tolerance in main nonlinear solver
const Real linear_tolerance = 1.e-3;
// Amount by which nonlinear residual should exceed linear solver
// tolerance
const Real relative_tolerance = 1.e-3;
// We'll shut up eventually...
const bool verbose_convergence_chatter = true;
const bool require_residual_reduction = false;

  EquationSystems &equation_systems = _system.get_equation_systems();

  equation_systems.parameters.set<unsigned int>
                   ("linear solver maximum iterations") =
                   max_linear_iterations;

  NumericVector<Number> &solution = *(_system.solution);
  NumericVector<Number> &newton_iterate =
    _system.get_vector("_nonlinear_solution");
  NumericVector<Number> &rhs = *(_system.rhs);

  SparseMatrix<Number> &matrix = *(_system.matrix);

  // Now we begin the nonlinear loop
  newton_iterate.zero();
  newton_iterate.close();

  // Prepare to take incomplete steps
  Real last_residual=0., first_residual=0.;

  // Set starting linear tolerance
  Real current_linear_tolerance = linear_tolerance;

  for (unsigned int l=0; l<max_nonlinear_steps; ++l)
    {
      _system.assembly(true, true);
      rhs.close();
      Real current_residual = rhs.l2_norm();
      if (!l)
        first_residual = current_residual;
      last_residual = current_residual;
std::cout << "Nonlinear Residual: " << current_residual << std::endl;

      // Make sure our linear tolerance is low enough
      if (current_linear_tolerance > current_residual * relative_tolerance)
        {
          current_linear_tolerance = current_residual * relative_tolerance;
          equation_systems.parameters.set<Real>
            ("linear solver tolerance") = current_linear_tolerance;
        }

      // At this point newton_iterate is the current guess, and
      // solution is now about to become the NEGATIVE of the next
      // Newton step

std::cout << "Linear solve starting" << std::endl;

      // Solve the linear system.  Two cases:
      const std::pair<unsigned int, Real> rval =
        (_system.have_matrix("Preconditioner")) ?
      // 1.) User-supplied preconditioner
        linear_solver->solve (matrix, _system.get_matrix("Preconditioner"),
                              solution, rhs, current_linear_tolerance,
                              max_linear_iterations) :
      // 2.) Use system matrix for the preconditioner
        linear_solver->solve (matrix, solution, rhs,
                              current_linear_tolerance,
                              max_linear_iterations);

std::cout << "Linear solve converged, step " << rval.first
          << ", residual " << rval.second
          << ", tolerance " << current_linear_tolerance << std::endl;

      // Compute the l2 norm of the nonlinear update
      Real norm_delta = solution.l2_norm();

std::cout << "Taking full Newton step" << std::endl;
          // Take a full Newton step
      newton_iterate.add (-1., solution);
      newton_iterate.close();

      // Check residual with full Newton step
      Real steplength = 1.;
      _system.assembly(true, false);

      // backtrack if necessary
      if (require_residual_reduction)
        {
          rhs.close();
          current_residual = rhs.l2_norm();
          while (current_residual > last_residual)
            {
              // Reduce step size to 1/2, 1/4, etc.
              steplength /= 2.;
              norm_delta /= 2.;
std::cout << "Shrinking Newton step to " << steplength << std::endl;
              newton_iterate.add (steplength, solution);
              newton_iterate.close();

              // Check residual with fractional Newton step
              std::cout << "          Checking " << std::flush;
              _system.assembly (true, false);
              current_residual = rhs.l2_norm();
              std::cout << "Current Residual: " << current_residual << std::endl;

              if (steplength/2. < minsteplength &&
                  current_residual > last_residual)
                {
std::cout << "Inexact Newton step FAILED at step " << l << std::endl;

                  error();
                }
            }
        }

      // Compute the l2 norm of the whole solution
      const Real norm_total = newton_iterate.l2_norm();

      // Print out information for the
      // nonlinear iterations.
      std::cout << "    Nonlinear step: |du|/|u| = "
                << norm_delta / norm_total
                << ", |du| = "
                << norm_delta
                << std::endl;

      // We haven't converged unless we pass a convergence test
      bool has_converged = false;

      // Is our absolute residual low enough?
      if (current_residual < nonlinear_abs_res_tolerance)
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", residual "
                    << current_residual
                    << std::endl;
          has_converged = true;
        }
      else if (verbose_convergence_chatter)
        {
          std::cout << "  Nonlinear solver current_residual "
                    << current_residual
                    << " > "
                    << (nonlinear_abs_res_tolerance)
                    << std::endl;
        }

      // Is our relative residual low enough?
      if ((current_residual / first_residual) < nonlinear_rel_res_tolerance)
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", residual reduction "
                    << current_residual / first_residual
                    << std::endl;
          has_converged = true;
        }
      else if (verbose_convergence_chatter)
        {
          std::cout << "  Nonlinear solver current/first residual "
                    << (current_residual / first_residual)
                    << " > "
                    << nonlinear_rel_res_tolerance
                    << std::endl;
        }

      // Is our absolute Newton step size small enough?
      if (l != 0 && (norm_delta / steplength <
          nonlinear_abs_step_tolerance))
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", absolute step size "
                    << norm_delta / steplength
                    << std::endl;
          has_converged = true;
        }

      // Is our relative Newton step size small enough?
      if (l != 0 && (norm_delta / steplength / norm_total <
          nonlinear_rel_step_tolerance))
        {
          std::cout << "  Nonlinear solver converged, step "
                    << l
                    << ", relative step size "
                    << (norm_delta / steplength / norm_total)
                    << std::endl;
          has_converged = true;
        }

      // Terminate the solution iteration if the difference between
      // this iteration and the last is sufficiently small.
      if (has_converged)
        {
          break;
        }
      if (l >= max_nonlinear_steps - 1)
        {
          std::cout << "  Nonlinear solver DIVERGED at step "
                    << l
                    << std::endl;
          error();
          continue;
        }
    } // end nonlinear loop
}
<|endoftext|>


<commit_before>#include "shader.h"
#include "mesh.h"
#include "texture.h"

#include <glm/gtc/type_ptr.hpp>

#include <stdexcept>
#include <fstream>

namespace te
{
    std::string getShaderLog(GLuint shader)
    {
        if (!glIsShader(shader))
        {
            throw std::runtime_error("Passed ID is not a shader.");
        }

        int infoLogLength = 0;
        int maxLength = 0;

        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

        char* infoLog = new char[maxLength];

        glGetShaderInfoLog(shader, maxLength, &infoLogLength, infoLog);
        if (infoLogLength > 0)
        {
            std::string log{ infoLog };
            delete[] infoLog;
            return log;
        }
        else
        {
            return{ "" };
        }
    }

    std::string getProgramLog(GLuint program)
    {
        if (!glIsProgram(program))
        {
            throw std::runtime_error("Passed ID is not a program.");
        }

        int infoLogLength = 0;
        int maxLength = 0;

        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

        char* infoLog = new char[maxLength];

        glGetProgramInfoLog(program, maxLength, &infoLogLength, infoLog);
        if (infoLogLength > 0)
        {
            std::string log{ infoLog };
            delete[] infoLog;
            return log;
        }
        else
        {
            return{ "" };
        }
    }

    GLuint loadShader(const std::string& path, GLenum shaderType)
    {
        GLuint shaderID = 0;
        std::string shaderString;
        std::ifstream srcFile(path.c_str());

        if (!srcFile) { throw std::runtime_error("Unable to open file."); }

        shaderString.assign(std::istreambuf_iterator<char>(srcFile), std::istreambuf_iterator<char>());
        shaderID = glCreateShader(shaderType);

        const GLchar* shaderSrc = shaderString.c_str();
        glShaderSource(shaderID, 1, (const GLchar**)&shaderSrc, NULL);

        glCompileShader(shaderID);

        GLint shaderCompiled = GL_FALSE;
        glGetShaderiv(shaderID, GL_COMPILE_STATUS, &shaderCompiled);

        if (shaderCompiled != GL_TRUE)
        {
            std::string msg{ getShaderLog(shaderID) };
            glDeleteShader(shaderID);
            throw std::runtime_error(msg);
        }

        return shaderID;
    }

    GLuint loadProgram(const std::string& vertexShaderPath, const std::string& fragmentShaderPath)
    {
        GLuint program = glCreateProgram();
        GLuint vertexShader = 0;
        GLuint fragmentShader = 0;

        try
        {
            vertexShader = loadShader(vertexShaderPath, GL_VERTEX_SHADER);

            glAttachShader(program, vertexShader);

            fragmentShader = loadShader(fragmentShaderPath, GL_FRAGMENT_SHADER);

            glAttachShader(program, fragmentShader);

            glLinkProgram(program);

            GLint programSuccess = GL_TRUE;
            glGetProgramiv(program, GL_LINK_STATUS, &programSuccess);
            if (programSuccess != GL_TRUE)
            {
                throw std::runtime_error(getProgramLog(program));
            }

            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
        }
        catch (std::exception e)
        {
            glDeleteProgram(program);
            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
            throw std::runtime_error(e.what());
        }

        return program;
    }

    Shader::Shader(const glm::mat4& projection, const glm::mat4& model)
        : mProgram(loadProgram("shaders/basic.glvs", "shaders/basic.glfs"))
        , mViewLocation(glGetUniformLocation(mProgram, "te_ViewMatrix"))
        , mLastView()
        , mModel(model)
    {
        glUseProgram(mProgram);

        GLint projectionMatrixLocation = glGetUniformLocation(mProgram, "te_ProjectionMatrix");
        if (projectionMatrixLocation == -1) { throw std::runtime_error("te_ProjectionMatrix: not a valid program variable."); }
        glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection));

        if (mViewLocation == -1) { throw std::runtime_error{ "te_ViewMatrix: not a valid program variable." }; }
        glUniformMatrix4fv(mViewLocation, 1, GL_FALSE, glm::value_ptr(mLastView));

        GLint modelMatrixLocation = glGetUniformLocation(mProgram, "te_ModelMatrix");
        if (modelMatrixLocation == -1) { throw std::runtime_error("te_ModelMatrix: not a valid program variable."); }
        glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(model));
    }

    void Shader::destroy()
    {
        glDeleteProgram(mProgram);
    }

    Shader::~Shader()
    {
        destroy();
    }

    Shader::Shader(Shader&& o)
        : mProgram(o.mProgram)
        , mLastView(o.mLastView)
    {
        o.mProgram = 0;
    }

    Shader& Shader::operator=(Shader&& o)
    {
        destroy();

        mProgram = o.mProgram;
        mLastView = o.mLastView;
        o.mProgram = 0;

        return *this;
    }

    glm::mat4 Shader::getModel() const
    {
        return mModel;
    }

    void Shader::draw(const glm::mat4& view, const Mesh& mesh)
    {
        glUseProgram(mProgram);

        if (view != mLastView) {
            glUniformMatrix4fv(mViewLocation, 1, GL_FALSE, glm::value_ptr(view));
            mLastView = view;
        }

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mesh.getTexture(0)->getID());
        glBindVertexArray(mesh.getVAO());
        glDrawElements(GL_TRIANGLES, mesh.getElementCount(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glUseProgram(0);
    }
}
<commit_msg>Add "assets/" to shader path<commit_after>#include "shader.h"
#include "mesh.h"
#include "texture.h"

#include <glm/gtc/type_ptr.hpp>

#include <stdexcept>
#include <fstream>

namespace te
{
    std::string getShaderLog(GLuint shader)
    {
        if (!glIsShader(shader))
        {
            throw std::runtime_error("Passed ID is not a shader.");
        }

        int infoLogLength = 0;
        int maxLength = 0;

        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);

        char* infoLog = new char[maxLength];

        glGetShaderInfoLog(shader, maxLength, &infoLogLength, infoLog);
        if (infoLogLength > 0)
        {
            std::string log{ infoLog };
            delete[] infoLog;
            return log;
        }
        else
        {
            return{ "" };
        }
    }

    std::string getProgramLog(GLuint program)
    {
        if (!glIsProgram(program))
        {
            throw std::runtime_error("Passed ID is not a program.");
        }

        int infoLogLength = 0;
        int maxLength = 0;

        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

        char* infoLog = new char[maxLength];

        glGetProgramInfoLog(program, maxLength, &infoLogLength, infoLog);
        if (infoLogLength > 0)
        {
            std::string log{ infoLog };
            delete[] infoLog;
            return log;
        }
        else
        {
            return{ "" };
        }
    }

    GLuint loadShader(const std::string& path, GLenum shaderType)
    {
        GLuint shaderID = 0;
        std::string shaderString;
        std::ifstream srcFile(path.c_str());

        if (!srcFile) { throw std::runtime_error("Unable to open file."); }

        shaderString.assign(std::istreambuf_iterator<char>(srcFile), std::istreambuf_iterator<char>());
        shaderID = glCreateShader(shaderType);

        const GLchar* shaderSrc = shaderString.c_str();
        glShaderSource(shaderID, 1, (const GLchar**)&shaderSrc, NULL);

        glCompileShader(shaderID);

        GLint shaderCompiled = GL_FALSE;
        glGetShaderiv(shaderID, GL_COMPILE_STATUS, &shaderCompiled);

        if (shaderCompiled != GL_TRUE)
        {
            std::string msg{ getShaderLog(shaderID) };
            glDeleteShader(shaderID);
            throw std::runtime_error(msg);
        }

        return shaderID;
    }

    GLuint loadProgram(const std::string& vertexShaderPath, const std::string& fragmentShaderPath)
    {
        GLuint program = glCreateProgram();
        GLuint vertexShader = 0;
        GLuint fragmentShader = 0;

        try
        {
            vertexShader = loadShader(vertexShaderPath, GL_VERTEX_SHADER);

            glAttachShader(program, vertexShader);

            fragmentShader = loadShader(fragmentShaderPath, GL_FRAGMENT_SHADER);

            glAttachShader(program, fragmentShader);

            glLinkProgram(program);

            GLint programSuccess = GL_TRUE;
            glGetProgramiv(program, GL_LINK_STATUS, &programSuccess);
            if (programSuccess != GL_TRUE)
            {
                throw std::runtime_error(getProgramLog(program));
            }

            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
        }
        catch (std::exception e)
        {
            glDeleteProgram(program);
            glDeleteShader(vertexShader);
            glDeleteShader(fragmentShader);
            throw std::runtime_error(e.what());
        }

        return program;
    }

    Shader::Shader(const glm::mat4& projection, const glm::mat4& model)
        : mProgram(loadProgram("assets/shaders/basic.glvs", "assets/shaders/basic.glfs"))
        , mViewLocation(glGetUniformLocation(mProgram, "te_ViewMatrix"))
        , mLastView()
        , mModel(model)
    {
        glUseProgram(mProgram);

        GLint projectionMatrixLocation = glGetUniformLocation(mProgram, "te_ProjectionMatrix");
        if (projectionMatrixLocation == -1) { throw std::runtime_error("te_ProjectionMatrix: not a valid program variable."); }
        glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, glm::value_ptr(projection));

        if (mViewLocation == -1) { throw std::runtime_error{ "te_ViewMatrix: not a valid program variable." }; }
        glUniformMatrix4fv(mViewLocation, 1, GL_FALSE, glm::value_ptr(mLastView));

        GLint modelMatrixLocation = glGetUniformLocation(mProgram, "te_ModelMatrix");
        if (modelMatrixLocation == -1) { throw std::runtime_error("te_ModelMatrix: not a valid program variable."); }
        glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, glm::value_ptr(model));
    }

    void Shader::destroy()
    {
        glDeleteProgram(mProgram);
    }

    Shader::~Shader()
    {
        destroy();
    }

    Shader::Shader(Shader&& o)
        : mProgram(o.mProgram)
        , mLastView(o.mLastView)
    {
        o.mProgram = 0;
    }

    Shader& Shader::operator=(Shader&& o)
    {
        destroy();

        mProgram = o.mProgram;
        mLastView = o.mLastView;
        o.mProgram = 0;

        return *this;
    }

    glm::mat4 Shader::getModel() const
    {
        return mModel;
    }

    void Shader::draw(const glm::mat4& view, const Mesh& mesh)
    {
        glUseProgram(mProgram);

        if (view != mLastView) {
            glUniformMatrix4fv(mViewLocation, 1, GL_FALSE, glm::value_ptr(view));
            mLastView = view;
        }

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, mesh.getTexture(0)->getID());
        glBindVertexArray(mesh.getVAO());
        glDrawElements(GL_TRIANGLES, mesh.getElementCount(), GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);

        glUseProgram(0);
    }
}
<|endoftext|>


<commit_before>
//  Camera.cpp
//  InternetMap
//

#include "Camera.hpp"
#include <stdlib.h>

static const float MOVE_TIME = 1.0f;
static const float MIN_ZOOM = -10.0f;
//we need a bound on the max. zoom because on small nodes the calculated max puts the target behind the camera.
//this might be a bug in targeting...?
static const float MAX_MAX_ZOOM = -0.2f;

// TODO: better way to register this
void cameraMoveFinishedCallback(void);

Camera::Camera() :
    _displayWidth(0.0f),
    _displayHeight(0.0f),
    _target(0.0f, 0.0f, 0.0f),
    _isMovingToTarget(false),
    _allowIdleAnimation(false),
    _rotation(0.0f),
    _zoom(-3.0f),
    _maxZoom(MAX_MAX_ZOOM),
    _targetMoveStartTime(MAXFLOAT),
    _targetMoveStartPosition(0.0f, 0.0f, 0.0f),
    _zoomStart(0.0f),
    _zoomTarget(0.0f),
    _zoomStartTime(0.0f),
    _zoomDuration(0.0f),
    _updateTime(0.0f),
    _idleStartTime(0.0f),
    _panEndTime(0.0f),
    _zoomVelocity(0.0f),
    _zoomEndTime(0.0f),
    _rotationVelocity(0.0f),
    _rotationEndTime(0.0f),
    _rotationStartTime(0.0f),
    _rotationDuration(0.0f),
    _subregionX(0.0f),
    _subregionY(0.0f),
    _subregionWidth(1.0f),
    _subregionHeight(1.0f)
{
    _rotationMatrix = Matrix4::identity();
    _panVelocity.x = 0.0f;
    _panVelocity.y = 0.0f;
}

static const float NEAR_PLANE = 0.1f;
static const float FAR_PLANE = 100.0f;

void Camera::update(TimeInterval currentTime) {
    TimeInterval delta = currentTime - _updateTime;
    _updateTime = currentTime;

    handleIdleMovement(delta);
    handleMomentumPan(delta);
    handleMomentumZoom(delta);
    handleMomentumRotation(delta);
    Vector3 currentTarget = calculateMoveTarget(delta);
    handleAnimatedZoom(delta);
    handleAnimatedRotation(delta);

    float aspect = fabsf(_displayWidth / _displayHeight);
    Matrix4 model = _rotationMatrix * Matrix4::translation(Vector3(-currentTarget.getX(), -currentTarget.getY(), -currentTarget.getZ()));
    Matrix4 view = Matrix4::translation(Vector3(0.0f, 0.0f, _zoom));
    Matrix4 modelView = view * model;
    Matrix4 projectionMatrix;

    if((_subregionX == 0.0f) && (_subregionY == 0.0f) && (_subregionWidth == 1.0f) && (_subregionHeight == 1.0f)) {
       projectionMatrix = Matrix4::perspective(DegreesToRadians(65.0f), aspect, NEAR_PLANE, FAR_PLANE);
    }
    else {
        float halfX = (float)tan( double( DegreesToRadians(65.0f) * 0.5 ) ) * NEAR_PLANE;
        float halfY = halfX / aspect;

        projectionMatrix = Matrix4::frustum(-halfX + (_subregionX * halfX * 2),
                                            -halfX + (_subregionX * halfX * 2) + (_subregionWidth * halfX * 2),
                                            -halfY + (_subregionY * halfY * 2),
                                            -halfY + (_subregionY * halfY * 2) + (_subregionHeight * halfY * 2),
                                            NEAR_PLANE, FAR_PLANE);
    }

    _projectionMatrix = projectionMatrix;
    _modelViewMatrix = modelView;
    _modelViewProjectionMatrix = projectionMatrix * modelView;
}

void Camera::handleIdleMovement(TimeInterval delta) {
    // Rotate camera if idle
    TimeInterval idleTime = _updateTime - _idleStartTime;
    float idleDelay = 0.1;

    if (_allowIdleAnimation && (idleTime > idleDelay)) {
        // Ease in
        float spinupFactor = fminf(1.0, (idleTime - idleDelay) / 2);
        rotateRadiansX(0.0006 * spinupFactor);
        rotateRadiansY(0.0001 * spinupFactor);
    }
}

void Camera::handleMomentumPan(TimeInterval delta) {
    //momentum panning
    if (_panVelocity.x != 0 && _panVelocity.y != 0) {

        TimeInterval rotationTime = _updateTime-_panEndTime;
        static TimeInterval totalTime = 1.0;
        float timeT = rotationTime / totalTime;
        if(timeT > 1.0) {
            _panVelocity.x = _panVelocity.y = 0.0f;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);

            rotateRadiansX(_panVelocity.x*delta*positionT);
            rotateRadiansY(_panVelocity.y*delta*positionT);
        }
    }
}

void Camera::handleMomentumZoom(TimeInterval delta) {
    //momentum zooming
    if (_zoomVelocity != 0) {
        static TimeInterval totalTime = 0.5;
        TimeInterval zoomTime = _updateTime-_zoomEndTime;
        float timeT = zoomTime / totalTime;
        if(timeT > 1.0) {
            _zoomVelocity = 0;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);
            zoomByScale(_zoomVelocity*delta*positionT);
        }
    }
}

void Camera::handleMomentumRotation(TimeInterval delta) {
    //momentum rotation
    if (_rotationVelocity != 0) {
        TimeInterval rotationTime = _updateTime-_rotationEndTime;
        static TimeInterval totalTime = 1.0;
        float timeT = rotationTime / totalTime;
        if(timeT > 1.0) {
            _rotationVelocity = 0;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);

            rotateRadiansZ(_rotationVelocity*delta*positionT);
        }
    }
}

void Camera::handleAnimatedZoom(TimeInterval delta) {
    //animated zoom
    if(_zoomStartTime < _updateTime) {
        float timeT = (_updateTime - _zoomStartTime) / _zoomDuration;
        if(timeT > 1.0f) {
            _zoomStartTime = MAXFLOAT;
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }
            _zoom = _zoomStart + (_zoomTarget-_zoomStart)*positionT;
        }
    }
}

void Camera::handleAnimatedRotation(TimeInterval delta) {
    //animated rotation
    if (_rotationStartTime < _updateTime) {
        float timeT = (_updateTime - _rotationStartTime) / _rotationDuration;
        if(timeT > 1.0f) {
            _rotationStartTime = MAXFLOAT;
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }
            _rotationMatrix = Matrix4(Vectormath::Aos::slerp(positionT, _rotationStart , _rotationTarget), Vector3(0.0f, 0.0f, 0.0f));
        }
    }
}
Vector3 Camera::calculateMoveTarget(TimeInterval delta) {
    Vector3 currentTarget;

    //animated move to target
    if(_targetMoveStartTime < _updateTime) {
        float timeT = (_updateTime - _targetMoveStartTime) / MOVE_TIME;
        if(timeT > 1.0f) {
            currentTarget = _target;
            _targetMoveStartTime = MAXFLOAT;
            _isMovingToTarget = false;
            cameraMoveFinishedCallback();
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }

            currentTarget = _targetMoveStartPosition + ((_target - _targetMoveStartPosition) * positionT);
        }
    }
    else {
        currentTarget = _target;
    }

    return currentTarget;
}

void Camera::setRotationAndRenormalize(const Matrix4& matrix) {
    _rotationMatrix = matrix;

    // Becasue we are doing sucessive modification of the rotation matrix, error can accumulate
    // Here we renormalize the matrix to make sure that the error doesn't grow
    Vector3 zAxis = Vectormath::Aos::normalize(_rotationMatrix.getCol2().getXYZ());
    _rotationMatrix.setCol0(Vector4(Vectormath::Aos::normalize(Vectormath::Aos::cross(_rotationMatrix.getCol1().getXYZ(), zAxis)), 0.0f));
    _rotationMatrix.setCol1(Vector4(Vectormath::Aos::normalize(Vectormath::Aos::cross(zAxis, _rotationMatrix.getCol0().getXYZ())), 0.0f));
    _rotationMatrix.setCol2(Vector4(zAxis, 0.0f));
}

float Camera::currentZoom(void) {
    return _zoom;
}

Matrix4 Camera::currentModelViewProjection(void) {
    return _modelViewProjectionMatrix;
}

Matrix4 Camera::currentModelView(void) {
    return _modelViewMatrix;
}

Matrix4 Camera::currentProjection(void) {
    return _projectionMatrix;
}

Vector3 Camera::cameraInObjectSpace(void) {
    Matrix4 invertedModelViewMatrix = Vectormath::Aos::inverse(_modelViewMatrix);
    return invertedModelViewMatrix.getTranslation();
}

Vector3 Camera::applyModelViewToPoint(Vector2 point) {
    Vector4 vec4FromPoint(point.x, point.y, -0.1, 1);
    Matrix4 invertedModelViewProjectionMatrix = Vectormath::Aos::inverse(_modelViewProjectionMatrix);
    vec4FromPoint = invertedModelViewProjectionMatrix * vec4FromPoint;
    vec4FromPoint = vec4FromPoint / vec4FromPoint.getW();

    return Vector3(vec4FromPoint.getX(), vec4FromPoint.getY(), vec4FromPoint.getZ());
}

void Camera::rotateRadiansX(float rotate) {
    setRotationAndRenormalize(Matrix4::rotation(rotate, Vector3(0.0f, 1.0f, 0.0f)) * _rotationMatrix);
}

void Camera::rotateRadiansY(float rotate) {
    setRotationAndRenormalize(Matrix4::rotation(rotate, Vector3(1.0f, 0.0f, 0.0f)) * _rotationMatrix);
}

void Camera::rotateRadiansZ(float rotate) {
    setRotationAndRenormalize(_rotationMatrix = Matrix4::rotation(rotate, Vector3(0.0f, 0.0f, 1.0f)) * _rotationMatrix);
}

void Camera::rotateAnimated(Matrix4 rotation, TimeInterval duration) {
    _rotationStart = Quaternion(_rotationMatrix.getUpper3x3());
    _rotationTarget = Quaternion(rotation.getUpper3x3());
    _rotationStartTime = _updateTime;
    _rotationDuration = duration;
}

void Camera::zoomByScale(float zoom) {
    _zoom += zoom * -_zoom;
    if(_zoom > _maxZoom) {
        _zoom = _maxZoom;
    }

    if(_zoom < MIN_ZOOM) {
        _zoom = MIN_ZOOM;
    }
}

void Camera::zoomAnimated(float zoom, TimeInterval duration) {
    if(zoom > _maxZoom) {
        zoom = _maxZoom;
    }

    if(zoom < MIN_ZOOM) {
        zoom = MIN_ZOOM;
    }

    _zoomStart = _zoom;
    _zoomTarget = zoom;
    _zoomStartTime = _updateTime;
    _zoomDuration = duration;
}

void Camera::setTarget(const Target& target) {
    _targetMoveStartPosition = _target;
    _target = target.vector;
    _targetMoveStartTime = _updateTime;
    _isMovingToTarget = true;
    _maxZoom = target.maxZoom;
    if (_maxZoom > MAX_MAX_ZOOM) {
        _maxZoom = MAX_MAX_ZOOM;
    }
    zoomAnimated(target.zoom, MOVE_TIME);
}

void Camera::startMomentumPanWithVelocity(Vector2 velocity) {
    _panEndTime = _updateTime;
    _panVelocity = velocity;
}

void Camera::stopMomentumPan(void) {
    _panVelocity.x = _panVelocity.y = 0.0f;
}

void Camera::startMomentumZoomWithVelocity(float velocity) {
    _zoomEndTime = _updateTime;
    _zoomVelocity = velocity*0.5;
}

void Camera::stopMomentumZoom(void) {
    _zoomVelocity = 0;
}

void Camera::startMomentumRotationWithVelocity(float velocity) {
    _rotationVelocity = velocity;
    _rotationEndTime = _updateTime;
}

void Camera::stopMomentumRotation(void) {
    _rotationVelocity = 0;
}

void Camera::resetIdleTimer() {
    _idleStartTime = _updateTime;
}

void Camera::setViewSubregion(float x, float y, float w, float h) {
    _subregionX = x;
    _subregionY = y;
    _subregionWidth = w;
    _subregionHeight = h;
}

float Camera::getSubregionScale(void) {
    return 1.0f / _subregionWidth;
}

<commit_msg>Tweak near plane and zoom clamping to allow getting closer to small nodes. Fixes #93.<commit_after>
//  Camera.cpp
//  InternetMap
//

#include "Camera.hpp"
#include <stdlib.h>

static const float MOVE_TIME = 1.0f;
static const float MIN_ZOOM = -10.0f;
//we need a bound on the max. zoom because on small nodes the calculated max puts the target behind the camera.
//this might be a bug in targeting...?
static const float MAX_MAX_ZOOM = -0.06f;

// TODO: better way to register this
void cameraMoveFinishedCallback(void);

Camera::Camera() :
    _displayWidth(0.0f),
    _displayHeight(0.0f),
    _target(0.0f, 0.0f, 0.0f),
    _isMovingToTarget(false),
    _allowIdleAnimation(false),
    _rotation(0.0f),
    _zoom(-3.0f),
    _maxZoom(MAX_MAX_ZOOM),
    _targetMoveStartTime(MAXFLOAT),
    _targetMoveStartPosition(0.0f, 0.0f, 0.0f),
    _zoomStart(0.0f),
    _zoomTarget(0.0f),
    _zoomStartTime(0.0f),
    _zoomDuration(0.0f),
    _updateTime(0.0f),
    _idleStartTime(0.0f),
    _panEndTime(0.0f),
    _zoomVelocity(0.0f),
    _zoomEndTime(0.0f),
    _rotationVelocity(0.0f),
    _rotationEndTime(0.0f),
    _rotationStartTime(0.0f),
    _rotationDuration(0.0f),
    _subregionX(0.0f),
    _subregionY(0.0f),
    _subregionWidth(1.0f),
    _subregionHeight(1.0f)
{
    _rotationMatrix = Matrix4::identity();
    _panVelocity.x = 0.0f;
    _panVelocity.y = 0.0f;
}

static const float NEAR_PLANE = 0.05f;
static const float FAR_PLANE = 100.0f;

void Camera::update(TimeInterval currentTime) {
    TimeInterval delta = currentTime - _updateTime;
    _updateTime = currentTime;

    handleIdleMovement(delta);
    handleMomentumPan(delta);
    handleMomentumZoom(delta);
    handleMomentumRotation(delta);
    Vector3 currentTarget = calculateMoveTarget(delta);
    handleAnimatedZoom(delta);
    handleAnimatedRotation(delta);

    float aspect = fabsf(_displayWidth / _displayHeight);
    Matrix4 model = _rotationMatrix * Matrix4::translation(Vector3(-currentTarget.getX(), -currentTarget.getY(), -currentTarget.getZ()));
    Matrix4 view = Matrix4::translation(Vector3(0.0f, 0.0f, _zoom));
    Matrix4 modelView = view * model;
    Matrix4 projectionMatrix;

    if((_subregionX == 0.0f) && (_subregionY == 0.0f) && (_subregionWidth == 1.0f) && (_subregionHeight == 1.0f)) {
       projectionMatrix = Matrix4::perspective(DegreesToRadians(65.0f), aspect, NEAR_PLANE, FAR_PLANE);
    }
    else {
        float halfX = (float)tan( double( DegreesToRadians(65.0f) * 0.5 ) ) * NEAR_PLANE;
        float halfY = halfX / aspect;

        projectionMatrix = Matrix4::frustum(-halfX + (_subregionX * halfX * 2),
                                            -halfX + (_subregionX * halfX * 2) + (_subregionWidth * halfX * 2),
                                            -halfY + (_subregionY * halfY * 2),
                                            -halfY + (_subregionY * halfY * 2) + (_subregionHeight * halfY * 2),
                                            NEAR_PLANE, FAR_PLANE);
    }

    _projectionMatrix = projectionMatrix;
    _modelViewMatrix = modelView;
    _modelViewProjectionMatrix = projectionMatrix * modelView;
}

void Camera::handleIdleMovement(TimeInterval delta) {
    // Rotate camera if idle
    TimeInterval idleTime = _updateTime - _idleStartTime;
    float idleDelay = 0.1;

    if (_allowIdleAnimation && (idleTime > idleDelay)) {
        // Ease in
        float spinupFactor = fminf(1.0, (idleTime - idleDelay) / 2);
        rotateRadiansX(0.0006 * spinupFactor);
        rotateRadiansY(0.0001 * spinupFactor);
    }
}

void Camera::handleMomentumPan(TimeInterval delta) {
    //momentum panning
    if (_panVelocity.x != 0 && _panVelocity.y != 0) {

        TimeInterval rotationTime = _updateTime-_panEndTime;
        static TimeInterval totalTime = 1.0;
        float timeT = rotationTime / totalTime;
        if(timeT > 1.0) {
            _panVelocity.x = _panVelocity.y = 0.0f;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);

            rotateRadiansX(_panVelocity.x*delta*positionT);
            rotateRadiansY(_panVelocity.y*delta*positionT);
        }
    }
}

void Camera::handleMomentumZoom(TimeInterval delta) {
    //momentum zooming
    if (_zoomVelocity != 0) {
        static TimeInterval totalTime = 0.5;
        TimeInterval zoomTime = _updateTime-_zoomEndTime;
        float timeT = zoomTime / totalTime;
        if(timeT > 1.0) {
            _zoomVelocity = 0;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);
            zoomByScale(_zoomVelocity*delta*positionT);
        }
    }
}

void Camera::handleMomentumRotation(TimeInterval delta) {
    //momentum rotation
    if (_rotationVelocity != 0) {
        TimeInterval rotationTime = _updateTime-_rotationEndTime;
        static TimeInterval totalTime = 1.0;
        float timeT = rotationTime / totalTime;
        if(timeT > 1.0) {
            _rotationVelocity = 0;
        }
        else {
            //quadratic ease out
            float positionT = 1+(timeT*timeT-2.0f*timeT);

            rotateRadiansZ(_rotationVelocity*delta*positionT);
        }
    }
}

void Camera::handleAnimatedZoom(TimeInterval delta) {
    //animated zoom
    if(_zoomStartTime < _updateTime) {
        float timeT = (_updateTime - _zoomStartTime) / _zoomDuration;
        if(timeT > 1.0f) {
            _zoomStartTime = MAXFLOAT;
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }
            _zoom = _zoomStart + (_zoomTarget-_zoomStart)*positionT;
        }
    }
}

void Camera::handleAnimatedRotation(TimeInterval delta) {
    //animated rotation
    if (_rotationStartTime < _updateTime) {
        float timeT = (_updateTime - _rotationStartTime) / _rotationDuration;
        if(timeT > 1.0f) {
            _rotationStartTime = MAXFLOAT;
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }
            _rotationMatrix = Matrix4(Vectormath::Aos::slerp(positionT, _rotationStart , _rotationTarget), Vector3(0.0f, 0.0f, 0.0f));
        }
    }
}
Vector3 Camera::calculateMoveTarget(TimeInterval delta) {
    Vector3 currentTarget;

    //animated move to target
    if(_targetMoveStartTime < _updateTime) {
        float timeT = (_updateTime - _targetMoveStartTime) / MOVE_TIME;
        if(timeT > 1.0f) {
            currentTarget = _target;
            _targetMoveStartTime = MAXFLOAT;
            _isMovingToTarget = false;
            cameraMoveFinishedCallback();
        }
        else {
            float positionT;

            // Quadratic ease-in / ease-out
            if (timeT < 0.5f)
            {
                positionT = timeT * timeT * 2;
            }
            else {
                positionT = 1.0f - ((timeT - 1.0f) * (timeT - 1.0f) * 2.0f);
            }

            currentTarget = _targetMoveStartPosition + ((_target - _targetMoveStartPosition) * positionT);
        }
    }
    else {
        currentTarget = _target;
    }

    return currentTarget;
}

void Camera::setRotationAndRenormalize(const Matrix4& matrix) {
    _rotationMatrix = matrix;

    // Becasue we are doing sucessive modification of the rotation matrix, error can accumulate
    // Here we renormalize the matrix to make sure that the error doesn't grow
    Vector3 zAxis = Vectormath::Aos::normalize(_rotationMatrix.getCol2().getXYZ());
    _rotationMatrix.setCol0(Vector4(Vectormath::Aos::normalize(Vectormath::Aos::cross(_rotationMatrix.getCol1().getXYZ(), zAxis)), 0.0f));
    _rotationMatrix.setCol1(Vector4(Vectormath::Aos::normalize(Vectormath::Aos::cross(zAxis, _rotationMatrix.getCol0().getXYZ())), 0.0f));
    _rotationMatrix.setCol2(Vector4(zAxis, 0.0f));
}

float Camera::currentZoom(void) {
    return _zoom;
}

Matrix4 Camera::currentModelViewProjection(void) {
    return _modelViewProjectionMatrix;
}

Matrix4 Camera::currentModelView(void) {
    return _modelViewMatrix;
}

Matrix4 Camera::currentProjection(void) {
    return _projectionMatrix;
}

Vector3 Camera::cameraInObjectSpace(void) {
    Matrix4 invertedModelViewMatrix = Vectormath::Aos::inverse(_modelViewMatrix);
    return invertedModelViewMatrix.getTranslation();
}

Vector3 Camera::applyModelViewToPoint(Vector2 point) {
    Vector4 vec4FromPoint(point.x, point.y, -0.1, 1);
    Matrix4 invertedModelViewProjectionMatrix = Vectormath::Aos::inverse(_modelViewProjectionMatrix);
    vec4FromPoint = invertedModelViewProjectionMatrix * vec4FromPoint;
    vec4FromPoint = vec4FromPoint / vec4FromPoint.getW();

    return Vector3(vec4FromPoint.getX(), vec4FromPoint.getY(), vec4FromPoint.getZ());
}

void Camera::rotateRadiansX(float rotate) {
    setRotationAndRenormalize(Matrix4::rotation(rotate, Vector3(0.0f, 1.0f, 0.0f)) * _rotationMatrix);
}

void Camera::rotateRadiansY(float rotate) {
    setRotationAndRenormalize(Matrix4::rotation(rotate, Vector3(1.0f, 0.0f, 0.0f)) * _rotationMatrix);
}

void Camera::rotateRadiansZ(float rotate) {
    setRotationAndRenormalize(_rotationMatrix = Matrix4::rotation(rotate, Vector3(0.0f, 0.0f, 1.0f)) * _rotationMatrix);
}

void Camera::rotateAnimated(Matrix4 rotation, TimeInterval duration) {
    _rotationStart = Quaternion(_rotationMatrix.getUpper3x3());
    _rotationTarget = Quaternion(rotation.getUpper3x3());
    _rotationStartTime = _updateTime;
    _rotationDuration = duration;
}

void Camera::zoomByScale(float zoom) {
    _zoom += zoom * -_zoom;
    if(_zoom > _maxZoom) {
        _zoom = _maxZoom;
    }

    if(_zoom < MIN_ZOOM) {
        _zoom = MIN_ZOOM;
    }
}

void Camera::zoomAnimated(float zoom, TimeInterval duration) {
    if(zoom > _maxZoom) {
        zoom = _maxZoom;
    }

    if(zoom < MIN_ZOOM) {
        zoom = MIN_ZOOM;
    }

    _zoomStart = _zoom;
    _zoomTarget = zoom;
    _zoomStartTime = _updateTime;
    _zoomDuration = duration;
}

void Camera::setTarget(const Target& target) {
    _targetMoveStartPosition = _target;
    _target = target.vector;
    _targetMoveStartTime = _updateTime;
    _isMovingToTarget = true;
    _maxZoom = target.maxZoom;
    if (_maxZoom > MAX_MAX_ZOOM) {
        _maxZoom = MAX_MAX_ZOOM;
    }
    zoomAnimated(target.zoom, MOVE_TIME);
}

void Camera::startMomentumPanWithVelocity(Vector2 velocity) {
    _panEndTime = _updateTime;
    _panVelocity = velocity;
}

void Camera::stopMomentumPan(void) {
    _panVelocity.x = _panVelocity.y = 0.0f;
}

void Camera::startMomentumZoomWithVelocity(float velocity) {
    _zoomEndTime = _updateTime;
    _zoomVelocity = velocity*0.5;
}

void Camera::stopMomentumZoom(void) {
    _zoomVelocity = 0;
}

void Camera::startMomentumRotationWithVelocity(float velocity) {
    _rotationVelocity = velocity;
    _rotationEndTime = _updateTime;
}

void Camera::stopMomentumRotation(void) {
    _rotationVelocity = 0;
}

void Camera::resetIdleTimer() {
    _idleStartTime = _updateTime;
}

void Camera::setViewSubregion(float x, float y, float w, float h) {
    _subregionX = x;
    _subregionY = y;
    _subregionWidth = w;
    _subregionHeight = h;
}

float Camera::getSubregionScale(void) {
    return 1.0f / _subregionWidth;
}

<|endoftext|>