-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwrite.go
134 lines (114 loc) · 2.76 KB
/
write.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package dump
import (
"bufio"
"github.com/mumax/3/data"
"github.com/mumax/3/util"
"hash"
"hash/crc64"
"io"
"math"
"os"
"unsafe"
)
// Write the slice to out in binary format. Add time stamp.
func Write(out io.Writer, s *data.Slice, info data.Meta) error {
w := newWriter(out)
// Writes the header.
w.writeString(MAGIC)
w.writeUInt64(uint64(s.NComp()))
size := s.Size()
w.writeUInt64(uint64(size[2])) // backwards compatible coordinates!
w.writeUInt64(uint64(size[1]))
w.writeUInt64(uint64(size[0]))
cell := info.CellSize
w.writeFloat64(cell[2])
w.writeFloat64(cell[1])
w.writeFloat64(cell[0])
w.writeString(info.MeshUnit)
w.writeFloat64(info.Time)
w.writeString("s") // time unit
w.writeString(info.Name)
w.writeString(info.Unit)
w.writeUInt64(4) // precission
// return header write error before writing data
if w.err != nil {
return w.err
}
w.writeData(s)
w.writeHash()
return w.err
}
// Write the slice to file in binary format. Add time stamp.
func WriteFile(fname string, s *data.Slice, info data.Meta) error {
f, err := os.OpenFile(fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
w := bufio.NewWriter(f)
defer w.Flush()
return Write(w, s, info)
}
// Write the slice to file in binary format, panic on error.
func MustWriteFile(fname string, s *data.Slice, info data.Meta) {
err := WriteFile(fname, s, info)
util.FatalErr(err)
}
var table = crc64.MakeTable(crc64.ISO)
type writer struct {
out io.Writer
crc hash.Hash64
err error
}
func newWriter(out io.Writer) *writer {
w := new(writer)
w.crc = crc64.New(table)
w.out = io.MultiWriter(w.crc, out)
return w
}
const MAGIC = "#dump002" // identifies dump format
// Writes the data.
func (w *writer) writeData(array *data.Slice) {
data := array.Tensors()
size := array.Size()
ncomp := array.NComp()
for c := 0; c < ncomp; c++ {
for iz := 0; iz < size[2]; iz++ {
for iy := 0; iy < size[1]; iy++ {
for ix := 0; ix < size[0]; ix++ {
w.writeFloat32(data[c][iz][iy][ix])
}
}
}
}
}
// Writes the accumulated hash of this frame, closing the frame.
func (w *writer) writeHash() {
w.writeUInt64(w.crc.Sum64())
w.crc.Reset()
}
func (w *writer) count(n int, err error) {
if err != nil && w.err == nil {
w.err = err
}
}
func (w *writer) writeFloat32(x float32) {
var bytes []byte
bytes = (*[4]byte)(unsafe.Pointer(&x))[:]
w.count(w.out.Write(bytes))
}
func (w *writer) writeFloat64(x float64) {
w.writeUInt64(math.Float64bits(x))
}
func (w *writer) writeString(x string) {
var buf [8]byte
copy(buf[:], x)
w.count(w.out.Write(buf[:]))
}
func (w *writer) writeUInt64(x uint64) {
w.count(w.out.Write((*(*[8]byte)(unsafe.Pointer(&x)))[:8]))
}
// product of elements.
func prod(size [3]int) int {
return size[0] * size[1] * size[2]
}