Actual source code: snestest.c
petsc-3.3-p7 2013-05-11
2: #include <petsc-private/snesimpl.h>
4: typedef struct {
5: PetscBool complete_print;
6: } SNES_Test;
8: /*
9: SNESSolve_Test - Tests whether a hand computed Jacobian
10: matches one compute via finite differences.
11: */
14: PetscErrorCode SNESSolve_Test(SNES snes)
15: {
16: Mat A = snes->jacobian,B;
17: Vec x = snes->vec_sol,f = snes->vec_func;
19: PetscInt i;
20: MatStructure flg;
21: PetscReal nrm,gnorm;
22: SNES_Test *neP = (SNES_Test*)snes->data;
26: if (A != snes->jacobian_pre) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot test with alternative preconditioner");
28: PetscPrintf(((PetscObject)snes)->comm,"Testing hand-coded Jacobian, if the ratio is\n");
29: PetscPrintf(((PetscObject)snes)->comm,"O(1.e-8), the hand-coded Jacobian is probably correct.\n");
30: if (!neP->complete_print) {
31: PetscPrintf(((PetscObject)snes)->comm,"Run with -snes_test_display to show difference\n");
32: PetscPrintf(((PetscObject)snes)->comm,"of hand-coded and finite difference Jacobian.\n");
33: }
35: for (i=0; i<3; i++) {
36: void *functx;
37: static const char *const loc[] = {"user-defined state","constant state -1.0","constant state 1.0"};
38: if (i == 1) {VecSet(x,-1.0);}
39: else if (i == 2) {VecSet(x,1.0);}
41: /* evaluate the function at this point because SNESDefaultComputeJacobianColor() assumes that the function has been evaluated and put into snes->vec_func */
42: SNESComputeFunction(snes,x,f);
43: if (snes->domainerror) {
44: PetscPrintf(((PetscObject)snes)->comm,"Domain error at %s\n",loc[i]);
45: snes->domainerror = PETSC_FALSE;
46: continue;
47: }
49: /* compute both versions of Jacobian */
50: SNESComputeJacobian(snes,x,&A,&A,&flg);
51: if (!i) {
52: PetscInt m,n,M,N;
53: MatCreate(((PetscObject)A)->comm,&B);
54: MatGetSize(A,&M,&N);
55: MatGetLocalSize(A,&m,&n);
56: MatSetSizes(B,m,n,M,N);
57: MatSetType(B,((PetscObject)A)->type_name);
58: MatSetUp(B);
59: }
60: SNESGetFunction(snes,PETSC_NULL,PETSC_NULL,&functx);
61: SNESDefaultComputeJacobian(snes,x,&B,&B,&flg,functx);
62: if (neP->complete_print) {
63: MPI_Comm comm;
64: PetscViewer viewer;
65: PetscPrintf(((PetscObject)snes)->comm,"Finite difference Jacobian (%s)\n",loc[i]);
66: PetscObjectGetComm((PetscObject)B,&comm);
67: PetscViewerASCIIGetStdout(comm,&viewer);
68: MatView(B,viewer);
69: }
70: /* compare */
71: MatAYPX(B,-1.0,A,DIFFERENT_NONZERO_PATTERN);
72: MatNorm(B,NORM_FROBENIUS,&nrm);
73: MatNorm(A,NORM_FROBENIUS,&gnorm);
74: if (neP->complete_print) {
75: MPI_Comm comm;
76: PetscViewer viewer;
77: PetscPrintf(((PetscObject)snes)->comm,"Hand-coded Jacobian (%s)\n",loc[i]);
78: PetscObjectGetComm((PetscObject)B,&comm);
79: PetscViewerASCIIGetStdout(comm,&viewer);
80: MatView(A,viewer);
81: PetscPrintf(((PetscObject)snes)->comm,"Hand-coded minus finite difference Jacobian (%s)\n",loc[i]);
82: MatView(B,viewer);
83: }
84: if (!gnorm) gnorm = 1; /* just in case */
85: PetscPrintf(((PetscObject)snes)->comm,"Norm of matrix ratio %g difference %g (%s)\n",(double)(nrm/gnorm),(double)nrm,loc[i]);
86: }
87: MatDestroy(&B);
88: /*
89: Return error code cause Jacobian not good
90: */
91: PetscFunctionReturn(PETSC_ERR_ARG_WRONGSTATE);
92: }
93: /* ------------------------------------------------------------ */
96: PetscErrorCode SNESDestroy_Test(SNES snes)
97: {
100: PetscFree(snes->data);
101: return(0);
102: }
106: static PetscErrorCode SNESSetFromOptions_Test(SNES snes)
107: {
108: SNES_Test *ls = (SNES_Test *)snes->data;
113: PetscOptionsHead("Hand-coded Jacobian tester options");
114: PetscOptionsBool("-snes_test_display","Display difference between hand-coded and finite difference Jacobians","None",ls->complete_print,&ls->complete_print,PETSC_NULL);
115: PetscOptionsTail();
116: return(0);
117: }
119: /* ------------------------------------------------------------ */
120: /*MC
121: SNESTEST - Test hand-coded Jacobian against finite difference Jacobian
123: Options Database:
124: . -snes_test_display Display difference between approximate and hand-coded Jacobian
126: Level: intermediate
128: .seealso: SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR
130: M*/
131: EXTERN_C_BEGIN
134: PetscErrorCode SNESCreate_Test(SNES snes)
135: {
136: SNES_Test *neP;
140: snes->ops->solve = SNESSolve_Test;
141: snes->ops->destroy = SNESDestroy_Test;
142: snes->ops->setfromoptions = SNESSetFromOptions_Test;
143: snes->ops->view = 0;
144: snes->ops->setup = 0;
145: snes->ops->reset = 0;
147: snes->usesksp = PETSC_FALSE;
149: PetscNewLog(snes,SNES_Test,&neP);
150: snes->data = (void*)neP;
151: neP->complete_print = PETSC_FALSE;
152: return(0);
153: }
154: EXTERN_C_END