I am trying to read the deepest level of quantities for objects in an ifc file, using IfcOpenShell in Python. So far I have:
import ifcopenshell
path = r'D:\ifcos_1\slab.ifc'
ifc_file = ifcopenshell.open(path)
geometries = ifc_file.by_type("IfcProduct")
for geometry in geometries:
if geometry.is_a("IfcSlab"):
print geometry
test = geometry.IfcPhysicalQuantity()
print test
I've studied the definitions
No matter which type of function I try to place for the test = geometry.X(), I get an error:
File "C:\Python27\lib\site-packages\ifcopenshell\entity_instance.py", line 48, in __getattr__
"entity instance of type '%s' has no attribute '%s'" % (self.wrapped_data.is_a(), name))
AttributeError: entity instance of type 'IfcSlab' has no attribute 'IfcPhysicalQuantity'
Not sure how to solve this and would appreciate help.
EDIT:
Further work which gets the slab and further references:
for geometry in geometries:
if geometry.is_a("IfcSlab"):
print geometry
definedBy = geometry.IsDefinedBy
print definedBy[0]
for each in definedBy:
test = each.is_a()
print test
As of this moment the obstacle is the compatibility with IFC4, which I will try to recompile with instructions from this forum post.
EDIT 2:
Further work using for now the IFC 2x3 standard, with a file that has quantity information (verified via the raw data). The following is the relevant code:
for geometry in geometries:
if geometry.is_a("IfcSlab"):
definedBy = geometry.IsDefinedBy
for line in definedBy:
test = line.is_a()
# print test
if line.is_a() == 'IfcRelDefinesByProperties' or line.is_a() == 'IfcRelDefinesByType':
step1 = line.RelatingPropertyDefinition
step2 = step1.is_a()
print step2
There is an error no matter what I place after step1 = line., none of the following give a result:
line.IfcPropertySet
line.IfcElementQuantity
line.RelatingPropertyDefiniton
The output from this code is nevertheless:
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcPropertySet
IfcElementQuantity
IfcElementQuantity
Which means that I can access IfcElementQuantity but none of the Attributes work. I've looked at schema reference but can't find the correct one.
When implementing this you should take care which version of IFC your import library works on - the version distributed by the IfcOpenShell-Website works with IFC2X3. For IFC4 you will probably need to compile a version yourself. (you can check your IFC version with ifcopenshell.schema_identifier)
I am putting links up to the buildingSMART IFC 4 definition even if I am talking about IFC2X3. Differences to IFC2X3 are marked in red on the buildingSMART web page. And the IFC4 definition is nicer to read (IMO).
Quantities aren't directly attached like an attribute. They are written as property sets and then related to the element or element type. So first you should ensure your IFC file contains quantities - otherwise you will not find any. Usually you start with a specific product - ifc_file.by_type('IfcSlab'). You can reach the property sets via inverse attributes - those are usually set up by the IFC library, they don't appear directly as attribute in the file.
I took you example file and shortened it to about a third (so it's still a valid IFC2X3 file):
ISO-10303-21;
HEADER;FILE_DESCRIPTION(('ViewDefinition [Custom, QuantityTakeOffAddOnView, SpaceBoundary2ndLevelAddOnView]','Option [Drawing Scale: 100.000000]','Option [Global Unique Identifiers (GUID): Keep existing]','Option [Elements to export: Visible elements (on all stories)]','Option [Partial Structure Display: Entire Model]','Option [IFC Domain: All]','Option [Structural Function: All Elements]','Option [Convert Grid elements: On]','Option [Convert IFC Annotations and ARCHICAD 2D elements: Off]','Option [Convert 2D symbols of Doors and Windows: Off]','Option [Explode Composite and Complex Profile elements into parts: On]','Option [Export geometries that Participates in Collision Detection only: Off]','Option [Elements in Solid Element Operations: Extruded/revolved]','Option [Elements with junctions: Extruded/revolved without junctions]','Option [Slabs with slanted edge(s): Extruded]','Option [Use legacy geometric methods as in Coordination View 1.0: Off]','Option [IFC Site Geometry: As boundary representation (BRep)]','Option [IFC Site Location: At Project Origin]','Option [Curtain Wall export mode: Container Element]','Option [Railing export mode: Single Element]','Option [Stair export mode: Container Element]','Option [Properties To Export: All properties]','Option [Space containment: On]','Option [IFC Domain For Space Containment: All]','Option [Bounding Box: Off]','Option [Geometry to type objects: Off]','Option [Element Properties: All]','Option [Property Type Element Parameter: On]','Option [Quantity Type Element Parameter: On]','Option [IFC Base Quantities: On]','Option [Window Door Lining and Panel Parameters: On]','Option [IFC Space boundaries: On]','Option [ARCHICAD Zone Categories as IFC Space classification data: On]','Option [Element Classifications: On]'),'2;1');
FILE_NAME('D:\\Side Projects\\Paragraph3\\The database\\IFC Files\\Local tests\\ifcos_1\\slab.ifc','2018-06-13T18:28:40',('Architect'),('Building Designer Office'),'The EXPRESS Data Manager Version 5.02.0100.09 : 26 Sep 2013','IFC file generated by GRAPHISOFT ARCHICAD-64 21.0.0 INT FULL Windows version (IFC2x3 add-on version: 3005 INT FULL).','The authorising person');
FILE_SCHEMA(('IFC2X3'));
ENDSEC;
DATA;
#1= IFCPERSON($,'Undefined',$,$,$,$,$,$);
#7= IFCPERSONANDORGANIZATION(#1,#10,$);
#10= IFCORGANIZATION('GS','GRAPHISOFT','GRAPHISOFT',$,$);
#11= IFCAPPLICATION(#10,'21.0.0','ARCHICAD-64','IFC2x3 add-on version: 3005 INT FULL');
#12= IFCOWNERHISTORY(#7,#11,$,.ADDED.,$,$,$,1528907320);
#13= IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
#14= IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.);
#16= IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#17= IFCMEASUREWITHUNIT(IFCPLANEANGLEMEASURE(0.0174532925199),#16);
#18= IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0);
#19= IFCCONVERSIONBASEDUNIT(#18,.PLANEANGLEUNIT.,'DEGREE',#17);
#29= IFCUNITASSIGNMENT((#13,#14,#19));
#31= IFCDIRECTION((1.,0.,0.));
#35= IFCDIRECTION((0.,0.,1.));
#37= IFCCARTESIANPOINT((0.,0.,0.));
#39= IFCAXIS2PLACEMENT3D(#37,#35,#31);
#40= IFCDIRECTION((0.,1.));
#42= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.00000000000E-5,#39,#40);
#45= IFCPROJECT('344O7vICcwH8qAEnwJDjSU',#12,'Project',$,$,$,$,(#42),#29);
#59= IFCLOCALPLACEMENT($,#39);
#62= IFCSITE('20FpTZCqJy2vhVJYtjuIce',#12,'Site',$,$,#59,$,$,.ELEMENT.,(47,33,34,948800),(19,3,17,204400),0.,$,$);
#68= IFCRELAGGREGATES('0Du7$nzQXCktKlPUTLFSAT',#12,$,$,#45,(#62));
#74= IFCQUANTITYLENGTH('GrossPerimeter',$,$,0.);
#76= IFCQUANTITYAREA('GrossArea',$,$,0.);
#77= IFCELEMENTQUANTITY('2GNZepdf73fvGc$0W6rozj',#12,'BaseQuantities',$,'ARCHICAD BIM Base Quantities',(#74,#76));
#82= IFCRELDEFINESBYPROPERTIES('2Hm9JvZjohDNSD2kdxZI3b',#12,$,$,(#62),#77);
#93= IFCLOCALPLACEMENT(#59,#39);
#95= IFCBUILDING('00tMo7QcxqWdIGvc4sMN2A',#12,'Building',$,$,#93,$,$,.ELEMENT.,$,$,$);
#97= IFCRELAGGREGATES('2b_h_mYcGArd6glJG2Fmbt',#12,$,$,#62,(#95));
#101= IFCQUANTITYAREA('GrossFloorArea',$,$,0.);
#102= IFCELEMENTQUANTITY('1kQMlmT0rD35a9E43iKTas',#12,'BaseQuantities',$,'ARCHICAD BIM Base Quantities',(#101));
#104= IFCRELDEFINESBYPROPERTIES('0L87OdSD3DqSTjSRlAciZL',#12,$,$,(#95),#102);
#115= IFCLOCALPLACEMENT(#93,#39);
#117= IFCBUILDINGSTOREY('1oZ0wPs_PE8ANCPg3bIs4j',#12,'Ground Floor',$,$,#115,$,$,.ELEMENT.,0.);
#119= IFCRELAGGREGATES('118jwqMnuwK1xuf97w7fU5',#12,$,$,#95,(#117));
#180= IFCSLAB('3W29Drc$H6CxK3FGIxjJNl',#12,'SLA - 001',$,$,$,$,'E0089375-9BF4-4633-B503-3D04BBB535EF',.FLOOR.);
#195= IFCRELCONTAINEDINSPATIALSTRUCTURE('04ldtj6cp2dME6CiP80Bzh',#12,$,$,(#180),#117);
#326= IFCPROPERTYSINGLEVALUE('Fragility rating',$,IFCLABEL('0'),$);
#327= IFCPROPERTYSINGLEVALUE('Tile dimensions',$,IFCLABEL('Undefined'),$);
#328= IFCPROPERTYSINGLEVALUE('Anti-static Surface',$,IFCBOOLEAN(.F.),$);
#329= IFCPROPERTYSINGLEVALUE('Non-skid Surface',$,IFCBOOLEAN(.F.),$);
#330= IFCPROPERTYSET('0LYX8AqOOS9ft8M4aJYEYa',#12,'FLOORINGS',$,(#326,#327,#328,#329));
#332= IFCRELDEFINESBYPROPERTIES('1G6WWCSQGg0PdTnW7hwMrM',#12,$,$,(#180),#330);
#335= IFCPROPERTYSINGLEVALUE('Renovation Status',$,IFCLABEL('Existing'),$);
#336= IFCPROPERTYSET('0cR6wsk2QWcLKPchA8mF3u',#12,'AC_Pset_RenovationAndPhasing',$,(#335));
#338= IFCRELDEFINESBYPROPERTIES('3nYD8KGPhoBw5okmj1JjsA',#12,$,$,(#180),#336);
#341= IFCQUANTITYLENGTH('Width',$,$,300.);
#342= IFCQUANTITYLENGTH('Perimeter',$,$,22000.);
#343= IFCQUANTITYAREA('GrossArea',$,$,28.);
#344= IFCQUANTITYAREA('NetArea',$,$,28.);
#345= IFCQUANTITYVOLUME('GrossVolume',$,$,8.4);
#346= IFCQUANTITYVOLUME('NetVolume',$,$,8.4);
#347= IFCELEMENTQUANTITY('1RfXJewSc7OCIaD$L2ZoXT',#12,'BaseQuantities',$,'ARCHICAD BIM Base Quantities',(#341,#342,#343,#344,#345,#346));
#349= IFCRELDEFINESBYPROPERTIES('085uLttAQRllG3nL_YikZ8',#12,$,$,(#180),#347);
#375= IFCQUANTITYVOLUME('Gross Volume of the Slab',$,$,8.4);
#376= IFCQUANTITYVOLUME('Gross Volume of the Slab with Holes',$,$,8.4);
#377= IFCQUANTITYLENGTH('Holes Perimeter',$,$,0.);
#378= IFCQUANTITYAREA('Holes Surface Area',$,$,0.);
#379= IFCQUANTITYLENGTH('Perimeter',$,$,22000.);
#381= IFCQUANTITYAREA('Top Surface Area',$,$,28.);
#382= IFCELEMENTQUANTITY('0DuZ12CVtssgcIQPaQ$1sp',#12,'ArchiCADQuantities',$,'ARCHICAD BIM Quantities',(#375,#376,#377,#378,#379,#381));
#384= IFCRELDEFINESBYPROPERTIES('0KgGv0Y8Fc2jg8BCPhxnM5',#12,$,$,(#180),#382);
#393= IFCSLABTYPE('0K1otpnkQcEpOBXPxnZ3dB',#12,'Timber - Floor 300',$,$,(#396),$,'14072DF3-C6E6-A63B-360B-859EF18C39CB',$,.FLOOR.);
#395= IFCRELDEFINESBYTYPE('353egCMRpZtJd$CDCoSsCb',#12,$,$,(#180),#393);
#352= IFCQUANTITYAREA('Area',$,$,28.);
#353= IFCQUANTITYLENGTH('Height',$,$,300.);
#354= IFCQUANTITYVOLUME('Net Volume',$,$,8.4);
#396= IFCELEMENTQUANTITY('1Zyxf4r7NogSp4V7ORMpET',#12,'ArchiCADQuantities',$,'ARCHICAD BIM Quantities',(#352,#353,#354));
ENDSEC;
END-ISO-10303-21;
This is a slab with an area measurement attached. It should have an inverse attribute IsDefinedBy. In IFC2X3 this points to a list of entities IfcRelDefinesByProperties and IfcRelDefinesByType. With IFC4 IfcRelDefinesByType will be put in the inverse attribute IsTypedBy.
Each IfcRelDefinesByProperties point to a property set in their attribute RelatingPropertyDefinition. There are various property set types, you want it to be of type IfcElementQuantity when searching for physical quantities. You will have to check at run time which type you currently hold while iterating the list of property relations.
The quantity set has a list of IfcPhysicalQuantities attached in the attribute Quantities. These can be simple quantities or complex quantities, which are composed of multiple simple quantities. For simple quantities there are specific subtypes for area, count or weight. Again you will have to check at runtime for the concrete type.
The area quantity itself has a name and description to give further context (not ours, but possibly in the real world). The value attribute is named after the quantity type, so IfcQuantityArea has an attribute AreaValue. Also of interest is attribute Unit which is a reference to the unit of the value. If it is not set (as in our example) you will need to look for assigned units at the IfcProject entity.
Unfortunately this might not be all. If the object (here our IfcSlab) has an assigned object type, that type can also have property sets attached (I modified the example file to be this case). Thy type entity does not have an inverse attribute, but a direct one, HasProperties. If it is set, you can discover attached properties through it.
To summarise, you will probably need multiple loops:
For each object, get property sets
For each property set, test if it is quantity set
For each quantity set, go through quantities
And potentially repeat this search if the object has a user defined type.
The following code should do exactly this (written on my machine with python 3.5.4 and ifcopenshell with IFC2X3 schema)):
Get all slabs from the file (there is only one)
Go through all entities in the inverse attribute IsDefinedBy - these can be IfcRelDefinesByProperties or IFcRelDefinesByType.
Get property sets from the entity
Check if the given property set is IfcElementQuantity and proceed to print quantitites if it is.
import ifcopenshell
def print_quantities(property_definition):
if 'IfcElementQuantity' == property_definition.is_a():
for quantity in property_definition.Quantities:
if 'IfcQuantityArea' == quantity.is_a():
print('Area value: ' + str(quantity.AreaValue))
if 'IfcQuantityVolume' == quantity.is_a():
print('Volume value: ' + str(quantity.VolumeValue))
if 'IfcQuantityLength' == quantity.is_a():
print('Length value: ' + str(quantity.LengthValue))
ifc_file = ifcopenshell.open('slab.ifc')
products = ifc_file.by_type('IfcSlab')
for product in products:
if product.IsDefinedBy:
definitions = product.IsDefinedBy
for definition in definitions:
#In IFC2X3 this could be property or type
#in IFC4 type is in inverse attribute IsTypedBy
if 'IfcRelDefinesByProperties' == definition.is_a():
property_definition = definition.RelatingPropertyDefinition
print_quantities(property_definition)
if 'IfcRelDefinesByType' == definition.is_a():
type = definition.RelatingType
if type.HasPropertySets:
for property_definition in type.HasPropertySets:
print_quantities(property_definition)
For the example this results in:
Length value: 300.0
Length value: 22000.0
Area value: 28.0
Area value: 28.0
Volume value: 8.4
Volume value: 8.4
Volume value: 8.4
Volume value: 8.4
Length value: 0.0
Area value: 0.0
Length value: 22000.0
Area value: 28.0
Area value: 28.0
Length value: 300.0
Volume value: 8.4
Quantities in IFC are stored in quantity sets, which are very similar in structure to property sets. IfcOpenShell offers utility functions to extract this data in a schema-agnostic manner:
for slab in ifc_file.by_type("IfcSlab"):
quantities = ifcopenshell.util.element.get_psets(slab, qtos_only=True)
print(quantities) # A dictionary of qtos and quantities
# For example print(quantities["Qto_SlabBaseQuantities"]["GrossVolume"])
I wrote a few functions once, to extract all properties.
https://github.com/johannesmichael/ifc-python/blob/master/modules/ifc_pset_utils.py
Might not be complete, but can give you an idea.
I extract all to excel for further analyzis.
BaseQuantities:
def get_related_quantities(ifc_instance):
"""
Returns a list of IfcElementQuantity for given IFC ID
argument: ifc_instance
return: list of property sets
"""
quantities_list =[]
for x in ifc_instance.IsDefinedBy:
if x.is_a("IfcRelDefinesByProperties"):
if x.RelatingPropertyDefinition.is_a("IfcElementQuantity"):
quantities_list.append(x.RelatingPropertyDefinition)
return quantities_list
def get_quantity_single_value(x):
"""
Returns a dict of dicts of IfcElementQuantity single values.
Returning a dictionary of dictionaries
is used, because it is easy to transform to pandas.DataFrame
argument: IFC Element as contained in list from get_related_property_sets()
return: dict of property single values like {"IfcName":"xx", "IfcGlobalId": "klkhlkh", ......}
"""
quantities_dicts = {}
for y in x.Quantities:
if y.is_a('IfcQuantityArea'):
quantities_dicts.update({y.Name:y.AreaValue})
if y.is_a('IfcQuantityLength'):
quantities_dicts.update({y.Name:y.LengthValue})
if y.is_a('IfcQuantityVolume'):
quantities_dicts.update({y.Name:y.VolumeValue})
if y.is_a('IfcQuantityCount'):
quantities_dicts.update({y.Name:y.CountValue})
if y.is_a('IfcQuantityWeight'):
quantities_dicts.update({y.Name:y.WeightValue})
return quantities_dicts
This was done for IFC 2x3 TC1
Hope that helps
one of my A Level students are trying to get their code to work in Python 3 but it keeps coming up with the error message: "sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 3, and there are 1 supplied". The code is as follows:
import sqlite3
def query(sql,data):
with sqlite3.connect("DogBreeds.db") as db:
cursor = db.cursor()
cursor.execute(sql,data)
db.commit()
def insert_dog_breed_data(records):
sql = "insert into DogBreed(Breed, Description, Previous_Litters) values (?,?,?)"
for record in records:
query(sql,record)
def insert_dog_data(records):
sql = "insert into Dogs (Name, Date of Birth, Gender, DogBreedID) values (?,?,?,?)"
for record in records:
query(sql,record)
if __name__ == "__main__":
dog_breeds = [("Shih Tzu",),("Jack Russell",),("Great Dane",),("Husky"("Cavalier King Charles Spaniel",),("Pug")]
insert_dog_breed_data(dog_breeds)
dogs = [("Steve", "10/08/2006", "Male",1),("John","08/05/2017", "Male",2),("Ellen", "25/12/2013","Female",3),("Betty", "13/01/2000", "Female",4),("Charlie", "30/03/2000", "Female",5),("Fred", "04/05/2000", "Male",5)]
insert_dog_data(dogs)
and the full error message is:
Traceback (most recent call last): File "G:\Dog Breeder Scenario - Python\Insert data 2.py", line 21, in <module>
insert_dog_breed_data(dog_breeds) File "G:\Dog Breeder Scenario - Python\Insert data 2.py", line 12, in insert_dog_breed_data
query(sql,record) File "G:\Dog Breeder Scenario - Python\Insert data 2.py", line 6, in query
cursor.execute(sql,data)
sqlite3.ProgrammingError: Incorrect number of bindings supplied. The current statement uses 3, and there are 1 supplied.
As a guide they are following the tutorial from Python School website - Task 4 from https://pythonschool.net/databases/inserting-data/
Any help will be appreciated.
Thanks.
You're passing a list of single-item tuples into insert_dog_breed_data - containing the breed name only - but the SQL query is expecting three items - name, description, previous_litters.
Note, one of the most useful skills a new programmer can learn is how to read error messages. All the information they - and you - needed to solve this themselves was presented in that message.
The problem is (as #DanielRoseman explained) that sqlite expects tuples containing 3 items each (Breed, Description, Previous_Litters) but the ones you are providing only contain one since:
dog_breeds = [("Shih Tzu",),("Jack Russell",),("Great Dane",),("Husky"("Cavalier King Charles Spaniel",),("Pug")])
One solution would be to modify your dog_breeds tuples before passing it on to the insert_dog_breed_data function as follows:
dog_breeds = [(x,) + ('', '') for x in dog_breeds]
Assuming you do not have the info on the Description and Previous_Litters available.
which will create tuples like this one: ("Shih Tzu", '', '')