Grasshopper (.ghx) Optimization
This section walks through running an optimization directly from a Grasshopper definition file (.ghx).
Tunny Dashboard supports not only analyzing optimization results but also running the optimization itself. Take a Grasshopper definition whose variables and objectives are wired into the Tunny component — one already set up so that Tunny itself could run the optimization — save it as .ghx, and drop it onto the Dashboard: the Dashboard proposes variable values with its sampler and drives an optimization loop that evaluates one trial at a time through Rhino.Compute. No Python or Optuna installation is required to run it. Results are written out as an Optuna-compatible journal file, so live updates and every analysis widget work exactly as they do for any other Study.
The overall flow looks like this:
- Wire the variables and objectives into the Tunny component and save the optimization-ready definition in .ghx format
- Set up Rhino.Compute
- Drop the .ghx onto the Dashboard and configure the optimization in the setup modal
- Run the optimization and watch results arrive via live updates
Requirements
Evaluating a Grasshopper definition requires Rhino.Compute. Rhino.Compute is a server that exposes Rhino's functionality over HTTP, and it is expected to run on Windows. Because the Dashboard loads the definition and drives the optimization loop itself, the machine running the Dashboard does not need Rhino installed.
The easiest way to get Rhino.Compute is to install Hops from Grasshopper's package manager. The Rhino.Compute executable set is installed alongside Hops and placed at the following path:
%AppData%\McNeel\Rhinoceros\packages\<Rhino version>\Hops\<Hops version>\rhino.compute\rhino.compute.exeWith the Launch EXE method described below, you can point to this path directly.
You can connect to Rhino.Compute in one of two ways:
- Launch EXE: point to the path of rhino.compute.exe, and the Dashboard starts and stops it for you at run time
- Server URL: connect to a Rhino.Compute instance that is already running
(default
http://localhost:6500)
If you choose Launch EXE, the Dashboard starts Rhino.Compute on the specified port (default 6500) and waits up to 180 seconds for it to respond before starting the optimization. When the optimization finishes, the Dashboard automatically stops the Rhino.Compute instance it launched.
This pipeline has been verified with Rhino.Compute from Rhino 8.31, Hops 0.17, and .ghx files saved from Grasshopper 1.0.
How the Grasshopper definition is recognized
The Dashboard reads the .ghx XML directly and extracts the optimization problem from the wiring into the Tunny component. Any component whose name or nickname contains "tunny" is detected as a Tunny component, and each of its inputs is interpreted as follows:
| Input | What is recognized |
|---|---|
| Variables | Number Sliders (one slider = one variable) and Gene Pools (one gene = one variable) |
| Objectives | Wired parameters (the NickName becomes the objective name) |
| Attributes | Constraint and Attribute inputs wired through a Construct Fish Attribute component |
In other words, if you have already set up Tunny optimization on the Grasshopper side in the usual way, it can be run as-is with no special naming conventions or extra components. Conversely, merely placing a Tunny component on the canvas is not enough: a definition with no Number Slider (or Gene Pool) wired into the Variables input, or no parameter wired into the Objectives input, fails with an error when dropped. Before dropping the .ghx, make sure it is in a state where Tunny itself could start the optimization in Grasshopper.
Variable ranges and precision come from the Number Slider settings (Min / Max / Digits), and a slider with Digits set to 0 is treated as an integer variable.
Constraints follow the same soft-constraint convention as Tunny: a trial is considered feasible when every constraint value is 0 or less. Trials that violate a constraint are still evaluated and recorded, and the amount of violation is used to steer NSGA-II's search toward the feasible region. Values wired into the Attribute input are recorded as per-trial user attributes and can be inspected with the widgets that display user attributes.
One caveat: whether an objective is minimized or maximized cannot be read from the .ghx file. The direction setting inside the Tunny component has no stable serialization format, so the Dashboard initially shows every objective as Minimize and leaves editing that up to the setup modal. If any objective should be maximized, be sure to change its direction before running.
Setup modal
Drag and drop a .ghx file onto the window, or select one from the Open dialog, and the "Grasshopper Optimization" modal opens. The modal shows the problem that was extracted and lets you configure:
- Objectives: choose Minimize / Maximize for each objective
- Rhino.Compute: connection method (Launch EXE / Server URL), port, API key, and parallelism (Max parallel, 1-16, default 4)
- Sampler: sampler type and its settings, and the random seed (default 42)
- Output: where to save the journal file and the Study name
The lists of variables, constraints, and attributes are read-only. If anything looks wrong, fix the definition on the Grasshopper side and save it again. Any element that had a problem during extraction is shown as a warning near the top of the modal.
If you enter an API key, it is sent as the RhinoComputeKey header on requests.
Leave it blank if you are connecting to a Rhino.Compute instance that has no
authentication configured.
By default, the journal is saved as <file name>_optuna.log in the same folder
as the .ghx file, and the Study name is generated from the file name and the
time the run started.
Choosing a sampler
The Method field in the Sampler section offers three choices:
| Sampler | Settings | Best suited for |
|---|---|---|
| NSGA-II (default) | Population (default 16), Generations (default 10) | Single- or multi-objective problems in general, constrained problems |
| Random | Trials (default 50) | Getting a baseline, surveying the search space |
| Adaptive (surrogate) | Initial trials, batch size, number of iterations, early stopping | Expensive evaluations where you want to limit the number of runs |
Choosing NSGA-II shows "Total evaluations", computed from Population and Generations. Multiplying that by the time each evaluation takes gives you a rough estimate of the total run time before you start.
Adaptive (surrogate) is what is generally called adaptive sampling, or Bayesian optimization. It first evaluates an initial batch of trials (at least 10) with random sampling, then automatically selects and fits a surrogate model for each objective from those results. After that, it evaluates the candidates proposed by an acquisition function (EI for single objectives, EHVI for multiple objectives) in batches and repeats the fit-and-propose cycle, concentrating the search on promising regions while using far fewer evaluations. Enabling "Stop early on convergence" makes the run stop automatically, even if iterations remain, once the improvement in the indicator falls below a specified rate for several iterations in a row.
Running and checking results
Pressing Run closes the modal and shows a progress overlay in the bottom-right corner of the screen. The Study is created in the journal as soon as the run starts and live updates are enabled automatically, so results flow into the dashboard as each trial completes. Placing widgets such as Optimization History or Pareto Scatter lets you watch the optimization progress in real time.
You can cancel the run in progress from the Cancel button on the progress overlay. The cancellation takes effect after the in-flight Rhino.Compute call finishes, and cancelled trials are not recorded in the journal. When the run finishes, the overlay shows the number of successful and failed trials.
For how to proceed with analysis after a run, see the analysis workflow.
Checking the definition sent to Rhino.Compute
At run time, the Dashboard generates a copy of the definition with variable
injection points (RH_IN) and result extraction points (RH_OUT) built in, and
saves it alongside the journal as <journal name>.compute.ghx. This is the file
that Rhino.Compute actually evaluates, so if you get unexpected results, you can
open this file in Grasshopper to check the wiring.
Note that Gene Pool does not support having values injected from Rhino.Compute,
so it is internally replaced with a regular Number parameter. When you open the
.compute.ghx file you will see the Gene Pool replaced by a different parameter
— this is expected behavior.
Caveats
- Binary .gh files are not supported: use "Save As" in Grasshopper and choose the .ghx (Grasshopper XML) format instead. Dropping a .gh file shows a guidance message
- A single trial times out after 300 seconds: evaluations that exceed this are recorded as failures
- A non-numeric evaluation value fails: trials whose output is empty, NaN, or infinite are recorded as failures, and the optimization continues
- Duplicate names are renamed automatically: if a variable, objective,
constraint, or attribute name is duplicated, a suffix such as
_2or_3is appended - Port conflicts: if Rhino.Compute exits immediately after Launch EXE starts it, check whether the specified port is already in use or whether the executable path is correct
- Load under parallel execution: raising Max parallel speeds up evaluation but also increases memory and CPU load on the Rhino.Compute side
Summary
This section covered optimizing a Grasshopper definition using a .ghx file.
- Just drop it in to run: the standard Tunny setup is recognized as-is, with no extra work needed
- Runs through Rhino.Compute: no Rhino or Python needed on the Dashboard side
- Results are an Optuna-compatible journal: live updates and every analysis widget are available while the optimization runs
- Three samplers to choose from: NSGA-II, Random, and Adaptive (surrogate), depending on the problem
Being able to move between running an optimization and analyzing its results within a single application lets you shorten the cycle of "run, analyze, and design the next optimization." For optimizing external tools that don't use Grasshopper with the same mechanism, see external tool optimization.