-
Notifications
You must be signed in to change notification settings - Fork 65
Snippets
Cyrus Harrison edited this page Dec 12, 2022
·
6 revisions
parse binary stl file and convert to blueprint
import conduit
def parse_binary(data):
res = conduit.Node()
# todo: optional header parse
# read # of triangles
tmp = conduit.Node()
stmp = conduit.Schema()
stmp.set(conduit.DataType.uint32(1,80))
tmp.set_external(stmp,data)
ntris = tmp.value()
# setup mesh bp
# coords
res["coordsets/coords/type"] = "explicit"
res["coordsets/coords/values/x"].set(conduit.DataType.float64(ntris * 3))
res["coordsets/coords/values/y"].set(conduit.DataType.float64(ntris * 3))
res["coordsets/coords/values/z"].set(conduit.DataType.float64(ntris * 3))
x_vals = res["coordsets/coords/values/x"]
y_vals = res["coordsets/coords/values/y"]
z_vals = res["coordsets/coords/values/z"]
# topo
res["topologies/topo/type"] = "unstructured"
res["topologies/topo/coordset"] = "coords"
res["topologies/topo/elements/shape"] = "tri"
res["topologies/topo/elements/connectivity"].set(conduit.DataType.uint32(ntris * 3))
conn_vals = res["topologies/topo/elements/connectivity"]
# also expose coordset as point mesh
res["topologies/topo_pts/type"] = "points"
res["topologies/topo_pts/coordset"] = "coords"
# fields
# normals (vec)
res["fields/normal/association"] = "element"
res["fields/normal/topology"] = "topo"
res["fields/normal/values/x"].set(conduit.DataType.float64(ntris))
res["fields/normal/values/y"].set(conduit.DataType.float64(ntris))
res["fields/normal/values/z"].set(conduit.DataType.float64(ntris))
nx_vals = res["fields/normal/values/x"]
ny_vals = res["fields/normal/values/y"]
nz_vals = res["fields/normal/values/z"]
# attrib (store as 32-bit int)
res["fields/attrib/association"] = "element"
res["fields/attrib/topology"] = "topo"
res["fields/attrib/values"].set(conduit.DataType.int64(ntris))
attr_vals = res["fields/attrib/values"]
#
# start reading tris
#
byte_offset = 84
print("number of triangles {0}".format(ntris))
for i in range(ntris):
# per tri schema
stmp = conduit.Schema()
stmp["normal"].set(conduit.DataType.float32(3,byte_offset))
stmp["v1"].set(conduit.DataType.float32(3,byte_offset + 12))
stmp["v2"].set(conduit.DataType.float32(3,byte_offset + 24))
stmp["v3"].set(conduit.DataType.float32(3,byte_offset + 36))
stmp["attr"].set(conduit.DataType.uint16(1,byte_offset + 48))
tmp.set_external(stmp,data)
byte_offset += stmp.total_bytes_compact()
# add verts to coordset
tri_offset = i*3
x_vals[tri_offset] = tmp["v1"][0]
y_vals[tri_offset] = tmp["v1"][1]
z_vals[tri_offset] = tmp["v1"][2]
x_vals[tri_offset+1] = tmp["v2"][0]
y_vals[tri_offset+1] = tmp["v2"][1]
z_vals[tri_offset+1] = tmp["v2"][2]
x_vals[tri_offset+2] = tmp["v3"][0]
y_vals[tri_offset+2] = tmp["v3"][1]
z_vals[tri_offset+2] = tmp["v3"][2]
# add entry to topo
conn_vals[tri_offset + 2 ] = tri_offset
conn_vals[tri_offset + 1 ] = tri_offset + 1
conn_vals[tri_offset + 0 ] = tri_offset + 2
# add atts to atts field
attr_vals[i] = tmp["attr"]
# add normal to normals field
nx_vals[i] = tmp["normal"][0]
ny_vals[i] = tmp["normal"][1]
nz_vals[i] = tmp["normal"][2]
print("done parsing")
return res
def check_stl_style(data):
n = conduit.Node()
s = conduit.Schema()
s.set(conduit.DataType.char8_str(80))
n.set(s,data)
sval = n.value()
res = conduit.Node()
if sval.count("shape") > 0:
return "ascii"
else:
return "binary"
def parse_stl(fname,ofname):
print(fname)
with open(fname,"rb")as f:
data = f.read()
print("done reading")
print(len(data))
# read the first 80 bytes, first as string to
# test if we have ascii or binary stl file
ftype = check_stl_style(data)
if ftype == "ascii":
print("ascii, not supported yet")
return
#res = parse_ascii(fname)
else:
print("binary")
res= parse_binary(data)
if not res.dtype().is_empty():
conduit.relay.io.blueprint.save_mesh(res, ofname,"hdf5")
helper to convert a bov (bof) file to a mesh bp uniform mesh
import conduit
import conduit.blueprint
import conduit.relay
import numpy as np
def bov_to_blueprint(fname):
res = conduit.Node()
ls = open(fname).readlines()
res["coordsets/coords/type"] = "uniform";
dinfo = conduit.Node()
# parse meta data lines
for l in ls:
if not l.strip() == "" and not l.strip().startswith("#"):
key, val = l.strip().split(":")
print(key,val)
# entries we care about:
if key == "DATA FILE":
# read data
pass
elif key == "DATA SIZE":
# shape of grid
vals = [ int(v) for v in val.split()]
res["coordsets/coords/dims/i"] = vals[0]
dinfo["npts"] = vals[0]
dinfo["neles"] = vals[0]-1
if len(vals) > 1:
res["coordsets/coords/dims/j"] = vals[1]
dinfo["npts"] *= vals[1]
dinfo["neles"] *= vals[1]-1
if len(vals) > 2:
res["coordsets/coords/dims/k"] = vals[2]
dinfo["npts"] *= vals[2]
dinfo["neles"] *= vals[2]-1
elif key == "BRICK ORIGIN":
# where we start in space
vals = [ float(v) for v in val.split()]
res["coordsets/coords/origin/x"] = vals[0]
if len(vals) > 1:
res["coordsets/coords/origin/y"] = vals[1]
if len(vals) > 2:
res["coordsets/coords/origin/z"] = vals[2]
elif key == "BRICK SIZE":
# use to get dx,dy,dz
# note, this assumes that DATA SIZE
# is presented before we parse this info
vals = [ float(v) for v in val.split()]
res["coordsets/coords/spacing/dx"] = vals[0]/ float(res["coordsets/coords/dims/i"]-1)
if len(vals) > 1:
res["coordsets/coords/spacing/dy"]= vals[1]/ float(res["coordsets/coords/dims/j"]-1)
if len(vals) > 2:
res["coordsets/coords/spacing/dz"]= vals[2]/ float(res["coordsets/coords/dims/k"]-1)
elif key == "DATA_FILE":
dinfo["file"] = val.strip()
elif key == "DATA FORMAT":
dinfo["format"] = val.strip().lower()
elif key == "VARIABLE":
if val.count('"') > 0:
val = val.replace('"','')
if val.count('/') > 0:
val = val[val.find("/"):]
dinfo["name"] = val
# describe our topo
res["topologies/topo/type"] = "uniform"
res["topologies/topo/coordset"] = "coords"
# now read the data and create a field
np_dtype = np.float64
if dinfo["format"] == "floats":
np_dtype = np.float32
val_array =np.fromfile(dinfo["file"],np_dtype)
n_field = res["fields"][dinfo["name"]]
n_field["association"]="vertex"
n_field["topology"]="topo"
n_field["values"]= val_array
info = conduit.Node()
if not conduit.blueprint.mesh.verify(res,info):
print("Mesh Verify Failed!")
print(info.to_yaml())
return res
Python to create blueprint json file with a uniform mesh, readable by VisIt's Blueprint plugin. (VisIt 3.0)
import conduit
import conduit.blueprint
import numpy as np
ofname = "basic_uniform.root"
protocol = "json"
n = conduit.Node()
n["mesh/coordsets/coords/type"] = "uniform"
n["mesh/coordsets/coords/dims/i"] = 21
n["mesh/coordsets/coords/dims/j"] = 31
n["mesh/topologies/topo/type"] = "uniform"
n["mesh/topologies/topo/coordset"] = "coords"
n["mesh/fields/vals/association"] = "element"
n["mesh/fields/vals/topology"] = "topo"
n["mesh/fields/vals/values"] = np.linspace(0.0, 20 * 30, num=(20 * 30))
conduit.blueprint.mesh.generate_index(n["mesh"],
"mesh",
1,
n["blueprint_index/mesh"])
n["protocol/name"] = protocol
n["protocol/version"] = "0.4.0";
n["number_of_files"] = 1;
n["number_of_trees"] = 1;
n["file_pattern"] = ofname;
n["tree_pattern"] = "/";
n.save(ofname,protocol)