Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
993e9b2
new results structure
Jan 12, 2025
184de6d
new modal results
Jan 19, 2025
1bae4ce
section forces
Jan 19, 2025
40e09e8
stress2D field
Jan 19, 2025
f87181b
spinner decorator
Jan 22, 2025
e42f01c
clean up input file
Jan 22, 2025
fdb1108
new output requests
Jan 23, 2025
4f88c1c
updated field results
Jan 23, 2025
ec246a5
resultants
Jan 23, 2025
cc1f8c1
type annotations and other fixes
Jan 31, 2025
d76fdb5
deepcopy almost working
Jan 31, 2025
cb715b1
copy working - needs clean up
Feb 1, 2025
7557bbf
clean up
Feb 1, 2025
94f411d
part_keys
Feb 1, 2025
3927a99
interface detection
Feb 1, 2025
32c7fb3
cluster planes
Feb 2, 2025
7969fd1
group tools
Feb 5, 2025
d77dc24
remove outputs
Feb 6, 2025
0b4466e
multiple results databases
Feb 10, 2025
eec995f
support for c3d10
Feb 16, 2025
66e16bf
patterns fix
Feb 16, 2025
7733171
new groups
Feb 22, 2025
0c73e7a
part_method
Feb 22, 2025
1edbf53
groups
Feb 23, 2025
bff7866
interfaces
Mar 9, 2025
19d2fa1
interfacesGroup
Mar 20, 2025
d705a8e
removed patterns
Mar 22, 2025
035176f
remove input_key
Mar 22, 2025
16e0c97
clean up
Mar 22, 2025
2425604
imposed disp
Mar 23, 2025
49bdeec
step increments
Mar 23, 2025
7d3c4e7
linear connectors
Mar 26, 2025
419f7db
reference point
Mar 26, 2025
b1a52d6
Merge branch 'dev' of github.com:fea2/compas_fea2 into dev
Mar 26, 2025
6b37ffb
tol in find_faces
franaudo May 5, 2025
12d762f
kdtree
May 5, 2025
680324c
Merge branch 'dev' of github.com:fea2/compas_fea2 into dev
May 5, 2025
3b93068
clean-up
franaudo May 7, 2025
7d5eef1
Merge branch 'dev'
franaudo May 7, 2025
f6723eb
Fixes #10 : Unicode Error Debug
May 9, 2025
7e1ef03
Fixes #9 : LoadCombination debug
May 9, 2025
97d5ec4
show_deformed debug
May 22, 2025
f9da5e0
Merge pull request #11 from InesChampagne/fix-issue-10
franaudo May 23, 2025
da3cc17
Merge pull request #12 from InesChampagne/fix-issue-9
franaudo May 23, 2025
13002d0
Merge pull request #17 from InesChampagne/fix-issue-15
franaudo May 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ indent_size = 4

[LICENSE]
insert_final_newline = false

2 changes: 1 addition & 1 deletion docs/api/compas_fea2.model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Parts
.. autosummary::
:toctree: generated/

DeformablePart
Part
RigidPart

Nodes
Expand Down
2 changes: 1 addition & 1 deletion docs/api/compas_fea2.units.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Units
********************************************************************************

compas_fe2 can use Pint for units consistency.
compas_fea2 can use Pint for units consistency.
25 changes: 0 additions & 25 deletions docs/api/compas_fea2.utilities.rst

This file was deleted.

11 changes: 1 addition & 10 deletions docs/userguide/basics.model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,11 @@ Point(x=0.0, y=0.0, z=0.0)
Besides coordinates, nodes have many other (optional) attributes.

>>> node.mass
(None, None, None)
[None, None, None, None, None, None]
>>> node.temperature
>>>
>>> node.dof
{'x': True, 'y': True, 'z': True, 'xx': True, 'yy': True, 'zz': True}
>>> node.loads
{}
>>> node.displacements
{}

Nodes also have a container for storing calculation results.

>>> node.results
{}


Elements
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ compas_viewer
Click
matplotlib
pint
python-dotenv
python-dotenv
h5py
matplotlib
17 changes: 0 additions & 17 deletions scripts/shape_transformation.py

This file was deleted.

10 changes: 4 additions & 6 deletions src/compas_fea2/UI/viewer/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
from .viewer import FEA2Viewer
from .scene import FEA2ModelObject
from .scene import FEA2StepObject
from .scene import FEA2StressFieldResultsObject
from .scene import FEA2DisplacementFieldResultsObject
from .scene import FEA2ReactionFieldResultsObject
from .scene import FEA2Stress2DFieldResultsObject
from .scene import FEA2NodeFieldResultsObject

from .primitives import (
_BCShape,
Expand All @@ -22,7 +21,6 @@
"ArrowShape",
"FEA2ModelObject",
"FEA2StepObject",
"FEA2StressFieldResultsObject",
"FEA2DisplacementFieldResultsObject",
"FEA2ReactionFieldResultsObject",
"FEA2Stress2DFieldResultsObject",
"FEA2NodeFieldResultsObject",
]
15 changes: 7 additions & 8 deletions src/compas_fea2/UI/viewer/drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from compas.geometry import Line


def draw_field_vectors(field_locations, field_vectors, scale_results, translate=0, high=None, low=None, cmap=None, **kwargs):
def draw_field_vectors(locations, vectors, scale_results, translate=0, high=None, low=None, cmap=None, **kwargs):
"""Display a given vector field.

Parameters
Expand All @@ -17,25 +17,24 @@ def draw_field_vectors(field_locations, field_vectors, scale_results, translate=
translate : float
The translation factor for the results.
"""
vectors = []
colors = []

lines = []
if cmap:
lengths = [v.length for v in field_vectors]
lengths = [v.length for v in vectors]
min_value = high or min(lengths)
max_value = low or max(lengths)
else:
colors = [Color.red()] * len(field_vectors)
colors = [Color.red()] * len(vectors)

for pt, vector in zip(list(field_locations), list(field_vectors)):
for pt, vector in zip(list(locations), list(vectors)):
if vector.length == 0:
continue
else:
v = vector.scaled(scale_results)
vectors.append(Line.from_point_and_vector(pt, v).translated(v * translate))
lines.append(Line.from_point_and_vector(pt, v).translated(v * translate))
if cmap:
colors.append(cmap(vector.length, minval=min_value, maxval=max_value))
return vectors, colors
return lines, colors


def draw_field_contour(model, field_locations, field_results, high=None, low=None, cmap=None, **kwargs):
Expand Down
125 changes: 36 additions & 89 deletions src/compas_fea2/UI/viewer/scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
from __future__ import division
from __future__ import print_function

from compas.scene import SceneObject # noqa: F401
from compas.colors import Color
from compas.colors import ColorMap
from compas.geometry import Vector

from .drawer import draw_field_contour
from .drawer import draw_field_vectors

from compas.scene import SceneObject # noqa: F401
from compas_viewer.scene import BufferGeometry # noqa: F401
from compas_viewer.scene import Collection
from compas_viewer.scene import GroupObject
from compas_viewer.scene import GroupObject # noqa: F401

from compas_fea2.model.bcs import FixedBC
from compas_fea2.model.bcs import PinnedBC
from compas_fea2.model.bcs import RollerBCX
Expand All @@ -21,6 +19,9 @@
from compas_fea2.UI.viewer.primitives import PinBCShape
from compas_fea2.UI.viewer.primitives import RollerBCShape

from .drawer import draw_field_contour
from .drawer import draw_field_vectors

color_palette = {
"faces": Color.from_hex("#e8e5d4"),
"edges": Color.from_hex("#4554ba"),
Expand Down Expand Up @@ -75,7 +76,7 @@ def __init__(self, fast=False, show_bcs=True, show_parts=True, show_connectors=T
line_color = kwargs.get("line_color", color_palette["edges"])
show_faces = kwargs.get("show_faces", True)
show_lines = kwargs.get("show_lines", False)
show_nodes = kwargs.get("show_nodes", False)
show_nodes = kwargs.get("show_nodes", True)
opacity = kwargs.get("opacity", 1.0)
part_meshes = []
if show_parts:
Expand Down Expand Up @@ -209,14 +210,14 @@ def __init__(self, scale_factor=1, **kwargs):
step = kwargs.pop("item")

# DRAW PATTERNS
patterns = []
for pattern in step.patterns:
pattern_forces = []
for node, load in pattern.node_load:
loadfields = []
for load_field in step.load_fields:
loadfield_forces = []
for node, load in load_field.node_load:
x = load.x or 0
y = load.y or 0
z = load.z or 0
pattern_forces.append(
loadfield_forces.append(
(
Vector(x * scale_factor, y * scale_factor, z * scale_factor), # .to_mesh(anchor=node.point)
{
Expand All @@ -226,19 +227,19 @@ def __init__(self, scale_factor=1, **kwargs):
},
)
)
patterns.append(
loadfields.append(
(
pattern_forces,
loadfield_forces,
{
"name": f"PATTERN-{pattern.name}",
"name": f"LOADFIELD-{load_field.name}",
},
)
)

super().__init__(item=patterns, name=f"STEP-{step.name}", componets=None, **kwargs)
super().__init__(item=loadfields, name=f"STEP-{step.name}", componets=None, **kwargs)


class FEA2StressFieldResultsObject(GroupObject):
class FEA2Stress2DFieldResultsObject(GroupObject):
"""StressFieldResults object for visualization.

Parameters
Expand All @@ -254,83 +255,30 @@ class FEA2StressFieldResultsObject(GroupObject):

"""

def __init__(self, step, scale_factor=1, components=None, **kwargs):
def __init__(self, model, components=None, show_vectors=1, plane="mid", show_contour=False, **kwargs):
field = kwargs.pop("item")

field_locations = list(field.locations(step))
field_locations = [e.reference_point for e in field.locations]

if not components:
components = [0, 1, 2]
names = {0: "min", 1: "mid", 2: "max"}
colors = {0: Color.blue(), 1: Color.yellow(), 2: Color.red()}

collections = []
for component in components:
field_results = [v[component] for v in field.principal_components_vectors(step)]
lines, _ = draw_field_vectors(field_locations, field_results, scale_factor, translate=-0.5)
collections.append((Collection(lines), {"name": f"PS-{names[component]}", "linecolor": colors[component], "linewidth": 3}))

super().__init__(item=collections, name=f"RESULTS-{field.name}", **kwargs)


class FEA2DisplacementFieldResultsObject(GroupObject):
"""DisplacementFieldResults object for visualization.

Parameters
----------
field : :class:`compas_fea2.results.Field`
The field to visualize.
step : :class:`compas_fea2.problem.steps.Step`
The step to visualize.
scale_factor : float
The scale factor for the visualization.
components : list
The components to visualize.

"""

# FIXME: component is not used
def __init__(self, step, component=None, show_vectors=1, show_contour=False, **kwargs):

field = kwargs.pop("item")
cmap = kwargs.get("cmap", ColorMap.from_palette("hawaii"))

group_elements = []
if show_vectors:
vectors, colors = draw_field_vectors([n.point for n in field.locations(step)], list(field.vectors(step)), show_vectors, translate=0, cmap=cmap)
# group_elements.append((Collection(vectors), {"name": f"DISP-{component}", "linecolors": colors, "linewidth": 3}))
for v, c in zip(vectors, colors):
group_elements.append((v, {"name": f"DISP-{component}", "linecolor": c, "linewidth": 3}))
for component in components:
field_results = [v[component] for v in field.principal_components_vectors(plane)]
lines, _ = draw_field_vectors(field_locations, field_results, show_vectors, translate=-0.5)
collections.append((Collection(lines), {"name": f"PS-{names[component]}", "linecolor": colors[component], "linewidth": 3}))

if show_contour:
from compas_fea2.model.elements import BeamElement

field_locations = list(field.locations(step))
field_results = list(field.component(step, component))
min_value = min(field_results)
max_value = max(field_results)
part_vertexcolor = draw_field_contour(step.model, field_locations, field_results, min_value, max_value, cmap)

# DRAW CONTOURS ON 2D and 3D ELEMENTS
for part, vertexcolor in part_vertexcolor.items():
group_elements.append((part._discretized_boundary_mesh, {"name": part.name, "vertexcolor": vertexcolor, "use_vertexcolors": True}))
raise NotImplementedError("Contour visualization not implemented for stress fields.")

# DRAW CONTOURS ON 1D ELEMENTS
for part in step.model.parts:
for element in part.elements:
vertexcolor = {}
if isinstance(element, BeamElement):
for c, n in enumerate(element.nodes):
v = field_results[field_locations.index(n)]
for p in range(len(element.section._shape.points)):
vertexcolor[p + c * len(element.section._shape.points)] = cmap(v, minval=min_value, maxval=max_value)
# vertexcolor = {c: Color.red() for c in range(2*len(element.section._shape.points))}
group_elements.append((element.outermesh, {"name": element.name, "vertexcolor": vertexcolor, "use_vertexcolors": True}))
super().__init__(item=collections, name=f"STRESS-{field.name}", **kwargs)

super().__init__(item=group_elements, name=f"RESULTS-{field.name}", **kwargs)


class FEA2ReactionFieldResultsObject(GroupObject):
class FEA2NodeFieldResultsObject(GroupObject):
"""DisplacementFieldResults object for visualization.

Parameters
Expand All @@ -346,34 +294,33 @@ class FEA2ReactionFieldResultsObject(GroupObject):

"""

def __init__(self, step, component, show_vectors=1, show_contour=False, **kwargs):
# FIXME: component is not used

def __init__(self, components=None, show_vectors=1, show_contour=False, **kwargs):
field = kwargs.pop("item")
cmap = kwargs.get("cmap", ColorMap.from_palette("hawaii"))
components = components or ["x", "y", "z"]

group_elements = []
if show_vectors:
vectors, colors = draw_field_vectors([n.point for n in field.locations(step)], list(field.vectors(step)), show_vectors, translate=0, cmap=cmap)
# group_elements.append((Collection(vectors), {"name": f"DISP-{component}", "linecolors": colors, "linewidth": 3}))
vectors, colors = draw_field_vectors([n.point for n in field.locations], list(field.components_vectors(components)), show_vectors, translate=0, cmap=cmap)

for v, c in zip(vectors, colors):
group_elements.append((v, {"name": f"DISP-{component}", "linecolor": c, "linewidth": 3}))
group_elements.append((v, {"name": f"DISP-{''.join(components)}", "linecolor": c, "linewidth": 3}))

if show_contour:
from compas_fea2.model.elements import BeamElement

field_locations = list(field.locations(step))
field_results = list(field.component(step, component))
field_locations = list(field.locations)
field_results = [v.length for v in field.components_vectors(components)]
min_value = min(field_results)
max_value = max(field_results)
part_vertexcolor = draw_field_contour(step.model, field_locations, field_results, min_value, max_value, cmap)
part_vertexcolor = draw_field_contour(field.model, field_locations, field_results, min_value, max_value, cmap)

# DRAW CONTOURS ON 2D and 3D ELEMENTS
for part, vertexcolor in part_vertexcolor.items():
group_elements.append((part._discretized_boundary_mesh, {"name": part.name, "vertexcolor": vertexcolor, "use_vertexcolors": True}))

# DRAW CONTOURS ON 1D ELEMENTS
for part in step.model.parts:
for part in field.model.parts:
for element in part.elements:
vertexcolor = {}
if isinstance(element, BeamElement):
Expand Down
Loading
Loading