mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-26 03:44:45 +00:00
Fixed multiple dispatch issues on io.jl
Related to issue #74, io.jl is no more modifying functionality of LightXML
This commit is contained in:
+1
-1
@@ -30,7 +30,7 @@ module Testing
|
||||
end
|
||||
|
||||
include("io.jl")
|
||||
export Xdmf, h5file, xmffile, has_child, get_child, new_dataitem
|
||||
export Xdmf, h5file, xmffile, xdmf_filter, new_dataitem, get_temporal_collection
|
||||
|
||||
include("fields.jl")
|
||||
export Field, DCTI, DVTI, DCTV, DVTV, CCTI, CVTI, CCTV, CVTV, Increment
|
||||
|
||||
@@ -3,100 +3,6 @@
|
||||
|
||||
using HDF5
|
||||
using LightXML
|
||||
importall LightXML
|
||||
importall Base
|
||||
|
||||
function new_element(name::String, 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::String)
|
||||
set_attribute(x, attr_name, content)
|
||||
end
|
||||
|
||||
function haskey(x::XMLElement, key::String)
|
||||
return has_child(x, key) || has_attribute(x, key)
|
||||
end
|
||||
|
||||
function has_child(x::XMLElement, child_name::String)
|
||||
return get_child(x, child_name) != nothing
|
||||
end
|
||||
|
||||
function get_attribute(x::XMLElement, attr_name::String)
|
||||
attr = attribute(x, attr_name)
|
||||
numeric = tryparse(Int64, attr)
|
||||
isnull(numeric) && (numeric = tryparse(Float64, attr))
|
||||
isnull(numeric) && return attr
|
||||
return get(numeric)
|
||||
end
|
||||
|
||||
function new_child(xparent::XMLElement, name::String, attrs::Dict)
|
||||
x = new_child(xparent, name)
|
||||
for (k, v) in attrs
|
||||
x[k] = v
|
||||
end
|
||||
return x
|
||||
end
|
||||
|
||||
""" Basic traverse support, so that it's possible to find data from xml using
|
||||
path syntax e.g. /foo/bar[2]/baz[@Name=Frame 1]/DataItem. If several elements
|
||||
with same name exists in tree, pick first by default and next ones can be picked
|
||||
using [] syntax or [@attr=value] syntax, see [1] for details. For last item use
|
||||
[end].
|
||||
|
||||
[1] http://www.xdmf.org/index.php/XDMF_Model_and_Format
|
||||
"""
|
||||
function get_child(x::XMLElement, child_name::String)
|
||||
'/' 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 = convert(String, m2[1])
|
||||
attr_value = convert(String, 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 getindex(x::XMLElement, attr_name::String)
|
||||
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 = map(String, 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
|
||||
|
||||
type Xdmf
|
||||
name :: String
|
||||
@@ -104,24 +10,6 @@ type Xdmf
|
||||
hdf :: HDF5File
|
||||
end
|
||||
|
||||
function new_child(xdmf::Xdmf, args...; kwargs...)
|
||||
new_child(xdmf.xml, args...; kwargs...)
|
||||
end
|
||||
|
||||
function read(xdmf::Xdmf, path::String)
|
||||
result = getindex(xdmf.xml, path)
|
||||
if endswith(path, "DataItem")
|
||||
format = get_attribute(result, "Format")
|
||||
@assert format == "HDF"
|
||||
h5file, path = map(String, 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
|
||||
@@ -134,6 +22,7 @@ function xmffile(xdmf::Xdmf)
|
||||
return xdmf.name*".xmf"
|
||||
end
|
||||
|
||||
""" Initialize a new Xdmf object. """
|
||||
function Xdmf(name::String; overwrite=false)
|
||||
xdmf = new_element("Xdmf")
|
||||
h5file = "$name.h5"
|
||||
@@ -164,6 +53,175 @@ function Xdmf(name::String; overwrite=false)
|
||||
return Xdmf(name, xdmf, hdf)
|
||||
end
|
||||
|
||||
""" Return the basic structure of Xdmf document. Creates a new TemporalCollection if not found.
|
||||
|
||||
Basic structure for XML part of Xdmf file is
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Xdmf xmlns:xi="http://www.w3.org/2001/XInclude" Version="2.1">
|
||||
<Domain>
|
||||
<Grid CollectionType="Temporal" GridType="Collection">
|
||||
</Grid>
|
||||
</Domain>
|
||||
</Xdmf>
|
||||
|
||||
"""
|
||||
function get_temporal_collection(xdmf::Xdmf)
|
||||
domain = find_element(xdmf.xml, "Domain")
|
||||
grid = nothing
|
||||
if domain == nothing
|
||||
debug("Xdmf: creating new temporal collection")
|
||||
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
|
||||
|
||||
""" Returns some spesific child xml element from a array of XMLElement based on,
|
||||
"Xdmf extensions" see [1] for details.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
child_elements :: Vector{XMLElement}
|
||||
A vector of XMLElements where to perform filtering.
|
||||
child_name :: String
|
||||
Child element name, maybe containing Xdmf instructions
|
||||
|
||||
Returns
|
||||
-------
|
||||
nothing if nothing is found, otherwise XMLElement matching to filtering
|
||||
|
||||
Examples
|
||||
--------
|
||||
julia> grid1 = new_element("Grid")
|
||||
julia> add_text(grid1, "I am first grid")
|
||||
julia> grid2 = new_element("Grid")
|
||||
julia> add_text(grid2, "I am second grid")
|
||||
julia> set_attribute(grid2, "Name", "Frame 2")
|
||||
julia> grid3 = new_element("Grid")
|
||||
julia> add_text(grid3, "I am third grid")
|
||||
julia> grids = [grid1, grid2, grid3]
|
||||
|
||||
To return second Grid element, one can use
|
||||
|
||||
julia> xdmf_filter(grids, "Grid[2]")
|
||||
|
||||
To return Grid which has attribute Name="Frame 2", use
|
||||
|
||||
julia> xdmf_filter(grids, "Grid[@name=Frame 2]")
|
||||
|
||||
To pick last Grid, use [end], e.g.
|
||||
|
||||
julia> xdmf_filter(grids, "Grid[end]").
|
||||
|
||||
References
|
||||
----------
|
||||
[1] http://www.xdmf.org/index.php/XDMF_Model_and_Format
|
||||
"""
|
||||
function xdmf_filter(child_elements, child_name)
|
||||
if '/' in child_name # needs path traversal
|
||||
return nothing
|
||||
end
|
||||
|
||||
# filter children elements using syntax child[X] -> rename child_name
|
||||
m = match(r"(\w+)\[(.+)\]", child_name)
|
||||
if m != nothing
|
||||
child_name = m[1]
|
||||
end
|
||||
|
||||
# first find any relevant child elements (has same tag)
|
||||
childs = []
|
||||
for child in child_elements
|
||||
if LightXML.name(child) == child_name
|
||||
push!(childs, child)
|
||||
end
|
||||
end
|
||||
|
||||
# childs not found at all
|
||||
length(childs) == 0 && return nothing
|
||||
|
||||
# by default return first
|
||||
m == nothing && return first(childs)
|
||||
|
||||
# if [end] return last
|
||||
m[2] == "end" && return childs[end]
|
||||
|
||||
# otherwise try parse int and return nth children from list
|
||||
parsed_int = tryparse(Int, m[2])
|
||||
if !isnull(parsed_int)
|
||||
idx = get(parsed_int)
|
||||
if (idx > 0) && (idx <= length(childs))
|
||||
return childs[idx]
|
||||
else
|
||||
# wrong index
|
||||
return nothing
|
||||
end
|
||||
end
|
||||
|
||||
# [X] is something else than integer, filter children elements using syntax child[@attr=value]
|
||||
m2 = match(r"@(.+)=(.+)", m[2])
|
||||
m2 == nothing && throw("Unable to parse: $(m[2])")
|
||||
attr_name = convert(String, m2[1])
|
||||
attr_value = convert(String, m2[2])
|
||||
for child in childs
|
||||
has_attribute(child, attr_name) || continue
|
||||
if attribute(child, attr_name) == attr_value
|
||||
return child
|
||||
end
|
||||
end
|
||||
|
||||
# nothing found
|
||||
return nothing
|
||||
end
|
||||
|
||||
""" Traverse XML path. Xdmf filtering can be used, so it's possible to find
|
||||
data from xml using syntax e.g.
|
||||
|
||||
julia> traverse(xdmf, x, "/Domain/Grid[2]/Grid[@Name=Frame 1]/DataItem")
|
||||
"""
|
||||
function traverse(xdmf::Xdmf, x::XMLElement, attr_name::String)
|
||||
attr_name = strip(attr_name, '/')
|
||||
|
||||
if has_attribute(x, attr_name)
|
||||
return attribute(x, attr_name)
|
||||
end
|
||||
|
||||
childs = child_elements(x)
|
||||
|
||||
if '/' in attr_name
|
||||
items = split(attr_name, '/')
|
||||
new_item = xdmf_filter(childs, first(items))
|
||||
new_path = join(items[2:end], '/')
|
||||
return traverse(xdmf, new_item, new_path)
|
||||
end
|
||||
|
||||
child = xdmf_filter(childs, attr_name)
|
||||
return child
|
||||
end
|
||||
|
||||
""" Read data from Xdmf file.
|
||||
|
||||
Traversing is supported, so one can easily traverse XML tree e.g.
|
||||
julia> read(xdmf, "/Domain/Grid/Grid[2]/Geometry")
|
||||
"""
|
||||
function read(xdmf::Xdmf, path::String)
|
||||
result = traverse(xdmf, xdmf.xml, path)
|
||||
if endswith(path, "DataItem")
|
||||
format = attribute(result, "Format"; required=true)
|
||||
@assert format == "HDF"
|
||||
h5file, path = map(String, 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 save!(xdmf::Xdmf)
|
||||
doc = XMLDocument()
|
||||
set_root(doc, xdmf.xml)
|
||||
|
||||
+4
-16
@@ -488,20 +488,6 @@ function (solver::Solver)(field_name::AbstractString, time::Float64)
|
||||
return merge(fields...)
|
||||
end
|
||||
|
||||
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(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
|
||||
|
||||
""" Default update for solver. """
|
||||
function update!{S}(solver::Solver{S}; show_info=true)
|
||||
u = solver.u
|
||||
@@ -540,7 +526,8 @@ function update_xdmf!{S}(solver::Solver{S}; show_info=true)
|
||||
geom_type = (ndim == 2 ? "XY" : "XYZ")
|
||||
data_node_ids = new_dataitem(xdmf, "/Node IDs", node_ids)
|
||||
data_geometry = new_dataitem(xdmf, "/Geometry", X)
|
||||
geometry = new_element("Geometry", Dict("Type" => geom_type))
|
||||
geometry = new_element("Geometry")
|
||||
set_attribute(geometry, "Type", geom_type)
|
||||
add_child(geometry, data_geometry)
|
||||
|
||||
# 2. save topology
|
||||
@@ -588,7 +575,8 @@ function update_xdmf!{S}(solver::Solver{S}; show_info=true)
|
||||
|
||||
# 3. save solved field
|
||||
frame = new_element("Grid")
|
||||
new_child(frame, "Time", Dict("Value" => solver.time))
|
||||
time = new_child(frame, "Time")
|
||||
set_attribute(time, "Value", solver.time)
|
||||
add_child(frame, geometry)
|
||||
for topo in topology
|
||||
add_child(frame, topo)
|
||||
|
||||
@@ -420,10 +420,12 @@ function update_xdmf!(solver::Solver{Modal}; show_info=true)
|
||||
info("Creating frequency frame f=$(round(freq, 3)), path=$path")
|
||||
|
||||
frame = new_element("Grid")
|
||||
new_child(frame, "Time", Dict("Value" => freq))
|
||||
time = new_child(frame, "Time")
|
||||
set_attribute(time, "Value", freq)
|
||||
|
||||
# add geometry
|
||||
geometry = new_element("Geometry", Dict("Type" => geom_type))
|
||||
geometry = new_element("Geometry")
|
||||
set_attribute(geometry, "Type", geom_type)
|
||||
data_node_ids = new_dataitem(xdmf, "/Node IDs", node_ids)
|
||||
data_geometry = new_dataitem(xdmf, "/Geometry", X)
|
||||
add_child(geometry, data_geometry)
|
||||
|
||||
Reference in New Issue
Block a user