Recently we have been looking into interoperability between the Speckle Python client and other connectors, e.g. Revit and Grasshopper. It now seems that there is a new setup for (de-)serialization of Speckle objects in the .NET connectors, which stores additional information onto a Speckle geometry object. So a Beam becomes a Geometry.Line object with an additional SpeckleSchema attribute that defines the actual beam, as shown here:
For our structural engineering work, we use Python and we would like to exchange models from there to Revit/GH and vice versa. I currently made some classes (see an example below) myself that are identical to the classes defined in C#, however, when sending these to the server, they are not yet serialized in the same manner, which causes interoperability issues between Python and the other connectors. Are you planning on implementing the same serialization procedure in the Python connector? Can imagine that you first need the classes to be in place. What is your view on this?
SpeckleSchema isn’t really a change in serialisation in the connectors, but rather an option that users of connectors have.
SpeckleSchema is a property you can add to geometry objects in Rhino or Grasshopper to indicate that they should be received as BIM objects in eg Revit (so not all objects will have this). These sections in the docs for Rhino and Grasshopper explain how the BIM feature works.
While specklepy doesn’t have the built elements classes, you should still be able to receive them fine. They will show up as a
Base in python, but all the properties should be there and the
speckle_type should be that of the original object. This means sending it back should work as expected. If this is not the case, then that’s definitely a bug! If you are able to share a test stream with me that shows this unexpected behaviour, I would be super grateful!!
As you noticed, specklepy only has geometry object classes at the moment. This is because ideally, all these classes should be generated from C# rather than written by hand. Once we have the speckle-sharp schemas available, we will be generating all object classes (including built elements!) for specklepy! You can also always write the classes you need (from sharp or your own custom ones) that will get picked up in the serialiser.
Regarding the class you’ve written, this class will not be received correctly in the other connectors or in C# in general because you are missing fields and because the
speckle_type is incorrect. If you look at the
speckle_type for the original object, it should be
Objects.BuiltElements.RevitBeam, not just
speckle_type is how Core figures out what your object is, so it has to be exactly correct for the kit you’re targeting! Additionally, in C# you’ll see that
RevitBeam inherits from
IDisplayMesh. Consequently, all fields in
Beam should to be included in your
RevitBeam class (this includes
displayMesh is not a mandatory field).
Hope that helps!
It was indeed helpful to have a look at the docs for some more background information on the SpeckleSchema.
Regarding your second point, I agree that receiving items, possibly changing them, and sending back would not be problematic. I tried and this will indeed not cause any issues. My initial problems were mainly with creating an object in Python from scratch, and get that to be recognized properly by the other connectors.
I now updated my Python classes slightly, which makes it possible to send a RevitBeam object from Python and receive it in Grasshopper as such (see ‘Receive’ GH node below). However, it does not have the
SpeckleSchema attribute that it has when creating a RevitBeam object in Grasshopper directly, which is shown by the ‘ESO’ nodes.
That does make sense of course. However, it does seem that the original Python object cannot be received properly by Revit, as this gives an error
current Unit System is unsupported. I believe my RevitBeam object does contain all necessary attributes and I already changed the units to
mm, which gives the same error.
So then the rephrased question is: Is it possible to create BIM objects from Python and would that require to add a
SpeckleSchema attribute in Python also? Or am I just missing something in the setup of my objects? I added you to my stream on speckle.xyz so you can have a look. The
BIM branch contains the latest
RevitBeam object created from Python.
Thanks for elaborating on this and for sharing the stream with me! Super helpful for me to understand the situation here.
I think I see the problem; you are trying to do two different things here. There are two options I suppose for creating a speckle object that will be received in Revit as a beam:
- Create a
RevitBeam object (this is what the Revit connector does)
- Create a
Line object and add a
SpeckleSchema property containing a
Beam object so Revit knows that this line is in fact a beam (this is what the Rhino / GH connectors do)
These are not equivalent and you’ll need to decide which one you want to go with from Python. (1) involves creating a
RevitBeam class in python and populating that to create your beams. (2) involves simply attaching a
@SpeckleSchema property (note the
@ as it’s detached) to any existing geometry object to create your beams.
If you are getting a “Unit System is unsupported” error, that’s probably because something that should have units is missing it. From the error, it looks like you’re missing units on the points.
I’ve created two commits to demonstrate how data should be structured which I’ve embedded below. Hopefully, opening them up and seeing the structure will make it clear!
Here you see option 1 from this commit:
and here is option 2 from this commit:
Both produce the following result when receiving in Revit:
RevitBeam will both be received successfully in Revit. Revit creates
RevitBeams and Rhino/GH BIM create
Beams. The difference between the two is that the
RevitBeam has additional Revit specific properties.
Hopefully that clears it up. If you’re still unsure, please keep firing away with the questions! This topic could def be written up in a tutorial or something so I’ll add that to my list. Thanks for bringing it up!
Thanks Izzy, that fully clears it up!
The commits you added are very helpful.
Indeed there was some confusion, I was sort of thinking that both options were equivalent. Now I see that they are just different ways to store the data, which can result in (more or less) the same beam in Revit.
I now can indeed receive the RevitBeam myself, after adding the units to the Points.
One strange I noticed here is that when I don’t set the
units attribute myself explicitly, it is not being sent to the server, while a default value
units = 'm' is always set by the
Base class. This is quite peculiar and also impractical, as this would require to manually set the
units for each object that we create in Python. Do you have any idea what is causing this, and is this expected behaviour?
super sorry about the delay in this, but I did track this down and it was indeed a serialisation bug!
if you’re curious, units are a property and not just a regular attribute on
Base. in serialisation, this was getting missed in classes that inherited from
anyway, it’s fixed now and releases above v2.2.4 will include this fix