opensourceBIM / BIMserver

The open source BIMserver platform
GNU Affero General Public License v3.0
1.55k stars 608 forks source link

Geometry generator: Missing objects in model #1256

Open dkurillo opened 2 years ago

dkurillo commented 2 years ago

I have the same problem as described here https://github.com/opensourceBIM/BIMserver/issues/815 though use the latest version of BIMServer. Any ideas where to dig?

hlg commented 2 years ago

Have you configured the geometry engine to use a more recent IfcOpenShell version by updating the "commit sha" plugin setting, e.g. to 517b819, as described in issue https://github.com/opensourceBIM/BIMserver/issues/1207, for example: https://github.com/opensourceBIM/BIMserver/issues/1207#issuecomment-878117652?

BeetleEda commented 2 years ago

In our case the object IfcSpace #14757 does not contain geometry when the file first declares the IfcRelAggregates, then the child object and the parent object.

#14756= IFCRELAGGREGATES('0B0GnqKfD6N8Atm42wZfl9',#2616,$,$,#14757,(#14758));
#14758= IFCSPACE('1M8Al9wgT6XfEQnMGosGr6',#2616,'4.25',$,'',#14759,#14760,$,.PARTIAL.,.SPACE.,3300.);
#14757= IFCSPACE('1M8Al9wgT6XfEQnMGosGzZ',#2616,'4.2.3.12',$,$,#14761,#14762,'',.ELEMENT.,.SPACE.,3300.);

After changing the order and changing expressId of IfcRelAggregates, the geometry was generated correctly

#14756= IFCSPACE('1M8Al9wgT6XfEQnMGosGzZ',#2616,'4.2.3.12',$,$,#14761,#14762,'',.ELEMENT.,.SPACE.,3300.);
#14757= IFCRELAGGREGATES('0B0GnqKfD6N8Atm42wZfl9',#2616,$,$,#14756,(#14758));
#14758= IFCSPACE('1M8Al9wgT6XfEQnMGosGr6',#2616,'4.25',$,'',#14759,#14760,$,.PARTIAL.,.SPACE.,3300.);

Why does this happen?

hlg commented 2 years ago

@BeetleEda, interesting catch - geometry generation should definitely not behave like this. Can this be reproduced with a minimal sample? So just the two spaces with geometry and aggregation, maybe a project? Is this directly related to the original issue or a separate case?

BeetleEda commented 2 years ago

@hlg I can't reproduce this behavior with a minimal example. It looks like it's not just about order. I'll keep looking for the reason...

dkurillo commented 2 years ago

It's the problem of BimServer. In some cases Representation property is not added to serialization array (addUseForSerialization method) and OpenShell engine doesn't get Representation data. The reason why it's not added is very sophisticated... There are many different StackFrames that are doing some indirect calls that lead to this situation. This is why the problem is not reproducible with minimal example...

if (queryObjectProvider.hasReadOrIsGoingToRead((rf)) || queryObjectProvider.hasReadOrIsGoingToRead(referenceClass)) {
  // some features are added, but representation feature in some cases is omitted 
  idEObject.addUseForSerialization(feature, i);
}

Can you maybe shed some light to the principle of how these StackFrames are working?

dkurillo commented 2 years ago

After having a hard time trying to debug this I managed to find out the reason for such a strange behaviour. The problem is hidden in drawbacks of how BimServer traverses object graph. Let me explain it using an example.

Let's say I have two IfcSpaces where one space aggregates another through "decomposes" attribute. BimServer utilizes depth-first traversing which leads to the following steps:

Any comments how to deal with this?

hlg commented 2 years ago

Thanks for the profound investigating - I will have a look, what can be done about it. At first, I thought it might be related to #1081, but you might as well have discovered something different. If that is the case, the fix would be to look for the actual (concrete) type instead of the declared type when choosing references (structural features) for processing and retrieval of related objects.

Regarding your first question about stack frames - they form the parts of a call stack. When executing a program with nested function calls - in this case a query with nested query parts - each call happens in a local environment, with local variables, intermediate state etc. Before execution of a nested function call or processing of a nested query part, the local state of the current execution is stored in a so-called "frame" and saved on top of a stack (last-in-first-out queue). Once the nested function or query part is processed, execution returns to the calling function or enclosing query part, pops the top frame from the stack, restores the previous environment and proceeds with processing the outer function or query.

hlg commented 2 years ago

I can follow your description and worked through StreamingGeometryGenerator and GeometryRunner code, yet I am not able to reproduce this issue and fully understand the details. I see that the "Decomposes" definition from the query std library does not include representation, which might be the cause rather than the suspected typing issue. Also, it might have to do with a specific constellation of mapped geometries. It seems like a very specific case. For further investigation: Can you share the full entity graph of geometries #14760 and #14762 (even if the issue does not occur in isolation)? In addition, can you tell whether the respective spaces end up in the same geometry runner "job" or in different ones? The report should show how many products end up in one job ("Max objects per file" and column 2 in the job list). I assume the issue only occurs when they are in the same job and that is the reason why it does not appear with smaller files (where every product gets a separate job).