Line data Source code
1 : /*
2 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3 : SLEPc - Scalable Library for Eigenvalue Problem Computations
4 : Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
5 :
6 : This file is part of SLEPc.
7 : SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9 : */
10 : /*
11 : Polygonal region defined by a set of vertices
12 : */
13 :
14 : #include <slepc/private/rgimpl.h> /*I "slepcrg.h" I*/
15 : #include <petscdraw.h>
16 :
17 : #define VERTMAX 30
18 :
19 : typedef struct {
20 : PetscInt n; /* number of vertices */
21 : PetscScalar *vr,*vi; /* array of vertices (vi not used in complex scalars) */
22 : } RG_POLYGON;
23 :
24 : static PetscErrorCode RGComputeBoundingBox_Polygon(RG,PetscReal*,PetscReal*,PetscReal*,PetscReal*);
25 :
26 : #if !defined(PETSC_USE_COMPLEX)
27 2 : static PetscBool CheckSymmetry(PetscInt n,PetscScalar *vr,PetscScalar *vi)
28 : {
29 2 : PetscInt i,j,k;
30 : /* find change of sign in imaginary part */
31 2 : j = vi[0]!=0.0? 0: 1;
32 2 : for (k=j+1;k<n;k++) {
33 2 : if (vi[k]!=0.0) {
34 2 : if (vi[k]*vi[j]<0.0) break;
35 0 : j++;
36 : }
37 : }
38 2 : if (k==n) return (j==1)? PETSC_TRUE: PETSC_FALSE;
39 : /* check pairing vertices */
40 8 : for (i=0;i<n/2;i++) {
41 6 : if (vr[k]!=vr[j] || vi[k]!=-vi[j]) return PETSC_FALSE;
42 6 : k = (k+1)%n;
43 6 : j = (j-1+n)%n;
44 : }
45 : return PETSC_TRUE;
46 : }
47 : #endif
48 :
49 2 : static PetscErrorCode RGPolygonSetVertices_Polygon(RG rg,PetscInt n,PetscScalar *vr,PetscScalar *vi)
50 : {
51 2 : PetscInt i;
52 2 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
53 :
54 2 : PetscFunctionBegin;
55 2 : PetscCheck(n>2,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"At least 3 vertices required, you provided %" PetscInt_FMT,n);
56 2 : PetscCheck(n<=VERTMAX,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_OUTOFRANGE,"Too many points, maximum allowed is %d",VERTMAX);
57 : #if !defined(PETSC_USE_COMPLEX)
58 2 : PetscCheck(CheckSymmetry(n,vr,vi),PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"In real scalars the region must be symmetric wrt real axis");
59 : #endif
60 2 : if (ctx->n) {
61 0 : PetscCall(PetscFree(ctx->vr));
62 : #if !defined(PETSC_USE_COMPLEX)
63 0 : PetscCall(PetscFree(ctx->vi));
64 : #endif
65 : }
66 2 : ctx->n = n;
67 2 : PetscCall(PetscMalloc1(n,&ctx->vr));
68 : #if !defined(PETSC_USE_COMPLEX)
69 2 : PetscCall(PetscMalloc1(n,&ctx->vi));
70 : #endif
71 16 : for (i=0;i<n;i++) {
72 14 : ctx->vr[i] = vr[i];
73 : #if !defined(PETSC_USE_COMPLEX)
74 14 : ctx->vi[i] = vi[i];
75 : #endif
76 : }
77 2 : PetscFunctionReturn(PETSC_SUCCESS);
78 : }
79 :
80 : /*@
81 : RGPolygonSetVertices - Sets the vertices that define the polygon region.
82 :
83 : Logically Collective
84 :
85 : Input Parameters:
86 : + rg - the region context
87 : . n - number of vertices
88 : . vr - array of vertices
89 : - vi - array of vertices (imaginary part)
90 :
91 : Options Database Keys:
92 : + -rg_polygon_vertices - Sets the vertices
93 : - -rg_polygon_verticesi - Sets the vertices (imaginary part)
94 :
95 : Notes:
96 : In the case of complex scalars, only argument vr is used, containing
97 : the complex vertices; the list of vertices can be provided in the
98 : command line with a comma-separated list of complex values
99 : [+/-][realnumber][+/-]realnumberi with no spaces.
100 :
101 : When PETSc is built with real scalars, the real and imaginary parts of
102 : the vertices must be provided in two separate arrays (or two lists in
103 : the command line). In this case, the region must be symmetric with
104 : respect to the real axis.
105 :
106 : Level: advanced
107 :
108 : .seealso: RGPolygonGetVertices()
109 : @*/
110 2 : PetscErrorCode RGPolygonSetVertices(RG rg,PetscInt n,PetscScalar vr[],PetscScalar vi[])
111 : {
112 2 : PetscFunctionBegin;
113 2 : PetscValidHeaderSpecific(rg,RG_CLASSID,1);
114 6 : PetscValidLogicalCollectiveInt(rg,n,2);
115 2 : PetscAssertPointer(vr,3);
116 : #if !defined(PETSC_USE_COMPLEX)
117 2 : PetscAssertPointer(vi,4);
118 : #endif
119 2 : PetscTryMethod(rg,"RGPolygonSetVertices_C",(RG,PetscInt,PetscScalar*,PetscScalar*),(rg,n,vr,vi));
120 2 : PetscFunctionReturn(PETSC_SUCCESS);
121 : }
122 :
123 2 : static PetscErrorCode RGPolygonGetVertices_Polygon(RG rg,PetscInt *n,PetscScalar **vr,PetscScalar **vi)
124 : {
125 2 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
126 2 : PetscInt i;
127 :
128 2 : PetscFunctionBegin;
129 2 : if (n) *n = ctx->n;
130 2 : if (vr) {
131 2 : if (!ctx->n) *vr = NULL;
132 : else {
133 2 : PetscCall(PetscMalloc1(ctx->n,vr));
134 16 : for (i=0;i<ctx->n;i++) (*vr)[i] = ctx->vr[i];
135 : }
136 : }
137 : #if !defined(PETSC_USE_COMPLEX)
138 2 : if (vi) {
139 2 : if (!ctx->n) *vi = NULL;
140 : else {
141 2 : PetscCall(PetscMalloc1(ctx->n,vi));
142 16 : for (i=0;i<ctx->n;i++) (*vi)[i] = ctx->vi[i];
143 : }
144 : }
145 : #endif
146 2 : PetscFunctionReturn(PETSC_SUCCESS);
147 : }
148 :
149 : /*@C
150 : RGPolygonGetVertices - Gets the vertices that define the polygon region.
151 :
152 : Not Collective
153 :
154 : Input Parameter:
155 : . rg - the region context
156 :
157 : Output Parameters:
158 : + n - number of vertices
159 : . vr - array of vertices
160 : - vi - array of vertices (imaginary part)
161 :
162 : Notes:
163 : The values passed by user with RGPolygonSetVertices() are returned (or null
164 : pointers otherwise).
165 : The returned arrays should be freed by the user when no longer needed.
166 :
167 : Level: advanced
168 :
169 : .seealso: RGPolygonSetVertices()
170 : @*/
171 2 : PetscErrorCode RGPolygonGetVertices(RG rg,PetscInt *n,PetscScalar **vr,PetscScalar **vi)
172 : {
173 2 : PetscFunctionBegin;
174 2 : PetscValidHeaderSpecific(rg,RG_CLASSID,1);
175 2 : PetscUseMethod(rg,"RGPolygonGetVertices_C",(RG,PetscInt*,PetscScalar**,PetscScalar**),(rg,n,vr,vi));
176 2 : PetscFunctionReturn(PETSC_SUCCESS);
177 : }
178 :
179 3 : static PetscErrorCode RGView_Polygon(RG rg,PetscViewer viewer)
180 : {
181 3 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
182 3 : PetscBool isdraw,isascii;
183 3 : int winw,winh;
184 3 : PetscDraw draw;
185 3 : PetscDrawAxis axis;
186 3 : PetscReal a,b,c,d,ab,cd,lx,ly,w,x0,y0,x1,y1,scale=1.2;
187 3 : PetscInt i;
188 3 : char str[50];
189 :
190 3 : PetscFunctionBegin;
191 3 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
192 3 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
193 3 : if (isascii) {
194 2 : PetscCall(PetscViewerASCIIPrintf(viewer," vertices: "));
195 2 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
196 16 : for (i=0;i<ctx->n;i++) {
197 : #if defined(PETSC_USE_COMPLEX)
198 : PetscCall(SlepcSNPrintfScalar(str,sizeof(str),ctx->vr[i],PETSC_FALSE));
199 : #else
200 14 : if (ctx->vi[i]!=0.0) PetscCall(PetscSNPrintf(str,sizeof(str),"%g%+gi",(double)ctx->vr[i],(double)ctx->vi[i]));
201 2 : else PetscCall(PetscSNPrintf(str,sizeof(str),"%g",(double)ctx->vr[i]));
202 : #endif
203 16 : PetscCall(PetscViewerASCIIPrintf(viewer,"%s%s",str,(i<ctx->n-1)?", ":""));
204 : }
205 2 : PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
206 2 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
207 1 : } else if (isdraw) {
208 1 : PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
209 1 : PetscCall(PetscDrawCheckResizedWindow(draw));
210 1 : PetscCall(PetscDrawGetWindowSize(draw,&winw,&winh));
211 1 : winw = PetscMax(winw,1); winh = PetscMax(winh,1);
212 1 : PetscCall(PetscDrawClear(draw));
213 1 : PetscCall(PetscDrawSetTitle(draw,"Polygonal region"));
214 1 : PetscCall(PetscDrawAxisCreate(draw,&axis));
215 1 : PetscCall(RGComputeBoundingBox_Polygon(rg,&a,&b,&c,&d));
216 1 : a *= rg->sfactor;
217 1 : b *= rg->sfactor;
218 1 : c *= rg->sfactor;
219 1 : d *= rg->sfactor;
220 1 : lx = b-a;
221 1 : ly = d-c;
222 1 : ab = (a+b)/2;
223 1 : cd = (c+d)/2;
224 1 : w = scale*PetscMax(lx/winw,ly/winh)/2;
225 1 : PetscCall(PetscDrawAxisSetLimits(axis,ab-w*winw,ab+w*winw,cd-w*winh,cd+w*winh));
226 1 : PetscCall(PetscDrawAxisDraw(axis));
227 1 : PetscCall(PetscDrawAxisDestroy(&axis));
228 8 : for (i=0;i<ctx->n;i++) {
229 : #if defined(PETSC_USE_COMPLEX)
230 : x0 = PetscRealPart(ctx->vr[i]); y0 = PetscImaginaryPart(ctx->vr[i]);
231 : if (i<ctx->n-1) {
232 : x1 = PetscRealPart(ctx->vr[i+1]); y1 = PetscImaginaryPart(ctx->vr[i+1]);
233 : } else {
234 : x1 = PetscRealPart(ctx->vr[0]); y1 = PetscImaginaryPart(ctx->vr[0]);
235 : }
236 : #else
237 7 : x0 = ctx->vr[i]; y0 = ctx->vi[i];
238 7 : if (i<ctx->n-1) {
239 6 : x1 = ctx->vr[i+1]; y1 = ctx->vi[i+1];
240 : } else {
241 1 : x1 = ctx->vr[0]; y1 = ctx->vi[0];
242 : }
243 : #endif
244 7 : PetscCall(PetscDrawLine(draw,x0*rg->sfactor,y0*rg->sfactor,x1*rg->sfactor,y1*rg->sfactor,PETSC_DRAW_MAGENTA));
245 : }
246 1 : PetscCall(PetscDrawFlush(draw));
247 1 : PetscCall(PetscDrawSave(draw));
248 1 : PetscCall(PetscDrawPause(draw));
249 : }
250 3 : PetscFunctionReturn(PETSC_SUCCESS);
251 : }
252 :
253 4 : static PetscErrorCode RGIsTrivial_Polygon(RG rg,PetscBool *trivial)
254 : {
255 4 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
256 :
257 4 : PetscFunctionBegin;
258 4 : *trivial = PetscNot(ctx->n);
259 4 : PetscFunctionReturn(PETSC_SUCCESS);
260 : }
261 :
262 2 : static PetscErrorCode RGComputeContour_Polygon(RG rg,PetscInt n,PetscScalar *ucr,PetscScalar *uci)
263 : {
264 2 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
265 2 : PetscReal length,h,d,rem=0.0;
266 2 : PetscInt k=1,idx=ctx->n-1,i;
267 2 : PetscBool ini=PETSC_FALSE;
268 2 : PetscScalar incr,*cr=ucr,*ci=uci;
269 : #if !defined(PETSC_USE_COMPLEX)
270 2 : PetscScalar inci;
271 : #endif
272 :
273 2 : PetscFunctionBegin;
274 2 : PetscCheck(ctx->n,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONGSTATE,"No vertices have been set yet");
275 2 : length = SlepcAbsEigenvalue(ctx->vr[0]-ctx->vr[ctx->n-1],ctx->vi[0]-ctx->vi[ctx->n-1]);
276 16 : for (i=0;i<ctx->n-1;i++) length += SlepcAbsEigenvalue(ctx->vr[i]-ctx->vr[i+1],ctx->vi[i]-ctx->vi[i+1]);
277 2 : h = length/n;
278 2 : if (!ucr) PetscCall(PetscMalloc1(n,&cr));
279 2 : if (!uci) PetscCall(PetscMalloc1(n,&ci));
280 2 : cr[0] = ctx->vr[0];
281 : #if !defined(PETSC_USE_COMPLEX)
282 2 : ci[0] = ctx->vi[0];
283 : #endif
284 2 : incr = ctx->vr[ctx->n-1]-ctx->vr[0];
285 : #if !defined(PETSC_USE_COMPLEX)
286 2 : inci = ctx->vi[ctx->n-1]-ctx->vi[0];
287 : #endif
288 2 : d = SlepcAbsEigenvalue(incr,inci);
289 2 : incr /= d;
290 : #if !defined(PETSC_USE_COMPLEX)
291 2 : inci /= d;
292 : #endif
293 32 : while (k<n) {
294 30 : if (ini) {
295 12 : incr = ctx->vr[idx]-ctx->vr[idx+1];
296 : #if !defined(PETSC_USE_COMPLEX)
297 12 : inci = ctx->vi[idx]-ctx->vi[idx+1];
298 : #endif
299 12 : d = SlepcAbsEigenvalue(incr,inci);
300 12 : incr /= d;
301 : #if !defined(PETSC_USE_COMPLEX)
302 12 : inci /= d;
303 : #endif
304 12 : if (rem+d>h) {
305 12 : cr[k] = ctx->vr[idx+1]+incr*(h-rem);
306 : #if !defined(PETSC_USE_COMPLEX)
307 12 : ci[k] = ctx->vi[idx+1]+inci*(h-rem);
308 : #endif
309 12 : k++;
310 12 : ini = PETSC_FALSE;
311 0 : } else {rem += d; idx--;}
312 : } else {
313 : #if !defined(PETSC_USE_COMPLEX)
314 18 : rem = SlepcAbsEigenvalue(ctx->vr[idx]-cr[k-1],ctx->vi[idx]-ci[k-1]);
315 : #else
316 : rem = PetscAbsScalar(ctx->vr[idx]-cr[k-1]);
317 : #endif
318 18 : if (rem>h) {
319 6 : cr[k] = cr[k-1]+incr*h;
320 : #if !defined(PETSC_USE_COMPLEX)
321 6 : ci[k] = ci[k-1]+inci*h;
322 : #endif
323 6 : k++;
324 12 : } else {ini = PETSC_TRUE; idx--;}
325 : }
326 : }
327 2 : if (!ucr) PetscCall(PetscFree(cr));
328 2 : if (!uci) PetscCall(PetscFree(ci));
329 2 : PetscFunctionReturn(PETSC_SUCCESS);
330 : }
331 :
332 3 : static PetscErrorCode RGComputeBoundingBox_Polygon(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
333 : {
334 3 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
335 3 : PetscInt i;
336 :
337 3 : PetscFunctionBegin;
338 3 : if (a) *a = PETSC_MAX_REAL;
339 3 : if (b) *b = -PETSC_MAX_REAL;
340 3 : if (c) *c = PETSC_MAX_REAL;
341 3 : if (d) *d = -PETSC_MAX_REAL;
342 24 : for (i=0;i<ctx->n;i++) {
343 : #if defined(PETSC_USE_COMPLEX)
344 : if (a) *a = PetscMin(*a,PetscRealPart(ctx->vr[i]));
345 : if (b) *b = PetscMax(*b,PetscRealPart(ctx->vr[i]));
346 : if (c) *c = PetscMin(*c,PetscImaginaryPart(ctx->vr[i]));
347 : if (d) *d = PetscMax(*d,PetscImaginaryPart(ctx->vr[i]));
348 : #else
349 27 : if (a) *a = PetscMin(*a,ctx->vr[i]);
350 30 : if (b) *b = PetscMax(*b,ctx->vr[i]);
351 30 : if (c) *c = PetscMin(*c,ctx->vi[i]);
352 39 : if (d) *d = PetscMax(*d,ctx->vi[i]);
353 : #endif
354 : }
355 3 : PetscFunctionReturn(PETSC_SUCCESS);
356 : }
357 :
358 2 : static PetscErrorCode RGCheckInside_Polygon(RG rg,PetscReal px,PetscReal py,PetscInt *inout)
359 : {
360 2 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
361 2 : PetscReal val,x[VERTMAX],y[VERTMAX];
362 2 : PetscBool mx,my,nx,ny;
363 2 : PetscInt i,j;
364 :
365 2 : PetscFunctionBegin;
366 16 : for (i=0;i<ctx->n;i++) {
367 : #if defined(PETSC_USE_COMPLEX)
368 : x[i] = PetscRealPart(ctx->vr[i])-px;
369 : y[i] = PetscImaginaryPart(ctx->vr[i])-py;
370 : #else
371 14 : x[i] = ctx->vr[i]-px;
372 14 : y[i] = ctx->vi[i]-py;
373 : #endif
374 : }
375 2 : *inout = -1;
376 16 : for (i=0;i<ctx->n;i++) {
377 14 : j = (i+1)%ctx->n;
378 14 : mx = PetscNot(x[i]<0.0);
379 14 : nx = PetscNot(x[j]<0.0);
380 14 : my = PetscNot(y[i]<0.0);
381 14 : ny = PetscNot(y[j]<0.0);
382 14 : if (!((my||ny) && (mx||nx)) || (mx&&nx)) continue;
383 0 : if (((my && ny && (mx||nx)) && (!(mx&&nx)))) {
384 0 : *inout = -*inout;
385 0 : continue;
386 : }
387 0 : val = (y[i]*x[j]-x[i]*y[j])/(x[j]-x[i]);
388 0 : if (PetscAbs(val)<10*PETSC_MACHINE_EPSILON) {
389 0 : *inout = 0;
390 0 : PetscFunctionReturn(PETSC_SUCCESS);
391 0 : } else if (val>0.0) *inout = -*inout;
392 : }
393 2 : PetscFunctionReturn(PETSC_SUCCESS);
394 : }
395 :
396 2 : static PetscErrorCode RGSetFromOptions_Polygon(RG rg,PetscOptionItems *PetscOptionsObject)
397 : {
398 2 : PetscScalar array[VERTMAX];
399 2 : PetscInt i,k;
400 2 : PetscBool flg,flgi=PETSC_FALSE;
401 : #if !defined(PETSC_USE_COMPLEX)
402 2 : PetscScalar arrayi[VERTMAX];
403 2 : PetscInt ki;
404 : #else
405 : PetscScalar *arrayi=NULL;
406 : #endif
407 :
408 2 : PetscFunctionBegin;
409 2 : PetscOptionsHeadBegin(PetscOptionsObject,"RG Polygon Options");
410 :
411 2 : k = VERTMAX;
412 62 : for (i=0;i<k;i++) array[i] = 0;
413 2 : PetscCall(PetscOptionsScalarArray("-rg_polygon_vertices","Vertices of polygon","RGPolygonSetVertices",array,&k,&flg));
414 : #if !defined(PETSC_USE_COMPLEX)
415 2 : ki = VERTMAX;
416 62 : for (i=0;i<ki;i++) arrayi[i] = 0;
417 2 : PetscCall(PetscOptionsScalarArray("-rg_polygon_verticesi","Vertices of polygon (imaginary part)","RGPolygonSetVertices",arrayi,&ki,&flgi));
418 2 : PetscCheck(ki==k,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_SIZ,"The number of real %" PetscInt_FMT " and imaginary %" PetscInt_FMT " parts do not match",k,ki);
419 : #endif
420 2 : if (flg || flgi) PetscCall(RGPolygonSetVertices(rg,k,array,arrayi));
421 :
422 2 : PetscOptionsHeadEnd();
423 2 : PetscFunctionReturn(PETSC_SUCCESS);
424 : }
425 :
426 2 : static PetscErrorCode RGDestroy_Polygon(RG rg)
427 : {
428 2 : RG_POLYGON *ctx = (RG_POLYGON*)rg->data;
429 :
430 2 : PetscFunctionBegin;
431 2 : if (ctx->n) {
432 2 : PetscCall(PetscFree(ctx->vr));
433 : #if !defined(PETSC_USE_COMPLEX)
434 2 : PetscCall(PetscFree(ctx->vi));
435 : #endif
436 : }
437 2 : PetscCall(PetscFree(rg->data));
438 2 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGPolygonSetVertices_C",NULL));
439 2 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGPolygonGetVertices_C",NULL));
440 2 : PetscFunctionReturn(PETSC_SUCCESS);
441 : }
442 :
443 2 : SLEPC_EXTERN PetscErrorCode RGCreate_Polygon(RG rg)
444 : {
445 2 : RG_POLYGON *polygon;
446 :
447 2 : PetscFunctionBegin;
448 2 : PetscCall(PetscNew(&polygon));
449 2 : rg->data = (void*)polygon;
450 :
451 2 : rg->ops->istrivial = RGIsTrivial_Polygon;
452 2 : rg->ops->computecontour = RGComputeContour_Polygon;
453 2 : rg->ops->computebbox = RGComputeBoundingBox_Polygon;
454 2 : rg->ops->checkinside = RGCheckInside_Polygon;
455 2 : rg->ops->setfromoptions = RGSetFromOptions_Polygon;
456 2 : rg->ops->view = RGView_Polygon;
457 2 : rg->ops->destroy = RGDestroy_Polygon;
458 2 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGPolygonSetVertices_C",RGPolygonSetVertices_Polygon));
459 2 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGPolygonGetVertices_C",RGPolygonGetVertices_Polygon));
460 2 : PetscFunctionReturn(PETSC_SUCCESS);
461 : }
|