@@ -639,3 +639,95 @@ def make():
639639 val = interp (2.0 )
640640 assert math .isfinite (val )
641641 assert val > 0
642+
643+
644+ # ---------------------------------------------------------------------------
645+ # BackwardflatLinearInterpolation (2D)
646+ # ---------------------------------------------------------------------------
647+
648+ def test_backwardflat_linear_2d_construction ():
649+ """BackwardflatLinearInterpolation constructs and evaluates."""
650+ x = [1.0 , 2.0 , 3.0 ]
651+ y = [10.0 , 20.0 , 30.0 ]
652+ z = ql .Matrix (3 , 3 )
653+ for i in range (3 ):
654+ for j in range (3 ):
655+ z [i ][j ] = (i + 1 ) * (j + 1 ) * 1.0
656+ interp = ql .BackwardflatLinearInterpolation (x , y , z )
657+ assert isinstance (interp , ql .base .Interpolation2D )
658+
659+
660+ def test_backwardflat_linear_2d_at_nodes ():
661+ """Backward-flat linear 2D hits node values."""
662+ x = [1.0 , 2.0 , 3.0 ]
663+ y = [10.0 , 20.0 ]
664+ z = ql .Matrix (2 , 3 )
665+ z [0 ][0 ] = 1.0 ; z [0 ][1 ] = 2.0 ; z [0 ][2 ] = 3.0
666+ z [1 ][0 ] = 4.0 ; z [1 ][1 ] = 5.0 ; z [1 ][2 ] = 6.0
667+ interp = ql .BackwardflatLinearInterpolation (x , y , z )
668+
669+ assert interp (1.0 , 10.0 ) == pytest .approx (1.0 )
670+ assert interp (2.0 , 20.0 ) == pytest .approx (5.0 )
671+ assert interp (3.0 , 20.0 ) == pytest .approx (6.0 )
672+
673+
674+ def test_backwardflat_linear_2d_interpolation ():
675+ """Backward-flat in x, linear in y."""
676+ x = [1.0 , 2.0 ]
677+ y = [0.0 , 1.0 ]
678+ z = ql .Matrix (2 , 2 )
679+ z [0 ][0 ] = 10.0 ; z [0 ][1 ] = 20.0
680+ z [1 ][0 ] = 30.0 ; z [1 ][1 ] = 40.0
681+ interp = ql .BackwardflatLinearInterpolation (x , y , z )
682+
683+ # Linear in y at x=1.0
684+ assert interp (1.0 , 0.5 ) == pytest .approx (20.0 ) # (10+30)/2
685+
686+ # Backward-flat in x: between 1 and 2, uses x=2 value
687+ assert interp (1.5 , 0.0 ) == pytest .approx (20.0 ) # backflat -> z[0][1]
688+
689+
690+ # ---------------------------------------------------------------------------
691+ # FlatExtrapolator2D
692+ # ---------------------------------------------------------------------------
693+
694+ def test_flat_extrapolator_2d_construction ():
695+ """FlatExtrapolator2D wraps a 2D interpolation."""
696+ x = [1.0 , 2.0 , 3.0 ]
697+ y = [10.0 , 20.0 , 30.0 ]
698+ z = ql .Matrix (3 , 3 )
699+ for i in range (3 ):
700+ for j in range (3 ):
701+ z [i ][j ] = float (i + j )
702+ inner = ql .BilinearInterpolation (x , y , z )
703+ extrap = ql .FlatExtrapolator2D (inner )
704+ assert isinstance (extrap , ql .base .Interpolation2D )
705+
706+
707+ def test_flat_extrapolator_2d_within_range ():
708+ """FlatExtrapolator2D passes through to inner interpolation within range."""
709+ x = [1.0 , 2.0 , 3.0 ]
710+ y = [10.0 , 20.0 ]
711+ z = ql .Matrix (2 , 3 )
712+ z [0 ][0 ] = 1.0 ; z [0 ][1 ] = 2.0 ; z [0 ][2 ] = 3.0
713+ z [1 ][0 ] = 4.0 ; z [1 ][1 ] = 5.0 ; z [1 ][2 ] = 6.0
714+ inner = ql .BilinearInterpolation (x , y , z )
715+ extrap = ql .FlatExtrapolator2D (inner )
716+
717+ assert extrap (2.0 , 15.0 ) == pytest .approx (inner (2.0 , 15.0 ))
718+
719+
720+ def test_flat_extrapolator_2d_outside_range ():
721+ """FlatExtrapolator2D clamps to boundary values outside range."""
722+ x = [1.0 , 2.0 ]
723+ y = [10.0 , 20.0 ]
724+ z = ql .Matrix (2 , 2 )
725+ z [0 ][0 ] = 1.0 ; z [0 ][1 ] = 2.0
726+ z [1 ][0 ] = 3.0 ; z [1 ][1 ] = 4.0
727+ inner = ql .BilinearInterpolation (x , y , z )
728+ extrap = ql .FlatExtrapolator2D (inner )
729+ extrap .enableExtrapolation ()
730+
731+ # Outside x range: clamps to boundary
732+ assert extrap (0.0 , 10.0 ) == pytest .approx (extrap (1.0 , 10.0 ))
733+ assert extrap (5.0 , 20.0 ) == pytest .approx (extrap (2.0 , 20.0 ))
0 commit comments