@@ -21,8 +21,10 @@ module fitpack_grid_surfaces
2121 use fitpack_core, only: FITPACK_SUCCESS,FP_REAL,FP_SIZE,FP_FLAG,FP_COMM,zero,IOPT_NEW_SMOOTHING,IOPT_OLD_FIT, &
2222 IOPT_NEW_LEASTSQUARES,bispev,fitpack_error_handling,get_smoothing,regrid, &
2323 parder,pardeu,FITPACK_INPUT_ERROR, &
24+ dblint,profil,pardtc, &
2425 FP_COMM_SIZE,FP_COMM_PACK,FP_COMM_EXPAND
2526 use fitpack_fitters
27+ use fitpack_curves, only: fitpack_curve
2628 implicit none
2729 private
2830
@@ -80,6 +82,15 @@ module fitpack_grid_surfaces
8082 generic :: dfdx = > gridded_derivatives_one,gridded_derivatives_many
8183 generic :: dfdx_ongrid = > gridded_derivatives_gridded
8284
85+ ! > Double integration over a rectangular domain
86+ procedure :: integral = > gridsurf_integral
87+
88+ ! > Extract a 1D cross-section curve from the surface
89+ procedure :: cross_section = > gridsurf_cross_section
90+
91+ ! > Compute the derivative spline coefficients
92+ procedure :: derivative_spline = > gridsurf_derivative_spline
93+
8394 ! > Parallel communication
8495 procedure :: comm_size = > gridsurf_comm_size
8596 procedure :: comm_pack = > gridsurf_comm_pack
@@ -464,6 +475,126 @@ real(FP_REAL) function gridded_derivatives_one(this,x,y,dx,dy,ierr) result(f)
464475
465476 end function gridded_derivatives_one
466477
478+ ! > Double integration of the surface over a rectangular domain [lower(1),upper(1)] x [lower(2),upper(2)]
479+ real (FP_REAL) function gridsurf_integral(this, lower, upper)
480+ class(fitpack_grid_surface), intent (in ) :: this
481+ real (FP_REAL), intent (in ) :: lower(2 ), upper(2 )
482+
483+ real (FP_REAL) :: wrk(this% knots(1 )+ this% knots(2 )- this% order(1 )- this% order(2 )- 2 )
484+
485+ gridsurf_integral = dblint(this% t(:,1 ), this% knots(1 ), &
486+ this% t(:,2 ), this% knots(2 ), &
487+ this% c, &
488+ this% order(1 ), this% order(2 ), &
489+ lower(1 ), upper(1 ), lower(2 ), upper(2 ), wrk)
490+
491+ end function gridsurf_integral
492+
493+ ! > Extract a 1D cross-section from the surface.
494+ ! > If along_y=.true., returns f(y) = s(u,y); if along_y=.false., returns g(x) = s(x,u).
495+ function gridsurf_cross_section (this , u , along_y , ierr ) result(curve)
496+ class(fitpack_grid_surface), intent (in ) :: this
497+ real (FP_REAL), intent (in ) :: u
498+ logical , intent (in ) :: along_y
499+ integer (FP_FLAG), optional , intent (out ) :: ierr
500+ type (fitpack_curve) :: curve
501+
502+ integer (FP_FLAG) :: ier
503+ integer (FP_SIZE) :: iopt, nu, nc
504+ real (FP_REAL), allocatable :: cu(:)
505+
506+ if (along_y) then
507+ iopt = 0
508+ nu = this% knots(2 )
509+ nc = this% knots(2 ) - this% order(2 ) - 1
510+ else
511+ iopt = 1
512+ nu = this% knots(1 )
513+ nc = this% knots(1 ) - this% order(1 ) - 1
514+ end if
515+
516+ allocate (cu(nu))
517+
518+ call profil(iopt, this% t(:,1 ), this% knots(1 ), &
519+ this% t(:,2 ), this% knots(2 ), &
520+ this% c, &
521+ this% order(1 ), this% order(2 ), &
522+ u, nu, cu, ier)
523+
524+ if (FITPACK_SUCCESS(ier)) then
525+ curve% order = merge (this% order(2 ), this% order(1 ), along_y)
526+ curve% knots = nu
527+ curve% nest = nu
528+ if (along_y) then
529+ allocate (curve% t(nu), source= this% t(1 :nu, 2 ))
530+ else
531+ allocate (curve% t(nu), source= this% t(1 :nu, 1 ))
532+ end if
533+ allocate (curve% c(nu), source= zero)
534+ curve% c(:nc) = cu(:nc)
535+ curve% xleft = curve% t(curve% order + 1 )
536+ curve% xright = curve% t(curve% knots - curve% order)
537+ end if
538+
539+ call fitpack_error_handling(ier, ierr, ' grid surface cross-section' )
540+
541+ end function gridsurf_cross_section
542+
543+ ! > Compute the derivative spline d^(nux+nuy)s / dx^nux dy^nuy.
544+ ! > Returns a new grid surface with reduced order and trimmed knots.
545+ function gridsurf_derivative_spline (this , nux , nuy , ierr ) result(dsurf)
546+ class(fitpack_grid_surface), intent (in ) :: this
547+ integer (FP_SIZE), intent (in ) :: nux, nuy
548+ integer (FP_FLAG), optional , intent (out ) :: ierr
549+ type (fitpack_grid_surface) :: dsurf
550+
551+ integer (FP_FLAG) :: ier
552+ integer (FP_SIZE) :: nx, ny, newkx, newky, newnx, newny, nc_old, nc_new
553+ real (FP_REAL), allocatable :: newc(:)
554+
555+ nx = this% knots(1 )
556+ ny = this% knots(2 )
557+ nc_old = (nx - this% order(1 ) - 1 ) * (ny - this% order(2 ) - 1 )
558+
559+ allocate (newc(nc_old))
560+
561+ call pardtc(this% t(:,1 ), nx, this% t(:,2 ), ny, &
562+ this% c, this% order(1 ), this% order(2 ), &
563+ nux, nuy, newc, ier)
564+
565+ if (FITPACK_SUCCESS(ier)) then
566+ newkx = this% order(1 ) - nux
567+ newky = this% order(2 ) - nuy
568+ newnx = nx - 2 * nux
569+ newny = ny - 2 * nuy
570+ nc_new = (newnx - newkx - 1 ) * (newny - newky - 1 )
571+
572+ dsurf% order = [newkx, newky]
573+ dsurf% knots = [newnx, newny]
574+ dsurf% nmax = max (newnx, newny)
575+ dsurf% nest = dsurf% nmax
576+
577+ allocate (dsurf% t(dsurf% nmax, 2 ), source= zero)
578+ dsurf% t(1 :newnx, 1 ) = this% t(1 + nux:nx- nux, 1 )
579+ dsurf% t(1 :newny, 2 ) = this% t(1 + nuy:ny- nuy, 2 )
580+
581+ allocate (dsurf% c(nc_new), source= newc(1 :nc_new))
582+
583+ dsurf% left = [dsurf% t(newkx+1 , 1 ), dsurf% t(newky+1 , 2 )]
584+ dsurf% right = [dsurf% t(newnx- newkx, 1 ), dsurf% t(newny- newky, 2 )]
585+
586+ ! Allocate evaluation workspace (bispev needs lwrk >= mx*(kx+1)+my*(ky+1), kwrk >= mx+my)
587+ dsurf% lwrk = newnx* (newkx+1 ) + newny* (newky+1 ) + nc_new
588+ dsurf% liwrk = newnx + newny
589+ allocate (dsurf% wrk(dsurf% lwrk), source= zero)
590+ allocate (dsurf% iwrk(dsurf% liwrk), source= 0_FP_SIZE )
591+ end if
592+
593+ call fitpack_error_handling(ier, ierr, ' grid surface derivative spline' )
594+
595+ end function gridsurf_derivative_spline
596+
597+
467598 ! =================================================================================================
468599 ! PARALLEL COMMUNICATION
469600 ! =================================================================================================
0 commit comments