File: write.go

package info (click to toggle)
mumax3 3.11.1-1
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid
  • size: 10,668 kB
  • sloc: makefile: 194; ansic: 155; sh: 86; javascript: 16
file content (135 lines) | stat: -rw-r--r-- 2,830 bytes parent folder | download
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
135
package dump

import (
	"bufio"
	"hash"
	"hash/crc64"
	"io"
	"math"
	"os"
	"unsafe"

	"github.com/mumax/3/data"
	"github.com/mumax/3/util"
)

// 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) // precision

	// 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]
}