better xdmf support

This commit is contained in:
Jukka Aho
2016-08-02 02:51:32 +03:00
parent 62efaa292a
commit e67422fa7c
6 changed files with 270 additions and 83 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ module Testing
end
include("io.jl")
export ModelIO
export Xdmf, h5file, xmffile, has_child, get_child, new_dataitem
include("fields.jl")
export Field, DCTI, DVTI, DCTV, DVTV, CCTI, CVTI, CCTV, CVTV, Increment
+145 -28
View File
@@ -3,51 +3,168 @@
using HDF5
using LightXML
importall LightXML
importall Base
type ModelIO
function new_element(name::AbstractString, attrs::Dict)
x = new_element(name)
for (k, v) in attrs
x[k] = v
end
return x
end
function setindex!(x::XMLElement, content::Any, attr_name::AbstractString)
set_attribute(x, attr_name, content)
end
function haskey(x::XMLElement, key::AbstractString)
return has_child(x, key) || has_attribute(x, key)
end
function get_child(x::XMLElement, child_name::AbstractString)
'/' in child_name && return nothing
m = match(r"(\w+)\[(.+)\]", child_name)
if m != nothing
child_name = m[1]
end
childs = []
for child in child_elements(x)
if name(child) == child_name
push!(childs, child)
end
end
length(childs) == 0 && return nothing
m == nothing && return first(childs)
j = tryparse(Int, m[2])
isnull(j) || return childs[get(j)]
m[2] == "end" && return childs[end]
m2 = match(r"@(.+)=(.+)", m[2])
m2 == nothing && throw("Unable to parse: $(m[2])")
attr_name = m2[1]
attr_value = m2[2]
for child in childs
has_attribute(child, attr_name) || continue
if get_attribute(child, attr_name) == attr_value
return child
end
end
throw("Unable to parse: $(m[2])")
end
function has_child(x::XMLElement, child_name::AbstractString)
return get_child(x, child_name) != nothing
end
function get_attribute(x::XMLElement, attr_name::AbstractString)
attr = attribute(x, attr_name)
numeric = tryparse(Int64, attr)
isnull(numeric) && (numeric = tryparse(Float64, attr))
isnull(numeric) && return attr
return get(numeric)
end
function getindex(x::XMLElement, attr_name::AbstractString)
attr_name = strip(attr_name, '/')
child = get_child(x, attr_name)
child == nothing || return child
has_attribute(x, attr_name) && return get_attribute(x, attr_name)
if '/' in attr_name
items = split(attr_name, '/')
attr_name = first(items)
length(items) > 1 || throw(KeyError(attr_name))
haskey(x, attr_name) || throw(KeyError(attr_name))
path = join(items[2:end], '/')
new_item = getindex(x, attr_name)
return new_item[path]
else
throw(KeyError(attr_name))
end
end
function new_child(xparent::XMLElement, name::AbstractString, attrs::Dict)
x = new_child(xparent, name)
for (k, v) in attrs
x[k] = v
end
return x
end
function new_child(xparent::XMLElement, name::AbstractString, attrs::Pair...)
x = new_child(xparent, name)
for (k, v) in attrs
x[k] = v
end
return x
end
type Xdmf
name :: AbstractString
xdmf :: XMLElement
xml :: XMLElement
hdf :: HDF5File
end
function ModelIO()
return ModelIO(tempname())
function new_child(xdmf::Xdmf, args...; kwargs...)
new_child(xdmf.xml, args...; kwargs...)
end
function ModelIO(name::AbstractString)
function read(xdmf::Xdmf, path::AbstractString)
result = getindex(xdmf.xml, path)
if endswith(path, "DataItem")
format = get_attribute(result, "Format")
@assert format == "HDF"
h5file, path = map(ASCIIString, split(content(result), ':'))
h5file = dirname(xdmf.name) * "/" * h5file
isfile(h5file) || throw("Xdmf: h5 file $h5file not found!")
return read(xdmf.hdf, path)
else
return result
end
end
function Xdmf()
return Xdmf(tempname())
end
function h5file(xdmf::Xdmf)
return xdmf.name*".h5"
end
function xmffile(xdmf::Xdmf)
return xdmf.name*".xmf"
end
function Xdmf(name::AbstractString)
xdmf = new_element("Xdmf")
set_attribute(xdmf, "xmlns:xi", "http://www.w3.org/2001/XInclude")
set_attribute(xdmf, "Version", "2.1")
return ModelIO(name, xdmf)
h5file = "$name.h5"
flag = isfile(h5file) ? "r+" : "w"
hdf = h5open(h5file, flag)
return Xdmf(name, xdmf, hdf)
end
function h5file(mio::ModelIO)
return mio.name*".h5"
function save!(xdmf::Xdmf)
doc = XMLDocument()
set_root(doc, xdmf.xml)
save_file(doc, xmffile(xdmf))
end
function put!{T,N}(mio::ModelIO, path::AbstractString, data::Array{T,N})
hdf = h5file(mio)
h5write(hdf, path, data)
end
function get_dataitem{T,N}(mio::ModelIO, path::AbstractString, data::Array{T,N}; format="HDF")
function new_dataitem{T,N}(xdmf::Xdmf, path::AbstractString, data::Array{T,N}; format="HDF")
dataitem = new_element("DataItem")
n, m = size(data)
set_attribute(dataitem, "DataType", "$T")
set_attribute(dataitem, "Dimensions", "$n $m")
datatype = replace("$T", "64", "")
dimensions = join(size(data), " ")
set_attribute(dataitem, "DataType", datatype)
set_attribute(dataitem, "Dimensions", dimensions)
set_attribute(dataitem, "Format", format)
if format == "HDF"
hdf = basename(h5file(mio))
hdf = basename(h5file(xdmf))
if !exists(xdmf.hdf, path)
write(xdmf.hdf, path, data)
end
add_text(dataitem, "$hdf:$path")
elseif format == "XML"
add_text(dataitem, strip(string(data), ['[', ']']))
end
return dataitem
end
function get(mio::ModelIO, path::AbstractString)
h5read(mio.name*".h5", path)
end
function save!(mio::ModelIO)
doc = XMLDocument()
set_root(doc, mio.xdmf)
save_file(doc, mio.name*".xmf")
end
+6 -3
View File
@@ -246,9 +246,12 @@ end
function call(solver::Solver, ::Type{DataFrame}, field_name::AbstractString,
abbreviation::Symbol, time::Float64=0.0)
u = Dict()
for problem in get_problems(solver)
u = merge(u, problem(field_name, time))
fields = [problem(field_name, time) for problem in get_problems(solver)]
fields = filter(f -> f != nothing, fields)
if length(fields) != 0
u = merge(fields...)
else
u = Dict()
end
return to_dataframe(u, abbreviation)
end
-1
View File
@@ -192,4 +192,3 @@ end
function xdmf_save!(xdmf, filename)
save_file(xdmf.xdoc, filename)
end
+34 -30
View File
@@ -9,7 +9,7 @@ type Solver{S<:AbstractSolver}
problems :: Vector{Problem}
norms :: Vector{Tuple} # solution norms for convergence studies
ndofs :: Int # number of degrees of freedom in problem
io :: Nullable{ModelIO} # input/output handle
xdmf :: Nullable{Xdmf} # input/output handle
properties :: S
end
@@ -457,15 +457,17 @@ function call(solver::Solver, field_name::AbstractString, time::Float64)
return merge(fields...)
end
function get_temporal_collection(mio::ModelIO)
grid = find_element(mio.xdmf, "Grid")
if grid == nothing
function get_temporal_collection(xdmf::Xdmf)
domain = find_element(xdmf.xml, "Domain")
grid = nothing
if domain == nothing
info("Xdmf: creating new temporal collection")
domain = new_child(mio.xdmf, "Domain")
domain = new_child(xdmf.xml, "Domain")
grid = new_child(domain, "Grid")
set_attribute(grid, "CollectionType", "Temporal")
set_attribute(grid, "GridType", "Collection")
end
grid = find_element(domain, "Grid")
return grid
end
@@ -473,6 +475,7 @@ end
function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
show_info && info("Updating problems ...")
t0 = Base.time()
for problem in solver.problems
assembly = get_assembly(problem)
elements = get_elements(problem)
@@ -483,27 +486,21 @@ function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
end
# if io is attached to solver, update hdf / xml also
if !isnull(solver.io)
io = get(solver.io)
xdmf = io.xdmf
temporal_collection = get_temporal_collection(io)
if !isnull(solver.xdmf)
xdmf = get(solver.xdmf)
temporal_collection = get_temporal_collection(xdmf)
frame = new_child(temporal_collection, "Grid")
time_item = new_child(frame, "Time")
set_attribute(time_item, "Value", solver.time)
new_child(frame, "Time", Dict("Value" => solver.time))
# save geometry
X = solver("geometry", solver.time)
node_ids = sort(collect(keys(X)))
geometry = hcat([X[nid] for nid in node_ids]...)
put!(io, "/Node IDs", node_ids)
path = "/Geometry"
put!(io, path, geometry)
dataitem = get_dataitem(io, path, geometry)
ndim, nnodes = size(geometry)
geom_type = ndim == 2 ? "XY" : "XYZ"
geom = new_child(frame, "Geometry")
set_attribute(geom, "Type", geom_type)
dataitem = new_dataitem(xdmf, "/Node IDs", node_ids)
geom = new_child(frame, "Geometry", Dict("Type" => geom_type))
dataitem = new_dataitem(xdmf, "/Geometry", geometry)
add_child(geom, dataitem)
# save topology
@@ -511,10 +508,21 @@ function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
nelements = length(all_elements)
element_types = unique(map(get_element_type, all_elements))
element_mapping = Dict(
"Quad4" => "Quadrilateral",
xdmf_element_mapping = Dict(
"Seg2" => "Polyline",
)
"Tri3" => "Triangle",
"Quad4" => "Quadrilateral",
"Tet4" => "Tetrahedron",
"Pyramid5" => "Pyramid",
"Wedge6" => "Wedge",
"Hex8" => "Hexahedron",
"Seg3" => "Edge_3",
"Tri6" => "Tri_6",
"Quad8" => "Quad_8",
"Tet10" => "Tet_10",
"Pyramid13" => "Pyramid_13",
"Wedge15" => "Wedge_15",
"Hex20" => "Hex_20")
for element_type in element_types
elements = filter_by_element_type(element_type, all_elements)
@@ -523,12 +531,10 @@ function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
element_conn = map(get_connectivity, elements)
element_conn = transpose(hcat(element_conn...)) - 1
element_code = split(string(element_type), ".")[end]
put!(io, "/Topology/$element_code/Element IDs", element_ids)
path = "/Topology/$element_code/Connectivity"
put!(io, path, element_conn)
dataitem = get_dataitem(io, path, element_conn)
dataitem = new_dataitem(xdmf, "/Topology/$element_code/Element IDs", element_ids)
dataitem = new_dataitem(xdmf, "/Topology/$element_code/Connectivity", element_conn)
topology = new_child(frame, "Topology")
set_attribute(topology, "TopologyType", element_mapping[element_code])
set_attribute(topology, "TopologyType", xdmf_element_mapping[element_code])
set_attribute(topology, "NumberOfElements", length(elements))
add_child(topology, dataitem)
end
@@ -551,14 +557,12 @@ function update!(solver::Solver, u::Vector, la::Vector; show_info=true)
end
U = hcat([U[nid] for nid in node_ids]...)
unknown_field_name = ucfirst(unknown_field_name)
path = "/Results/$time/Nodal Fields/$unknown_field_name"
put!(io, path, U)
dataitem = get_dataitem(io, path, U)
dataitem = new_dataitem(xdmf, "/Results/$time/Nodal Fields/$unknown_field_name", U)
attribute = new_child(frame, "Attribute")
set_attribute(attribute, "Name", unknown_field_name)
set_attribute(attribute, "Center", field_center)
add_child(attribute, dataitem)
save!(io)
save!(xdmf)
end
t1 = round(Base.time()-t0, 2)