test_nurbs_curve Program

Uses

  • program~~test_nurbs_curve~~UsesGraph program~test_nurbs_curve test_nurbs_curve forunittest forunittest program~test_nurbs_curve->forunittest module~forcad_kinds forcad_kinds program~test_nurbs_curve->module~forcad_kinds module~forcad_nurbs_curve forcad_nurbs_curve program~test_nurbs_curve->module~forcad_nurbs_curve module~forcad_nurbs_curve->module~forcad_kinds fordebug fordebug module~forcad_nurbs_curve->fordebug module~forcad_utils forcad_utils module~forcad_nurbs_curve->module~forcad_utils module~forcad_utils->module~forcad_kinds

Calls

program~~test_nurbs_curve~~CallsGraph program~test_nurbs_curve test_nurbs_curve check check program~test_nurbs_curve->check finalize finalize program~test_nurbs_curve->finalize initialize initialize program~test_nurbs_curve->initialize lsq_fit_bspline lsq_fit_bspline program~test_nurbs_curve->lsq_fit_bspline none~basis~3 nurbs_curve%basis program~test_nurbs_curve->none~basis~3 none~derivative2~3 nurbs_curve%derivative2 program~test_nurbs_curve->none~derivative2~3 none~derivative~3 nurbs_curve%derivative program~test_nurbs_curve->none~derivative~3 none~get_knot~3 nurbs_curve%get_knot program~test_nurbs_curve->none~get_knot~3 none~get_wc~3 nurbs_curve%get_Wc program~test_nurbs_curve->none~get_wc~3 none~get_xc~3 nurbs_curve%get_Xc program~test_nurbs_curve->none~get_xc~3 none~get_xg~3 nurbs_curve%get_Xg program~test_nurbs_curve->none~get_xg~3 none~set~3 nurbs_curve%set program~test_nurbs_curve->none~set~3 proc~cmp_elem_xc_vis~3 nurbs_curve%cmp_elem_Xc_vis program~test_nurbs_curve->proc~cmp_elem_xc_vis~3 proc~cmp_elem_xg_vis~3 nurbs_curve%cmp_elem_Xg_vis program~test_nurbs_curve->proc~cmp_elem_xg_vis~3 proc~cmp_elem~3 nurbs_curve%cmp_elem program~test_nurbs_curve->proc~cmp_elem~3 proc~cmp_length nurbs_curve%cmp_length program~test_nurbs_curve->proc~cmp_length proc~cmp_nc~3 nurbs_curve%cmp_nc program~test_nurbs_curve->proc~cmp_nc~3 proc~create~3 nurbs_curve%create program~test_nurbs_curve->proc~create~3 proc~elevate_degree~3 nurbs_curve%elevate_degree program~test_nurbs_curve->proc~elevate_degree~3 proc~export_iges~2 nurbs_curve%export_iges program~test_nurbs_curve->proc~export_iges~2 proc~export_xc~3 nurbs_curve%export_Xc program~test_nurbs_curve->proc~export_xc~3 proc~export_xg~3 nurbs_curve%export_Xg program~test_nurbs_curve->proc~export_xg~3 proc~export_xth~3 nurbs_curve%export_Xth program~test_nurbs_curve->proc~export_xth~3 proc~get_continuity~3 nurbs_curve%get_continuity program~test_nurbs_curve->proc~get_continuity~3 proc~get_degree nurbs_curve%get_degree program~test_nurbs_curve->proc~get_degree proc~get_elem_xc_vis~3 nurbs_curve%get_elem_Xc_vis program~test_nurbs_curve->proc~get_elem_xc_vis~3 proc~get_elem_xg_vis~3 nurbs_curve%get_elem_Xg_vis program~test_nurbs_curve->proc~get_elem_xg_vis~3 proc~get_elem~3 nurbs_curve%get_elem program~test_nurbs_curve->proc~get_elem~3 proc~get_multiplicity~3 nurbs_curve%get_multiplicity program~test_nurbs_curve->proc~get_multiplicity~3 proc~get_nc nurbs_curve%get_nc program~test_nurbs_curve->proc~get_nc proc~get_ng~3 nurbs_curve%get_ng program~test_nurbs_curve->proc~get_ng~3 proc~get_xt~3 nurbs_curve%get_Xt program~test_nurbs_curve->proc~get_xt~3 proc~insert_knots~3 nurbs_curve%insert_knots program~test_nurbs_curve->proc~insert_knots~3 proc~modify_wc~3 nurbs_curve%modify_Wc program~test_nurbs_curve->proc~modify_wc~3 proc~modify_xc~3 nurbs_curve%modify_Xc program~test_nurbs_curve->proc~modify_xc~3 proc~nearest_point2~3 nurbs_curve%nearest_point2 program~test_nurbs_curve->proc~nearest_point2~3 proc~nearest_point~3 nurbs_curve%nearest_point program~test_nurbs_curve->proc~nearest_point~3 proc~remove_knots~3 nurbs_curve%remove_knots program~test_nurbs_curve->proc~remove_knots~3 proc~rotate_xc~3 nurbs_curve%rotate_Xc program~test_nurbs_curve->proc~rotate_xc~3 proc~rotate_xg~3 nurbs_curve%rotate_Xg program~test_nurbs_curve->proc~rotate_xg~3 proc~set_circle nurbs_curve%set_circle program~test_nurbs_curve->proc~set_circle proc~set_elem_xc_vis~3 nurbs_curve%set_elem_Xc_vis program~test_nurbs_curve->proc~set_elem_xc_vis~3 proc~set_elem_xg_vis~3 nurbs_curve%set_elem_Xg_vis program~test_nurbs_curve->proc~set_elem_xg_vis~3 proc~set_elem~3 nurbs_curve%set_elem program~test_nurbs_curve->proc~set_elem~3 proc~set_half_circle nurbs_curve%set_half_circle program~test_nurbs_curve->proc~set_half_circle proc~translate_xc~3 nurbs_curve%translate_Xc program~test_nurbs_curve->proc~translate_xc~3 proc~translate_xg~3 nurbs_curve%translate_Xg program~test_nurbs_curve->proc~translate_xg~3 summary summary program~test_nurbs_curve->summary xdata xdata program~test_nurbs_curve->xdata xg_eval xg_eval program~test_nurbs_curve->xg_eval xt_fit xt_fit program~test_nurbs_curve->xt_fit proc~basis_scalar~3 nurbs_curve%basis_scalar none~basis~3->proc~basis_scalar~3 proc~basis_vector~3 nurbs_curve%basis_vector none~basis~3->proc~basis_vector~3 proc~derivative2_scalar~3 nurbs_curve%derivative2_scalar none~derivative2~3->proc~derivative2_scalar~3 proc~derivative2_vector~3 nurbs_curve%derivative2_vector none~derivative2~3->proc~derivative2_vector~3 proc~derivative_scalar~3 nurbs_curve%derivative_scalar none~derivative~3->proc~derivative_scalar~3 proc~derivative_vector~3 nurbs_curve%derivative_vector none~derivative~3->proc~derivative_vector~3 proc~get_knot_all~3 nurbs_curve%get_knot_all none~get_knot~3->proc~get_knot_all~3 proc~get_knoti~3 nurbs_curve%get_knoti none~get_knot~3->proc~get_knoti~3 proc~get_wc_all~3 nurbs_curve%get_Wc_all none~get_wc~3->proc~get_wc_all~3 proc~get_wci~3 nurbs_curve%get_Wci none~get_wc~3->proc~get_wci~3 proc~get_xc_all~3 nurbs_curve%get_Xc_all none~get_xc~3->proc~get_xc_all~3 proc~get_xcid~3 nurbs_curve%get_Xcid none~get_xc~3->proc~get_xcid~3 proc~get_xci~3 nurbs_curve%get_Xci none~get_xc~3->proc~get_xci~3 proc~get_xg_all~3 nurbs_curve%get_Xg_all none~get_xg~3->proc~get_xg_all~3 proc~get_xgid~3 nurbs_curve%get_Xgid none~get_xg~3->proc~get_xgid~3 proc~get_xgi~3 nurbs_curve%get_Xgi none~get_xg~3->proc~get_xgi~3 proc~set1a nurbs_curve%set1a none~set~3->proc~set1a proc~set1~3 nurbs_curve%set1 none~set~3->proc~set1~3 proc~set2~3 nurbs_curve%set2 none~set~3->proc~set2~3 proc~set3~3 nurbs_curve%set3 none~set~3->proc~set3~3 proc~set4~3 nurbs_curve%set4 none~set~3->proc~set4~3 interface~elemconn_c0 elemConn_C0 proc~cmp_elem_xc_vis~3->interface~elemconn_c0 proc~cmp_elem_xg_vis~3->interface~elemconn_c0 proc~cmp_elem~3->proc~get_multiplicity~3 interface~elemconn_cn elemConn_Cn proc~cmp_elem~3->interface~elemconn_cn interface~unique unique proc~cmp_elem~3->interface~unique proc~cmp_length->proc~cmp_elem~3 proc~ansatz~3 nurbs_curve%ansatz proc~cmp_length->proc~ansatz~3 interface~compute_multiplicity compute_multiplicity proc~cmp_nc~3->interface~compute_multiplicity interface~compute_xg~3 compute_Xg proc~create~3->interface~compute_xg~3 proc~is_rational~3 nurbs_curve%is_rational proc~create~3->proc~is_rational~3 set set proc~create~3->set proc~elevate_degree~3->none~set~3 proc~elevate_degree_a_5_9 elevate_degree_A_5_9 proc~elevate_degree~3->proc~elevate_degree_a_5_9 proc~elevate_degree~3->proc~is_rational~3 append append proc~export_iges~2->append delete delete proc~export_iges~2->delete init init proc~export_iges~2->init makedpsections makedpsections proc~export_iges~2->makedpsections makegsection makegsection proc~export_iges~2->makegsection makessection makessection proc~export_iges~2->makessection proc~export_iges~2->proc~is_rational~3 writeigesfile writeigesfile proc~export_iges~2->writeigesfile proc~export_xc~3->proc~cmp_elem_xc_vis~3 proc~export_vtk_legacy export_vtk_legacy proc~export_xc~3->proc~export_vtk_legacy proc~export_xc~3->set proc~export_xg~3->proc~cmp_elem_xg_vis~3 proc~export_xg~3->proc~export_vtk_legacy proc~export_xg~3->set interface~ndgrid ndgrid proc~export_xth~3->interface~ndgrid proc~export_xth~3->interface~unique proc~cmp_elem_xth~3 nurbs_curve%cmp_elem_Xth proc~export_xth~3->proc~cmp_elem_xth~3 proc~export_xth~3->proc~export_vtk_legacy proc~get_continuity~3->interface~compute_multiplicity proc~get_multiplicity~3->interface~compute_multiplicity proc~insert_knots~3->none~set~3 proc~insert_knots~3->interface~compute_multiplicity proc~findspan findspan proc~insert_knots~3->proc~findspan proc~insert_knot_a_5_1 insert_knot_A_5_1 proc~insert_knots~3->proc~insert_knot_a_5_1 proc~insert_knots~3->proc~is_rational~3 proc~modify_wc~3->none~get_knot~3 proc~modify_wc~3->none~get_wc~3 proc~modify_wc~3->none~get_xc~3 proc~modify_wc~3->none~set~3 proc~modify_xc~3->none~get_knot~3 proc~modify_xc~3->none~get_wc~3 proc~modify_xc~3->none~get_xc~3 proc~modify_xc~3->none~set~3 proc~nearest_point2~3->none~derivative2~3 proc~nearest_point2~3->proc~create~3 proc~nearest_point2~3->proc~nearest_point~3 proc~cmp_xg~3 nurbs_curve%cmp_Xg proc~nearest_point2~3->proc~cmp_xg~3 proc~finalize~3 nurbs_curve%finalize proc~nearest_point2~3->proc~finalize~3 proc~remove_knots~3->none~set~3 proc~remove_knots~3->interface~compute_multiplicity proc~remove_knots~3->proc~findspan proc~remove_knots~3->proc~is_rational~3 proc~remove_knots_a_5_8 remove_knots_A_5_8 proc~remove_knots~3->proc~remove_knots_a_5_8 proc~rotation rotation proc~rotate_xc~3->proc~rotation proc~rotate_xg~3->proc~rotation proc~set_circle->none~set~3 proc~set_half_circle->none~set~3 proc~compute_multiplicity1 compute_multiplicity1 interface~compute_multiplicity->proc~compute_multiplicity1 proc~compute_multiplicity2 compute_multiplicity2 interface~compute_multiplicity->proc~compute_multiplicity2 proc~compute_xg_bspline_1d compute_Xg_bspline_1d interface~compute_xg~3->proc~compute_xg_bspline_1d proc~compute_xg_bspline_1d_1point compute_Xg_bspline_1d_1point interface~compute_xg~3->proc~compute_xg_bspline_1d_1point proc~compute_xg_nurbs_1d compute_Xg_nurbs_1d interface~compute_xg~3->proc~compute_xg_nurbs_1d proc~compute_xg_nurbs_1d_1point compute_Xg_nurbs_1d_1point interface~compute_xg~3->proc~compute_xg_nurbs_1d_1point proc~cmp_elemconn_c0_l cmp_elemConn_C0_L interface~elemconn_c0->proc~cmp_elemconn_c0_l proc~cmp_elemconn_c0_s cmp_elemConn_C0_S interface~elemconn_c0->proc~cmp_elemconn_c0_s proc~cmp_elemconn_c0_v cmp_elemConn_C0_V interface~elemconn_c0->proc~cmp_elemconn_c0_v proc~cmp_elemconn_cn_l cmp_elemConn_Cn_L interface~elemconn_cn->proc~cmp_elemconn_cn_l proc~cmp_elemconn_cn_s cmp_elemConn_Cn_S interface~elemconn_cn->proc~cmp_elemconn_cn_s proc~cmp_elemconn_cn_v cmp_elemConn_Cn_V interface~elemconn_cn->proc~cmp_elemconn_cn_v proc~ndgrid2 ndgrid2 interface~ndgrid->proc~ndgrid2 proc~ndgrid3 ndgrid3 interface~ndgrid->proc~ndgrid3 proc~unique_integer unique_integer interface~unique->proc~unique_integer proc~unique_real unique_real interface~unique->proc~unique_real proc~ansatz~3->none~derivative~3 proc~ansatz~3->none~set~3 proc~ansatz~3->proc~cmp_elem~3 proc~ansatz~3->interface~unique interface~dyad dyad proc~ansatz~3->interface~dyad interface~gauss_leg gauss_leg proc~ansatz~3->interface~gauss_leg proc~basis_scalar~3->proc~is_rational~3 interface~compute_tgc~3 compute_Tgc proc~basis_scalar~3->interface~compute_tgc~3 proc~basis_vector~3->proc~is_rational~3 proc~basis_vector~3->interface~compute_tgc~3 proc~cmp_elem_xth~3->interface~elemconn_c0 proc~cmp_elem_xth~3->interface~unique proc~cmp_xg~3->interface~compute_xg~3 proc~cmp_xg~3->proc~is_rational~3 proc~derivative2_scalar~3->proc~is_rational~3 interface~compute_d2tgc~3 compute_d2Tgc proc~derivative2_scalar~3->interface~compute_d2tgc~3 proc~derivative2_vector~3->proc~is_rational~3 proc~derivative2_vector~3->interface~compute_d2tgc~3 proc~derivative_scalar~3->proc~is_rational~3 interface~compute_dtgc~3 compute_dTgc proc~derivative_scalar~3->interface~compute_dtgc~3 proc~derivative_vector~3->proc~is_rational~3 proc~derivative_vector~3->interface~compute_dtgc~3 proc~elevate_degree_a_5_9->interface~compute_multiplicity proc~bincoeff bincoeff proc~elevate_degree_a_5_9->proc~bincoeff cosd cosd proc~rotation->cosd sind sind proc~rotation->sind proc~set1a->set proc~cmp_degree~3 nurbs_curve%cmp_degree proc~set1a->proc~cmp_degree~3 proc~set1~3->set proc~set1~3->proc~cmp_degree~3 proc~set2~3->proc~cmp_nc~3 proc~set2~3->set proc~compute_knot_vector compute_knot_vector proc~set2~3->proc~compute_knot_vector proc~set3~3->set proc~set3~3->proc~cmp_degree~3 proc~set4~3->set proc~compute_d2tgc_bspline_1d_scalar compute_d2Tgc_bspline_1d_scalar interface~compute_d2tgc~3->proc~compute_d2tgc_bspline_1d_scalar proc~compute_d2tgc_bspline_1d_vector compute_d2Tgc_bspline_1d_vector interface~compute_d2tgc~3->proc~compute_d2tgc_bspline_1d_vector proc~compute_d2tgc_nurbs_1d_scalar compute_d2Tgc_nurbs_1d_scalar interface~compute_d2tgc~3->proc~compute_d2tgc_nurbs_1d_scalar proc~compute_d2tgc_nurbs_1d_vector compute_d2Tgc_nurbs_1d_vector interface~compute_d2tgc~3->proc~compute_d2tgc_nurbs_1d_vector proc~compute_dtgc_bspline_1d_scalar compute_dTgc_bspline_1d_scalar interface~compute_dtgc~3->proc~compute_dtgc_bspline_1d_scalar proc~compute_dtgc_bspline_1d_vector compute_dTgc_bspline_1d_vector interface~compute_dtgc~3->proc~compute_dtgc_bspline_1d_vector proc~compute_dtgc_nurbs_1d_scalar compute_dTgc_nurbs_1d_scalar interface~compute_dtgc~3->proc~compute_dtgc_nurbs_1d_scalar proc~compute_dtgc_nurbs_1d_vector compute_dTgc_nurbs_1d_vector interface~compute_dtgc~3->proc~compute_dtgc_nurbs_1d_vector proc~compute_tgc_bspline_1d_scalar compute_Tgc_bspline_1d_scalar interface~compute_tgc~3->proc~compute_tgc_bspline_1d_scalar proc~compute_tgc_bspline_1d_vector compute_Tgc_bspline_1d_vector interface~compute_tgc~3->proc~compute_tgc_bspline_1d_vector proc~compute_tgc_nurbs_1d_scalar compute_Tgc_nurbs_1d_scalar interface~compute_tgc~3->proc~compute_tgc_nurbs_1d_scalar proc~compute_tgc_nurbs_1d_vector compute_Tgc_nurbs_1d_vector interface~compute_tgc~3->proc~compute_tgc_nurbs_1d_vector proc~dyad_t1_t1 dyad_t1_t1 interface~dyad->proc~dyad_t1_t1 proc~gauss_legendre_1d gauss_legendre_1D interface~gauss_leg->proc~gauss_legendre_1d proc~gauss_legendre_2d gauss_legendre_2D interface~gauss_leg->proc~gauss_legendre_2d proc~gauss_legendre_3d gauss_legendre_3D interface~gauss_leg->proc~gauss_legendre_3d proc~factln factln proc~bincoeff->proc~factln proc~cmp_degree~3->proc~get_multiplicity~3 proc~repelem repelem proc~compute_knot_vector->proc~repelem proc~basis_bspline basis_bspline proc~compute_xg_bspline_1d->proc~basis_bspline proc~compute_xg_bspline_1d_1point->proc~basis_bspline proc~cmp_tgc_1d cmp_Tgc_1d proc~compute_xg_nurbs_1d->proc~cmp_tgc_1d proc~compute_xg_nurbs_1d_1point->proc~basis_bspline proc~cmp_tgc_1d->proc~basis_bspline interface~basis_bspline_2der basis_bspline_2der proc~compute_d2tgc_bspline_1d_scalar->interface~basis_bspline_2der proc~compute_d2tgc_bspline_1d_vector->interface~basis_bspline_2der proc~compute_d2tgc_nurbs_1d_scalar->interface~basis_bspline_2der proc~compute_d2tgc_nurbs_1d_vector->interface~basis_bspline_2der interface~basis_bspline_der basis_bspline_der proc~compute_dtgc_bspline_1d_scalar->interface~basis_bspline_der proc~compute_dtgc_bspline_1d_vector->interface~basis_bspline_der proc~compute_dtgc_nurbs_1d_scalar->interface~basis_bspline_der proc~compute_dtgc_nurbs_1d_vector->interface~basis_bspline_der proc~compute_tgc_bspline_1d_scalar->proc~basis_bspline proc~compute_tgc_bspline_1d_vector->proc~basis_bspline proc~compute_tgc_nurbs_1d_scalar->proc~basis_bspline proc~compute_tgc_nurbs_1d_vector->proc~basis_bspline proc~gauss_legendre gauss_legendre proc~gauss_legendre_1d->proc~gauss_legendre proc~gauss_legendre_2d->interface~ndgrid interface~kron kron proc~gauss_legendre_2d->interface~kron proc~gauss_legendre_2d->proc~gauss_legendre proc~gauss_legendre_3d->interface~ndgrid proc~gauss_legendre_3d->interface~kron proc~gauss_legendre_3d->proc~gauss_legendre proc~basis_bspline_2der_a basis_bspline_2der_A interface~basis_bspline_2der->proc~basis_bspline_2der_a proc~basis_bspline_2der_b basis_bspline_2der_B interface~basis_bspline_2der->proc~basis_bspline_2der_b proc~basis_bspline_2der_c basis_bspline_2der_C interface~basis_bspline_2der->proc~basis_bspline_2der_c proc~basis_bspline_der_a basis_bspline_der_A interface~basis_bspline_der->proc~basis_bspline_der_a proc~basis_bspline_der_b basis_bspline_der_B interface~basis_bspline_der->proc~basis_bspline_der_b proc~kron3 kron3 interface~kron->proc~kron3 proc~kron_t1_t1 kron_t1_t1 interface~kron->proc~kron_t1_t1 proc~kron_t1_t2 kron_t1_t2 interface~kron->proc~kron_t1_t2

Variables

Type Attributes Name Initial
integer, parameter :: NTESTS = 113
real(kind=rk), parameter :: PI = acos(-1.0_rk)
real(kind=rk), parameter :: TOL = 1.0e-5_rk
real(kind=rk), allocatable :: Tgc(:,:)
real(kind=rk), allocatable :: Tgc1(:)
real(kind=rk), allocatable :: Tgc1b(:)
real(kind=rk), allocatable :: Tgcb(:,:)
real(kind=rk), allocatable :: Wc(:)
real(kind=rk), allocatable :: Xc(:,:)
real(kind=rk), allocatable :: Xg(:,:)
real(kind=rk), allocatable :: Xgb(:,:)
real(kind=rk), allocatable :: Xt(:)
type(nurbs_curve) :: bsp
real(kind=rk), allocatable :: d2Tgc(:,:)
real(kind=rk), allocatable :: d2Tgc1(:)
real(kind=rk), allocatable :: d2Tgc1b(:)
real(kind=rk), allocatable :: d2Tgcb(:,:)
real(kind=rk), allocatable :: dTgc(:,:)
real(kind=rk), allocatable :: dTgc1(:)
real(kind=rk), allocatable :: dTgc1b(:)
real(kind=rk), allocatable :: dTgcb(:,:)
integer, allocatable :: elemConn(:,:)
character(len=*), parameter :: fIgs_bsp = 'iges/test_bsp_curve.iges'
character(len=*), parameter :: fIgs_nurbs = 'iges/test_nurbs_curve.iges'
character(len=*), parameter :: fXc_bsp = 'vtk/test_bsp_curve_Xc.vtk'
character(len=*), parameter :: fXc_nurbs = 'vtk/test_nurbs_curve_Xc.vtk'
character(len=*), parameter :: fXg_bsp = 'vtk/test_bsp_curve_Xg.vtk'
character(len=*), parameter :: fXg_nurbs = 'vtk/test_nurbs_curve_Xg.vtk'
character(len=*), parameter :: fXth_bsp = 'vtk/test_bsp_curve_Xth.vtk'
character(len=*), parameter :: fXth_nurbs = 'vtk/test_nurbs_curve_Xth.vtk'
integer :: i
integer :: id
real(kind=rk) :: knot(6)
real(kind=rk) :: length
real(kind=rk) :: lengthb
real(kind=rk) :: nearest_Xg(3)
real(kind=rk) :: nearest_Xt
type(nurbs_curve) :: nurbs
logical :: okIges_bsp
logical :: okIges_nurbs
logical :: okXc_bsp
logical :: okXc_nurbs
logical :: okXg_bsp
logical :: okXg_nurbs
logical :: okXth_bsp
logical :: okXth_nurbs
integer :: ti
type(unit_tests) :: ut

Source Code

program test_nurbs_curve
   use forcad_kinds, only: rk
   use forcad_nurbs_curve, only: nurbs_curve, compute_Tgc, compute_dTgc
   use forunittest, only: unit_tests
   implicit none

   integer, parameter :: NTESTS = 113
   type(unit_tests) :: ut
   real(rk), parameter :: TOL = 1.0e-5_rk
   real(rk), parameter :: PI = acos(-1.0_rk)

   type(nurbs_curve) :: nurbs, bsp
   real(rk), allocatable :: Xc(:,:), Wc(:)
   real(rk), allocatable :: Xg(:,:), Xgb(:,:)
   real(rk) :: knot(6)
   integer, allocatable :: elemConn(:,:)
   real(rk), allocatable :: Tgc(:,:), dTgc(:,:), Tgcb(:,:), dTgcb(:,:), d2Tgc(:,:), d2Tgcb(:,:)
   real(rk), allocatable :: Tgc1(:), dTgc1(:), Tgc1b(:), dTgc1b(:), d2Tgc1(:), d2Tgc1b(:)
   real(rk) :: nearest_Xg(3), nearest_Xt, length, lengthb
   integer :: i, id, ti
   real(rk), allocatable :: Xt(:)
   character(len=*), parameter :: fXc_nurbs = 'vtk/test_nurbs_curve_Xc.vtk'
   character(len=*), parameter :: fXg_nurbs = 'vtk/test_nurbs_curve_Xg.vtk'
   character(len=*), parameter :: fXth_nurbs = 'vtk/test_nurbs_curve_Xth.vtk'
   character(len=*), parameter :: fIgs_nurbs = 'iges/test_nurbs_curve.iges'
   character(len=*), parameter :: fXc_bsp = 'vtk/test_bsp_curve_Xc.vtk'
   character(len=*), parameter :: fXg_bsp = 'vtk/test_bsp_curve_Xg.vtk'
   character(len=*), parameter :: fXth_bsp = 'vtk/test_bsp_curve_Xth.vtk'
   character(len=*), parameter :: fIgs_bsp = 'iges/test_bsp_curve.iges'
   logical :: okXc_nurbs, okXg_nurbs, okXth_nurbs, okIges_nurbs
   logical :: okXc_bsp, okXg_bsp, okXth_bsp, okIges_bsp

   call ut%initialize(NTESTS)
   ti = 1

   ! Initialize curve data
   allocate(Xc(3, 3))
   Xc(1,:) = [0.0_rk, 0.0_rk, 0.0_rk]
   Xc(2,:) = [1.0_rk, 0.0_rk, 0.0_rk]
   Xc(3,:) = [2.0_rk, 0.0_rk, 0.0_rk]
   allocate(Wc(3))
   Wc = [1.0_rk, 0.9_rk, 0.8_rk]
   knot = [0.0_rk, 0.0_rk, 0.0_rk, 1.0_rk, 1.0_rk, 1.0_rk]

   ! 1) Set and create NURBS and B-spline curves
   call nurbs%set(knot, Xc, Wc)
   call bsp%set(knot, Xc)
   call nurbs%set(degree=nurbs%get_degree(), nc=nurbs%get_nc(), Xc=nurbs%get_Xc(), Wc=nurbs%get_Wc())
   call bsp%set(degree=bsp%get_degree(), nc=bsp%get_nc(), Xc=bsp%get_Xc())
   call nurbs%create(res=23)
   call bsp%create(res=23)


   call ut%test(ti)%check( &
      name="set(): degree==2", &
      res=nurbs%get_degree(), &
      expected=2, &
      msg="NURBS degree not 2", &
      group="setup"); ti=ti+1
   call ut%test(ti)%check( &
      name="set(): degree==2 (B-spline)", &
      res=bsp%get_degree(), &
      expected=2, &
      msg="B-spline degree not 2", &
      group="setup"); ti=ti+1
   call ut%test(ti)%check( &
      name="set(): nc==3", &
      res=nurbs%get_nc(), &
      expected=3, &
      msg="NURBS nc not 3", &
      group="setup"); ti=ti+1
   call ut%test(ti)%check( &
      name="set(): nc==3 (B-spline)", &
      res=bsp%get_nc(), &
      expected=3, &
      msg="B-spline nc not 3", &
      group="setup"); ti=ti+1

   call ut%test(ti)%check( &
      name="set(): knot matches", &
      res=nurbs%get_knot(), &
      expected=knot, &
      tol=TOL, &
      msg="NURBS knot vector mismatch", &
      group="setup"); ti=ti+1

      call ut%test(ti)%check( &
      name="set(): knot matches (B-spline)", &
      res=bsp%get_knot(), &
      expected=knot, &
      tol=TOL, &
      msg="B-spline knot vector mismatch", &
      group="setup"); ti=ti+1

   ! 2) Export tests
   call nurbs%export_Xc(fXc_nurbs)
   call bsp%export_Xc(fXc_bsp)
   call nurbs%export_Xg(fXg_nurbs)
   call bsp%export_Xg(fXg_bsp)
   call nurbs%export_Xth(fXth_nurbs)
   call bsp%export_Xth(fXth_bsp)
   call nurbs%export_iges(fIgs_nurbs)
   call bsp%export_iges(fIgs_bsp)
   inquire(file=fXc_nurbs, exist=okXc_nurbs)
   inquire(file=fXg_nurbs, exist=okXg_nurbs)
   inquire(file=fXth_nurbs, exist=okXth_nurbs)
   inquire(file=fIgs_nurbs, exist=okIges_nurbs)
   inquire(file=fXc_bsp, exist=okXc_bsp)
   inquire(file=fXg_bsp, exist=okXg_bsp)
   inquire(file=fXth_bsp, exist=okXth_bsp)
   inquire(file=fIgs_bsp, exist=okIges_bsp)
   call ut%test(ti)%check( &
      name="export_Xc/Xg/Xth/IGES(): files exist (NURBS)", &
      res=merge(1,0,okXc_nurbs .and. okXg_nurbs .and. okXth_nurbs .and. okIges_nurbs), &
      expected=1, &
      msg="NURBS export did not create all files", &
      group="io"); ti=ti+1
   call ut%test(ti)%check( &
      name="export_Xc/Xg/Xth/IGES(): files exist (B-spline)", &
      res=merge(1,0,okXc_bsp .and. okXg_bsp .and. okXth_bsp .and. okIges_bsp), &
      expected=1, &
      msg="B-spline export did not create all files", &
      group="io"); ti=ti+1

   ! 3) Length tests
   call nurbs%cmp_length(length)
   call bsp%cmp_length(lengthb)
   call ut%test(ti)%check( &
      name="cmp_length(): length == 2 (NURBS)", &
      res=length, &
      expected=2.0_rk, &
      tol=TOL, &
      msg="NURBS arc length incorrect", &
      group="geometry"); ti=ti+1
   call ut%test(ti)%check( &
      name="cmp_length(): length == 2 (B-spline)", &
      res=lengthb, &
      expected=2.0_rk, &
      tol=TOL, &
      msg="B-spline arc length incorrect", &
      group="geometry"); ti=ti+1

   ! 4) Nearest point tests
   call nurbs%nearest_point([0.0_rk, 0.0_rk, 0.5_rk], nearest_Xg, nearest_Xt, id)
   call ut%test(ti)%check( &
      name="nearest_point(): point matches [0,0,0] (NURBS)", &
      res=nearest_Xg, &
      expected=[0.0_rk, 0.0_rk, 0.0_rk], &
      tol=TOL, &
      msg="NURBS nearest point mismatch", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point(): param == 0 (NURBS)", &
      res=nearest_Xt, &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS nearest param incorrect", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point(): id == 1 (NURBS)", &
      res=id, &
      expected=1, &
      msg="NURBS nearest id incorrect", &
      group="nearest"); ti=ti+1

   call bsp%nearest_point([0.0_rk, 0.0_rk, 0.5_rk], nearest_Xg, nearest_Xt, id)
   call ut%test(ti)%check( &
      name="nearest_point(): point matches [0,0,0] (B-spline)", &
      res=nearest_Xg, &
      expected=[0.0_rk, 0.0_rk, 0.0_rk], &
      tol=TOL, &
      msg="B-spline nearest point mismatch", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point(): param == 0 (B-spline)", &
      res=nearest_Xt, &
      expected=0.0_rk, &
      tol=TOL, &
      msg="B-spline nearest param incorrect", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point(): id == 1 (B-spline)", &
      res=id, &
      expected=1, &
      msg="B-spline nearest id incorrect", &
      group="nearest"); ti=ti+1

   call nurbs%nearest_point2([0.0_rk, 0.0_rk, 0.5_rk], 1.0e-10_rk, 10, nearest_Xt, nearest_Xg)
   call ut%test(ti)%check( &
      name="nearest_point2(): point matches [0,0,0] (NURBS)", &
      res=nearest_Xg, &
      expected=[0.0_rk, 0.0_rk, 0.0_rk], &
      tol=TOL, &
      msg="NURBS nearest_point2 point mismatch", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point2(): param == 0 (NURBS)", &
      res=nearest_Xt, &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS nearest_point2 param incorrect", &
      group="nearest"); ti=ti+1

   call bsp%nearest_point2([0.0_rk, 0.0_rk, 0.5_rk], 1.0e-10_rk, 10, nearest_Xt, nearest_Xg)
   call ut%test(ti)%check( &
      name="nearest_point2(): point matches [0,0,0] (B-spline)", &
      res=nearest_Xg, &
      expected=[0.0_rk, 0.0_rk, 0.0_rk], &
      tol=TOL, &
      msg="B-spline nearest_point2 point mismatch", &
      group="nearest"); ti=ti+1
   call ut%test(ti)%check( &
      name="nearest_point2(): param == 0 (B-spline)", &
      res=nearest_Xt, &
      expected=0.0_rk, &
      tol=TOL, &
      msg="B-spline nearest_point2 param incorrect", &
      group="nearest"); ti=ti+1

   ! 5) Store initial geometry
   Xg = nurbs%get_Xg()
   Xgb = bsp%get_Xg()

   ! 6) Set with Xth_dir and continuity
   call nurbs%set([0.0_rk, 1.0_rk], 2, [-1, -1], Xc, Wc)
   call bsp%set([0.0_rk, 1.0_rk], 2, [-1, -1], Xc)
   call nurbs%create(res=23)
   call bsp%create(res=23)
   call ut%test(ti)%check( &
      name="set(Xth_dir): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after set(Xth_dir)", &
      group="setup"); ti=ti+1
   call ut%test(ti)%check( &
      name="set(Xth_dir): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after set(Xth_dir)", &
      group="setup"); ti=ti+1

   ! 7) Set with Xc and Wc
   call nurbs%set(Xc, Wc)
   call bsp%set(Xc)
   call nurbs%create(res=23)
   call bsp%create(res=23)
   call ut%test(ti)%check( &
      name="set(Xc,Wc): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after set(Xc,Wc)", &
      group="setup"); ti=ti+1
   call ut%test(ti)%check( &
      name="set(Xc): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after set(Xc)", &
      group="setup"); ti=ti+1

   ! 8) Create with explicit Xt
   call nurbs%create(Xt=nurbs%get_Xt())
   call bsp%create(Xt=bsp%get_Xt())
   call ut%test(ti)%check( &
      name="create(Xt): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after create(Xt)", &
      group="sampling"); ti=ti+1
   call ut%test(ti)%check( &
      name="create(Xt): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after create(Xt)", &
      group="sampling"); ti=ti+1

   ! 9) Export after create(Xt)
   call nurbs%export_Xc(fXc_nurbs)
   call bsp%export_Xc(fXc_bsp)
   call nurbs%export_Xg(fXg_nurbs)
   call bsp%export_Xg(fXg_bsp)
   call nurbs%export_Xth(fXth_nurbs)
   call bsp%export_Xth(fXth_bsp)
   call nurbs%export_iges(fIgs_nurbs)
   call bsp%export_iges(fIgs_bsp)
   inquire(file=fXc_nurbs, exist=okXc_nurbs)
   inquire(file=fXg_nurbs, exist=okXg_nurbs)
   inquire(file=fXth_nurbs, exist=okXth_nurbs)
   inquire(file=fIgs_nurbs, exist=okIges_nurbs)
   inquire(file=fXc_bsp, exist=okXc_bsp)
   inquire(file=fXg_bsp, exist=okXg_bsp)
   inquire(file=fXth_bsp, exist=okXth_bsp)
   inquire(file=fIgs_bsp, exist=okIges_bsp)
   call ut%test(ti)%check( &
      name="export after create(Xt): files exist (NURBS)", &
      res=merge(1,0,okXc_nurbs .and. okXg_nurbs .and. okXth_nurbs .and. okIges_nurbs), &
      expected=1, &
      msg="NURBS export after create(Xt) did not create all files", &
      group="io"); ti=ti+1
   call ut%test(ti)%check( &
      name="export after create(Xt): files exist (B-spline)", &
      res=merge(1,0,okXc_bsp .and. okXg_bsp .and. okXth_bsp .and. okIges_bsp), &
      expected=1, &
      msg="B-spline export after create(Xt) did not create all files", &
      group="io"); ti=ti+1

   ! 10) Getter tests
   call ut%test(ti)%check( &
      name="get_Xc(): matches input (NURBS)", &
      res=nurbs%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="NURBS Xc mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xc(): matches input (B-spline)", &
      res=bsp%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="B-spline Xc mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xc(1): matches input (NURBS)", &
      res=nurbs%get_Xc(1), &
      expected=Xc(1,:), &
      tol=TOL, &
      msg="NURBS Xc(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xc(1): matches input (B-spline)", &
      res=bsp%get_Xc(1), &
      expected=Xc(1,:), &
      tol=TOL, &
      msg="B-spline Xc(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xc(1,1): matches input (NURBS)", &
      res=nurbs%get_Xc(1,1), &
      expected=Xc(1,1), &
      tol=TOL, &
      msg="NURBS Xc(1,1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xc(1,1): matches input (B-spline)", &
      res=bsp%get_Xc(1,1), &
      expected=Xc(1,1), &
      tol=TOL, &
      msg="B-spline Xc(1,1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(): matches initial (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS Xg mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(): matches initial (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline Xg mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(1): matches initial (NURBS)", &
      res=nurbs%get_Xg(1), &
      expected=Xg(1,:), &
      tol=TOL, &
      msg="NURBS Xg(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(1): matches initial (B-spline)", &
      res=bsp%get_Xg(1), &
      expected=Xgb(1,:), &
      tol=TOL, &
      msg="B-spline Xg(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(1,1): matches initial (NURBS)", &
      res=nurbs%get_Xg(1,1), &
      expected=Xg(1,1), &
      tol=TOL, &
      msg="NURBS Xg(1,1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Xg(1,1): matches initial (B-spline)", &
      res=bsp%get_Xg(1,1), &
      expected=Xgb(1,1), &
      tol=TOL, &
      msg="B-spline Xg(1,1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Wc(): matches input (NURBS)", &
      res=nurbs%get_Wc(), &
      expected=Wc, &
      tol=TOL, &
      msg="NURBS Wc mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_Wc(1): matches input (NURBS)", &
      res=nurbs%get_Wc(1), &
      expected=Wc(1), &
      tol=TOL, &
      msg="NURBS Wc(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_knot(): matches input (NURBS)", &
      res=nurbs%get_knot(), &
      expected=knot, &
      tol=TOL, &
      msg="NURBS knot mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_knot(): matches input (B-spline)", &
      res=bsp%get_knot(), &
      expected=knot, &
      tol=TOL, &
      msg="B-spline knot mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_knot(1): matches input (NURBS)", &
      res=nurbs%get_knot(1), &
      expected=knot(1), &
      tol=TOL, &
      msg="NURBS knot(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_knot(1): matches input (B-spline)", &
      res=bsp%get_knot(1), &
      expected=knot(1), &
      tol=TOL, &
      msg="B-spline knot(1) mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_ng(): matches Xg size (NURBS)", &
      res=nurbs%get_ng(), &
      expected=size(Xg,1), &
      msg="NURBS ng mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_ng(): matches Xgb size (B-spline)", &
      res=bsp%get_ng(), &
      expected=size(Xgb,1), &
      msg="B-spline ng mismatch", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_degree(): matches 2 (NURBS)", &
      res=nurbs%get_degree(), &
      expected=2, &
      msg="NURBS degree not 2", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_degree(): matches 2 (B-spline)", &
      res=bsp%get_degree(), &
      expected=2, &
      msg="B-spline degree not 2", &
      group="getters"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_multiplicity(): matches [3,3] (NURBS)", &
      res=nurbs%get_multiplicity(), &
      expected=[3,3], &
      msg="NURBS multiplicity not [3,3]", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_multiplicity(): matches [3,3] (B-spline)", &
      res=bsp%get_multiplicity(), &
      expected=[3,3], &
      msg="B-spline multiplicity not [3,3]", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_continuity(): matches [-1,-1] (NURBS)", &
      res=nurbs%get_continuity(), &
      expected=[-1,-1], &
      msg="NURBS continuity not [-1,-1]", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="get_continuity(): matches [-1,-1] (B-spline)", &
      res=bsp%get_continuity(), &
      expected=[-1,-1], &
      msg="B-spline continuity not [-1,-1]", &
      group="knot-ops"); ti=ti+1
   call nurbs%cmp_nc()
   call bsp%cmp_nc()
   call ut%test(ti)%check( &
      name="cmp_nc(): matches nc (NURBS)", &
      res=nurbs%get_nc(), &
      expected=size(Xc,1), &
      msg="NURBS cmp_nc mismatch", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="cmp_nc(): matches nc (B-spline)", &
      res=bsp%get_nc(), &
      expected=size(Xc,1), &
      msg="B-spline cmp_nc mismatch", &
      group="knot-ops"); ti=ti+1

   ! 11) Element connectivity tests
   elemConn = nurbs%cmp_elem_Xc_vis(2)
   call nurbs%set_elem_Xc_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xc_vis(p=2): equality (NURBS)", &
      res=nurbs%get_elem_Xc_vis(), &
      expected=elemConn, &
      msg="NURBS elem_Xc_vis(p=2) mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = nurbs%cmp_elem_Xc_vis()
   call nurbs%set_elem_Xc_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xc_vis(): equality (NURBS)", &
      res=nurbs%get_elem_Xc_vis(), &
      expected=elemConn, &
      msg="NURBS elem_Xc_vis mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = bsp%cmp_elem_Xc_vis(2)
   call bsp%set_elem_Xc_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xc_vis(p=2): equality (B-spline)", &
      res=bsp%get_elem_Xc_vis(), &
      expected=elemConn, &
      msg="B-spline elem_Xc_vis(p=2) mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = bsp%cmp_elem_Xc_vis()
   call bsp%set_elem_Xc_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xc_vis(): equality (B-spline)", &
      res=bsp%get_elem_Xc_vis(), &
      expected=elemConn, &
      msg="B-spline elem_Xc_vis mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = nurbs%cmp_elem_Xg_vis(2)
   call nurbs%set_elem_Xg_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xg_vis(p=2): equality (NURBS)", &
      res=nurbs%get_elem_Xg_vis(), &
      expected=elemConn, &
      msg="NURBS elem_Xg_vis(p=2) mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = nurbs%cmp_elem_Xg_vis()
   call nurbs%set_elem_Xg_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xg_vis(): equality (NURBS)", &
      res=nurbs%get_elem_Xg_vis(), &
      expected=elemConn, &
      msg="NURBS elem_Xg_vis mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = bsp%cmp_elem_Xg_vis(2)
   call bsp%set_elem_Xg_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xg_vis(p=2): equality (B-spline)", &
      res=bsp%get_elem_Xg_vis(), &
      expected=elemConn, &
      msg="B-spline elem_Xg_vis(p=2) mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = bsp%cmp_elem_Xg_vis()
   call bsp%set_elem_Xg_vis(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem_Xg_vis(): equality (B-spline)", &
      res=bsp%get_elem_Xg_vis(), &
      expected=elemConn, &
      msg="B-spline elem_Xg_vis mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = nurbs%cmp_elem()
   call nurbs%set_elem(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem: equality (NURBS)", &
      res=nurbs%get_elem(), &
      expected=elemConn, &
      msg="NURBS elem mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)
   elemConn = bsp%cmp_elem()
   call bsp%set_elem(elemConn)
   call ut%test(ti)%check( &
      name="set/get elem: equality (B-spline)", &
      res=bsp%get_elem(), &
      expected=elemConn, &
      msg="B-spline elem mismatch", &
      group="elements"); ti=ti+1
   deallocate(elemConn)

   ! 12) Modify and export
   call nurbs%modify_Xc(Xc(1,1), 1, 1)
   call bsp%modify_Xc(Xc(1,1), 1, 1)
   call nurbs%modify_Wc(Wc(1), 1)
   call nurbs%create()
   call bsp%create()
   call nurbs%export_Xc(fXc_nurbs)
   call bsp%export_Xc(fXc_bsp)
   call nurbs%export_Xg(fXg_nurbs)
   call bsp%export_Xg(fXg_bsp)
   call ut%test(ti)%check( &
      name="modify_Xc/Wc: geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after modify_Xc/Wc", &
      group="modify"); ti=ti+1
   call ut%test(ti)%check( &
      name="modify_Xc: geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after modify_Xc", &
      group="modify"); ti=ti+1

   ! 13) Basis and derivative tests
   call nurbs%basis(res=23, Tgc=Tgc)
   call bsp%basis(res=23, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="basis(res=23): sum(N)=1 rows (NURBS)", &
      res=all(abs(sum(Tgc,dim=2)-1.0_rk) <= TOL), &
      expected=.true., &
      msg="NURBS basis partition of unity violated", &
      group="basis"); ti=ti+1
   call ut%test(ti)%check( &
      name="basis(res=23): sum(N)=1 rows (B-spline)", &
      res=all(abs(sum(Tgcb,dim=2)-1.0_rk) <= TOL), &
      expected=.true., &
      msg="B-spline basis partition of unity violated", &
      group="basis"); ti=ti+1

   call nurbs%basis(Xt=0.0_rk, Tgc=Tgc1)
   call bsp%basis(Xt=0.0_rk, Tgc=Tgc1b)
   call ut%test(ti)%check( &
      name="basis(Xt=0): sum(N)=1 (NURBS)", &
      res=sum(Tgc1), &
      expected=1.0_rk, &
      tol=TOL, &
      msg="NURBS basis sum not 1 at t=0", &
      group="basis"); ti=ti+1
   call ut%test(ti)%check( &
      name="basis(Xt=0): sum(N)=1 (B-spline)", &
      res=sum(Tgc1b), &
      expected=1.0_rk, &
      tol=TOL, &
      msg="B-spline basis sum not 1 at t=0", &
      group="basis"); ti=ti+1

   allocate(Xt(23))
   do i = 1, 23
      Xt(i) = real(i-1,rk) / real(23-1,rk)
   end do
   call nurbs%basis(Xt=Xt, Tgc=Tgc)
   call bsp%basis(Xt=Xt, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="basis(Xt vector): sum(N)=1 rows (NURBS)", &
      res=all(abs(sum(Tgc,dim=2)-1.0_rk) <= TOL), &
      expected=.true., &
      msg="NURBS basis partition of unity violated (vector)", &
      group="basis"); ti=ti+1
   call ut%test(ti)%check( &
      name="basis(Xt vector): sum(N)=1 rows (B-spline)", &
      res=all(abs(sum(Tgcb,dim=2)-1.0_rk) <= TOL), &
      expected=.true., &
      msg="B-spline basis partition of unity violated (vector)", &
      group="basis"); ti=ti+1

   call nurbs%derivative(res=23, dTgc=dTgc, Tgc=Tgc)
   call bsp%derivative(res=23, dTgc=dTgcb, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="derivative(res=23): sum(dN)=0 rows (NURBS)", &
      res=all(abs(sum(dTgc,dim=2)) <= TOL), &
      expected=.true., &
      msg="NURBS derivative sum not zero", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative(res=23): sum(dN)=0 rows (B-spline)", &
      res=all(abs(sum(dTgcb,dim=2)) <= TOL), &
      expected=.true., &
      msg="B-spline derivative sum not zero", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative(Xt=Xt, dTgc=dTgc, Tgc=Tgc)
   call bsp%derivative(Xt=Xt, dTgc=dTgcb, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="derivative(Xt vector): sum(dN)=0 rows (NURBS)", &
      res=all(abs(sum(dTgc,dim=2)) <= TOL), &
      expected=.true., &
      msg="NURBS derivative sum not zero (vector)", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative(Xt vector): sum(dN)=0 rows (B-spline)", &
      res=all(abs(sum(dTgcb,dim=2)) <= TOL), &
      expected=.true., &
      msg="B-spline derivative sum not zero (vector)", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative(Xt=0.0_rk, dTgc=dTgc1, Tgc=Tgc1)
   call bsp%derivative(Xt=0.0_rk, dTgc=dTgc1b, Tgc=Tgc1b)
   call ut%test(ti)%check( &
      name="derivative(Xt=0): sum(dN)=0 (NURBS)", &
      res=sum(dTgc1), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS derivative sum not zero at t=0", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative(Xt=0): sum(dN)=0 (B-spline)", &
      res=sum(dTgc1b), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="B-spline derivative sum not zero at t=0", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative(Xt=0.0_rk, dTgc=dTgc1, Tgc=Tgc1, elem=[1,2,3])
   call bsp%derivative(Xt=0.0_rk, dTgc=dTgc1b, Tgc=Tgc1b, elem=[1,2,3])
   call ut%test(ti)%check( &
      name="derivative(Xt=0, elem): sum(dN)=0 (NURBS)", &
      res=sum(dTgc1), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS derivative sum not zero (elem)", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative(Xt=0, elem): sum(dN)=0 (B-spline)", &
      res=sum(dTgc1b), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="B-spline derivative sum not zero (elem)", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative2(res=23, d2Tgc=d2Tgc, dTgc=dTgc, Tgc=Tgc)
   call bsp%derivative2(res=23, d2Tgc=d2Tgcb, dTgc=dTgcb, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="derivative2(res=23): sum(d2N)=0 rows (NURBS)", &
      res=all(abs(sum(d2Tgc,dim=2)) <= TOL), &
      expected=.true., &
      msg="NURBS second derivative sum not zero", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative2(res=23): sum(d2N)=0 rows (B-spline)", &
      res=all(abs(sum(d2Tgcb,dim=2)) <= TOL), &
      expected=.true., &
      msg="B-spline second derivative sum not zero", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative2(Xt=Xt, d2Tgc=d2Tgc, dTgc=dTgc, Tgc=Tgc)
   call bsp%derivative2(Xt=Xt, d2Tgc=d2Tgcb, dTgc=dTgcb, Tgc=Tgcb)
   call ut%test(ti)%check( &
      name="derivative2(Xt vector): sum(d2N)=0 rows (NURBS)", &
      res=all(abs(sum(d2Tgc,dim=2)) <= TOL), &
      expected=.true., &
      msg="NURBS second derivative sum not zero (vector)", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative2(Xt vector): sum(d2N)=0 rows (B-spline)", &
      res=all(abs(sum(d2Tgcb,dim=2)) <= TOL), &
      expected=.true., &
      msg="B-spline second derivative sum not zero (vector)", &
      group="derivatives"); ti=ti+1

   call nurbs%derivative2(Xt=0.0_rk, d2Tgc=d2Tgc1, dTgc=dTgc1, Tgc=Tgc1)
   call bsp%derivative2(Xt=0.0_rk, d2Tgc=d2Tgc1b, dTgc=dTgc1b, Tgc=Tgc1b)
   call ut%test(ti)%check( &
      name="derivative2(Xt=0): sum(d2N)=0 (NURBS)", &
      res=sum(d2Tgc1), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS second derivative sum not zero at t=0", &
      group="derivatives"); ti=ti+1
   call ut%test(ti)%check( &
      name="derivative2(Xt=0): sum(d2N)=0 (B-spline)", &
      res=sum(d2Tgc1b), &
      expected=0.0_rk, &
      tol=TOL, &
      msg="B-spline second derivative sum not zero at t=0", &
      group="derivatives"); ti=ti+1

   ! 14) Rotation tests (Xc)
   call nurbs%rotate_Xc(45.0_rk, 0.0_rk, 0.0_rk)
   call nurbs%rotate_Xc(-45.0_rk, 0.0_rk, 0.0_rk)
   call bsp%rotate_Xc(45.0_rk, 0.0_rk, 0.0_rk)
   call bsp%rotate_Xc(-45.0_rk, 0.0_rk, 0.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xc(X-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="NURBS Xc changed after X-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xc(X-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="B-spline Xc changed after X-axis rotation", &
      group="transform"); ti=ti+1

   call nurbs%rotate_Xc(0.0_rk, 45.0_rk, 0.0_rk)
   call nurbs%rotate_Xc(0.0_rk, -45.0_rk, 0.0_rk)
   call bsp%rotate_Xc(0.0_rk, 45.0_rk, 0.0_rk)
   call bsp%rotate_Xc(0.0_rk, -45.0_rk, 0.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xc(Y-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="NURBS Xc changed after Y-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xc(Y-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="B-spline Xc changed after Y-axis rotation", &
      group="transform"); ti=ti+1

   call nurbs%rotate_Xc(0.0_rk, 0.0_rk, 45.0_rk)
   call nurbs%rotate_Xc(0.0_rk, 0.0_rk, -45.0_rk)
   call bsp%rotate_Xc(0.0_rk, 0.0_rk, 45.0_rk)
   call bsp%rotate_Xc(0.0_rk, 0.0_rk, -45.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xc(Z-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="NURBS Xc changed after Z-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xc(Z-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="B-spline Xc changed after Z-axis rotation", &
      group="transform"); ti=ti+1

   ! 15) Rotation tests (Xg)
   call nurbs%rotate_Xg(45.0_rk, 0.0_rk, 0.0_rk)
   call nurbs%rotate_Xg(-45.0_rk, 0.0_rk, 0.0_rk)
   call bsp%rotate_Xg(45.0_rk, 0.0_rk, 0.0_rk)
   call bsp%rotate_Xg(-45.0_rk, 0.0_rk, 0.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xg(X-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS Xg changed after X-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xg(X-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline Xg changed after X-axis rotation", &
      group="transform"); ti=ti+1

   call nurbs%rotate_Xg(0.0_rk, 45.0_rk, 0.0_rk)
   call nurbs%rotate_Xg(0.0_rk, -45.0_rk, 0.0_rk)
   call bsp%rotate_Xg(0.0_rk, 45.0_rk, 0.0_rk)
   call bsp%rotate_Xg(0.0_rk, -45.0_rk, 0.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xg(Y-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS Xg changed after Y-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xg(Y-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline Xg changed after Y-axis rotation", &
      group="transform"); ti=ti+1

   call nurbs%rotate_Xg(0.0_rk, 0.0_rk, 45.0_rk)
   call nurbs%rotate_Xg(0.0_rk, 0.0_rk, -45.0_rk)
   call bsp%rotate_Xg(0.0_rk, 0.0_rk, 45.0_rk)
   call bsp%rotate_Xg(0.0_rk, 0.0_rk, -45.0_rk)
   call ut%test(ti)%check( &
      name="rotate_Xg(Z-axis): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS Xg changed after Z-axis rotation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="rotate_Xg(Z-axis): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline Xg changed after Z-axis rotation", &
      group="transform"); ti=ti+1

   ! 16) Translation tests (Xc)
   call nurbs%translate_Xc([5.0_rk, 5.0_rk, 5.0_rk])
   call nurbs%translate_Xc([-5.0_rk, -5.0_rk, -5.0_rk])
   call bsp%translate_Xc([5.0_rk, 5.0_rk, 5.0_rk])
   call bsp%translate_Xc([-5.0_rk, -5.0_rk, -5.0_rk])
   call ut%test(ti)%check( &
      name="translate_Xc(): geometry preserved (NURBS)", &
      res=nurbs%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="NURBS Xc changed after translation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="translate_Xc(): geometry preserved (B-spline)", &
      res=bsp%get_Xc(), &
      expected=Xc, &
      tol=TOL, &
      msg="B-spline Xc changed after translation", &
      group="transform"); ti=ti+1

   ! 17) Translation tests (Xg)
   call nurbs%translate_Xg([5.0_rk, 5.0_rk, 5.0_rk])
   call nurbs%translate_Xg([-5.0_rk, -5.0_rk, -5.0_rk])
   call bsp%translate_Xg([5.0_rk, 5.0_rk, 5.0_rk])
   call bsp%translate_Xg([-5.0_rk, -5.0_rk, -5.0_rk])
   call ut%test(ti)%check( &
      name="translate_Xg(): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS Xg changed after translation", &
      group="transform"); ti=ti+1
   call ut%test(ti)%check( &
      name="translate_Xg(): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline Xg changed after translation", &
      group="transform"); ti=ti+1

   ! 18) Knot insertion
   call nurbs%insert_knots([0.25_rk, 0.75_rk], [2,1])
   call bsp%insert_knots([0.25_rk, 0.75_rk], [2,1])
   call nurbs%create()
   call bsp%create()
   call ut%test(ti)%check( &
      name="insert_knots(): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after knot insertion", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="insert_knots(): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after knot insertion", &
      group="knot-ops"); ti=ti+1

   ! 19) Degree elevation
   call nurbs%elevate_degree(2)
   call bsp%elevate_degree(2)
   call nurbs%create()
   call bsp%create()
   call ut%test(ti)%check( &
      name="elevate_degree(): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after degree elevation", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="elevate_degree(): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after degree elevation", &
      group="knot-ops"); ti=ti+1

   ! 20) Knot removal
   call nurbs%remove_knots([0.25_rk, 0.75_rk], [2,1])
   call bsp%remove_knots([0.25_rk, 0.75_rk], [2,1])
   call nurbs%create()
   call bsp%create()
   call ut%test(ti)%check( &
      name="remove_knots(): geometry preserved (NURBS)", &
      res=nurbs%get_Xg(), &
      expected=Xg, &
      tol=TOL, &
      msg="NURBS geometry changed after knot removal", &
      group="knot-ops"); ti=ti+1
   call ut%test(ti)%check( &
      name="remove_knots(): geometry preserved (B-spline)", &
      res=bsp%get_Xg(), &
      expected=Xgb, &
      tol=TOL, &
      msg="B-spline geometry changed after knot removal", &
      group="knot-ops"); ti=ti+1

   ! 21) Shape functions (circle, half-circle)
   call nurbs%set_circle([0.0_rk, 0.0_rk, 0.0_rk], 1.0_rk)
   call nurbs%create(res=23)
   call nurbs%nearest_point([1.0_rk, 0.0_rk, 0.0_rk], nearest_Xg, nearest_Xt, id)
   call ut%test(ti)%check( &
      name="set_circle(): nearest point param (NURBS)", &
      res=nearest_Xt, &
      expected=0.0_rk, &
      tol=TOL, &
      msg="NURBS circle nearest point param incorrect", &
      group="shapes"); ti=ti+1

   call nurbs%set_half_circle([0.0_rk, 0.0_rk, 0.0_rk], 1.0_rk)
   call nurbs%create(res=23)
   call nurbs%nearest_point([0.0_rk, 1.0_rk, 0.0_rk], nearest_Xg, nearest_Xt, id)
   call ut%test(ti)%check( &
      name="set_half_circle(): nearest point param (NURBS)", &
      res=nearest_Xt, &
      expected=0.5_rk, &
      tol=TOL, &
      msg="NURBS half-circle nearest point param incorrect", &
      group="shapes"); ti=ti+1

   ! 22) Least-squares B-spline fitting
   block
      type(nurbs_curve) :: bsp_fit
      integer :: n
      real(rk), allocatable :: Xt_fit(:), Xdata(:,:), Xg_eval(:,:)
      real(rk) :: err1, err2, err3, rms

      n = 42
      allocate(Xt_fit(n), Xdata(n, 3))
      do i = 1, n
         Xt_fit(i) = real(i-1, rk) / real(n-1, rk)
         Xdata(i,1) = Xt_fit(i)
         Xdata(i,2) = 0.3_rk * sin(4.0_rk * PI * Xt_fit(i))
         Xdata(i,3) = 0.3_rk * cos(4.0_rk * PI * Xt_fit(i))
      end do

      call bsp_fit%set( &
         degree=5, &
         Xth_dir=[(real(i-1, rk)/10.0_rk, i=1,11)], &
         continuity=[-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1])
      call bsp_fit%lsq_fit_bspline(Xt_fit, Xdata, n)
      call bsp_fit%create(res=n)
      Xg_eval = bsp_fit%get_Xg()

      err1 = norm2(Xg_eval(:,1) - Xdata(:,1)) / norm2(Xdata(:,1))
      err2 = norm2(Xg_eval(:,2) - Xdata(:,2)) / norm2(Xdata(:,2))
      err3 = norm2(Xg_eval(:,3) - Xdata(:,3)) / norm2(Xdata(:,3))
      rms = sqrt((err1**2 + err2**2 + err3**2) / 3.0_rk)

      call ut%test(ti)%check( &
         name="lsq_fit_bspline(): RMS error", &
         res=rms, &
         expected=0.0_rk, &
         tol=1.0e-6_rk, &
         msg="B-spline least-squares fit RMS error too high", &
         group="basis"); ti=ti+1

      call bsp_fit%finalize()
      deallocate(Xt_fit, Xdata, Xg_eval)
   end block

   ! Finalize
   call nurbs%finalize()
   call bsp%finalize()
   deallocate(Xc, Wc, Xg, Xgb, Xt)
   if (allocated(Tgc)) deallocate(Tgc)
   if (allocated(Tgcb)) deallocate(Tgcb)
   if (allocated(dTgc)) deallocate(dTgc)
   if (allocated(dTgcb)) deallocate(dTgcb)
   if (allocated(d2Tgc)) deallocate(d2Tgc)
   if (allocated(d2Tgcb)) deallocate(d2Tgcb)
   if (allocated(Tgc1)) deallocate(Tgc1)
   if (allocated(Tgc1b)) deallocate(Tgc1b)
   if (allocated(dTgc1)) deallocate(dTgc1)
   if (allocated(dTgc1b)) deallocate(dTgc1b)
   if (allocated(d2Tgc1)) deallocate(d2Tgc1)
   if (allocated(d2Tgc1b)) deallocate(d2Tgc1b)

   call ut%summary(verbose=3, required_score=100.0)

end program test_nurbs_curve