Updating and persisting a material property
First of all: thanks for the great Tutorials on IfcOpenShell. Without those I wouldn't know where to even begin! Getting that out of the way, I'm very new to the Ifc format and therefore very new to IfcOpenShell.
I have a wall object with a pset attached to the material properties. Now I want to change a value of one of the material properties. In this case it's about "Test2" which should take the value of "Test1". This means I have to a) extract the value of "Test1" (which is 0.629...) and replace the value of "Test2" by exactly that number.
I've managed to do that in Python, however, I don't know how to proceed from there to "persist" or write the ifc file with the new values. This is what my current code looks like:
import ifcopenshell
import ifcopenshell.util
import ifcopenshell.util.element
import ifcopenshell.util.pset
import ifcopenshell.geom
ifc = ifcopenshell.open("./ifc_file.ifc")
materials = ifc.by_type("IfcMaterial")
wall = ifc.by_type("IfcWall")[0]
for material in materials:
psets = ifcopenshell.util.element.get_psets(material)
for key, pset in psets.items():
if key.startswith("HHLA"):
print(pset)
pset["Test2"] = pset["Test1"]
print(pset)
The question is: how exactly do I manage to write an updated ifc file with everything being the same as the old ifc file but the new entries for Test2? When using "write", I end up having the same file which I had before.
If anything is unclear or if there is a much less complicated way to achieve what I want to do, please let me know.
I've uploaded an excerpt of what the IFC file looks like in FZKViewer here: https://community.osarch.org/uploads/editor/1b/zlmpu5jlz2cj.png
Comments
This should help :)
Hey there! Thanks a lot fo answering this quick and sorry for answering in a very verbose way since I want to make sure that I don't miss the simple way (again) :)
I'm having a
type
issue when reading in the material properties which end up being alist
which doesn't have an attribtue calledis_a
(that's what my error message says, which looks as following):What I am trying to do is to get the correspondig psets of my materials to use in the api call described in your post (
ifcopenshell.api.run("pset.edit_pset", ifc, pset=pset
<- I'm looking for the pset to pass to the function here). If I access the materials withifcopenshell.util.element.get_psets(ifc.by_type("IfcMaterial"), psets_only=True)
, I'm getting a list which is not the expected data type to pass as pset if I understand the error messages correctly.If I keep iterating over the dictionary (as shown below), I keep getting an AttributeError since my
dict
object doesn't have an attribute calledName
which is expected by theedit_pset
method.What is the correct way to query to actually get a data type which is compatible with the
edit_pset
method? I've tried to find a solution in this thread. There is a good example (coincidentally written by yourself as well) here which seems to work for psets of walls, however, I can't access the psets of my materials in the same way without ending up with an error message.ifc.by_type('IfcMaterial')
returns a list of all materials in your project. You can get the psets of a single material by doing:get_psets
returns a dictionary of psets, whereas the API expects an element. Each pset has an ID, which you can use to fetch the element.Also of interest is the
ifcopenshell.util.element.get_material(element)
function :)Thanks again @Moult - I've been awkward for some reasons. I didn't get right away that when looping over my pset keys,
ifc.by_id(pset["id"]
would already get the pset keys so I was trying a way more complicated solution by passing the id's by parsing them outside of the loop until I've noticed that I can leave it as is haha. The usual fun and "aha"-moments when digging into a new library :)To wrap it up, this is what my solution looks like:
The solution, however, is only good with prior knowledge of the property I want to change. It's also not (yet) considered that if there is a property set that shoulnd't be modified which however includes a property with the same name (since I'm querying for the propertyname (
if propertyname in pset.keys()
).Thanks again and I'll take a look at the
ifcopenshell.util.element.get_material(element)
! :)Cheers, glad it works now :)
.