Actual source code: rginterval.c

slepc-3.18.2 2023-01-26
Report Typos and Errors
  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;

 32: #if !defined(PETSC_USE_COMPLEX)
 34: #endif
 35:   ctx->a = a;
 36:   ctx->b = b;
 37:   ctx->c = c;
 38:   ctx->d = d;
 39:   return 0;
 40: }

 42: /*@
 43:    RGIntervalSetEndpoints - Sets the parameters defining the interval region.

 45:    Logically Collective on rg

 47:    Input Parameters:
 48: +  rg  - the region context
 49: .  a - left endpoint of the interval in the real axis
 50: .  b - right endpoint of the interval in the real axis
 51: .  c - bottom endpoint of the interval in the imaginary axis
 52: -  d - top endpoint of the interval in the imaginary axis

 54:    Options Database Keys:
 55: .  -rg_interval_endpoints - the four endpoints

 57:    Note:
 58:    The region is defined as [a,b]x[c,d]. Particular cases are an interval on
 59:    the real axis (c=d=0), similar for the imaginary axis (a=b=0), the whole
 60:    complex plane (a=-inf,b=inf,c=-inf,d=inf), and so on.

 62:    When PETSc is built with real scalars, the region must be symmetric with
 63:    respect to the real axis.

 65:    Level: advanced

 67: .seealso: RGIntervalGetEndpoints()
 68: @*/
 69: PetscErrorCode RGIntervalSetEndpoints(RG rg,PetscReal a,PetscReal b,PetscReal c,PetscReal d)
 70: {
 76:   PetscTryMethod(rg,"RGIntervalSetEndpoints_C",(RG,PetscReal,PetscReal,PetscReal,PetscReal),(rg,a,b,c,d));
 77:   return 0;
 78: }

 80: static PetscErrorCode RGIntervalGetEndpoints_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
 81: {
 82:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;

 84:   if (a) *a = ctx->a;
 85:   if (b) *b = ctx->b;
 86:   if (c) *c = ctx->c;
 87:   if (d) *d = ctx->d;
 88:   return 0;
 89: }

 91: /*@C
 92:    RGIntervalGetEndpoints - Gets the parameters that define the interval region.

 94:    Not Collective

 96:    Input Parameter:
 97: .  rg - the region context

 99:    Output Parameters:
100: +  a - left endpoint of the interval in the real axis
101: .  b - right endpoint of the interval in the real axis
102: .  c - bottom endpoint of the interval in the imaginary axis
103: -  d - top endpoint of the interval in the imaginary axis

105:    Level: advanced

107: .seealso: RGIntervalSetEndpoints()
108: @*/
109: PetscErrorCode RGIntervalGetEndpoints(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
110: {
112:   PetscUseMethod(rg,"RGIntervalGetEndpoints_C",(RG,PetscReal*,PetscReal*,PetscReal*,PetscReal*),(rg,a,b,c,d));
113:   return 0;
114: }

116: PetscErrorCode RGView_Interval(RG rg,PetscViewer viewer)
117: {
118:   RG_INTERVAL    *ctx = (RG_INTERVAL*)rg->data;
119:   PetscBool      isdraw,isascii;
120:   int            winw,winh;
121:   PetscDraw      draw;
122:   PetscDrawAxis  axis;
123:   PetscReal      a,b,c,d,ab,cd,lx,ly,w,scale=1.2;

125:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
126:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
127:   if (isascii) PetscViewerASCIIPrintf(viewer,"  region: [%g,%g]x[%g,%g]\n",RGShowReal(ctx->a),RGShowReal(ctx->b),RGShowReal(ctx->c),RGShowReal(ctx->d));
128:   else if (isdraw) {
129:     PetscViewerDrawGetDraw(viewer,0,&draw);
130:     PetscDrawCheckResizedWindow(draw);
131:     PetscDrawGetWindowSize(draw,&winw,&winh);
132:     winw = PetscMax(winw,1); winh = PetscMax(winh,1);
133:     PetscDrawClear(draw);
134:     PetscDrawSetTitle(draw,"Interval region");
135:     PetscDrawAxisCreate(draw,&axis);
136:     a  = ctx->a*rg->sfactor;
137:     b  = ctx->b*rg->sfactor;
138:     c  = ctx->c*rg->sfactor;
139:     d  = ctx->d*rg->sfactor;
140:     lx = b-a;
141:     ly = d-c;
142:     ab = (a+b)/2;
143:     cd = (c+d)/2;
144:     w  = scale*PetscMax(lx/winw,ly/winh)/2;
145:     PetscDrawAxisSetLimits(axis,ab-w*winw,ab+w*winw,cd-w*winh,cd+w*winh);
146:     PetscDrawAxisDraw(axis);
147:     PetscDrawAxisDestroy(&axis);
148:     PetscDrawRectangle(draw,a,c,b,d,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE,PETSC_DRAW_BLUE);
149:     PetscDrawFlush(draw);
150:     PetscDrawSave(draw);
151:     PetscDrawPause(draw);
152:   }
153:   return 0;
154: }

156: PetscErrorCode RGIsTrivial_Interval(RG rg,PetscBool *trivial)
157: {
158:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;

160:   if (rg->complement) *trivial = (ctx->a==ctx->b && ctx->c==ctx->d)? PETSC_TRUE: PETSC_FALSE;
161:   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;
162:   return 0;
163: }

165: PetscErrorCode RGComputeContour_Interval(RG rg,PetscInt n,PetscScalar *cr,PetscScalar *ci)
166: {
167:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
168:   PetscInt    i,N,Nv,Nh,k1,k0;
169:   PetscReal   hv,hh,t;

172:   if (ctx->a==ctx->b || ctx->c==ctx->d) {
173:     if (ctx->a==ctx->b) {hv = (ctx->d-ctx->c)/(n-1); hh = 0.0;}
174:     else {hh = (ctx->b-ctx->a)/(n-1); hv = 0.0;}
175:     for (i=0;i<n;i++) {
176: #if defined(PETSC_USE_COMPLEX)
177:       cr[i] = PetscCMPLX(ctx->a+hh*i,ctx->c+hv*i);
178: #else
179:       if (cr) cr[i] = ctx->a+hh*i;
180:       if (ci) ci[i] = ctx->c+hv*i;
181: #endif
182:     }
183:   } else {
185:     N = n/2;
186:     t = ((ctx->d-ctx->c)/(ctx->d-ctx->c+ctx->b-ctx->a))*N;
187:     Nv = t-PetscFloorReal(t)>0.5?PetscCeilReal(t):PetscFloorReal(t);
188:     if (Nv==0) Nv++;
189:     else if (Nv==N) Nv--;
190:     Nh = N-Nv;
191:     hh = (ctx->b-ctx->a)/Nh;
192:     hv = (ctx->d-ctx->c)/Nv;
193:     /* positive imaginary part first */
194:     k1 = Nv/2+1;
195:     k0 = Nv-k1;

197:     for (i=k1;i<Nv;i++) {
198: #if defined(PETSC_USE_COMPLEX)
199:       cr[i-k1]   = PetscCMPLX(ctx->b,ctx->c+i*hv);
200:       cr[i-k1+N] = PetscCMPLX(ctx->a,ctx->d-i*hv);
201: #else
202:       if (cr) {cr[i-k1] = ctx->b;      cr[i-k1+N] = ctx->a;}
203:       if (ci) {ci[i-k1] = ctx->c+i*hv; ci[i-k1+N] = ctx->d-i*hv;}
204: #endif
205:     }
206:     for (i=0;i<Nh;i++) {
207: #if defined(PETSC_USE_COMPLEX)
208:       cr[i+k0]   = PetscCMPLX(ctx->b-i*hh,ctx->d);
209:       cr[i+k0+N] = PetscCMPLX(ctx->a+i*hh,ctx->c);
210: #else
211:       if (cr) {cr[i+k0] = ctx->b-i*hh; cr[i+k0+N] = ctx->a+i*hh;}
212:       if (ci) {ci[i+k0] = ctx->d;      ci[i+k0+N] = ctx->c;}
213: #endif
214:     }
215:     for (i=0;i<k1;i++) {
216: #if defined(PETSC_USE_COMPLEX)
217:       cr[i+k0+Nh]   = PetscCMPLX(ctx->a,ctx->d-i*hv);
218:       cr[i+k0+Nh+N] = PetscCMPLX(ctx->b,ctx->c+i*hv);
219: #else
220:       if (cr) {cr[i+k0+Nh] = ctx->a; cr[i+k0+Nh+N] = ctx->b;}
221:       if (ci) {ci[i+k0+Nh] = ctx->d+i*hv; ci[i+k0+Nh+N] = ctx->c-i*hv;}
222: #endif
223:     }
224:   }
225:   return 0;
226: }

228: PetscErrorCode RGComputeBoundingBox_Interval(RG rg,PetscReal *a,PetscReal *b,PetscReal *c,PetscReal *d)
229: {
230:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;

232:   if (a) *a = ctx->a;
233:   if (b) *b = ctx->b;
234:   if (c) *c = ctx->c;
235:   if (d) *d = ctx->d;
236:   return 0;
237: }

239: PetscErrorCode RGComputeQuadrature_Interval(RG rg,RGQuadRule quad,PetscInt n,PetscScalar *z,PetscScalar *zn,PetscScalar *w)
240: {
241:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;
242:   PetscReal   theta,max_w=0.0,radius=1.0;
243:   PetscScalar tmp,tmp2,center=0.0;
244:   PetscInt    i,j;

246:   if (quad == RG_QUADRULE_CHEBYSHEV) {
248:     for (i=0;i<n;i++) {
249:       theta = PETSC_PI*(i+0.5)/n;
250:       zn[i] = PetscCosReal(theta);
251:       w[i]  = PetscCosReal((n-1)*theta)/n;
252:       if (ctx->c==ctx->d) z[i] = ((ctx->b-ctx->a)*(zn[i]+1.0)/2.0+ctx->a)*rg->sfactor;
253:       else if (ctx->a==ctx->b) {
254: #if defined(PETSC_USE_COMPLEX)
255:         z[i] = ((ctx->d-ctx->c)*(zn[i]+1.0)/2.0+ctx->c)*rg->sfactor*PETSC_i;
256: #else
257:         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Integration points on a vertical line require complex arithmetic");
258: #endif
259:       }
260:     }
261:   } else {  /* RG_QUADRULE_TRAPEZOIDAL */
262: #if defined(PETSC_USE_COMPLEX)
263:     center = rg->sfactor*PetscCMPLX(ctx->b+ctx->a,ctx->d+ctx->c)/2.0;
264: #else
265:     center = rg->sfactor*(ctx->b+ctx->a)/2.0;
266: #endif
267:     radius = PetscSqrtReal(PetscPowRealInt(rg->sfactor*(ctx->b-ctx->a)/2.0,2)+PetscPowRealInt(rg->sfactor*(ctx->d-ctx->c)/2.0,2));
268:     for (i=0;i<n;i++) {
269:       zn[i] = (z[i]-center)/radius;
270:       tmp = 1.0; tmp2 = 1.0;
271:       for (j=0;j<n;j++) {
272:         tmp *= z[j];
273:         if (i != j) tmp2 *= z[j]-z[i];
274:       }
275:       w[i] = tmp/tmp2;
276:       max_w = PetscMax(PetscAbsScalar(w[i]),max_w);
277:     }
278:     for (i=0;i<n;i++) w[i] /= (PetscScalar)max_w;
279:   }
280:   return 0;
281: }

283: PetscErrorCode RGCheckInside_Interval(RG rg,PetscReal dx,PetscReal dy,PetscInt *inside)
284: {
285:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;

287:   if (dx>ctx->a && dx<ctx->b) *inside = 1;
288:   else if (dx==ctx->a || dx==ctx->b) *inside = 0;
289:   else *inside = -1;
290:   if (*inside>=0) {
291:     if (dy>ctx->c && dy<ctx->d) ;
292:     else if (dy==ctx->c || dy==ctx->d) *inside = 0;
293:     else *inside = -1;
294:   }
295:   return 0;
296: }

298: PetscErrorCode RGIsAxisymmetric_Interval(RG rg,PetscBool vertical,PetscBool *symm)
299: {
300:   RG_INTERVAL *ctx = (RG_INTERVAL*)rg->data;

302:   if (vertical) *symm = (ctx->a == -ctx->b)? PETSC_TRUE: PETSC_FALSE;
303:   else *symm = (ctx->c == -ctx->d)? PETSC_TRUE: PETSC_FALSE;
304:   return 0;
305: }

307: PetscErrorCode RGSetFromOptions_Interval(RG rg,PetscOptionItems *PetscOptionsObject)
308: {
309:   PetscBool      flg;
310:   PetscInt       k;
311:   PetscReal      array[4]={0,0,0,0};

313:   PetscOptionsHeadBegin(PetscOptionsObject,"RG Interval Options");

315:     k = 4;
316:     PetscOptionsRealArray("-rg_interval_endpoints","Interval endpoints (two or four real values separated with a comma without spaces)","RGIntervalSetEndpoints",array,&k,&flg);
317:     if (flg) {
319:       RGIntervalSetEndpoints(rg,array[0],array[1],array[2],array[3]);
320:     }

322:   PetscOptionsHeadEnd();
323:   return 0;
324: }

326: PetscErrorCode RGDestroy_Interval(RG rg)
327: {
328:   PetscFree(rg->data);
329:   PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",NULL);
330:   PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",NULL);
331:   return 0;
332: }

334: SLEPC_EXTERN PetscErrorCode RGCreate_Interval(RG rg)
335: {
336:   RG_INTERVAL    *interval;

338:   PetscNew(&interval);
339:   interval->a = -PETSC_MAX_REAL;
340:   interval->b = PETSC_MAX_REAL;
341:   interval->c = -PETSC_MAX_REAL;
342:   interval->d = PETSC_MAX_REAL;
343:   rg->data = (void*)interval;

345:   rg->ops->istrivial         = RGIsTrivial_Interval;
346:   rg->ops->computecontour    = RGComputeContour_Interval;
347:   rg->ops->computebbox       = RGComputeBoundingBox_Interval;
348:   rg->ops->computequadrature = RGComputeQuadrature_Interval;
349:   rg->ops->checkinside       = RGCheckInside_Interval;
350:   rg->ops->isaxisymmetric    = RGIsAxisymmetric_Interval;
351:   rg->ops->setfromoptions    = RGSetFromOptions_Interval;
352:   rg->ops->view              = RGView_Interval;
353:   rg->ops->destroy           = RGDestroy_Interval;
354:   PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",RGIntervalSetEndpoints_Interval);
355:   PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",RGIntervalGetEndpoints_Interval);
356:   return 0;
357: }