# -*- coding: utf-8 -*-
#
# This file is subject to the terms and conditions defined in
# file 'LICENSE.txt', which is part of this source code package.
#
""" LSDyna file reader.
Documentation of the format:
http://ftp.lstc.com/anonymous/outgoing/jday/manuals/DRAFT_Vol_I.pdf
"""
from Muscat.IO.IOFactory import RegisterReaderClass
import numpy as np
from Muscat.Types import MuscatIndex, MuscatFloat
from Muscat.Containers.Mesh import Mesh
from Muscat.IO.ReaderBase import ReaderBase
from Muscat.Helpers.Logger import Debug, Info
LSDynaNumber = {4: "tet4"} # 4-point tetraedron
[docs]def ReadLSDyna(fileName: str = "", string: str = "", out=None, printNotRead=True):
"""Function API for reading a LSDyna mesh file
Parameters
----------
fileName : str, optional
name of the file to be read, by default None
string : str, optional
data to be read as a string instead of a file, by default None
out : Mesh, optional
output unstructured mesh object containing reading result, by default None
printNotRead : bool, optional
if True, prints in console the lines dot understood by the reader, by default True
Returns
-------
Mesh
output unstructured mesh object containing reading result
"""
reader = LSDynaReader()
reader.SetFileName(fileName)
reader.SetStringToRead(string)
return reader.Read(fileName=fileName, string=string, out=out, printNotRead=printNotRead)
[docs]def LineToListNoQuote(text):
return [s.strip() for s in text.split()]
[docs]def ListToNumber(list):
"""hack where the element type is defined by inspecting the number of identical
columns at the end of the connectivity list.
"""
l = len(list)
val = list[-1]
for i in range(l - 2, -1, -1):
if list[i] != val:
break
return i + 2
[docs]class LSDynaReader(ReaderBase):
"""LSDyna Reader class"""
def __init__(self):
super().__init__()
self.commentHeader = "$"
self.readFormat = "r"
[docs] def Read(self, fileName=None, string=None, out=None, printNotRead=True):
"""Function that performs the reading of a LSDyna mesh file
Parameters
----------
fileName : str, optional
name of the file to be read, by default None
string : str, optional
data to be read as a string instead of a file, by default None
out : Mesh, optional
output unstructured mesh object containing reading result, by default None
printNotRead : bool, optional
if True, prints in console the lines dot understood by the reader, by default True
Returns
-------
Mesh
output unstructured mesh object containing reading result
"""
if fileName is not None:
self.SetFileName(fileName)
if string is not None:
self.SetStringToRead(string)
self.StartReading()
if out is None:
res = Mesh()
else:
res = out
filetointernalid = {}
oidToElementContainer = {}
oidToLocalElementNumber = {}
l = self.ReadCleanLine()
originalIds = []
nodes = []
nodeSetCounter = 0
while True:
# premature EOF
if l is None:
print("ERROR premature EOF: please check the integrity of your .k file") # pragma: no cover
break # pragma: no cover
# if len(l) == 0: l = string.readline().strip('\n').lstrip().rstrip(); continue
if l.find("*ELEMENT") > -1:
while True:
l = self.ReadCleanLine()
if l.find("*") > -1:
break
s = LineToListNoQuote(l)
n = ListToNumber(s[2:])
try:
nametype = LSDynaNumber[n]
except KeyError: # pragma: no cover
raise RuntimeError("Elements with " + str(n) + "vertices not compatible with reader")
conn = [x for x in map(int, s[2:6])]
elements = res.GetElementsOfType(nametype)
oid = int(s[0])
cpt = elements.AddNewElement(conn, oid)
oidToElementContainer[oid] = elements
oidToLocalElementNumber[oid] = cpt
elTag = "canonical:" + s[1]
elements.tags.CreateTag(elTag, False).AddToTag(cpt - 1)
continue # pragma: no cover # unseen by coverage peephole optimization
if l.find("*NODE") > -1:
dim = 3
s = None
cpt = 0
while True:
l = self.ReadCleanLine()
if l.find("*") > -1:
break
s = LineToListNoQuote(l)
oid = int(s[0])
filetointernalid[oid] = cpt
originalIds.append(oid)
nodes.append(list(map(float, s[1 : dim + 1])))
cpt += 1
continue # pragma: no cover # unseen by coverage peephole optimization
if l.find("*SET_NODE_LIST") > -1:
tag = res.GetNodalTag(str(nodeSetCounter))
nodeSetCounter += 1
self.ReadCleanLine()
while True:
l = self.ReadCleanLine()
if l.find("*") > -1:
break
s = np.array(l.split(), dtype=int)
for oid in s[s > 0]:
tag.AddToTag(int(oid))
continue # pragma: no cover # unseen by coverage peephole optimization
if l.find("*ED.") > -1:
Debug("End file")
break
# case not treated
if printNotRead == True:
Info("line starting with <<" + l + ">> not considered in the reader")
l = self.ReadCleanLine()
continue
self.EndReading()
res.nodes = np.array(nodes, dtype=MuscatFloat)
res.nodes.shape = (cpt, dim)
res.originalIDNodes = np.array(originalIds, dtype=MuscatIndex)
def updateIDsFunc(x):
return filetointernalid[x]
for tag in res.nodesTags:
tag.SetIds(np.vectorize(updateIDsFunc)(tag.GetIds()))
for _, data in res.elements.items():
data.Tighten()
data.connectivity = np.vectorize(updateIDsFunc)(data.connectivity)
res.PrepareForOutput()
return res
RegisterReaderClass(".k", LSDynaReader)
[docs]def CheckIntegrity():
data = """
$# LS-DYNA Keyword file created by LS-PrePost(R) V4.5.0
*KEYWORD
*TITLE
*ELEMENT_SOLID
$# eid pid n1 n2 n3 n4 n5 n6 n7 n8
1 3000001 1 2 3 4 4 4 4 4
*SET_NODE_LIST
$# sid da1 da2 da3 da4 solver
1 0.0 0.0 0.0 0.0MECH
$# nid1 nid2 nid3 nid4 nid5 nid6 nid7 nid8
1 2 3 4 0 0 0 0
*SET_NODE_LIST
$# sid da1 da2 da3 da4 solver
1 0.0 0.0 0.0 0.0MECH
$# nid1 nid2 nid3 nid4 nid5 nid6 nid7 nid8
1 3 0 0 0 0 0 0
*NODE
$# nid x y z tc rc
1 0.0 0.0 0.0 0 0
2 0.6 0.0 0.0 0 0
3 0.6 0.7 0.0 0 0
4 0.2 0.2 0.3 0 0
5 0.3 0.0 0.1 0 0
*ED.
"""
res = ReadLSDyna(string=data)
res = ReadLSDyna(string=data, out=Mesh())
print(res)
return "ok"
if __name__ == "__main__":
print(CheckIntegrity()) # pragma: no cover