Sie sind auf Seite 1von 29

parametric engineering

Scripting Guide
(Version 1.3.2)

written by Clemens Preisinger


August 2, 2019
Contents

1 Introduction 2
1.1 About this Manual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Scripting with Karamba3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 What’s new in Karamba3D 1.3.2 Regarding Scripting . . . . . . . . . . . . . . . . . . 3
1.3.1 Partial Separation from Grasshopper . . . . . . . . . . . . . . . . . . . . . 3
1.3.2 Karamba3D’s Geometry Types . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3.3 Factories as Access Points to the Karamba3D API . . . . . . . . . . . . . . 3

2 Scripting with Karamba3D inside Grasshopper 4


2.1 Hello Karamba3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Data Retrieval from Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.1 The Data Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2.2 Retrieving Masses Sorted by Material . . . . . . . . . . . . . . . . . . . . . 6
2.2.3 Handling of Physical Units . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3 How to Create Structural Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 How to Modify Structural Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.1 Cross section Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.2 Activation and Deactivation of Elements . . . . . . . . . . . . . . . . . . . 12
2.5 Data Export from Karamba3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.6 The VB Script Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.7 The IronPython Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.7.1 Results Retrieval on Shells . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.7.2 A Simplified ESO-Procedure on Shells . . . . . . . . . . . . . . . . . . . . . 19

3 How to create your own Karamba3D Grasshopper-component 21


3.1 Setting up a Visual Studio Project for GH Plug-ins . . . . . . . . . . . . . . . . . . . 21
3.2 Basic Component Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.3 How to Reference Karamba3D Assemblies . . . . . . . . . . . . . . . . . . . . . . . 23
3.4 Input- and Output-Plugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5 Adding Functionality to a GH Component . . . . . . . . . . . . . . . . . . . . . . . . 25

Bibliography 28

1
Chapter 1

Introduction

1.1 About this Manual

This manual describes how to use Karamba3D inside C#-scripts. Since C# is a member of the .NET
family everything said also applies to code in IronPython, F#, Visual Basic or any other scripting
language being based on the Common Language Infrastructure (CLI).
This manual is not an introduction to C#. For introductional material see e.g. [1] or [3]. More advanced
topics – useful yet not necessary for reading this manual – can be found in the fantastic book “C#
in Depth” see [4].
The previous version of this guide contained sections on how to integrate Karamba3D (K3D) in Java,
C++ and native Python. Judging from user feedback these options are not widely used. This is why
those chapters where left out in this manual. Instead this manual dwells more on the C#-interface
of Karamba3D.

1.2 Scripting with Karamba3D

Sometimes when creating a Grasshopper (GH) definition you may reach a point where it makes sense
to switch from GH’s visual computing environment to textual scripting. This is e.g. the case if you
want to apply loops, functions or more refined object oriented programming concepts. Other points
in favor of a textual approach would be debugging or code reuse.
When installed for Grasshopper Karamba3D consists of three main parts:

• “karamba.dll” is a C++ library which does the numeric calculations. It can be found under
C:\Windows\.

• “karambaCommon.dll” provides the .NET user interface to the Karamba3D functionality. It


features its own set of geometric types (e.g. vectors, points, meshes,. . . ) and is therefore
independent from Grasshopper or Rhino. The file resides in the “Plug-ins”-folder of Rhino.

• “karamba.gha” connects GH to “karambaCommon.dll” and takes care of the graphical user-


interface. It sits in the same place as “karambaCommon.dll”

This scripting guide comes with a help-file (“Karamba3D_1_3_2_SDKDoc.chm”) which covers “karam-
baCommon.dll” and parts of “karamba.gha”. It can be found in the “ScriptingGuideExamples” archive

2
1.3 What’s new in Karamba3D 1.3.2 Regarding Scripting 3

which accompanies this manual. A useful additional source of information regarding scripting with
Karamba3D are the “karambaCommon.dll”- and “karamba.gha” files themselves: Feel free to use a
tool like “ILSpy” to decompile them and have a look at their inner workings.
The main incentive behind decoupling K3D from Grasshopper was to enable Unit-testing for the
C# application programming interface (API) of Karamba3D and thus enhance its code quality. You
can download the Karamba3D test-project from https://github.com/karamba3d/K3D_tests. The test
cases represent code-snippets which show how to work with the Karamba3D API and form another
useful source of knowhow regarding C# of K3D.
Karamba3D is work in progress. So are its interface definitions. Be aware of the fact, that they will
probably change in future.

1.3 What’s new in Karamba3D 1.3.2 Regarding Scripting

1.3.1 Partial Separation from Grasshopper


The biggest change from Karamba3D 1.3.1 to 1.3.2 is its partial independence from Grasshopper.
When taking a look at the contents of the “Karamba3D_1_3_2_SDKDoc.chm”-file one sees a list of
name-spaces: everything under “Karamba.GHopper” comes with “karamba.gha” and links the C# API
of Karamba3D to GH. All the rest resides in “karambaCommon.dll”.

1.3.2 Karamba3D’s Geometry Types


Under “Karamba.Geometry” one finds the geometry types of Karamba3D. In most cases the K3D-
equivalents of a GH geometry types come without the “D” at the end: e.g. Grasshopper’s Vector3D
is equivalent to K3D’s Vector3. The static class Karamba.GHopper.Utilities.FromGH provide type-
conversion from GH to K3D. In the other direction the “Karamba.GHopper.Geometry.GeometryExtension”-
class provides “Convert” methods for all K3D geometry types.

1.3.3 Factories as Access Points to the Karamba3D API


For nearly all Karamba3D components visible in Grasshopper there is a static class in “karamba-
Common.dll” which does the work behind the scenes. Thus one approach would be to use these
static classes to manage Karamba3D models. However this makes scripts dependent on the inter-
face definitions of the static classes. In order to provide a more stable API a hierarchy of factories
has been implemented. It resides under KarambaCommon.Factories. The “Toolkit” class provides
access to it and can be used to set up Karamba3D models. An additional advantage of the toolkit
consists in the fact that it provides useful default-values for many arguments. Currently not all fea-
tures of Karamba3D are available via the “Toolkit”. It will however grow in future and constitutes the
recommended access point to Karamba3D.
Chapter 2

Scripting with Karamba3D inside Grasshopper

For small scripts the Grasshopper scripting components “C# Script”, “VB Script” or “Python Script” 1
from the “Maths” subsection come in handy. A good introduction to scripting in GH can be found in
the “Grasshopper Primer”.
All examples which follow can be found in the “ScriptingGuideExamples”-archive that accompanies
this manual. When opening them in Grasshopper do not panic if some components turn red. In that
case some paths need adaptation (see below).

2.1 Hello Karamba3D

In order to get going let’s start with a simple example (see “HelloKaramba3D.gh” in the examples
archive): Place a C# scripting component on the canvas, right-click on its icon and select “Manage As-
semblies . . . ” from the context menu. In order to make the “karambaCommon.dll” and “karamba.gha”
assemblies accessible to your script, click on “Add” left beside “Referenced Assemblies” and browse
to the files. They both live in the “Plug-ins”-folder of Rhino (e.g. “C:\ProgramFiles\Rhino6\
Plug-ins”). From there all users can access the Karamba3D plug-in 2 . By default one only sees
“.dll”-files. Select “Grasshopper Assemblies (*.gha)” from the drop-down list on the lower right side
of the browse-window.
The first script (“HelloKaramba3D.gh” in the examples folder) takes a K3D model as input and outputs
the number of its nodes and elements. Fig. 2.1 displays the Grasshopper definition which generates
a Karamba3D-model consisting of one beam only. Zooming in on the C#-components makes small
“plus” and “minus” signs appear next to the input- and output-plugs of the component. Use these to
change the number of parameters; right-click on them to change their names. The parameter names
which appear on the component act also as the argument names in the underlying C#-script. This
sometimes proves to be awkward: input- and output-parameters need to be named differently. Also
the fact that input- and output-plugs names normally start with capital letters clashes with customary
C# naming conventions where names starting with capital letters normally signify classes.
The source-code to be added inside the C#-component looks like this:
1 In Rhino 5 the “Python Script” component comes in an extra gh-file which can be downloaded from http://www.
food4rhino.com/project/ghpython
2 Normally GH plug-ins reside in the “Libraries”-folder of Grasshopper. This means however that they are only available
to the current user. What’s more installation and updates need to be done per user - a nightmare in case one has to manage
a larger number of computers

4
2.2 Data Retrieval from Models 5

Figure 2.1 A minimal K3D-model for retrieving the number of elements, materials and cross sections via a C#
script.

1 ...
2 u s i n g Karamba . M o d e l s ;
3 ...
4 private void RunScript ( object Model_in )
5 {
6 v a r model = M o d e l _ i n as M o d e l ;
7 i f ( model == n u l l ) {
8 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i s n o t o f t y p e model ! " ) ;
9 }
10 P r i n t ( " Number o f E l e m e n t s : " + model . e l e m s . C o u n t ) ;
11 P r i n t ( " Number o f M a t e r i a l s : " + model . m a t e r i a l s . C o u n t ) ;
12 P r i n t ( " Number o f C r o s s s e c t i o n s : " + model . c r o s e c s . C o u n t ) ;
13 }

The addition of the “using” command in line 2 is for convenience. It spares one to type out the fully
qualified names of classes. In case of “Model” in line 6 this would have been “Karamba.Models.Model”.
In this example the benefit of the “using” command does not weigh much – longer scripts however
gain in readability.
“Model_in” comes as type “object”, so one needs to cast it into its real type to get access to it. The com-
mands in line 6 do so. Since type conversions may fail (think of a user plugging a vector into where the
model should go) the “if” in line 7 tests this condition and throws an invalid argument exception if nec-
essary. “model” contains now a reference to the model-object and can be used to retrieve data from
it. For a complete specification of the API of the “Model”-class see “Karamba3D_1_3_2_SDKDoc.chm”
where it can be found under “Karamba.Models”.

2.2 Data Retrieval from Models

2.2.1 The Data Model


The data inside a Karamba3D model is organized in a tree-like object structure. The following diagram
shows a part of that tree – for full details see “Karamba3D_1_3_2_SDKDoc.chm”:
2.2 Data Retrieval from Models 6

Figure 2.2 Data retrieval from a K3D model.

Model
List<Node> nodes
List<ModelElement> elems
ModelElement
IReadOnlyList<int> node_inds
IReadOnlyList<ElementLoad> Elem_loads
CroSec crosec
string name
string family
FemMaterial material
...
...

List<PointLoad> ploads
List<PointMass> pmass
List<MeshLoad> mloads
List<ElementLoad> eloads
...

2.2.2 Retrieving Masses Sorted by Material


The following script (see “DataRetrieval.gh”) shows how to use that model-data to retrieve the mass
sorted by material. One can see in fig 2.2 the corresponding GH setup. The model comprises two
beams made from steel and concrete respectively. The total mass amounts to 87.5 kg, 37.5 kg come
from concrete, 50.0 kg from steel.
1 ...
2.2 Data Retrieval from Models 7

2 u s i n g Karamba . M o d e l s ;
3 u s i n g Karamba . U t i l i t i e s ;
4 u s i n g Karamba . M a t e r i a l s ;
5 ...
6 private void RunScript ( object Model_in )
7 {
8 v a r model = M o d e l _ i n as M o d e l ;
9 i f ( model == n u l l ) {
10 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i s n o t o f t y p e Karamba . M o d e l s . M o d e l ! " ) ;
11 }
12
13 v a r m a t W e i g h t s = new D i c t i o n a r y < F e m M a t e r i a l , d o u b l e > ( ) ;
14
15 f o r e a c h ( v a r e l e m i n model . e l e m s ) {
16 v a r mat = e l e m . c r o s e c . m a t e r i a l ;
17 i f ( ! m a t W e i g h t s . C o n t a i n s K e y ( mat ) ) {
18 m a t W e i g h t s [ mat ] = 0 ;
19 }
20 m a t W e i g h t s [ mat ] += e l e m . w e i g h t ( model . n o d e s ) ;
21 }
22
23 v a r u c f = U n i t s C o n v e r s i o n F a c t o r i e s . Conv ( ) ;
24 v a r kg = u c f . w e i g h t 2 k g ( ) ;
25
26 foreach ( var e n t r y i n matWeights ) {
27 P r i n t ( " M a t e r i a l : " + e n t r y . Key . name + " : " + kg . t o B a s e ( e n t r y . V a l u e ) + kg . u n i t B ) ;
28 }
29 }

The first lines contain “using” statements for the name-spaces “Karamba.Utilities” and “Karamba.-
Materials”. These house the “UnitsConversionFactories”, “INIReader” and “FemMaterial”-classes re-
spectively.
The script starts as before with a type-conversion for the argument “Model_in” from “object” to
“Model”. The “matWeights” dictionary provides the mapping from K3D materials to weights. A “foreach”-
loop cycles over all elements of the model and gets their materials. If not already present in “matWeights”
a new material entry is created. Line 19 updates the material’s total weight.

2.2.3 Handling of Physical Units


Creating the output consists of looping over the entries in “matWeights”. The tricky part is to get the
physical units right. Internally the C++ part of Karamba3D does not care about physical units. As
long as they are consistent the results will be fine. When using SI-units Karamba3D works with these
base units: meters (m), kilo Newtons (kN), tons (t) and degrees Celsius. When in Imperial-mode
the units of length, force and mass get converted to feet (ft), kilo Pounds force(kipf), kilo Pounds
mass (kipm) and degrees Fahrenheit. Units conversion between e.g. centimeter and meter, inch
and feet, . . . occurs at output and input only. The material and cross section tables which come with
Karamba3D – and can be produced via e.g. the “Generate Cross Section Table”-component – contain
values in SI-units only. They get converted to the right units-system (SI or Imperial) on the fly when
loading them into Karamba3D.
The matter of mass has it difficulties: in the SI system there is a clear separation between force (kN)
and mass (kg) and e.g. Newton’s law takes the form

F [N] = m[kg] · a[m/s2 ]


since the definition 1N = 1kg m/s2 holds.
In Imperial units one has Pound-force (lb, sometimes lbf) and Pound-mass (lbm). The former is
defined as the force which corresponds to the weight of one pound mass. So “g” – the acceleration
2.3 How to Create Structural Models 8

of gravity – is not involved. To make Newton’s law work in Imperial units one thus needs to divide
the right side by a constant g c = 32.174ft/s2 which is by convention the acceleration of gravity to
be used:

F [lbf ] = m[lbm] · a[ft/s2 ]/g c [ft/s2 ]


To make calculations involving mass work irrespective of the system of physical units the “kg”-
conversion does the following: Under Imperial units masses get scaled by 1/g c .
Sometime it happens that one wants to convert weight to mass. In this case weight gets scales
by g user /g c and g user for Imperial and SI-units respectively, g user being the acceleration of gravity
given in the karamba.ini-file.
The first step in unit-conversion consists of getting a units-conversion-factory (UCF), (see line 23).
This factory converts derived SI or Imperial units (e.g. inch, centimeter, millimeter, . . . ) to base units
(e.g. feet, meter). A UCF features a long list of conversion objects, “weight2kg” being one of them. In
line 24 a units conversion object gets instantiated using the factory. This lets one convert from force
to mass using the acceleration of gravity from the “karamba.ini”-file via the “toBase”-method. Con-
version in the other direction works with “toUnit”. The method “unitB” renders a string representation
of the unit with brackets.

2.3 How to Create Structural Models

Starting with version 1.0.5 most of the Karamba3D-components are split in two parts: one manages
the graphical user interface, unit conversions and default values, the other handles the functionality.
Let’s take the “LineToBeam”-component as an example:

• The class “Component_LineToBeam_GUI” in namespace “Karamba.GHopper.Elements” derives


from Grasshopper’s “GH_Component” and provides the visual component properties.

• “LineToBeam”, a static class in namespace “Karamba.Elements” features the static method


“solve(...)” which executes the actual tasks and gets used by “Component_LineToBeam_GUI”

Generally the names of classes which belong to the GUI start with “Component” and belong to the
namespace “Karamba.GHopper”. Since there are static solve-methods for all components it would
be possible to build a model using only these. This would entail two disadvantages:

• The solve-methods do not provide default values for their arguments, so one has to provide
them explicitly.

• In later versions of Karamba3D the order and number of arguments of the solve-methods
might change

One way to mitigate these problems is to refrain from direct object creation and use a factory-pattern
instead. See [2] for further information on this topic. In the script below a structural model gets
assembled and output: it consists of a vertical cantilever-beam with a point-load on top (see 2.3).
This is the source-code inside the C#-component (see example “ModelCreation.gh”):
2.3 How to Create Structural Models 9

Figure 2.3 A model can be created from scratch using a C# script.

1 ...
2 u s i n g Karamba . U t i l i t i e s ;
3 u s i n g Karamba . G e o m e t r y ;
4 u s i n g Karamba . C r o s s S e c t i o n s ;
5 u s i n g Karamba . S u p p o r t s ;
6 u s i n g Karamba . L o a d s ;
7 ...
8 p r i v a t e void RunScript ( r e f object Model_out )
9 {
10 v a r l o g g e r = new M e s s a g e L o g g e r ( ) ;
11 v a r k3d = new KarambaCommon . T o o l k i t ( ) ;
12
13 v a r p0 = new P o i n t 3 ( 0 , 0 , 0 ) ;
14 v a r p 1 = new P o i n t 3 ( 0 , 0 , 5 ) ;
15 v a r L0 = new L i n e 3 ( p0 , p 1 ) ;
16
17 v a r n o d e s = new L i s t < P o i n t 3 > ( ) ;
18 v a r e l e m s = k3d . P a r t . L i n e T o B e a m ( new L i s t < L i n e 3 > ( ) { L0 } , new L i s t < s t r i n g > ( ) { " B1 " } ,
19 new L i s t < C r o S e c > ( ) , l o g g e r , o u t n o d e s ) ;
20
21 v a r cond = new L i s t < b o o l > ( ) { t r u e , t r u e , t r u e , t r u e , t r u e , t r u e } ;
22 v a r s u p p o r t = k3d . S u p p o r t . S u p p o r t ( 0 , cond ) ;
23 v a r s u p p o r t s = new L i s t < S u p p o r t > ( ) { s u p p o r t } ;
24
25 v a r p l o a d = k3d . Load . P o i n t L o a d ( 1 , new V e c t o r 3 ( 0 , 0 , − 1 0 ) , new V e c t o r 3 ( ) ) ;
26 v a r p l o a d s = new L i s t < Load > ( ) { p l o a d } ;
27
28 d o u b l e mass ;
29 P o i n t 3 cog ;
30 bool f l a g ;
31 string info ;
32 v a r model = k3d . M o d e l . A s s e m b l e M o d e l ( elems , s u p p o r t s , p l o a d s ,
33 o u t i n f o , o u t mass , o u t cog , o u t i n f o , o u t f l a g ) ;
34
35 / / c a l c u l a t e Th . I r e s p o n s e
36 L i s t < double > max_disp ;
37 L i s t < double > out _g ;
38 L i s t < double > out_comp ;
39 s t r i n g message ;
40 model = k3d . A l g o r i t h m s . A n a l y z e T h I ( model , o u t m a x _ d i s p , o u t o u t _ g , o u t out_comp , o u t message ) ;
41
42 v a r u c f = U n i t s C o n v e r s i o n F a c t o r i e s . Conv ( ) ;
43 U n i t C o n v e r s i o n cm = u c f . cm ( ) ;
44 P r i n t ( " max d i s p : " + cm . t o U n i t ( m a x _ d i s p [ 0 ] ) + cm . u n i t B ) ;
45
46 M o d e l _ o u t = new Karamba . GHopper . M o d e l s . GH_Model ( model ) ;
47 }
2.4 How to Modify Structural Models 10

As a means of reporting problems a “logger”-objects gets instantiated in line 10. This class limits
the amount of text to a preset maximum so that in case of multiple errors the log-file does not grow
without limits. Next comes the factory “k3d” which further on serves as the main hub of object
creation. The classes “Point3” and “Line3” represent the Karamba3D equivalent of Grasshopper’s
“Point3d” and “Line”. Their instantiations “p0”, “p1” and “L0” make up the model’s geometry. In line 19
the k3d-factory creates a list of objects of type “BuilderBeam” – with one entry in this case. This is
not yet an element which forms part of a model – this would be “ModelBeam”. It rather represents a
recipe for creating them. This concept applies to all elements in Karamba3D: Via the assemble-step
objects of type “BuilderBeam” or “BuilderShell” produce “ModelBeams”-, “ModelTruss”-, “ModelSpring”
and “ModelShell”-objects which form part of the C# structural model. What the user sees as “Element”
in the Grasshopper GUI are the element-builders not the model-elements. Since C# structural models
can be disassembled and reassembled the model-elements need to keep a reference to their builder-
elements. This is achieved via the protected property “builder_element”.
The creation of supports and loads works similarly as for the element-builder. In Line 32 follows the
model-assemble step, in line 40 the first order theory calculation of the model-response.
User defined objects that get piped through grasshopper definitions need to be wrapped: In line 101
a GH_Model wrapper object is created from the model-object that contains the final results. Similar
wrapper classes exist for all Karamba3D entities that can populate a Grasshopper definition. Their
names start with “GH_” which makes them easy to find.

2.4 How to Modify Structural Models

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.

Figure 2.4 Modification of cross sections.


2.4 How to Modify Structural Models 11

The example “CrossSectionOptimization.gh” (see fig. 2.4) shows how to optimize beam cross sec-
tions 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 se-
lection. 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.
1 ...
2 u s i n g Karamba . M o d e l s ;
3 u s i n g Karamba . C r o s s S e c t i o n s ;
4 u s i n g Karamba . E l e m e n t s ;
5 u s i n g Karamba . R e s u l t s ;
6 ...
7 p r i v a t e void RunScript ( o b j e c t Model_in , List < object > CroSecs_in , i n t n i t e r , i n t lcind ,
8 r e f o b j e c t Model_out , r e f o b j e c t D i s p _ o u t )
9 {
10 v a r model = M o d e l _ i n as M o d e l ;
11 i f ( model == n u l l ) {
12 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i n ’ M o d e l _ i n ’ i s n o t o f t y p e Karamba . M o d e l s . M o d e l ! " ) ;
13 }
14
15 v a r c r o s e c s = new L i s t < CroSec_Beam > ( C r o S e c s _ i n . C o u n t ) ;
16 foreach ( var item in CroSecs_in ) {
17 v a r c r o s e c = i t e m as C r o S e c _ B e a m ;
18 i f ( c r o s e c == n u l l ) {
19 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i n ’ C r o S e c s _ i n ’ c o n t a i n s o b j e c t s w h i c h " +
20 " a r e n o t o f t y p e Karamba . C r o s s S e c t i o n s . C r o S e c _ B e a m ! " ) ;
21 }
22 c r o s e c s . Add ( c r o s e c ) ;
23 }
24
25 v a r k3d = new KarambaCommon . T o o l k i t ( ) ;
26 L i s t < double > max_disp ;
27 L i s t < double > out _g ;
28 L i s t < double > out_comp ;
29 s t r i n g message ;
30 L i s t < L i s t < double >> N ;
31 L i s t < L i s t < double >> V ;
32 L i s t < L i s t < double >> M;
33
34 // avoid side effects
35 model = model . C l o n e ( ) ;
36 model . c l o n e E l e m e n t s ( ) ;
37
38 f o r ( i n t i = 0 ; i < n i t e r ; ++ i ) {
39 model = k3d . A l g o r i t h m s . A n a l y z e T h I ( model , o u t m a x _ d i s p , o u t o u t _ g , o u t out_comp , o u t message ) ;
40
41 f o r ( i n t e l e m _ i n d = 0 ; e l e m _ i n d < model . e l e m s . C o u n t ; ++ e l e m _ i n d ) {
42 v a r beam = model . e l e m s [ e l e m _ i n d ] as ModelBeam ;
43 i f ( beam == n u l l ) c o n t i n u e ;
44
45 // avoid side effects
46 beam = ( ModelBeam ) beam . C l o n e ( ) ;
47 model . e l e m s [ e l e m _ i n d ] = beam ;
48
49 B e a m R e s u l t a n t F o r c e s . s o l v e ( model , new L i s t < s t r i n g > { " " + e l e m _ i n d } , l c i n d , 1 0 0 , 1 ,
50 out N , out V , out M) ;
51
52 f o r ( i n t c r o s e c _ i n d = 0 ; c r o s e c _ i n d < c r o s e c s . C o u n t ; ++ c r o s e c _ i n d ) {
53 var crosec = crosecs [ crosec_ind ] ;
54 beam . c r o s e c = c r o s e c ;
55 v a r max_sigma = Math . Abs ( N [ l c i n d ] [ 0 ] ) / c r o s e c . A + M [ l c i n d ] [ 0 ] / c r o s e c . W e l y _ z _ p o s ;
56 i f ( max_sigma < c r o s e c . m a t e r i a l . f y ( ) ) b r e a k ;
57 }
58 }
59 model . i n i t M a t e r i a l C r o S e c L i s t s ( ) ;
60 model . f e b m o d e l = model . b u i l d F E M o d e l ( ) ;
2.4 How to Modify Structural Models 12

61 }
62
63 model = k3d . A l g o r i t h m s . A n a l y z e T h I ( model , o u t m a x _ d i s p , o u t o u t _ g , o u t out_comp , o u t message ) ;
64 D i s p _ o u t = new GH_Number ( m a x _ d i s p [ l c i n d ] ) ;
65 M o d e l _ o u t = new Karamba . GHopper . M o d e l s . GH_Model ( model ) ;
66 }

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 35 for the model and in line 36 for its list of elements.
The loop in line 38 cycles over the optimisation 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 46) 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 49.
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 59) and recreation of the C++ model on which the C# model
depends for result evaluation (line 60).
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.

2.4.2 Activation and Deactivation of Elements

Figure 2.5 From the initial truss only those elements without tensile forces survive.
2.4 How to Modify Structural Models 13

The example “ActivationDeactivationofElements.gh” features a simplified version of Karamba3D’s


“Tension/Compression Eliminator”-component. It repeatedly evaluates a structure and removes all
elements with tensile normal force. In the source-code one finds an alternative approach to changing
model properties as compared to the above example. Starting from an arbitrary structural model the
script iteratively removes those elements which are under tension (see 2.5). In order to improve
computational efficiency model-modifications occur on the level of the C++ model. This spares the
C++ model creation, however introduces additional complexity with regards to model-handling.
1 ...
2 u s i n g Karamba . M o d e l s ;
3 u s i n g Karamba . GHopper . M o d e l s ;
4 ...
5 p r i v a t e void R u n S c r i p t ( o b j e c t Model_in , i n t maxiter , r e f o b j e c t Model_out , r e f o b j e c t i s A c t i v e ,
6 r e f o b j e c t maxDisp )
7 {
8 v a r model = M o d e l _ i n as M o d e l ;
9 i f ( model == n u l l ) {
10 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i n ’ M o d e l _ i n ’ i s n o t o f t y p e k a r a m b a . M o d e l s . M o d e l ! " ) ;
11 }
12
13 / / load case to c o n s i d e r f o r e l i m i n a t i o n of elements
14 i n t lc_num = 0 ;
15
16 / / c l o n e t h e m o d e l and i t s l i s t o f e l e m e n t s t o a v o i d s i d e e f f e c t s
17 model = model . C l o n e ( ) ;
18 // clone i t s elements to avoid side e f f e c t s
19 model . c l o n e E l e m e n t s ( ) ;
20 / / c l o n e t h e f e b −model t o a v o i d s i d e e f f e c t s
21 model . d e e p C l o n e F E M o d e l ( ) ;
22
23 s t r i n g s i n g u l a r _ s y s t e m _ m s g = " The s t i f f n e s s m a t r i x o f t h e s y s t e m i s s i n g u l a r . " ;
24
25 / / do t h e i t e r a t i o n and r e m o v e e l e m e n t s w i t h t e n s i l e axial forces
26 for ( i n t i t e r = 0 ; i t e r < maxiter ; i t e r ++) {
27
28 / / c r e a t e a d e f o r m and r e s p o n s e o b j e c t f o r c a l c u l a t i n g and r e t r i e v i n g results
29 f e b . D e f o r m d e f o r m = new f e b . D e f o r m ( model . f e b m o d e l ) ;
30 f e b . R e s p o n s e r e s p o n s e = new f e b . R e s p o n s e ( d e f o r m ) ;
31
32 try
33 {
34 // c a l c u l a t e the displacements
35 response . updateNodalDisplacements ( ) ;
36 / / c a l c u l a t e t h e member f o r c e s
37 response . updateMemberForces ( ) ;
38 }
39 catch
40 {
41 / / s e n d an e r r o r message i n c a s e s o m e t h i n g w e n t w r o n g
42 t h r o w new E x c e p t i o n ( s i n g u l a r _ s y s t e m _ m s g ) ;
43 }
44
45 / / c h e c k t h e n o r m a l f o r c e o f e a c h e l e m e n t and d e a c t i v a t e t h o s e u n d e r t e n s i o n
46 double N , V , M;
47 bool has_changed = f a l s e ;
48 f o r e a c h ( Karamba . E l e m e n t s . M o d e l E l e m e n t e l e m i n model . e l e m s ) {
49 // r e t r i e v e r e s u l t a n t cross section forces
50 e l e m . r e s u l t a n t C r o S e c F o r c e s ( model , l c _ n u m , o u t N , o u t V , o u t M ) ;
51 / / check whether normal f o r c e i s t e n s i l e
52 i f ( N >= 0 ) {
53 // set element i n a c t i v e
54 e l e m . s e t _ i s _ a c t i v e ( model , f a l s e ) ;
55 has_changed = true ;
56 }
57 }
58
59 / / l e a v e i t e r a t i o n loop i f n o t h i n g changed
60 i f ( ! has_changed ) break ;
61
62 / / i f s o m e t h i n g c h a n g e d i n f o r m t h e f e b −model a b o u t i t ( o t h e r w i s e i t won ’ t r e c a l c u l a t e )
63 model . f e b m o d e l . t o u c h ( ) ;
2.4 How to Modify Structural Models 14

64
65 / / t h i s guards the o b j e c t s from b e i n g f r e e d p r e m a t u r e l y
66 GC . K e e p A l i v e ( D i s p o s e ) ;
67 GC . K e e p A l i v e ( D i s p o s e ) ;
68 }
69
70 / / u p d a t e model t o i t s f i n a l s t a t e
71 try
72 {
73 / / c r e a t e a d e f o r m and r e s p o n s e o b j e c t f o r c a l c u l a t i n g and r e t r i e v i n g results
74 f e b . D e f o r m d e f o r m = new f e b . D e f o r m ( model . f e b m o d e l ) ;
75 f e b . R e s p o n s e r e s p o n s e = new f e b . R e s p o n s e ( d e f o r m ) ;
76
77 // c a l c u l a t e the displacements
78 response . updateNodalDisplacements ( ) ;
79 / / c a l c u l a t e t h e member f o r c e s
80 response . updateMemberForces ( ) ;
81
82 maxDisp = r e s p o n s e . maxDisplacement ( ) ;
83
84 / / t h i s guards the o b j e c t s from b e i n g f r e e d p r e m a t u r e l y
85 GC . K e e p A l i v e ( d e f o r m ) ;
86 GC . K e e p A l i v e ( r e s p o n s e ) ;
87 }
88 catch
89 {
90 / / s e n d an e r r o r message i n c a s e s o m e t h i n g w e n t w r o n g
91 t h r o w new E x c e p t i o n ( s i n g u l a r _ s y s t e m _ m s g ) ;
92 }
93
94 / / s e t up l i s t o f t r u e / f a l s e v a l u e s t h a t c o r r e s p o n d s t o t h e e l e m m e n t s t a t e s
95 L i s t < b o o l > e l e m _ a c t i v i t y = new L i s t < b o o l > ( ) ;
96 f o r e a c h ( v a r e l e m i n model . e l e m s ) {
97 e l e m _ a c t i v i t y . Add ( e l e m . i s _ a c t i v e ) ;
98 }
99
100 isActive = elem_activity ;
101 M o d e l _ o u t = new GH_Model ( model ) ;
102
103 P r i n t ( " E v e r y t h i n g OK " ) ;
104 }

As usual at the beginning of the above script the input variable “Model_in” gets type-cast to “Karamba.Models.Model”.
in case the supplied object does not fit an “ArgumentException” gets thrown.
The index of the load case to consider is hard-wired to “0” in line 14. In order to avoid side-effects, the
data needs to be copied before any modifications take place. Line 17 effects this for the Karamba3D-
model. Since the model-object itself contains objects these need to be copied as well. Since the
script changes the element’s activation state, the list referencing them needs to be copied as done
in line 19. The same is true for the C++-model which gets cloned in line 21.
The C++ model contains all the predefined data like geometry, materials, supports, loads, and the like.
It lives in the “feb”-namespace which stands for finite element basis. In order to perform an analysis
on it, one needs to configure a corresponding object. In line 21 a simple “Deform” object gets created
which calculates static deflections. A response object lets you query the analysis for results. It gets
created in line 30. One has to make sure that a new set of Deform- and Response-objects is created
for every new state of the model. This is the reason why their creation occurs inside the loop for
changing the activation state of the model elements.
Lines 35 and 37 contain the calls for calculating the model displacements and cross section forces.
In case the system can not be evaluated (e.g. due to being kinematic) an exception will fly.
In lines 48 to 57 the algorithm iterates over all elements in the system, reads out their resultant sec-
tion forces and sets all members inactive that are under tension (N ≥ 0). The “set_is_active” method
sets the “is_active”-flag both in the C#-model and the C++-model. If properties get only changed in
the C#-model the C++-model gets out of sync and thus would calculate a wrong structure. A way
2.5 Data Export from Karamba3D 15

to avoid this would be to rebuild the C++-model completely from the C#-model (as demonstrated in
the previous section) after having changed the latter. As this step can be time-consuming it is better
avoided whenever possible.
Each time the C++-model changes it needs to be made aware of that. In order to invalidate its state,
the touch()-function gets invoked. When leaving out this command the C++-model will not recalculate
in the next iteration as it assumes that its results from the previous cycle are still valid.
As soon as there are no more changes (line 60) or the maximum number of iterations is reached the
program leaves the loop and the model gets updated for a last time.
The “GC.KeepAlive” commands in lines 85 and 86 make sure that the automatic garbage collection
in C# does not prematurely free the “deform” and “response” objects. As “deform” is internally ref-
erenced by “response” freeing the former object would lead to a dangling pointer and undefined
behavior “response”.
An iteration over all elements creates a list of boolean values that corresponds to their activation
state(lines 95 to 98). In line 100 this list is handed over to the output variable. Line 101 puts a
GH_Model wrapper object around the model-object that contains the final results.
In line 82 the response object is queried for the maximum deflection in the model. Its value is then
handed over to the “maxDisp” output variable.

2.5 Data Export from Karamba3D

Figure 2.6 By inheriting from “Karamba.Exporters.ExportBuilder” and overriding “builder”-methods a builder-


class can be configured to export Karamba3D-models to any format – here XML.

When it comes to exporting data from a Karamba3D model to another data-format one could sim-
ply go through the object tree of the model and iterate manually over the existing entities like e.g.
nodes, elements, materials, . . . . The use of a builder pattern removes some of the bureaucratic
overhead involved in this approach. The script in the example “ModelExport.gh” shows how to gen-
erate an XML-file based on a given Karamba3D-model. The output consists of a string which can be
streamed to a file. When opened with a web-browser a nicely formatted tree results (see fig. 2.6).
The corresponding source-code looks like this:
1 ...
2 using S y s t e m . Xml ;
3 using System . IO ;
4 using Karamba . M o d e l s ;
5 using Karamba . Nodes ;
6 using Karamba . C r o s s S e c t i o n s ;
7 using Karamba . E l e m e n t s ;
8 using Karamba . L o a d s ;
9 using Karamba . M a t e r i a l s ;
2.5 Data Export from Karamba3D 16

10 u s i n g Karamba . S u p p o r t s ;
11 u s i n g Karamba . G e o m e t r y ;
12 ...
13 p r i v a t e v o i d R u n S c r i p t ( o b j e c t M o d e l _ i n , r e f o b j e c t XML )
14 {
15 v a r model = M o d e l _ i n as M o d e l ;
16 i f ( model == n u l l ) {
17 t h r o w new A r g u m e n t E x c e p t i o n ( " The i n p u t i s n o t o f t y p e model ! " ) ;
18 }
19
20 v a r b u i l d e r = new B u i l d e r X M L ( ) ;
21 v a r d i r e c t o r = new Karamba . E x p o r t e r s . E x p o r t D i r e c t o r ( ) ;
22 d i r e c t o r . C o n s t r u c t E x p o r t ( model , b u i l d e r ) ;
23
24 XML = b u i l d e r . g e t P r o d u c t ( ) ;
25 }
26
27 / / < Custom a d d i t i o n a l code >
28 p u b l i c c l a s s B u i l d e r X M L : Karamba . E x p o r t e r s . E x p o r t B u i l d e r {
29 / / t h e XML d o c u m e n t
30 p r i v a t e XmlDocument d o c _ = new XmlDocument ( ) ;
31 / / t h e m o d e l i n s i d e t h e xml − d o c u m e n t
32 p r i v a t e XmlElement model_ ;
33
34 p u b l i c o v e r r i d e void newProduct ( ) {
35 m o d e l _ = ( X m l E l e m e n t ) d o c _ . A p p e n d C h i l d ( d o c _ . C r e a t e E l e m e n t ( " K3DModel " ) ) ;
36 }
37
38 p u b l i c o v e r r i d e v o i d b u i l d M a t e r i a l ( F e m M a t e r i a l m, i n t i n d ) {
39 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " FemMaterial " ) ) ;
40 xml_node . I n n e r T e x t = " i n d : " + i n d + " : " + m. T o S t r i n g ( ) ;
41 }
42
43 p u b l i c o v e r r i d e v o i d b u i l d V e r t e x ( Node v ) {
44 v a r x m l _ n o d e = ( X m l E l e m e n t ) m o d e l _ . A p p e n d C h i l d ( d o c _ . C r e a t e E l e m e n t ( " Node " ) ) ;
45 xml_node . I n n e r T e x t = v . T o S t r i n g ( ) ;
46 }
47
48 p u b l i c o v e r r i d e void b u i l d C r o S e c ( CroSec crosec ) {
49 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " CroSec " ) ) ;
50 xml_node . I n n e r T e x t = crosec . T o S t r i n g ( ) ;
51 }
52
53 p u b l i c o v e r r i d e v o i d b u i l d E l e m e n t ( M o d e l E l e m e n t e , M o d e l model ) {
54 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " ModelElement " ) ) ;
55 xml_node . I n n e r T e x t = e . T o S t r i n g ( ) ;
56 }
57
58 p u b l i c o v e r r i d e v o i d b u i l d E l e m e n t L o a d ( M o d e l E l e m e n t elem , M o d e l model ) {
59 f o r e a c h ( v a r l i n elem . E l e m _ l o a d s ) {
60 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " ElementLoad " ) ) ;
61 xml_node . I n n e r T e x t = l . T o S t r i n g ( ) ;
62 }
63 }
64
65 p u b l i c o v e r r i d e v o i d b u i l d L o a d C a s e ( i n t l c _ i n d , M o d e l model ) {
66 V e c t o r 3 g _ v e c = new V e c t o r 3 ( 0 , 0 , 0 ) ;
67 f o r e a c h ( G r a v i t y L o a d g i n model . g r a v i t i e s . V a l u e s ) {
68 i f ( g . l o a d c a s e < 0 | | g . l o a d c a s e == l c _ i n d ) {
69 g_vec = g . force ;
70 };
71 }
72 v a r xml_node = ( XmlElement ) model_ . A p p e n d C h i l d ( doc_ . C r e a t e E l e m e n t ( " LoadCase " ) ) ;
73 x m l _ n o d e . I n n e r T e x t = " l o a d −case : " + l c _ i n d + " g = " + g _ v e c ;
74 }
75
76 public o v e r r i d e void buildSupport ( Support s ) {
77 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " Support " ) ) ;
78 xml_node . I n n e r T e x t = s . T o S t r i n g ( ) ;
79 }
80
81 public o v e r r i d e void buildPointLoad ( PointLoad p ) {
82 v a r xml_node = ( XmlElement ) model_ . AppendChild ( doc_ . C r e a t e E l e m e n t ( " PointLoad " ) ) ;
83 xml_node . I n n e r T e x t = p . T o S t r i n g ( ) ;
84 }
2.6 The VB Script Component 17

85
86 p u b l i c o v e r r i d e v o i d b u i l d M e s h L o a d ( MeshLoad m) {
87 v a r x m l _ n o d e = ( X m l E l e m e n t ) m o d e l _ . A p p e n d C h i l d ( d o c _ . C r e a t e E l e m e n t ( " MeshLoad " ) ) ;
88 x m l _ n o d e . I n n e r T e x t = m. T o S t r i n g ( ) ;
89 }
90
91 public string getProduct ( ) {
92 S t r i n g W r i t e r sw = new S t r i n g W r i t e r ( ) ;
93 X m l T e x t W r i t e r t x = new X m l T e x t W r i t e r ( sw ) ;
94 doc_ . WriteTo ( t x ) ;
95 s t r i n g s t r = sw . T o S t r i n g ( ) ; / /
96 return str ;
97 }
98 }

The first part of the script comprises the “RunScript”-method. There the “Model_in”-object gets con-
verted to a Karamba3D-Model. In line 20 follows the creation of a builder-object which does the
conversion-work. The class “BuilderXML” gets defined further below in the script. A director-objects
is instantiated in the next line. Its task consists of iterating over the model constituents and present-
ing them to the builder. Calling “ConstructExport” in line 22 initiates the creation process. Line 24
assigns the builder’s product to the output variable “XML”.
The “BuilderXML”-class derives from Karamba.Exporters.ExportBuilder and overrides some of its
methods. In order to keep things simple each build-method adds a XML-node which contains the
string-representation of the corresponding argument. In case of “ModelElement” the corresponding
build-method does not know which type of element gets passed. Thus one has to apply pattern-
matching to find get the right type (e.g. “ModelBeam”, “ModelTruss”, “ModelShell” or “ModelSpring”)

2.6 The VB Script Component

The steps for setting up a VB script component for using Karamba3D are analogous to those de-
scribed in section 2.1. In order to run the above example in VB you could use one of the many C# to VB
converters (see e.g. http://www.developerfusion.com/tools/convert/csharp-to-vb/)
to get the corresponding VB source text.

2.7 The IronPython Component

2.7.1 Results Retrieval on Shells

Figure 2.7 Two python scripts: the first retrieves shell results, the second one performs a simplified variant
of an evolutionary structural optimization (ESO) procedure.
2.7 The IronPython Component 18

IronPython is the DotNet version of Python. Being an open platform independent scripting language,
Python comes with many useful libraries (of which however not all run under IronPython). In order to
use it from within Grasshopper under Rhino5 install GHPython which can be downloaded from http:
//www.food4rhino.com/project/ghpython. GH for Rhino6 and 7 comes with GHPython by
default.
The example file “SimpleShellESO” (see fig. 2.7) contains two Python-scripts which will be explained
below. The first script retrieves results from Karamba3D’s triangular shell elements:
1 import c l r
2
3 c l r . A d d R e f e r e n c e T o F i l e A n d P a t h ( " C : \ P r o g r a m F i l e s \ R h i n o 6 \ P l u g − i n s \ Karamba . gha " )
4 c l r . A d d R e f e r e n c e T o F i l e A n d P a t h ( " C : \ P r o g r a m F i l e s \ R h i n o 6 \ P l u g − i n s \ KarambaCommon . d l l " )
5
6 import Karamba . M o d e l s . M o d e l as M o d e l
7 import Karamba . E l e m e n t s . M o d e l S h e l l as S h e l l
8 import f e b . S h e l l M e s h as S h e l l M e s h
9 import f e b . T r i S h e l l 3 D as T r i S h e l l
10 import f e b . V e c t S u r f a c e 3 D S i g E p s as T r i S t a t e s
11 import f e b . E n e r g y V i s i t o r as E n e r g y V i s i t o r
12
13 f o r element i n M o d e l _ i n . elems :
14 i f type ( element ) != S h e l l :
15 continue
16
17 print " shell ! "
18 femesh = M o d e l _ i n . f e b m o d e l . t r i M e s h ( e l e m e n t . f e _ i d )
19 n _ t r i = f eme sh . n u m b e r O f E l e m s ( )
20 p r i n t " number o f t r i a n g l e e l e m e n t s : " , n _ t r i
21
22 e n e r g y _ v i s i t o r = E n e r g y V i s i t o r ( Model_in . febmodel , Model_in . febmodel . s t a t e ( 0 ) , 0 ) ;
23 e n e r g y _ v i s i t o r . v i s i t ( Model_in . febmodel ) ;
24
25 for ind in xrange ( n _ t r i ) :
26 p r i n t " A x i a l Energy " , e n e r g y _ v i s i t o r . a x i a l E n e r g y ( M o d e l _ i n . elems [ 0 ] . f e _ i d + i n d )
27 p r i n t " Bending Energy " , e n e r g y _ v i s i t o r . b e n d i n g E n e r g y ( M o d e l _ i n . elems [ 0 ] . f e _ i d + i n d )
28
29 t r i _ s t a t e s = fe mes h . e l e m e n t S i g E p s ( M o d e l _ i n . f e b m o d e l , 0 , M o d e l _ i n . s u p e r i m p F a c s S t a t e s )
30 for t r i _ s t a t e in t r i _ s t a t e s :
31 s = tri_state . sig_princ ()
32 p r i n t " f i r s t p r i n c i p a l s t r e s s ( kN / cm2 ) : " , s . x ( ) / 1 0 0 0 0
33 p r i n t " s e c o n d p r i n c i p a l s t r e s s ( kN / cm2 ) : " , s . y ( ) / 1 0 0 0 0
34
35 p r i n t " Number o f e l e m e n t s " , M o d e l _ i n . e l e m s . C o u n t

Lines three and four reference the Karamba3D DotNet-assemblies. Depending on how you installed
Rhino it might be necessary to adapt the paths. In case that one of them can not be located an error
will be issued.
Plug the output of “out” into a panel. If there is only one line of output, type “GrasshopperDevelop-
erSettings” in the Rhino text window and check whether the “Memory load *.GHA assemblies using
COFF byte arrays”-option is unhooked.
The retrieval of axial- and bending-energies works via the visitor-pattern (see [2] for details on that).
Line 22 creates such a visitor object for the elastic element energies by handing over a reference
to a C++ model, a state, a load-case index and possibly a load-case factor. Unless one performs
non-linear calculations state “0” is the right one to chose.
A shell patch consists of several shell elements. This might lead to some confusion since in the
Grasshopper UI shell patches are named “elements”, in the C++ model however the patches consist
of several triangular shell elements. In lines 26 and 27 the property “fe_ind” returns the index of a
C++ element that corresponds to a given C#-element. In case of shell-patches this corresponds to
the first C++-element.
2.7 The IronPython Component 19

Other shell results like principal stresses can be retrieved directly from the FE-mesh like in lines 29
to 33. “Model_in.superimpFacsStates” represents a list of load-factors which gets defined via the
“Result-Case”-setting or the input-plug “R-Factors” of the “ModelView”-component-

2.7.2 A Simplified ESO-Procedure on Shells


The example file “SimpleShellEso.gh” contains also a Python script which performs a simple evolu-
tionary structural optimization (ESO) procedure on shell elements. As it applies no filters for calculat-
ing the fitness of individual shell triangles checkerboard patterns result (see fig. 2.7). Alas the script
can be easily extended to include more elaborate fitness calculation schemes. The script shows how
to work directly with the C++ model in order to avoid costly mappings to and fro the C#-model:
1 import c l r
2
3 c l r . A d d R e f e r e n c e T o F i l e A n d P a t h ( " C : \ P r o g r a m F i l e s \ R h i n o 6 \ P l u g − i n s \ Karamba . gha " )
4 c l r . A d d R e f e r e n c e T o F i l e A n d P a t h ( " C : \ P r o g r a m F i l e s \ R h i n o 6 \ P l u g − i n s \ KarambaCommon . d l l " )
5
6 import Karamba . M o d e l s . M o d e l as M o d e l
7 import Karamba . E l e m e n t s . M o d e l S h e l l as S h e l l
8 import Karamba . M a t e r i a l s . F e m M a t e r i a l _ I s o t r o p as F e m M a t e r i a l
9 import f e b . S h e l l M e s h as S h e l l M e s h
10 import f e b . T r i S h e l l 3 D as T r i S h e l l 3 D
11 import f e b . V e c t S u r f a c e 3 D S i g E p s as T r i S t a t e s
12 import f e b . D e f o r m as D e f o r m
13 import f e b . R e s p o n s e as R e s p o n s e
14 import f e b . E n e r g y V i s i t o r as E n e r g y V i s i t o r
15 import R h i n o . G e o m e t r y as Rh
16
17 from o p e r a t o r i m p o r t a t t r g e t t e r
18
19 # e n c a p s u l a t e ESO p r o p e r t i e s o f s h e l l e l e m e n t s
20 class EsoItem :
21 def _ _ i n i t _ _ ( self , shell_elem , elem_ind ) :
22 s e l f . a c t i v e = True
23 self . fitness = 0
24 self . shell_elem = shell_elem
25 s e l f . area = shell_elem . area ( )
26 s e l f . ind = elem_ind
27
28 def update ( self , e n e r g y _ v i s i t o r ) :
29 s e l f . f i t n e s s = e n e r g y _ v i s i t o r . e l a s t i c E n e r g y ( s e l f . ind ) / s e l f . area
30
31
32 # c l o n e model t o a v o i d s i d e e f f e c t s
33 model = M o d e l _ i n . C l o n e ( )
34 model . d e e p C l o n e F E M o d e l ( )
35
36 # g e n e r a t e ESO p r o p e r t i e s o f e a c h t r i a n g u l a r s h e l l e l e m e n t
37 eso_items = [ ]
38 f o r e l e m i n model . e l e m s :
39 i f t y p e ( elem ) ! = S h e l l :
40 continue
41 t r i _ m e s h = model . f e b m o d e l . t r i M e s h ( e l e m . f e _ i d )
42 f o r i i n xrange ( t r i _ m e s h . numberOfElems ( ) ) :
43 e s o _ i t e m s . append ( EsoItem ( t r i _ m e s h . elem ( i ) , i ) )
44
45 n r e m o v e _ p e r _ i t e r = i n t ( NRemove / N I t e r + 1 )
46 n_removed = 0
47
48 # do t h e ESO i t e r a t i o n s
49 for i t e r in xrange ( N I t e r ) :
50 a n a l y s i s = D e f o r m ( model . f e b m o d e l )
51 response = Response ( a n a l y s i s )
52
53 try :
54 response . updateNodalDisplacements ( )
55 response . updateMemberForces ( )
56 except :
57 raise Exception ( " singular stiffness " )
2.7 The IronPython Component 20

58
59 e n e r g y _ v i s i t o r = E n e r g y V i s i t o r ( model . f e b m o d e l , model . f e b m o d e l . s t a t e ( 0 ) , 0 ) ;
60 e n e r g y _ v i s i t o r . v i s i t ( model . f e b m o d e l ) ;
61
62 for eso_item in eso_items :
63 eso_item . update ( e n e r g y _ v i s i t o r )
64
65 eso_items = s o r t e d ( eso_items , key = a t t r g e t t e r ( " f i t n e s s " ) )
66
67 n_removed_per_iter = 0
68 has_changed = False
69 for eso_item in eso_items :
70 i f ( n _ r e m o v e d >= NRemove ) : b r e a k
71 i f ( n _ r e m o v e d _ p e r _ i t e r >= n r e m o v e _ p e r _ i t e r ) : b r e a k
72 i f ( e s o _ i t e m . a c t i v e == F a l s e ) :
73 continue
74 eso_item . s h e l l _ e l e m . s o f t K i l l e d ( True )
75 eso_item . active = False
76 n_removed +=1
77 n _ r e m o v e d _ p e r _ i t e r +=1
78
79 has_changed = True
80 i f ( h a s _ c h a n g e d == F a l s e ) :
81 break
82 model . f e b m o d e l . t o u c h ( )
83
84 # c r e a t e a c t i v e and i n a c t i v e mesh f o r o u t p u t
85 a c t i v e _ m e s h = Rh . Mesh ( )
86 i n a c t i v e _ m e s h = Rh . Mesh ( )
87 f o r i i n x r a n g e ( model . f e b m o d e l . n u m b e r O f N o d e s ( ) ) :
88 f e b _ p o s = model . f e b m o d e l . node ( i ) . pos ( )
89 a c t i v e _ m e s h . V e r t i c e s . Add ( Rh . P o i n t 3 d ( f e b _ p o s . x ( ) , f e b _ p o s . y ( ) , f e b _ p o s . z ( ) ) )
90 i n a c t i v e _ m e s h . V e r t i c e s . Add ( Rh . P o i n t 3 d ( f e b _ p o s . x ( ) , f e b _ p o s . y ( ) , f e b _ p o s . z ( ) ) )
91
92 for eso_item in eso_items :
93 i n d 0 = e s o _ i t e m . s h e l l _ e l e m . node ( 0 ) . i n d ( )
94 i n d 1 = e s o _ i t e m . s h e l l _ e l e m . node ( 1 ) . i n d ( )
95 i n d 2 = e s o _ i t e m . s h e l l _ e l e m . node ( 2 ) . i n d ( )
96 i f ( eso_item . active ) :
97 a c t i v e _ m e s h . F a c e s . A d d F a c e ( Rh . MeshFace ( i n d 0 , i n d 1 , i n d 2 ) )
98 else :
99 i n a c t i v e _ m e s h . F a c e s . A d d F a c e ( Rh . MeshFace ( i n d 0 , i n d 1 , i n d 2 ) )
100
101 activeMesh = active_mesh
102 inactiveMesh = inactive_mesh

In the above code the class “ESOItem” handles the book-keeping necessary in the optimization steps.
it contains the activation-state, the fitness, the element’s area, a reference to the C++-element and
the element’s index in the C#-model. The “update”-method calculates the specific elastic energy of
the underlying shell-element.
Activation and deactivation of model elements works via setting the soft-kill status of C++-elements
to “True” or “False” (see line 74). On model-assembly the stiffness of the corresponding element will
be multiplied with the soft-kill-factor which is 1.0 × 10−10 . This factor can be set on the C++-model
via “softKillFactor(new_factor)” if necessary.
The last part of the script categorizes the shell-faces into active or in-active adding their geometry
to the corresponding output-meshes.
Chapter 3

How to create your own Karamba3D Grasshopper-component

In case of larger scripting projects advanced debugging facilities and the organization of source
code in neatly separated files makes life easier. Integrated development environments like Microsoft
Visual Studio offer these possibilities – and some more. The “Community”-version of Visual Studio
can be downloaded for free from the Microsoft web-site.

3.1 Setting up a Visual Studio Project for GH Plug-ins

A useful GH related tool for Visual Studio can be found at https://marketplace.visualstudio.


com/items?itemName=McNeel.GrasshopperAssemblyforv6: It contains project and compo-
nent wizards which take care of the project settings and boiler-plate code necessary to create valid
GH-components.

3.2 Basic Component Setup

The example in this section assumes that you have Visual Studio 2017 and the above mentioned
GH add-on installed. In order to make things easy, the script will be analogous to that presented in
section 2.4.2. Follow these steps to set up a project for creating a GH component which makes use
of Karamba3D functionality:
1. Start Visual Studio and select “File/New/Project . . . ” from the main menu. A Window appears
which lets you select from among different project types (see fig 3.1).
2. Go to the bottom of the window and set the name of the project to “TensionElim”.
Grasshopper loads plug-ins according to the alphanumeric order of their file-names. If
a component intends to use Karamba3D functionality make sure its name comes after
“Karamba3D” otherwise it will not be able to reference it.
3. Browse to a folder where your project shall be created using the “Browse”-button
4. Unhook the “Create directory for solution”-option.
5. Select “Visual C#” from the right hand side tree-menu of installed templates. In case you want
to script in VB select the corresponding entry. Double-click on “Grasshopper Add-On” in the
middle part of the window.

21
3.2 Basic Component Setup 22

Figure 3.1 Select Grasshopper Add-On from the templates available for C# or VB.

6. Another window appears that lets you configure the properties of the Grasshopper component.
7. You can now change the name, nick-name, category (e.g. “Karamba3D”) and subcategory
(e.g. “Extra”) under which the component appears inside Grasshopper – but they can also be
changed later on.
8. In case that the path to Grasshopper, RhinoCommon or Rhino appears in red click on the “...”
button and point to the right directory.
9. Press “Finish”. The GH component wizard now creates the project “TensionElim” which already
contains the basic frame for a GH component.

Select “View/SolutionExplorer” to get a list of all files that belong to the project. The file “Assem-
blyInfo.cs” in the “Properties”-folder of the SolutionExplorer lets you set the title of your assembly, a
description, a copyright message and so on. The folder “References” lists all those assemblies which
the component borrows functionality from. By default these are “GH_IO”, “Grasshopper”, “RhinoCom-
mon” and some system assemblies. In “TensionElimComponent.cs” you will find the definition of the
class “TensionElimComponent”. It inherits its functionality from the class “GH_Component” and thus
lets you define the properties and behavior of the component later visible in GH.
As a first try right-click on the project “TensionElim” and select “Build” from the context menu. If all
goes well the file “TensionElim.gha” gets created in the “bin”-folder of the Visual Studio project. Copy
this file to one of the places where Grasshopper looks for plug-ins at start-up. Among others these
two choices exist:
• The “Libraries”-folder of Grasshopper. It sits in the user-directors under “C:/Users/Username/App-
Data/Roaming/Grasshopper/Libraries” an can be accessed from within Grasshopper via the
menu “File/Special Folders/Components Folder”. The advantage of putting a plug-in there is,
that a user does not need any special privileges to install it.
• The “Plug-ins”-folder of Rhino to be found at e.g. “C:/Program Files/Rhino 6” when working
with Rhinoceros 6. Placing a plug-in there makes it accessible to all users of the computer.
The disadvantage of this file location lies in the fact that one needs to have admin-rights to
install a file there.
3.3 How to Reference Karamba3D Assemblies 23

Karamba3D lives in the “Plug-ins”-folder of Rhino. So plug-ins which reference its functionality need
to be placed there as well.
In order to avoid the manual copying of the “.gha”-file you can setup a post-build-event in the Visual
Studio Project settings – this makes debugging more comfortable: Right-click on the project entry
in the Solution Explorer, select “Properties”, choose “Build Events” from the left-hand tabs, and add
in one line at the end of the “Post-build event command line” text window
1 Copy ’ ’ $ ( T a r g e t D i r ) $ ( P r o j e c t N a m e ) . gha ’ ’
2 ’ ’ C : \ U s e r s \ Y o u r U s e r N a m e H e r e ! ! \ A p p D a t a \ Roaming \ G r a s s h o p p e r \ L i b r a r i e s \ $ ( P r o j e c t N a m e ) . gha ’ ’

or
1 Copy ’ ’ $ ( T a r g e t D i r ) $ ( P r o j e c t N a m e ) . gha ’ ’
2 ’ ’ C : \ P r o g r a m F i l e s \ R h i n o 6 \ $ ( P r o j e c t N a m e ) . gha ’ ’

in case you use Rhino 6. Do not forget to replace “YourUserNameHere!!” by your user name in case
of option one. For option one has to assume ownership of of the Rhino “Plug-ins”-folder and acquire
write-rights otherwise the copy command fails.
Upon starting (or restarting) GH there should now show up a new icon in the category and subcat-
egory previously provided by you in the constructor of the “TensionElimComponent”-class (see fig.
3.2). As yet there is no image attached to the new button. Therefore it shows up as a circle filled
with black and white rectangles. Take a look at the function “Icon” of the “TensionElimComponent”-
class to change this if you want. You will also notice that the new component has neither input- nor
output-plugs.

Figure 3.2 First step: Custom component without input- or output-plugs.

3.3 How to Reference Karamba3D Assemblies

In order to package the script of section 2.4.2 into a GH-component there needs to be one input-plug
that receives a Karamba3D model. Three output plugs return an updated Karamba3D model, a list of
boolean values that signifies which elements are active or not and the value of the largest resultant
displacement.
The following example can be found in the examples that accompany this guide. Go to “#/TensionE-
lim” and double-click on “TensionElim.sln” to open the project with Visual Studio. Depending on what
version of Grasshopper you use it will be necessary to reestablish the project references.
The first step consists in referencing the “karambaCommon.dll”-library so that Karamba3D-classes
(such as the Model-class) can be dealt with. For this right-click on “References” in the “Solution
3.4 Input- and Output-Plugs 24

Figure 3.3 Work-around for referencing “karamba.gha” in Visual Studio: Edit the “TensionElim.csproj”-file

Explorer” select “Add Reference...” from the context menu and go to “Browse” on the tabbed view
and point to “karambaCommon.dll” in the Rhino “Plug-ins”-folder. Since Karmba3D shall be used
within Grasshopper, one needs to include “karamba.gha” as well. Alas by default Visual Studio does
not allow the selection of files with extension “.gha”. As a work-around do the following: Save and
close your Visual Studio project. In the project directory you will find a file called “TensionElim.csproj”.
Open it with a text editor, search for “karambaCommon”, copy its entry, fill in “karamba.gha” (see fig.
3.3), save it and reopen the Visual Studio project.
Now right-click on the “karamba” and “karambaCommon”-entries in “References” and select “Prop-
erties” from the context menu. Set the property “Copy Local” (it has the value true by default) to
false.

3.4 Input- and Output-Plugs

Now it is time to add the input- and output-plugs to the new component. This is the listing of the first
few lines of “TensionElimComponent.cs” which implements this functionality:
1 u s i n g System ;
2 u s i n g System . C o l l e c t i o n s . G e n e r i c ;
3
4 using Grasshopper . Kernel ;
5
6 u s i n g Karamba . M o d e l s ;
7 u s i n g Karamba . GHopper . M o d e l s ;
8
9 namespace T e n s i o n E l i m {
10 p u b l i c c l a s s T e n s i o n E l i m C o m p o n e n t : GH_Component
11 {
12 public TensionElimComponent ( )
13 : base ( " T e n s i o n E l i m " , " TenElim " ,
14 "." ,
15 " Karamba " , " E x t r a " )
16 {
17 }
18
19 p r o t e c t e d o v e r r i d e v o i d R e g i s t e r I n p u t P a r a m s ( GH_Component . G H _ I n p u t P a r a m M a n a g e r p Ma n ag e r )
20 {
21 p M a na g er . A d d P a r a m e t e r ( new P a r a m _ M o d e l ( ) , " M o d e l _ i n " , " M o d e l _ i n " ,
22 " M o d e l t o be m a n i p u l a t e d " , GH_ParamAccess . i t e m ) ;
23 }
24
25 p r o t e c t e d o v e r r i d e v o i d R e g i s t e r O u t p u t P a r a m s ( GH_Component . G H _ O u t p u t P a r a m M a n a g e r p Ma n a ge r )
26 {
27 p M an a g er . R e g i s t e r P a r a m ( new P a r a m _ M o d e l ( ) , " M o d e l _ o u t " , " M o d e l _ o u t " ,
28 " Model a f t e r e l i m i n a t i n g a l l t e n s i o n e l e m e n t s " ) ;
29 p M an a g er . R e g i s t e r _ B o o l e a n P a r a m ( " i s A c t i v e " , " i s A c t i v e " ,
30 " L i s t o f b o o l e a n v a l u e s c o r r e s p o n d i n g t o e a c h e l e m e n t i n t h e model . " +
31 " True i f the element i s a c t i v e . " ) ;
32 p M a na g er . R e g i s t e r _ D o u b l e P a r a m ( " maximum d i s p l a c e m e n t " , " m a x D i s p " ,
3.5 Adding Functionality to a GH Component 25

33 " Maximum d i s p l a c e m e n t [ m ] o f t h e model a f t e r e l i m i n a t i o n p r o c e s s . " ) ;


34 }

Figure 3.4 Second step: Custom component with input- and output-plugs but no functionality yet.

Line 1 to 4 get automatically created by the GH-wizard. Lines 6 and 7 are important: they make the
classes available (i.e. Model, Param_Model, GH_Model, Element, ...) which reside in the namespaces
“Karamba.Models” and “Karamba.GHopper.Models”. This allows to define the component input in
lines 21 and 22. Objects that are used as component input or output need to be wrapped so that
GH can handle them. In Karamba3D these wrapper classes are named after the class they wrap
preceded by “Param_” and “GH_”. Lines 27 to 33 specify the output plugs. Supplement “TensionElim-
Component.cs” with the above lines, compile the project and copy the resulting “TensionElim.gha”
as before. Restart Rhino. Fig. 3.4 shows the component with input and output-plugs.

3.5 Adding Functionality to a GH Component

In order to make the component do something one has to add code to the “SolveInstance” function
in “TensionElimComponents”:
1 p r o t e c t e d o v e r r i d e v o i d S o l v e I n s t a n c e ( I G H _ D a t a A c c e s s DA )
2 {
3 GH_Model i n _ g h _ m o d e l = n u l l ;
4 i f ( ! DA . G e t D a t a < GH_Model > ( 0 , r e f i n _ g h _ m o d e l ) ) r e t u r n ;
5 v a r model = i n _ g h _ m o d e l . V a l u e ;
6
7 / / maximum number o f i t e r a t i o n s
8 int max_iter = 10;
9 DA . G e t D a t a < i n t > ( 1 , r e f m a x _ i t e r ) ;
10
11 / / load case to c o n s i d e r f o r e l i m i n a t i o n of elements
12 i n t lc_num = 0 ;
13
14 / / c l o n e model t o a v o i d s i d e e f f e c t s
15 model = ( Karamba . M o d e l s . M o d e l ) model . C l o n e ( ) ;
16
17 // clone i t s elements to avoid side e f f e c t s
18 model . c l o n e E l e m e n t s ( ) ;
19
20 / / c l o n e t h e f e b −model t o a v o i d s i d e e f f e c t s
21 model . d e e p C l o n e F E M o d e l ( ) ;
22
23 s t r i n g s i n g u l a r _ s y s t e m _ m s g = " The s t i f f n e s s m a t r i x o f t h e s y s t e m i s s i n g u l a r . " ;
24
25 / / do t h e i t e r a t i o n and r e m o v e e l e m e n t s w i t h t e n s i l e a x i a l f o r c e s
26 for ( i n t i t e r = 0 ; i t e r < max_iter ; i t e r ++)
27 {
28 / / c r e a t e an a n a l y s i s and r e s p o n s e o b j e c t f o r c a l c u l a t i n g and r e t r i e v i n g results
29 f e b . D e f o r m a n a l y s i s = new f e b . D e f o r m ( model . f e b m o d e l ) ;
30 f e b . R e s p o n s e r e s p o n s e = new f e b . R e s p o n s e ( a n a l y s i s ) ;
31
32 try
33 {
34 // c a l c u l a t e the displacements
3.5 Adding Functionality to a GH Component 26

35 response . updateNodalDisplacements ( ) ;
36 / / c a l c u l a t e t h e member f o r c e s
37 response . updateMemberForces ( ) ;
38 }
39 catch
40 {
41 / / s e n d an e r r o r message i n c a s e s o m e t h i n g w e n t w r o n g
42 t h r o w new E x c e p t i o n ( s i n g u l a r _ s y s t e m _ m s g ) ;
43 }
44
45 / / c h e c k t h e n o r m a l f o r c e o f e a c h e l e m e n t and d e a c t i v a t e t h o s e u n d e r t e n s i o n
46 double N , V , M;
47 bool has_changed = f a l s e ;
48 f o r e a c h ( v a r e l e m i n model . e l e m s )
49 {
50 // r e t r i e v e r e s u l t a n t cross section forces
51 e l e m . r e s u l t a n t C r o S e c F o r c e s ( model , l c _ n u m , o u t N , o u t V , o u t M ) ;
52 / / check whether normal f o r c e i s t e n s i l e
53 i f ( ! ( N >= 0 ) ) c o n t i n u e ;
54 // set element i n a c t i v e
55 e l e m . s e t _ i s _ a c t i v e ( model , f a l s e ) ;
56 has_changed = true ;
57 }
58
59 / / l e a v e i t e r a t i o n loop i f n o t h i n g changed
60 i f ( ! has_changed ) break ;
61
62 / / i f s o m e t h i n g c h a n g e d i n f o r m t h e f e b −model a b o u t i t
63 / / ( o t h e r w i s e i t won ’ t r e c a l c u l a t e )
64 model . f e b m o d e l . t o u c h ( ) ;
65
66 / / t h i s guards the o b j e c t s from b e i n g f r e e d p r e m a t u r e l y
67 GC . K e e p A l i v e ( a n a l y s i s ) ;
68 GC . K e e p A l i v e ( r e s p o n s e ) ;
69 }
70
71 / / u p d a t e model t o i t s f i n a l s t a t e
72 double max_disp = 0 ;
73 try
74 {
75 / / c r e a t e an a n a l y s i s and r e s p o n s e o b j e c t f o r c a l c u l a t i n g and r e t r i e v i n g results
76 f e b . D e f o r m a n a l y s i s = new f e b . D e f o r m ( model . f e b m o d e l ) ;
77 f e b . R e s p o n s e r e s p o n s e = new f e b . R e s p o n s e ( a n a l y s i s ) ;
78
79 // c a l c u l a t e the displacements
80 response . updateNodalDisplacements ( ) ;
81 / / c a l c u l a t e t h e member f o r c e s
82 response . updateMemberForces ( ) ;
83
84 max_disp = response . maxDisplacement ( ) ;
85
86 / / t h i s guards the o b j e c t s from b e i n g f r e e d p r e m a t u r e l y
87 GC . K e e p A l i v e ( a n a l y s i s ) ;
88 GC . K e e p A l i v e ( r e s p o n s e ) ;
89 }
90 catch
91 {
92 / / s e n d an e r r o r message i n c a s e s o m e t h i n g w e n t w r o n g
93 t h r o w new E x c e p t i o n ( s i n g u l a r _ s y s t e m _ m s g ) ;
94 }
95
96 / / s e t up l i s t o f t r u e / f a l s e v a l u e s t h a t c o r r e s p o n d s t o t h e e l e m e n t s t a t e s
97 L i s t < b o o l > e l e m _ a c t i v i t y = new L i s t < b o o l > ( ) ;
98 f o r e a c h ( v a r e l e m i n model . e l e m s )
99 {
100 e l e m _ a c t i v i t y . Add ( e l e m . i s _ a c t i v e ) ;
101 }
102
103 DA . S e t D a t a ( 0 , new GH_Model ( model ) ) ;
104 DA . S e t D a t a L i s t ( 1 , e l e m _ a c t i v i t y ) ;
105 DA . S e t D a t a ( 2 , m a x _ d i s p ) ;
106 }

A comparison with the listing in section 2 shows that only the first and last parts differ significantly:
3.5 Adding Functionality to a GH Component 27

In line 3 a wrapper-object for a Karamba3D model gets initialized to null and set to the value of the
input plug of index “0”. The “if” statement in line 4 checks whether there is any data to process. In line
5 the Karamba3D-model gets retrieved from the GH-wrapper. In lines 8 to 9 the value of the “maxiter”
plug-in gets read.
All the rest down to line 101 constitutes more or less a replica of the code of section 2.4.2. Lines 103
to 105 transfer the results of the algorithm to the output-plugs.
The example “ActivationDeactivationOfElements_CustomComponent” (see fig. 3.5) shows that the
results using the GH custom component are the same as in section 2.4.2.

Figure 3.5 Elimination of elements under tension. This time using a custom GH-component.
Bibliography

[1] Joseph Albahari. C# 7.0 in a Nutshell. O’Reilly UK Ltd., 2017. ISBN 1491987650. URL
https://www.ebook.de/de/product/29084295/joseph_albahari_c_7_0_in_a_
nutshell.html.

[2] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Pat-
terns: Elements of Reusable Object-Oriented Software. Addison-Wesley Pro-
fessional, 1994. ISBN 8601419047741. URL https://www.amazon.com/
Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612?
SubscriptionId=AKIAIOBINVZYXZQZ2U3A&tag=chimbori05-20&linkCode=xm2&
camp=2025&creative=165953&creativeASIN=0201633612.

[3] Mark Michaelis. Essential C# 7.0. Microsoft Press, 2018. ISBN 1509303588. URL https:
//www.ebook.de/de/product/28341699/mark_michaelis_essential_c_7_0.html.

[4] Jon Skeet. C# in Depth. Manning, 2019. ISBN 1617294535. URL https://www.ebook.de/de/
product/30504497/jon_skeet_c_in_depth.html.

28

Das könnte Ihnen auch gefallen