Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

* Updated TNA_Loads and TNA_analysis

### Changed

### Removed


## [0.2.3] 2025-09-09

### Added
Expand Down
61 changes: 45 additions & 16 deletions commands/TNA_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# venv: brg-csd
# r: compas_masonry>=0.2.3

import ast

import numpy as np
import rhinoscriptsyntax as rs # type: ignore

Expand Down Expand Up @@ -34,6 +32,11 @@ def RunCommand():

formobject.redraw()

sum_loads = sum(formobject.diagram.vertices_attribute("pz"))
if abs(sum_loads) < 0.001:
feedback.warn("There are no loads applied to the model. Please assign loads.")
return

# =============================================================================
# Create an analysis
# =============================================================================
Expand Down Expand Up @@ -67,10 +70,11 @@ def RunCommand():
index_vertex = formobject.diagram.index_vertex()

while True:
formobject.show_vertices = list(formobject.diagram.vertices()) # type: ignore
vertices = formobject.select_vertices()
formobject.show_vertices = list(formobject.vertices()) # type: ignore
formobject.redraw()

vertices = formobject.select_vertices()

if not vertices:
break

Expand Down Expand Up @@ -100,30 +104,36 @@ def RunCommand():

while True:
formobject.show_vertices = supports
vertices = formobject.select_vertices()
formobject.redraw()

vertices = formobject.select_vertices()

if not vertices:
break

displ = rs.GetString(message="Vector to displace selected supports", defaultString="[-1, -1, 0]")

if not displ:
break

displ_list = ast.literal_eval(displ)
if len(displ_list) != 3:
print("provide a 3x1 vector as shown as the example")
break
ux = rs.GetReal("Define the Support displacement [Ux, Uy, Uz]. Enter Ux", -1)
if not ux:
ux = 0.0
uy = rs.GetReal("Define the Support displacement [Ux, Uy, Uz]. Enter Uy", -1)
if not uy:
uy = 0.0
uz = rs.GetReal("Define the Support displacement [Ux, Uy, Uz]. Enter Uz", 0)
if not uz:
uz = 0.0
displ_list = [ux, uy, uz]

for vertex in vertices:
displacement_array[supports.index(vertex)] = np.array(displ_list)
print("Applied Vector {0} to support {1}".format(displ_list, vertex))

# Here we should add a vector to the Scene showing the displacement that we are maximizing.

add_vector = rs.GetString(message="Define additional displacement vectors?", strings=["Yes", "No"])
rs.UnselectAllObjects()

if not add_vector:
return

if add_vector == "Yes":
pass
else:
Expand All @@ -138,11 +148,30 @@ def RunCommand():
raise NotImplementedError

analysis.optimiser.settings["printout"] = True # need to be true so people see the fopt.
analysis.apply_selfweight()
analysis.apply_envelope()
# analysis.apply_selfweight() # This needs to be removed if loads were applied previously
# analysis.apply_envelope() # This is also not necessary if we included it before
analysis.set_up_optimiser()
analysis.run()

# =============================================================================
# Post Solver Messages
# =============================================================================

fopt = analysis.optimiser.fopt

if objective == "MaximumLoad":
print("Maximum Load Multipled to the loads assigned: {0:.3f}".format(fopt))
elif objective == "MinimumThrust" or objective == "MaximumThrust":
print("Optimal Horizontal Thrust Calculated: {0:.3f}".format(fopt))
elif objective == "MinimumThickness":
print("Minimum Thickness Calculated: {0:.3f}".format(fopt))
elif objective == "SupportDisplacement":
print("Complementary Energy to Assigned Displacements: {0:.3f}".format(fopt))
elif objective == "Bestfit":
print("Optimal Squared vertical distance to middle surface: {0:.3f}".format(fopt))
else:
pass

# =============================================================================
# Update scene
# =============================================================================
Expand Down
17 changes: 13 additions & 4 deletions commands/TNA_loads.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ def RunCommand():
return

# =============================================================================
# Update the supports
# Update the Loads
# =============================================================================

rs.UnselectAllObjects()

options = ["Add", "Clear All"]
options = ["Add", "ClearAll"]
option = rs.GetString("Add or Remove Loads in the Model", strings=options)
if not option:
return
Expand All @@ -46,7 +46,14 @@ def RunCommand():
return

if option == "Selfweight":
envelope.apply_selfweight_to_formdiagram(formdiagram)
option = rs.GetString("Normalize loads to Envelope SWT?", defaultString="Yes", strings=["Yes", "No"])
if not option:
return
elif option == "Yes":
normalize = True
else:
normalize = False
envelope.apply_selfweight_to_formdiagram(formdiagram, normalize=normalize)

elif option == "External":
formobject.show_vertices = list(formobject.vertices()) # type: ignore
Expand All @@ -61,9 +68,11 @@ def RunCommand():

for key in selected:
pz = formdiagram.vertex_attribute(key, "pz") or 0
print("Load at vertex {0} updated from {1:.2f} to {2:.2f}".format(key, pz, pz + load))
formdiagram.vertex_attribute(key, "pz", pz + load)

elif option == "Clear All":
elif option == "ClearAll":
print("Cleared Loads in the Model.")
formobject.mesh.vertices_attribute(name="pz", value=0)

else:
Expand Down
Loading