Skip to content

Commit

Permalink
FEM: added import/export of mesh as YAML/JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
joha2 authored and berndhahnebach committed Jun 8, 2019
1 parent c1d0c98 commit d78f5a1
Show file tree
Hide file tree
Showing 7 changed files with 374 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Mod/Fem/CMakeLists.txt
Expand Up @@ -52,6 +52,7 @@ SET(FemInOut_SRCS
feminout/importInpMesh.py
feminout/importToolsFem.py
feminout/importVTKResults.py
feminout/importYamlJsonMesh.py
feminout/importZ88Mesh.py
feminout/importZ88O2Results.py
feminout/readFenicsXDMF.py
Expand Down Expand Up @@ -183,6 +184,7 @@ SET(FemTestsMesh_SRCS
femtest/testfiles/mesh/tetra10_mesh.inp
femtest/testfiles/mesh/tetra10_mesh.unv
femtest/testfiles/mesh/tetra10_mesh.vtk
femtest/testfiles/mesh/tetra10_mesh.yml
femtest/testfiles/mesh/tetra10_mesh.z88
)

Expand Down
7 changes: 7 additions & 0 deletions src/Mod/Fem/Init.py
Expand Up @@ -39,6 +39,13 @@
FreeCAD.addImportType("FEM mesh Fenics (*.xml *.xdmf)", "feminout.importFenicsMesh")
FreeCAD.addExportType("FEM mesh Fenics (*.xml *.xdmf)", "feminout.importFenicsMesh")

FreeCAD.addImportType(
"FEM mesh YAML/JSON (*.meshyaml *.meshjson *.yaml *.json)", "feminout.importYamlJsonMesh"
)
FreeCAD.addExportType(
"FEM mesh YAML/JSON (*.meshyaml *.meshjson *.yaml *.json)", "feminout.importYamlJsonMesh"
)

FreeCAD.addImportType("FEM mesh Z88 (*i1.txt)", "feminout.importZ88Mesh")
FreeCAD.addExportType("FEM mesh Z88 (*i1.txt)", "feminout.importZ88Mesh")

Expand Down
4 changes: 4 additions & 0 deletions src/Mod/Fem/TestFem.py
Expand Up @@ -117,6 +117,7 @@
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_inp"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_unv"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_vkt"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_yml"
./bin/FreeCADCmd --run-test "femtest.testmesh.TestMeshEleTetra10.test_tetra10_z88"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectCreate.test_femobjects_make"
./bin/FreeCADCmd --run-test "femtest.testobject.TestObjectType.test_femobjects_type"
Expand Down Expand Up @@ -185,6 +186,9 @@
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_vkt"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_yml"))
import unittest
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromName("femtest.testmesh.TestMeshEleTetra10.test_tetra10_z88"))
Expand Down
90 changes: 90 additions & 0 deletions src/Mod/Fem/feminout/importToolsFem.py
Expand Up @@ -242,6 +242,96 @@ def make_femmesh(
return mesh


def make_dict_from_femmesh(
femmesh
):
"""
Converts FemMesh into dictionary structure which can immediately used
from importToolsFem.make_femmesh(mesh_data) to create a valid FEM mesh.
"""
# this dict can be easily saved and reloaded by yaml
# see importYamlJasonMesh for a implementation

mesh_data = {}

seg2 = []
seg3 = []

tri3 = []
tri6 = []
quad4 = []
quad8 = []

tet4 = []
tet10 = []
hex8 = []
hex20 = []
pent6 = []
pent15 = []

# associations for lengths of tuples to different
# edge, face, and volume elements

len_to_edge = {2: seg2, 3: seg3}
len_to_face = {3: tri3, 6: tri6, 4: quad4, 8: quad8}
len_to_volume = {
4: tet4,
10: tet10,
8: hex8,
20: hex20,
6: pent6,
15: pent15
}

# analyze edges

for e in femmesh.Edges:
t = femmesh.getElementNodes(e)
len_to_edge[len(t)].append((e, t))

# analyze faces

for f in femmesh.Faces:
t = femmesh.getElementNodes(f)
len_to_face[len(t)].append((f, t))

# analyze volumes

for v in femmesh.Volumes:
t = femmesh.getElementNodes(v)
len_to_volume[len(t)].append((v, t))

mesh_data = {
'Nodes': dict([(k, (v.x, v.y, v.z))
for (k, v) in femmesh.Nodes.items()]),
'Seg2Elem': dict(seg2),
'Seg3Elem': dict(seg3),

'Tria3Elem': dict(tri3),
'Tria6Elem': dict(tri6),
'Quad4Elem': dict(quad4),
'Quad8Elem': dict(quad8),

'Tetra4Elem': dict(tet4),
'Tetra10Elem': dict(tet10),
'Hexa8Elem': dict(hex8),
'Hexa20Elem': dict(hex20),
'Penta6Elem': dict(pent6),
'Penta15Elem': dict(pent15),

'Groups': dict([(
group_num, (
femmesh.getGroupName(group_num),
femmesh.getGroupElements(group_num)
)
) for group_num in femmesh.Groups])

}
# no pyr5, pyr13?
# no groups?
return mesh_data


def fill_femresult_mechanical(
res_obj,
result_set
Expand Down
220 changes: 220 additions & 0 deletions src/Mod/Fem/feminout/importYamlJsonMesh.py
@@ -0,0 +1,220 @@
# ***************************************************************************
# * *
# * Copyright (c) 2019 - Johannes Hartung <j.hartung@gmx.net> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU Lesser General Public License (LGPL) *
# * as published by the Free Software Foundation; either version 2 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU Library General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************

__title__ = "FreeCAD YAML and JSON mesh reader and writer"
__author__ = "Johannes Hartung"
__url__ = "http://www.freecadweb.org"

## @package importYAMLJSONMesh
# \ingroup FEM
# \brief FreeCAD YAML and JSON Mesh reader and writer for FEM workbench

import json
import os

import FreeCAD
from . import importToolsFem

has_yaml = True
try:
import yaml
except ImportError:
FreeCAD.Console.PrintMessage(
"No YAML available (import yaml failure), "
"yaml import/export won't work\n"
)
has_yaml = False


# ****************************************************************************
# ********* generic FreeCAD import and export methods ************************
# names are fix given from FreeCAD, these methods are called from FreeCAD
# they are set in FEM modules Init.py

if open.__module__ == '__builtin__':
# because we'll redefine open below (Python2)
pyopen = open
elif open.__module__ == 'io':
# because we'll redefine open below (Python3)
pyopen = open


def open(
filename
):
'''called when freecad opens a file
a FEM mesh object is created in a new document'''

docname = os.path.splitext(os.path.basename(filename))[0]
return insert(filename, docname)


def insert(
filename,
docname
):
'''called when freecad wants to import a file"
a FEM mesh object is created in a existing document'''

try:
doc = FreeCAD.getDocument(docname)
except NameError:
doc = FreeCAD.newDocument(docname)
FreeCAD.ActiveDocument = doc

import_yaml_json_mesh(filename)
return doc


def export(objectslist, fileString):
"called when freecad exports a file"
if len(objectslist) != 1:
FreeCAD.Console.PrintError(
"This exporter can only "
"export one object.\n")
return
obj = objectslist[0]
if not obj.isDerivedFrom("Fem::FemMeshObject"):
FreeCAD.Console.PrintError("No FEM mesh object selected.\n")
return

write(fileString, obj.FemMesh)


# ****************************************************************************
# ********* module specific methods ******************************************
# reader:
# - a method uses a FemMesh instance, creates the FEM mesh document object and
# returns this object
# - a method read the data from file creates FemMesh instance out of the
# FEM mesh dictionary. This instance is returned
# - a converts the raw read data into the FEM mesh dictionary which
# can be used to create a FemMesh instance
#
#
# writer:
# - a method directly writes a FemMesh to the mesh file

# ********* reader ***********************************************************
def import_yaml_json_mesh(
fileString
):
"""
read a FemMesh from a yaml/json mesh file
insert a FreeCAD FEM Mesh object in the ActiveDocument
return the FEM mesh document object
"""

mesh_name = os.path.basename(os.path.splitext(fileString)[0])

femmesh = read(fileString)
if femmesh:
mesh_object = FreeCAD.ActiveDocument.addObject(
'Fem::FemMeshObject',
mesh_name
)
mesh_object.FemMesh = femmesh

return mesh_object


def read(
fileString
):
'''read a FemMesh from a yaml/json mesh file and return the FemMesh
'''
# no document object is created, just the FemMesh is returned

fileExtension = os.path.basename(os.path.splitext(fileString)[1])

raw_mesh_data = {}
if fileExtension.lower() == ".meshjson" or\
fileExtension.lower() == ".json":
fp = pyopen(fileString, "rt")
raw_mesh_data = json.load(fp)
fp.close()
elif (
fileExtension.lower() == ".meshyaml"
or fileExtension.lower() == ".meshyml"
or fileExtension.lower() == ".yaml"
or fileExtension.lower() == ".yml"
) and has_yaml:
fp = pyopen(fileString, "rt")
raw_mesh_data = yaml.load(fp)
fp.close()
else:
FreeCAD.Console.PrintError(
"Unknown extension, "
"please select other importer.\n")

FreeCAD.Console.PrintMessage("Converting indices to integer numbers ...")
mesh_data = convert_raw_data_to_mesh_data(raw_mesh_data)
FreeCAD.Console.PrintMessage("OK\n")

return importToolsFem.make_femmesh(mesh_data)


def convert_raw_data_to_mesh_data(
raw_mesh_data
):
"""
Converts raw dictionary data from JSON or YAML file to proper dict
for importToolsFem.make_femmesh(mesh_data). This is necessary since
JSON and YAML save dict keys as strings while make_femmesh expects
integers.
"""

mesh_data = {}
for (type_key, type_dict) in raw_mesh_data.items():
if type_key.lower() != "groups":
mesh_data[type_key] = dict([
(int(k), v) for (k, v) in type_dict.items()
])
return mesh_data


# ********* writer ***********************************************************
def write(
fileString,
fem_mesh
):
'''directly write a FemMesh to a yaml/json mesh file
fem_mesh: a FemMesh'''

mesh_data = importToolsFem.make_dict_from_femmesh(fem_mesh)

if fileString != "":
fileName, fileExtension = os.path.splitext(fileString)
if fileExtension.lower() == ".json" \
or fileExtension.lower() == ".meshjson":
fp = pyopen(fileString, "wt")
json.dump(mesh_data, fp, indent=4)
fp.close()
elif (
fileExtension.lower() == ".meshyaml"
or fileExtension.lower() == ".meshyml"
or fileExtension.lower() == ".yaml"
or fileExtension.lower() == ".yml"
) and has_yaml:
fp = pyopen(fileString, "wt")
yaml.safe_dump(mesh_data, fp)
fp.close()
25 changes: 25 additions & 0 deletions src/Mod/Fem/femtest/testfiles/mesh/tetra10_mesh.yml
@@ -0,0 +1,25 @@
Groups: {}
Hexa20Elem: {}
Hexa8Elem: {}
Nodes:
1: [6.0, 12.0, 18.0]
2: [0.0, 0.0, 18.0]
3: [12.0, 0.0, 18.0]
4: [6.0, 6.0, 0.0]
5: [3.0, 6.0, 18.0]
6: [6.0, 0.0, 18.0]
7: [9.0, 6.0, 18.0]
8: [6.0, 9.0, 9.0]
9: [3.0, 3.0, 9.0]
10: [9.0, 3.0, 9.0]
Penta15Elem: {}
Penta6Elem: {}
Quad4Elem: {}
Quad8Elem: {}
Seg2Elem: {}
Seg3Elem: {}
Tetra10Elem:
1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Tetra4Elem: {}
Tria3Elem: {}
Tria6Elem: {}

0 comments on commit d78f5a1

Please sign in to comment.