I tested a few other things and it turned out that the function added
as a dirichlet boundary condition via PetscDSAddBoundary doesn't
receive the time values correctly (PetscReal time is always 0.0).

I also see no effect adding DMTSSetIJacobianLocal vs. not setting the
jacobian function. The analytic solution i used in my attached example
is the same as in the src/ts/examples/tutorials/ex32.c.

Am i doing anything obviously wrong here? My next step would be to try
if assembling the matrices myself and writing a custom
IFunction/IJacobian which assembles the different parts of the matrix
like M and J for the stiff ODE with nontrivial mass matrix (see manual
section of TS -> F = M u' - f) but i think this should be obsolete
right?

Appreciate your help.

Regards
Julian

On Mon, Nov 7, 2016 at 10:49 AM, Julian Andrej <[email protected]> wrote:
> Hello,
>
> i'm using PetscFE in combination with SNES and a hand written backward
> euler solver right now and like to hand that over to TS. I have been
> fiddling quite a while getting TS to work with PetscFE and have
> encountered a few unclarities.
>
> I have looked at examples which are outdated i guess
> (src/ts/examples/tutorials/ex32.c) and i am confused on how i have to
> formulate the discretization of the jacobian and the residual. It
> seems obvious to use the DMTSSetIFunctionLocal and
> DMTSSetIJacobianLocal functions because there are prepared wrappers
> from DMPlexTSComputeIFunctionFEM and DMPlexTSComputeIJacobianFEM.
>
> I need a Mass matrix for my problem, is that formed from the function
> space information or do i have to form it myself? Is there any working
> example which uses PetscFE and TS to form the DMTSSetIFunctionLocal
> and DMTSSetIJacobianLocal? (grepping the tree tells me "no"
> unfortunately).
>
> Regards
> Julian
#include <petscdmplex.h>
#include <petscts.h>
#include <petscsnes.h>
#include <petscds.h>
#include <petscviewerhdf5.h>

typedef struct {
  int debug;
  int dim;
  PetscBool interpolate;
  PetscReal refinementLimit;
  PetscErrorCode (**exactFuncs)(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx);
} AppCtx;

PetscErrorCode CreateMesh(MPI_Comm, DM*, AppCtx*);
PetscErrorCode SetupDiscretization(DM, AppCtx*);

PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
{
  u[0] = 0.0;
  return 0;
}

PetscErrorCode analytic_temp_2d(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx)
{
  *u = 2.0*time + x[0]*x[0] + x[1]*x[1];
  /*
    if (x[0] == 0) {
    *u = time * 1.0;
    } else {
    *u = 0.0;
    }
  */
  return 0;
}

void f0_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
          const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
          const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
          PetscReal t, const PetscReal x[], PetscScalar f0[])
{
  f0[0] = u_t[0] - 2.0;
}

void f1_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
	     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
	     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
	     PetscReal t, const PetscReal x[], PetscScalar f1[])
{
  PetscInt d;
  for (d = 0; d < dim; ++d) {
    f1[d] = u_x[d];
  }
}

void g3_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
	     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
	     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
	     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g3[])
{
  PetscInt d;
  for (d = 0; d < dim; ++d) {
    g3[d*dim+d] = 1.0;
  }
}

void g0_temp(PetscInt dim, PetscInt Nf, PetscInt NfAux,
	     const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[],
	     const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[],
	     PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscScalar g0[])
{
  g0[0] = 1.0;
}

#undef __FUNCT__
#define __FUNCT__ "main"
int main(int argc, char **argv)
{
  PetscErrorCode ierr;
  AppCtx ctx;
  DM dm;
  TS ts;
  Vec u, r;
  PetscReal t = 0.0;
  PetscReal l2error = 0.0; /* L_2 error in the solution */
  
  ierr = PetscInitialize(&argc, &argv, NULL, NULL);
  if (ierr) {
    return ierr;
  }

  /* Default context initialization */
  ctx.debug = 0;
  ctx.dim = 2;
  ctx.interpolate = PETSC_TRUE;
  ctx.refinementLimit = 0.0;

  ierr = CreateMesh(PETSC_COMM_WORLD, &dm, &ctx);CHKERRQ(ierr);
  ierr = DMSetApplicationContext(dm, &ctx);CHKERRQ(ierr);
  ierr = PetscMalloc(1, &ctx.exactFuncs);CHKERRQ(ierr);
  ierr = SetupDiscretization(dm, &ctx);CHKERRQ(ierr);

  ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) u, "temperature");CHKERRQ(ierr);
  ierr = VecDuplicate(u, &r);CHKERRQ(ierr);

  ierr = TSCreate(PETSC_COMM_WORLD, &ts);CHKERRQ(ierr);
  ierr = TSSetDM(ts, dm);CHKERRQ(ierr);
  ierr = DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx);CHKERRQ(ierr);
  ierr = DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx);CHKERRQ(ierr);
  ierr = TSSetType(ts, TSBEULER);CHKERRQ(ierr);
  ierr = TSSetDuration(ts, 1, 1.0);CHKERRQ(ierr);
  ierr = TSSetInitialTimeStep(ts, 0.0, 0.001);CHKERRQ(ierr);
  ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER);CHKERRQ(ierr);
  
  ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
  ierr = TSSolve(ts, u);CHKERRQ(ierr);

  ierr = TSGetTime(ts, &t);CHKERRQ(ierr);
  ierr = DMComputeL2Diff(dm, t, ctx.exactFuncs, NULL, u, &l2error);CHKERRQ(ierr);
  if (l2error < 1.0e-11) {
    ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: < 1.0e-11\n");CHKERRQ(ierr);
  }
  else {
    ierr = PetscPrintf(PETSC_COMM_WORLD, "L_2 Error: %g\n", l2error);CHKERRQ(ierr);
  }
  
  // ierr = DMProjectFunction(dm, t, ctx.exactFuncs, NULL, INSERT_ALL_VALUES, u);CHKERRQ(ierr);
  ierr = VecViewFromOptions(u, NULL, "-sol_view");CHKERRQ(ierr);
  
  ierr = VecDestroy(&u);CHKERRQ(ierr);
  ierr = VecDestroy(&r);CHKERRQ(ierr);
  ierr = TSDestroy(&ts);CHKERRQ(ierr);
  ierr = DMDestroy(&dm);CHKERRQ(ierr);
  ierr = PetscFree(ctx.exactFuncs);CHKERRQ(ierr);
  ierr = PetscFinalize();
  return ierr;
}

#undef __FUNCT__
#define __FUNCT__ "SetupDiscretization"
PetscErrorCode SetupDiscretization(DM dm, AppCtx* ctx)
{
  PetscErrorCode ierr;
  const PetscInt id = 1;
  const PetscInt dim = ctx->dim;
  PetscFE temp_fe;
  PetscDS temp_ds;
    
  PetscFunctionBeginUser;
  ierr = PetscFECreateDefault(dm, dim, 1, PETSC_FALSE, "temp_", -1, &temp_fe);CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) temp_fe, "temperature");CHKERRQ(ierr);
  ierr = DMGetDS(dm, &temp_ds);CHKERRQ(ierr);
  ierr = PetscDSSetDiscretization(temp_ds, 0, (PetscObject) temp_fe);CHKERRQ(ierr);

  ierr = PetscDSSetResidual(temp_ds, 0, f0_temp, f1_temp);CHKERRQ(ierr);
  ierr = PetscDSSetJacobian(temp_ds, 0, 0, g0_temp, NULL, NULL, g3_temp);CHKERRQ(ierr);

  switch (ctx->dim) {
  case 2:
    ctx->exactFuncs[0] = analytic_temp_2d;
    break;
  default:
    SETERRQ1(PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %d", ctx->dim);
  }
  ierr = PetscDSAddBoundary(temp_ds, DM_BC_ESSENTIAL, "wall", "marker", 0, 0, NULL, (void (*)()) ctx->exactFuncs[0], 1, &id, ctx);CHKERRQ(ierr);
  
  ierr = PetscFEDestroy(&temp_fe);CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "CreateBCLabel"
PetscErrorCode CreateBCLabel(DM dm, const char name[])
{
  DMLabel label;
  PetscErrorCode ierr;

  PetscFunctionBeginUser;
  ierr = DMCreateLabel(dm, name);CHKERRQ(ierr);
  ierr = DMGetLabel(dm, name, &label);CHKERRQ(ierr);
  ierr = DMPlexMarkBoundaryFaces(dm, label);CHKERRQ(ierr);
  ierr = DMPlexLabelComplete(dm, label);CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

#undef __FUNCT__
#define __FUNCT__ "CreateMesh"
PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *ctx)
{
  PetscErrorCode ierr;
  const int dim = ctx->dim;
  const PetscReal refinementLimit = ctx->refinementLimit;
  PetscInt cells[3] = {1, 1, 1}; /* coarse mesh is one cell; refine from there */

  PetscFunctionBeginUser;
  ierr = DMPlexCreateHexBoxMesh(comm, dim, cells, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE, dm);CHKERRQ(ierr);
  ierr = PetscObjectSetName((PetscObject) *dm, "Mesh");CHKERRQ(ierr);

  PetscBool hasLabel;
  ierr = DMHasLabel(*dm,"marker",&hasLabel);CHKERRQ(ierr);
  if (!hasLabel) {
    ierr = CreateBCLabel(*dm, "marker");CHKERRQ(ierr);
  }
  {
    DM refinedMesh = NULL;
    DM distributedMesh = NULL;

    /* Refine mesh using a volume constraint */
    ierr = DMPlexSetRefinementLimit(*dm, refinementLimit);CHKERRQ(ierr);
    ierr = DMRefine(*dm, comm, &refinedMesh);CHKERRQ(ierr);
    if (refinedMesh) {
      const char *name;

      ierr = PetscObjectGetName((PetscObject) *dm, &name);CHKERRQ(ierr);
      ierr = PetscObjectSetName((PetscObject) refinedMesh, name);CHKERRQ(ierr);
      ierr = DMDestroy(dm);CHKERRQ(ierr);
      *dm = refinedMesh;
    }
    /* Distribute mesh over processes */
    ierr = DMPlexDistribute(*dm, 0, NULL, &distributedMesh);CHKERRQ(ierr);
    if (distributedMesh) {
      ierr = DMDestroy(dm);CHKERRQ(ierr);
      *dm = distributedMesh;
    }
  }
  ierr = DMSetFromOptions(*dm);CHKERRQ(ierr);
  ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr);
  PetscFunctionReturn(0);
}

Reply via email to