comparison cmd/soundingresults/main.go @ 603:3d33c53db1e3

Sounding results: Read point data from xyz files.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Mon, 10 Sep 2018 12:10:10 +0200
parents 10f898bbe50f
children 4d97066c311c
comparison
equal deleted inserted replaced
602:10f898bbe50f 603:3d33c53db1e3
1 package main 1 package main
2 2
3 import ( 3 import (
4 "bufio" 4 "bufio"
5 "compress/bzip2"
6 "compress/gzip"
5 "database/sql" 7 "database/sql"
6 "flag" 8 "flag"
7 "fmt" 9 "fmt"
10 "io"
8 "log" 11 "log"
9 "os" 12 "os"
10 "path/filepath" 13 "path/filepath"
14 "runtime"
15 "strconv"
11 "strings" 16 "strings"
17 "sync"
12 "time" 18 "time"
13 19
14 "github.com/jackc/pgx" 20 "github.com/jackc/pgx"
15 "github.com/jackc/pgx/stdlib" 21 "github.com/jackc/pgx/stdlib"
16 ) 22 )
50 date time.Time 56 date time.Time
51 name string 57 name string
52 depthReference string 58 depthReference string
53 } 59 }
54 60
61 func wrap(fname string, f io.Reader) (io.Reader, error) {
62
63 switch strings.ToLower(filepath.Ext(fname)) {
64 case ".gz":
65 return gzip.NewReader(f)
66 case ".bz2":
67 return bzip2.NewReader(f), nil
68 }
69
70 return bufio.NewReader(f), nil
71 }
72
73 type point3d struct {
74 x float64
75 y float64
76 z float64
77 }
78
79 func parseXYZ(fname string) ([]*point3d, error) {
80 f, err := os.Open(fname)
81 if err != nil {
82 return nil, err
83 }
84 defer f.Close()
85
86 r, err := wrap(fname, f)
87 if err != nil {
88 return nil, err
89 }
90
91 // Alloc in larger chunks to reduce pressure on memory management.
92 var chunk []point3d
93 alloc := func() *point3d {
94 if len(chunk) == 0 {
95 chunk = make([]point3d, 8*1024)
96 }
97 p := &chunk[0]
98 chunk = chunk[1:]
99 return p
100 }
101
102 var points []*point3d
103
104 s := bufio.NewScanner(r)
105 if s.Scan() { // Skip header line.
106 for line := 2; s.Scan(); line++ {
107 p := alloc()
108 text := s.Text()
109 // fmt.Sscanf(text, "%f,%f,%f") is 4 times slower.
110 idx := strings.IndexByte(text, ',')
111 if idx == -1 {
112 log.Printf("format error in line %d\n", line)
113 continue
114 }
115 if p.x, err = strconv.ParseFloat(text[:idx], 64); err != nil {
116 log.Printf("format error in line %d: %v\n", line, err)
117 continue
118 }
119 text = text[idx+1:]
120 if idx = strings.IndexByte(text, ','); idx == -1 {
121 log.Printf("format error in line %d\n", line)
122 continue
123 }
124 if p.y, err = strconv.ParseFloat(text[:idx], 64); err != nil {
125 log.Printf("format error in line %d: %v\n", line, err)
126 continue
127 }
128 text = text[idx+1:]
129 if p.z, err = strconv.ParseFloat(text, 64); err != nil {
130 log.Printf("format error in line %d: %v\n", line, err)
131 continue
132 }
133 points = append(points, p)
134 }
135 }
136
137 return points, s.Err()
138 }
139
55 func substituteName(fname, name string) string { 140 func substituteName(fname, name string) string {
56 dir := filepath.Dir(fname) 141 dir := filepath.Dir(fname)
57 info := filepath.Join(dir, "INFO.txt") 142 info := filepath.Join(dir, "INFO.txt")
58 f, err := os.Open(info) 143 f, err := os.Open(info)
59 if err != nil { 144 if err != nil {
102 return meta{}, fmt.Errorf("%s is not in WGS84", base) 187 return meta{}, fmt.Errorf("%s is not in WGS84", base)
103 } 188 }
104 189
105 base = base[:len(base)-len("_WGS84")] 190 base = base[:len(base)-len("_WGS84")]
106 191
107 log.Printf("base: %s\n", base)
108
109 idx := strings.IndexRune(base, '_') 192 idx := strings.IndexRune(base, '_')
110 if idx == -1 { 193 if idx == -1 {
111 return meta{}, fmt.Errorf("%s has no date", base) 194 return meta{}, fmt.Errorf("%s has no date", base)
112 } 195 }
113 196
141 depthReference: depthReference, 224 depthReference: depthReference,
142 date: date, 225 date: date,
143 }, nil 226 }, nil
144 } 227 }
145 228
229 func processor(fnames <-chan string, wg *sync.WaitGroup) {
230 defer wg.Done()
231
232 for fname := range fnames {
233 log.Printf("Processing %s\n", fname)
234 m, err := parseFilename(fname)
235 if err != nil {
236 log.Printf("error: %v\n", err)
237 continue
238 }
239 _ = m
240 points, err := parseXYZ(fname)
241 if err != nil {
242 log.Printf("error: %v\n", err)
243 continue
244 }
245 fmt.Printf("Number of points: %d\n", len(points))
246 }
247 }
248
146 func main() { 249 func main() {
147 flag.Parse() 250 flag.Parse()
148 251
252 var wg sync.WaitGroup
253
254 fnames := make(chan string)
255
256 for i, n := 0, runtime.NumCPU(); i < n; i++ {
257 wg.Add(1)
258 go processor(fnames, &wg)
259 }
260
149 for _, fname := range flag.Args() { 261 for _, fname := range flag.Args() {
150 m, err := parseFilename(fname) 262 fnames <- fname
151 if err != nil { 263 }
152 log.Printf("error: %s\n", err) 264
153 continue 265 close(fnames)
154 } 266
155 fmt.Printf("%q\n", m) 267 wg.Wait()
156 } 268 }
157 }