Skip to content

Commit 69f2392

Browse files
committed
Public API cleanup: umbrella module re-exports and missing methods
Re-export constants, error flags, fitting flags, and utility functions from the fitpack umbrella module so users need only `use fitpack`. Add missing methods across types: - eval/eval_ongrid on fitpack_surface (scattered via bispeu, grid via bispev) - interpolate/least_squares on fitpack_surface - least_squares on fitpack_curve - mse on all 6 surface/polar/sphere types
1 parent 64db2bd commit 69f2392

11 files changed

+291
-5
lines changed

.claude/settings.local.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
"Bash(git add:*)",
88
"Bash(git commit:*)",
99
"Bash(git checkout:*)",
10-
"Bash(git push:*)"
10+
"Bash(git push:*)",
11+
"Bash(grep:*)",
12+
"Bash(fpm build:*)",
13+
"Bash(git status:*)"
1114
],
1215
"deny": [],
1316
"ask": []

src/fitpack.f90

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ module fitpack
3232
implicit none
3333
private
3434

35-
! Public interface
35+
! Public interface: kind parameters
3636
public :: FP_REAL
3737
public :: FP_SIZE
3838
public :: FP_FLAG
3939
public :: FP_BOOL
4040

41+
! Public interface: types
4142
public :: fitpack_curve
4243
public :: fitpack_closed_curve
4344
public :: fitpack_periodic_curve
@@ -54,5 +55,24 @@ module fitpack
5455
public :: fitpack_grid_surface
5556
public :: fitpack_parametric_surface
5657

58+
! Public interface: boundary behavior flags
59+
public :: OUTSIDE_EXTRAPOLATE, OUTSIDE_ZERO, OUTSIDE_NOT_ALLOWED, OUTSIDE_NEAREST_BND
60+
61+
! Public interface: fitting state flags
62+
public :: IOPT_NEW_LEASTSQUARES, IOPT_NEW_SMOOTHING, IOPT_OLD_FIT
63+
64+
! Public interface: error flags
65+
public :: FITPACK_OK, FITPACK_INTERPOLATING_OK, FITPACK_LEASTSQUARES_OK
66+
public :: FITPACK_INSUFFICIENT_STORAGE, FITPACK_S_TOO_SMALL, FITPACK_MAXIT
67+
public :: FITPACK_TOO_MANY_KNOTS, FITPACK_OVERLAPPING_KNOTS, FITPACK_INVALID_RANGE
68+
public :: FITPACK_INPUT_ERROR, FITPACK_TEST_ERROR
69+
public :: FITPACK_INVALID_CONSTRAINT, FITPACK_INSUFFICIENT_KNOTS
70+
71+
! Public interface: error utility functions
72+
public :: FITPACK_SUCCESS, FITPACK_MESSAGE, IOPT_MESSAGE
73+
74+
! Public interface: named constants
75+
public :: zero, one, half, pi
76+
5777

5878
end module fitpack

src/fitpack_curves.f90

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,9 @@ module fitpack_curves
8181
procedure :: new_fit
8282

8383
!> Generate/update fitting curve, with optional smoothing
84-
procedure :: fit => curve_fit_automatic_knots
85-
procedure :: interpolate => interpolating_curve
84+
procedure :: fit => curve_fit_automatic_knots
85+
procedure :: interpolate => interpolating_curve
86+
procedure :: least_squares => curve_fit_least_squares
8687

8788
!> Evaluate curve at given coordinates
8889
procedure, private :: curve_eval_one
@@ -363,6 +364,13 @@ integer(FP_FLAG) function interpolating_curve(this,order) result(ierr)
363364

364365
end function interpolating_curve
365366

367+
! Least-squares curve fit with current knots
368+
integer(FP_FLAG) function curve_fit_least_squares(this) result(ierr)
369+
class(fitpack_curve), intent(inout) :: this
370+
this%iopt = IOPT_NEW_LEASTSQUARES
371+
ierr = this%fit()
372+
end function curve_fit_least_squares
373+
366374
! Curve fitting driver: automatic number of knots
367375
integer(FP_FLAG) function curve_fit_automatic_knots(this,smoothing,order) result(ierr)
368376
class(fitpack_curve), intent(inout) :: this

src/fitpack_grid_surfaces.f90

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ module fitpack_grid_surfaces
9292
generic :: dfdx => gridded_derivatives_one,gridded_derivatives_many
9393
generic :: dfdx_ongrid => gridded_derivatives_gridded
9494

95+
!> Properties: MSE
96+
procedure, non_overridable :: mse => gridsurf_error
97+
9598
end type fitpack_grid_surface
9699

97100
interface fitpack_grid_surface
@@ -458,4 +461,10 @@ real(FP_REAL) function gridded_derivatives_one(this,x,y,dx,dy,ierr) result(f)
458461

459462
end function gridded_derivatives_one
460463

464+
! Return fitting MSE
465+
elemental real(FP_REAL) function gridsurf_error(this)
466+
class(fitpack_grid_surface), intent(in) :: this
467+
gridsurf_error = this%fp
468+
end function gridsurf_error
469+
461470
end module fitpack_grid_surfaces

src/fitpack_gridded_polar.f90

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ module fitpack_gridded_polar
102102
procedure, private :: gridded_eval_many
103103
generic :: eval => gridded_eval_one,gridded_eval_many
104104

105+
!> Properties: MSE
106+
procedure, non_overridable :: mse => gridpolar_error
107+
105108
!> Write to disk
106109
procedure :: write => gridded_to_disk
107110

@@ -389,4 +392,10 @@ end function numbered
389392

390393
end subroutine gridded_to_disk
391394

395+
! Return fitting MSE
396+
elemental real(FP_REAL) function gridpolar_error(this)
397+
class(fitpack_grid_polar), intent(in) :: this
398+
gridpolar_error = this%fp
399+
end function gridpolar_error
400+
392401
end module fitpack_gridded_polar

src/fitpack_gridded_sphere.f90

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ module fitpack_gridded_sphere
9595
procedure, private :: gridded_eval_many
9696
generic :: eval => gridded_eval_one,gridded_eval_many
9797

98+
!> Properties: MSE
99+
procedure, non_overridable :: mse => gridsphere_error
100+
98101
!> Write to disk
99102
procedure :: write => gridded_to_disk
100103

@@ -396,4 +399,10 @@ end function numbered
396399

397400
end subroutine gridded_to_disk
398401

402+
! Return fitting MSE
403+
elemental real(FP_REAL) function gridsphere_error(this)
404+
class(fitpack_grid_sphere), intent(in) :: this
405+
gridsphere_error = this%fp
406+
end function gridsphere_error
407+
399408
end module fitpack_gridded_sphere

src/fitpack_polar.f90

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@ module fitpack_polar_domains
103103
procedure, private :: polr_eval_many
104104
generic :: eval => polr_eval_one,polr_eval_many
105105

106+
!> Properties: MSE
107+
procedure, non_overridable :: mse => polar_error
108+
106109
end type fitpack_polar
107110

108111
interface fitpack_polar
@@ -342,4 +345,10 @@ integer function polr_new_fit(this,x,y,z,boundary,w,boundary_bc,smoothing)
342345

343346
end function polr_new_fit
344347

348+
! Return fitting MSE
349+
elemental real(FP_REAL) function polar_error(this)
350+
class(fitpack_polar), intent(in) :: this
351+
polar_error = this%fp
352+
end function polar_error
353+
345354
end module fitpack_polar_domains

src/fitpack_spheres.f90

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ module fitpack_sphere_domains
8484
procedure, private :: sphere_eval_many
8585
generic :: eval => sphere_eval_one,sphere_eval_many
8686

87+
!> Properties: MSE
88+
procedure, non_overridable :: mse => sphere_error
89+
8790
end type fitpack_sphere
8891

8992
interface fitpack_sphere
@@ -302,4 +305,10 @@ integer function sphere_new_fit(this,theta,phi,r,w,smoothing)
302305

303306
end function sphere_new_fit
304307

308+
! Return fitting MSE
309+
elemental real(FP_REAL) function sphere_error(this)
310+
class(fitpack_sphere), intent(in) :: this
311+
sphere_error = this%fp
312+
end function sphere_error
313+
305314
end module fitpack_sphere_domains

src/fitpack_surfaces.f90

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,18 @@ module fitpack_surfaces
7878
procedure :: new_fit => surf_new_fit
7979

8080
!> Generate/update fitting curve, with optional smoothing
81-
procedure :: fit => surface_fit_automatic_knots
81+
procedure :: fit => surface_fit_automatic_knots
82+
procedure :: interpolate => surface_fit_interpolating
83+
procedure :: least_squares => surface_fit_least_squares
84+
85+
!> Evaluate surface at given coordinates
86+
procedure, private :: surface_eval_one
87+
procedure, private :: surface_eval_many
88+
generic :: eval => surface_eval_one,surface_eval_many
89+
90+
!> Evaluate surface on a grid
91+
procedure, private :: surface_eval_gridded
92+
generic :: eval_ongrid => surface_eval_gridded
8293

8394
!> Evaluate derivatives at given coordinates
8495
procedure, private :: surface_derivatives_gridded
@@ -87,6 +98,9 @@ module fitpack_surfaces
8798
generic :: dfdx => surface_derivatives_one,surface_derivatives_many
8899
generic :: dfdx_ongrid => surface_derivatives_gridded
89100

101+
!> Properties: MSE
102+
procedure, non_overridable :: mse => surface_error
103+
90104
end type fitpack_surface
91105

92106
interface fitpack_surface
@@ -144,6 +158,104 @@ integer(FP_FLAG) function surface_fit_automatic_knots(this,smoothing,order) resu
144158
end function surface_fit_automatic_knots
145159

146160

161+
! Find interpolating surface
162+
integer(FP_FLAG) function surface_fit_interpolating(this) result(ierr)
163+
class(fitpack_surface), intent(inout) :: this
164+
ierr = surface_fit_automatic_knots(this,smoothing=zero)
165+
end function surface_fit_interpolating
166+
167+
! Fit a surface to least squares of the current knots
168+
integer(FP_FLAG) function surface_fit_least_squares(this) result(ierr)
169+
class(fitpack_surface), intent(inout) :: this
170+
this%iopt = IOPT_NEW_LEASTSQUARES
171+
ierr = this%fit()
172+
end function surface_fit_least_squares
173+
174+
!> Evaluate surface on a list of (x(i),y(i)) scattered points using bispeu
175+
function surface_eval_many(this,x,y,ierr) result(f)
176+
class(fitpack_surface), intent(inout) :: this
177+
real(FP_REAL), intent(in) :: x(:),y(size(x))
178+
real(FP_REAL) :: f(size(x))
179+
integer(FP_FLAG), optional, intent(out) :: ierr
180+
181+
integer(FP_FLAG) :: ier
182+
integer(FP_SIZE) :: min_lwrk
183+
real(FP_REAL), allocatable :: wrk(:)
184+
185+
! bispeu workspace: lwrk >= kx+ky+2
186+
min_lwrk = sum(this%order) + 2
187+
allocate(wrk(min_lwrk))
188+
189+
call bispeu(tx=this%t(:,1),nx=this%knots(1), &
190+
ty=this%t(:,2),ny=this%knots(2), &
191+
c=this%c, &
192+
kx=this%order(1),ky=this%order(2), &
193+
x=x,y=y,z=f,m=size(x), &
194+
wrk=wrk,lwrk=min_lwrk, &
195+
ier=ier)
196+
197+
call fitpack_error_handling(ier,ierr,'evaluate bivariate surface')
198+
199+
end function surface_eval_many
200+
201+
!> Evaluate surface at a single (x,y) point
202+
real(FP_REAL) function surface_eval_one(this,x,y,ierr) result(f)
203+
class(fitpack_surface), intent(inout) :: this
204+
real(FP_REAL), intent(in) :: x,y
205+
integer(FP_FLAG), optional, intent(out) :: ierr
206+
207+
real(FP_REAL) :: z1(1)
208+
209+
z1 = surface_eval_many(this,[x],[y],ierr)
210+
f = z1(1)
211+
212+
end function surface_eval_one
213+
214+
!> Evaluate surface on a grid domain using bispev
215+
function surface_eval_gridded(this,x,y,ierr) result(f)
216+
class(fitpack_surface), intent(inout) :: this
217+
real(FP_REAL), intent(in) :: x(:),y(:)
218+
real(FP_REAL) :: f(size(y),size(x))
219+
integer(FP_FLAG), optional, intent(out) :: ierr
220+
221+
integer(FP_FLAG) :: ier
222+
integer(FP_SIZE) :: min_lwrk,min_kwrk,m(2)
223+
real(FP_REAL), allocatable :: min_wrk(:)
224+
integer(FP_SIZE), allocatable :: min_iwrk(:)
225+
226+
m = [size(x),size(y)]
227+
228+
! Assert real working storage
229+
min_lwrk = sum(m*(this%order+1)) + product(this%knots-this%order-1)
230+
if (min_lwrk>this%lwrk1) then
231+
allocate(min_wrk(min_lwrk),source=0.0_FP_REAL)
232+
call move_alloc(from=min_wrk,to=this%wrk1)
233+
this%lwrk1 = min_lwrk
234+
end if
235+
236+
! Assert integer working storage
237+
min_kwrk = sum(m)
238+
if (min_kwrk>this%liwrk) then
239+
allocate(min_iwrk(min_kwrk),source=0_FP_SIZE)
240+
call move_alloc(from=min_iwrk,to=this%iwrk)
241+
this%liwrk = min_kwrk
242+
end if
243+
244+
call bispev(tx=this%t(:,1),nx=this%knots(1), &
245+
ty=this%t(:,2),ny=this%knots(2), &
246+
c=this%c, &
247+
kx=this%order(1),ky=this%order(2), &
248+
x=x,mx=size(x), &
249+
y=y,my=size(y), &
250+
z=f, &
251+
wrk=this%wrk1,lwrk=this%lwrk1, &
252+
iwrk=this%iwrk,kwrk=this%liwrk, &
253+
ier=ier)
254+
255+
call fitpack_error_handling(ier,ierr,'evaluate gridded surface')
256+
257+
end function surface_eval_gridded
258+
147259
elemental subroutine surf_destroy(this)
148260
class(fitpack_surface), intent(inout) :: this
149261
integer :: ierr
@@ -424,4 +536,10 @@ real(FP_REAL) function surface_derivatives_one(this,x,y,dx,dy,ierr) result(f)
424536
end function surface_derivatives_one
425537

426538

539+
! Return fitting MSE
540+
elemental real(FP_REAL) function surface_error(this)
541+
class(fitpack_surface), intent(in) :: this
542+
surface_error = this%fp
543+
end function surface_error
544+
427545
end module fitpack_surfaces

0 commit comments

Comments
 (0)