icon

Support Forum

Attribut für Kostengruppen - PythonPart [Gelöst]


Hallo,

ich habe das Video gefunden und war total begeistert, dass man das Attribut der Kostengruppen automatisch an das Bauteil dranschreiben kann (0:55-1:40 min).

https://www.youtube.com/watch?v=zfHkuLeHOfU

Daraufhin habe ich das Python-Part-Paket installiert.

Da ich das Attribut nicht in den Standard-Attibuten von Allplan gefunden habe, habe ich das Attribut "KG_DIN276" selber angelegt.

Die Formel
p:assignKG(@IFC Entity@;@IFC PredefinedType@;@Tragendes Bauteil@;@Außenliegend@) habe ich händisch abgetippt. Nach dem Ausführen ist leider eine Fehlermeldung, wie im Screenshot, erschienen.

Kann es vielleicht damit zusammenhängen, dass das Attribut @618@ - "Außenbauteil" bei uns die Bezeichnung "Außenliegend" hat?
Was habe ich falsch gemacht und wie kann ich es zum Funktionieren bringen?

Ich feue mich auf Eure hilfreichen Tipps!

Anhänge (1)

Typ: image/jpeg
99-mal heruntergeladen
Größe: 35,23 KiB

Lösung anzeigen Lösung verbergen

wichtig ist eine (am besten csv) Datenbank, in der die möglichen Kombinationen aufgelistet sind. An sich kann dafür die Excel-Datei, die mit dem PythonPart mitgeliefert wird als Grundlage dienen.

Aus meiner Sicht ist es ziemlich unsinnig, für das Ermitteln der Kostengruppe aus 4 Attributwerten eine Datenbank oder Excel-Datei zu bemühen!

Eine 4 stufige if-elif-else-Bedingung reicht völlig aus. Hier mal der Code für die Funktion assignKG:

def assignKG(IfcEntity,IfcType,LoadBearing,IsExternal):
    
    costGroup = "KG 000"
    
    if IfcEntity == "IfcFooting":
        if IfcType == "PILE_CAP":
            costGroup = "KG 323"
        else:
            costGroup = "KG 322"
    
    elif IfcEntity == "IfcWall":
        if LoadBearing != 0:
            if IsExternal == "ja":
                costGroup = "KG 331"
            else:
                costGroup = "KG 341"
        else:
            if IsExternal == "ja":
                costGroup = "KG 332"
            else:
                costGroup = "KG 342"
                
    elif IfcEntity == "IfcColumn":
        if LoadBearing != 0:
            if IsExternal == "ja":
                costGroup="KG 333"
            else:
                costGroup = "KG 343"
    
    elif IfcEntity == "IfcSlab":
        if LoadBearing != 0:
            if IsExternal == "ja":
                if IfcType == "BASESLAB":
                    costGroup = "KG 322"
                elif IfcType == "ROOF":
                    costGroup = "KG 361"
            else:
                costGroup = "KG 351"
                
    elif IfcEntity == "IfcRoof":
        costGroup = "KG 361"
      
    elif IfcEntity == "IfcBeam":
        if LoadBearing != 0:
            if IsExternal == "ja":
                if IfcType == "SPANDREL":
                    costGroup = "KG 331"
                else:
                    costGroup = "KG 361"
            else:
                if IfcType == "HOLLOWCORE" and LoadBearing == 0:
                    costGroup = "KG 355"
                else:
                    costGroup = "KG 351"

    elif IfcEntity == "IfcPile":
        costGroup="KG 323"
    
    elif IfcEntity == "IfcDoor":
        if IsExternal == "ja":
            if IfcType == "TRAPDOOR":
                costGroup="KG 362"
            else:
                costGroup="KG 334"
        else:
            if IfcType == "TRAPDOOR":
                costGroup="KG 352"
            else:
                costGroup="KG 344"
            
    elif IfcEntity == "IfcWindow":
        if IsExternal == "ja":
            if IfcType == "SKYLIGHT" or IfcType == "LIGHTDOME":
                costGroup="KG 362"
            else:
                costGroup="KG 334"
        else:
            costGroup="KG 344"
    
    elif IfcEntity == "IfcCovering":
        if IsExternal == "ja":
            if IfcType == "FLOORING":
                costGroup = "KG 324"
            elif IfcType == "CLADDING" or IfcType == "USERDEFINED" or IfcType == "NOTDEFINED":
                costGroup = "KG 335"
            elif IfcType == "INSULATION" or IfcType == "MEMBRANE":
                costGroup = "KG 325"
            elif IfcType == "ROOFING":
                costGroup = "KG 363"
        else:
            if IfcType == "FLOORING" or IfcType == "SKIRTINGBOARD":
                costGroup = "KG 353"
            elif IfcType == "CEILING":
                costGroup = "KG 354"
            else:
                costGroup = "KG 345"
                
    elif IfcEntity == "IfcCurtainWall":
        if IsExternal == "ja":
            costGroup = "KG 337"
        else:
            costGroup = "KG 346"
            
    elif IfcEntity == "IfcShadingDevice":
        if IsExternal == "ja":
            if IfcType == "AWNING":
                costGroup = "KG 361"
            else:
                costGroup = "KG 338"
        else:
            costGroup = "KG 347"
            
    elif IfcEntity == "IfcMember":
        if IfcType == "COLLAR" or IfcType == "POST" or IfcType == "PURLIN" or IfcType == "RAFTER":
            costGroup = "KG 361"
            
    elif IfcEntity == "IfcRailing":
        if IsExternal == "ja":
            costGroup = "KG 339"
        else:
            costGroup = "KG 349"
            
    elif IfcEntity == "IfcStair":
        costGroup = "KG 351"
        
    elif IfcEntity == "IfcRamp":
        costGroup = "KG 351"
            
    elif IfcEntity == "IfcChimney":
        costGroup = "KG 399"
        
    elif IfcEntity == "IfcFurniture":
        costGroup = "KG 610"
        
    return costGroup

Diese Funktion ergibt dasselbe, wie ein Look-Up in der Excel oder Datenbank.

Aber: Aus meiner Sicht sind die Kriterien IfcEntity, IfcType, LoadBearing, IsExternal die Falschen.
Das Klassifizieren mit diesen Kriterien setzt voraus, dass diese korrekt an allen Objekten vorhanden sind bzw gesetzt wurden.
Ein Test mit dem Allplan Hello!-Projekt zeigt, dass diese Attribut-Werte von der Formel nicht korrekt erkannt werden.
Beispielsweise wurde die IfcEntity einer Wandschicht mit "IfcWall" angezeigt, in Script kam aber "undefiniert" an!
Dazu habe ich eine Testfunktion readAttr benutzt:

def readAttr(IfcEntity,IfcType,LoadBearing,IsExternal):
    return IfcEntity+IfcType+str(LoadBearing)+str(IsExternal)

Diese bringt folgendes Ergebnis für die Wand (s.attr_gesamtwand.png) und für die Wandschicht (s.attr_wandschicht.png)
Bei der Wandschicht kommt statt "IfcWall" "undefiniert" an!
Erst nach Wechseln zu "IfcBeam" und zurück zu "IfcWall" wurde diese auch in das Script "reingereicht".
@Allplan
Das ist ein gravierender Fehler, der behoben werden sollte.

Anhänge (3)

Typ: image/png
19-mal heruntergeladen
Größe: 97,39 KiB
Typ: image/png
16-mal heruntergeladen
Größe: 109,09 KiB
Typ: application/zip
3-mal heruntergeladen
Größe: 914,00 B
11 - 20 (21)

Hallo Florian,

vielen Dank für den Tipp. Ich habe es aber mittlerweile hinbekommen. Im Prinzip waren es nur Formatierungsfehler mit den Leerzeilen und Einrückungen im Pythoncode in der functions.py Die Fehlermeldungen die Allplan ausspuckt sind leider völlig zufällig und kein bisschen hilfreich, daher dachte ich erst Allplan findet die functions.py nicht...

Hallo Andreas,
Freut mich, dass du eine Lösung finden konntest.
Zu den Meldungen stimme ich dir voll zu. Die Fehlermeldungen könnten aussagekräftiger sein für die "DIY Programmierung", die man als Allplan-Anwender macht.
Musste mich auch Attribut für Attribut vortasten, um zur Lösung zu kommen.

Viele Grüße
Florian

LinkedIn-Profil

www.vollack.de

wichtig ist eine (am besten csv) Datenbank, in der die möglichen Kombinationen aufgelistet sind. An sich kann dafür die Excel-Datei, die mit dem PythonPart mitgeliefert wird als Grundlage dienen.

Aus meiner Sicht ist es ziemlich unsinnig, für das Ermitteln der Kostengruppe aus 4 Attributwerten eine Datenbank oder Excel-Datei zu bemühen!

Eine 4 stufige if-elif-else-Bedingung reicht völlig aus. Hier mal der Code für die Funktion assignKG:

def assignKG(IfcEntity,IfcType,LoadBearing,IsExternal):
    
    costGroup = "KG 000"
    
    if IfcEntity == "IfcFooting":
        if IfcType == "PILE_CAP":
            costGroup = "KG 323"
        else:
            costGroup = "KG 322"
    
    elif IfcEntity == "IfcWall":
        if LoadBearing != 0:
            if IsExternal == "ja":
                costGroup = "KG 331"
            else:
                costGroup = "KG 341"
        else:
            if IsExternal == "ja":
                costGroup = "KG 332"
            else:
                costGroup = "KG 342"
                
    elif IfcEntity == "IfcColumn":
        if LoadBearing != 0:
            if IsExternal == "ja":
                costGroup="KG 333"
            else:
                costGroup = "KG 343"
    
    elif IfcEntity == "IfcSlab":
        if LoadBearing != 0:
            if IsExternal == "ja":
                if IfcType == "BASESLAB":
                    costGroup = "KG 322"
                elif IfcType == "ROOF":
                    costGroup = "KG 361"
            else:
                costGroup = "KG 351"
                
    elif IfcEntity == "IfcRoof":
        costGroup = "KG 361"
      
    elif IfcEntity == "IfcBeam":
        if LoadBearing != 0:
            if IsExternal == "ja":
                if IfcType == "SPANDREL":
                    costGroup = "KG 331"
                else:
                    costGroup = "KG 361"
            else:
                if IfcType == "HOLLOWCORE" and LoadBearing == 0:
                    costGroup = "KG 355"
                else:
                    costGroup = "KG 351"

    elif IfcEntity == "IfcPile":
        costGroup="KG 323"
    
    elif IfcEntity == "IfcDoor":
        if IsExternal == "ja":
            if IfcType == "TRAPDOOR":
                costGroup="KG 362"
            else:
                costGroup="KG 334"
        else:
            if IfcType == "TRAPDOOR":
                costGroup="KG 352"
            else:
                costGroup="KG 344"
            
    elif IfcEntity == "IfcWindow":
        if IsExternal == "ja":
            if IfcType == "SKYLIGHT" or IfcType == "LIGHTDOME":
                costGroup="KG 362"
            else:
                costGroup="KG 334"
        else:
            costGroup="KG 344"
    
    elif IfcEntity == "IfcCovering":
        if IsExternal == "ja":
            if IfcType == "FLOORING":
                costGroup = "KG 324"
            elif IfcType == "CLADDING" or IfcType == "USERDEFINED" or IfcType == "NOTDEFINED":
                costGroup = "KG 335"
            elif IfcType == "INSULATION" or IfcType == "MEMBRANE":
                costGroup = "KG 325"
            elif IfcType == "ROOFING":
                costGroup = "KG 363"
        else:
            if IfcType == "FLOORING" or IfcType == "SKIRTINGBOARD":
                costGroup = "KG 353"
            elif IfcType == "CEILING":
                costGroup = "KG 354"
            else:
                costGroup = "KG 345"
                
    elif IfcEntity == "IfcCurtainWall":
        if IsExternal == "ja":
            costGroup = "KG 337"
        else:
            costGroup = "KG 346"
            
    elif IfcEntity == "IfcShadingDevice":
        if IsExternal == "ja":
            if IfcType == "AWNING":
                costGroup = "KG 361"
            else:
                costGroup = "KG 338"
        else:
            costGroup = "KG 347"
            
    elif IfcEntity == "IfcMember":
        if IfcType == "COLLAR" or IfcType == "POST" or IfcType == "PURLIN" or IfcType == "RAFTER":
            costGroup = "KG 361"
            
    elif IfcEntity == "IfcRailing":
        if IsExternal == "ja":
            costGroup = "KG 339"
        else:
            costGroup = "KG 349"
            
    elif IfcEntity == "IfcStair":
        costGroup = "KG 351"
        
    elif IfcEntity == "IfcRamp":
        costGroup = "KG 351"
            
    elif IfcEntity == "IfcChimney":
        costGroup = "KG 399"
        
    elif IfcEntity == "IfcFurniture":
        costGroup = "KG 610"
        
    return costGroup

Diese Funktion ergibt dasselbe, wie ein Look-Up in der Excel oder Datenbank.

Aber: Aus meiner Sicht sind die Kriterien IfcEntity, IfcType, LoadBearing, IsExternal die Falschen.
Das Klassifizieren mit diesen Kriterien setzt voraus, dass diese korrekt an allen Objekten vorhanden sind bzw gesetzt wurden.
Ein Test mit dem Allplan Hello!-Projekt zeigt, dass diese Attribut-Werte von der Formel nicht korrekt erkannt werden.
Beispielsweise wurde die IfcEntity einer Wandschicht mit "IfcWall" angezeigt, in Script kam aber "undefiniert" an!
Dazu habe ich eine Testfunktion readAttr benutzt:

def readAttr(IfcEntity,IfcType,LoadBearing,IsExternal):
    return IfcEntity+IfcType+str(LoadBearing)+str(IsExternal)

Diese bringt folgendes Ergebnis für die Wand (s.attr_gesamtwand.png) und für die Wandschicht (s.attr_wandschicht.png)
Bei der Wandschicht kommt statt "IfcWall" "undefiniert" an!
Erst nach Wechseln zu "IfcBeam" und zurück zu "IfcWall" wurde diese auch in das Script "reingereicht".
@Allplan
Das ist ein gravierender Fehler, der behoben werden sollte.

Anhänge (3)

Typ: image/png
19-mal heruntergeladen
Größe: 97,39 KiB
Typ: image/png
16-mal heruntergeladen
Größe: 109,09 KiB
Typ: application/zip
3-mal heruntergeladen
Größe: 914,00 B

Der oben angedeutete Fehler ist leider noch gravierender:

Im Dialog "Attribute modifizieren" wird das Formelattribut der Wandschicht falsch ausgewertet, wenn man eines der Eingangsattribute der Formel ändert.
Beispielsweise mit obiger Test-Funkion readAttr(IfcEntity,IfcType,LoadBearing,IsExternal) werden nach Ändern des Attributes IfcEntity auf "IfcBeam"
die Attribut-Werte der Gesamtwand in die Funktion "reingereicht"!

Anhänge (1)

Typ: video/mp4
4-mal heruntergeladen
Größe: 2,15 MiB

Zitiert von: Nemo

Aus meiner Sicht ist es ziemlich unsinnig, für das Ermitteln der Kostengruppe aus 4 Attributwerten eine Datenbank oder Excel-Datei zu bemühen!
Eine 4 stufige if-elif-else-Bedingung reicht völlig aus. Hier mal der Code für die Funktion assignKG:

...

hands on Idee, würde auch gehen, sehe ich aber nicht unbedingt als Lösung für die Eingangsfrage, die auf das Video von Allplan abzielt.
der Charme per Excel/csv: Das Ergänzen von fehlenden Bauteilzuordnungen kann ein jeder machen. Auf die funtctions.py kann ich die Kollegen nicht loslasse ;)

Ich war eingangs auch kein großer Fan der Lösung eines zusätzlichen Attributs in Allplan nur für die automatische Zuweisung der Kgr, mittlerweile kann ich dem was abgewinnen, wenn es für eine schnelle Darstellung in Allplan geht UND um zu prüfen, ob in den Bauteilen auch die ifc-Standard Attribute vorhanden und korrekt zugewiesen sind.
Falls eine Unstimmigkeit mit der Datenbank kommt, gibt das Script "KG nicht gefunden" aus.
Das Thema mit dem durchschleifen sollte dringend gelöst werden. die Anzeige der KGr funktioniert in den Schichten auch nicht so zuverlässig wie in der Gesamtwand. Ich vermute, dass es daran liegt.

Anbei mal mein Script, gerne ohne gewähr verwenden ;)
die csv ist einfach aus der excel Datei von Allplan zusammenkopiert. auch da keine Garantie auf Vollständigkeit.

die csv habe ich in das gleiche Verzeichnis wie die functions.py gelegt.
wie gesagt, ist durch try and error entstanden und ich bin wahrlich kein python Experte!

import csv

def assignKG(ifc_entity, ifc_predefined_type, tragendes_bauteil, aussenliegend):
    csv_path = r"HIER ALLPLAN STD PFAD EINGEBEN\Scripts\Kostengruppen.csv"

    # Checkbox-Wert für tragendes Bauteil übersetzen
    tragend_map = {"1.0": "ja", "0.0": "nein"}
    tragend_wert = tragend_map.get(str(tragendes_bauteil).strip(), "").lower()

    try:
        with open(csv_path, newline='', encoding='utf-8') as file:
            reader = csv.reader(file, delimiter=';')
            for row in reader:
                if len(row) < 5:
                    continue
                kostengruppe = row[0].strip()
                csv_entity = row[1].strip()
                csv_type = row[2].strip()
                csv_tragend = row[3].strip().lower()
                csv_aussen = row[4].strip().lower()

                if (csv_entity == ifc_entity.strip() and
                    csv_type == ifc_predefined_type.strip() and
		    csv_aussen == aussenliegend and                   
		    csv_tragend == tragend_wert and
                    csv_aussen == aussenliegend):
                    return kostengruppe

        return "KG nicht gefunden"
    except FileNotFoundError:
        return "CSV fehlt"

Viele Grüße
Florian

LinkedIn-Profil

www.vollack.de

Anhänge (1)

Typ: text/plain
1-mal heruntergeladen
Größe: 6,64 KiB

Echt jetzt, Du willst ernsthaft bei jedem Aufruf der Formel-Funktion:
-eine csv-Datei vom Server laden und parsen
-und jede Zeile nach Gleichheit der Attribut-Werte durchsuchen

Die oben fett geschriebenen Funktionen sind Performance-Killer!

Hast Du mal versucht, im Objekt-Manager nach dem Formel-Attribut zu sortieren, und dann ein "Refresh" gemacht.
Die Zeit, die dies dauert, würde mich mal interessieren.

Die "csv-Tabelle" funktioniert auch nur, wenn alle 4 Attribute vorhanden sind.
z.B. eine IfCWall ohne IfcPredefined_Type wird nicht erkannt, egal ob tragend und außenliegend vorhanden sind.
Bei der if-elif-else-Lösung wird hingegen nur nach den logisch wirklich benötigten Attributen klassifiziert.
Und: Wenn man in jedem Fall ein else: am Ende jeder if-Verzweigung hat, ist man auch sicher, dass alle vorkommenden Fälle von Eingabe-Werten "abgedeckt" sind.

Nur mal so: Python (ohne Datei-Öffnen und Parsen und Durchsuchen) ist schon ca. 200-mal langsamer als nativer C++-Code!
Das ist auch der Grund, warum man bei der grafischen Überschreibung vermutlich nie ein Python-Script verwenden (können) wird.

Ich denke, man könnte die Kostengruppe einzig und alleine unter Verwendung der Allplan-Eigenschaften Objekt-Typ, Nachbarschaft (liegt Raum beidseitig an) , tragendes Bauteil und ggf. Schichtanzahl der Wand- Decken- und Dachhautschichten herausfinden. Die Kostengruppe ist eigentlich nur für die Mengen- und Kostenermittlung in LP3-6 interessant. Das ist also ganz abgekoppelt vom BIM-Workflow und den Ifc-Attributen (IfcEntity und IfcPredefined_Type sind dafür nicht notwendig.)

hahaha, ne hätte wohl mehr im konjunktiv schreiben sollen.
ich will davon gar nichts, weder das eine noch das andere. was ich möchte, dass die Frage vom OP beantwortet ist.
Wir lösen das anders, nicht in Allplan.
Mir geht es darum es zu verstehen und ggf. Möglichkeiten und Wege zu sehen, die bei anderen Fällen unter umständen hilfreich sein könnten.

Viele Grüße
Florian

LinkedIn-Profil

www.vollack.de

Hi zusammen, wir sind dankbar um jeden Hinweis und es ist ja nicht schlecht wenn mehrere Wege nach Rom führen... wir würden halt nur gern ankommen

Wir haben es über diesen Weg versucht, wie Andi schrieb und ja es ist die Gefahr der nicht belegten Attribute.
Eine Formelfunktion wäre mir ja auch schon recht.

Nemo: wir haben im Tragwerksmodell leider keine Räume. Die Kostengruppe wird von uns verlangt im BIM-Projekt.
Wie machen es denn die ganzen Allplan-Architekten?
Heißt wir probieren es über die Formel?

Danke Euch
Jana

Für ein Tragwerksmodell kann man das Script sogar noch vereinfachen!

Theoretisch kommen ja nur folgende Werte für IfcEntity in Frage:
IfcFooting
IfcWall
IfcColumn
IfcBeam
IfcSlab
IfcPile
IfcStair
IfcRamp

Alle anderen kann man aus der Funktion rausschmeißen.
Ebenso kann als Kostengruppe ja nur vorkommen:
KG 312
KG 321
KG 322
KG 323
KG 331
KG 333
KG 341
KG 342 (falls Mauerwerk und Nachweis erforderlich und vereinbart)
KG 343
KG 351
KG 361

Alle "Ergebnisse" mit anderen Kostengruppen können ebenfalls entfallen.

Warum gibt es keine Funktion im CAD, für so etwas wichtiges?
Anstatt dessen gibt es ein Phytonpart welches ein „normaler User“ nicht ans Laufen bekommt. Geht es den grundsätzlich nicht einfacher?

Gruß!
Jürgen

Allplan Ingenieurbau V10 bis V2025

11 - 20 (21)