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. 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 “lcind” the index 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.
Fig. Modification of cross sections.
using Karamba.Models;
using Karamba.CrossSections;
using Karamba.Elements;
using Karamba.Results;
private void RunScript(object Model_in, List<object> CroSecs_in, int niter, int lcind, 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!");
var k3d = new KarambaCommon.Toolkit();
List<double> max_disp;
List<double> out_g;
List<double> out_comp;
string message;
List<List<double>> N;
List<List<double>> V;
List<List<double>> M;
// avoid side effects
model = model.Clone();
for (int i = 0; i < niter; ++i) {
model = k3d.Algorithms.AnalyzeThI(model, out max_disp, out out_g, out out_comp, out message);
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}, model.lc_combinator.load_case_ids[lcind], 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[lcind][0]) / crosec.A + M[lcind][0] / crosec.Wely_z_pos;
if (max_sigma < crosec.material.ft()) break;
model = k3d.Algorithms.AnalyzeThI(model, out max_disp, out out_g, out out_comp, out message);
Disp_out = new GH_Number(max_disp[lcind]);
Model_out = new Karamba.GHopper.Models.GH_Model(model);
In the first two paragraphs of source-code the type of the “Model_in” and “CroSecs_in” input gets checked. The third block consists of instantiations of objects which are used later when looping over the model’s elements.
When C# assigns an object to a variable it actually assigns a reference. Changes made on the object are thus visible in all variables that also reference that object. In Grasshopper this breaks the data flow logic that an object is only influenced by upstream operations. Whenever an object gets plugged into two different components a change in one object would magically transfer to the other object. In order to avoid this, the actual data and not only references need to be assigned and copied. This is done in line 33 for the model and in line 36 for its list of elements.
The loop in line 39 cycles over the optimization iterations and starts with calculating the system response. Starting in line 41 all elements get checked whether they epitomize beam-elements. If yes the beam gets cloned (see line 44) to avoid side-effects and re-enlisted in the model.
For cross section-optimization the beam’s resultant cross section forces are determine in line 47. One could have used “Karamba.Results.BeamForces.solve()” here instead for considering e.g. bi-axial bending. The loop which follows goes through the list of user-provided cross sections and chooses an appropriate one by comparing the maximum stress in a cross section against the cross section’s material strength.
After completing cross section selection, the iteration step ends with initializing the model’s lists of cross sections and materials (line 58) and recreation of the C++ model on which the C# model depends for result evaluation (line 59).
Before handing over the model to the output-plug an analysis step updates the structural response and determines the model’s maximum displacement.
The above C# script could be improved in many ways i.e. by providing a stop criteria for the optimization iterations or more elaborate design procedures for determining the load-bearing capacity of the elements. Yet this was omitted for the the sake of simplicity.