Actual source code: ex18.c
2: static char help[] ="Nonlinear Radiative Transport PDE with multigrid in 2d.\n\
3: Uses 2-dimensional distributed arrays.\n\
4: A 2-dim simplified Radiative Transport test problem is used, with analytic Jacobian. \n\
5: \n\
6: Solves the linear systems via multilevel methods \n\
7: \n\
8: The command line\n\
9: options are:\n\
10: -tleft <tl>, where <tl> indicates the left Diriclet BC \n\
11: -tright <tr>, where <tr> indicates the right Diriclet BC \n\
12: -beta <beta>, where <beta> indicates the exponent in T \n\n";
14: /*T
15: Concepts: SNES^solving a system of nonlinear equations
16: Concepts: DA^using distributed arrays
17: Concepts: multigrid;
18: Processors: n
19: T*/
21: /*
22:
23: This example models the partial differential equation
24:
25: - Div(alpha* T^beta (GRAD T)) = 0.
26:
27: where beta = 2.5 and alpha = 1.0
28:
29: BC: T_left = 1.0, T_right = 0.1, dT/dn_top = dTdn_bottom = 0.
30:
31: in the unit square, which is uniformly discretized in each of x and
32: y in this simple encoding. The degrees of freedom are cell centered.
33:
34: A finite volume approximation with the usual 5-point stencil
35: is used to discretize the boundary value problem to obtain a
36: nonlinear system of equations.
38: This code was contributed by David Keyes
39:
40: */
42: #include petscsnes.h
43: #include petscda.h
44: #include petscmg.h
46: /* User-defined application context */
48: typedef struct {
49: PetscReal tleft,tright; /* Dirichlet boundary conditions */
50: PetscReal beta,bm1,coef; /* nonlinear diffusivity parameterizations */
51: } AppCtx;
53: #define POWFLOP 5 /* assume a pow() takes five flops */
61: int main(int argc,char **argv)
62: {
63: DMMG *dmmg;
64: SNES snes;
65: AppCtx user;
67: PetscInt its,lits;
68: PetscReal litspit;
69: DA da;
71: PetscInitialize(&argc,&argv,PETSC_NULL,help);
73: /* set problem parameters */
74: user.tleft = 1.0;
75: user.tright = 0.1;
76: user.beta = 2.5;
77: PetscOptionsGetReal(PETSC_NULL,"-tleft",&user.tleft,PETSC_NULL);
78: PetscOptionsGetReal(PETSC_NULL,"-tright",&user.tright,PETSC_NULL);
79: PetscOptionsGetReal(PETSC_NULL,"-beta",&user.beta,PETSC_NULL);
80: user.bm1 = user.beta - 1.0;
81: user.coef = user.beta/2.0;
84: /*
85: Create the multilevel DA data structure
86: */
87: DMMGCreate(PETSC_COMM_WORLD,3,&user,&dmmg);
89: /*
90: Set the DA (grid structure) for the grids.
91: */
92: DACreate2d(PETSC_COMM_WORLD,DA_NONPERIODIC,DA_STENCIL_STAR,5,5,PETSC_DECIDE,PETSC_DECIDE,1,1,0,0,&da);
93: DMMGSetDM(dmmg,(DM)da);
94: DADestroy(da);
96: /*
97: Create the nonlinear solver, and tell the DMMG structure to use it
98: */
99: DMMGSetSNES(dmmg,FormFunction,FormJacobian);
101: /*
102: PreLoadBegin() means that the following section of code is run twice. The first time
103: through the flag PreLoading is on this the nonlinear solver is only run for a single step.
104: The second time through (the actually timed code) the maximum iterations is set to 10
105: Preload of the executable is done to eliminate from the timing the time spent bring the
106: executable into memory from disk (paging in).
107: */
108: PreLoadBegin(PETSC_TRUE,"Solve");
109: DMMGSetInitialGuess(dmmg,FormInitialGuess);
110: DMMGSolve(dmmg);
111: PreLoadEnd();
112: snes = DMMGGetSNES(dmmg);
113: SNESGetIterationNumber(snes,&its);
114: SNESGetNumberLinearIterations(snes,&lits);
115: litspit = ((PetscReal)lits)/((PetscReal)its);
116: PetscPrintf(PETSC_COMM_WORLD,"Number of Newton iterations = %D\n",its);
117: PetscPrintf(PETSC_COMM_WORLD,"Number of Linear iterations = %D\n",lits);
118: PetscPrintf(PETSC_COMM_WORLD,"Average Linear its / Newton = %e\n",litspit);
120: DMMGDestroy(dmmg);
121: PetscFinalize();
123: return 0;
124: }
125: /* -------------------- Form initial approximation ----------------- */
128: PetscErrorCode FormInitialGuess(DMMG dmmg,Vec X)
129: {
130: AppCtx *user = (AppCtx*)dmmg->user;
131: PetscInt i,j,xs,ys,xm,ym;
133: PetscReal tleft = user->tleft;
134: PetscScalar **x;
138: /* Get ghost points */
139: DAGetCorners((DA)dmmg->dm,&xs,&ys,0,&xm,&ym,0);
140: DAVecGetArray((DA)dmmg->dm,X,&x);
142: /* Compute initial guess */
143: for (j=ys; j<ys+ym; j++) {
144: for (i=xs; i<xs+xm; i++) {
145: x[j][i] = tleft;
146: }
147: }
148: DAVecRestoreArray((DA)dmmg->dm,X,&x);
149: return(0);
150: }
151: /* -------------------- Evaluate Function F(x) --------------------- */
154: PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void* ptr)
155: {
156: DMMG dmmg = (DMMG)ptr;
157: AppCtx *user = (AppCtx*)dmmg->user;
159: PetscInt i,j,mx,my,xs,ys,xm,ym;
160: PetscScalar zero = 0.0,one = 1.0;
161: PetscScalar hx,hy,hxdhy,hydhx;
162: PetscScalar t0,tn,ts,te,tw,an,as,ae,aw,dn,ds,de,dw,fn = 0.0,fs = 0.0,fe =0.0,fw = 0.0;
163: PetscScalar tleft,tright,beta;
164: PetscScalar **x,**f;
165: Vec localX;
168: DAGetLocalVector((DA)dmmg->dm,&localX);
169: DAGetInfo((DA)dmmg->dm,PETSC_NULL,&mx,&my,0,0,0,0,0,0,0,0);
170: hx = one/(PetscReal)(mx-1); hy = one/(PetscReal)(my-1);
171: hxdhy = hx/hy; hydhx = hy/hx;
172: tleft = user->tleft; tright = user->tright;
173: beta = user->beta;
174:
175: /* Get ghost points */
176: DAGlobalToLocalBegin((DA)dmmg->dm,X,INSERT_VALUES,localX);
177: DAGlobalToLocalEnd((DA)dmmg->dm,X,INSERT_VALUES,localX);
178: DAGetCorners((DA)dmmg->dm,&xs,&ys,0,&xm,&ym,0);
179: DAVecGetArray((DA)dmmg->dm,localX,&x);
180: DAVecGetArray((DA)dmmg->dm,F,&f);
182: /* Evaluate function */
183: for (j=ys; j<ys+ym; j++) {
184: for (i=xs; i<xs+xm; i++) {
185: t0 = x[j][i];
187: if (i > 0 && i < mx-1 && j > 0 && j < my-1) {
189: /* general interior volume */
191: tw = x[j][i-1];
192: aw = 0.5*(t0 + tw);
193: dw = PetscPowScalar(aw,beta);
194: fw = dw*(t0 - tw);
196: te = x[j][i+1];
197: ae = 0.5*(t0 + te);
198: de = PetscPowScalar(ae,beta);
199: fe = de*(te - t0);
201: ts = x[j-1][i];
202: as = 0.5*(t0 + ts);
203: ds = PetscPowScalar(as,beta);
204: fs = ds*(t0 - ts);
205:
206: tn = x[j+1][i];
207: an = 0.5*(t0 + tn);
208: dn = PetscPowScalar(an,beta);
209: fn = dn*(tn - t0);
211: } else if (i == 0) {
213: /* left-hand boundary */
214: tw = tleft;
215: aw = 0.5*(t0 + tw);
216: dw = PetscPowScalar(aw,beta);
217: fw = dw*(t0 - tw);
219: te = x[j][i+1];
220: ae = 0.5*(t0 + te);
221: de = PetscPowScalar(ae,beta);
222: fe = de*(te - t0);
224: if (j > 0) {
225: ts = x[j-1][i];
226: as = 0.5*(t0 + ts);
227: ds = PetscPowScalar(as,beta);
228: fs = ds*(t0 - ts);
229: } else {
230: fs = zero;
231: }
233: if (j < my-1) {
234: tn = x[j+1][i];
235: an = 0.5*(t0 + tn);
236: dn = PetscPowScalar(an,beta);
237: fn = dn*(tn - t0);
238: } else {
239: fn = zero;
240: }
242: } else if (i == mx-1) {
244: /* right-hand boundary */
245: tw = x[j][i-1];
246: aw = 0.5*(t0 + tw);
247: dw = PetscPowScalar(aw,beta);
248: fw = dw*(t0 - tw);
249:
250: te = tright;
251: ae = 0.5*(t0 + te);
252: de = PetscPowScalar(ae,beta);
253: fe = de*(te - t0);
254:
255: if (j > 0) {
256: ts = x[j-1][i];
257: as = 0.5*(t0 + ts);
258: ds = PetscPowScalar(as,beta);
259: fs = ds*(t0 - ts);
260: } else {
261: fs = zero;
262: }
263:
264: if (j < my-1) {
265: tn = x[j+1][i];
266: an = 0.5*(t0 + tn);
267: dn = PetscPowScalar(an,beta);
268: fn = dn*(tn - t0);
269: } else {
270: fn = zero;
271: }
273: } else if (j == 0) {
275: /* bottom boundary,and i <> 0 or mx-1 */
276: tw = x[j][i-1];
277: aw = 0.5*(t0 + tw);
278: dw = PetscPowScalar(aw,beta);
279: fw = dw*(t0 - tw);
281: te = x[j][i+1];
282: ae = 0.5*(t0 + te);
283: de = PetscPowScalar(ae,beta);
284: fe = de*(te - t0);
286: fs = zero;
288: tn = x[j+1][i];
289: an = 0.5*(t0 + tn);
290: dn = PetscPowScalar(an,beta);
291: fn = dn*(tn - t0);
293: } else if (j == my-1) {
295: /* top boundary,and i <> 0 or mx-1 */
296: tw = x[j][i-1];
297: aw = 0.5*(t0 + tw);
298: dw = PetscPowScalar(aw,beta);
299: fw = dw*(t0 - tw);
301: te = x[j][i+1];
302: ae = 0.5*(t0 + te);
303: de = PetscPowScalar(ae,beta);
304: fe = de*(te - t0);
306: ts = x[j-1][i];
307: as = 0.5*(t0 + ts);
308: ds = PetscPowScalar(as,beta);
309: fs = ds*(t0 - ts);
311: fn = zero;
313: }
315: f[j][i] = - hydhx*(fe-fw) - hxdhy*(fn-fs);
317: }
318: }
319: DAVecRestoreArray((DA)dmmg->dm,localX,&x);
320: DAVecRestoreArray((DA)dmmg->dm,F,&f);
321: DARestoreLocalVector((DA)dmmg->dm,&localX);
322: PetscLogFlops((22 + 4*POWFLOP)*ym*xm);
323: return(0);
324: }
325: /* -------------------- Evaluate Jacobian F(x) --------------------- */
328: PetscErrorCode FormJacobian(SNES snes,Vec X,Mat *J,Mat *B,MatStructure *flg,void *ptr)
329: {
330: DMMG dmmg = (DMMG)ptr;
331: AppCtx *user = (AppCtx*)dmmg->user;
332: Mat jac = *J;
334: PetscInt i,j,mx,my,xs,ys,xm,ym;
335: PetscScalar one = 1.0,hx,hy,hxdhy,hydhx,t0,tn,ts,te,tw;
336: PetscScalar dn,ds,de,dw,an,as,ae,aw,bn,bs,be,bw,gn,gs,ge,gw;
337: PetscScalar tleft,tright,beta,bm1,coef;
338: PetscScalar v[5],**x;
339: Vec localX;
340: MatStencil col[5],row;
343: DAGetLocalVector((DA)dmmg->dm,&localX);
344: *flg = SAME_NONZERO_PATTERN;
345: DAGetInfo((DA)dmmg->dm,PETSC_NULL,&mx,&my,0,0,0,0,0,0,0,0);
346: hx = one/(PetscReal)(mx-1); hy = one/(PetscReal)(my-1);
347: hxdhy = hx/hy; hydhx = hy/hx;
348: tleft = user->tleft; tright = user->tright;
349: beta = user->beta; bm1 = user->bm1; coef = user->coef;
351: /* Get ghost points */
352: DAGlobalToLocalBegin((DA)dmmg->dm,X,INSERT_VALUES,localX);
353: DAGlobalToLocalEnd((DA)dmmg->dm,X,INSERT_VALUES,localX);
354: DAGetCorners((DA)dmmg->dm,&xs,&ys,0,&xm,&ym,0);
355: DAVecGetArray((DA)dmmg->dm,localX,&x);
357: /* Evaluate Jacobian of function */
358: for (j=ys; j<ys+ym; j++) {
359: for (i=xs; i<xs+xm; i++) {
360: t0 = x[j][i];
362: if (i > 0 && i < mx-1 && j > 0 && j < my-1) {
364: /* general interior volume */
366: tw = x[j][i-1];
367: aw = 0.5*(t0 + tw);
368: bw = PetscPowScalar(aw,bm1);
369: /* dw = bw * aw */
370: dw = PetscPowScalar(aw,beta);
371: gw = coef*bw*(t0 - tw);
373: te = x[j][i+1];
374: ae = 0.5*(t0 + te);
375: be = PetscPowScalar(ae,bm1);
376: /* de = be * ae; */
377: de = PetscPowScalar(ae,beta);
378: ge = coef*be*(te - t0);
380: ts = x[j-1][i];
381: as = 0.5*(t0 + ts);
382: bs = PetscPowScalar(as,bm1);
383: /* ds = bs * as; */
384: ds = PetscPowScalar(as,beta);
385: gs = coef*bs*(t0 - ts);
386:
387: tn = x[j+1][i];
388: an = 0.5*(t0 + tn);
389: bn = PetscPowScalar(an,bm1);
390: /* dn = bn * an; */
391: dn = PetscPowScalar(an,beta);
392: gn = coef*bn*(tn - t0);
394: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
395: v[1] = - hydhx*(dw - gw); col[1].j = j; col[1].i = i-1;
396: v[2] = hxdhy*(ds + dn + gs - gn) + hydhx*(dw + de + gw - ge); col[2].j = row.j = j; col[2].i = row.i = i;
397: v[3] = - hydhx*(de + ge); col[3].j = j; col[3].i = i+1;
398: v[4] = - hxdhy*(dn + gn); col[4].j = j+1; col[4].i = i;
399: MatSetValuesStencil(jac,1,&row,5,col,v,INSERT_VALUES);
401: } else if (i == 0) {
403: /* left-hand boundary */
404: tw = tleft;
405: aw = 0.5*(t0 + tw);
406: bw = PetscPowScalar(aw,bm1);
407: /* dw = bw * aw */
408: dw = PetscPowScalar(aw,beta);
409: gw = coef*bw*(t0 - tw);
410:
411: te = x[j][i + 1];
412: ae = 0.5*(t0 + te);
413: be = PetscPowScalar(ae,bm1);
414: /* de = be * ae; */
415: de = PetscPowScalar(ae,beta);
416: ge = coef*be*(te - t0);
417:
418: /* left-hand bottom boundary */
419: if (j == 0) {
421: tn = x[j+1][i];
422: an = 0.5*(t0 + tn);
423: bn = PetscPowScalar(an,bm1);
424: /* dn = bn * an; */
425: dn = PetscPowScalar(an,beta);
426: gn = coef*bn*(tn - t0);
427:
428: v[0] = hxdhy*(dn - gn) + hydhx*(dw + de + gw - ge); col[0].j = row.j = j; col[0].i = row.i = i;
429: v[1] = - hydhx*(de + ge); col[1].j = j; col[1].i = i+1;
430: v[2] = - hxdhy*(dn + gn); col[2].j = j+1; col[2].i = i;
431: MatSetValuesStencil(jac,1,&row,3,col,v,INSERT_VALUES);
432:
433: /* left-hand interior boundary */
434: } else if (j < my-1) {
436: ts = x[j-1][i];
437: as = 0.5*(t0 + ts);
438: bs = PetscPowScalar(as,bm1);
439: /* ds = bs * as; */
440: ds = PetscPowScalar(as,beta);
441: gs = coef*bs*(t0 - ts);
442:
443: tn = x[j+1][i];
444: an = 0.5*(t0 + tn);
445: bn = PetscPowScalar(an,bm1);
446: /* dn = bn * an; */
447: dn = PetscPowScalar(an,beta);
448: gn = coef*bn*(tn - t0);
449:
450: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
451: v[1] = hxdhy*(ds + dn + gs - gn) + hydhx*(dw + de + gw - ge); col[1].j = row.j = j; col[1].i = row.i = i;
452: v[2] = - hydhx*(de + ge); col[2].j = j; col[2].i = i+1;
453: v[3] = - hxdhy*(dn + gn); col[3].j = j+1; col[3].i = i;
454: MatSetValuesStencil(jac,1,&row,4,col,v,INSERT_VALUES);
455: /* left-hand top boundary */
456: } else {
458: ts = x[j-1][i];
459: as = 0.5*(t0 + ts);
460: bs = PetscPowScalar(as,bm1);
461: /* ds = bs * as; */
462: ds = PetscPowScalar(as,beta);
463: gs = coef*bs*(t0 - ts);
464:
465: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
466: v[1] = hxdhy*(ds + gs) + hydhx*(dw + de + gw - ge); col[1].j = row.j = j; col[1].i = row.i = i;
467: v[2] = - hydhx*(de + ge); col[2].j = j; col[2].i = i+1;
468: MatSetValuesStencil(jac,1,&row,3,col,v,INSERT_VALUES);
469: }
471: } else if (i == mx-1) {
472:
473: /* right-hand boundary */
474: tw = x[j][i-1];
475: aw = 0.5*(t0 + tw);
476: bw = PetscPowScalar(aw,bm1);
477: /* dw = bw * aw */
478: dw = PetscPowScalar(aw,beta);
479: gw = coef*bw*(t0 - tw);
480:
481: te = tright;
482: ae = 0.5*(t0 + te);
483: be = PetscPowScalar(ae,bm1);
484: /* de = be * ae; */
485: de = PetscPowScalar(ae,beta);
486: ge = coef*be*(te - t0);
487:
488: /* right-hand bottom boundary */
489: if (j == 0) {
491: tn = x[j+1][i];
492: an = 0.5*(t0 + tn);
493: bn = PetscPowScalar(an,bm1);
494: /* dn = bn * an; */
495: dn = PetscPowScalar(an,beta);
496: gn = coef*bn*(tn - t0);
497:
498: v[0] = - hydhx*(dw - gw); col[0].j = j; col[0].i = i-1;
499: v[1] = hxdhy*(dn - gn) + hydhx*(dw + de + gw - ge); col[1].j = row.j = j; col[1].i = row.i = i;
500: v[2] = - hxdhy*(dn + gn); col[2].j = j+1; col[2].i = i;
501: MatSetValuesStencil(jac,1,&row,3,col,v,INSERT_VALUES);
502:
503: /* right-hand interior boundary */
504: } else if (j < my-1) {
506: ts = x[j-1][i];
507: as = 0.5*(t0 + ts);
508: bs = PetscPowScalar(as,bm1);
509: /* ds = bs * as; */
510: ds = PetscPowScalar(as,beta);
511: gs = coef*bs*(t0 - ts);
512:
513: tn = x[j+1][i];
514: an = 0.5*(t0 + tn);
515: bn = PetscPowScalar(an,bm1);
516: /* dn = bn * an; */
517: dn = PetscPowScalar(an,beta);
518: gn = coef*bn*(tn - t0);
519:
520: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
521: v[1] = - hydhx*(dw - gw); col[1].j = j; col[1].i = i-1;
522: v[2] = hxdhy*(ds + dn + gs - gn) + hydhx*(dw + de + gw - ge); col[2].j = row.j = j; col[2].i = row.i = i;
523: v[3] = - hxdhy*(dn + gn); col[3].j = j+1; col[3].i = i;
524: MatSetValuesStencil(jac,1,&row,4,col,v,INSERT_VALUES);
525: /* right-hand top boundary */
526: } else {
528: ts = x[j-1][i];
529: as = 0.5*(t0 + ts);
530: bs = PetscPowScalar(as,bm1);
531: /* ds = bs * as; */
532: ds = PetscPowScalar(as,beta);
533: gs = coef*bs*(t0 - ts);
534:
535: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
536: v[1] = - hydhx*(dw - gw); col[1].j = j; col[1].i = i-1;
537: v[2] = hxdhy*(ds + gs) + hydhx*(dw + de + gw - ge); col[2].j = row.j = j; col[2].i = row.i = i;
538: MatSetValuesStencil(jac,1,&row,3,col,v,INSERT_VALUES);
539: }
541: /* bottom boundary,and i <> 0 or mx-1 */
542: } else if (j == 0) {
544: tw = x[j][i-1];
545: aw = 0.5*(t0 + tw);
546: bw = PetscPowScalar(aw,bm1);
547: /* dw = bw * aw */
548: dw = PetscPowScalar(aw,beta);
549: gw = coef*bw*(t0 - tw);
551: te = x[j][i+1];
552: ae = 0.5*(t0 + te);
553: be = PetscPowScalar(ae,bm1);
554: /* de = be * ae; */
555: de = PetscPowScalar(ae,beta);
556: ge = coef*be*(te - t0);
558: tn = x[j+1][i];
559: an = 0.5*(t0 + tn);
560: bn = PetscPowScalar(an,bm1);
561: /* dn = bn * an; */
562: dn = PetscPowScalar(an,beta);
563: gn = coef*bn*(tn - t0);
564:
565: v[0] = - hydhx*(dw - gw); col[0].j = j; col[0].i = i-1;
566: v[1] = hxdhy*(dn - gn) + hydhx*(dw + de + gw - ge); col[1].j = row.j = j; col[1].i = row.i = i;
567: v[2] = - hydhx*(de + ge); col[2].j = j; col[2].i = i+1;
568: v[3] = - hxdhy*(dn + gn); col[3].j = j+1; col[3].i = i;
569: MatSetValuesStencil(jac,1,&row,4,col,v,INSERT_VALUES);
570:
571: /* top boundary,and i <> 0 or mx-1 */
572: } else if (j == my-1) {
573:
574: tw = x[j][i-1];
575: aw = 0.5*(t0 + tw);
576: bw = PetscPowScalar(aw,bm1);
577: /* dw = bw * aw */
578: dw = PetscPowScalar(aw,beta);
579: gw = coef*bw*(t0 - tw);
581: te = x[j][i+1];
582: ae = 0.5*(t0 + te);
583: be = PetscPowScalar(ae,bm1);
584: /* de = be * ae; */
585: de = PetscPowScalar(ae,beta);
586: ge = coef*be*(te - t0);
588: ts = x[j-1][i];
589: as = 0.5*(t0 + ts);
590: bs = PetscPowScalar(as,bm1);
591: /* ds = bs * as; */
592: ds = PetscPowScalar(as,beta);
593: gs = coef*bs*(t0 - ts);
595: v[0] = - hxdhy*(ds - gs); col[0].j = j-1; col[0].i = i;
596: v[1] = - hydhx*(dw - gw); col[1].j = j; col[1].i = i-1;
597: v[2] = hxdhy*(ds + gs) + hydhx*(dw + de + gw - ge); col[2].j = row.j = j; col[2].i = row.i = i;
598: v[3] = - hydhx*(de + ge); col[3].j = j; col[3].i = i+1;
599: MatSetValuesStencil(jac,1,&row,4,col,v,INSERT_VALUES);
600:
601: }
602: }
603: }
604: MatAssemblyBegin(jac,MAT_FINAL_ASSEMBLY);
605: DAVecRestoreArray((DA)dmmg->dm,localX,&x);
606: MatAssemblyEnd(jac,MAT_FINAL_ASSEMBLY);
607: DARestoreLocalVector((DA)dmmg->dm,&localX);
609: PetscLogFlops((41 + 8*POWFLOP)*xm*ym);
610: return(0);
611: }