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 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
package engine
import (
"fmt"
"path"
"reflect"
"strings"
"github.com/mumax/3/cuda"
"github.com/mumax/3/data"
"github.com/mumax/3/draw"
"github.com/mumax/3/dump"
"github.com/mumax/3/httpfs"
"github.com/mumax/3/oommf"
"github.com/mumax/3/util"
)
func init() {
DeclFunc("Save", Save, "Save space-dependent quantity once, with auto filename")
DeclFunc("SaveAs", SaveAs, "Save space-dependent quantity with custom filename")
DeclLValue("FilenameFormat", &fformat{}, "printf formatting string for output filenames.")
DeclLValue("OutputFormat", &oformat{}, "Format for data files: OVF1_TEXT, OVF1_BINARY, OVF2_TEXT or OVF2_BINARY")
DeclROnly("OVF1_BINARY", OVF1_BINARY, "OutputFormat = OVF1_BINARY sets binary OVF1 output")
DeclROnly("OVF2_BINARY", OVF2_BINARY, "OutputFormat = OVF2_BINARY sets binary OVF2 output")
DeclROnly("OVF1_TEXT", OVF1_TEXT, "OutputFormat = OVF1_TEXT sets text OVF1 output")
DeclROnly("OVF2_TEXT", OVF2_TEXT, "OutputFormat = OVF2_TEXT sets text OVF2 output")
DeclROnly("DUMP", DUMP, "OutputFormat = DUMP sets text DUMP output")
DeclFunc("Snapshot", Snapshot, "Save image of quantity")
DeclFunc("SnapshotAs", SnapshotAs, "Save image of quantity with custom filename")
DeclVar("SnapshotFormat", &SnapshotFormat, "Image format for snapshots: jpg, png or gif.")
}
var (
FilenameFormat = "%s%06d" // formatting string for auto filenames.
SnapshotFormat = "jpg" // user-settable snapshot format
outputFormat = OVF2_BINARY // user-settable output format
)
type fformat struct{}
func (*fformat) Eval() interface{} { return FilenameFormat }
func (*fformat) SetValue(v interface{}) { drainOutput(); FilenameFormat = v.(string) }
func (*fformat) Type() reflect.Type { return reflect.TypeOf("") }
type oformat struct{}
func (*oformat) Eval() interface{} { return outputFormat }
func (*oformat) SetValue(v interface{}) { drainOutput(); outputFormat = v.(OutputFormat) }
func (*oformat) Type() reflect.Type { return reflect.TypeOf(OutputFormat(OVF2_BINARY)) }
// Save once, with auto file name
func Save(q Quantity) {
qname := NameOf(q)
fname := autoFname(NameOf(q), outputFormat, autonum[qname])
SaveAs(q, fname)
autonum[qname]++
}
// Save under given file name (transparent async I/O).
func SaveAs(q Quantity, fname string) {
if !strings.HasPrefix(fname, OD()) {
fname = OD() + fname // don't clean, turns http:// in http:/
}
if path.Ext(fname) == "" {
fname += ("." + StringFromOutputFormat[outputFormat])
}
buffer := ValueOf(q) // TODO: check and optimize for Buffer()
defer cuda.Recycle(buffer)
info := data.Meta{Time: Time, Name: NameOf(q), Unit: UnitOf(q), CellSize: MeshOf(q).CellSize()}
data := buffer.HostCopy() // must be copy (async io)
queOutput(func() { saveAs_sync(fname, data, info, outputFormat) })
}
// Save image once, with auto file name
func Snapshot(q Quantity) {
qname := NameOf(q)
fname := fmt.Sprintf(OD()+FilenameFormat+"."+SnapshotFormat, qname, autonum[qname])
s := ValueOf(q)
defer cuda.Recycle(s)
data := s.HostCopy() // must be copy (asyncio)
queOutput(func() { snapshot_sync(fname, data) })
autonum[qname]++
}
func SnapshotAs(q Quantity, fname string) {
if !strings.HasPrefix(fname, OD()) {
fname = OD() + fname // don't clean, turns http:// in http:/
}
if path.Ext(fname) == "" {
fname += ("." + StringFromOutputFormat[outputFormat])
}
s := ValueOf(q)
defer cuda.Recycle(s)
data := s.HostCopy() // must be copy (asyncio)
queOutput(func() { snapshot_sync(fname, data) })
}
// synchronous snapshot
func snapshot_sync(fname string, output *data.Slice) {
f, err := httpfs.Create(fname)
util.FatalErr(err)
defer f.Close()
draw.RenderFormat(f, output, "auto", "auto", arrowSize, path.Ext(fname))
}
// synchronous save
func saveAs_sync(fname string, s *data.Slice, info data.Meta, format OutputFormat) {
f, err := httpfs.Create(fname)
util.FatalErr(err)
defer f.Close()
switch format {
case OVF1_TEXT:
oommf.WriteOVF1(f, s, info, "text")
case OVF1_BINARY:
oommf.WriteOVF1(f, s, info, "binary 4")
case OVF2_TEXT:
oommf.WriteOVF2(f, s, info, "text")
case OVF2_BINARY:
oommf.WriteOVF2(f, s, info, "binary 4")
case DUMP:
dump.Write(f, s, info)
default:
panic("invalid output format")
}
}
type OutputFormat int
const (
OVF1_TEXT OutputFormat = iota + 1
OVF1_BINARY
OVF2_TEXT
OVF2_BINARY
DUMP
)
var (
StringFromOutputFormat = map[OutputFormat]string{
OVF1_TEXT: "ovf",
OVF1_BINARY: "ovf",
OVF2_TEXT: "ovf",
OVF2_BINARY: "ovf",
DUMP: "dump"}
)
|