Actual source code: rginterval.c
slepc-main 2024-12-17
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, 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: Interval of the real axis or more generally a (possibly open) rectangle
12: of the complex plane
13: */
15: #include <slepc/private/rgimpl.h>
16: #include <petscdraw.h>
18: typedef struct {
19: PetscReal a,b; /* interval in the real axis */
20: PetscReal c,d; /* interval in the imaginary axis */
21: } RG_INTERVAL;
23: static PetscErrorCode RGIntervalSetEndpoints_Interval(RG rg,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
24: {
25: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
27: PetscFunctionBegin;
28: PetscCheck(a || b || c || d,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"At least one argument must be nonzero");
29: PetscCheck(a!=b || !a,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, endpoints must be distinct (or both zero)");
30: PetscCheck(a<=b,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, must be a<b");
31: PetscCheck(c!=d || !c,PetscObjectComm((PetscObject)rg),PETSC_ERR_ARG_WRONG,"Badly defined interval, endpoints must be distinct (or both zero)");
32: 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: ctx->a = a;
37: ctx->b = b;
38: ctx->c = c;
39: ctx->d = d;
40: PetscFunctionReturn(PETSC_SUCCESS);
41: }
43: /*@
44: RGIntervalSetEndpoints - Sets the parameters defining the interval region.
46: Logically Collective
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
55: Options Database Keys:
56: . -rg_interval_endpoints - the four endpoints
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.
63: When PETSc is built with real scalars, the region must be symmetric with
64: respect to the real axis.
66: Level: advanced
68: .seealso: RGIntervalGetEndpoints()
69: @*/
70: PetscErrorCode RGIntervalSetEndpoints(RG rg,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
71: {
72: PetscFunctionBegin;
78: PetscTryMethod(rg,"RGIntervalSetEndpoints_C",(RG,PetscReal,PetscReal,PetscReal,PetscReal),(rg,a,b,c,d));
79: PetscFunctionReturn(PETSC_SUCCESS);
80: }
82: static PetscErrorCode RGIntervalGetEndpoints_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
83: {
84: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
86: PetscFunctionBegin;
87: if (a) *a = ctx->a;
88: if (b) *b = ctx->b;
89: if (c) *c = ctx->c;
90: if (d) *d = ctx->d;
91: PetscFunctionReturn(PETSC_SUCCESS);
92: }
94: /*@
95: RGIntervalGetEndpoints - Gets the parameters that define the interval region.
97: Not Collective
99: Input Parameter:
100: . rg - the region context
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
108: Level: advanced
110: .seealso: RGIntervalSetEndpoints()
111: @*/
112: PetscErrorCode RGIntervalGetEndpoints(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
113: {
114: PetscFunctionBegin;
116: PetscUseMethod(rg,"RGIntervalGetEndpoints_C",(RG,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,a,b,c,d));
117: PetscFunctionReturn(PETSC_SUCCESS);
118: }
120: static PetscErrorCode RGView_Interval(RG rg,PetscViewer viewer)
121: {
122: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
123: PetscBool isdraw,isascii;
124: int winw,winh;
125: PetscDraw draw;
126: PetscDrawAxis axis;
127: PetscReal a,b,c,d,ab,cd,lx,ly,w,scale=1.2;
129: PetscFunctionBegin;
130: PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
131: PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
132: 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: else if (isdraw) {
134: PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
135: PetscCall(PetscDrawCheckResizedWindow(draw));
136: PetscCall(PetscDrawGetWindowSize(draw,&winw,&winh));
137: winw = PetscMax(winw,1); winh = PetscMax(winh,1);
138: PetscCall(PetscDrawClear(draw));
139: PetscCall(PetscDrawSetTitle(draw,"Interval region"));
140: PetscCall(PetscDrawAxisCreate(draw,&axis));
141: a = ctx->a*rg->sfactor;
142: b = ctx->b*rg->sfactor;
143: c = ctx->c*rg->sfactor;
144: d = ctx->d*rg->sfactor;
145: lx = b-a;
146: ly = d-c;
147: ab = (a+b)/2;
148: cd = (c+d)/2;
149: w = scale*PetscMax(lx/winw,ly/winh)/2;
150: PetscCall(PetscDrawAxisSetLimits(axis,ab-w*winw,ab+w*winw,cd-w*winh,cd+w*winh));
151: PetscCall(PetscDrawAxisDraw(axis));
152: PetscCall(PetscDrawAxisDestroy(&axis));
153: PetscCall(PetscDrawRectangle(draw,a,c,b,d,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE));
154: PetscCall(PetscDrawFlush(draw));
155: PetscCall(PetscDrawSave(draw));
156: PetscCall(PetscDrawPause(draw));
157: }
158: PetscFunctionReturn(PETSC_SUCCESS);
159: }
161: static PetscErrorCode RGIsTrivial_Interval(RG rg,PetscBool *trivial)
162: {
163: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
165: PetscFunctionBegin;
166: if (rg->complement) *trivial = (ctx->a==ctx->b && ctx->c==ctx->d)? PETSC_TRUE: PETSC_FALSE;
167: 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: PetscFunctionReturn(PETSC_SUCCESS);
169: }
171: static PetscErrorCode RGComputeContour_Interval(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
172: {
173: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
174: PetscInt i,N,Nv,Nh,k1,k0;
175: PetscReal hv,hh,t;
177: PetscFunctionBegin;
178: 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: if (ctx->a==ctx->b || ctx->c==ctx->d) {
180: if (ctx->a==ctx->b) {hv = (ctx->d-ctx->c)/(n-1); hh = 0.0;}
181: else {hh = (ctx->b-ctx->a)/(n-1); hv = 0.0;}
182: for (i=0;i<n;i++) {
183: #if defined(PETSC_USE_COMPLEX)
184: 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: PetscCheck(n>3,PetscObjectComm((PetscObject)rg),PETSC_ERR_SUP,"Minimum number of contour points: 4");
192: N = n/2;
193: t = ((ctx->d-ctx->c)/(ctx->d-ctx->c+ctx->b-ctx->a))*N;
194: Nv = t-PetscFloorReal(t)>0.5?PetscCeilReal(t):PetscFloorReal(t);
195: if (Nv==0) Nv++;
196: else if (Nv==N) Nv--;
197: Nh = N-Nv;
198: hh = (ctx->b-ctx->a)/Nh;
199: hv = (ctx->d-ctx->c)/Nv;
200: /* positive imaginary part first */
201: k1 = Nv/2+1;
202: k0 = Nv-k1;
204: for (i=k1;i<Nv;i++) {
205: #if defined(PETSC_USE_COMPLEX)
206: cr[i-k1] = PetscCMPLX(ctx->b,ctx->c+i*hv);
207: 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: for (i=0;i<Nh;i++) {
214: #if defined(PETSC_USE_COMPLEX)
215: cr[i+k0] = PetscCMPLX(ctx->b-i*hh,ctx->d);
216: 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: for (i=0;i<k1;i++) {
223: #if defined(PETSC_USE_COMPLEX)
224: cr[i+k0+Nh] = PetscCMPLX(ctx->a,ctx->d-i*hv);
225: 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: PetscFunctionReturn(PETSC_SUCCESS);
233: }
235: static PetscErrorCode RGComputeBoundingBox_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
236: {
237: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
239: PetscFunctionBegin;
240: if (a) *a = ctx->a;
241: if (b) *b = ctx->b;
242: if (c) *c = ctx->c;
243: if (d) *d = ctx->d;
244: PetscFunctionReturn(PETSC_SUCCESS);
245: }
247: static PetscErrorCode RGComputeQuadrature_Interval(RG rg,RGQuadRule quad,PetscInt n,PetscScalar *z,PetscScalar *zn,PetscScalar *w)
248: {
249: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
250: PetscReal theta,max_w=0.0,radius=1.0;
251: PetscScalar tmp,tmp2,center=0.0;
252: PetscInt i,j;
254: PetscFunctionBegin;
255: if (quad == RG_QUADRULE_CHEBYSHEV) {
256: 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: for (i=0;i<n;i++) {
258: theta = PETSC_PI*(i+0.5)/n;
259: zn[i] = PetscCosReal(theta);
260: w[i] = PetscCosReal((n-1)*theta)/n;
261: if (ctx->c==ctx->d) z[i] = ((ctx->b-ctx->a)*(zn[i]+1.0)/2.0+ctx->a)*rg->sfactor;
262: else if (ctx->a==ctx->b) {
263: #if defined(PETSC_USE_COMPLEX)
264: 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: 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: radius = PetscSqrtReal(PetscPowRealInt(rg->sfactor*(ctx->b-ctx->a)/2.0,2)+PetscPowRealInt(rg->sfactor*(ctx->d-ctx->c)/2.0,2));
277: for (i=0;i<n;i++) {
278: zn[i] = (z[i]-center)/radius;
279: tmp = 1.0; tmp2 = 1.0;
280: for (j=0;j<n;j++) {
281: tmp *= z[j];
282: if (i != j) tmp2 *= z[j]-z[i];
283: }
284: w[i] = tmp/tmp2;
285: max_w = PetscMax(PetscAbsScalar(w[i]),max_w);
286: }
287: for (i=0;i<n;i++) w[i] /= (PetscScalar)max_w;
288: }
289: PetscFunctionReturn(PETSC_SUCCESS);
290: }
292: static PetscErrorCode RGCheckInside_Interval(RG rg,PetscReal dx,PetscReal dy,PetscInt *inside)
293: {
294: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
296: PetscFunctionBegin;
297: if (dx>ctx->a && dx<ctx->b) *inside = 1;
298: else if (dx==ctx->a || dx==ctx->b) *inside = 0;
299: else *inside = -1;
300: if (*inside>=0) {
301: if (dy>ctx->c && dy<ctx->d) ;
302: else if (dy==ctx->c || dy==ctx->d) *inside = 0;
303: else *inside = -1;
304: }
305: PetscFunctionReturn(PETSC_SUCCESS);
306: }
308: static PetscErrorCode RGIsAxisymmetric_Interval(RG rg,PetscBool vertical,PetscBool *symm)
309: {
310: RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
312: PetscFunctionBegin;
313: if (vertical) *symm = (ctx->a == -ctx->b)? PETSC_TRUE: PETSC_FALSE;
314: else *symm = (ctx->c == -ctx->d)? PETSC_TRUE: PETSC_FALSE;
315: PetscFunctionReturn(PETSC_SUCCESS);
316: }
318: static PetscErrorCode RGSetFromOptions_Interval(RG rg,PetscOptionItems *PetscOptionsObject)
319: {
320: PetscBool flg;
321: PetscInt k;
322: PetscReal array[4]={0,0,0,0};
324: PetscFunctionBegin;
325: PetscOptionsHeadBegin(PetscOptionsObject,"RG Interval Options");
327: k = 4;
328: PetscCall(PetscOptionsRealArray("-rg_interval_endpoints","Interval endpoints (two or four real values separated with a comma without spaces)","RGIntervalSetEndpoints",array,&k,&flg));
329: if (flg) {
330: 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: PetscCall(RGIntervalSetEndpoints(rg,array[0],array[1],array[2],array[3]));
332: }
334: PetscOptionsHeadEnd();
335: PetscFunctionReturn(PETSC_SUCCESS);
336: }
338: static PetscErrorCode RGDestroy_Interval(RG rg)
339: {
340: PetscFunctionBegin;
341: PetscCall(PetscFree(rg->data));
342: PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",NULL));
343: PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",NULL));
344: PetscFunctionReturn(PETSC_SUCCESS);
345: }
347: SLEPC_EXTERN PetscErrorCode RGCreate_Interval(RG rg)
348: {
349: RG_INTERVAL *interval;
351: PetscFunctionBegin;
352: PetscCall(PetscNew(&interval));
353: interval->a = -PETSC_MAX_REAL;
354: interval->b = PETSC_MAX_REAL;
355: interval->c = -PETSC_MAX_REAL;
356: interval->d = PETSC_MAX_REAL;
357: rg->data = (void*)interval;
359: rg->ops->istrivial = RGIsTrivial_Interval;
360: rg->ops->computecontour = RGComputeContour_Interval;
361: rg->ops->computebbox = RGComputeBoundingBox_Interval;
362: rg->ops->computequadrature = RGComputeQuadrature_Interval;
363: rg->ops->checkinside = RGCheckInside_Interval;
364: rg->ops->isaxisymmetric = RGIsAxisymmetric_Interval;
365: rg->ops->setfromoptions = RGSetFromOptions_Interval;
366: rg->ops->view = RGView_Interval;
367: rg->ops->destroy = RGDestroy_Interval;
368: PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",RGIntervalSetEndpoints_Interval));
369: PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",RGIntervalGetEndpoints_Interval));
370: PetscFunctionReturn(PETSC_SUCCESS);
371: }