Skip to content

Commit

Permalink
IVS-369 SPS002 behaviour update (#344)
Browse files Browse the repository at this point in the history
  • Loading branch information
aothms authored Feb 1, 2025
1 parent f3163d7 commit 4e1884b
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 15 deletions.
2 changes: 1 addition & 1 deletion features/SPS002_Correct-spatial-breakdown.feature
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@implementer-agreement
@SPS
@version2
@version3
@E00100
Feature: SPS002 - Correct spatial breakdown
The rule verifies that spatial elements are aggregated as per the Spatial Composition Table.
Expand Down
7 changes: 4 additions & 3 deletions features/steps/thens/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,22 +42,23 @@ def step_impl(context, inst, relationship, table):
# raise Exception(f'Entity {entity} was not found in the {table}')
continue

applicable_entity = ifc.order_by_ifc_inheritance(applicable_entities, base_class_last = True)[0]
expected_relationship_objects = aggregated_table[applicable_entity]
# For all applicable entities (could be multiple e.g IfcRoad, IfcFacility) we union the allowed types
expected_relationship_objects = sorted(set(functools.reduce(operator.or_, map(set, [aggregated_table[e] for e in applicable_entities]))))
try:
relation = getattr(inst, stmt_to_op[relationship], True)[0]
except IndexError: # no relationship found for the entity
if is_required:
yield ValidationOutcome(inst=inst, expected={"oneOf": expected_relationship_objects, "context": context}, severity=OutcomeSeverity.ERROR)
continue

relationship_objects = getattr(relation, relationship_tbl_header, True)
if not isinstance(relationship_objects, tuple):
relationship_objects = (relationship_objects,)


for relationship_object in relationship_objects:
is_correct = any(relationship_object.is_a(expected_relationship_object) for expected_relationship_object in expected_relationship_objects)
if not is_correct:
# related object not of the correct type
yield ValidationOutcome(inst=inst, expected={"oneOf": expected_relationship_objects, "context": context}, observed=relationship_object, severity=OutcomeSeverity.ERROR)


Expand Down
11 changes: 0 additions & 11 deletions features/steps/utils/ifc.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,6 @@ def instance_getter(i, representation_id, representation_type, negative=False):
if condition(i, representation_id, representation_type):
return i

def order_by_ifc_inheritance(instances, base_class_last):
import ifcopenshell
ifc = ifcopenshell.file(schema='IFC4X3')
inheritance_nr = {}
for instance in instances:
ifc_instance = ifc.create_entity(instance)
result = sum(1 for str_instance in instances if ifc_instance.is_a(str_instance))
inheritance_nr[instance] = result
inheritance_nr = dict(sorted(inheritance_nr.items(), key=lambda item: item[1], reverse=base_class_last))
return list(inheritance_nr.keys())


def recurrently_get_entity_attr(ifc_context, inst, entity_to_look_for, attr_to_get, attr_found=None):
if attr_found is None:
Expand Down
69 changes: 69 additions & 0 deletions test/files/sps002/pass-sps002-road_facilitypart.ifc
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
ISO-10303-21;
/* Testfile: pass-sps002-road_facilitypart.ifc */
/* IFC-Requirement: sps002; Correct spatial breakdown */
HEADER;
FILE_DESCRIPTION(('ViewDefinition [Ifc4X3NotAssigned]'),'2;1');
FILE_NAME ('pass-sps002-road_facilitypart.ifc', '2023-03-14T15:36:48', ('redacted'), ('redacted'), 'Python+IfcOpenShell', '','');
FILE_SCHEMA(('IFC4X3_ADD2'));
ENDSEC;
DATA;
#1= IFCAPPLICATION(#2,'1.0.0.0','redacted','redacted');
#2= IFCORGANIZATION($,'Geometry Gym Pty Ltd',$,$,$);
#3= IFCPERSONANDORGANIZATION(#4,#5,$);
#4= IFCPERSON('redacted','redacted',$,$,$,$,$,$);
#5= IFCORGANIZATION($,'redacted',$,$,$);
#6= IFCOWNERHISTORY(#3,#1,$,.ADDED.,1418084874,$,$,1418084874);
#7= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.0001,#8,#10);
#8= IFCAXIS2PLACEMENT3D(#9,$,$);
#9= IFCCARTESIANPOINT((0.0,0.0,0.0));
#10= IFCDIRECTION((0.0,1.0));
#11= IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#7,$,.MODEL_VIEW.,$);
#12= IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#7,$,.MODEL_VIEW.,$);
#13= IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,0.0001,#8,#14);
#14= IFCDIRECTION((0.0,1.0));
#50= IFCBUILDING('0Cd2Mw3cP09wW6qWHK8v2f',$,'IfcBuilding',$,$,#51,$,$,.ELEMENT.,$,$,#57);
#51= IFCLOCALPLACEMENT($,#52);
#52= IFCAXIS2PLACEMENT3D(#53,$,$);
#53= IFCCARTESIANPOINT((0.0,0.0,0.0));
#54= IFCRELCONTAINEDINSPATIALSTRUCTURE('3ffS1zvV94ExNgP6hOHMLr',$,'Building','Building Container for Elements',(#302),#50);
#57= IFCPOSTALADDRESS($,$,$,$,$,$,$,'Unknown',$,$);
#100= IFCPROJECT('3KEb34nozBu9ezspX8gM9d',#6,'IfcProject',$,$,'IfcProject','',(#13),#101);
#101= IFCUNITASSIGNMENT((#102,#103,#104));
#102= IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.);
#103= IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.);
#104= IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.);
#200= IFCMATERIAL('Masonry - Brick - Brown',$,$);
#203= IFCMATERIAL('Masonry',$,$);
#206= IFCMATERIALLAYER(#200,110.0,.F.,'Finish',$,$,$);
#208= IFCMATERIALLAYER($,50.0,.T.,'Air Infiltration Barrier',$,$,$);
#210= IFCMATERIALLAYER(#203,110.0,.F.,'Core',$,$,$);
#212= IFCMATERIALLAYERSET((#206,#208,#210),'Double Brick - 270',$);
#213= IFCRELASSOCIATESMATERIAL('2D3xie$bD8YgahfQF1htfq',$,'MatAssoc','Material Associates',(#300),#212);
#300= IFCWALLTYPE('2GdZ7nhi52Geyiua9QcAH9',$,'Double Brick - 270',$,$,$,$,$,$,.NOTDEFINED.);
#301= IFCRELDEFINESBYTYPE('3Gcd0t0WTDWe18S5rhROgf',$,'Double Brick - 270',$,(#302),#300);
#302= IFCWALLSTANDARDCASE('0czCsOQ5z4dg8QGBRFInu2',$,$,$,$,#305,#320,$,$);
#303= IFCMATERIALLAYERSETUSAGE(#212,.AXIS2.,.POSITIVE.,0.0,$);
#304= IFCRELASSOCIATESMATERIAL('0PFtmoJBHDOvVAl6M9w55u',$,'MatAssoc','Material Associates',(#302),#303);
#305= IFCLOCALPLACEMENT($,#306);
#306= IFCAXIS2PLACEMENT3D(#307,#308,#309);
#307= IFCCARTESIANPOINT((0.0,0.0,0.0));
#308= IFCDIRECTION((0.0,0.0,1.0));
#309= IFCDIRECTION((1.0,0.0,0.0));
#310= IFCCARTESIANPOINT((5000.0,0.0));
#311= IFCCARTESIANPOINT((0.0,0.0));
#312= IFCPOLYLINE((#311,#310));
#313= IFCSHAPEREPRESENTATION(#11,'Axis','Curve2D',(#312));
#314= IFCAXIS2PLACEMENT2D(#315,$);
#315= IFCCARTESIANPOINT((2500.0,135.0));
#316= IFCRECTANGLEPROFILEDEF(.AREA.,'Wall Perim',#314,5000.0,270.0);
#317= IFCDIRECTION((0.0,0.0,1.0));
#318= IFCEXTRUDEDAREASOLID(#316,$,#317,2000.0);
#319= IFCSHAPEREPRESENTATION(#12,'Body','SweptSolid',(#318));
#320= IFCPRODUCTDEFINITIONSHAPE($,$,(#313,#319));
#321=IFCROAD('0hb5vCxjv2ZetiycRLI_Fx',#6,'','',$,$,$,$,$,$);
#322=IFCFACILITYPARTCOMMON('0hb5vCxjv2ZetiycRLI_Fy',#6,'','',$,$,$,$,$,.NOTDEFINED.,$);
#323= IFCRELAGGREGATES('2G17HB5orFmhdpTVYmbgKX',$,'RailwayContainer','Container for Railway Parts',#321,(#322));
#324= IFCRELAGGREGATES('2G17HB5orFmhdpTVYmbgCX',$,'RailwayContainer','Container for Railway Parts',#100,(#321,#50));
ENDSEC;

END-ISO-10303-21;

0 comments on commit 4e1884b

Please sign in to comment.