Actual source code: rgring.c

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    Ring region, similar to the ellipse but with a start and end angle,
     12:    together with the width
     13: */

     15: #include <slepc/private/rgimpl.h>
     16: #include <petscdraw.h>

     18: typedef struct {
     19:   PetscScalar center;     /* center of the ellipse */
     20:   PetscReal   radius;     /* radius of the ellipse */
     21:   PetscReal   vscale;     /* vertical scale of the ellipse */
     22:   PetscReal   start_ang;  /* start angle */
     23:   PetscReal   end_ang;    /* end angle */
     24:   PetscReal   width;      /* ring width */
     25: } RG_RING;

     27: static PetscErrorCode RGRingSetParameters_Ring(RG rg,PetscScalar center,PetscReal radius,PetscReal vscale,PetscReal start_ang,PetscReal end_ang,PetscReal width)
     28: {
     29:   RG_RING *ctx = (RG_RING*)rg->data;

     31:   PetscFunctionBegin;
     32:   ctx->center = center;
     33:   if (radius == (PetscReal)PETSC_DETERMINE) {
     34:     ctx->radius = 1.0;
     35:   } else if (radius != (PetscReal)PETSC_CURRENT) {
     36:     PetscCheck(radius>0.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The radius argument must be > 0.0");
     37:     ctx->radius = radius;
     38:   }
     39:   if (vscale == (PetscReal)PETSC_DETERMINE) {
     40:     ctx->vscale = 1.0;
     41:   } else if (vscale != (PetscReal)PETSC_CURRENT) {
     42:     PetscCheck(vscale>0.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The vscale argument must be > 0.0");
     43:     ctx->vscale = vscale;
     44:   }
     45:   if (start_ang == (PetscReal)PETSC_DETERMINE) {
     46:     ctx->start_ang = 0.0;
     47:   } else if (start_ang != (PetscReal)PETSC_CURRENT) {
     48:     PetscCheck(start_ang>=0.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The right-hand side angle argument must be >= 0.0");
     49:     PetscCheck(start_ang<=1.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The right-hand side angle argument must be <= 1.0");
     50:     ctx->start_ang = start_ang;
     51:   }
     52:   if (end_ang == (PetscReal)PETSC_DETERMINE) {
     53:     ctx->end_ang = 1.0;
     54:   } else if (end_ang != (PetscReal)PETSC_CURRENT) {
     55:     PetscCheck(end_ang>=0.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The left-hand side angle argument must be >= 0.0");
     56:     PetscCheck(end_ang<=1.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The left-hand side angle argument must be <= 1.0");
     57:     ctx->end_ang = end_ang;
     58:   }
     59: #if !defined(PETSC_USE_COMPLEX)
     60:   PetscCheck(ctx->start_ang+ctx->end_ang==1.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"In real scalars the region must be symmetric wrt real axis");
     61: #endif
     62:   if (width == (PetscReal)PETSC_DETERMINE) {
     63:     ctx->width = 0.1;
     64:   } else if (width != (PetscReal)PETSC_CURRENT) {
     65:     PetscCheck(width>0.0,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The width argument must be > 0.0");
     66:     ctx->width = width;
     67:   }
     68:   PetscFunctionReturn(PETSC_SUCCESS);
     69: }

     71: /*@
     72:    RGRingSetParameters - Sets the parameters defining the ring region.

     74:    Logically Collective

     76:    Input Parameters:
     77: +  rg        - the region context
     78: .  center    - center of the ellipse
     79: .  radius    - radius of the ellipse
     80: .  vscale    - vertical scale of the ellipse
     81: .  start_ang - the right-hand side angle
     82: .  end_ang   - the left-hand side angle
     83: -  width     - width of the ring

     85:    Options Database Keys:
     86: +  -rg_ring_center \<center\>        - sets the center
     87: .  -rg_ring_radius \<radius\>        - sets the radius
     88: .  -rg_ring_vscale \<vscale\>        - sets the vertical scale
     89: .  -rg_ring_startangle \<start_ang\> - sets the right-hand side angle
     90: .  -rg_ring_endangle \<end_ang\>     - sets the left-hand side angle
     91: -  -rg_ring_width \<width\>          - sets the width of the ring

     93:    Notes:
     94:    The values of `center`, `radius` and `vscale` have the same meaning as in the
     95:    ellipse region. The `startangle` and `endangle` define the span of the ring
     96:    (by default it is the whole ring), while the `width` is the separation
     97:    between the two concentric ellipses (above and below the radius by
     98:    `width/2`).

    100:    The start and end angles are expressed as a fraction of the circumference.
    101:    The allowed range is $[0,\dots,1]$, with `0` corresponding to 0 radians, `0.25` to
    102:    $\pi/2$ radians, and so on. It is allowed to have `startangle`>`endangle`, in
    103:    which case the ring region crosses over the zero angle.

    105:    In the case of complex scalars, a complex center can be provided in the
    106:    command line with `[+/-][realnumber][+/-]realnumberi` with no spaces, e.g.,
    107:    `-rg_ring_center 1.0+2.0i`.

    109:    When PETSc is built with real scalars, the center is restricted to a real value,
    110:    and the start and end angles must be such that the region is symmetric with
    111:    respect to the real axis.

    113:    For all arguments except `center`, you can use `PETSC_CURRENT` to keep the current
    114:    value, and `PETSC_DETERMINE` to set them to a default value (1 for `radius`, `vscale`,
    115:    `end_ang`, 0 for `start_and`, and 0.1 for `width`).

    117:    Level: advanced

    119: .seealso: [](sec:rg), `RGRING`, `RGRingGetParameters()`, `RGELLIPSE`
    120: @*/
    121: PetscErrorCode RGRingSetParameters(RG rg,PetscScalar center,PetscReal radius,PetscReal vscale,PetscReal start_ang,PetscReal end_ang,PetscReal width)
    122: {
    123:   PetscFunctionBegin;
    131:   PetscTryMethod(rg,"RGRingSetParameters_C",(RG,PetscScalar,PetscReal,PetscReal,PetscReal,PetscReal,PetscReal),(rg,center,radius,vscale,start_ang,end_ang,width));
    132:   PetscFunctionReturn(PETSC_SUCCESS);
    133: }

    135: static PetscErrorCode RGRingGetParameters_Ring(RG rg,PetscScalar *center,PetscReal *radius,PetscReal *vscale,PetscReal *start_ang,PetscReal *end_ang,PetscReal *width)
    136: {
    137:   RG_RING *ctx = (RG_RING*)rg->data;

    139:   PetscFunctionBegin;
    140:   if (center)    *center    = ctx->center;
    141:   if (radius)    *radius    = ctx->radius;
    142:   if (vscale)    *vscale    = ctx->vscale;
    143:   if (start_ang) *start_ang = ctx->start_ang;
    144:   if (end_ang)   *end_ang   = ctx->end_ang;
    145:   if (width)     *width     = ctx->width;
    146:   PetscFunctionReturn(PETSC_SUCCESS);
    147: }

    149: /*@
    150:    RGRingGetParameters - Gets the parameters that define the ring region.

    152:    Not Collective

    154:    Input Parameter:
    155: .  rg     - the region context

    157:    Output Parameters:
    158: +  center    - center of the region
    159: .  radius    - radius of the region
    160: .  vscale    - vertical scale of the region
    161: .  start_ang - the right-hand side angle
    162: .  end_ang   - the left-hand side angle
    163: -  width     - width of the ring

    165:    Level: advanced

    167: .seealso: [](sec:rg), `RGRING`, `RGRingSetParameters()`
    168: @*/
    169: PetscErrorCode RGRingGetParameters(RG rg,PetscScalar *center,PetscReal *radius,PetscReal *vscale,PetscReal *start_ang,PetscReal *end_ang,PetscReal *width)
    170: {
    171:   PetscFunctionBegin;
    173:   PetscUseMethod(rg,"RGRingGetParameters_C",(RG,PetscScalar*,PetscReal*,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,center,radius,vscale,start_ang,end_ang,width));
    174:   PetscFunctionReturn(PETSC_SUCCESS);
    175: }

    177: static PetscErrorCode RGView_Ring(RG rg,PetscViewer viewer)
    178: {
    179:   RG_RING        *ctx = (RG_RING*)rg->data;
    180:   int            winw,winh;
    181:   PetscBool      isdraw,isascii;
    182:   PetscDraw      draw;
    183:   PetscDrawAxis  axis;
    184:   PetscReal      cx,cy,radius,width,ab,cd,lx,ly,w,end_ang,x1,y1,x2,y2,r,theta,scale=1.2;
    185:   char           str[50];

    187:   PetscFunctionBegin;
    188:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
    189:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    190:   if (isascii) {
    191:     PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->center,PETSC_FALSE));
    192:     PetscCall(PetscViewerASCIIPrintf(viewer,"  center: %s, radius: %g, vscale: %g, start angle: %g, end angle: %g, ring width: %g\n",str,RGShowReal(ctx->radius),RGShowReal(ctx->vscale),(double)ctx->start_ang,(double)ctx->end_ang,(double)ctx->width));
    193:   } else if (isdraw) {
    194:     PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
    195:     PetscCall(PetscDrawCheckResizedWindow(draw));
    196:     PetscCall(PetscDrawGetWindowSize(draw,&winw,&winh));
    197:     winw = PetscMax(winw,1); winh = PetscMax(winh,1);
    198:     PetscCall(PetscDrawClear(draw));
    199:     PetscCall(PetscDrawSetTitle(draw,"Ring region"));
    200:     PetscCall(PetscDrawAxisCreate(draw,&axis));
    201:     cx = PetscRealPart(ctx->center)*rg->sfactor;
    202:     cy = PetscImaginaryPart(ctx->center)*rg->sfactor;
    203:     radius = ctx->radius*rg->sfactor;
    204:     width  = ctx->width*rg->sfactor;
    205:     lx = 2*(radius+width);
    206:     ly = 2*(radius+width)*ctx->vscale;
    207:     ab = cx;
    208:     cd = cy;
    209:     w  = scale*PetscMax(lx/winw,ly/winh)/2;
    210:     PetscCall(PetscDrawAxisSetLimits(axis,ab-w*winw,ab+w*winw,cd-w*winh,cd+w*winh));
    211:     PetscCall(PetscDrawAxisDraw(axis));
    212:     PetscCall(PetscDrawAxisDestroy(&axis));
    213:     /* draw outer ellipse */
    214:     PetscCall(PetscDrawEllipse(draw,cx,cy,2*(radius+width),2*(radius+width)*ctx->vscale,PETSC_DRAW_ORANGE));
    215:     /* remove inner part */
    216:     PetscCall(PetscDrawEllipse(draw,cx,cy,2*(radius-width),2*(radius-width)*ctx->vscale,PETSC_DRAW_WHITE));
    217:     if (ctx->start_ang!=ctx->end_ang) {
    218:       /* remove section from end_ang to start_ang */
    219:       end_ang = (ctx->start_ang<ctx->end_ang)? ctx->end_ang-1: ctx->end_ang;
    220:       theta = end_ang;
    221:       r = scale*(radius+width);
    222:       if (ctx->vscale>1) r *= ctx->vscale;
    223:       x1 = PetscMin(PetscMax(ab+r*PetscCosReal(2.0*PETSC_PI*theta),ab-w*winw),ab+w*winw);
    224:       y1 = PetscMin(PetscMax(cd+r*PetscSinReal(2.0*PETSC_PI*theta),cd-w*winh),cd+w*winh);
    225:       do {
    226:         theta = PetscMin(PetscFloorReal(8*theta+1)/8,ctx->start_ang);
    227:         x2 = PetscMin(PetscMax(ab+r*PetscCosReal(2.0*PETSC_PI*theta),ab-w*winw),ab+w*winw);
    228:         y2 = PetscMin(PetscMax(cd+r*PetscSinReal(2.0*PETSC_PI*theta),cd-w*winh),cd+w*winh);
    229:         PetscCall(PetscDrawTriangle(draw,cx,cy,x1,y1,x2,y2,PETSC_DRAW_WHITE,PETSC_DRAW_WHITE,PETSC_DRAW_WHITE));
    230:         x1 = x2; y1 = y2;
    231:       } while (theta<ctx->start_ang);
    232:     }
    233:     PetscCall(PetscDrawFlush(draw));
    234:     PetscCall(PetscDrawSave(draw));
    235:     PetscCall(PetscDrawPause(draw));
    236:   }
    237:   PetscFunctionReturn(PETSC_SUCCESS);
    238: }

    240: static PetscErrorCode RGIsTrivial_Ring(RG rg,PetscBool *trivial)
    241: {
    242:   RG_RING *ctx = (RG_RING*)rg->data;

    244:   PetscFunctionBegin;
    245:   if (rg->complement) *trivial = PetscNot(ctx->radius);
    246:   else *trivial = PetscNot(ctx->radius<PETSC_MAX_REAL);
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: static PetscErrorCode RGComputeContour_Ring(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
    251: {
    252:   RG_RING   *ctx = (RG_RING*)rg->data;
    253:   PetscReal theta,start_ang;
    254:   PetscInt  i,n2=n/2;

    256:   PetscFunctionBegin;
    257:   start_ang = (ctx->start_ang>ctx->end_ang)? ctx->start_ang-1: ctx->start_ang;
    258:   for (i=0;i<n;i++) {
    259:     if (i < n2) {
    260:       theta = ((ctx->end_ang-start_ang)*i/n2 + start_ang)*2.0*PETSC_PI;
    261: #if defined(PETSC_USE_COMPLEX)
    262:       cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*PetscCMPLX(PetscCosReal(theta),ctx->vscale*PetscSinReal(theta));
    263: #else
    264:       if (cr) cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*PetscCosReal(theta);
    265:       if (ci) ci[i] = (ctx->radius+ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
    266: #endif
    267:     } else {
    268:       theta = ((ctx->end_ang-start_ang)*(n-i)/n2 + start_ang)*2.0*PETSC_PI;
    269: #if defined(PETSC_USE_COMPLEX)
    270:       cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*PetscCMPLX(PetscCosReal(theta),ctx->vscale*PetscSinReal(theta));
    271: #else
    272:       if (cr) cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*PetscCosReal(theta);
    273:       if (ci) ci[i] = (ctx->radius-ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
    274: #endif
    275:     }
    276:   }
    277:   PetscFunctionReturn(PETSC_SUCCESS);
    278: }

    280: static PetscErrorCode RGComputeBoundingBox_Ring(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
    281: {
    282:   RG_RING *ctx = (RG_RING*)rg->data;

    284:   PetscFunctionBegin;
    285:   /* current implementation does not return a tight bounding box */
    286:   if (a) *a = PetscRealPart(ctx->center) - (ctx->radius+ctx->width/2.0);
    287:   if (b) *b = PetscRealPart(ctx->center) + (ctx->radius+ctx->width/2.0);
    288:   if (c) *c = PetscImaginaryPart(ctx->center) - (ctx->radius+ctx->width/2.0)*ctx->vscale;
    289:   if (d) *d = PetscImaginaryPart(ctx->center) + (ctx->radius+ctx->width/2.0)*ctx->vscale;
    290:   PetscFunctionReturn(PETSC_SUCCESS);
    291: }

    293: static PetscErrorCode RGComputeQuadrature_Ring(RG rg,RGQuadRule quad,PetscInt n,PetscScalar *z,PetscScalar *zn,PetscScalar *w)
    294: {
    295:   RG_RING     *ctx = (RG_RING*)rg->data;
    296:   PetscReal   max_w=0.0;
    297:   PetscScalar tmp,tmp2;
    298:   PetscInt    i,j;

    300:   PetscFunctionBegin;
    301:   if (quad == RG_QUADRULE_CHEBYSHEV) {
    302: #if defined(PETSC_USE_COMPLEX)
    303:     PetscReal theta;
    304:     for (i=0;i<n;i++) {
    305:       theta = PETSC_PI*(i+0.5)/n;
    306:       zn[i] = PetscCosReal(theta);
    307:       w[i]  = PetscCosReal((n-1)*theta)/n;
    308:       theta = (ctx->start_ang*2.0+(ctx->end_ang-ctx->start_ang)*(PetscRealPart(zn[i])+1.0))*PETSC_PI;
    309:       z[i] = rg->sfactor*(ctx->center + ctx->radius*PetscCMPLX(PetscCosReal(theta),ctx->vscale*PetscSinReal(theta)));
    310:     }
    311: #else
    312:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Integration points on a vertical line require complex arithmetic");
    313: #endif
    314:   } else {  /* RG_QUADRULE_TRAPEZOIDAL */
    315:     for (i=0;i<n;i++) {
    316:       zn[i] = (z[i]-rg->sfactor*ctx->center)/(rg->sfactor*ctx->radius);
    317:       tmp = 1.0; tmp2 = 1.0;
    318:       for (j=0;j<n;j++) {
    319:         tmp *= z[j];
    320:         if (i != j) tmp2 *= z[j]-z[i];
    321:       }
    322:       w[i] = tmp/tmp2;
    323:       max_w = PetscMax(PetscAbsScalar(w[i]),max_w);
    324:     }
    325:     for (i=0;i<n;i++) w[i] /= (PetscScalar)max_w;
    326:   }
    327:   PetscFunctionReturn(PETSC_SUCCESS);
    328: }

    330: static PetscErrorCode RGCheckInside_Ring(RG rg,PetscReal px,PetscReal py,PetscInt *inside)
    331: {
    332:   RG_RING   *ctx = (RG_RING*)rg->data;
    333:   PetscReal dx,dy,r;

    335:   PetscFunctionBegin;
    336:   /* outer ellipse */
    337: #if defined(PETSC_USE_COMPLEX)
    338:   dx = (px-PetscRealPart(ctx->center))/(ctx->radius+ctx->width/2.0);
    339:   dy = (py-PetscImaginaryPart(ctx->center))/(ctx->radius+ctx->width/2.0);
    340: #else
    341:   dx = (px-ctx->center)/(ctx->radius+ctx->width/2.0);
    342:   dy = py/(ctx->radius+ctx->width/2.0);
    343: #endif
    344:   r = 1.0-dx*dx-(dy*dy)/(ctx->vscale*ctx->vscale);
    345:   *inside = PetscSign(r);
    346:   /* inner ellipse */
    347: #if defined(PETSC_USE_COMPLEX)
    348:   dx = (px-PetscRealPart(ctx->center))/(ctx->radius-ctx->width/2.0);
    349:   dy = (py-PetscImaginaryPart(ctx->center))/(ctx->radius-ctx->width/2.0);
    350: #else
    351:   dx = (px-ctx->center)/(ctx->radius-ctx->width/2.0);
    352:   dy = py/(ctx->radius-ctx->width/2.0);
    353: #endif
    354:   r = -1.0+dx*dx+(dy*dy)/(ctx->vscale*ctx->vscale);
    355:   *inside *= PetscSign(r);
    356:   if (*inside == 1) {  /* check angles */
    357: #if defined(PETSC_USE_COMPLEX)
    358:     dx = (px-PetscRealPart(ctx->center));
    359:     dy = (py-PetscImaginaryPart(ctx->center));
    360: #else
    361:     dx = px-ctx->center;
    362:     dy = py;
    363: #endif
    364:     if (dx == 0) {
    365:       if (dy == 0) r = -1;
    366:       else if (dy > 0) r = 0.25;
    367:       else r = 0.75;
    368:     } else if (dx > 0) {
    369:       r = PetscAtanReal((dy/ctx->vscale)/dx);
    370:       if (dy >= 0) r /= 2*PETSC_PI;
    371:       else r = r/(2*PETSC_PI)+1;
    372:     } else r = PetscAtanReal((dy/ctx->vscale)/dx)/(2*PETSC_PI)+0.5;
    373:     if (ctx->start_ang>ctx->end_ang) {
    374:       if (r>ctx->end_ang && r<ctx->start_ang) *inside = -1;
    375:     } else {
    376:       if (r<ctx->start_ang || r>ctx->end_ang) *inside = -1;
    377:     }
    378:   }
    379:   PetscFunctionReturn(PETSC_SUCCESS);
    380: }

    382: static PetscErrorCode RGIsAxisymmetric_Ring(RG rg,PetscBool vertical,PetscBool *symm)
    383: {
    384:   RG_RING *ctx = (RG_RING*)rg->data;

    386:   PetscFunctionBegin;
    387:   if (vertical) *symm = (PetscRealPart(ctx->center) == 0.0 && PetscAbs(ctx->start_ang+ctx->end_ang-PetscRealConstant(1.0)) == 0.5)? PETSC_TRUE: PETSC_FALSE;
    388:   else *symm = (PetscImaginaryPart(ctx->center) == 0.0 && ctx->start_ang+ctx->end_ang == 1.0)? PETSC_TRUE: PETSC_FALSE;
    389:   PetscFunctionReturn(PETSC_SUCCESS);
    390: }

    392: static PetscErrorCode RGSetFromOptions_Ring(RG rg,PetscOptionItems PetscOptionsObject)
    393: {
    394:   PetscScalar    s;
    395:   PetscReal      r1,r2,r3,r4,r5;
    396:   PetscBool      flg1,flg2,flg3,flg4,flg5,flg6;

    398:   PetscFunctionBegin;
    399:   PetscOptionsHeadBegin(PetscOptionsObject,"RG Ring Options");

    401:     PetscCall(RGRingGetParameters(rg,&s,&r1,&r2,&r3,&r4,&r5));
    402:     PetscCall(PetscOptionsScalar("-rg_ring_center","Center of ellipse","RGRingSetParameters",s,&s,&flg1));
    403:     PetscCall(PetscOptionsReal("-rg_ring_radius","Radius of ellipse","RGRingSetParameters",r1,&r1,&flg2));
    404:     PetscCall(PetscOptionsReal("-rg_ring_vscale","Vertical scale of ellipse","RGRingSetParameters",r2,&r2,&flg3));
    405:     PetscCall(PetscOptionsReal("-rg_ring_startangle","Right-hand side angle","RGRingSetParameters",r3,&r3,&flg4));
    406:     PetscCall(PetscOptionsReal("-rg_ring_endangle","Left-hand side angle","RGRingSetParameters",r4,&r4,&flg5));
    407:     PetscCall(PetscOptionsReal("-rg_ring_width","Width of ring","RGRingSetParameters",r5,&r5,&flg6));
    408:     if (flg1 || flg2 || flg3 || flg4 || flg5 || flg6) PetscCall(RGRingSetParameters(rg,s,r1,r2,r3,r4,r5));

    410:   PetscOptionsHeadEnd();
    411:   PetscFunctionReturn(PETSC_SUCCESS);
    412: }

    414: static PetscErrorCode RGDestroy_Ring(RG rg)
    415: {
    416:   PetscFunctionBegin;
    417:   PetscCall(PetscFree(rg->data));
    418:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",NULL));
    419:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",NULL));
    420:   PetscFunctionReturn(PETSC_SUCCESS);
    421: }

    423: /*MC
    424:    RGRING - RGRING = "ring" - A ring region similar to an ellipse but consisting
    425:    of a thin stripe along the ellipse with optional start and end angles.

    427:    Note:
    428:    The parameters can be set with `RGRingSetParameters()`.
    429:    The following figure shows an example of a ring region.

    431:    ![Ring region](../../_static/images/manual/svg/fig-rg-ring.svg)

    433:    Level: beginner

    435: .seealso: [](sec:rg), `RG`, `RGType`, `RGSetType()`, `RGRingSetParameters()`
    436: M*/

    438: SLEPC_EXTERN PetscErrorCode RGCreate_Ring(RG rg)
    439: {
    440:   RG_RING        *ring;

    442:   PetscFunctionBegin;
    443:   PetscCall(PetscNew(&ring));
    444:   ring->center    = 0.0;
    445:   ring->radius    = PETSC_MAX_REAL;
    446:   ring->vscale    = 1.0;
    447:   ring->start_ang = 0.0;
    448:   ring->end_ang   = 1.0;
    449:   ring->width     = 0.1;
    450:   rg->data = (void*)ring;

    452:   rg->ops->istrivial         = RGIsTrivial_Ring;
    453:   rg->ops->computecontour    = RGComputeContour_Ring;
    454:   rg->ops->computebbox       = RGComputeBoundingBox_Ring;
    455:   rg->ops->computequadrature = RGComputeQuadrature_Ring;
    456:   rg->ops->checkinside       = RGCheckInside_Ring;
    457:   rg->ops->isaxisymmetric    = RGIsAxisymmetric_Ring;
    458:   rg->ops->setfromoptions    = RGSetFromOptions_Ring;
    459:   rg->ops->view              = RGView_Ring;
    460:   rg->ops->destroy           = RGDestroy_Ring;
    461:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",RGRingSetParameters_Ring));
    462:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",RGRingGetParameters_Ring));
    463:   PetscFunctionReturn(PETSC_SUCCESS);
    464: }