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 : Interval of the real axis or more generally a (possibly open) rectangle
12 : of the complex plane
13 : */
14 :
15 : #include <slepc/private/rgimpl.h> /*I "slepcrg.h" I*/
16 : #include <petscdraw.h>
17 :
18 : typedef struct {
19 : PetscReal a,b; /* interval in the real axis */
20 : PetscReal c,d; /* interval in the imaginary axis */
21 : } RG_INTERVAL;
22 :
23 119 : static PetscErrorCode RGIntervalSetEndpoints_Interval(RG rg,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
24 : {
25 119 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
26 :
27 119 : PetscFunctionBegin;
28 119 : PetscCheck(a || b || c || d,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"At least one argument must be nonzero");
29 119 : PetscCheck(a!=b || !a,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, endpoints must be distinct (or both zero)");
30 119 : PetscCheck(a<=b,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, must be a<b");
31 119 : PetscCheck(c!=d || !c,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, endpoints must be distinct (or both zero)");
32 119 : PetscCheck(c<=d,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, must be c<d");
33 : #if !defined(PETSC_USE_COMPLEX)
34 : PetscCheck(c==-d,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"In real scalars the region must be symmetric wrt real axis");
35 : #endif
36 119 : ctx->a = a;
37 119 : ctx->b = b;
38 119 : ctx->c = c;
39 119 : ctx->d = d;
40 119 : PetscFunctionReturn(PETSC_SUCCESS);
41 : }
42 :
43 : /*@
44 : RGIntervalSetEndpoints - Sets the parameters defining the interval region.
45 :
46 : Logically Collective
47 :
48 : Input Parameters:
49 : + rg - the region context
50 : . a - left endpoint of the interval in the real axis
51 : . b - right endpoint of the interval in the real axis
52 : . c - bottom endpoint of the interval in the imaginary axis
53 : - d - top endpoint of the interval in the imaginary axis
54 :
55 : Options Database Keys:
56 : . -rg_interval_endpoints - the four endpoints
57 :
58 : Note:
59 : The region is defined as [a,b]x[c,d]. Particular cases are an interval on
60 : the real axis (c=d=0), similar for the imaginary axis (a=b=0), the whole
61 : complex plane (a=-inf,b=inf,c=-inf,d=inf), and so on.
62 :
63 : When PETSc is built with real scalars, the region must be symmetric with
64 : respect to the real axis.
65 :
66 : Level: advanced
67 :
68 : .seealso: RGIntervalGetEndpoints()
69 : @*/
70 119 : PetscErrorCode RGIntervalSetEndpoints(RG rg,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
71 : {
72 119 : PetscFunctionBegin;
73 119 : PetscValidHeaderSpecific(rg,RG_CLASSID,1);
74 357 : PetscValidLogicalCollectiveReal(rg,a,2);
75 357 : PetscValidLogicalCollectiveReal(rg,b,3);
76 357 : PetscValidLogicalCollectiveReal(rg,c,4);
77 357 : PetscValidLogicalCollectiveReal(rg,d,5);
78 119 : PetscTryMethod(rg,"RGIntervalSetEndpoints_C",(RG,PetscReal,PetscReal,PetscReal,PetscReal),(rg,a,b,c,d));
79 119 : PetscFunctionReturn(PETSC_SUCCESS);
80 : }
81 :
82 435 : static PetscErrorCode RGIntervalGetEndpoints_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
83 : {
84 435 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
85 :
86 435 : PetscFunctionBegin;
87 435 : if (a) *a = ctx->a;
88 435 : if (b) *b = ctx->b;
89 435 : if (c) *c = ctx->c;
90 435 : if (d) *d = ctx->d;
91 435 : PetscFunctionReturn(PETSC_SUCCESS);
92 : }
93 :
94 : /*@
95 : RGIntervalGetEndpoints - Gets the parameters that define the interval region.
96 :
97 : Not Collective
98 :
99 : Input Parameter:
100 : . rg - the region context
101 :
102 : Output Parameters:
103 : + a - left endpoint of the interval in the real axis
104 : . b - right endpoint of the interval in the real axis
105 : . c - bottom endpoint of the interval in the imaginary axis
106 : - d - top endpoint of the interval in the imaginary axis
107 :
108 : Level: advanced
109 :
110 : .seealso: RGIntervalSetEndpoints()
111 : @*/
112 435 : PetscErrorCode RGIntervalGetEndpoints(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
113 : {
114 435 : PetscFunctionBegin;
115 435 : PetscValidHeaderSpecific(rg,RG_CLASSID,1);
116 435 : PetscUseMethod(rg,"RGIntervalGetEndpoints_C",(RG,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,a,b,c,d));
117 435 : PetscFunctionReturn(PETSC_SUCCESS);
118 : }
119 :
120 5 : static PetscErrorCode RGView_Interval(RG rg,PetscViewer viewer)
121 : {
122 5 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
123 5 : PetscBool isdraw,isascii;
124 5 : int winw,winh;
125 5 : PetscDraw draw;
126 5 : PetscDrawAxis axis;
127 5 : PetscReal a,b,c,d,ab,cd,lx,ly,w,scale=1.2;
128 :
129 5 : PetscFunctionBegin;
130 5 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
131 5 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
132 5 : if (isascii) PetscCall(PetscViewerASCIIPrintf(viewer," region: [%g,%g]x[%g,%g]\n",RGShowReal(ctx->a),RGShowReal(ctx->b),RGShowReal(ctx->c),RGShowReal(ctx->d)));
133 1 : else if (isdraw) {
134 1 : PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
135 1 : PetscCall(PetscDrawCheckResizedWindow(draw));
136 1 : PetscCall(PetscDrawGetWindowSize(draw,&winw,&winh));
137 1 : winw = PetscMax(winw,1); winh = PetscMax(winh,1);
138 1 : PetscCall(PetscDrawClear(draw));
139 1 : PetscCall(PetscDrawSetTitle(draw,"Interval region"));
140 1 : PetscCall(PetscDrawAxisCreate(draw,&axis));
141 1 : a = ctx->a*rg->sfactor;
142 1 : b = ctx->b*rg->sfactor;
143 1 : c = ctx->c*rg->sfactor;
144 1 : d = ctx->d*rg->sfactor;
145 1 : lx = b-a;
146 1 : ly = d-c;
147 1 : ab = (a+b)/2;
148 1 : cd = (c+d)/2;
149 1 : w = scale*PetscMax(lx/winw,ly/winh)/2;
150 1 : PetscCall(PetscDrawAxisSetLimits(axis,ab-w*winw,ab+w*winw,cd-w*winh,cd+w*winh));
151 1 : PetscCall(PetscDrawAxisDraw(axis));
152 1 : PetscCall(PetscDrawAxisDestroy(&axis));
153 1 : PetscCall(PetscDrawRectangle(draw,a,c,b,d,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE));
154 1 : PetscCall(PetscDrawFlush(draw));
155 1 : PetscCall(PetscDrawSave(draw));
156 1 : PetscCall(PetscDrawPause(draw));
157 : }
158 5 : PetscFunctionReturn(PETSC_SUCCESS);
159 : }
160 :
161 5982 : static PetscErrorCode RGIsTrivial_Interval(RG rg,PetscBool *trivial)
162 : {
163 5982 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
164 :
165 5982 : PetscFunctionBegin;
166 6009 : if (rg->complement) *trivial = (ctx->a==ctx->b && ctx->c==ctx->d)? PETSC_TRUE: PETSC_FALSE;
167 6499 : else *trivial = (ctx->a<=-PETSC_MAX_REAL && ctx->b>=PETSC_MAX_REAL && ctx->c<=-PETSC_MAX_REAL && ctx->d>=PETSC_MAX_REAL)? PETSC_TRUE: PETSC_FALSE;
168 5982 : PetscFunctionReturn(PETSC_SUCCESS);
169 : }
170 :
171 38 : static PetscErrorCode RGComputeContour_Interval(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
172 : {
173 38 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
174 38 : PetscInt i,N,Nv,Nh,k1,k0;
175 38 : PetscReal hv,hh,t;
176 :
177 38 : PetscFunctionBegin;
178 38 : PetscCheck(ctx->a>-PETSC_MAX_REAL && ctx->b<PETSC_MAX_REAL && ctx->c>-PETSC_MAX_REAL && ctx->d<PETSC_MAX_REAL,PetscObjectComm((PetscObject)rg),PETSC_ERR_SUP,"Contour not defined in unbounded regions");
179 38 : if (ctx->a==ctx->b || ctx->c==ctx->d) {
180 8 : if (ctx->a==ctx->b) {hv = (ctx->d-ctx->c)/(n-1); hh = 0.0;}
181 8 : else {hh = (ctx->b-ctx->a)/(n-1); hv = 0.0;}
182 236 : for (i=0;i<n;i++) {
183 : #if defined(PETSC_USE_COMPLEX)
184 228 : cr[i] = PetscCMPLX(ctx->a+hh*i,ctx->c+hv*i);
185 : #else
186 : if (cr) cr[i] = ctx->a+hh*i;
187 : if (ci) ci[i] = ctx->c+hv*i;
188 : #endif
189 : }
190 : } else {
191 30 : PetscCheck(n>3,PetscObjectComm((PetscObject)rg),PETSC_ERR_SUP,"Minimum number of contour points: 4");
192 30 : N = n/2;
193 30 : t = ((ctx->d-ctx->c)/(ctx->d-ctx->c+ctx->b-ctx->a))*N;
194 30 : Nv = t-PetscFloorReal(t)>0.5?PetscCeilReal(t):PetscFloorReal(t);
195 30 : if (Nv==0) Nv++;
196 22 : else if (Nv==N) Nv--;
197 30 : Nh = N-Nv;
198 30 : hh = (ctx->b-ctx->a)/Nh;
199 30 : hv = (ctx->d-ctx->c)/Nv;
200 : /* positive imaginary part first */
201 30 : k1 = Nv/2+1;
202 30 : k0 = Nv-k1;
203 :
204 37 : for (i=k1;i<Nv;i++) {
205 : #if defined(PETSC_USE_COMPLEX)
206 7 : cr[i-k1] = PetscCMPLX(ctx->b,ctx->c+i*hv);
207 7 : cr[i-k1+N] = PetscCMPLX(ctx->a,ctx->d-i*hv);
208 : #else
209 : if (cr) {cr[i-k1] = ctx->b; cr[i-k1+N] = ctx->a;}
210 : if (ci) {ci[i-k1] = ctx->c+i*hv; ci[i-k1+N] = ctx->d-i*hv;}
211 : #endif
212 : }
213 75577 : for (i=0;i<Nh;i++) {
214 : #if defined(PETSC_USE_COMPLEX)
215 75547 : cr[i+k0] = PetscCMPLX(ctx->b-i*hh,ctx->d);
216 75547 : cr[i+k0+N] = PetscCMPLX(ctx->a+i*hh,ctx->c);
217 : #else
218 : if (cr) {cr[i+k0] = ctx->b-i*hh; cr[i+k0+N] = ctx->a+i*hh;}
219 : if (ci) {ci[i+k0] = ctx->d; ci[i+k0+N] = ctx->c;}
220 : #endif
221 : }
222 68 : for (i=0;i<k1;i++) {
223 : #if defined(PETSC_USE_COMPLEX)
224 38 : cr[i+k0+Nh] = PetscCMPLX(ctx->a,ctx->d-i*hv);
225 38 : cr[i+k0+Nh+N] = PetscCMPLX(ctx->b,ctx->c+i*hv);
226 : #else
227 : if (cr) {cr[i+k0+Nh] = ctx->a; cr[i+k0+Nh+N] = ctx->b;}
228 : if (ci) {ci[i+k0+Nh] = ctx->d+i*hv; ci[i+k0+Nh+N] = ctx->c-i*hv;}
229 : #endif
230 : }
231 : }
232 38 : PetscFunctionReturn(PETSC_SUCCESS);
233 : }
234 :
235 4 : static PetscErrorCode RGComputeBoundingBox_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
236 : {
237 4 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
238 :
239 4 : PetscFunctionBegin;
240 4 : if (a) *a = ctx->a;
241 4 : if (b) *b = ctx->b;
242 4 : if (c) *c = ctx->c;
243 4 : if (d) *d = ctx->d;
244 4 : PetscFunctionReturn(PETSC_SUCCESS);
245 : }
246 :
247 10 : static PetscErrorCode RGComputeQuadrature_Interval(RG rg,RGQuadRule quad,PetscInt n,PetscScalar *z,PetscScalar *zn,PetscScalar *w)
248 : {
249 10 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
250 10 : PetscReal theta,max_w=0.0,radius=1.0;
251 10 : PetscScalar tmp,tmp2,center=0.0;
252 10 : PetscInt i,j;
253 :
254 10 : PetscFunctionBegin;
255 10 : if (quad == RG_QUADRULE_CHEBYSHEV) {
256 7 : PetscCheck((ctx->c==ctx->d && ctx->c==0.0) || (ctx->a==ctx->b && ctx->a==0.0),PetscObjectComm((PetscObject)rg),PETSC_ERR_SUP,"Endpoints of the imaginary axis or the real axis must be both zero");
257 211 : for (i=0;i<n;i++) {
258 204 : theta = PETSC_PI*(i+0.5)/n;
259 204 : zn[i] = PetscCosReal(theta);
260 204 : w[i] = PetscCosReal((n-1)*theta)/n;
261 204 : if (ctx->c==ctx->d) z[i] = ((ctx->b-ctx->a)*(zn[i]+1.0)/2.0+ctx->a)*rg->sfactor;
262 0 : else if (ctx->a==ctx->b) {
263 : #if defined(PETSC_USE_COMPLEX)
264 0 : z[i] = ((ctx->d-ctx->c)*(zn[i]+1.0)/2.0+ctx->c)*rg->sfactor*PETSC_i;
265 : #else
266 : SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Integration points on a vertical line require complex arithmetic");
267 : #endif
268 : }
269 : }
270 : } else { /* RG_QUADRULE_TRAPEZOIDAL */
271 : #if defined(PETSC_USE_COMPLEX)
272 3 : center = rg->sfactor*PetscCMPLX(ctx->b+ctx->a,ctx->d+ctx->c)/2.0;
273 : #else
274 : center = rg->sfactor*(ctx->b+ctx->a)/2.0;
275 : #endif
276 6 : radius = PetscSqrtReal(PetscPowRealInt(rg->sfactor*(ctx->b-ctx->a)/2.0,2)+PetscPowRealInt(rg->sfactor*(ctx->d-ctx->c)/2.0,2));
277 91 : for (i=0;i<n;i++) {
278 88 : zn[i] = (z[i]-center)/radius;
279 88 : tmp = 1.0; tmp2 = 1.0;
280 2712 : for (j=0;j<n;j++) {
281 2624 : tmp *= z[j];
282 2624 : if (i != j) tmp2 *= z[j]-z[i];
283 : }
284 88 : w[i] = tmp/tmp2;
285 107 : max_w = PetscMax(PetscAbsScalar(w[i]),max_w);
286 : }
287 91 : for (i=0;i<n;i++) w[i] /= (PetscScalar)max_w;
288 : }
289 10 : PetscFunctionReturn(PETSC_SUCCESS);
290 : }
291 :
292 221248 : static PetscErrorCode RGCheckInside_Interval(RG rg,PetscReal dx,PetscReal dy,PetscInt *inside)
293 : {
294 221248 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
295 :
296 221248 : PetscFunctionBegin;
297 221248 : if (dx>ctx->a && dx<ctx->b) *inside = 1;
298 124357 : else if (dx==ctx->a || dx==ctx->b) *inside = 0;
299 124342 : else *inside = -1;
300 221248 : if (*inside>=0) {
301 96906 : if (dy>ctx->c && dy<ctx->d) ;
302 74519 : else if (dy==ctx->c || dy==ctx->d) *inside = 0;
303 74476 : else *inside = -1;
304 : }
305 221248 : PetscFunctionReturn(PETSC_SUCCESS);
306 : }
307 :
308 8 : static PetscErrorCode RGIsAxisymmetric_Interval(RG rg,PetscBool vertical,PetscBool *symm)
309 : {
310 8 : RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
311 :
312 8 : PetscFunctionBegin;
313 8 : if (vertical) *symm = (ctx->a == -ctx->b)? PETSC_TRUE: PETSC_FALSE;
314 5 : else *symm = (ctx->c == -ctx->d)? PETSC_TRUE: PETSC_FALSE;
315 8 : PetscFunctionReturn(PETSC_SUCCESS);
316 : }
317 :
318 816 : static PetscErrorCode RGSetFromOptions_Interval(RG rg,PetscOptionItems *PetscOptionsObject)
319 : {
320 816 : PetscBool flg;
321 816 : PetscInt k;
322 816 : PetscReal array[4]={0,0,0,0};
323 :
324 816 : PetscFunctionBegin;
325 816 : PetscOptionsHeadBegin(PetscOptionsObject,"RG Interval Options");
326 :
327 816 : k = 4;
328 816 : PetscCall(PetscOptionsRealArray("-rg_interval_endpoints","Interval endpoints (two or four real values separated with a comma without spaces)","RGIntervalSetEndpoints",array,&k,&flg));
329 816 : if (flg) {
330 54 : PetscCheck(k>1,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_SIZ,"Must pass at least two values in -rg_interval_endpoints (comma-separated without spaces)");
331 54 : PetscCall(RGIntervalSetEndpoints(rg,array[0],array[1],array[2],array[3]));
332 : }
333 :
334 816 : PetscOptionsHeadEnd();
335 816 : PetscFunctionReturn(PETSC_SUCCESS);
336 : }
337 :
338 871 : static PetscErrorCode RGDestroy_Interval(RG rg)
339 : {
340 871 : PetscFunctionBegin;
341 871 : PetscCall(PetscFree(rg->data));
342 871 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",NULL));
343 871 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",NULL));
344 871 : PetscFunctionReturn(PETSC_SUCCESS);
345 : }
346 :
347 871 : SLEPC_EXTERN PetscErrorCode RGCreate_Interval(RG rg)
348 : {
349 871 : RG_INTERVAL *interval;
350 :
351 871 : PetscFunctionBegin;
352 871 : PetscCall(PetscNew(&interval));
353 871 : interval->a = -PETSC_MAX_REAL;
354 871 : interval->b = PETSC_MAX_REAL;
355 871 : interval->c = -PETSC_MAX_REAL;
356 871 : interval->d = PETSC_MAX_REAL;
357 871 : rg->data = (void*)interval;
358 :
359 871 : rg->ops->istrivial = RGIsTrivial_Interval;
360 871 : rg->ops->computecontour = RGComputeContour_Interval;
361 871 : rg->ops->computebbox = RGComputeBoundingBox_Interval;
362 871 : rg->ops->computequadrature = RGComputeQuadrature_Interval;
363 871 : rg->ops->checkinside = RGCheckInside_Interval;
364 871 : rg->ops->isaxisymmetric = RGIsAxisymmetric_Interval;
365 871 : rg->ops->setfromoptions = RGSetFromOptions_Interval;
366 871 : rg->ops->view = RGView_Interval;
367 871 : rg->ops->destroy = RGDestroy_Interval;
368 871 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",RGIntervalSetEndpoints_Interval));
369 871 : PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",RGIntervalGetEndpoints_Interval));
370 871 : PetscFunctionReturn(PETSC_SUCCESS);
371 : }
|