Actual source code: rgring.c

slepc-3.7.3 2016-09-29
Report Typos and Errors
  1: /*
  2:    Ring region, similar to the ellipse but with a start and end angle,
  3:    together with the width.

  5:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  6:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  7:    Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain

  9:    This file is part of SLEPc.

 11:    SLEPc is free software: you can redistribute it and/or modify it under  the
 12:    terms of version 3 of the GNU Lesser General Public License as published by
 13:    the Free Software Foundation.

 15:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
 16:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
 17:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
 18:    more details.

 20:    You  should have received a copy of the GNU Lesser General  Public  License
 21:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
 22:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 23: */

 25: #include <slepc/private/rgimpl.h>      /*I "slepcrg.h" I*/

 27: typedef struct {
 28:   PetscScalar center;     /* center of the ellipse */
 29:   PetscReal   radius;     /* radius of the ellipse */
 30:   PetscReal   vscale;     /* vertical scale of the ellipse */
 31:   PetscReal   start_ang;  /* start angle */
 32:   PetscReal   end_ang;    /* end angle */
 33:   PetscReal   width;      /* ring width */
 34: } RG_RING;

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

 43:   ctx->center = center;
 44:   if (radius == PETSC_DEFAULT) {
 45:     ctx->radius = 1.0;
 46:   } else {
 47:     if (radius<=0.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The radius argument must be > 0.0");
 48:     ctx->radius = radius;
 49:   }
 50:   if (vscale<=0.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The vscale argument must be > 0.0");
 51:   ctx->vscale = vscale;
 52:   if (start_ang == PETSC_DEFAULT) {
 53:     ctx->start_ang = 0.0;
 54:   } else {
 55:     if (start_ang<0.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The right-hand side angle argument must be >= 0.0");
 56:     if (start_ang>1.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The right-hand side angle argument must be <= 1.0");
 57:     ctx->start_ang = start_ang;
 58:   }
 59:   if (end_ang == PETSC_DEFAULT) {
 60:     ctx->end_ang = 1.0;
 61:   } else {
 62:     if (end_ang<0.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The left-hand side angle argument must be >= 0.0");
 63:     if (end_ang>1.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The left-hand side angle argument must be <= 1.0");
 64:     ctx->end_ang = end_ang;
 65:   }
 66:   if (ctx->start_ang>ctx->end_ang) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The right-hand side angle argument must be smaller than left one");
 67:   if (width == PETSC_DEFAULT) {
 68:     ctx->width = 0.1;
 69:   } else {
 70:     if (width<=0.0) SETERRQ(PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"The width argument must be > 0.0");
 71:     ctx->width = width;
 72:   }
 73:   return(0);
 74: }

 78: /*@
 79:    RGRingSetParameters - Sets the parameters defining the ring region.

 81:    Logically Collective on RG

 83:    Input Parameters:
 84: +  rg        - the region context
 85: .  center    - center of the ellipse
 86: .  radius    - radius of the ellipse
 87: .  vscale    - vertical scale of the ellipse
 88: .  start_ang - the right-hand side angle
 89: .  end_ang   - the left-hand side angle
 90: -  width     - width of the ring

 92:    Options Database Keys:
 93: +  -rg_ring_center     - Sets the center
 94: .  -rg_ring_radius     - Sets the radius
 95: .  -rg_ring_vscale     - Sets the vertical scale
 96: .  -rg_ring_startangle - Sets the right-hand side angle
 97: .  -rg_ring_endangle   - Sets the left-hand side angle
 98: -  -rg_ring_width      - Sets the width of the ring

100:    Notes:
101:    The values of center, radius and vscale have the same meaning as in the
102:    ellipse region. The startangle and endangle define the span of the ring
103:    (by default it is the whole ring), while the width is the separation
104:    between the two concentric ellipses (above and below the radius by
105:    width/2). The start and end angles are expressed as a fraction of the
106:    circumference: the allowed range is [0..1], with 0 corresponding to 0
107:    radians, 0.25 to pi/2 radians, and so on.

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

113:    When PETSc is built with real scalars, the center is restricted to a real value.

115:    Level: advanced

117: .seealso: RGRingGetParameters()
118: @*/
119: PetscErrorCode RGRingSetParameters(RG rg,PetscScalar center,PetscReal radius,PetscReal vscale,PetscReal start_ang,PetscReal end_ang,PetscReal width)
120: {

131:   PetscTryMethod(rg,"RGRingSetParameters_C",(RG,PetscScalar,PetscReal,PetscReal,PetscReal,PetscReal,PetscReal),(rg,center,radius,vscale,start_ang,end_ang,width));
132:   return(0);
133: }

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

142:   if (center)    *center    = ctx->center;
143:   if (radius)    *radius    = ctx->radius;
144:   if (vscale)    *vscale    = ctx->vscale;
145:   if (start_ang) *start_ang = ctx->start_ang;
146:   if (end_ang)   *end_ang   = ctx->end_ang;
147:   if (width)     *width     = ctx->width;
148:   return(0);
149: }

153: /*@
154:    RGRingGetParameters - Gets the parameters that define the ring region.

156:    Not Collective

158:    Input Parameter:
159: .  rg     - the region context

161:    Output Parameters:
162: +  center    - center of the region
163: .  radius    - radius of the region
164: .  vscale    - vertical scale of the region
165: .  start_ang - the right-hand side angle
166: .  end_ang   - the left-hand side angle
167: -  width     - width of the ring

169:    Level: advanced

171: .seealso: RGRingSetParameters()
172: @*/
173: PetscErrorCode RGRingGetParameters(RG rg,PetscScalar *center,PetscReal *radius,PetscReal *vscale,PetscReal *start_ang,PetscReal *end_ang,PetscReal *width)
174: {

179:   PetscUseMethod(rg,"RGRingGetParameters_C",(RG,PetscScalar*,PetscReal*,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,center,radius,vscale,start_ang,end_ang,width));
180:   return(0);
181: }

185: PetscErrorCode RGView_Ring(RG rg,PetscViewer viewer)
186: {
188:   RG_RING        *ctx = (RG_RING*)rg->data;
189:   PetscBool      isascii;
190:   char           str[50];

193:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
194:   if (isascii) {
195:     SlepcSNPrintfScalar(str,50,ctx->center,PETSC_FALSE);
196:     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),ctx->start_ang,ctx->end_ang,ctx->width);
197:   }
198:   return(0);
199: }

203: PetscErrorCode RGIsTrivial_Ring(RG rg,PetscBool *trivial)
204: {
205:   RG_RING *ctx = (RG_RING*)rg->data;

208:   if (rg->complement) *trivial = PetscNot(ctx->radius);
209:   else *trivial = PetscNot(ctx->radius<PETSC_MAX_REAL);
210:   return(0);
211: }

215: PetscErrorCode RGComputeContour_Ring(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
216: {
217:   RG_RING   *ctx = (RG_RING*)rg->data;
218:   PetscReal theta;
219:   PetscInt  i,n2=n/2;

222:   for (i=0;i<n;i++) {
223:     if (i < n2) {
224:       theta = ((ctx->end_ang-ctx->start_ang)*i/n2 + ctx->start_ang)*2.0*PETSC_PI;
225: #if defined(PETSC_USE_COMPLEX)
226:       cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*(PetscCosReal(theta)+ctx->vscale*PetscSinReal(theta)*PETSC_i);
227: #else
228:       cr[i] = ctx->center + (ctx->radius+ctx->width/2.0)*PetscCosReal(theta);
229:       ci[i] = (ctx->radius+ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
230: #endif
231:     } else {
232:       theta = ((ctx->end_ang-ctx->start_ang)*(n-i)/n2 + ctx->start_ang)*2.0*PETSC_PI;
233: #if defined(PETSC_USE_COMPLEX)
234:       cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*(PetscCosReal(theta)+ctx->vscale*PetscSinReal(theta)*PETSC_i);
235: #else
236:       cr[i] = ctx->center + (ctx->radius-ctx->width/2.0)*PetscCosReal(theta);
237:       ci[i] = (ctx->radius-ctx->width/2.0)*ctx->vscale*PetscSinReal(theta);
238: #endif
239:     }
240:   }
241:   return(0);
242: }

246: PetscErrorCode RGCheckInside_Ring(RG rg,PetscReal px,PetscReal py,PetscInt *inside)
247: {
248:   RG_RING   *ctx = (RG_RING*)rg->data;
249:   PetscReal dx,dy,r;

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

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

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

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

317:   PetscOptionsTail();
318:   return(0);
319: }

323: PetscErrorCode RGDestroy_Ring(RG rg)
324: {

328:   PetscFree(rg->data);
329:   PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",NULL);
330:   PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",NULL);
331:   return(0);
332: }

336: PETSC_EXTERN PetscErrorCode RGCreate_Ring(RG rg)
337: {
338:   RG_RING        *ring;

342:   PetscNewLog(rg,&ring);
343:   ring->center    = 0.0;
344:   ring->radius    = 1.0;
345:   ring->vscale    = 1.0;
346:   ring->start_ang = 0.0;
347:   ring->end_ang   = 1.0;
348:   ring->width     = 0.1;
349:   rg->data = (void*)ring;

351:   rg->ops->istrivial      = RGIsTrivial_Ring;
352:   rg->ops->computecontour = RGComputeContour_Ring;
353:   rg->ops->checkinside    = RGCheckInside_Ring;
354:   rg->ops->setfromoptions = RGSetFromOptions_Ring;
355:   rg->ops->view           = RGView_Ring;
356:   rg->ops->destroy        = RGDestroy_Ring;
357:   PetscObjectComposeFunction((PetscObject)rg,"RGRingSetParameters_C",RGRingSetParameters_Ring);
358:   PetscObjectComposeFunction((PetscObject)rg,"RGRingGetParameters_C",RGRingGetParameters_Ring);
359:   return(0);
360: }