Skip to content

Commit 59feeae

Browse files
authored
Fixed findDateFactor to return error (#30)
* Fixed `findDateFactor` to return error
1 parent e1e6ff8 commit 59feeae

File tree

4 files changed

+113
-39
lines changed

4 files changed

+113
-39
lines changed

coeffs/read.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func (igrf *IGRFcoeffs) Coeffs(date float64) (*[]float64, *[]float64, int, error
4848
min_epoch := (*igrf.epochs)[0]
4949
max_epoch := (*igrf.epochs)[max_column-1]
5050
if date < min_epoch || date > max_epoch {
51-
return nil, nil, 0, errors.New(fmt.Sprintf("Date %v is out of range (%v, %v).", date, min_epoch, max_epoch))
51+
return nil, nil, 0, fmt.Errorf("Date %v is out of range (%v, %v).", date, min_epoch, max_epoch)
5252
}
5353
// calculate coeffs for the requested date
5454
start, end := igrf.findEpochs(date)
@@ -66,7 +66,10 @@ func (igrf *IGRFcoeffs) Coeffs(date float64) (*[]float64, *[]float64, int, error
6666
}
6767

6868
func (igrf *IGRFcoeffs) interpolateCoeffs(start_epoch, end_epoch string, date float64) (*[]float64, int) {
69-
factor := findDateFactor(start_epoch, end_epoch, date)
69+
factor, err := findDateFactor(start_epoch, end_epoch, date)
70+
if err != nil {
71+
log.Fatal("Epochs are incorrect!")
72+
}
7073
coeffs_start := (*igrf.data)[start_epoch].coeffs
7174
coeffs_end := (*igrf.data)[end_epoch].coeffs
7275
values := make([]float64, len(*coeffs_start))

coeffs/read_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,22 @@ func TestIGRFcoeffs_Coeffs(t *testing.T) {
7474
want3: 13,
7575
wantErr: false,
7676
},
77+
{
78+
name: "1024.5: Date below the starting epoch..",
79+
args: args{date: 1024.5},
80+
want1: nil,
81+
want2: nil,
82+
want3: 0,
83+
wantErr: true,
84+
},
85+
{
86+
name: "3024.5: Date beyond the ending epoch..",
87+
args: args{date: 3024.5},
88+
want1: nil,
89+
want2: nil,
90+
want3: 0,
91+
wantErr: true,
92+
},
7793
}
7894
for _, tt := range tests {
7995
t.Run(tt.name, func(t *testing.T) {
@@ -86,6 +102,9 @@ func TestIGRFcoeffs_Coeffs(t *testing.T) {
86102
t.Errorf("IGRFcoeffs.Coeffs() nmax got %v, wanted %v", got3, tt.want3)
87103
return
88104
}
105+
if err != nil {
106+
return
107+
}
89108
for index, value1 := range *got1 {
90109
value2 := (*got2)[index]
91110
ref_value1 := math.Abs((*tt.want1)[index])

coeffs/utils.go

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ import (
44
"bufio"
55
"errors"
66
"fmt"
7-
"log"
87
"regexp"
98
"strconv"
109
"strings"
1110
)
1211

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

14+
// Calculates the number of seconds per year, respects leap years.
1515
func secsInYear(year int) int {
1616
var days_per_year int = 365
1717
if isLeapYear(year) {
@@ -21,21 +21,37 @@ func secsInYear(year int) int {
2121
return days_per_year * secs_per_day
2222
}
2323

24+
// Returns whether the given year is leap or not.
2425
func isLeapYear(year int) bool {
2526
isDivisibleBy4 := year%4 == 0
2627
isDivisibleBy100 := year%100 == 0
2728
isDivisibleBy400 := year%400 == 0
2829
return isDivisibleBy400 || (isDivisibleBy4 && !isDivisibleBy100)
2930
}
3031

31-
func findDateFactor(start_epoch, end_epoch string, date float64) float64 {
32-
dte1, _ := strconv.ParseFloat(start_epoch, 32)
33-
dte2, _ := strconv.ParseFloat(end_epoch, 32)
32+
// Finds the factor for a given `date` between two epochs.
33+
// In the first approximation the factor is calculated like:
34+
//
35+
// factor = (date - start_epoch) / (end_epoch - start_epoch)
36+
//
37+
// This is the coarse approach and the actual factor is calculated with respect to the leap years,
38+
// unless `date` is beyond the `end_epoch`. In this case the above formula is used.
39+
//
40+
// If `end_epoch` is less or equal to `start_epoch` - 0 is returned, no negative values returned.
41+
//
42+
// In case of no correct epochs are provided, error is returned.
43+
func findDateFactor(start_epoch, end_epoch string, date float64) (float64, error) {
44+
parser := errParser{}
45+
dte1 := parser.parseFloat(start_epoch)
46+
dte2 := parser.parseFloat(end_epoch)
47+
if parser.err != nil {
48+
return -999, fmt.Errorf("Epoch(s) cannot be parsed, start:%v, end:%v", start_epoch, end_epoch)
49+
}
3450
if dte2 <= dte1 {
35-
log.Fatalf("End epoch %v is less than start epoch %v", end_epoch, start_epoch)
51+
return 0, nil
3652
}
3753
if date > dte2 {
38-
return (date - dte1) / (dte2 - dte1)
54+
return (date - dte1) / (dte2 - dte1), nil
3955
}
4056
loc_interval := int(dte2) - int(dte1)
4157
var total_secs, fraction_secs float64
@@ -49,7 +65,7 @@ func findDateFactor(start_epoch, end_epoch string, date float64) float64 {
4965
total_secs += float64(secs_in_year)
5066
}
5167
factor := fraction_secs / total_secs
52-
return factor
68+
return factor, nil
5369
}
5470

5571
// coeffsLineProvider - reads lines from raw coeffs data, omits comments
@@ -91,3 +107,16 @@ func parseArrayToFloat(raw_data []string) (*[]float64, error) {
91107
}
92108
return &data, nil
93109
}
110+
111+
type errParser struct {
112+
err error
113+
}
114+
115+
func (p *errParser) parseFloat(v string) float64 {
116+
if p.err != nil {
117+
return 0
118+
}
119+
var value float64
120+
value, p.err = strconv.ParseFloat(v, 64)
121+
return value
122+
}

coeffs/utils_test.go

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -77,58 +77,81 @@ func Test_secsInYear(t *testing.T) {
7777
}
7878
}
7979

80-
func Test_findDateFraction(t *testing.T) {
80+
func Test_findDateFactor(t *testing.T) {
8181
type args struct {
8282
start_epoch string
8383
end_epoch string
8484
date float64
8585
}
8686
tests := []struct {
87-
name string
88-
args args
89-
want float64
87+
name string
88+
args args
89+
want float64
90+
wantErr bool
9091
}{
9192
{
92-
name: "Exact match (start epoch)",
93-
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1900.0},
94-
want: 0.0,
93+
name: "Exact match (start epoch)",
94+
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1900.0},
95+
want: 0.0,
96+
wantErr: false,
9597
},
9698
{
97-
name: "Exact match (end epoch)",
98-
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1910.0},
99-
want: 0.0,
99+
name: "Exact match (end epoch)",
100+
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1910.0},
101+
want: 0.0,
102+
wantErr: false,
100103
},
101-
// this generates os.Exit(1)
102-
// {
103-
// name: "End epoch is less than start epoch",
104-
// args: args{start_epoch: "1910.0", end_epoch: "1900.0", date: 1910.0},
105-
// want: 1.0,
106-
// },
107104
{
108-
name: "Middle",
109-
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1905.0},
110-
want: 0.5,
105+
name: "End epoch is less than start epoch",
106+
args: args{start_epoch: "1910.0", end_epoch: "1900.0", date: 1910.0},
107+
want: 0.0,
108+
wantErr: false,
111109
},
112110
{
113-
name: "1950.01",
114-
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1950.01},
115-
want: 0.001998904709746265,
111+
name: "Middle",
112+
args: args{start_epoch: "1900.0", end_epoch: "1910.0", date: 1905.0},
113+
want: 0.5,
114+
wantErr: false,
116115
},
117116
{
118-
name: "1950.99",
119-
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1954.99},
120-
want: 0.9980010952902538,
117+
name: "1950.01",
118+
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1950.01},
119+
want: 0.001998904709746265,
120+
wantErr: false,
121121
},
122122
{
123-
name: "2025.5",
124-
args: args{start_epoch: "2020.0", end_epoch: "2025.0", date: 2025.5},
125-
want: 1.1,
123+
name: "1950.99",
124+
args: args{start_epoch: "1950.0", end_epoch: "1955.0", date: 1954.99},
125+
want: 0.9980010952902538,
126+
wantErr: false,
127+
},
128+
{
129+
name: "2025.5",
130+
args: args{start_epoch: "2020.0", end_epoch: "2025.0", date: 2025.5},
131+
want: 1.1,
132+
wantErr: false,
133+
},
134+
{
135+
name: "Incorrect start_epoch",
136+
args: args{start_epoch: "start_epoch", end_epoch: "2025.0", date: 2025.5},
137+
want: -999,
138+
wantErr: true,
139+
},
140+
{
141+
name: "Incorrect end_epoch",
142+
args: args{start_epoch: "2020.0", end_epoch: "end_epoch", date: 2025.5},
143+
want: -999,
144+
wantErr: true,
126145
},
127146
}
128147
for _, tt := range tests {
129148
t.Run(tt.name, func(t *testing.T) {
130-
got := findDateFactor(tt.args.start_epoch, tt.args.end_epoch, tt.args.date)
131-
if !almostEqual(got, tt.want, 1e6) {
149+
got, err := findDateFactor(tt.args.start_epoch, tt.args.end_epoch, tt.args.date)
150+
if (err != nil) && !tt.wantErr {
151+
t.Errorf("findDateFactor() error = %v, wantErr %v", err, tt.wantErr)
152+
return
153+
}
154+
if !almostEqual(got, tt.want, 1e8) {
132155
t.Errorf("findDateFraction() = %v, want %v", got, tt.want)
133156
}
134157
})

0 commit comments

Comments
 (0)