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