Skip to content

Commit

Permalink
Fixed findDateFactor to return error (#30)
Browse files Browse the repository at this point in the history
* Fixed `findDateFactor` to return error
  • Loading branch information
proway2 authored May 7, 2022
1 parent e1e6ff8 commit 59feeae
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 39 deletions.
7 changes: 5 additions & 2 deletions coeffs/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (igrf *IGRFcoeffs) Coeffs(date float64) (*[]float64, *[]float64, int, error
min_epoch := (*igrf.epochs)[0]
max_epoch := (*igrf.epochs)[max_column-1]
if date < min_epoch || date > max_epoch {
return nil, nil, 0, errors.New(fmt.Sprintf("Date %v is out of range (%v, %v).", date, min_epoch, max_epoch))
return nil, nil, 0, fmt.Errorf("Date %v is out of range (%v, %v).", date, min_epoch, max_epoch)
}
// calculate coeffs for the requested date
start, end := igrf.findEpochs(date)
Expand All @@ -66,7 +66,10 @@ func (igrf *IGRFcoeffs) Coeffs(date float64) (*[]float64, *[]float64, int, error
}

func (igrf *IGRFcoeffs) interpolateCoeffs(start_epoch, end_epoch string, date float64) (*[]float64, int) {
factor := findDateFactor(start_epoch, end_epoch, date)
factor, err := findDateFactor(start_epoch, end_epoch, date)
if err != nil {
log.Fatal("Epochs are incorrect!")
}
coeffs_start := (*igrf.data)[start_epoch].coeffs
coeffs_end := (*igrf.data)[end_epoch].coeffs
values := make([]float64, len(*coeffs_start))
Expand Down
19 changes: 19 additions & 0 deletions coeffs/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ func TestIGRFcoeffs_Coeffs(t *testing.T) {
want3: 13,
wantErr: false,
},
{
name: "1024.5: Date below the starting epoch..",
args: args{date: 1024.5},
want1: nil,
want2: nil,
want3: 0,
wantErr: true,
},
{
name: "3024.5: Date beyond the ending epoch..",
args: args{date: 3024.5},
want1: nil,
want2: nil,
want3: 0,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand All @@ -86,6 +102,9 @@ func TestIGRFcoeffs_Coeffs(t *testing.T) {
t.Errorf("IGRFcoeffs.Coeffs() nmax got %v, wanted %v", got3, tt.want3)
return
}
if err != nil {
return
}
for index, value1 := range *got1 {
value2 := (*got2)[index]
ref_value1 := math.Abs((*tt.want1)[index])
Expand Down
43 changes: 36 additions & 7 deletions coeffs/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import (
"bufio"
"errors"
"fmt"
"log"
"regexp"
"strconv"
"strings"
)

var comment_line *regexp.Regexp = regexp.MustCompile(`^\s*#.*`)

// Calculates the number of seconds per year, respects leap years.
func secsInYear(year int) int {
var days_per_year int = 365
if isLeapYear(year) {
Expand All @@ -21,21 +21,37 @@ func secsInYear(year int) int {
return days_per_year * secs_per_day
}

// Returns whether the given year is leap or not.
func isLeapYear(year int) bool {
isDivisibleBy4 := year%4 == 0
isDivisibleBy100 := year%100 == 0
isDivisibleBy400 := year%400 == 0
return isDivisibleBy400 || (isDivisibleBy4 && !isDivisibleBy100)
}

func findDateFactor(start_epoch, end_epoch string, date float64) float64 {
dte1, _ := strconv.ParseFloat(start_epoch, 32)
dte2, _ := strconv.ParseFloat(end_epoch, 32)
// Finds the factor for a given `date` between two epochs.
// In the first approximation the factor is calculated like:
//
// factor = (date - start_epoch) / (end_epoch - start_epoch)
//
// This is the coarse approach and the actual factor is calculated with respect to the leap years,
// unless `date` is beyond the `end_epoch`. In this case the above formula is used.
//
// If `end_epoch` is less or equal to `start_epoch` - 0 is returned, no negative values returned.
//
// In case of no correct epochs are provided, error is returned.
func findDateFactor(start_epoch, end_epoch string, date float64) (float64, error) {
parser := errParser{}
dte1 := parser.parseFloat(start_epoch)
dte2 := parser.parseFloat(end_epoch)
if parser.err != nil {
return -999, fmt.Errorf("Epoch(s) cannot be parsed, start:%v, end:%v", start_epoch, end_epoch)
}
if dte2 <= dte1 {
log.Fatalf("End epoch %v is less than start epoch %v", end_epoch, start_epoch)
return 0, nil
}
if date > dte2 {
return (date - dte1) / (dte2 - dte1)
return (date - dte1) / (dte2 - dte1), nil
}
loc_interval := int(dte2) - int(dte1)
var total_secs, fraction_secs float64
Expand All @@ -49,7 +65,7 @@ func findDateFactor(start_epoch, end_epoch string, date float64) float64 {
total_secs += float64(secs_in_year)
}
factor := fraction_secs / total_secs
return factor
return factor, nil
}

// coeffsLineProvider - reads lines from raw coeffs data, omits comments
Expand Down Expand Up @@ -91,3 +107,16 @@ func parseArrayToFloat(raw_data []string) (*[]float64, error) {
}
return &data, nil
}

type errParser struct {
err error
}

func (p *errParser) parseFloat(v string) float64 {
if p.err != nil {
return 0
}
var value float64
value, p.err = strconv.ParseFloat(v, 64)
return value
}
83 changes: 53 additions & 30 deletions coeffs/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,58 +77,81 @@ func Test_secsInYear(t *testing.T) {
}
}

func Test_findDateFraction(t *testing.T) {
func Test_findDateFactor(t *testing.T) {
type args struct {
start_epoch string
end_epoch string
date float64
}
tests := []struct {
name string
args args
want float64
name string
args args
want float64
wantErr bool
}{
{
name: "Exact match (start epoch)",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1900.0},
want: 0.0,
name: "Exact match (start epoch)",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1900.0},
want: 0.0,
wantErr: false,
},
{
name: "Exact match (end epoch)",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1910.0},
want: 0.0,
name: "Exact match (end epoch)",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1910.0},
want: 0.0,
wantErr: false,
},
// this generates os.Exit(1)
// {
// name: "End epoch is less than start epoch",
// args: args{start_epoch: "1910.0", end_epoch: "1900.0", date: 1910.0},
// want: 1.0,
// },
{
name: "Middle",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1905.0},
want: 0.5,
name: "End epoch is less than start epoch",
args: args{start_epoch: "1910.0", end_epoch: "1900.0", date: 1910.0},
want: 0.0,
wantErr: false,
},
{
name: "1950.01",
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1950.01},
want: 0.001998904709746265,
name: "Middle",
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1905.0},
want: 0.5,
wantErr: false,
},
{
name: "1950.99",
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1954.99},
want: 0.9980010952902538,
name: "1950.01",
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1950.01},
want: 0.001998904709746265,
wantErr: false,
},
{
name: "2025.5",
args: args{start_epoch: "2020.0", end_epoch: "2025.0", date: 2025.5},
want: 1.1,
name: "1950.99",
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1954.99},
want: 0.9980010952902538,
wantErr: false,
},
{
name: "2025.5",
args: args{start_epoch: "2020.0", end_epoch: "2025.0", date: 2025.5},
want: 1.1,
wantErr: false,
},
{
name: "Incorrect start_epoch",
args: args{start_epoch: "start_epoch", end_epoch: "2025.0", date: 2025.5},
want: -999,
wantErr: true,
},
{
name: "Incorrect end_epoch",
args: args{start_epoch: "2020.0", end_epoch: "end_epoch", date: 2025.5},
want: -999,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := findDateFactor(tt.args.start_epoch, tt.args.end_epoch, tt.args.date)
if !almostEqual(got, tt.want, 1e6) {
got, err := findDateFactor(tt.args.start_epoch, tt.args.end_epoch, tt.args.date)
if (err != nil) && !tt.wantErr {
t.Errorf("findDateFactor() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !almostEqual(got, tt.want, 1e8) {
t.Errorf("findDateFraction() = %v, want %v", got, tt.want)
}
})
Expand Down

0 comments on commit 59feeae

Please sign in to comment.