The example file “SimpleShellEso.gh” contains also a Python script which performs a simple evolutionary structural optimization (ESO) procedure on shell elements. As it applies no filters for calculating the fitness of individual shell triangles checkerboard patterns result (see fig. 2.7.2.1). 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 from the C#-model:
import clrclr.AddReferenceToFileAndPath("C:\Program Files\Rhino 8\Plug-ins\karamba\Karamba.gha")clr.AddReferenceToFileAndPath("C:\Program Files\Rhino 8\Plug-ins\karamba\KarambaCommon.dll")import Karamba.Models.Model as Modelimport Karamba.Elements.ModelShell as Shellimport Karamba.Materials.FemMaterial_Isotrop as FemMaterialimport Karamba.Utilities.Utils as Utilsimport feb.ShellMesh as ShellMeshimport feb.TriShell3D as TriShell3Dimport feb.VectSurface3DSigEps as TriStatesimport feb.Deform as Deformimport feb.Response as Responseimport feb.EnergyVisitor as EnergyVisitorimport Rhino.Geometry as Rhfrom operator import attrgetter# encapsulate ESO properties of shell elementsclassEsoItem:def__init__(self,shell_elem,elem_ind): self.active =True self.fitness =0 self.shell_elem = shell_elem self.area = shell_elem.area() self.ind = elem_inddefupdate(self,energy_visitor): self.fitness = energy_visitor.elasticEnergy(self.ind)/ self.area# clone model to avoid side effectsmodel = Model_in.Clone()model.deepCloneFEModel()# generate ESO properties of each triangular shell elementeso_items = []for elem in model.elems:iftype(elem)!= Shell:continue tri_mesh = model.febmodel.triMesh(elem.fe_id)for i inxrange(tri_mesh.numberOfElems()): eso_items.append(EsoItem(tri_mesh.elem(i), i))nremove_per_iter =int(NRemove/NIter+1)n_removed =0# do the ESO iterationsforiterinxrange(NIter): analysis =Deform(model.febmodel) response =Response(analysis) loadCaseCombinationIndex =0 Utils.handleError(response.update(loadCaseCombinationIndex), analysis); energy_visitor =EnergyVisitor(model.febmodel, model.febmodel.state(0), 0); energy_visitor.visit(model.febmodel);for eso_item in eso_items: eso_item.update(energy_visitor) eso_items =sorted(eso_items, key =attrgetter("fitness")) n_removed_per_iter =0 has_changed =Falsefor eso_item in eso_items:if (n_removed >= NRemove):breakif (n_removed_per_iter >= nremove_per_iter):breakif (eso_item.active ==False):continue eso_item.shell_elem.softKilled(True) eso_item.active =False n_removed +=1 n_removed_per_iter +=1 has_changed =Trueif (has_changed ==False):break model.febmodel.touch()# create active and inactive mesh for output active_mesh = Rh.Mesh() inactive_mesh = Rh.Mesh()for i inxrange(model.febmodel.numberOfNodes()): feb_pos = model.febmodel.node(i).pos() active_mesh.Vertices.Add(Rh.Point3d(feb_pos.x(), feb_pos.y(), feb_pos.z())) inactive_mesh.Vertices.Add(Rh.Point3d(feb_pos.x(), feb_pos.y(), feb_pos.z()))for eso_item in eso_items: ind0 = eso_item.shell_elem.node(0).ind() ind1 = eso_item.shell_elem.node(1).ind() ind2 = eso_item.shell_elem.node(2).ind()if (eso_item.active): active_mesh.Faces.AddFace(Rh.MeshFace(ind0, ind1, ind2))else: inactive_mesh.Faces.AddFace(Rh.MeshFace(ind0, ind1, ind2)) activeMesh = active_mesh 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.