Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7382db3
Fixed compas_CGAL dependency issue
Baraa-Elmoussa May 4, 2026
2c60da4
Merge branch 'BlockResearchGroup:main' into LMGC90-problem
Baraa-Elmoussa May 4, 2026
62dd2b9
Added Change to CHANGELOG.md
Baraa-Elmoussa May 4, 2026
27dd7c5
CRA Blockmodel to Assembly Function
Baraa-Elmoussa May 5, 2026
7d4f353
Moved BlockModel import
Baraa-Elmoussa May 5, 2026
ac6728c
Modfied Scalling - Fixed 1 Based LMGC90 indexing
Baraa-Elmoussa May 5, 2026
4ba7b7c
Fixed indexing
Baraa-Elmoussa May 5, 2026
317ccfe
Added Edge Contact
Baraa-Elmoussa May 6, 2026
0f05804
Examples Setup
Baraa-Elmoussa May 6, 2026
a4c035f
Added Reaction Force in viwer
Baraa-Elmoussa May 6, 2026
baaa36f
Viewer Update
Baraa-Elmoussa May 6, 2026
8be0a2f
Fixed CRA Viz
Baraa-Elmoussa May 6, 2026
52b0418
Updated CHANGELOG.md
Baraa-Elmoussa May 6, 2026
49de4e2
Fixed CRA solve density to 1
Baraa-Elmoussa May 6, 2026
56982c4
Fixed CRA density scaling
Baraa-Elmoussa May 6, 2026
461e49c
Added exception to mesh.edgelength in viewer
Baraa-Elmoussa May 6, 2026
4fd0a15
Scale CRA by gravity
Baraa-Elmoussa May 6, 2026
c7ac7f8
viz scale fix
Baraa-Elmoussa May 6, 2026
91799c6
set min contact polygon area
Baraa-Elmoussa May 6, 2026
a550d7b
Fixed LMGC90 auto-add suppoort problem
Baraa-Elmoussa May 6, 2026
792bd58
Fixed edge contacts naming in viewer
Baraa-Elmoussa May 6, 2026
7b91667
Modified LMGC90 Post-processsing
Baraa-Elmoussa May 7, 2026
93a6d20
fixed ruff issue
Baraa-Elmoussa May 7, 2026
23ca44e
Fixed post processing of forces
Baraa-Elmoussa May 7, 2026
6df7154
Removed JSON Files
Baraa-Elmoussa May 7, 2026
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,10 @@ scripts/__testing
.ruff_cache

webviewer/**

# DEM analysis outputs
OUTBOX/
scripts/DEM_Analysis_References/2_Blocks/*.json
scripts/DEM_Analysis_References/3_Blocks/*.json
scripts/DEM_Analysis_References/Arch/*.json
scripts/DEM_Analysis_References/Barrel_Vault/*.json
10 changes: 7 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* Added `Problem` class, `BoundaryConditions`, and LMGC90 solver support.
* Added `Problem` class and `BoundaryConditions` (gravity, body forces, point/surface loads, prescribed displacements/rotations, supports).
* Added `Solver` abstraction in `compas_dem.problem.solvers` so additional backends can be plugged in alongside CRA, LMGC90, and RBE.
* Added LMGC90 solver support (`compas_dem.analysis.lmgc90`).
* Added CRA penalty and RBE solver support (`compas_dem.analysis.cra`), with results written back to the `BlockModel` graph in the same schema as LMGC90.
* Added `compas_dem.interactions.ContactProperties` and `JointModel` / `MohrCoulomb` for configuring contact behaviour.
* Added force visualization in `compas_dem.viewer.DEMViewer.add_solution`: per-edge contact resultants, per-support reaction resultants, contact polygons, and reaction labels showing force components and magnitude.

### Changed

* Fixed ruff F401 false positives on conditional re-exports in `compas_dem.analysis.__init__`.
* Fixed doctest failures in `Problem` and `BoundaryConditions` docstrings.
* Fixed Compas_CGAL >= 0.9.1 import error.

### Removed

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
compas >= 2.4
compas_cgal ==0.9.1
compas_cgal >=0.9.1
compas_libigl >=0.7.4
compas_model >= 0.9.1
1 change: 0 additions & 1 deletion scripts/DEM_Analysis_Guide/DEM_model.json

This file was deleted.

1 change: 0 additions & 1 deletion scripts/DEM_Analysis_Guide/DEM_problem.json

This file was deleted.

1 change: 0 additions & 1 deletion scripts/DEM_Analysis_Guide/DEM_problem_updated.json

This file was deleted.

1 change: 0 additions & 1 deletion scripts/DEM_Analysis_Guide/DEM_results.json

This file was deleted.

52 changes: 52 additions & 0 deletions scripts/DEM_Analysis_References/2_Blocks/100_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import os

import compas
import compas.geometry as cg

from compas_dem.material import Stone
from compas_dem.models import BlockModel

# =============================================================================
# Block Geometry
# =============================================================================

block_w = 1.0
block_h = 1.0


# Base Plate
Pl = cg.Box.from_corner_corner_height([0, 0, -0.1], [block_w, block_w, -0.1], 0.1)

block_bot = cg.Box.from_corner_corner_height([0, 0, 0], [block_w, block_w, 0], block_h)

block_top = cg.Box.from_corner_corner_height([0, 0, block_h], [0 + block_w, block_w, block_h], block_h)

blocks: list[cg.Box] = [Pl, block_bot, block_top]


model = BlockModel.from_boxes(blocks)

# =============================================================================
# Compute contacts and supports
# =============================================================================
model.compute_contacts()
for block in model.elements():
if block.point.z < 0.1:
block.is_support = True


# =============================================================================
# Add material and assign to blocks
# =============================================================================

limestone = Stone.from_predefined_material("LimeStone")
model.add_material(limestone)
limestone.density = 2000
model.assign_material(limestone, elements=list(model.elements()))

# =============================================================================
# Json Dump
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(model, os.path.join(HERE, "DEM_model.json"))
47 changes: 47 additions & 0 deletions scripts/DEM_Analysis_References/2_Blocks/200_SW_Problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os

import compas

from compas_dem.problem import Problem
from compas_dem.viewer import DEMViewer

# =============================================================================
# Load model
# =============================================================================

HERE = os.path.dirname(__file__)
model = compas.json_load(
os.path.join(HERE, "DEM_model.json"),
)

# =============================================================================
# Create Problem
# =============================================================================

problem = Problem(model)

# =============================================================================
# Add supports
# =============================================================================

problem.add_supports_from_model()

# =============================================================================
# Add contact properties
# =============================================================================

problem.add_contact_model("MohrCoulomb", mu=0.5)

# =============================================================================
# Save problem
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(problem, os.path.join(HERE, "DEM_problem.json"))
# =============================================================================
# Visualize problem
# =============================================================================

viewer = DEMViewer(problem.model)
viewer.setup()
viewer.show()
39 changes: 39 additions & 0 deletions scripts/DEM_Analysis_References/2_Blocks/300_SW_Analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os

import compas

from compas_dem.problem import Solver

# =============================================================================
# Load Problem
# =============================================================================

HERE = os.path.dirname(__file__)
problem = compas.json_load(
os.path.join(HERE, "DEM_problem.json"),
)

# =============================================================================
# Create Problem
# =============================================================================

# lmgc90 = Solver.LMGC90(duration=1.0, n_steps=100, urf_threshold=0.001)
# problem.solve(lmgc90)

lmgc90 = Solver.LMGC90(n_steps=100, dt=0.001)
problem.solve(lmgc90)

# =============================================================================
# Save results
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(problem, os.path.join(HERE, "DEM_results.json"))

# # # =============================================================================
# # # Visualize problem
# # # =============================================================================

# viewer = DEMViewer(problem.model)
# viewer.add_solution(scale=0.5)
# viewer.show()
28 changes: 28 additions & 0 deletions scripts/DEM_Analysis_References/2_Blocks/300_SW_Analysis_CRA.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os

import compas

from compas_dem.problem import Solver

# =============================================================================
# Load Problem
# =============================================================================

HERE = os.path.dirname(__file__)
problem = compas.json_load(
os.path.join(HERE, "DEM_problem.json"),
)

# =============================================================================
# Create Problem
# =============================================================================

cra = Solver.CRA(verbose=True)
problem.solve(cra)

# =============================================================================
# Save results
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(problem, os.path.join(HERE, "DEM_results.json"))
37 changes: 37 additions & 0 deletions scripts/DEM_Analysis_References/2_Blocks/301_SW_Viz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import os

import compas

from compas_dem.viewer import DEMViewer

# =============================================================================
# Load Problem
# =============================================================================

HERE = os.path.dirname(__file__)
problem = compas.json_load(
os.path.join(HERE, "DEM_results.json"),
)

# =============================================================================
# Visualize block results
# =============================================================================

# graph = problem.model.graph
# for node in graph.nodes():
# block_transformation = graph.node_attribute(node, "transformation")
# # print(f"Block {node} transformation:\n{block_transformation}\n")

# for edge in graph.edges():
# gap = graph.edge_attribute(edge, "gap")
# magnitude = graph.edge_attribute(edge, "force_magnitude")
# print(f"Edge {edge} gap: {gap}, force magnitude: {magnitude}")


# # =============================================================================
# # Visualize problem
# # =============================================================================

viewer = DEMViewer(problem.model)
viewer.add_solution(scale=0.5)
viewer.show()
54 changes: 54 additions & 0 deletions scripts/DEM_Analysis_References/3_Blocks/100_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os

import compas
import compas.geometry as cg

from compas_dem.material import Stone
from compas_dem.models import BlockModel

# =============================================================================
# Block Geometry
# =============================================================================

block_w = 1.0
block_h = 1.0
gap = 0.1

total_w = 2 * block_w + gap

# Base Plate
Pl = cg.Box.from_corner_corner_height([0, 0, -0.1], [total_w, block_w, -0.1], 0.1)

base_left = cg.Box.from_corner_corner_height([0, 0, 0], [block_w, block_w, 0], block_h)
base_right = cg.Box.from_corner_corner_height([block_w + gap, 0, 0], [total_w, block_w, 0], block_h)
top_x = (total_w - block_w) / 2
top = cg.Box.from_corner_corner_height([top_x, 0, block_h], [top_x + block_w, block_w, block_h], block_h)

blocks: list[cg.Box] = [Pl, base_left, base_right, top]


model = BlockModel.from_boxes(blocks)

# =============================================================================
# Compute contacts and supports
# =============================================================================
model.compute_contacts()
for block in model.elements():
if block.point.z < 0.1:
block.is_support = True

# =============================================================================
# Add material and assign to blocks
# =============================================================================

limestone = Stone.from_predefined_material("LimeStone")
model.add_material(limestone)
limestone.density = 2000
model.assign_material(limestone, elements=list(model.elements()))

# =============================================================================
# Json Dump
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(model, os.path.join(HERE, "DEM_model.json"))
47 changes: 47 additions & 0 deletions scripts/DEM_Analysis_References/3_Blocks/200_SW_Problem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import os

import compas

from compas_dem.problem import Problem
from compas_dem.viewer import DEMViewer

# =============================================================================
# Load model
# =============================================================================

HERE = os.path.dirname(__file__)
model = compas.json_load(
os.path.join(HERE, "DEM_model.json"),
)

# =============================================================================
# Create Problem
# =============================================================================

problem = Problem(model)

# =============================================================================
# Add supports
# =============================================================================

problem.add_supports_from_model()

# =============================================================================
# Add contact properties
# =============================================================================

problem.add_contact_model("MohrCoulomb", mu=0.5)

# =============================================================================
# Save problem
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(problem, os.path.join(HERE, "DEM_problem.json"))
# =============================================================================
# Visualize problem
# =============================================================================

viewer = DEMViewer(problem.model)
viewer.setup()
viewer.show()
39 changes: 39 additions & 0 deletions scripts/DEM_Analysis_References/3_Blocks/300_SW_Analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import os

import compas

from compas_dem.problem import Solver

# =============================================================================
# Load Problem
# =============================================================================

HERE = os.path.dirname(__file__)
problem = compas.json_load(
os.path.join(HERE, "DEM_problem.json"),
)

# =============================================================================
# Create Problem
# =============================================================================

# lmgc90 = Solver.LMGC90(duration=1.0, n_steps=100, urf_threshold=0.001)
# problem.solve(lmgc90)

lmgc90 = Solver.LMGC90(n_steps=100, dt=0.001)
problem.solve(lmgc90)

# =============================================================================
# Save results
# =============================================================================

HERE = os.path.dirname(__file__)
compas.json_dump(problem, os.path.join(HERE, "DEM_results.json"))

# # # =============================================================================
# # # Visualize problem
# # # =============================================================================

# viewer = DEMViewer(problem.model)
# viewer.add_solution(scale=0.5)
# viewer.show()
Loading
Loading