Actual source code: ex70.c

  1: static char help[] = "Tests that SNESSetUp() propagates application context to the NPC only when the NPC has no existing context.\n\n";

  3: #include <petscsnes.h>

  5: typedef struct {
  6:   PetscInt tag;
  7: } AppCtx;

  9: PetscErrorCode FormFunction(SNES snes, Vec x, Vec f, PetscCtx ctx)
 10: {
 11:   const PetscScalar *xx;
 12:   PetscScalar       *ff;

 14:   PetscFunctionBeginUser;
 15:   PetscCall(VecGetArrayRead(x, &xx));
 16:   PetscCall(VecGetArray(f, &ff));
 17:   ff[0] = xx[0];
 18:   PetscCall(VecRestoreArrayRead(x, &xx));
 19:   PetscCall(VecRestoreArray(f, &ff));
 20:   PetscFunctionReturn(PETSC_SUCCESS);
 21: }

 23: PetscErrorCode FormJacobian(SNES snes, Vec x, Mat jac, Mat B, PetscCtx ctx)
 24: {
 25:   PetscScalar one = 1.0;
 26:   PetscInt    idx = 0;

 28:   PetscFunctionBeginUser;
 29:   PetscCall(MatSetValues(B, 1, &idx, 1, &idx, &one, INSERT_VALUES));
 30:   PetscCall(MatAssemblyBegin(B, MAT_FINAL_ASSEMBLY));
 31:   PetscCall(MatAssemblyEnd(B, MAT_FINAL_ASSEMBLY));
 32:   if (jac != B) {
 33:     PetscCall(MatAssemblyBegin(jac, MAT_FINAL_ASSEMBLY));
 34:     PetscCall(MatAssemblyEnd(jac, MAT_FINAL_ASSEMBLY));
 35:   }
 36:   PetscFunctionReturn(PETSC_SUCCESS);
 37: }

 39: int main(int argc, char **argv)
 40: {
 41:   SNES      snes, npc;
 42:   Vec       x, r;
 43:   Mat       J;
 44:   AppCtx    parent_ctx, npc_ctx;
 45:   void     *retrieved_ctx;
 46:   PetscBool test_preserve = PETSC_FALSE;

 48:   PetscFunctionBeginUser;
 49:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
 50:   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test_preserve", &test_preserve, NULL));

 52:   parent_ctx.tag = 1;
 53:   npc_ctx.tag    = 2;

 55:   PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
 56:   PetscCall(VecSetSizes(x, PETSC_DECIDE, 1));
 57:   PetscCall(VecSetFromOptions(x));
 58:   PetscCall(VecDuplicate(x, &r));

 60:   PetscCall(MatCreate(PETSC_COMM_WORLD, &J));
 61:   PetscCall(MatSetSizes(J, PETSC_DECIDE, PETSC_DECIDE, 1, 1));
 62:   PetscCall(MatSetFromOptions(J));
 63:   PetscCall(MatSetUp(J));

 65:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
 66:   PetscCall(SNESSetFunction(snes, r, FormFunction, NULL));
 67:   PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, NULL));
 68:   PetscCall(SNESSetApplicationContext(snes, &parent_ctx));

 70:   /* Use SNESSetNPC with a freshly created SNES so no automatic context copy occurs */
 71:   PetscCall(SNESCreate(PETSC_COMM_WORLD, &npc));
 72:   if (test_preserve) PetscCall(SNESSetApplicationContext(npc, &npc_ctx));
 73:   PetscCall(SNESSetNPC(snes, npc));
 74:   PetscCall(SNESDestroy(&npc));

 76:   PetscCall(SNESSetFromOptions(snes));
 77:   PetscCall(SNESSetUp(snes));

 79:   PetscCall(SNESGetNPC(snes, &npc));
 80:   PetscCall(SNESGetApplicationContext(npc, &retrieved_ctx));
 81:   if (test_preserve) {
 82:     PetscCheck(retrieved_ctx == (void *)&npc_ctx, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "NPC context was overwritten by parent context");
 83:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "NPC kept its own context (tag=%" PetscInt_FMT ")\n", ((AppCtx *)retrieved_ctx)->tag));
 84:   } else {
 85:     PetscCheck(retrieved_ctx == (void *)&parent_ctx, PETSC_COMM_WORLD, PETSC_ERR_PLIB, "NPC did not inherit parent context");
 86:     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "NPC inherited parent context (tag=%" PetscInt_FMT ")\n", ((AppCtx *)retrieved_ctx)->tag));
 87:   }

 89:   PetscCall(VecDestroy(&x));
 90:   PetscCall(VecDestroy(&r));
 91:   PetscCall(MatDestroy(&J));
 92:   PetscCall(SNESDestroy(&snes));
 93:   PetscCall(PetscFinalize());
 94:   return 0;
 95: }

 97: /*TEST

 99:    test:
100:       suffix: inherit
101:       nsize: 1
102:       output_file: output/ex70_inherit.out

104:    test:
105:       suffix: preserve
106:       nsize: 1
107:       args: -test_preserve
108:       output_file: output/ex70_preserve.out

110: TEST*/