feat(decart): interp
This commit is contained in:
parent
1bd9143186
commit
19557f3a62
14 changed files with 681 additions and 208 deletions
|
|
@ -1,6 +1,9 @@
|
|||
package numerics
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// Axis describes a regularly-spaced grid axis with N grid points,
|
||||
// values left, left+step, left+2*step, ..., left+(N-1)*step.
|
||||
|
|
@ -28,27 +31,43 @@ func (e *AxisError) Error() string {
|
|||
|
||||
// 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).
|
||||
// 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).
|
||||
// The accepted range is closed at both ends: [Left, Left + (N-1)*Step] for a
|
||||
// non-wrapping axis, [Left, Left + N*Step] for a wrapping one.
|
||||
//
|
||||
// The upper end is closed deliberately. On the GFS latitude axis it is the
|
||||
// north pole, whose row holds real data — NCEP resolves it per longitude, so it
|
||||
// is a usable grid row like any other. Rejecting it used to abort the wind
|
||||
// lookup, and because the caller discarded that error the whole prediction
|
||||
// silently froze at latitude 90. The same argument applies to the last forecast
|
||||
// hour and the topmost pressure level.
|
||||
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 {
|
||||
// Bound-check in float space. Checking the truncated index instead would
|
||||
// let values just below Left through: int() truncates toward zero, so a pos
|
||||
// of -0.002 became index 0 rather than -1 and extrapolated off the end.
|
||||
if pos < 0 || pos > float64(maxLo+1) {
|
||||
return Bracket{}, &AxisError{Axis: a.Name, Value: value}
|
||||
}
|
||||
|
||||
lo := int(math.Floor(pos))
|
||||
// The exact upper bound belongs to the top cell at Frac 1, rather than
|
||||
// opening a cell that has no neighbour above it.
|
||||
if lo > maxLo {
|
||||
lo = maxLo
|
||||
}
|
||||
|
||||
hi := lo + 1
|
||||
if a.Wrap && hi == a.N {
|
||||
hi = 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue