Actual source code: rgring.c

slepc-3.8.0 2017-10-20
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-2017, 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>      /*I "slepcrg.h" I*/

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

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

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

 66: /*@
 67:    RGRingSetParameters - Sets the parameters defining the ring region.

 69:    Logically Collective on RG

 71:    Input Parameters:
 72: +  rg        - the region context
 73: .  center    - center of the ellipse
 74: .  radius    - radius of the ellipse
 75: .  vscale    - vertical scale of the ellipse
 76: .  start_ang - the right-hand side angle
 77: .  end_ang   - the left-hand side angle
 78: -  width     - width of the ring

 80:    Options Database Keys:
 81: +  -rg_ring_center     - Sets the center
 82: .  -rg_ring_radius     - Sets the radius
 83: .  -rg_ring_vscale     - Sets the vertical scale
 84: .  -rg_ring_startangle - Sets the right-hand side angle
 85: .  -rg_ring_endangle   - Sets the left-hand side angle
 86: -  -rg_ring_width      - Sets the width of the ring

 88:    Notes:
 89:    The values of center, radius and vscale have the same meaning as in the
 90:    ellipse region. The startangle and endangle define the span of the ring
 91:    (by default it is the whole ring), while the width is the separation
 92:    between the two concentric ellipses (above and below the radius by
 93:    width/2).

 95:    The start and end angles are expressed as a fraction of the circumference:
 96:    the allowed range is [0..1], with 0 corresponding to 0 radians, 0.25 to
 97:    pi/2 radians, and so on. It is allowed to have startangle>endangle, in
 98:    which case the ring region crosses over the zero angle.

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

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

108:    Level: advanced

110: .seealso: RGRingGetParameters()
111: @*/
112: PetscErrorCode RGRingSetParameters(RG rg,PetscScalar center,PetscReal radius,PetscReal vscale,PetscReal start_ang,PetscReal end_ang,PetscReal width)
113: {

124:   PetscTryMethod(rg,"RGRingSetParameters_C",(RG,PetscScalar,PetscReal,PetscReal,PetscReal,PetscReal,PetscReal),(rg,center,radius,vscale,start_ang,end_ang,width));
125:   return(0);
126: }

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

133:   if (center)    *center    = ctx->center;
134:   if (radius)    *radius    = ctx->radius;
135:   if (vscale)    *vscale    = ctx->vscale;
136:   if (start_ang) *start_ang = ctx->start_ang;
137:   if (end_ang)   *end_ang   = ctx->end_ang;
138:   if (width)     *width     = ctx->width;
139:   return(0);
140: }

142: /*@
143:    RGRingGetParameters - Gets the parameters that define the ring region.

145:    Not Collective

147:    Input Parameter:
148: .  rg     - the region context

150:    Output Parameters:
151: +  center    - center of the region
152: .  radius    - radius of the region
153: .  vscale    - vertical scale of the region
154: .  start_ang - the right-hand side angle
155: .  end_ang   - the left-hand side angle
156: -  width     - width of the ring

158:    Level: advanced

160: .seealso: RGRingSetParameters()
161: @*/
162: PetscErrorCode RGRingGetParameters(RG rg,PetscScalar *center,PetscReal *radius,PetscReal *vscale,PetscReal *start_ang,PetscReal *end_ang,PetscReal *width)
163: {

168:   PetscUseMethod(rg,"RGRingGetParameters_C",(RG,PetscScalar*,PetscReal*,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,center,radius,vscale,start_ang,end_ang,width));
169:   return(0);
170: }

172: PetscErrorCode RGView_Ring(RG rg,PetscViewer viewer)
173: {
175:   RG_RING        *ctx = (RG_RING*)rg->data;
176:   PetscBool      isascii;
177:   char           str[50];

180:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
181:   if (isascii) {
182:     SlepcSNPrintfScalar(str,50,ctx->center,PETSC_FALSE);
183:     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);
184:   }
185:   return(0);
186: }

188: PetscErrorCode RGIsTrivial_Ring(RG rg,PetscBool *trivial)
189: {
190:   RG_RING *ctx = (RG_RING*)rg->data;

193:   if (rg->complement) *trivial = PetscNot(ctx->radius);
194:   else *trivial = PetscNot(ctx->radius<PETSC_MAX_REAL);
195:   return(0);
196: }

198: PetscErrorCode RGComputeContour_Ring(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
199: {
200:   RG_RING   *ctx = (RG_RING*)rg->data;
201:   PetscReal theta,start_ang;
202:   PetscInt  i,n2=n/2;

205:   start_ang = (ctx->start_ang>ctx->end_ang)? ctx->start_ang-1: ctx->start_ang;
206:   for (i=0;i<n;i++) {
207:     if (i < n2) {
208:       theta = ((ctx->end_ang-start_ang)*i/n2 + start_ang)*2.0*PETSC_PI;
209: #if defined(PETSC_USE_COMPLEX)
210:       cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*(PetscCosReal(theta)+ctx->vscale*PetscSinReal(theta)*PETSC_i);
211: #else
212:       cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*PetscCosReal(theta);
213:       ci[i] = (ctx->radius+ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
214: #endif
215:     } else {
216:       theta = ((ctx->end_ang-start_ang)*(n-i)/n2 + start_ang)*2.0*PETSC_PI;
217: #if defined(PETSC_USE_COMPLEX)
218:       cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*(PetscCosReal(theta)+ctx->vscale*PetscSinReal(theta)*PETSC_i);
219: #else
220:       cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*PetscCosReal(theta);
221:       ci[i] = (ctx->radius-ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
222: #endif
223:     }
224:   }
225:   return(0);
226: }

228: PetscErrorCode RGComputeBoundingBox_Ring(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
229: {
230:   RG_RING *ctx = (RG_RING*)rg->data;

233:   /* current implementation does not return a tight bounding box */
234:   if (a) *a = PetscRealPart(ctx->center) - (ctx->radius+ctx->width/2.0);
235:   if (b) *b = PetscRealPart(ctx->center) + (ctx->radius+ctx->width/2.0);
236:   if (c) *c = PetscImaginaryPart(ctx->center) - (ctx->radius+ctx->width/2.0)*ctx->vscale;
237:   if (d) *d = PetscImaginaryPart(ctx->center) + (ctx->radius+ctx->width/2.0)*ctx->vscale;
238:   return(0);
239: }

241: PetscErrorCode RGCheckInside_Ring(RG rg,PetscReal px,PetscReal py,PetscInt *inside)
242: {
243:   RG_RING   *ctx = (RG_RING*)rg->data;
244:   PetscReal dx,dy,r;

247:   /* outer ellipse */
248: #if defined(PETSC_USE_COMPLEX)
249:   dx = (px-PetscRealPart(ctx->center))/(ctx->radius+ctx->width/2.0);
250:   dy = (py-PetscImaginaryPart(ctx->center))/(ctx->radius+ctx->width/2.0);
251: #else
252:   dx = (px-ctx->center)/(ctx->radius+ctx->width/2.0);
253:   dy = py/(ctx->radius+ctx->width/2.0);
254: #endif
255:   r = 1.0-dx*dx-(dy*dy)/(ctx->vscale*ctx->vscale);
256:   *inside = PetscSign(r);
257:   /* inner ellipse */
258: #if defined(PETSC_USE_COMPLEX)
259:   dx = (px-PetscRealPart(ctx->center))/(ctx->radius-ctx->width/2.0);
260:   dy = (py-PetscImaginaryPart(ctx->center))/(ctx->radius-ctx->width/2.0);
261: #else
262:   dx = (px-ctx->center)/(ctx->radius-ctx->width/2.0);
263:   dy = py/(ctx->radius-ctx->width/2.0);
264: #endif
265:   r = -1.0+dx*dx+(dy*dy)/(ctx->vscale*ctx->vscale);
266:   *inside *= PetscSign(r);
267:   if (*inside == 1) {  /* check angles */
268: #if defined(PETSC_USE_COMPLEX)
269:     dx = (px-PetscRealPart(ctx->center));
270:     dy = (py-PetscImaginaryPart(ctx->center));
271: #else
272:     dx = px-ctx->center;
273:     dy = py;
274: #endif
275:     if (dx == 0) {
276:       if (dy == 0) r = -1;
277:       else if (dy > 0) r = 0.25;
278:       else r = 0.75;
279:     } else if (dx > 0) {
280:       r = PetscAtanReal((dy/ctx->vscale)/dx);
281:       if (dy >= 0) r /= 2*PETSC_PI;
282:       else r = r/(2*PETSC_PI)+1;
283:     } else r = PetscAtanReal((dy/ctx->vscale)/dx)/(2*PETSC_PI)+0.5;
284:     if (ctx->start_ang>ctx->end_ang) {
285:       if (r>ctx->end_ang && r<ctx->start_ang) *inside = -1;
286:     } else {
287:       if (r<ctx->start_ang || r>ctx->end_ang) *inside = -1;
288:     }
289:   }
290:   return(0);
291: }

293: PetscErrorCode RGSetFromOptions_Ring(PetscOptionItems *PetscOptionsObject,RG rg)
294: {
296:   PetscScalar    s;
297:   PetscReal      r1,r2,r3,r4,r5;
298:   PetscBool      flg1,flg2,flg3,flg4,flg5,flg6;

301:   PetscOptionsHead(PetscOptionsObject,"RG Ring Options");

303:     RGRingGetParameters(rg,&s,&r1,&r2,&r3,&r4,&r5);
304:     PetscOptionsScalar("-rg_ring_center","Center of ellipse","RGRingSetParameters",s,&s,&flg1);
305:     PetscOptionsReal("-rg_ring_radius","Radius of ellipse","RGRingSetParameters",r1,&r1,&flg2);
306:     PetscOptionsReal("-rg_ring_vscale","Vertical scale of ellipse","RGRingSetParameters",r2,&r2,&flg3);
307:     PetscOptionsReal("-rg_ring_startangle","Right-hand side angle","RGRingSetParameters",r3,&r3,&flg4);
308:     PetscOptionsReal("-rg_ring_endangle","Left-hand side angle","RGRingSetParameters",r4,&r4,&flg5);
309:     PetscOptionsReal("-rg_ring_width","Width of ring","RGRingSetParameters",r5,&r5,&flg6);
310:     if (flg1 || flg2 || flg3 || flg4 || flg5 || flg6) { RGRingSetParameters(rg,s,r1,r2,r3,r4,r5); }

312:   PetscOptionsTail();
313:   return(0);
314: }

316: PetscErrorCode RGDestroy_Ring(RG rg)
317: {

321:   PetscFree(rg->data);
322:   PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",NULL);
323:   PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",NULL);
324:   return(0);
325: }

327: PETSC_EXTERN PetscErrorCode RGCreate_Ring(RG rg)
328: {
329:   RG_RING        *ring;

333:   PetscNewLog(rg,&ring);
334:   ring->center    = 0.0;
335:   ring->radius    = PETSC_MAX_REAL;
336:   ring->vscale    = 1.0;
337:   ring->start_ang = 0.0;
338:   ring->end_ang   = 1.0;
339:   ring->width     = 0.1;
340:   rg->data = (void*)ring;

342:   rg->ops->istrivial      = RGIsTrivial_Ring;
343:   rg->ops->computecontour = RGComputeContour_Ring;
344:   rg->ops->computebbox    = RGComputeBoundingBox_Ring;
345:   rg->ops->checkinside    = RGCheckInside_Ring;
346:   rg->ops->setfromoptions = RGSetFromOptions_Ring;
347:   rg->ops->view           = RGView_Ring;
348:   rg->ops->destroy        = RGDestroy_Ring;
349:   PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",RGRingSetParameters_Ring);
350:   PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",RGRingGetParameters_Ring);
351:   return(0);
352: }