Source code for Muscat.IO.AnsysWriter

# -*- 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.
#

"""Ansys CDB format writer
"""
from typing import Optional, List
from io import TextIOWrapper
from pathlib import Path


import numpy as np

from Muscat.Types import MuscatIndex
import Muscat.MeshContainers.ElementsDescription as ED
from Muscat.MeshContainers.Mesh import Mesh
from Muscat.MeshContainers.Filters.FilterObjects import ElementFilter
from Muscat.IO.WriterBase import WriterBase


[docs] def WriteMeshToCDB(fileName: str, mesh: Mesh, file: Optional[Path] = None) -> None: """Function API for writing mesh in the CDB format file (Ansys). A file is created using the path and name of fileName Parameters ---------- fileName : str name with path to the file to be created (relative or absolute) mesh : UnstructuredMesh the mesh to be exported """ anWriter = AnsysWriter() anWriter.Open(fileName) if file: anWriter.WriteFromFile(mesh, file) else: anWriter.Write(mesh) anWriter.Close()
[docs] def ExportElementTagsInCDBFormat(mesh: Mesh, tagnames: List[str], filename: Optional[str]=None, filePointer: Optional[TextIOWrapper] =None): """Function to export multiple elements tags to Ansys CDB format Parameters ---------- mesh : Mesh mesh from which elements ids for each tag are searched tagnames : list[str] list of element tags filename : str, optional filename in CDB format where the element ids for each tag are exported, by default None """ ft = False for tname in tagnames: ExportElementTagInCDBFormat(mesh, tname, filename=filename, append=ft, filePointer=filePointer) ft = True
[docs] def ExportElementTagInCDBFormat(mesh: Mesh, tagname: str, filename:Optional[str]=None, append: bool =False, filePointer: Optional[TextIOWrapper]=None): """ Functions to export one element tag as Ansys CDB format. It uses the originals ids Parameters ---------- mesh : Mesh mesh from which elements ids for each tag are searched tagname : str element tag filename : str, optional filename in CDB format where the element ids for the provided tag are exported, by default None append : str, optional selects if the info is appended to the file (a+) or overwritten (w or False), by default False """ lglobal: List[MuscatIndex] = [] ef = ElementFilter(eTag=tagname) for selection in ef(mesh): lglobal.extend(selection.meshOffset + selection.indices) NB_ELEM_DANS_GROUPE = len(lglobal) if NB_ELEM_DANS_GROUPE == 0: # pragma: no cover print(f"Empty tag {tagname}") return if filePointer is None: if filename is None: filename = tagname + ".cdb" if append: mode = "a+" else: mode = "w" fh = open(filename, mode) else: fh = filePointer fh.write("CMBLOCK,{NOM_GROUPE},ELEM,{NB_ELEM_DANS_GROUPE}\n".format(NOM_GROUPE=tagname, NB_ELEM_DANS_GROUPE=NB_ELEM_DANS_GROUPE)) fh.write("(8i10)\n") l = np.asarray(lglobal) stop = 0 for cpt in range(len(l)//8): start = cpt*8 stop = (cpt+1)*8 if stop >= len(l): stop = len(l)-1 np.savetxt(fh, l[start:stop][np.newaxis], fmt="%10i", delimiter="") np.savetxt(fh, l[stop:][np.newaxis], fmt="%10i", delimiter="") if filePointer is None: fh.close()
[docs] class AnsysWriter(WriterBase): """Ansys CDB format writer attributes ---------- AnsysFormulation : ["SOLID3D","SOLID2D"] to export element with a specific physics read the file AnsysTools.py (variable MuscatToAnsysFormulation) for more details """ def __init__(self) -> None: super().__init__() self.canHandleBinaryChange = False self.AnsysFormulation = {3:"SOLID3D", 2:"SOLID2D"}
[docs] def CompactIndices(self, indices: np.ndarray) -> List: """From a list of indices in a ansys cdb compact form Parameters ---------- indices : np.ndarray indices of elements one by one Returns ------- List list of indices where consecutive indices are replaced by begin and -end, and clipped to contain 8 elements or fewer """ arr = np.sort(indices) diffs = np.diff(arr) split_indices = np.where(diffs != 1)[0] + 1 sections = np.split(arr, split_indices) idx = [] for section in sections: if section.shape[0] > 2: idx.extend([section[0], -section[-1]]) elif section.shape[0] == 2: idx.extend([section[0], section[1]]) elif section.shape[0] == 1: idx.extend([section[0]]) lines_idx = [idx[i:i+8] for i in range(0, len(idx), 8)] return lines_idx
[docs] def Write(self, mesh: Mesh) -> None: """Write cdb file from mesh information Parameters ---------- mesh : Mesh """ mesh.PrepareForOutput() self.filePointer.write("! ****** Written by Muscat package ******\n") self.filePointer.write("! ****** Please Disconnect 'Check Valid Blocked CDB File' ******\n") # self.filePointer.write("! ****** Named selections must be read inside mechanical by reimporting this cdb file' ******\n") self.filePointer.write("/PREP7\n/NOPR\n") dim = mesh.GetPointsDimensionality() numberOfPoints = mesh.GetNumberOfNodes() self.filePointer.write(f"NUMOFF,NODE,{numberOfPoints:>9}\n") self.filePointer.write(f"NUMOFF,ELEM,{mesh.GetNumberOfElements(dim):>9}\n") self.filePointer.write(f"NUMOFF,TYPE, 1\n") self.filePointer.write("/com,*********** Nodes for the whole assembly ***********\n") self.filePointer.write(f"NBLOCK,{dim},,{numberOfPoints}\n") self.filePointer.write("(1i9,3e20.9e3)\n") posn = mesh.GetPosOfNodes() for n in range(numberOfPoints): self.filePointer.write(f"{n+1}".rjust(9)) for d in range(3): self.filePointer.write(f"{posn[n,d]:1.9E}".rjust(20)) self.filePointer.write("\n") self.filePointer.write("-1\n") exportMask = {} exportMask[ED.Hexahedron_8] = [0, 1, 2, 3, 4, 5, 6, 7] exportMask[ED.Wedge_6] = [0, 1, 2, 2, 3, 4, 2, 5] exportMask[ED.Tetrahedron_4] = [0, 1, 2, 2, 3, 3, 3, 3] exportMask[ED.Pyramid_5] = [0, 1, 2, 3, 4, 4, 5, 5] exportMask[ED.Triangle_3] = [0, 1, 2, 2] exportMask[ED.Quadrangle_4] = [0, 1, 2, 3] exportMask[ED.Triangle_6] = [0, 1, 2, 3, 4, 5] exportMask[ED.Tetrahedron_10] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] from Muscat.IO.AnsysTools import MuscatToAnsysFormulation elcpt = 1 elemTypeNumber = 0 for ntype, elems in mesh.elements.items(): elemTypeNumber += 1 numberOfElements = elems.GetNumberOfElements() numberOfNodesPerElement = elems.GetNumberOfNodesPerElement() dim_elt = ED.dimensionality[ntype] if dim == dim_elt: self.filePointer.write(f"/com,*********** Elements for Body ***********\n") self.filePointer.write(f"et,{elemTypeNumber},{MuscatToAnsysFormulation[self.AnsysFormulation[dim]].get(ntype,0)}\n") mask = exportMask[ntype] if ntype in MuscatToAnsysFormulation[self.AnsysFormulation[dim]]: Solkey = "SOLID" nfield = 19 header1 = "1".rjust(9) # 1 The material number header1 += f"{elemTypeNumber}".rjust(9) # 2 The element type number header1 += "1".rjust(9) # 3 The real constant number header1 += "1".rjust(9) # 4 The real constant number header1 += "0".rjust(9) # 5 Element coordinate system number header1 += "0".rjust(9) # 6 the birth/death flag header1 += "0".rjust(9) # 7 the solid model reference number header1 += "0".rjust(9) # 8 the element shape flag header1 += f"{len(mask)}".rjust(9) # 9 number of nodes defining this element if SOLID, otherwise 0 header1 += "0".rjust(9) # 10 Not used (p-elements) header2 = "" else: header1 = "" Solkey = "" header2 = "0".rjust(9) # 2 The type of section ID. header2 += "1".rjust(9) # 3 The real constant number header2 += "1".rjust(9) # 4 The material number header2 += "0".rjust(9) # 5 Element coordinate system number self.filePointer.write(f"EBLOCK,{nfield},{Solkey},,{numberOfElements}\n") self.filePointer.write(f"({nfield}i9)\n") originalelcpt = elcpt for n in range(numberOfElements): self.filePointer.write(header1) # 1 The material number self.filePointer.write(f"{elcpt}".rjust(9)) # 11 the element number self.filePointer.write(header2) # 1 The material number elcpt += 1 if numberOfNodesPerElement <= 8: for i in mask: self.filePointer.write(f"{elems.connectivity[n,i]+1}".rjust(9)) # 12-18 the element number self.filePointer.write("\n") else: begin = ''.join(f'{str(elem):>9}' for elem in elems.connectivity[n,:8]+1) end = ''.join(f'{str(elem):>9}' for elem in elems.connectivity[n,8:]+1) self.filePointer.write(f"{begin}\n") # 12-18 the element number self.filePointer.write(f"{end}\n") # 19: the element number self.filePointer.write("-1\n") for tag in mesh.nodesTags: if len(tag) == 0: continue self.filePointer.write(f"CMBLOCK,{tag.name},NODE,{len(tag)}\n") self.filePointer.write("(8i10)\n") indices = tag.GetIds() lines_idx = self.CompactIndices(indices) for line_idx in lines_idx: idxi = ''.join(f'{str(elem+1):>10}' for elem in line_idx) self.filePointer.write(f"{idxi}".rjust(10)) self.filePointer.write("\n") for ntype, elems in mesh.elements.items(): if dim == ED.dimensionality[ntype]: for tag in elems.tags: if len(tag) == 0: continue self.filePointer.write(f"CMBLOCK,{tag.name},ELEMENT,{len(tag)}\n") self.filePointer.write("(8i10)\n") indices = tag.GetIds()+originalelcpt lines_idx = self.CompactIndices(indices) for line_idx in lines_idx: idxi = ''.join(f'{str(elem+1):>10}' for elem in line_idx) self.filePointer.write(f"{idxi}".rjust(10)) self.filePointer.write("\n") self.filePointer.write("/GO\nFINISH\n")
[docs] def WriteFromFile(self, mesh: Mesh, file: Path) -> None: """Update an existing cdb file with new mesh information Parameters ---------- mesh : Mesh file : Path Path to existing cdb file to update """ from Muscat.IO.AnsysTools import MuscatToAnsysFormulation mesh.PrepareForOutput() dim = mesh.GetPointsDimensionality() with open(file, 'r') as infile: lines = infile.readlines() i = 0 while i < len(lines): if lines[i].startswith(f"nblock,{dim},,"): numberOfPoints = mesh.GetNumberOfNodes() self.filePointer.write(f"nblock,{dim},,{numberOfPoints}\n") self.filePointer.write("(1i9,3e20.9e3)\n") posn = mesh.GetPosOfNodes() for n in range(numberOfPoints): self.filePointer.write(f"{n+1}".rjust(9)) for d in range(3): self.filePointer.write(f"{posn[n,d]:1.9E}".rjust(20)) self.filePointer.write("\n") for tag in mesh.nodesTags: if len(tag) == 0: continue self.filePointer.write(f"CMBLOCK,{tag.name},NODE,{len(tag)}\n") self.filePointer.write("(8i10)\n") tagcpt = 0 indices = tag.GetIds() while (tagcpt < len(tag)): icpt = 0 while (tagcpt < len(tag)): self.filePointer.write(f"{indices[tagcpt]+1}".rjust(10)) tagcpt += 1 self.filePointer.write("\n") i += int(lines[i].split(",")[-1]) + 2 elif lines[i].startswith("et,1,"): elcpt = 1 elemTypeNumber = 0 for ntype, elems in mesh.elements.items(): elemTypeNumber += 1 numberOfElements = elems.GetNumberOfElements() numberOfNodesPerElement = elems.GetNumberOfNodesPerElement() dim_elt = ED.dimensionality[ntype] if dim == dim_elt: self.filePointer.write(f"et,{elemTypeNumber},{MuscatToAnsysFormulation[self.AnsysFormulation[dim]].get(ntype,0)}\n") self.filePointer.write(lines[i+1]) if ntype in MuscatToAnsysFormulation[self.AnsysFormulation[dim]]: Solkey = "COMPACT" nfield = 11 header1 = "" header2 = "" else: header1 = "" Solkey = "" header2 = "0".rjust(9) # 2 The type of section ID. header2 += "1".rjust(9) # 3 The real constant number header2 += "1".rjust(9) # 4 The material number header2 += "0".rjust(9) # 5 Element coordinate system number self.filePointer.write(f"eblock,{nfield},{Solkey},,{numberOfElements}\n") self.filePointer.write(f"({nfield}i9)\n") for n in range(numberOfElements): self.filePointer.write(header1) # 1 The material number self.filePointer.write(f"{elcpt}".rjust(9)) # 11 the element number self.filePointer.write(header2) # 1 The material number elcpt += 1 for j in range(numberOfNodesPerElement): self.filePointer.write(f"{elems.connectivity[n,j]+1}".rjust(9)) # 12-18 the element number self.filePointer.write("\n") i += int(lines[i+1].split(",")[-1]) + 4 else: self.filePointer.write(lines[i]) i += 1
[docs] def CheckIntegrity(GUI: bool = False) -> str: from Muscat.MeshTools.MeshCreationTools import CreateCube mesh = CreateCube(dimensions=[3, 2, 2], ofTetras=True) # from Muscat.IO.GmshReader import ReadGmsh # from Muscat.TestData import GetTestDataPath # from Muscat.MeshTools.MeshInspectionTools import ExtractElementsByElementFilter # from Muscat.MeshContainers.Filters.FilterObjects import ElementFilter # mesh = ReadGmsh(GetTestDataPath() + "dent3D.msh") # mesh = ExtractElementsByElementFilter(mesh, ElementFilter(dimensionality=[3,2]) ) mesh.GenerateManufacturedOriginalIDs() from Muscat.Helpers.IO.TemporaryDirectory import TemporaryDirectory tempdir = TemporaryDirectory.GetTempPath() ExportElementTagsInCDBFormat(mesh, mesh.elements.GetTagsNames(), filename=tempdir+"/AnsysWriterCheckIntegrity_AnsysWriter.cdb") WriteMeshToCDB(tempdir+"/AnsysWriterCheckIntegrity_mesh.cdb", mesh) from Muscat.TestData import GetTestDataPath WriteMeshToCDB(tempdir+"/AnsysWriterCheckIntegrity_mesh.cdb", mesh, GetTestDataPath() + "exemple.cdb") return "ok"
if __name__ == '__main__': print(CheckIntegrity(True)) # pragma: no cover