Date: 2026-05-01T10:02:19+00:00

Actual source code: rginterval.c

      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 Key:
     56: .  -rg_interval_endpoints a,b,c,d - comma-separated list of values (two or four)

     58:    Note:
     59:    The region is defined as $[a,b]\times[c,d]$. Particular cases are an interval on
     60:    the real axis ($c=d=0$), similarly for the imaginary axis ($a=b=0$), the whole
     61:    complex plane ($a=-\infty,b=\infty,c=-\infty,d=\infty$), 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: [](sec:rg), `RGINTERVAL`, `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: [](sec:rg), `RGINTERVAL`, `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] = ((zn[i]+1.0)*(ctx->b-ctx->a)/2.0+ctx->a)*rg->sfactor;
    262:       else if (ctx->a==ctx->b) {
    263: #if defined(PETSC_USE_COMPLEX)
    264:         z[i] = ((zn[i]+1.0)*(ctx->d-ctx->c)/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 = PetscCMPLX(ctx->b+ctx->a,ctx->d+ctx->c)*rg->sfactor/2.0;
    273: #else
    274:     center = (ctx->b+ctx->a)*rg->sfactor/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: /*MC
    348:    RGINTERVAL - RGINTERVAL = "interval" - A region consisting of a (generalized)
    349:    interval, defined as $[a,b]\times[c,d]$, where the four parameters can be set with
    350:    `RGIntervalSetEndpoints()`.

    352:    Note:
    353:    The following figure shows an example of an interval region.

    355:    ![Interval region](../../_static/images/manual/svg/fig-rg-interval.svg)

    357:    Level: beginner

    359: .seealso: [](sec:rg), `RG`, `RGType`, `RGSetType()`, `RGIntervalSetEndpoints()`
    360: M*/

    362: SLEPC_EXTERN PetscErrorCode RGCreate_Interval(RG rg)
    363: {
    364:   RG_INTERVAL    *interval;

    366:   PetscFunctionBegin;
    367:   PetscCall(PetscNew(&interval));
    368:   interval->a = -PETSC_MAX_REAL;
    369:   interval->b = PETSC_MAX_REAL;
    370:   interval->c = -PETSC_MAX_REAL;
    371:   interval->d = PETSC_MAX_REAL;
    372:   rg->data = (void*)interval;

    374:   rg->ops->istrivial         = RGIsTrivial_Interval;
    375:   rg->ops->computecontour    = RGComputeContour_Interval;
    376:   rg->ops->computebbox       = RGComputeBoundingBox_Interval;
    377:   rg->ops->computequadrature = RGComputeQuadrature_Interval;
    378:   rg->ops->checkinside       = RGCheckInside_Interval;
    379:   rg->ops->isaxisymmetric    = RGIsAxisymmetric_Interval;
    380:   rg->ops->setfromoptions    = RGSetFromOptions_Interval;
    381:   rg->ops->view              = RGView_Interval;
    382:   rg->ops->destroy           = RGDestroy_Interval;
    383:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalSetEndpoints_C",RGIntervalSetEndpoints_Interval));
    384:   PetscCall(PetscObjectComposeFunction((PetscObject)rg,"RGIntervalGetEndpoints_C",RGIntervalGetEndpoints_Interval));
    385:   PetscFunctionReturn(PETSC_SUCCESS);
    386: }