$ fv cube
vol = tetrahedra_volume cube
--- Feels dirty, but whatever.
-tetrahedron _ _ = error "asked for a nonexistent tetrahedron"
-
-- Only used in tests, so we don't need the added speed
-- of Data.Vector.
2*(value_at v3d i j 0) - (value_at v3d i j 1)
else
2*(value_at v3d i j (k-1)) - (value_at v3d i j (k-2))
-
- | otherwise =
- let istr = show i
- jstr = show j
- kstr = show k
- coordstr = "(" ++ istr ++ "," ++ jstr ++ "," ++ kstr ++ ")"
- in
- error $ "value_at called outside of domain: " ++ coordstr
where
(dim_i, dim_j, dim_k) = dims v3d
return (make_grid h' fvs)
--- | The constructor that we want people to use. If we're passed a
--- non-positive grid size, we throw an error.
+-- | The constructor that we want people to use.
+-- Ignore non-positive grid sizes for performance.
make_grid :: Double -> Values3D -> Grid
-make_grid grid_size values
- | grid_size <= 0 = error "grid size must be positive"
- | otherwise = Grid grid_size values
+make_grid grid_size values =
+ Grid grid_size values
-- | Takes a grid and a position as an argument and returns the cube
--- centered on that position. If there is no cube there (i.e. the
--- position is outside of the grid), it will throw an error.
+-- centered on that position. If there is no cube there, well, you
+-- shouldn't have done that. The omitted "otherwise" case actually
+-- does improve performance.
cube_at :: Grid -> Int -> Int -> Int -> Cube
-cube_at !g !i !j !k
- | i < 0 = error "i < 0 in cube_at"
- | i >= xsize = error "i >= xsize in cube_at"
- | j < 0 = error "j < 0 in cube_at"
- | j >= ysize = error "j >= ysize in cube_at"
- | k < 0 = error "k < 0 in cube_at"
- | k >= zsize = error "k >= zsize in cube_at"
- | otherwise = Cube delta i j k fvs' tet_vol
- where
- fvs = function_values g
- (xsize, ysize, zsize) = dims fvs
- fvs' = make_values fvs i j k
- delta = h g
- tet_vol = (1/24)*(delta^(3::Int))
+cube_at !g !i !j !k =
+ Cube delta i j k fvs' tet_vol
+ where
+ fvs = function_values g
+ fvs' = make_values fvs i j k
+ delta = h g
+ tet_vol = (1/24)*(delta^(3::Int))
+
-- The first cube along any axis covers (-h/2, h/2). The second
-- covers (h/2, 3h/2). The third, (3h/2, 5h/2), and so on.
-- 24
--
factorial :: Int -> Int
-factorial !n
- | n > 20 = error "integer overflow in factorial function"
- | otherwise = go 1 n
- where go !acc !i
- | i <= 1 = acc
- | otherwise = go (acc * i) (i - 1)
+factorial !n =
+ go 1 n
+ where
+ go !acc !i
+ | i <= 1 = acc
+ | otherwise = go (acc * i) (i - 1)
-- | Takes a three-dimensional list, and flattens it into a
-- one-dimensional one.
-- | The Bernstein polynomial on t with indices i,j,k,l. Denoted by a
-- capital 'B' in the Sorokina/Zeilfelder paper.
beta :: Tetrahedron -> Int -> Int -> Int -> Int -> (RealFunction Point)
-beta t i j k l
- | (i + j + k + l == 3) =
- coefficient `cmult` (b0_term * b1_term * b2_term * b3_term)
- | otherwise = error "basis function index out of bounds"
+beta t i j k l =
+ coefficient `cmult` (b0_term * b1_term * b2_term * b3_term)
where
denominator = (factorial i)*(factorial j)*(factorial k)*(factorial l)
coefficient = 6 / (fromIntegral denominator)
-- | The coefficient function. c t i j k l returns the coefficient
-- c_ijkl with respect to the tetrahedron t. The definition uses
-- pattern matching to mimic the definitions given in Sorokina and
--- Zeilfelder, pp. 84-86. If incorrect indices are supplied, the
--- function will simply error.
+-- Zeilfelder, pp. 84-86. If incorrect indices are supplied, the world
+-- will end. This is for performance reasons.
c :: Tetrahedron -> Int -> Int -> Int -> Int -> Double
c !t !i !j !k !l =
coefficient i j k l
+ (1/96)*(lt + fl + ft + rt + bt + fr)
+ (1/96)*(fd + ld + bd + br + rd + bl)
- coefficient _ _ _ _ = error "coefficient index out of bounds"
-
-- | Compute the determinant of the 4x4 matrix,
where
-- | Returns the domain point of t with indices i,j,k,l.
domain_point :: Tetrahedron -> Int -> Int -> Int -> Int -> Point
- domain_point t i j k l
- | i + j + k + l == 3 = weighted_sum `scale` (1/3)
- | otherwise = error "domain point index out of bounds"
+ domain_point t i j k l =
+ weighted_sum `scale` (1/3)
where
v0' = (v0 t) `scale` (fromIntegral i)
v1' = (v1 t) `scale` (fromIntegral j)