xref: /petsc/src/sys/classes/draw/utils/axisc.c (revision 1b37a2a7cc4a4fb30c3e967db1c694c0a1013f51)
1 #include <petsc/private/drawimpl.h> /*I   "petscdraw.h"  I*/
2 
3 #define PETSC_DRAW_AXIS_MAX_SEGMENTS 20
4 PetscClassId PETSC_DRAWAXIS_CLASSID = 0;
5 
6 /*@
7   PetscDrawAxisCreate - Generate the axis data structure.
8 
9   Collective
10 
11   Input Parameter:
12 . draw - `PetscDraw` object where axis to to be made
13 
14   Output Parameter:
15 . axis - the axis datastructure
16 
17   Note:
18   The MPI communicator that owns the underlying draw object owns the `PetscDrawAxis` object, but calls to set `PetscDrawAxis` options are
19   ignored by all processes except the first MPI rank in the communicator
20 
21   Level: advanced
22 
23 .seealso: `PetscDrawLGCreate()`, `PetscDrawLG`, `PetscDrawSPCreate()`, `PetscDrawSP`, `PetscDrawHGCreate()`, `PetscDrawHG`, `PetscDrawBarCreate()`, `PetscDrawBar`, `PetscDrawLGGetAxis()`, `PetscDrawSPGetAxis()`,
24           `PetscDrawHGGetAxis()`, `PetscDrawBarGetAxis()`, `PetscDrawAxis`, `PetscDrawAxisDestroy()`, `PetscDrawAxisSetColors()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetHoldLimits()`,
25           `PetscDrawAxisDraw()`
26 @*/
27 PetscErrorCode PetscDrawAxisCreate(PetscDraw draw, PetscDrawAxis *axis)
28 {
29   PetscDrawAxis ad;
30 
31   PetscFunctionBegin;
32   PetscValidHeaderSpecific(draw, PETSC_DRAW_CLASSID, 1);
33   PetscAssertPointer(axis, 2);
34 
35   PetscCall(PetscHeaderCreate(ad, PETSC_DRAWAXIS_CLASSID, "DrawAxis", "Draw Axis", "Draw", PetscObjectComm((PetscObject)draw), PetscDrawAxisDestroy, NULL));
36 
37   PetscCall(PetscObjectReference((PetscObject)draw));
38   ad->win = draw;
39 
40   ad->xticks    = PetscADefTicks;
41   ad->yticks    = PetscADefTicks;
42   ad->xlabelstr = PetscADefLabel;
43   ad->ylabelstr = PetscADefLabel;
44   ad->ac        = PETSC_DRAW_BLACK;
45   ad->tc        = PETSC_DRAW_BLACK;
46   ad->cc        = PETSC_DRAW_BLACK;
47   ad->xlabel    = NULL;
48   ad->ylabel    = NULL;
49   ad->toplabel  = NULL;
50 
51   *axis = ad;
52   PetscFunctionReturn(PETSC_SUCCESS);
53 }
54 
55 /*@
56   PetscDrawAxisDestroy - Frees the space used by an axis structure.
57 
58   Collective
59 
60   Input Parameter:
61 . axis - the axis context
62 
63   Level: advanced
64 
65 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`
66 @*/
67 PetscErrorCode PetscDrawAxisDestroy(PetscDrawAxis *axis)
68 {
69   PetscFunctionBegin;
70   if (!*axis) PetscFunctionReturn(PETSC_SUCCESS);
71   PetscValidHeaderSpecific(*axis, PETSC_DRAWAXIS_CLASSID, 1);
72   if (--((PetscObject)(*axis))->refct > 0) {
73     *axis = NULL;
74     PetscFunctionReturn(PETSC_SUCCESS);
75   }
76 
77   PetscCall(PetscFree((*axis)->toplabel));
78   PetscCall(PetscFree((*axis)->xlabel));
79   PetscCall(PetscFree((*axis)->ylabel));
80   PetscCall(PetscDrawDestroy(&(*axis)->win));
81   PetscCall(PetscHeaderDestroy(axis));
82   PetscFunctionReturn(PETSC_SUCCESS);
83 }
84 
85 /*@
86   PetscDrawAxisSetColors -  Sets the colors to be used for the axis,
87   tickmarks, and text.
88 
89   Logically Collective
90 
91   Input Parameters:
92 + axis - the axis
93 . ac   - the color of the axis lines
94 . tc   - the color of the tick marks
95 - cc   - the color of the text strings
96 
97   Level: advanced
98 
99 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
100 @*/
101 PetscErrorCode PetscDrawAxisSetColors(PetscDrawAxis axis, int ac, int tc, int cc)
102 {
103   PetscFunctionBegin;
104   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
105   PetscValidLogicalCollectiveInt(axis, ac, 2);
106   PetscValidLogicalCollectiveInt(axis, tc, 3);
107   PetscValidLogicalCollectiveInt(axis, cc, 4);
108   axis->ac = ac;
109   axis->tc = tc;
110   axis->cc = cc;
111   PetscFunctionReturn(PETSC_SUCCESS);
112 }
113 
114 /*@C
115   PetscDrawAxisSetLabels -  Sets the x and y axis labels.
116 
117   Logically Collective
118 
119   Input Parameters:
120 + axis   - the axis
121 . top    - the label at the top of the image
122 . xlabel - the x axis label
123 - ylabel - the y axis label
124 
125   Level: advanced
126 
127   Notes:
128   Must be called before `PetscDrawAxisDraw()` or `PetscDrawLGDraw()`
129 
130   There should be no newlines in the arguments
131 
132 .seealso: `PetscDraw`, `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetColors()`, `PetscDrawAxisDraw()`, `PetscDrawAxisSetLimits()`
133 @*/
134 PetscErrorCode PetscDrawAxisSetLabels(PetscDrawAxis axis, const char top[], const char xlabel[], const char ylabel[])
135 {
136   PetscFunctionBegin;
137   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
138   PetscCall(PetscFree(axis->xlabel));
139   PetscCall(PetscFree(axis->ylabel));
140   PetscCall(PetscFree(axis->toplabel));
141   PetscCall(PetscStrallocpy(xlabel, &axis->xlabel));
142   PetscCall(PetscStrallocpy(ylabel, &axis->ylabel));
143   PetscCall(PetscStrallocpy(top, &axis->toplabel));
144   PetscFunctionReturn(PETSC_SUCCESS);
145 }
146 
147 /*@
148   PetscDrawAxisSetLimits -  Sets the limits (in user coords) of the axis
149 
150   Logically Collective
151 
152   Input Parameters:
153 + axis - the axis
154 . xmin - the lower x limit
155 . xmax - the upper x limit
156 . ymin - the lower y limit
157 - ymax - the upper y limit
158 
159   Options Database Key:
160 . -drawaxis_hold - hold the initial set of axis limits for future plotting
161 
162   Level: advanced
163 
164 .seealso: `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
165 @*/
166 PetscErrorCode PetscDrawAxisSetLimits(PetscDrawAxis axis, PetscReal xmin, PetscReal xmax, PetscReal ymin, PetscReal ymax)
167 {
168   PetscFunctionBegin;
169   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
170   if (axis->hold) PetscFunctionReturn(PETSC_SUCCESS);
171   axis->xlow  = xmin;
172   axis->xhigh = xmax;
173   axis->ylow  = ymin;
174   axis->yhigh = ymax;
175   PetscCall(PetscOptionsHasName(((PetscObject)axis)->options, ((PetscObject)axis)->prefix, "-drawaxis_hold", &axis->hold));
176   PetscFunctionReturn(PETSC_SUCCESS);
177 }
178 
179 /*@
180   PetscDrawAxisGetLimits -  Gets the limits (in user coords) of the axis
181 
182   Not Collective
183 
184   Input Parameters:
185 + axis - the axis
186 . xmin - the lower x limit
187 . xmax - the upper x limit
188 . ymin - the lower y limit
189 - ymax - the upper y limit
190 
191   Level: advanced
192 
193 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisSetHoldLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
194 @*/
195 PetscErrorCode PetscDrawAxisGetLimits(PetscDrawAxis axis, PetscReal *xmin, PetscReal *xmax, PetscReal *ymin, PetscReal *ymax)
196 {
197   PetscFunctionBegin;
198   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
199   if (xmin) *xmin = axis->xlow;
200   if (xmax) *xmax = axis->xhigh;
201   if (ymin) *ymin = axis->ylow;
202   if (ymax) *ymax = axis->yhigh;
203   PetscFunctionReturn(PETSC_SUCCESS);
204 }
205 
206 /*@
207   PetscDrawAxisSetHoldLimits -  Causes an axis to keep the same limits until this is called
208   again
209 
210   Logically Collective
211 
212   Input Parameters:
213 + axis - the axis
214 - hold - `PETSC_TRUE` - hold current limits, `PETSC_FALSE` allow limits to be changed
215 
216   Level: advanced
217 
218   Note:
219   Once this has been called with `PETSC_TRUE` the limits will not change if you call
220   `PetscDrawAxisSetLimits()` until you call this with `PETSC_FALSE`
221 
222 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
223 @*/
224 PetscErrorCode PetscDrawAxisSetHoldLimits(PetscDrawAxis axis, PetscBool hold)
225 {
226   PetscFunctionBegin;
227   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
228   PetscValidLogicalCollectiveBool(axis, hold, 2);
229   axis->hold = hold;
230   PetscFunctionReturn(PETSC_SUCCESS);
231 }
232 
233 /*@
234   PetscDrawAxisDraw - draws an axis.
235 
236   Collective
237 
238   Input Parameter:
239 . axis - `PetscDrawAxis` structure
240 
241   Level: advanced
242 
243   Note:
244   This draws the actual axis.  The limits etc have already been set.
245   By picking special routines for the ticks and labels, special
246   effects may be generated.  These routines are part of the Axis
247   structure (axis).
248 
249 .seealso: `PetscDrawAxisCreate()`, `PetscDrawAxis`, `PetscDrawAxisGetLimits()`, `PetscDrawAxisSetLimits()`, `PetscDrawAxisSetLabels()`, `PetscDrawAxisSetColors()`
250 @*/
251 PetscErrorCode PetscDrawAxisDraw(PetscDrawAxis axis)
252 {
253   int         i, ntick, numx, numy, ac, tc, cc;
254   PetscMPIInt rank;
255   size_t      len, ytlen = 0;
256   PetscReal   coors[4], tickloc[PETSC_DRAW_AXIS_MAX_SEGMENTS], sep, tw, th;
257   PetscReal   xl, xr, yl, yr, dxl = 0, dyl = 0, dxr = 0, dyr = 0;
258   char       *p;
259   PetscDraw   draw;
260   PetscBool   isnull;
261 
262   PetscFunctionBegin;
263   PetscValidHeaderSpecific(axis, PETSC_DRAWAXIS_CLASSID, 1);
264   PetscCall(PetscDrawIsNull(axis->win, &isnull));
265   if (isnull) PetscFunctionReturn(PETSC_SUCCESS);
266   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)axis), &rank));
267 
268   draw = axis->win;
269 
270   ac = axis->ac;
271   tc = axis->tc;
272   cc = axis->cc;
273   if (axis->xlow == axis->xhigh) {
274     axis->xlow -= .5;
275     axis->xhigh += .5;
276   }
277   if (axis->ylow == axis->yhigh) {
278     axis->ylow -= .5;
279     axis->yhigh += .5;
280   }
281 
282   PetscDrawCollectiveBegin(draw);
283   if (rank) goto finally;
284 
285   /* get canonical string size */
286   PetscCall(PetscDrawSetCoordinates(draw, 0, 0, 1, 1));
287   PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
288   /* lower spacing */
289   if (axis->xlabelstr) dyl += 1.5 * th;
290   if (axis->xlabel) dyl += 1.5 * th;
291   /* left spacing */
292   if (axis->ylabelstr) dxl += 7.5 * tw;
293   if (axis->ylabel) dxl += 2.0 * tw;
294   /* right and top spacing */
295   if (axis->xlabelstr) dxr = 2.5 * tw;
296   if (axis->ylabelstr) dyr = 0.5 * th;
297   if (axis->toplabel) dyr = 1.5 * th;
298   /* extra spacing */
299   dxl += 0.7 * tw;
300   dxr += 0.5 * tw;
301   dyl += 0.2 * th;
302   dyr += 0.2 * th;
303   /* determine coordinates */
304   xl = (dxl * axis->xhigh + dxr * axis->xlow - axis->xlow) / (dxl + dxr - 1);
305   xr = (dxl * axis->xhigh + dxr * axis->xlow - axis->xhigh) / (dxl + dxr - 1);
306   yl = (dyl * axis->yhigh + dyr * axis->ylow - axis->ylow) / (dyl + dyr - 1);
307   yr = (dyl * axis->yhigh + dyr * axis->ylow - axis->yhigh) / (dyl + dyr - 1);
308   PetscCall(PetscDrawSetCoordinates(draw, xl, yl, xr, yr));
309   PetscCall(PetscDrawStringGetSize(draw, &tw, &th));
310 
311   /* PetscDraw the axis lines */
312   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xhigh, axis->ylow, ac));
313   PetscCall(PetscDrawLine(draw, axis->xlow, axis->ylow, axis->xlow, axis->yhigh, ac));
314   PetscCall(PetscDrawLine(draw, axis->xlow, axis->yhigh, axis->xhigh, axis->yhigh, ac));
315   PetscCall(PetscDrawLine(draw, axis->xhigh, axis->ylow, axis->xhigh, axis->yhigh, ac));
316 
317   /* PetscDraw the top label */
318   if (axis->toplabel) {
319     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->yhigh + 0.5 * th;
320     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->toplabel));
321   }
322 
323   /* PetscDraw the X ticks and labels */
324   if (axis->xticks) {
325     numx = (int)(.15 * (axis->xhigh - axis->xlow) / tw);
326     numx = PetscClipInterval(numx, 2, 6);
327     PetscCall((*axis->xticks)(axis->xlow, axis->xhigh, numx, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
328     /* PetscDraw in tick marks */
329     for (i = 0; i < ntick; i++) {
330       PetscCall(PetscDrawLine(draw, tickloc[i], axis->ylow, tickloc[i], axis->ylow + .5 * th, tc));
331       PetscCall(PetscDrawLine(draw, tickloc[i], axis->yhigh, tickloc[i], axis->yhigh - .5 * th, tc));
332     }
333     /* label ticks */
334     if (axis->xlabelstr) {
335       for (i = 0; i < ntick; i++) {
336         if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
337         else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
338         else sep = 0.0;
339         PetscCall((*axis->xlabelstr)(tickloc[i], sep, &p));
340         PetscCall(PetscDrawStringCentered(draw, tickloc[i], axis->ylow - 1.5 * th, cc, p));
341       }
342     }
343   }
344   if (axis->xlabel) {
345     PetscReal x = (axis->xlow + axis->xhigh) / 2, y = axis->ylow - 1.5 * th;
346     if (axis->xlabelstr) y -= 1.5 * th;
347     PetscCall(PetscDrawStringCentered(draw, x, y, cc, axis->xlabel));
348   }
349 
350   /* PetscDraw the Y ticks and labels */
351   if (axis->yticks) {
352     numy = (int)(.50 * (axis->yhigh - axis->ylow) / th);
353     numy = PetscClipInterval(numy, 2, 6);
354     PetscCall((*axis->yticks)(axis->ylow, axis->yhigh, numy, &ntick, tickloc, PETSC_DRAW_AXIS_MAX_SEGMENTS));
355     /* PetscDraw in tick marks */
356     for (i = 0; i < ntick; i++) {
357       PetscCall(PetscDrawLine(draw, axis->xlow, tickloc[i], axis->xlow + .5 * tw, tickloc[i], tc));
358       PetscCall(PetscDrawLine(draw, axis->xhigh, tickloc[i], axis->xhigh - .5 * tw, tickloc[i], tc));
359     }
360     /* label ticks */
361     if (axis->ylabelstr) {
362       for (i = 0; i < ntick; i++) {
363         if (i < ntick - 1) sep = tickloc[i + 1] - tickloc[i];
364         else if (i > 0) sep = tickloc[i] - tickloc[i - 1];
365         else sep = 0.0;
366         PetscCall((*axis->ylabelstr)(tickloc[i], sep, &p));
367         PetscCall(PetscStrlen(p, &len));
368         ytlen = PetscMax(ytlen, len);
369         PetscCall(PetscDrawString(draw, axis->xlow - (len + .5) * tw, tickloc[i] - .5 * th, cc, p));
370       }
371     }
372   }
373   if (axis->ylabel) {
374     PetscReal x = axis->xlow - 2.0 * tw, y = (axis->ylow + axis->yhigh) / 2;
375     if (axis->ylabelstr) x -= (ytlen + .5) * tw;
376     PetscCall(PetscStrlen(axis->ylabel, &len));
377     PetscCall(PetscDrawStringVertical(draw, x, y + len * th / 2, cc, axis->ylabel));
378   }
379 
380   PetscCall(PetscDrawGetCoordinates(draw, &coors[0], &coors[1], &coors[2], &coors[3]));
381 finally:
382   PetscDrawCollectiveEnd(draw);
383   PetscCallMPI(MPI_Bcast(coors, 4, MPIU_REAL, 0, PetscObjectComm((PetscObject)draw)));
384   PetscCall(PetscDrawSetCoordinates(draw, coors[0], coors[1], coors[2], coors[3]));
385   PetscFunctionReturn(PETSC_SUCCESS);
386 }
387 
388 /*
389     Removes all zeros but one from .0000
390 */
391 PetscErrorCode PetscStripe0(char *buf)
392 {
393   size_t    n;
394   PetscBool flg;
395   char     *str = NULL;
396 
397   PetscFunctionBegin;
398   PetscCall(PetscStrlen(buf, &n));
399   PetscCall(PetscStrendswith(buf, "e00", &flg));
400   if (flg) buf[n - 3] = 0;
401   PetscCall(PetscStrstr(buf, "e0", &str));
402   if (str) {
403     buf[n - 2] = buf[n - 1];
404     buf[n - 1] = 0;
405   }
406   PetscCall(PetscStrstr(buf, "e-0", &str));
407   if (str) {
408     buf[n - 2] = buf[n - 1];
409     buf[n - 1] = 0;
410   }
411   PetscFunctionReturn(PETSC_SUCCESS);
412 }
413 
414 /*
415     Removes all zeros but one from .0000
416 */
417 PetscErrorCode PetscStripAllZeros(char *buf)
418 {
419   size_t i, n;
420 
421   PetscFunctionBegin;
422   PetscCall(PetscStrlen(buf, &n));
423   if (buf[0] != '.') PetscFunctionReturn(PETSC_SUCCESS);
424   for (i = 1; i < n; i++) {
425     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
426   }
427   buf[0] = '0';
428   buf[1] = 0;
429   PetscFunctionReturn(PETSC_SUCCESS);
430 }
431 
432 /*
433     Removes trailing zeros
434 */
435 #if (PETSC_SIZEOF_SIZE_T == 8)
436   #define MAX_SIZE_T PETSC_INT64_MAX
437 #else
438   #define MAX_SIZE_T INT_MAX
439 #endif
440 PetscErrorCode PetscStripTrailingZeros(char *buf)
441 {
442   char  *found = NULL;
443   size_t i, n, m = MAX_SIZE_T;
444 
445   PetscFunctionBegin;
446   /* if there is an e in string DO NOT strip trailing zeros */
447   PetscCall(PetscStrchr(buf, 'e', &found));
448   if (found) PetscFunctionReturn(PETSC_SUCCESS);
449 
450   PetscCall(PetscStrlen(buf, &n));
451   /* locate decimal point */
452   for (i = 0; i < n; i++) {
453     if (buf[i] == '.') {
454       m = i;
455       break;
456     }
457   }
458   /* if not decimal point then no zeros to remove */
459   if (m == MAX_SIZE_T) PetscFunctionReturn(PETSC_SUCCESS);
460   /* start at right end of string removing 0s */
461   for (i = n - 1; i > m; i++) {
462     if (buf[i] != '0') PetscFunctionReturn(PETSC_SUCCESS);
463     buf[i] = 0;
464   }
465   PetscFunctionReturn(PETSC_SUCCESS);
466 }
467 
468 /*
469     Removes leading 0 from 0.22 or -0.22
470 */
471 PetscErrorCode PetscStripInitialZero(char *buf)
472 {
473   size_t i, n;
474 
475   PetscFunctionBegin;
476   PetscCall(PetscStrlen(buf, &n));
477   if (buf[0] == '0') {
478     for (i = 0; i < n; i++) buf[i] = buf[i + 1];
479   } else if (buf[0] == '-' && buf[1] == '0') {
480     for (i = 1; i < n; i++) buf[i] = buf[i + 1];
481   }
482   PetscFunctionReturn(PETSC_SUCCESS);
483 }
484 
485 /*
486      Removes the extraneous zeros in numbers like 1.10000e6
487 */
488 PetscErrorCode PetscStripZeros(char *buf)
489 {
490   size_t i, j, n;
491 
492   PetscFunctionBegin;
493   PetscCall(PetscStrlen(buf, &n));
494   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
495   for (i = 1; i < n - 1; i++) {
496     if (buf[i] == 'e' && buf[i - 1] == '0') {
497       for (j = i; j < n + 1; j++) buf[j - 1] = buf[j];
498       PetscCall(PetscStripZeros(buf));
499       PetscFunctionReturn(PETSC_SUCCESS);
500     }
501   }
502   PetscFunctionReturn(PETSC_SUCCESS);
503 }
504 
505 /*
506       Removes the plus in something like 1.1e+2 or 1.1e+02
507 */
508 PetscErrorCode PetscStripZerosPlus(char *buf)
509 {
510   size_t i, j, n;
511 
512   PetscFunctionBegin;
513   PetscCall(PetscStrlen(buf, &n));
514   if (n < 5) PetscFunctionReturn(PETSC_SUCCESS);
515   for (i = 1; i < n - 2; i++) {
516     if (buf[i] == '+') {
517       if (buf[i + 1] == '0') {
518         for (j = i + 1; j < n; j++) buf[j - 1] = buf[j + 1];
519         PetscFunctionReturn(PETSC_SUCCESS);
520       } else {
521         for (j = i + 1; j < n + 1; j++) buf[j - 1] = buf[j];
522         PetscFunctionReturn(PETSC_SUCCESS);
523       }
524     } else if (buf[i] == '-') {
525       if (buf[i + 1] == '0') {
526         for (j = i + 1; j < n; j++) buf[j] = buf[j + 1];
527         PetscFunctionReturn(PETSC_SUCCESS);
528       }
529     }
530   }
531   PetscFunctionReturn(PETSC_SUCCESS);
532 }
533