Grasshopper: Calculate the Pareto front in multi-objective data in C#

A method for returning a collection of Pareto-optimal data. Pareto analysis is used in multi-objective optimisation to search for potential non-dominated solutions, i.e. solutions for which there are no solutions that perform better in every objective being assessed.

pareto-front

Input a collection of data. This data is accepted as Grasshopper’s DataTree format. The ‘tree’ contains a collection of branches. Each branch contains a list. Each list corresponds to the list of objective results corresponding to a single node.

The method sorts the input data into two DataTrees: Pareto-optimal branches and non-Pareto-optimal branches.

The algorithm is simple and unsophisticated, running in O(n2). It is fine for smaller data sets, though you may wish to investigate more sophisticated algorithms for larger datasets.

C# code to find the Pareto front

  private void RunScript(DataTree<double> data, ref object opt, ref object nonopt)
  {

    DataTree<double> optimal = new DataTree<double>();
    DataTree<double> nonoptimal = new DataTree<double>();

    //data should be a tree, where each branch is equivalent to one data point, and the length of the list is equal to the number of parameters.
    for(int n = 0; n < data.BranchCount; n++) //for each node
    {
      //check it against every other node
      //we need to find one node where every parameter is superior. if not, we have pareto optimality
      bool superiornodefound = false;
      for (int i = 0; i < data.BranchCount; i++) //check node i
      {
        bool issuperior = true;
        for(int p = 0; p < data.Branch(0).Count; p++)
        {
          if(data.Branch(i)[p] > data.Branch(n)[p])
          {
            issuperior = false;
            break;
          }
        }
        if(issuperior && i != n) superiornodefound = true;
      }
      if(superiornodefound) nonoptimal.AddRange(data.Branch(n), new GH_Path(nonoptimal.BranchCount));
      else optimal.AddRange(data.Branch(n), new GH_Path(optimal.BranchCount));
    }

    //return outputs
    opt = optimal;
    nonopt = nonoptimal;

    //grasshopper-related UI
    double optimalratio = Math.Round(100.0 * optimal.BranchCount / data.BranchCount, 1);
    Component.Message = optimalratio.ToString() + "% optimal";
    Component.Description = optimalratio.ToString() + "% of solutions are Pareto optimal.";

  }

Get a point between two points in Grasshopper with C#

How to get a point a certain ratio between two points in Grasshopper, using the C# component.

The method below allows you to return a point between two input points. Input two Point3d values and a number between 0 and 1.

‘Ratio’ is a value between 0 and 1. Enter 0 and the resultant point will be on top of frompt. Enter 1 and it will be on top of the topt. Enter something between, and the point will also be between. You can also enter a value that is !=[0,1] to extrapolate.

The easiest way to use the method is to paste it into the ‘additional code’ section of the C# component.

C# method

  private void RunScript(Point3d pt1, Point3d pt2, double t, ref object A)
  {

    A = MovePoint(pt1, pt2, t);

  }

  // <Custom additional code> 
  public Point3d MovePoint(Point3d frompt, Point3d topt, double ratio)
  {
    return new Point3d(ratio * (topt.X - frompt.X) + frompt.X, 
      ratio * (topt.Y - frompt.Y) + frompt.Y, 
      ratio * (topt.Z - frompt.Z) + frompt.Z);
  }
  // </Custom additional code> 

Grasshopper C# component points ratio

Points in Rhino viewport from Grasshopper

Read and edit persistent data in Grasshopper components with C#

A guide to accessing, reading and editing the persistent data property of Grasshopper components. This guide follows on from this post.

Every input of normal Grasshopper components has the ability to save persistent data. Persistent data is what you see when you right-click on a component and set the input’s value from there. The opposite, data fed into a component from another component, is called volatile data.

In this example, I will take the Circle CNR component. Using techniques borrowed from this post and this post, I am going to create a new CNR component using C#, then modify its persistent data.

circle CNR Grasshopper component

Add persistent data

Firstly, we need to add or reference the component for which we want to modify the persistent data.

Here, I am creating a new instance of Circle_CNR, which is contained within curve.gha.

    //Create the component
    var cs = new CurveComponents.Component_CircleCNR();

    //add the circle centre (input 0)
    var pp = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentGeometryParam<Grasshopper.Kernel.Types.GH_Point>;
    pp.PersistentData.ClearData();
    pp.PersistentData.Append(new GH_Point(new Point3d(0, 0, 0)));

    //add the circle radius
    var pn = cs.Params.Input[2] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Number>;
    pn.PersistentData.ClearData();
    pn.PersistentData.Append(new GH_Number(y)); //y is another variable

Read persistent data

Persistent data is saved as a GH_Structure. This is a tree-like data structure.

The ‘Append’ method above will add the data item to the final branch in the structure. Since we cleared the structure in the line before, there are no branches, so Grasshopper adds the data to a new branch.

So, in order to read our data, we need to access the list contained in branch 0.

    var readpt = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Point>;
    return readpt.PersistentData[0];

A full example

In the manner of this post, here I have a C# component that creates an instance of the CNR component hidden from the user on a dummy document. By modifying the CNR component’s input persistent data, we can modify the properties of the circle. The circle is calculated, and we read the output from the CNR component.

  private void RunScript(double y, ref object A)
  {

    //Create the component
    var cs = new CurveComponents.Component_CircleCNR();

    //add the circle centre (input 0)
    var pp = cs.Params.Input[0] as Grasshopper.Kernel.GH_PersistentGeometryParam<Grasshopper.Kernel.Types.GH_Point>;
    pp.PersistentData.ClearData();
    pp.PersistentData.Append(new GH_Point(new Point3d(0, 0, 3)));

    //add the circle radius (input 2)
    var pn = cs.Params.Input[2] as Grasshopper.Kernel.GH_PersistentParam<Grasshopper.Kernel.Types.GH_Number>;
    pn.PersistentData.ClearData();
    pn.PersistentData.Append(new GH_Number(y)); //y is another variable

    //run calculations
    cs.ExpireSolution(true);

    //add to a dummy document so we can read outputs
    var doc = new Grasshopper.Kernel.GH_Document();
    doc.AddObject(cs, false);

    //read output circle
    cs.Params.Output[0].CollectData();
    A = cs.Params.Output[0].VolatileData.get_Branch(0)[0];

    //remove that component
    doc.RemoveObject(cs.Attributes, false);

  }

circle CNR component C# Grasshopper

DDY Design Day weather file reader in Grasshopper C#

How to open a DDY (Design Day) file in Grasshopper.

Design day files are used for performing energy calculations in building design during represenative climatic extremes in summer and winter. Importing weather files into Grasshopper can be useful for energy analyses in Ladybug/Honeybee.

Download

Download the Grasshopper file here, which contains a C# component which you can run or edit. The code itself is pasted below, which could be used for any C# application.

You will also need your own DDY weather files. You can download them from here. Find the file you are interested in. Once you have downloaded the ZIP file, there should be a DDY file inside it.

C# code

  private void RunScript(string path, int y, ref object A)
  {

    int counter = 0;
    string ln;
    List<string> x = new List<string>();

    // Read the file
    System.IO.StreamReader f = new System.IO.StreamReader(path);
    while((ln = f.ReadLine()) != null)
    {
      x.Add(ln);
      counter++;
    }

    f.Close();



    var rtntree = new DataTree<String>();

    //strip comments
    for(int i = 0; i < x.Count; i++)
    {
      int ind = x[i].IndexOf('!');
      try{x[i] = x[i].Substring(0, ind);}catch{}
    }

    //reconstruct as one line
    string wholefile = "";
    foreach (string line in x) wholefile += line;

    //split into sections and fields
    List<List<string>> file = new List<List<string>>();

    string[] splitfile = wholefile.Split(';');
    foreach(string line in splitfile)
    {
      var section = new List<string>();

      string[] splitline = line.Split(',');
      foreach (string item in splitline)
      {
        section.Add(RemoveWhitespace(item));
      }
      file.Add(section);
    }

    //parse file
    var ddfile = new DDYFile();

    foreach (var s in file)
    {
      if(s[0] == "Site:Location")
      {
        ddfile.Site_Location.SiteName = s[1];
        ddfile.Site_Location.Latitude = Convert.ToDouble(s[2]);
        ddfile.Site_Location.Longitude = Convert.ToDouble(s[3]);
        ddfile.Site_Location.Gmt = Convert.ToDouble(s[4]);
        ddfile.Site_Location.Elevation = Convert.ToDouble(s[5]);
      }
      else if (s[0] == "SizingPeriod:DesignDay")
      {
        var dd = new DesignDay();
        dd.Name = s[1];
        dd.Month = TryToInt(s[2]);
        dd.DayOfMonth = TryToInt(s[3]);
        dd.DayType = s[4];
        dd.MaxTdb = TryToDouble(s[5]);
        dd.DailyTdbRange = TryToDouble(s[6]);
        dd.DailyTdbModifierType = s[7];
        dd.DailyTdbModifiedSchedule = s[8];
        dd.HumidityType = s[9];
        dd.TwbAtMaxTdb = TryToDouble(s[10]);
        dd.HumidityIndicatingDayScheduleName = s[11];
        dd.HumidityRatio = TryToDouble(s[12]);
        dd.Enthalpy = TryToDouble(s[13]);
        dd.DailyTwbRange = TryToDouble(s[14]);
        dd.BarometricPressure = TryToDouble(s[15]);
        dd.WindSpeed = TryToDouble(s[16]);
        dd.WindDirection = TryToDouble(s[17]);
        dd.Raining = TryToBool(s[18]);
        dd.Snowy = TryToBool(s[19]);
        dd.Dst = TryToBool(s[20]);
        dd.SolarModelIndicator = s[21];
        dd.BeamSolarDayScheduleName = s[22];
        dd.DiffuseSolarDayScheduleName = s[23];
        dd.OpticalDepthBeam = TryToDouble(s[24]);
        dd.OpticalDepthDiffuse = TryToDouble(s[25]);
        if(s.Count >= 27) dd.Clearness = TryToDouble(s[26]);

        ddfile.Design_Days.Add(dd);
      }
    }

    A = ddfile.Design_Days[y].ToListString();


  }

  // <Custom additional code> 

  public string RemoveWhitespace(string input)
  {
    return new string(input.ToCharArray()
      .Where(c => !Char.IsWhiteSpace(c))
      .ToArray());
  }

  public double TryToDouble(string input)
  {
    try
    {
      return Convert.ToDouble(input);
    }
    catch
    {
      return double.MinValue;
    }
  }

  public int TryToInt(string input)
  {
    try
    {
      return Convert.ToInt32(input);
    }
    catch
    {
      return Int32.MinValue;
    }
  }

  public bool TryToBool(string input)
  {
    try
    {
      return Convert.ToBoolean(input);
    }
    catch
    {
      return false; //should we always return false? or use a nullable type?
    }
  }

  public class DesignDay
  {
    public DesignDay(){}

    private string _name;
    private int _month;
    private int _dayOfMonth;
    private string _dayType;
    private double _maxTdb;
    private double _dailyTdbRange;
    private string _dailyTdbModifierType;
    private string _dailyTdbModifiedSchedule;
    private string _humidityType;
    private double _TwbAtMaxTdb;
    private string _humidityIndicatingDayScheduleName; //type unknown
    private double _humidityRatio;
    private double _enthalpy;
    private double _dailyTwbRange;
    private double _barometricPressure;
    private double _windSpeed;
    private double _windDirection;
    private bool _raining;
    private bool _snowy;
    private bool _dst; //daylight savings time
    private string _solarModelIndicator;
    private string _beamSolarDayScheduleName;
    private string _diffuseSolarDayScheduleName;
    private double _opticalDepthBeam;
    private double _opticalDepthDiffuse;
    private double _clearness;

    public string Name {get { return _name;} set {_name = value;}}
    public int Month { get { return _month; } set { _month = value;}}
    public int DayOfMonth{ get { return _dayOfMonth; } set { _dayOfMonth = value;}}
    public string DayType{ get { return _dayType; } set { _dayType = value;}}
    public double MaxTdb{ get { return _maxTdb; } set { _maxTdb = value;}}
    public double DailyTdbRange{ get { return _dailyTdbRange; } set { _dailyTdbRange = value;}}
    public string DailyTdbModifierType {get { return _dailyTdbModifierType;} set {_dailyTdbModifierType = value;}}
    public string DailyTdbModifiedSchedule{get { return _dailyTdbModifiedSchedule;} set {_dailyTdbModifiedSchedule = value;}}
    public string HumidityType{ get { return _humidityType; } set { _humidityType = value;}}
    public double TwbAtMaxTdb{get { return _TwbAtMaxTdb;} set {_TwbAtMaxTdb = value;}}
    public string HumidityIndicatingDayScheduleName{ get { return _humidityIndicatingDayScheduleName; } set { _humidityIndicatingDayScheduleName = value;}}
    public double HumidityRatio{ get { return _humidityRatio; } set { _humidityRatio = value;}}
    public double Enthalpy{ get { return _enthalpy; } set { _enthalpy = value;}}
    public double DailyTwbRange{ get { return _dailyTwbRange; } set { _dailyTwbRange = value;}}
    public double BarometricPressure{ get { return _barometricPressure; } set { _barometricPressure = value;}}
    public double WindSpeed{ get { return _windSpeed; } set { _windSpeed = value;}}
    public double WindDirection{ get { return _windDirection; } set { _windDirection = value;}}
    public bool Raining{ get { return _raining; } set { _raining = value;}}
    public bool Snowy{ get { return _snowy; } set { _snowy = value;}}
    public bool Dst{ get { return _dst; } set { _dst = value;}}
    public string SolarModelIndicator{ get { return _solarModelIndicator; } set { _solarModelIndicator = value;}}
    public string BeamSolarDayScheduleName{ get { return _beamSolarDayScheduleName; } set { _beamSolarDayScheduleName = value;}}
    public string DiffuseSolarDayScheduleName{ get { return _diffuseSolarDayScheduleName; } set { _diffuseSolarDayScheduleName = value;}}
    public double OpticalDepthBeam{ get { return _opticalDepthBeam; } set { _opticalDepthBeam = value;}}
    public double OpticalDepthDiffuse{ get { return _opticalDepthDiffuse; } set { _opticalDepthDiffuse = value;}}
    public double Clearness{ get { return _clearness; } set { _clearness = value;}}

    public override string ToString()
    {
      return "DesignDay item";
    }

    public List<string> ToListString()
    {
      var rtnlist = new List<string>();

      rtnlist.Add("Name: " + _name);
      rtnlist.Add("Month: " + _month.ToString());
      rtnlist.Add("DayOfMonth: " + _dayOfMonth.ToString());
      rtnlist.Add("DayType: " + _dayType.ToString());
      rtnlist.Add("MaxTdb: " + _maxTdb.ToString());
      rtnlist.Add("DailyTdbRange: " + _dailyTdbRange.ToString());
      rtnlist.Add("DailyTdbModifierType: " + _dailyTdbModifierType);
      rtnlist.Add("DailyTdbModifiedSchedule: " + _dailyTdbModifiedSchedule);
      rtnlist.Add("HumidityType: " + _humidityType);
      rtnlist.Add("TwbAtMaxTdb: " + _TwbAtMaxTdb.ToString());
      rtnlist.Add("HumidityIndicatingDayScheduleName: " + _humidityIndicatingDayScheduleName);
      rtnlist.Add("HumidityRatio: " + _humidityRatio.ToString());
      rtnlist.Add("Enthalpy: " + _enthalpy.ToString());
      rtnlist.Add("DailyTwbRange: " + _dailyTwbRange.ToString());
      rtnlist.Add("BarometricPressure: " + _barometricPressure.ToString());
      rtnlist.Add("WindSpeed: " + _windSpeed.ToString());
      rtnlist.Add("WindDirection: " + _windDirection.ToString());
      rtnlist.Add("Raining: " + _raining.ToString());
      rtnlist.Add("Snowy: " + _snowy.ToString());
      rtnlist.Add("Dst: " + _dst.ToString());
      rtnlist.Add("SolarModelIndicator: " + _solarModelIndicator);
      rtnlist.Add("BeamSolarDayScheduleName: " + _beamSolarDayScheduleName);
      rtnlist.Add("DiffuseSolarDayScheduleName: " + _diffuseSolarDayScheduleName);
      rtnlist.Add("OpticalDepthBeam: " + _opticalDepthBeam.ToString());
      rtnlist.Add("OpticalDepthDiffuse: " + _opticalDepthDiffuse.ToString());
      rtnlist.Add("Clearness: " + _clearness.ToString());
      return rtnlist;
    }
  }

  public class SiteLocation
  {
    public SiteLocation(){}

    private string _siteName;
    private double _latitude;
    private double _longitude;
    private double _gmt; //time zone
    private double _elevation;

    public string SiteName { get { return _siteName; } set { _siteName = value;}}
    public double Latitude { get { return _latitude; } set { _latitude = value;}}
    public double Longitude { get { return _longitude; } set { _longitude = value;}}
    public double Gmt { get { return _gmt; } set { _gmt = value;}}
    public double Elevation { get { return _elevation; } set { _elevation = value;}}

    public override string ToString()
    {
      return "SiteLocation " + _siteName;
    }
  }

  public class DDYFile
  {
    public DDYFile(){}

    private SiteLocation _siteLocation = new SiteLocation();
    private List<DesignDay> _designDays = new List<DesignDay>();

    public SiteLocation Site_Location { get { return _siteLocation; } set { _siteLocation = value;}}
    public List<DesignDay> Design_Days { get { return _designDays; } set { _designDays = value;}}

    public override string ToString()
    {
      return "DDY file for " + _siteLocation.SiteName + ", " + _designDays.Count.ToString() + " design days found";
    }
  }

  // </Custom additional code> 
}

Manually expire downstream components in Grasshopper with C#

How does component calculation in Grasshopper work, and how can we control how to expire downstream components in Grasshopper?

The calculation of a Grasshopper canvas is quite complicated. It has to be able to calculate which components need calculating, and the order it does it in.

How Grasshopper does calculations – usually

It does this through a system of ‘expired’ markers. If a component needs calculating, it is marked as ‘expired = true’. It then solves each component marked as expired, one at a time, until all expired components have been calculated. A calculated component can then have its ‘expired’ flag set to false.

A component will be marked as expired if any changes are made to it, for example, it receives a new value in one of its inputs. Furthermore, if a component is marked as expired, by default, every component downstream of this component will also be marked as expired.

This behaviour is quite reasonable in most cases in Grasshopper. It guarantees that all components will be up-to-date, and that each component’s output will be correct according to the latest input values happening upstream. It also ensures that components are not re-calcualted needlessly – only components that need calculating will be recalculated.

What if this behaviour isn’t what I want?

On a rare occasion, this method of component calculation is actually not helpful for us. This usually happens when we are trying to perform another task which is also not in the spirit of Grasshopper workflows.

I have recently been working on the BatchRun component to make it more usable in design workflows. This component remotely adjusts sliders on the canvas, allowing a form of iterative workflow not normally possible in Grasshopper.

One key feature I needed from BatchRun was that, for every movement of the slider, a new set of geometry would be generated in Grasshopper, and this requires a unique name. The most logical solution is to generate a name from the slider values. So I added a ‘name’ output:

Grasshopper component Batchrun for looping

When the user presses ‘startme’, BatchRun will automatically cycle through the sliders. Two sliders, each with 11 values, will produce 121 combinations of the two sliders. To be sure that the user wants to do this possibly time-consuming task, a message box appears:

Grasshopper message box for BatchRun component

If the user presses ‘yes’, and only when the user presses ‘yes’, Grasshopper should start to iterate through the sliders.

Why wouldn’t this normally work?

Notice that the component is initiated by a boolean button. The behaviour of the BatchRun component, explained fully here, dictates that BatchRun will then adjust the sliders. The intended action is that the sliders will then trigger the ‘building height’ and ‘building width’ params, which then will trigger the ‘doCalcs’. DoCalcs will pick up the name from the BatchRun ‘name’ output.

This normally works well. DoCalcs recognises that, when a slider has changed, both the slider values and the name have expired, and doCalcs will only function once both the sliders and the ‘name’ are up-to-date.

But what about, right at the beginning, when the user has pressed the button just to trigger the message box? The user may press ‘no’, in which case, we shouldn’t expect that any calculations have taken place. But watch what happens instead:

Expiration wave in Grasshopper with Batchrun component

Because the button is pressed, this instantly expires the BatchRun component. This is necessary – since it’s this expiration which causes BatchRun to wake up, calculate itself, and realise it needs to show a message box.

But – BatchRun itself also has outputs. Anything connected to these outputs will then be expired. So the panel becomes expired. And, in turn, doCalcs becomes expired.

Then, once this ‘expiration wave’ has come to a stop, Grasshopper then sets itself up with doing the calculations on these expired components. As a simplified rule, it starts with the left-most components and works right.

The trouble is that, even when a component’s inputs’ data has not changed, if that component has been marked as ‘expired’, it still feels the need to recalculate itself. So, the simple act of pressing the button will compel doCalcs to recalculate – even if the user then selects ‘no’ on the messagebox that is triggered.

What’s the solution?

Ideally, we want BatchRun to be expired whenever the startme button is pressed. This is of course important – since it’s expiration which triggers BatchRun to do calculations on itself.

But, we want control on when BatchRun expires downstream objects. Can we use some logic to control whether or not BatchRun will send an expiration to downstream objects?

To try this out, I will be working on a component developed in Visual Studio. As far as I know, these techniques aren’t possible directly in the C# component in Grasshopper. You can set yourself up for developing components in VS here.

How not to expire downstream objects

My first idea was to try and find a component property called ‘Expired’ or something like it. But that failed – there’s nothing there!

Grasshopper Visual Studio expire component Intellisense

There are plenty of methods to force a component to expire and recalculate, but nothing to cancel it.

But there must be some other way of controlling the expiration wave, right?

How not to expire downstream objects, v2

When developing Grasshopper components in Visual Studio, you have access to a wide range of override methods. Override methods control various behaviours of our component class. If we don’t implement an override, these methods work in the background and implement default behaviour. By implementing an override, we can override this default behaviour. To view which overrides are possible, simply type ‘override’ in your component class, and IntelliSense should show you a drop-down.

Grasshopper visual studio override methods in C#

We can then select the method for which we want to change the default behaviour, for example:

Grasshopper visual studio override AddedToDocument

The ‘base’ part is added automatically when we select the override from IntelliSense. The ‘base’ calls the default behaviour of that method.

We can add extra code beneath or above ‘base’. This code will be called in addition to the ‘base’ code. We can also remove the ‘base’ line, which effectively removes the default behaviour alltogether.

Having a dig through the various overrides reveals one called ExpireDownStreamObjects(). Perfect – this is the one! What I can do is remove the base from this override, so Grasshopper will no longer expire downstream objects. Then, I can use the methods above to manually expire the components that I want, when I want, during the solution.

So, I simply comment out the base, and add a few lines into my SolveInstance. This extra code finds the components I want to expire at strategic times, and asks them to expire and recalculate.

            if (expire_downstream)
            {
                foreach (var receiver in Component.Params.Output[1].Recipients)
                {
                    receiver.ExpireSolution(true);
                }
            }

(Note: I have defined ‘Component’ to be the same as writing ‘this’.)

This does actually work in principle. But, for reasons I can only guess, Grasshopper prohibits expiring components during the solution, at least in certain cases. The result is an error message, below, saying that “an object expired during a solution”. This message can be cancelled, and the component will then work as designed, but this still presents a poor user experience.

Grasshopper object expired during solution error message

What you SHOULD do

The solution is to bring out the logic from the ‘solveInstance’ method. The best way to do this is to be slightly more sophisticated in our ExpireDownstreamObjects override.

One way to do this is to add a conditional to the ‘base’.

        protected override void ExpireDownStreamObjects()
        {
            if (_run || _running)
            {
                base.ExpireDownStreamObjects();
            }
        }

The above method now only allows downstream objects to be expired if the class variables _run or _running are set to true. If they’re both false, nothing will happen. Grasshopper is now much happier – no error messages, and objects are being expired as we designed them to be.

Another option is, instead of using base, we can manually expire any component we want here:

        protected override void ExpireDownStreamObjects()
        {
            if (_run || _running)
            {
                this.Params.Output[1].Recipients[0].ExpireSolution(false);
            }
        }

The above code will now only expire the first connected component to the second output, and only if either _run or _running are true.

Grasshopper component controlling expired status

So in the image above, if BatchRun is not set to _run or _running, then pressing the button will not expire the panel. This is because the component has been repressed from transmitting an ‘expire’ command to the panel. Consequently, the doCalcs component will not recalculate – which was the intended behaviour.

You should be implementing Esc behaviour in your Grasshopper development

All Grasshopper users know the pain that comes with accidentally setting off an enormous calculation, and realising we’ve done something wrong and need to cancel it.

Since Grasshopper is tied on to the Rhino process in Windows, and the whole thing is single threaded, it is very difficult programatically to allow users to cancel a calculation part-way through. Part of the reason is that the UI and the calculations share that same thread. When heavy calculations are running, there are basically no cycles spare to handle a ‘cancel’ button.

Rutten has implemented a workaround, however. By button-mashing the Esc key during calculations, some components can listen for this key and issue an ‘abort request’. This system isn’t perfect, but it has on numerous occasions saved me from needing me to completely kill and restart Rhino.

This functionality doesn’t happen automatically. The Esc key check only happens when specified within your code, so if you never check if the Esc key is down, it is impossible for the user to abort the solution whilst Grasshopper is churning through your component. We need to implement this functionality manually.

For many lightweight components, this isn’t critical. But if your component takes a long time to calculate, it’s more likely that the user will want to abort the solution while Grasshopper is calculating yours – since Grasshopper processes each component during calculation one at a time.

How to implement Esc behaviour

Grasshopper includes some useful methods to provide the behaviour we need. How it works is that, every once in a while, we check if the escape key is down as part of our calculations. If it is down, the user wants to cancel calculations. So we submit a cancel request to Grasshopper. It is then up to Grasshopper to act upon this request.

For a compiled component, we can implement the code within SolveInstance(), or within another calculation-heavy part of your code.

The following code is in C#:

                    if (GH_Document.IsEscapeKeyDown())
                    {
                        GH_Document GHDocument = OnPingDocument();
                        GHDocument.RequestAbortSolution();
                    }

A good place to put this code is within a loop within your component. Don’t call IsEscapeKeyDown() too often though, as it requires processing power to handle this method, which will slow down your component.

Since the GH_Document is likely constant for the life of the component instance, you could pull this out and calculate it in the constructor* at the top of your SolveInstance() – since it’s a useful variable elsewhere anyway.

References

http://www.grasshopper3d.com/forum/topics/acknowledging-abort-request
And for a rather interesting comment thread… http://www.grasshopper3d.com/forum/topics/emergency-top-for-solution-calculation

Append menu items to Grasshopper components with C#

How to add items to the right-click menu in Grasshopper.

This example shows how we can add a text item to the right-click menu, and change a field within the class of our Grasshopper component.

Custom menu item in right click menu in Grasshopper

The code to do this is written for compiled C# components written in an environment such as Visual Studio. Add these methods to your component class.

        protected override void AppendAdditionalComponentMenuItems(System.Windows.Forms.ToolStripDropDown menu)
        {
            base.AppendAdditionalComponentMenuItems(menu);
            Menu_AppendItem(menu, "Flip myBool", Menu_DoClick);
        }

        private void Menu_DoClick(object sender, EventArgs e)
        {
            myBool = !myBool;
        }
        public bool myBool = false; 

This creates the menu item called ‘Flip myBool’ when we right-click the component. When we click on the menu item, it calls the Menu_DoClick method. We can define any method (with any name) that we want here.

References

http://www.grasshopper3d.com/forum/topics/set-input-parameter-from-a-pop-up-menu-vb

Remove the text below Grasshopper components

The text that appears below some components in Grasshopper – called messages – often adds some useful information about that component.

Grasshopper message text bounding box component

But sometimes – especially if you want to create a nice, simplified image of your Grasshopper component – you want to remove these messages.

There appears to be no easy way to remove these messages in the Grasshopper user interface, but with a bit of C# we can hack together our own solution.

Using a similar idea to the way that we can expire any component that we want, we can also manually control the properties of any component on the canvas.

C# code

Create a new C# component in Grasshopper, and create a boolean input called no_message. Then paste the following code:

  private void RunScript(bool no_message)
  {

    //for each component on the canvas
    foreach (IGH_DocumentObject obj in GrasshopperDocument.Objects)
    {
      try {
        if(no_message)
        {
          Grasshopper.Kernel.GH_Component thisobj = obj as Grasshopper.Kernel.GH_Component;
          thisobj.Message = "";
        }
      }
      catch{}
    }
  }

The trick is that we have to cast each object that we find on the canvas to a GH_Component. This exposes the Message property. Then, simply setting the Message to blank text is enough to make the message go away.

We use a try-catch because some components do not inherit from GH_Component, and so fail when we try to modify the message. (An alternative method would be to only try to modify the message if the cast object != null.)

And the result? Perfect.

Grasshopper message text bounding box component

Some pointless fun with C# and the Grasshopper timer

I made a thing, and it ripples!

It could be sound in an auditorium. It could be waves in water. It could be energy dissipating from an earthquake’s epicentre. But that’s not the point.

What it is is a great demonstration on what you can make with the Grasshopper timer, and bit of C#, and 15 minutes to kill.

In the C# component, there are two regions you can edit: the RunScript section, and the ‘additional code’ section. Data stored in RunScript is volatile – it gets deleted every time the component is run. But data stored in the second region is preserved.

By running a timer on our component, it will be executed repeatedly. We can use this second region to hold information between these executions, allowing us to build up complex and dynamic behaviour in Grasshopper.

Grasshopper component C# timer example

The code within the C# component handles each ‘frame’ of the animation. It maintains the current time (increasing by 1 for each cycle) and uses this time to decide what colour each part of the mesh will be.

  private void RunScript(bool _clap, bool _reset, Mesh _mesh, ref object A)
  {
    
    thetime++;

    //button actions
    if(_clap)
    {
      times.Add(thetime);
    }
    if(_reset)
    {
      times.Clear();
      thetime = 0;
      CalcDistances(_mesh, new Point3d(0, 0, 0));
    }

    //maintain list size to maintain performance
    if(times.Count > 50) times.RemoveAt(0);

    //calculate mesh colours
    _mesh.VertexColors.Clear();
    int i = 0;
    foreach(var v in _mesh.Vertices)
    {
      bool shouldbegreen = false;
      foreach(var time in times)
      {
        if(thetime == (time + (int) (distances[i])))
        {
          shouldbegreen = true;
        }
      }
      if(shouldbegreen)
      {
        _mesh.VertexColors.Add(Color.Green);
        _mesh.Vertices.SetVertex(i, _mesh.Vertices[i].X, _mesh.Vertices[i].Y, 1);
      }
      else
      {
        _mesh.VertexColors.Add(Color.Red);
        _mesh.Vertices.SetVertex(i, _mesh.Vertices[i].X, _mesh.Vertices[i].Y, 0);
      }
      i++;
    }

    //output
    A = _mesh;
  }

  // <Custom additional code> 

  int thetime = 0;
  List<int> times = new List<int>();
  List<double> distances = new List<double>();
  
  //preprocessed here to speed up calculation
  public void CalcDistances(Mesh msh, Point3d pt)
  {
    distances.Clear();
    foreach (var v in msh.Vertices)
    {
      distances.Add(pt.DistanceTo(v));
    }
  }

A kernel density estimation implementation for Grasshopper

Kernel density estimation is a way of generating a smoothed function of density of a collection of data.

Randal Olson used Kernel density estimation to perform a statistical likelihood on the location of Waldo in the Where’s Waldo (Where’s Wally) books. Perhaps surprisingly, this didn’t reveal a random distribution, but showed that Waldo was more likely to appear in certain areas of the page.

The mathematics of kernel density estimation are closely linked to kernel smoothing, which I use a lot for my interpolation development. And since pretty much everything I do is in Grasshopper, I wanted to see if I could quickly implement KDE and make a few pretty pictures.

Output

Here, we can input and move a collection of points. In regions with high point density, the colour becomes more red.

And of course, making the most of the parametric capability of Grasshopper, we can move the points and get an updated Kernel Density Estimation in real time.

Grasshopper script

Kernel density estimation Grasshopper Rhino script

We input a mesh (or a Brep to convert to a mesh), which will provide our analysis surface for colouring later. We also input a list of data points.

A bit of C# then calculates the ‘score’ for each mesh point – or an estimation for the density over that mesh point. This returns a list of numbers. We can then colour the mesh according to these values.

The C# script – the ‘density’ component – contains the following code:

  private void RunScript(List<Point3d> pts, Mesh mesh, ref object A)
  {

    var rtnlist = new List<double>();

    foreach(var v in mesh.Vertices)
    {
      double tempval = 0;
      foreach (var pt in pts)
      {
        tempval += kernel(pt.DistanceTo(v), 0.2); //0.2 is a smoothing value - you can change this 
      }
      rtnlist.Add(tempval);
    }

    A = rtnlist;
  }

  // <Custom additional code> 

  public double kernel(double input, double factor)
  {
    return Math.Exp(-(factor * input));
  }

Gravity wells

The kernel density estimation can sometimes be thought of as a smoothed histogram. Another way to visualise regions of high density is to take advantage of the Z component and give our mesh some height.

To do this, I reconstructed each mesh point using the vertex score as an input for the mesh point Z component. So that the input mesh points are still easily visible, I multiplied these scores by -1. This gave a visualisation quite akin to a collection of gravity wells, the points perhaps being tiny planets floating in a 2D space.

The mesh can be modified by deconstructing the mesh and then deconstructing the points within this mesh. We then supply a modified Z value, then re-construct the mesh.

Kernel density estimation Grasshopper