Actual source code: rgring.c
slepc-3.8.2 2017-12-01
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: }