Skip to content

Commit

Permalink
Using placement as default input method for Plate orientation as oppo…
Browse files Browse the repository at this point in the history
…sed to origin, xdir and zdir (normal).

Created test to handle line/shell meshing to ensure line elements are connected to adjoining shell elements
  • Loading branch information
Krande committed Oct 21, 2021
1 parent 2522a2a commit 44423df
Show file tree
Hide file tree
Showing 24 changed files with 104 additions and 72 deletions.
2 changes: 2 additions & 0 deletions src/ada/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
Shape,
)
from ada.concepts.structural import Beam, Plate, Wall
from ada.concepts.transforms import Placement
from ada.config import User
from ada.materials import Material
from ada.sections import Section
Expand Down Expand Up @@ -75,6 +76,7 @@ def from_fem(
"Material",
"Shape",
"Node",
"Placement",
"PrimBox",
"PrimCyl",
"PrimExtrude",
Expand Down
9 changes: 6 additions & 3 deletions src/ada/concepts/connections.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from typing import List

from ada.base.physical_objects import BackendGeom
from ada.concepts.containers import Beams
from ada.concepts.containers import Beams, Connections
from ada.concepts.primitives import PrimBox
from ada.concepts.structural import Beam

Expand Down Expand Up @@ -51,8 +51,8 @@ class JointBase(BackendGeom, ABC):
mem_types: list
num_mem: int

def __init__(self, name, members, centre):
super(JointBase, self).__init__(name)
def __init__(self, name, members, centre, parent: Connections = None):
super(JointBase, self).__init__(name, parent)
self._init_check(members)
self._centre = centre
self._beams = Beams(members)
Expand All @@ -62,6 +62,9 @@ def __init__(self, name, members, centre):
m.connected_to.append(self)
m._ifc_elem = None

if parent is not None:
parent.parent.add_set(f"{name}_joint", members)

def _init_check(self, members):
if self.__class__.__name__ == "JointBase":
return None
Expand Down
11 changes: 8 additions & 3 deletions src/ada/concepts/containers.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ class BaseCollections:
def __init__(self, parent):
self._parent = parent

@property
def parent(self):
""":rtype: ada.Part"""
return self._parent


class Beams(BaseCollections):
"""A collections of Beam objects"""
Expand Down Expand Up @@ -307,7 +312,7 @@ def add(self, joint, point_tol=Settings.point_tol):
return self._nmap[node]
else:
self._nmap[node] = joint

joint.parent = self
self._dmap[joint.name] = joint
self._connections.append(joint)

Expand All @@ -333,11 +338,11 @@ def find(self, out_of_plane_tol=0.1, joint_func=None, point_tol=Settings.point_t

for node, mem in nmap.items():
if joint_func is not None:
joint = joint_func(next(self._counter), mem, node.p)
joint = joint_func(next(self._counter), mem, node.p, parent=self)
if joint is None:
continue
else:
joint = JointBase(next(self._counter), mem, node.p)
joint = JointBase(next(self._counter), mem, node.p, parent=self)

self.add(joint, point_tol=point_tol)

Expand Down
19 changes: 6 additions & 13 deletions src/ada/concepts/structural.py
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ class Plate(BackendGeom):
:param nodes: List of coordinates that make up the plate. Points can be Node, tuple or list
:param t: Thickness of plate
:param mat: Material. Can be either Material object or built-in materials ('S420' or 'S355')
:param origin: Explicitly define origin of plate. If not set
:param placement: Explicitly define origin of plate. If not set
"""

def __init__(
Expand All @@ -752,9 +752,7 @@ def __init__(
t,
mat="S420",
use3dnodes=False,
origin=None,
normal=None,
xdir=None,
placement=Placement(),
pl_id=None,
offset=None,
colour=None,
Expand All @@ -766,10 +764,8 @@ def __init__(
units="m",
ifc_elem=None,
guid=None,
**kwargs,
):
# TODO: Support generation of plate object from IFC elem
placement = Placement(origin=origin, xdir=xdir, zdir=normal)
super().__init__(name, guid=guid, metadata=metadata, units=units, ifc_elem=ifc_elem, placement=placement)

points2d = None
Expand All @@ -780,9 +776,7 @@ def __init__(
self.guid = ifc_elem.GlobalId
t = props["t"]
points2d = props["nodes2d"]
origin = props["origin"]
normal = props["normal"]
xdir = props["xdir"]
self.placement = Placement(props["origin"], xdir=props["xdir"], zdir=props["normal"])
ifc_geom = props["ifc_geom"]
colour = props["colour"]
opacity = props["opacity"]
Expand All @@ -808,12 +802,11 @@ def __init__(
self._poly = CurvePoly(
points3d=points3d,
points2d=points2d,
normal=normal,
origin=origin,
xdir=xdir,
normal=self.placement.zdir,
origin=self.placement.origin,
xdir=self.placement.xdir,
tol=tol,
parent=self,
**kwargs,
)
self.colour = colour
self._offset = offset
Expand Down
10 changes: 5 additions & 5 deletions src/ada/concepts/transforms.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Iterable
from typing import Iterable, Union

import numpy as np
from pyquaternion import Quaternion
Expand Down Expand Up @@ -31,10 +31,10 @@ def to_rot_matrix(self):

@dataclass
class Placement:
origin: np.ndarray = np.array([0, 0, 0], dtype=float)
xdir: np.ndarray = None
ydir: np.ndarray = None
zdir: np.ndarray = None
origin: Union[list, tuple, np.ndarray] = np.array([0, 0, 0], dtype=float)
xdir: Union[list, tuple, np.ndarray] = None
ydir: Union[list, tuple, np.ndarray] = None
zdir: Union[list, tuple, np.ndarray] = None
parent = None

def __post_init__(self):
Expand Down
12 changes: 6 additions & 6 deletions src/ada/param_models/basic_joints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ def eval_joint_req(joint: JointBase, intersecting_members):
return jrc.eval_joint_req()


def joint_map(joint_name, intersecting_members, centre) -> Union[JointBase, None]:
def joint_map(joint_name, intersecting_members, centre, parent=None) -> Union[JointBase, None]:
joints = [JointB, JointIXZ]

for joint in joints:
if eval_joint_req(joint, intersecting_members):
return joint(joint_name, intersecting_members, centre)
return joint(joint_name, intersecting_members, centre, parent=None)

member_types = [m.section.type for m in intersecting_members]
logging.debug(f'Unable to find matching Joint using joint map for members "{member_types}"')
Expand All @@ -28,8 +28,8 @@ class JointIXZ(JointBase):
beamtypes = ["IPE", "IPE"]
num_mem = 2

def __init__(self, name, members, centre):
super(JointIXZ, self).__init__(name, members, centre)
def __init__(self, name, members, centre, parent=None):
super(JointIXZ, self).__init__(name, members, centre, parent=parent)

non_girder = None
gi1 = None
Expand Down Expand Up @@ -66,8 +66,8 @@ class JointB(JointBase):
beamtypes = ["IG", "IG", "IG"]
num_mem = 3

def __init__(self, name, members, centre):
super(JointB, self).__init__(name, members, centre)
def __init__(self, name, members, centre, parent=None):
super(JointB, self).__init__(name, members, centre, parent=parent)

column = None
gi1 = None
Expand Down
6 changes: 2 additions & 4 deletions src/ada/param_models/basic_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ def __init__(
name + "_pl",
points,
pl_thick,
origin=self.placement.origin,
xdir=self.placement.xdir,
normal=self.placement.zdir,
placement=self.placement,
use3dnodes=use3dnodes,
)
self.add_plate(plate)
Expand All @@ -55,7 +53,7 @@ def __init__(
diff = xmax - xmin - tot_spacing
x = diff / 2
y = diff / 2
for i in range(0, snum):
for i in range(0, snum + 1):
if stringer_dir == "Y":
p1 = (x, ymin, z)
p2 = (x, ymax, z)
Expand Down
23 changes: 12 additions & 11 deletions tests/concept_objects/test_stru_plates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

from common import dummy_display

from ada import Assembly, Part, Plate
from ada import Assembly, Part, Placement, Plate
from ada.config import Settings
from ada.core.constants import O, X, Z

test_dir = Settings.test_dir / "plates"


class TestPlates(unittest.TestCase):
def setUp(self) -> None:
self.atts = dict(origin=(0, 0, 0), xdir=(1, 0, 0), normal=(0, 0, 1))
self.atts = dict(placement=Placement(origin=(0, 0, 0), xdir=(1, 0, 0), zdir=(0, 0, 1)))
self.atts2 = dict(placement=Placement(origin=(0, 0, 0), xdir=(1, 0, 0), zdir=(0, -1, 0)))

def test_3dinit(self):
pl1 = Plate("MyPl", [(0, 0, 0), (5, 0, 0), (5, 5, 0), (0, 5, 0)], 20e-3, use3dnodes=True)
Expand All @@ -28,8 +28,7 @@ def test_roundtrip_fillets(self):
pl1 = Plate("MyPl", [(0, 0, 0.2), (5, 0), (5, 5), (0, 5)], 20e-3, **self.atts)
p.add_plate(pl1)

atts2 = dict(origin=(0, 0, 0), xdir=(1, 0, 0), normal=(0, -1, 0))
pl2 = Plate("MyPl2", [(0, 0, 0.2), (5, 0, 0.2), (5, 5), (0, 5)], 20e-3, **atts2)
pl2 = Plate("MyPl2", [(0, 0, 0.2), (5, 0, 0.2), (5, 5), (0, 5)], 20e-3, **self.atts2)
p.add_plate(pl2)

a.to_ifc(test_dir / "my_plate_simple.ifc")
Expand All @@ -42,17 +41,15 @@ def test_2ifc_simple(self):
a = Assembly("ExportedPlates")
p = Part("MyPart")
a.add_part(p)

atts2 = dict(origin=(0, 0, 0), xdir=(1, 0, 0), normal=(0, -1, 0))
pl2 = Plate("MyPl2", [(0, 0, 0.2), (5, 0, 0.2), (5, 5), (0, 5)], 20e-3, **atts2)
pl2 = Plate("MyPl2", [(0, 0, 0.2), (5, 0, 0.2), (5, 5), (0, 5)], 20e-3, **self.atts2)
p.add_plate(pl2)
a.to_ifc(test_dir / "my_plate_poly.ifc")


class BasicShapes(unittest.TestCase):
def test_triangle(self):
local_points2d = [(0, 0), (1, 0, 0.1), (0.5, 0.5)]
pl = Plate("test", local_points2d, 20e-3, origin=O, normal=Z, xdir=X)
pl = Plate("test", local_points2d, 20e-3)

a = Assembly() / [Part("te") / pl]
a.to_ifc(test_dir / "triangle_plate.ifc")
Expand Down Expand Up @@ -80,7 +77,9 @@ def test_ex1(self):
[-15.14, 261.52],
]
thick = 30
pl = Plate("test", local_points2d, thick, origin=origin, normal=csys[2], xdir=csys[0], units="mm")
pl = Plate(
"test", local_points2d, thick, placement=Placement(origin=origin, zdir=csys[2], xdir=csys[0]), units="mm"
)

a = Assembly() / [Part("te") / pl]
a.to_ifc(test_dir / "error_plate.ifc")
Expand All @@ -106,7 +105,9 @@ def test_ex2(self):
[-34.99999999999994, 500.0330344161669, -7.881391015070461e-12],
]
thick = 30
pl = Plate("test2", local_points2d, thick, origin=origin, normal=csys[2], xdir=csys[0], units="mm")
pl = Plate(
"test2", local_points2d, thick, placement=Placement(origin=origin, zdir=csys[2], xdir=csys[0]), units="mm"
)

a = Assembly(units="mm") / [Part("te", units="mm") / pl]
a.to_ifc(test_dir / "error_plate2.ifc")
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Empty file added tests/fem/meshing/__init__.py
Empty file.
29 changes: 29 additions & 0 deletions tests/fem/meshing/test_intersecting_edges.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import ada
from ada.core.utils import Counter

test_dir = ada.config.Settings.test_dir / "meshing"


def test_edges_intersect():
bm_name = Counter(1, "bm")
pl = ada.Plate("MyPlate", [(0, 0), (1, 0), (1, 1), (0, 1)], 10e-3)
points = pl.poly.points3d
objects = [pl]

# Beams along 3 of 4 along circumference
for p1, p2 in zip(points[:-1], points[1:]):
objects.append(ada.Beam(next(bm_name), p1, p2, "IPE100"))

# Beam along middle in x-dir
objects.append(ada.Beam(next(bm_name), (0, 0.5, 0.0), (1, 0.5, 0), "IPE100"))

# Beam along diagonal
objects.append(ada.Beam(next(bm_name), (0, 0, 0.0), (1, 1, 0), "IPE100"))

a = ada.Assembly() / (ada.Part("MyPart") / objects)
p = a.get_part("MyPart")
p.connections.find()
p.fem = p.to_fem_obj(0.1)

a.to_fem("MyIntersectingedge_ufo", "usfos", overwrite=True, scratch_dir=test_dir)
a.to_ifc(test_dir / "IntersectingFEM", include_fem=False)
Empty file.
8 changes: 4 additions & 4 deletions tests/fem/test_elem_mesh.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import unittest

from ada import Assembly, Beam, Part, Plate, PrimCyl, PrimExtrude
from ada import Assembly, Beam, Part, Placement, Plate, PrimCyl, PrimExtrude
from ada.config import Settings
from ada.core.utils import align_to_plate
from ada.fem.meshing import GmshOptions

test_folder = Settings.test_dir / "mesh"
test_dir = Settings.test_dir / "mesh"

atts = dict(origin=(0, 0, 0), xdir=(1, 0, 0), normal=(0, 0, 1))
atts2 = dict(origin=(1, 0, -0.1), xdir=(0, 0, 1), normal=(-1, 0, 0))
atts = dict(placement=Placement(origin=(0, 0, 0), xdir=(1, 0, 0), zdir=(0, 0, 1)))
atts2 = dict(placement=Placement(origin=(1, 0, -0.1), xdir=(0, 0, 1), zdir=(-1, 0, 0)))


class BeamIO(unittest.TestCase):
Expand Down
4 changes: 2 additions & 2 deletions tests/fem/test_gmsh_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ def setUp(self) -> None:
self.bm2 = Beam("bm2", (1.1, 0, 1), (2, 0, 1), "IPE300")
self.bm3 = Beam("bm3", (2.1, 0, 1), (3, 0, 1), "IPE300")

pl_atts = dict(origin=(1, 1, 1), xdir=(1, 0, 0), normal=(0, 0, 1))
placement = Placement(origin=(1, 1, 1), xdir=(1, 0, 0), zdir=(0, 0, 1))
pl_points = [(0, 0), (1, 0), (1, 1), (0, 1)]
self.pl1 = Plate("MyPlate", pl_points, 10e-3, **pl_atts)
self.pl1 = Plate("MyPlate", pl_points, 10e-3, placement=placement)

self.pipe = Pipe("MyPipe", [(0, 0.5, 0), (1, 0.5, 0), (1.2, 0.7, 0.2), (1.5, 0.7, 0.2)], "OD120x6")

Expand Down
Loading

0 comments on commit 44423df

Please sign in to comment.