IFCPatch tool now available

I problem I usually face is that IFCs exported from proprietary applications have various issues in them. I want to fix them, but most IFC authoring programs do an import-export process that results in a huge amount of data being lost in-between.

To solve this, I usually run a quick Python script which uses IfcOpenShell to modify the IFC file. However this is usually something only I can do but others cannot do in the office. For this reason I made IFCPatch.

Basically, it's a CLI app which you can feed in an IFC file, and apply a "recipe" which will modify the IFC in some predefined manner. For example:

$ ifcpatch -i foo.ifc -r ResetAbsoluteCoordinates

This will detect any IfcCartesianPoint which are placed in absolute coordinates (i.e. very far away) and correct them - which is a common problem in incorrectly geolocated IFCs produced from 12D.

Recipes can also allow arguments to be passed, such as:

$ ifcpatch -i foo.ifc -r OffsetStoreyLocations -a 1000

That will shift up all building stories by 1000 units.

I hope its useful to someone. Being a CLI app, I have integrated it into a Git hook when consultants submit their files.

bitacovirJesusbilledwinguerraberndCGREloyRDBTokarzewskiJohannes990cvillagrasaArv
«1

Comments

  • How do I run IfcPatch? If I compile and install latest IfcOpenShell I only have "IfcConvert" and "IfcGeomServer" binaries starting with "Ifc" installed?

    Do you have an exapmple for IfcPatch and ExtractElements ?

  • @bernd IfcPatch is pure Python. See link in first post.

    Example:

    $ ifcpatch -i foo.ifc -o out.ifc -r ExtractElements -a ".IfcWall"
    
  • ok
    In your example you did call ifcpatch out of your bash, but ifcpatch is a directory in ifcopenshell sources. How should I call ifcpatch if there is no python module ifcpatch? There is only a package (directory) named ifcpatch in ifcopenshell sources.

    I seam to miss the forest because of the trees ...

  • Ah ifcpatch used to be a standalone .py file which symlinked in my /usr/local/bin to give that behaviour... now it's a module, so, uh :) Times change!

  • than there where just clouds in front of the forest :-) Again the sun is shining ... Got it. Thanks

    Moult
  • So i have a big IFC from Tekla which is too big and creating problems in Revit. @Moult thought that IfcPatch could be a solution since what I want to do is split the file so there is one file per building. It's a huge steel structure for two buildings in one file. Dion is rather busy at the moment @bernd do you have time to help me understand how to do something like this?

  • edited February 2021

    @duncan : I missed the post ...
    I will give it a try ... hoepfully you are on Linux ...

    read this first ... https://github.com/IfcOpenShell/IfcOpenShell/blob/3eacd809b0dc0c4d03d4675f3f64a509cb27789f/src/ifcpatch/README.md

    Set up you system

    # clone ifcopenshell
    # start Python 3, on most Linux machines this is done by "python3" ATM
    the_path_of_ifcpatch = "/the/path/to/ifcopenshell/which/you/have/cloned/into/src/ifcpatch/"  # change this for your needs
    import sys
    sys.path.append(the_path_of_ifcpatch)
    import ifcpatch 
    import lark  # you will need this, I had to insall it by "pip3 install lark" because Debian Buster does not have lark packages
    # if there was no error you are ready ...
    

    get some ifc data to play with ... https://github.com/buildingSMART/Sample-Test-Files/tree/master/IFC 2x3/Schependomlaan/Design model IFC

    Run ifcpatch:

    • cd in the directory where the Schependomlaan ifc is saved
    • start python by python3
    • copy the following code
    import sys
    sys.path.append("/home/hugo/Documents/dev/ifcopenshell/ifcopenshell-official/ifcos/src/ifcpatch/")  # change this for your needs
    import ifcpatch
    
    ifcpatch.execute({
        "input": "IFC Schependomlaan.ifc",
        "output": "IFC Schependomlaan_OnlyWalls.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": [".IfcWall"],
    })
    
  • Moult this is AWESOME * AWESOME

  • edited February 2021

    some more examples ... the query taken from here
    https://wiki.osarch.org/index.php?title=IfcOpenShell_code_examples#IFC_Query_Syntax

    import sys
    sys.path.append("/home/hugo/Documents/dev/ifcopenshell/ifcopenshell-official/ifcos/src/ifcpatch/")
    import ifcpatch
    
    ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "output": "/home/hugo/NeuOrd/IFC Schependomlaan_AllWalls.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": [".IfcWall"],
    })
    
    ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "output": "/home/hugo/NeuOrd/IFC Schependomlaan_AllSabsWalls.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": [".IfcWall | .IfcSlab"],
    })
    
    ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "output": "/home/hugo/NeuOrd/IFC Schependomlaan_StoreyElements.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": ["@ #0u4wgLe6n0ABVaiXyikbkA"],
    })
    
    ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "output": "/home/hugo/NeuOrd/IFC Schependomlaan_WallsComplexWithOpenings.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": ["#0BbZBldn94MfvyeV9ZExMT | #1HB2RkFMD9UQq5pmmS3kII"],
    })
    
    
    ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "output": "/home/hugo/NeuOrd/IFC Schependomlaan_WallsSimple.ifc",
        "recipe": "ExtractElements",
        "log": "ifcpatch.log",
        "arguments": ["#0GkhpndB96r98q9Zpfg0ks| #2kHoPrvTH4mgO72z01pDOc"],
    })
    
  • I am looking to test this IFCPatch out. I was wondering if we can patch any property within an IFC File? Particularly in my case is the IFCGUID. Maintaining IFCGUID has been a problem for various modeling platforms and I am looking for a way to keep that a constant even if it mean replacing it again with a baseline reference. Any ideas?

  • For a bit of clarification, IfcPatch is simply a way to distribute a script that modifies an IFC in some way. It is up to you to write the script yourself, or use one from a collection of recipes provided with IfcPatch. If you're after modifying a particular property, it's best to write your own script. Alternatively, if scripting is not your thing, IfcCSV is a great way to pull out particular properties, modify them, then import the changes back in.

  • @Moult to clarify: I thought from a previous post that attributes , such as Global ID, could not be modified using IfcCSV, is this accurate?

  • @edwinguerra you should be able to edit attribute, except for GlobalId. The reason the GlobalId cannot be edited is because it is used as the unique linking key.

    edwinguerra
  • edited July 2022

    Currently, IFCPatch works with very simple recipes.
    Will it be able to run more complex algorithms that contain many recipes? Something similar to OpenStudio measures?
    Hmm, it would be nice to have a library of IFC measures.

  • edited July 2022

    Can someone tell me what
    https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.6.0/src/ifcpatch/ifcpatch/recipes/SplitByBuildingStorey.py
    does? creates an ifc for each Storey? Depending where the one ifc-object is classified to?
    sorry found: https://community.osarch.org/discussion/comment/1150/#Comment_1150
    What when the ifc-building is messed up with elements that range over several floors. Or a declared Groundfloor-element appears in geometry in the 1st floor? (would be like sorting manually the scene collections) Would it be possible to sort all elements depending on their elevation? Cut the elements that range over several floors?
    Where is the IFCPatch menu gone in Blender3.2.1 BlenderBIM 220711 ?
    Thanks.

  • edited March 2023

    the call has slightly changed a bit ... see in Source or this example from above here:

    import sys
    sys.path.append("/home/hugo/Documents/dev/ifcopenshell/ifcopenshell-official/ifcos/src/ifcpatch/")
    import ifcpatch
    import ifcopenshell
    in_ifcfile = ifcopenshell.open("/home/hugo/NeuOrd/IFC Schependomlaan.ifc")
    
    
    out_ifcfile = ifcpatch.execute({
        "input": "/home/hugo/NeuOrd/IFC Schependomlaan.ifc",
        "file": in_ifcfile,
        "recipe": "ExtractElements",
        "arguments": [".IfcWall"],
    })
    ifcpatch.write(out_ifcfile, "/home/hugo/NeuOrd/IFC Schependomlaan_AllWalls.ifc")
    
  • edited March 2023

    What else can be used as selector? I know of
    ".IfcSomeWhat"
    "#AGUID"

    They can be combined by a "|"
    They can even be mixed like get all IfcSlab and than this GUID.
    Can I get the inverse, means all but not IfcSlab?
    Can I get all with material xyz, or pset.attribut with value xyz?

    Where in source is this implementet? It seams not here in ExtractElements.py ... https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.7.0/src/ifcpatch/ifcpatch/recipes/ExtractElements.py or more direct where is the Selector implemented https://github.com/IfcOpenShell/IfcOpenShell/blob/v0.7.0/src/ifcpatch/ifcpatch/recipes/ExtractElements.py#L62

        selector = ifcopenshell.util.selector.Selector()
        for element in selector.parse(self.file, self.query):
            self.add_element(element)
    
  • edited March 2023

    on huge files it can take some time and on complicated queries it needs some trys to find the correct querry.
    How about the following ...
    I have some own ExtractElements Python code which is from the old times and much less smart than ifcpatch but one thing is quite cool.
    Before it really creates a new ifcfile it does a BIMCollabSmartView and the result can easily be controlled. For ifcpatch we would have to use something more generic like bcf. means instead creating a new ifc it creates a bcf. With this bcf the result can be controlled in just a few seconds. On a new run the ifc does not even be loaded, just load the bcf controll run again as long as it fits, than create the ifc. This is how I do it with my ooold extractor and BIMCollabSmartView.

  • edited August 2023

    I am trying to use ifcpatch to create a mini-app in streamlit that extracts an object from an IFC using GUID:

            extracted_ifc = ifcpatch.execute({"input": ifc, "file": ifc, "recipe": "ExtractElements", "arguments": [ f"#{guid}"]})
    

    From what I see at the moment I can only pass an IfcEntity as an argument, is there any chance to pass a GUID instead? Or am I just passing GUID incorrectly?

  • edited August 2023

    @PeterPetersen said:
    I am trying to use ifcpatch to create a mini-app in streamlit that extracts an object from an IFC using GUID:

            extracted_ifc = ifcpatch.execute({"input": ifc, "file": ifc, "recipe": "ExtractElements", "arguments": [ f"#{guid}"]})
     
    

    From what I see at the moment I can only pass an IfcEntity as an argument, is there any chance to pass a GUID instead? Or am I just passing GUID incorrectly?

    All sorted, human error - it is f"{guid}" rather than f"#{guid}". Thanks for ifcpatch - it is simply brilliant!

    One more question - is ifcpatch going to be integrated in the ifcopenshell pip distribution? This would make it a lot easier for deployment on the web..

  • is ifcpatch going to be integrated in the ifcopenshell pip distribution?

    There are plans to. Would you like to help?

  • There are plans to. Would you like to help?

    Hi Moult, great to hear this will eventually be integrated! As for help - the will is there, but capacity isn't - at least not at the moment (work+PhD+family). I can imagine contributing once my PhD is finished - but this is at least a year away.

  • @PeterPetersen if you know Python, it isn't that hard. Take a look in the .github/workflows folder and you can copy paste from how we ship other PyPI builds. It would also help if you could file a bug to track this to bring awareness to it. Maybe someone else can help contribute.

    PeterPetersen
  • edited November 2023

    Hi I hope this is the right place to post this. I am attempting to upgrade a 2x3 to IFC 4 from a C# application. I have taken the simplest approach I can imagine by running the command from powershell, to verify I am running correctly. Once I have completed this I will add to my dll. I am receiving an error but can't make sense of why. Please see PowerShell commands and error below . I have also attached a screen shot of the directory I am running power shell from and the 2x3 file I am trying to upgrade.
    As I am working in C# I have mostly relied on Xbim. I have been unable to find any other resource to upgrade from 2x3 to IFC4. If there is another option for C# I would love to hear about it.
    Thank you,
    Jason

    Windows PowerShell
    Copyright (C) Microsoft Corporation. All rights reserved.
    
    Try the new cross-platform PowerShell https://aka.ms/pscore6
    
    PS D:\_AdvancedSteel\OneDrive_2023-10-09\JasonHolden\02SampleModel> python
    Python 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> the_path_of_ifcpatch = "C:/Users/jason/AppData/Local/Programs/Python/Python39/Lib/site-packages/ifcpatch/"
    >>> import sys
    >>> sys.path.append(the_path_of_ifcpatch)
    >>> import ifcpatch
    >>> import lark
    >>> ifcpatch.execute({
    ...     "input": "nclous_IFCexport.ifc",
    ...     "output": "P0042_01-IFC4-Copy.ifc",
    ...     "recipe": "Migrate",
    ...     "log": "ifcpatch.log",
    ...     "arguments": [".IfcWall"],
    ... })
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:\Users\jason\AppData\Local\Programs\Python\Python39\lib\site-packages\ifcpatch\__init__.py", line 76, in execute
        patcher = recipe.Patcher(args["input"], args["file"], logger, *args["arguments"])
    KeyError: 'file'
    >>>
    

  • I'm not aware of a C# solution to upgrade models unfortunately. Using IfcPatch is a great idea, you can also ship it as a standalone executable.

    The error is because you're not calling IfcPatch correctly: you're missing the "file" setting. You should call it like this:

    import ifcpatch
    
    output = ifcpatch.execute({
        "input": "input.ifc",
        "file": ifcopenshell.open("input.ifc"),
        "recipe": "Migrate",
        "arguments": ["IFC4"],
    })
    ifcpatch.write(output, "output.ifc")
    

    See the documentation: https://blenderbim.org/docs-python/ifcpatch.html

    I've just realised that our examples for the actual recipes are missing the file argument too https://blenderbim.org/docs-python/autoapi/ifcpatch/recipes/Migrate/index.html which is a bug. It's now been fixed https://github.com/IfcOpenShell/IfcOpenShell/commit/640341715c40af9917475409dc093854cf708575

    jason_holden
  • Thank you awesome. It works perfectly.

  • I can't use ifcpatch
    It's giving an error when importing. What may be the problem?


  • edited January 25

    Hi Zanoni, have you put the ifcpatch folder to python's site-packages folder? If yes, is it nested?
    You should have a folder structure like that on windows (or something similar on mac/linux):

Sign In or Register to comment.