/**
 * Example 3
 * =========
 * We demonstrate how to construct a curved grid from a discrete function, i.e., a coefficient
 * vector and a function-space basis. For this, we use dune-functions, but any other implementation
 * of localizable (discrete) functions can be used instead. These discrete representations of the
 * surface allow an simple implementation of evolving surfaces. Just the coefficient vector needs
 * to be updated in order to move the surface nodes.
 **/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <dune/common/parallel/mpihelper.hh>
#include <dune/curvedgrid/curvedgrid.hh>
#include <dune/curvedgrid/gridfunctions/discretegridviewfunction.hh>
#include <dune/functions/functionspacebases/interpolate.hh>
#include <dune/grid/yaspgrid.hh>
#include <dune/grid/io/file/vtk.hh>

using namespace Dune;

int main(int argc, char** argv)
{
  MPIHelper::instance(argc, argv);

  // Construct a reference grid
  YaspGrid<2> refGrid{ {1.0,1.0}, {16,16} };

  // Define a discrete grid-function on the reference grid
  // with dim(range) = 3 and polynomial order k
  auto f = discreteGridViewFunction<3>(refGrid.leafGridView(), /*order*/ 3);

  // Wrap the reference grid and the grid-function
  // Note, the grid-function is passed in a reference wrapper to prevent from copy
  CurvedGrid grid{refGrid, std::ref(f)};

  // 4. Write grid to vtu file
  auto gv = grid.leafGridView();
  using GridView = decltype(gv);
  auto writer = std::make_shared<SubsamplingVTKWriter<GridView>>(gv, refinementIntervals(3));
  auto pvdwriter = VTKSequenceWriter<GridView>{writer, "evolving"};

  for (double t = 0.0; t < 10.0; t += 0.1)
  {
    std::cout << "time t = " << t << std::endl;

    // Interpolate the parametrization into the grid-function
    // This updates the coefficients. Automatically, the curved grid gets
    // a new shape.
    Functions::interpolate(f.basis(), f.coefficients(),
      [t](const FieldVector<double,2>& x) -> FieldVector<double,3>
      {
        return {x[0], x[1], 0.2*std::sin(2*x[0]*x[1] + t)};
      });

    pvdwriter.write(t);
  }
}