2.4.2: Activation and Deactivation of Elements

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 fig. 2.4.2.1). 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.

...
using Karamba.Models;
using Karamba.GHopper.Models;
using Karamba.Loads.Combinations;
...
private void RunScript(object Model_in, int maxiter, ref object Model_out, ref object isActive, ref object maxDisp)
{
  var model = Model_in as Model;
  if (model == null) {
    throw new ArgumentException("The input in 'Model_in' is not of type karamba.Models.Model!");
  }

  // load case to consider for elimination of elements
  int lc_num = 0;

  // clone the model and its list of elements to avoid side effects
  model = model.Clone();
  // clone its elements to avoid side effects
  model.cloneElements();
  // clone the feb-model to avoid side effects
  model.deepCloneFEModel();

  string singular_system_msg = "The stiffness matrix of the system is singular.";

  // do the iteration and remove elements with tensile axial forces
  for (int iter = 0; iter < maxiter; iter++) {

    // create a deform and response object for calculating and retrieving results
    feb.Deform deform = new feb.Deform(model.febmodel);
    feb.Response response = new feb.Response(deform);

    try
    {
      // calculate the displacements
      response.updateNodalDisplacements();
      // calculate the member forces
      response.updateMemberForces();
    }
    catch
    {
      // send an error message in case something went wrong
      throw new Exception(singular_system_msg);
    }

    // check the normal force of each element and deactivate those under tension
    double N, V, M;
    bool has_changed = false;
    foreach (Karamba.Elements.ModelElement elem in model.elems) {
      // retrieve resultant cross section forces
      elem.resultantCroSecForces(model,  new LCSuperPosition(lc_num, model), 
        out N, out V, out M);
      // check whether normal force is tensile
      if (N >= 0) {
        // set element inactive
        elem.set_is_active(model, false);
        has_changed = true;
      }
    }

    // leave iteration loop if nothing changed
    if (!has_changed) break;

    // if something changed inform the feb-model about it (otherwise it won't recalculate)
    model.febmodel.touch();

    // this guards the objects from being freed prematurely
    GC.KeepAlive(deform);
    GC.KeepAlive(response);
  }

  // update model to its final state
  try
  {
    // create a deform and response object for calculating and retrieving results
    feb.Deform deform = new feb.Deform(model.febmodel);
    feb.Response response = new feb.Response(deform);

    // calculate the displacements
    response.updateNodalDisplacements();
    // calculate the member forces
    response.updateMemberForces();

    maxDisp = response.maxDisplacement();

    // this guards the objects from being freed prematurely
    GC.KeepAlive(deform);
    GC.KeepAlive(response);
  }
  catch
  {
    // send an error message in case something went wrong
    throw new Exception(singular_system_msg);
  }

  // set up list of true/false values that corresponds to the elemment states
  List<bool> elem_activity = new List<bool>();
  foreach (var elem in model.elems) {
    elem_activity.Add(elem.IsActive);
  }

  isActive = elem_activity;
  Model_out = new GH_Model(model);

  Print("Everything OK");
}

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 13. In order to avoid side-effects, the data needs to be copied before any modifications take place. Line 16 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 18. The same is true for the C++-model which gets cloned in line 20.

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 28 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 29. 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 34 and 36 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 47 to 56 the algorithm iterates over all elements in the system, reads out their resultant section forces and sets all members inactive that are under tension (N0). 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 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 59) 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 84 and 85 make sure that the automatic garbage collection in C# does not prematurely free the “deform” and “response” objects. As “deform” is internally referenced 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 94 to 97). In line 99 this list is handed over to the output variable. Line 100 puts a GH_Model wrapper object around the model-object that contains the final results.

In line 81 the response object is queried for the maximum deflection in the model. Its value is then handed over to the “maxDisp” output variable.

Last updated