Generating designs
This tutorial provides a step-by-step guide for generating designs using the Generative Platform. It uses design of a cantilever as an example. The inputs will be the cantilever’s dimensions, the material it is made from and the load applied. The outputs will be its deflection under this load, approximate construction cost and a 3D model.
Final outcome of the tutorial.
You can also see the code defining the Generative Function and the finished project in the app.
Setup
Prerequisites: Python + an IDE (a code editor)
Optionally, to more easily manage Python packages, you’ll need a Python package manager.
See the Setup page if you’re missing any of these.
Initialising a code repository
To create and run a Generative Function you need somewhere to store and run the code. This is simply a folder anywhere on your computer that has access to Python.
Create an empty folder
If you are using an IDE (code editor), you can probably do this step there.
We recommend you do not create a venv, which some IDEs will do by default when making a new project, unless you’re already comfortable with virtual environments.
If you want to manage different Python packages per repository, we recommend you use a package manager - see the ‘Advanced’ track in the Setup guide for how to set one up.
Install the Generative packages
Install Generative packages generative-core
and generative-server
from pypi.generative.vision.
Open a terminal window, navigate to the folder you created, and run:
If this is successful, the version of generative.server
will be printed.
If you’re not using a virtual environment (venv), this installs Generative packages globally - so you’d only need to do this once per machine. If you are using a venv then you will need to install generative server inside the venv.
Create an empty folder
If you are using an IDE (code editor), you can probably do this step there.
We recommend you do not create a venv, which some IDEs will do by default when making a new project, unless you’re already comfortable with virtual environments.
If you want to manage different Python packages per repository, we recommend you use a package manager - see the ‘Advanced’ track in the Setup guide for how to set one up.
Install the Generative packages
Install Generative packages generative-core
and generative-server
from pypi.generative.vision.
Open a terminal window, navigate to the folder you created, and run:
If this is successful, the version of generative.server
will be printed.
If you’re not using a virtual environment (venv), this installs Generative packages globally - so you’d only need to do this once per machine. If you are using a venv then you will need to install generative server inside the venv.
This initialisation method assumes you have a Python package manager set up - see the ‘Advanced’ track in the Setup guide for how to set one up.
The steps given are for UV or Poetry, but will be similar for whichever package manager you’re using.
Create an empty folder
If you are using an IDE (code editor), you can probably manage this step there.
Initialise package manager
In the same folder, run:
Follow the instructions to initialise an empty repository.
Add the Generative packages
Run the following to install the generative-core
and generative-server
Python packages as dependencies:
Installing other dependencies
This tutorial uses Python packages trimesh, shapely and triangle to create a 3D model of the cantilever. Install them by running in your terminal:
Writing the Generative Function
In this section, the Generative Function will be defined in Python code.
You can see the complete code which we’ll build up through this section.
Defining input and output Generative types
Generative Types are Python classes subclassing GenerativeType
, which is imported from generative.core
.
They let you structure your data with clearly defined fields, types and validation.
Below, several Generative Types are defined that describe both the inputs and outputs for our cantilever example.
Create a Python file in your folder. We’ll call the file cantilever.py
, but it can be anything you like.
Copy the below code to that file.
CantileverGeometricProperties
groups together all geometry-related fields (length, depth, width, wall thickness).
PointLoadScenario
includes the load magnitude and where it’s applied along the beam.
CantileverInputs
collects these together, along with a material_idx to decide which material to use.
Outputs of cost, structural response and a 3D model are combined into more Generative Types.
An Asset type is used for the model
field.
This allows non-numeric data to be passed to the app, for example images, videos, or 3D geometry.
Setting defaults and bounds
Default values and bounds are set for inputs using Pydantic’s Field
- you’ll see later how the app treats these, or you can learn more in the concepts section.
For example:
length_m: float = Field(default=1, gt=0)
means that the value forlength_m
must be greater than 0, and has a default value of 1force_location_proportion: float = Field(default=1, ge=0, le=1)
means thatforce_location_proportion
must be between 0 and 1 (inclusive) and has a default value of 1.
Generative Function definition
With the Generative Types defined, it’s now possible to write a Generative Function using the @generative_function
decorator, which is imported from generative.core
.
Add the function below to your Python file.
It takes the CantileverInputs
Generative Type we defined earlier as its input,
and returns the CantileverOutputs
Generative Type.
Internally it uses other normal Python functions for validation and calculations.
We’ll define these in the following sections.
The generative function has been called cantilever
, which is the name that will appear in the app.
Each field of CantileverInputs
can be accessed in the function,
for example inputs.material_idx
gives the integer value input for the material index.
On the last line, an instance of CantileverOutputs
is created by passing in all its fields by keyword,
and this instance is then returned.
Validating the input data
The function validate_inputs()
is called at the start of the generative function.
This raises an Exception if it finds any non-physical characteristics in the inputs.
Copy the code below into your Python file.
Any Exceptions raised during the evaluation of a Generative Function will be caught and logged, and the app will show a failed design which has inputs but no outputs.
Creating an Asset
The 3D model of the cantilever must be an Asset
so that can be viewed in the app.
The cantilever_3d_model
function that constructs the 3D model is defined below.
Add it to your Python file.
This function is called from the cantilever
Generative Function defined above,
and creates an Asset from a GLB file (which is a universal mesh file format).
Most of the function is creating a mesh of the cantilever using the Python packages Trimesh, Shapely and Triangle.
Other geometry creating packages could be used instead. For example you could use the Python package CadQuery or connect to a traditional CAD package. Get in touch if you need any help doing this.
The highlighted lines at the end of the function create the Asset.
FileAsset
(from generative.core
) is used because our 3D model is a file, rather than a digital asset at a URL.
First a FileAsset
instance is created - asset = FileAsset()
- which makes an empty temporary file.
Then the path of the asset is converted to a string and passed to Trimesh’s normal export function.
FileAsset
is a type of Asset
, so the return type of the function should still be Asset
.
Learn more in the concepts section.
Getting material data from the material index
The material index is an integer input to the Generative Function. When defining the Generative Types it was defined to have a value between 0 and 1.
This index is used to get relevant material data from a table, defined in Python as a dictionary. Another Generative Type is used to store the data associated with each material, though a dataclass or dictionary could also be used. Add this to your Python file.
Filling in the rest
The rest of the functions used in the cantilever
Generative Function are defined below.
They calculate the deflection and slope of the cantilever using standard formulas
and produce a rough estimate of the cantilever cost for demonstration purposes.
Copy these functions into your Python file.
That's all the coding done!
You can see the complete Generative Function here.
Connecting to the app
Great! Now you have finished writing a Generative Function, the next step is to connect to the app to start generating designs.
Start up a local function server
Run the following command from a terminal at the root of your repository or in the folder your Generative Function is in:
When you make changes to your function, manually stop the server (e.g. Ctrl-C in Powershell) and run the above command again.
If you want the server to automatically restart when you make changes to your function, you can remove the --no-reload
option or use --reload
,
but on Windows this is known to not work as expected so we recommend using --no-reload
.
To learn more, see the concepts section.
Login to the app
Account is required to proceed. If you haven’t already, sign up at generative.vision.
Open app
Create an empty project
Create and navigate to an empty project. Under the ‘Experiment’ tab, your local function server will be automatically detected if it’s running on port 3000.
If your function server is not detected, check the logs in your terminal where you’re running the server. If the server started correctly, you should see a link, which will take you the server’s API docs page.
Generating designs
You should now have a project open in the app connected to your Generative Function on the Experiment page.
If you haven’t got the Generative Function running on a Function Server, you can go to the app and open a copy of the tutorial project ''.
From here you can use the Generative Function running in our cloud to continue with the rest of the tutorial.
Add parameters to control
Add some parameters to the Experiment by clicking Add parameters
and selecting the ones you want.
Add depth, width, length, wall thickness, force and material index, and then close the selector box by clicking outside of it.
Any inputs not selected here will be kept constant, at their default value set in the Python code.
Set values for the parameters
You’ll now see the input parameters you selected on the left hand side of the screen.
We haven’t added any output parameters for this tutorial as we’re only interested in generating designs. The outputs will still be calculated, but no optimisation (like trying to minimise or maximise different outputs) will take place.
Set the following for the input parameters:
- Length to exactly 1
- Force to exactly 100
- Depth to range from 0.2 to 0.5
- Width to range from 0.2 to 0.5
- Wall thickness to range from 0.02 to 0.1
- Material index to range from 0 to 1
Ranges are inclusive, so setting a range from 0 - 1 means .
The Experiment is now set up and the Generate button should be activated
The Experiment is now set up and the Generate button is activated
Click Generate
Press Generate and watch designs being generated!
If you left the settings at default, 100 designs will be generated at random in the specified input ranges.
Failed designs
With our inputs, a few of the designs might fail the validation we wrote - the wall thickness is more than twice the width or depth. If this happens these designs appear with warning triangles showing that they failed to generate outputs.
Viewing results
Compare all
Click ‘Compare All’ to navigate to the Compare page and see a tabular view of all the designs you’ve just generated.
Compare all results from an Experiment
Any designs which failed validation show values for their inputs, but no values are shown for their output parameters because an Exception was raised before the Generative Function returned.
If you click the Add
button and add parameter force_location_proportion
,
you’ll can see that it’s always equal to 1
(the default value we set in the Python code)
because it wasn’t given a different value or range on the Experiment page.
Discover different views
Navigate to the ‘Discover’ tab and follow the guidance there to add a plot viewing the results from the latest experiment with parameters depth, width and deflection.
If you copied the existing tutorial project from within the app rather than making your own, an Insight tab will already exist. Click the plus at the bottom of the page to create a new Insight tab to follow this step of the tutorial.
Click the plus symbol on the right hand side to add another plot, this time adding parameter ‘model’. Change the collection being plotted in the dropdown menu from all designs to selected design. Now as you select different designs on the 3D plot on the left hand plot, you’ll see the 3D model for that design on the right.
Custom plots on Discover page
Finished project
Congratulations, you finished the tutorial!
To see the finished project:
- Go to the app
- Open a copy of the tutorial project ''
- Navigate to the ‘Discover’ tab to view generated designs