Skip to content

Commit

Permalink
Successfully completed first eigenfrequency of shell and beam element…
Browse files Browse the repository at this point in the history
…s using code aster

Created tests to verify eigenfrequency analysis results with analytical solution
  • Loading branch information
Krande committed Jul 4, 2021
1 parent 2a36413 commit c78f3be
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 38 deletions.
69 changes: 63 additions & 6 deletions images/tests/test_code_aster_fem.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,35 @@
import unittest

import h5py
import numpy as np
from ada import Assembly, Beam, Part, PrimBox, PrimCyl, PrimExtrude, Material, CarbonSteel
from ada.fem import Bc, FemSet, Load, Step

from ada import Assembly, Beam, Material, Part
from ada.fem import Bc, FemSet, Step
from ada.fem.io.mesh.recipes import create_beam_mesh
from ada.fem.utils import get_beam_end_nodes
from ada.materials.metals import CarbonSteel


def fundamental_eigenfrequency(bm: Beam):
L = bm.length
E = bm.material.model.E
rho = bm.material.model.rho
I = bm.section.properties.Iy
return (1 / (2 * np.pi)) * (3.5156 / L ** 2) * np.sqrt(E * I / rho)


def test_bm():
return Beam("MyBeam", (0, 0.5, 0.5), (5, 0.5, 0.5), "IPE400", Material("S420", CarbonSteel("S420")))


class CodeAsterTests(unittest.TestCase):
def test_eigenfrequency(self):
bm = Beam("MyBeam", (0, 0.5, 0.5), (1.5, 0.5, 0.5), "IPE400", Material('S420', CarbonSteel("S420")))
def test_bm_eigenfrequency_beam(self):
bm = test_bm()
f1 = fundamental_eigenfrequency(bm)
f2 = 6.268 * f1
f3 = 17.456 * f1
print(f"1: {f1}\n2: {f2}\n3: {f3}")

p = Part("MyPart")
a = Assembly("MyAssembly") / [p / bm]
p.gmsh.mesh(0.1)
Expand All @@ -19,7 +39,44 @@ def test_eigenfrequency(self):

a.fem.add_step(Step("Eigen", "eigenfrequency"))

a.to_fem('Cantilever_CA_EIG', 'code_aster', overwrite=True)
res = a.to_fem("Cantilever_CA_EIG_bm", "code_aster", overwrite=True, execute=True)

f = h5py.File(res.results_file_path)
modes = f.get("CHA/modes___DEPL")

for mname, m in modes.items():
mode = m.attrs["NDT"]
freq = m.attrs["PDT"]

print(mode, freq)

def test_bm_eigenfrequency_shell(self):
bm = test_bm()
f1 = fundamental_eigenfrequency(bm)
f2 = 6.268 * f1
f3 = 17.456 * f1
print(f"Fundamental Eigenfrequencies\n\n1: {f1}\n2: {f2}\n3: {f3}")

p = Part("MyPart")
a = Assembly("MyAssembly") / [p / bm]
create_beam_mesh(bm, p.fem, "shell")

fix_set = p.fem.add_set(FemSet("bc_nodes", get_beam_end_nodes(bm), "nset"))
a.fem.add_bc(Bc("Fixed", fix_set, [1, 2, 3, 4, 5, 6]))

a.fem.add_step(Step("Eigen", "eigenfrequency"))

res = a.to_fem("Cantilever_CA_EIG_sh", "code_aster", overwrite=True, execute=True)

f = h5py.File(res.results_file_path)
modes = f.get("CHA/modes___DEPL")

for mname, m in modes.items():
mode = m.attrs["NDT"]
freq = m.attrs["PDT"]

print(mode, freq)


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()
2 changes: 2 additions & 0 deletions src/ada/base/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def get_edges_and_faces_from_mesh(mesh):
for elem in cell_block.data:
res = ElemShapes(el_type, elem)
edges += res.edges
if res.type in res.beam:
continue
faces += res.faces
return edges, faces

Expand Down
4 changes: 4 additions & 0 deletions src/ada/base/render_fem.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def __init__(self, result_file_path, part=None, palette=None):
self._undeformed_mesh = None
self._deformed_mesh = None

@property
def results_file_path(self):
return self._results_file_path

@property
def mesh(self):
return self._mesh
Expand Down
12 changes: 12 additions & 0 deletions src/ada/fem/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,20 @@


def femio(f):
"""
:param f: dsd
:return:
"""

@wraps(f)
def convert_fem_wrapper(*args, **kwargs):
"""
:param args:
:param kwargs:
:return:
"""
from .io_meshio import meshio_read_fem, meshio_to_fem

f_name = f.__name__
Expand Down
58 changes: 35 additions & 23 deletions src/ada/fem/io/code_aster/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from ada.config import Settings as _Settings
from ada.fem import ElemShapes, FemSection
from ada.fem.containers import FemSections

from ..utils import _folder_prep, get_fem_model_from_assembly
from .common import abaqus_to_med_type
Expand Down Expand Up @@ -91,6 +92,14 @@ def write_to_comm(assembly, part):
sections_str = write_sections(part.fem.sections)
bc_str = "\n".join([write_boundary_condition(bc) for bc in assembly.fem.bcs])
step_str = "\n".join([write_step(s, part) for s in assembly.fem.steps])
model_type_str = ""
if len(part.fem.sections.beams) > 0:
bm_elset_str = ",".join([f"'{bm_fs.elset.name}'" for bm_fs in part.fem.sections.beams])
model_type_str += f"_F(GROUP_MA=({bm_elset_str}),PHENOMENE='MECANIQUE', MODELISATION='POU_D_E',),"

if len(part.fem.sections.shells) > 0:
sh_elset_str = ",".join([f"'{bm_fs.elset.name}'" for bm_fs in part.fem.sections.shells])
model_type_str += f"_F(GROUP_MA=({sh_elset_str}),PHENOMENE='MECANIQUE', MODELISATION='DKT',),"

comm_str = f"""#
# COMM file created by ADA (Assembly for Design and Analysis)
Expand All @@ -103,7 +112,10 @@ def write_to_comm(assembly, part):
mesh = LIRE_MAILLAGE(FORMAT="MED", UNITE=20)
model = AFFE_MODELE(
AFFE=_F(MODELISATION=("DKT",), PHENOMENE="MECANIQUE", TOUT="OUI"), MAILLAGE=mesh
AFFE=(
{model_type_str}
),
MAILLAGE=mesh
)
# Materials
Expand Down Expand Up @@ -160,7 +172,7 @@ def write_material(material):
"""


def write_sections(fem_sections):
def write_sections(fem_sections: FemSections):
"""
:param fem_sections:
Expand All @@ -171,20 +183,20 @@ def write_sections(fem_sections):

if len(fem_sections.shells) > 0:
mat_assign_str, shell_sections_str = [
"".join(x) for x in zip(*list(map(write_shell_section, fem_sections.shells)))
"".join(x) for x in zip(*[write_shell_section(sh) for sh in fem_sections.shells])
]
shell_sections_str = f"\n COQUE=(\n{shell_sections_str}\n ),"
else:
shell_sections_str = f"\n COQUE=(),"
shell_sections_str = "\n COQUE=(),"

if len(fem_sections.beams) > 0:
mat_assign_str, beam_sections_str, orientations_str = [
"".join(x) for x in zip(*list(map(write_beam_section, fem_sections.beams)))
"".join(x) for x in zip(*[write_beam_section(bm) for bm in fem_sections.beams])
]
beam_sections_str = f"\n POUTRE=(\n{beam_sections_str}\n ),"
beam_sections_str += f"\n ORIENTATION=(\n{orientations_str}\n ),"
else:
beam_sections_str = f"\n POUTRE=(),"
beam_sections_str = "\n POUTRE=(),"

if len(fem_sections.solids) > 0:
logging.error("Solid section export to Code Aster is not yet supported")
Expand All @@ -203,11 +215,8 @@ def write_sections(fem_sections):
# EPAIS: thickness
# VECTEUR: a direction of reference in the tangent plan
# Beam elements:
#
element = AFFE_CARA_ELEM(
MODELE=model,{shell_sections_str}{beam_sections_str}
MODELE=model,{shell_sections_str}{beam_sections_str}{solid_sections_str}
)
"""

Expand All @@ -230,15 +239,18 @@ def write_shell_section(fem_sec: FemSection):
def write_beam_section(fem_sec: FemSection):
mat_name = fem_sec.material.name
sec_name = fem_sec.elset.name
#
p = fem_sec.section.properties

values = ",".join([str(x) for x in [p.Ax, p.Iy, p.Iz, p.Ix]])

local_vec = str(tuple(fem_sec.local_y))

mat_ = f' _F(MATER=({mat_name},), GROUP_MA="{sec_name}"),\n'
sec_str = f""" _F(
GROUP_MA=("{sec_name}"),
SECTION = 'RECTANGLE',
CARA = ('HY', 'HZ'),
VALE = (0.2, 0.4)
SECTION = 'GENERALE',
CARA = ('A', 'IY', 'IZ', 'JX'),
VALE = ({values})
),
"""
orientations = f""" _F(
Expand Down Expand Up @@ -383,23 +395,23 @@ def step_eig_str(step, part):
raise NotImplementedError("Number of BC sets is for now limited to 1 for eigenfrequency analysis")
bc = part.get_assembly().fem.bcs[0]
return f"""
#modal analysis
#modal analysis
ASSEMBLAGE(
MODELE=model,
# CHAM_MATER=material,
# CARA_ELEM=element,
MODELE=model,
CHAM_MATER=material,
CARA_ELEM=element,
CHARGE= {bc.name}_bc,
NUME_DDL=CO('dofs' ),
NUME_DDL=CO('dofs' ),
MATR_ASSE = (
_F(MATRICE=CO('stiff'), OPTION ='RIGI_MECA',),
_F(MATRICE=CO('stiff'), OPTION ='RIGI_MECA',),
_F(MATRICE=CO('mass'), OPTION ='MASS_MECA', ),
),
),
)
modes = CALC_MODES(
CALC_FREQ=_F(NMAX_FREQ={step.eigenmodes}, ) ,
SOLVEUR_MODAL=_F(METHODE='SORENSEN'),
SOLVEUR_MODAL=_F(METHODE='SORENSEN'),
MATR_MASS=mass,
MATR_RIGI=stiff,
MATR_RIGI=stiff,
OPTION='PLUS_PETITE',
)
Expand Down
6 changes: 1 addition & 5 deletions src/ada/fem/io/mesh/recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def create_plate_mesh(


def create_beam_mesh(
beam, fem, geom_repr="solid", max_size=0.1, order=1, algo=8, tol=1e-3, interactive=False, gmsh_session=None
beam, fem, geom_repr="shell", max_size=0.1, order=1, algo=8, tol=1e-3, interactive=False, gmsh_session=None
):
"""
:param beam:
Expand Down Expand Up @@ -137,8 +137,6 @@ def create_beam_mesh(
model.add(name)

if geom_repr in ["shell", "solid"]:
# geom_so = beam.solid
# geom_sh = beam.shell
beam.to_stp(temp_dir / name, geom_repr=geom_repr)
gmsh_session.open(str(temp_dir / f"{name}.stp"))
else: # beam
Expand All @@ -150,8 +148,6 @@ def create_beam_mesh(
if len(e) == 0:
e = [(0, model.geo.addPoint(*p2.tolist(), max_size))]

# line = model.geo.addLine(s[0][1], e[0][1])

model.geo.synchronize()
model.mesh.setRecombine(3, 1)
model.mesh.generate(3)
Expand Down
12 changes: 9 additions & 3 deletions src/ada/fem/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import numpy as np


def get_eldata(fem_source):
"""
Expand Down Expand Up @@ -76,7 +79,10 @@ def get_beam_end_nodes(bm, end=1, part=None):
nodes = p.fem.nodes
w = bm.section.w_btn
h = bm.section.h
members = [
e for e in nodes.get_by_volume((-0.1, -(w / 2) * 1.1, -(h / 2) * 1.1), (0.02, (w / 2) * 1.1, (h / 2) * 1.1))
]

min_np = np.array([-0.1, -(w / 2) * 1.1, -(h / 2) * 1.1])
max_np = np.array([0.02, (w / 2) * 1.1, (h / 2) * 1.1])
n = bm.n1.p if end == 1 else bm.n2.p

members = [e for e in nodes.get_by_volume(n + min_np, n + max_np)]
return members
3 changes: 2 additions & 1 deletion tests/test_io_cache.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import unittest
import time
import unittest

from ada import Assembly
from ada.config import Settings
from ada.param_models.basic_module import SimpleStru
Expand Down

0 comments on commit c78f3be

Please sign in to comment.