2.4.1: Cross section Optimization
When it comes to modifying an existing Karamba3D model keep to these general rules:
In order to avoid side-effects, clone objects before modifying them. This applies recursively to the objects which contain objects to be modified.
The Karamba3D API for modifications allows for changes which can make the C++-model crash. So make it a habit to regularly save your work.
The example “CrossSectionOptimization.gh” (see fig. 2.4.1.1) shows how to optimize beam cross sections under arbitrary loads. The C#-component takes a model and an ordered list of cross sections as the main input, chooses the optimum cross sections according to the given cross section forces and outputs the optimized model as well as its maximum displacement. The input-plug “niter” lets one chose the number of iteration steps. Each consists of model evaluation and cross section selection. With “lcName” the name of a load-case to be considered for cross section optimization can be selected. The algorithm inside the component neglects buckling and calculates the maximum stress in the cross section based on the assumption that there are only normal forces and bending moments about the local Y-axis.

...
using Karamba.Models;
using Karamba.CrossSections;
using Karamba.Elements;
using Karamba.Results;
using Karamba.Geometry;
...
private void RunScript(
object Model_in,
List<object> CroSecs_in,
int niter,
string lcName,
ref object Model_out,
ref object Disp_out)
{
var model = Model_in as Model;
if (model == null) {
throw new ArgumentException("The input in 'Model_in' is not of type Karamba.Models.Model!");
}
var crosecs = new List<CroSec_Beam>(CroSecs_in.Count);
foreach (var item in CroSecs_in) {
var crosec = item as CroSec_Beam;
if (crosec == null) {
throw new ArgumentException("The input in 'CroSecs_in' contains objects which are not of type Karamba.CrossSections.CroSec_Beam!");
}
crosecs.Add(crosec);
}
var k3d = new KarambaCommon.Toolkit();
IReadOnlyList<double> max_disp;
IReadOnlyList<Vector3> out_force;
IReadOnlyList<double> out_energy;
string warning;
List<List<double>> N;
List<List<double>> V;
List<List<double>> M;
// avoid side effects
model = model.Clone();
model.cloneElements();
for (int i = 0; i < niter; ++i)
{
model = k3d.Algorithms.Analyze(model, new List<string>(){lcName}, out max_disp, out out_force, out out_energy, out warning);
for (int elem_ind = 0; elem_ind < model.elems.Count; ++elem_ind) {
var beam = model.elems[elem_ind] as ModelBeam;
if (beam == null) continue;
// avoid side effects
beam = (ModelBeam) beam.Clone();
model.elems[elem_ind] = beam;
BeamResultantForces.solve(model, new List<string> {"" + elem_ind}, lcName, 100, 1,
out N, out V, out M);
for (int crosec_ind = 0; crosec_ind < crosecs.Count; ++crosec_ind) {
var crosec = crosecs[crosec_ind];
beam.crosec = crosec;
var max_sigma = Math.Abs(N[0][0]) / crosec.A + M[0][0] / crosec.Wely_z_pos;
if (max_sigma < crosec.material.ft()) break;
}
}
model.initMaterialCroSecLists();
model.buildFEModel();
}
model = k3d.Algorithms.Analyze(model, new List<string>(){lcName}, out max_disp, out out_force, out out_energy, out warning);
Disp_out = new GH_Number(max_disp[0]);
Model_out = new Karamba.GHopper.Models.GH_Model(model);
}
Here the detailed account of the above algorithm:
1. Input Type Validation
The first two blocks of code check the data types of the
Model_in
andCroSecs_in
inputs. This ensures the inputs are valid and compatible with subsequent operations.
2. Object Instantiations
The third code section initializes objects that are required later during the iterative optimization loop. These objects facilitate efficient data handling and manipulation.
3. Reference Management in C#:
In C#, assigning an object to a variable actually assigns a reference. This means changes made to the object are reflected in all variables that reference it.
This behavior conflicts with Grasshopper’s data flow logic, where objects should only be influenced by upstream operations.
To prevent unintended data flow and ensure independent object manipulation:
Clone the model using
model = model.Clone();
.Clone the model's elements with
model.cloneElements();
.
4. Optimization Loop
The main optimization loop performs the following steps:
System Response Calculation:
At the start of each iteration, the structural response is calculated.
Beam Element Handling:
All elements in the model are checked to identify beam elements.
Beam elements are cloned to avoid side effects and re-added to the model.
Cross Section Forces Calculation:
The resultant forces for each beam’s cross section are determined using
BeamResultantForces.solve
.Alternatively,
Karamba.Results.BeamForces.solve()
could be used for more complex scenarios, such as considering bi-axial bending.
Cross Section Selection:
The loop iterates through the user-provided list of cross sections.
An appropriate cross section is selected by comparing the maximum stress in the cross section with the material's strength.
Model Update:
After selecting cross sections, the model's lists of cross sections and materials are re-initialized.
The C++ model, which the C# model relies on for result evaluation, is recreated.
5. Finalization
Before the model is passed to the output plug:
An analysis step updates the structural response.
The maximum displacement of the model is determined.
6. Potential Improvements
The script is kept simple for clarity, but it can be enhanced in several ways:
Stop Criteria: Implementing a mechanism to terminate the optimization loop when convergence is reached.
Advanced Design Procedures: Incorporating more detailed methods to evaluate the load-bearing capacity of elements.
Enhanced Analysis: Including additional considerations such as buckling or multi-axis forces for more robust designs.
This structured approach to code ensures clarity and minimizes unintended interactions between components, making the process easier to follow and adapt for complex scenarios.
Last updated