step one
This commit is contained in:
parent
7a8d5d13fa
commit
9e663db9dc
68 changed files with 5647 additions and 2958 deletions
86
internal/numerics/grid.go
Normal file
86
internal/numerics/grid.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package numerics
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Axis describes a regularly-spaced grid axis with N grid points,
|
||||
// values left, left+step, left+2*step, ..., left+(N-1)*step.
|
||||
//
|
||||
// If Wrap is true, the axis is periodic with period N*step (e.g. longitude).
|
||||
// A query value at left+N*step wraps to the value at left+0*step. Locate
|
||||
// returns Hi = 0 in that case.
|
||||
type Axis struct {
|
||||
Left float64
|
||||
Step float64
|
||||
N int
|
||||
Wrap bool
|
||||
Name string
|
||||
}
|
||||
|
||||
// AxisError is returned by Axis.Locate when value lies outside a non-wrapping axis.
|
||||
type AxisError struct {
|
||||
Axis string
|
||||
Value float64
|
||||
}
|
||||
|
||||
func (e *AxisError) Error() string {
|
||||
return fmt.Sprintf("%s=%v out of range", e.Axis, e.Value)
|
||||
}
|
||||
|
||||
// Bracket holds the two surrounding grid indices and the fractional position
|
||||
// of a value within an axis. The weight at Lo is (1 - Frac); the weight at Hi
|
||||
// is Frac. Frac lies in [0, 1).
|
||||
type Bracket struct {
|
||||
Lo, Hi int
|
||||
Frac float64
|
||||
}
|
||||
|
||||
// Locate returns the bracket containing value within the axis.
|
||||
// For a non-wrapping axis, value must lie in [Left, Left + (N-1)*Step);
|
||||
// for a wrapping axis, value must lie in [Left, Left + N*Step).
|
||||
func (a Axis) Locate(value float64) (Bracket, error) {
|
||||
pos := (value - a.Left) / a.Step
|
||||
lo := int(pos) // truncates toward zero; pos is non-negative for valid inputs
|
||||
|
||||
maxLo := a.N - 2
|
||||
if a.Wrap {
|
||||
maxLo = a.N - 1
|
||||
}
|
||||
if lo < 0 || lo > maxLo {
|
||||
return Bracket{}, &AxisError{Axis: a.Name, Value: value}
|
||||
}
|
||||
|
||||
hi := lo + 1
|
||||
if a.Wrap && hi == a.N {
|
||||
hi = 0
|
||||
}
|
||||
return Bracket{Lo: lo, Hi: hi, Frac: pos - float64(lo)}, nil
|
||||
}
|
||||
|
||||
// EvalTrilinear samples a 3D field via f at the eight corners defined by b3
|
||||
// and returns the trilinearly interpolated value.
|
||||
//
|
||||
// The corners are visited in the order (axis0 outer, axis2 inner), matching
|
||||
// the Cython reference. With f(i,j,k) = a*i + b*j + c*k + d this returns
|
||||
// a*pos0 + b*pos1 + c*pos2 + d exactly, modulo floating-point rounding.
|
||||
func EvalTrilinear(b3 [3]Bracket, f func(i, j, k int) float64) float64 {
|
||||
wa0, wa1 := 1-b3[0].Frac, b3[0].Frac
|
||||
wb0, wb1 := 1-b3[1].Frac, b3[1].Frac
|
||||
wc0, wc1 := 1-b3[2].Frac, b3[2].Frac
|
||||
a0, a1 := b3[0].Lo, b3[0].Hi
|
||||
bb0, bb1 := b3[1].Lo, b3[1].Hi
|
||||
c0, c1 := b3[2].Lo, b3[2].Hi
|
||||
|
||||
return wa0*wb0*wc0*f(a0, bb0, c0) +
|
||||
wa0*wb0*wc1*f(a0, bb0, c1) +
|
||||
wa0*wb1*wc0*f(a0, bb1, c0) +
|
||||
wa0*wb1*wc1*f(a0, bb1, c1) +
|
||||
wa1*wb0*wc0*f(a1, bb0, c0) +
|
||||
wa1*wb0*wc1*f(a1, bb0, c1) +
|
||||
wa1*wb1*wc0*f(a1, bb1, c0) +
|
||||
wa1*wb1*wc1*f(a1, bb1, c1)
|
||||
}
|
||||
|
||||
// Lerp returns (1-l)*a + l*b.
|
||||
func Lerp(a, b, l float64) float64 {
|
||||
return (1-l)*a + l*b
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue