!> !> @file l2appr.f90 !> !> @brief !> !> @copyright !> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) !> SPC (Swiss Plasma Center) !> !> SPClibs is free software: you can redistribute it and/or modify it under !> the terms of the GNU Lesser General Public License as published by the Free !> Software Foundation, either version 3 of the License, or (at your option) !> any later version. !> !> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY !> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS !> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. !> !> You should have received a copy of the GNU Lesser General Public License !> along with this program. If not, see . !> !> @author !> (in alphabetical order) !> @author Trach-Minh Tran !> subroutine l2appr ( t, n, k, q, diag, bcoef ) !************************************************************************* ! !! L2APPR constructs a weighted L2 spline approximation to given data. ! ! Discussion: ! ! The routine constructs the weighted discrete L2-approximation by ! splines of order K with knot sequence T(1), ..., T(n+k) to ! given data points ( TAU(1:NTAU), GTAU(1:NTAU) ). ! ! The B-spline coefficients BCOEF of the approximating spline are ! determined from the normal equations using Cholesky's method. ! ! Method: ! ! The B-spline coefficients of the L2-approximation are determined as the ! solution of the normal equations ! ! sum ( (b(i), b(j) ) * bcoef(j) : j=1,...,n) =(b(i),g), ! i=1, ..., n . ! Here, b(i) denotes the i-th B-spline, G denotes the function to ! be approximated, and the inner product of two functions F and G ! is given by ! ! (f,g) := sum ( f(tau(i))*g(tau(i))*weight(i) : i=1,...,ntau) . ! ! The arrays TAU and WEIGHT are given in common block ! DATA, as is the array GTAU containing the sequence ! g(tau(i)), i=1,..., NTAU. ! ! The relevant function values of the B-splines b(i), i=1,...,n, are ! supplied by the subprogram BSPLVB. ! ! The coefficient matrix C, with ! c(i,j) := (b(i), b(j)), i,j=1,...,n, ! of the normal equations is symmetric and (2*k-1)-banded, therefore ! can be specified by giving its K bands at or below the diagonal. ! For i=1,...,n, we store ! (b(i),b(j)) = c(i,j) in q(i-j+1,j), j=i,...,min(i+k-1,n) ! and the right side ! (b(i), g ) in bcoef(i). ! ! Since B-spline values are most efficiently generated by finding sim- ! ultaneously the value of every nonzero B-spline at one point, ! the entries of C (i.e., of Q ), are generated by computing, for ! each ll, all the terms involving tau(ll) simultaneously and adding ! them to all relevant entries. ! ! Reference: ! ! Carl DeBoor, ! A Practical Guide to Splines, ! Springer Verlag. ! ! Parameters: ! ! Input, real ( kind = 8 ) T(N+K), the knot sequence. ! ! Input, integer N, the dimension of the space of splines of order K ! with knots t. ! ! Input, integer K, the order. ! ! work arrays ! ! q....a work array of size (at least) k*n. its first k rows are used ! for the k lower diagonals of the gramian matrix c. ! ! diag.....a work array of length n used in bchfac . ! ! input via c o m m o n /data/ ! ! ntau.....number of data points ! (tau(i),gtau(i)), i=1,...,ntau are the ntau data points to be ! fitted . ! weight(i), i=1,...,ntau are the corresponding weights . ! ! output ! bcoef(1), ..., bcoef(n) the b-spline coefficients of the l2-appr. ! implicit none integer k integer n integer, parameter :: ntmax = 200 real ( kind = 8 ) bcoef(n) real ( kind = 8 ) biatx(k) real ( kind = 8 ) diag(n) real ( kind = 8 ) dw real ( kind = 8 ) gtau integer i integer j integer jj integer left integer leftmk integer ll integer mm integer ntau real ( kind = 8 ) q(k,n) real ( kind = 8 ) t(n+k) real ( kind = 8 ) tau real ( kind = 8 ) totalw real ( kind = 8 ) weight COMMON /DATA/ tau(ntmax),gtau(ntmax),weight(ntmax),totalw,ntau bcoef(1:n) = 0.0D+00 q(1:k,1:n) = 0.0D+00 left = k leftmk = 0 do ll = 1, ntau ! ! Locate LEFT such that tau(ll) in (t(left),t(left+1)). ! do if ( left == n ) then exit end if if ( tau(ll) < t(left+1) ) then exit end if left = left + 1 leftmk = leftmk + 1 end do call bsplvb ( t, k, 1, tau(ll), left, biatx ) ! ! biatx(mm) contains the value of b(left-k+mm) at tau(ll). ! hence, with dw := biatx(mm)*weight(ll), the number dw*gtau(ll) ! is a summand in the inner product ! (b(left-k+mm), g) which goes into bcoef(left-k+mm) ! and the number biatx(jj)*dw is a summand in the inner product ! (b(left-k+jj), b(left-k+mm)), into q(jj-mm+1,left-k+mm) ! since (left-k+jj)-(left-k+mm)+1 = jj - mm + 1 . ! do mm = 1, k dw = biatx(mm)*weight(ll) j = leftmk+mm bcoef(j) = dw*gtau(ll)+bcoef(j) i = 1 do jj = mm, k q(i,j) = biatx(jj)*dw+q(i,j) i = i+1 end do end do end do ! ! Construct the Cholesky factorization for C in q , then ! use it to solve the normal equations ! c*x = bcoef ! for X, and store X in BCOEF. ! call bchfac ( q, k, n, diag ) call bchslv ( q, k, n, bcoef ) return end