Hypermesh Scripting - how to carry out boolean operations on groups of type SURFACE_ELEMENT (abaqus).

Peter VanWieren
Peter VanWieren Altair Community Member
edited December 2020 in Community Q&A

Hi,

I am seeking a method to generate new element face based surface definitions using Boolean operations where the element faces being operated on may come from either already defined groups (ABAQUS interface, card type SURFACE_ELEMENT) or the special group "^faces".   There are two issues:

First: I have not found a method in the API for referencing the particular faces in a consistent way.  Integers values for "^faces" can be retrieved with the commands below, however, the integers do not consistently relate to the same face in various calls to *findfaces.

*createmark elements 1 "^faces"

hm_getmark elements

Second: I searched for, but was unable to find, in the API documentation a way to retrieve a similar list of values from already defined "groups".  Can anyone direct me to where this is documented?

Thanks in advance.

Pete

P.S. I am quite new to scripting in hypermesh.

Answers

  • tinh
    tinh Altair Community Member
    edited December 2020

    Hi,

    For ^faces integer values , you must retrieve it everytime after invoke *findfaces (because *findfaces will delete the old ones and create new)

     

    To retrieve integer values from already defined 'groups' you can use below command:

    *createmark elems 1 "by group name" $name_of_the_group

    hm_getmark elems 1

  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020
    tinh said:

    Hi,

    For ^faces integer values , you must retrieve it everytime after invoke *findfaces (because *findfaces will delete the old ones and create new)

     

    To retrieve integer values from already defined 'groups' you can use below command:

    *createmark elems 1 "by group name" $name_of_the_group

    hm_getmark elems 1

    Tinh,

    Thank you for your help.  I was able to retrieve the integer values for an existing group using the commands you gave.   

    Since *findfaces has been used more than once, the integer values in the several groups need to be interpreted to be compared to those retrieved from another group or ^faces.  Is there any way to identify, for each integer, the element number and face ID it represents?

    Thanks

    Pete

  • tinh
    tinh Altair Community Member
    edited December 2020

    Hi, If your group refers to face's elems, i am sure you need to keep them (but *findfaces will delete them, and component that name starts with '^' is not export to FEM file)

    To keep face's elems, create new comps and move the elems to, or simply rename ^faces before calling *findfaces

    Example

    *findfaces ... (Face1)  *createmark elems 1 "by comp name" ^faces  .... -> retrieve and add to group  *renamecollector comps ^faces surf_elems_1  *findfaces ... (Face2)  ... ...

     

     

     

    (I edited because using cellphone will neglect all "new line \n" characters)

  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020

    Thank tinh.  Unfortunately in the ".hm" file I am working with now elements generated by *findfaces were not retained.  I would very much prefer that those who do our meshing tasks would not have to be careful to store ^faces as other components each time another surface is created.

    Internally hm still retains the information I am seeking to retrieve as when exporting the model I will get *SURFACE, TYPE=ELEMENT, followed by a list of the correct pairs of element labels and face labels for each group (despite ^faces being removed).   Does the API lack a way to access this information?

  • tinh
    tinh Altair Community Member
    edited December 2020

    Thank tinh.  Unfortunately in the ".hm" file I am working with now elements generated by *findfaces were not retained.  I would very much prefer that those who do our meshing tasks would not have to be careful to store ^faces as other components each time another surface is created.

    Internally hm still retains the information I am seeking to retrieve as when exporting the model I will get *SURFACE, TYPE=ELEMENT, followed by a list of the correct pairs of element labels and face labels for each group (despite ^faces being removed).   Does the API lack a way to access this information?

    Hi, I don't know Abaqus. API is not a problem, if you can do it on HM GUI, then API is applicable So please do it on GUI, and take screenshoot step by step including export model file, and show your steps here. We will consider then.
  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020
    tinh said:

    Hi, I don't know Abaqus. API is not a problem, if you can do it on HM GUI, then API is applicable So please do it on GUI, and take screenshoot step by step including export model file, and show your steps here. We will consider then.

    I can get the pairs of element and face labels using the GUI this way:

    1) show surface "A"

    image

    2) show surface "B"

    image

    3) show both A and B

    image

    4) export to file "x.inp".

    image

    Open "x.inp" in a text editor showing pairs of element labels and face ID's ( "S1", "S2", "S3",..) for each group.  The yellow integers on the left are line numbers in the text file, so two parts of the text file are shown split by about 250 lines.

    image

    At this point code could parse the "inp" file content to create a new surface derived by a boolean operation.  For example to generate a new surface with all faces in "A" that are not in "B".

    What I can't determine is how to identify by API queries of the hm database that surface "A" consists of these particular element and face pairs without exporting the ".inp" file and parsing the contents of it.

  • tinh
    tinh Altair Community Member
    edited December 2020

    Hi,

    ☺ I don't see any step creating ^faces !

    You said you are new to scripting HM so I think you misunderstand about "surface elems" with ^faces

    ^faces are normal 2d (quad, tria) elems that cover 3D, ^faces are generated by panel Tools>faces

    "surface elems" is a kind of pseudo element (i think), aim to define contact surface. In Hypermesh, "surface elems" is of config "slave". You can select them "by config" > slave...

    You will not see them in panel "elem types" > 2D&3D because it is not a structural elems.

     

    Comback to your problem, focus on boolean operations that you want to do A = A - B, forget *findfaces you can do like this:

    *createmark elems 1 "by group name" A B ; #please replace 'A', 'B' with your actual group names *clearmark elems 2 *elementtestconnectivity elements 1 2 2 *createmark elems 1 "by group name" A ; #please replace 'A' with your actual group name *markintersection elems 1 elems 2 if {[hm_marklength elems 1]} {    *deletemark elems 1 } *clearmark elems 2

     

     

  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020

    Hi,

    Yes, the question I am asking about is the definition of "surface elems".   In ABAQUS these are not called elements, but rather are selections of faces on solid or shell elements.  These can be used for contact but also for many other purposes that have nothing to do with contact - for example applying thermal boundary conditions, distributed loads, bolt pretension sections, etc,.   I am aware of only two ways to create this entity in the HM GUI; Using ^faces or importing a solver deck.

    I provided an example solver deck which contains only two hex elements (12 free faces).   The model defines "SURF_A" consisting of seven faces and "SURF_B" consisting of four faces.   In ABAQUS these are not additional quad elements.   

    Thank you for the example code above.  I tested it by importing the  solver deck below with the objective of creating a new surface "SURF_C" that has all faces in A that are not in B.  I have four questions:

     1) What type of test is elementtestconnectivity carrying out?  The documentation does not specify which invalid ways are being tested for.

     2) Using deletemark is a problem because the definition of SURF_A is altered, which is not desired.  Is there another approach that can be used?

     3) Does the HM API provide selection commands that correspond more directly to boolean operations: AND, OR, NOT, XOR?  If so what are they?

     4) What API command can create the new group "SURF_C" of type "surface elems" after the selection is established in mark 1 or mark 2?

    Thanks,

    *NODE
    111, 1.0, 0.0, 0.0
    211, 2.0, 0.0, 0.0
    311, 3.0, 0.0, 0.0
    411, 4.0, 0.0, 0.0
    121, 1.0, 0.7, 0.0
    221, 2.0, 0.7, 0.0
    321, 3.0, 0.7, 0.0
    421, 4.0, 0.7, 0.0
    112, 1.0, 0.0, 0.4
    212, 2.0, 0.0, 0.4
    312, 3.0, 0.0, 0.4
    412, 4.0, 0.0, 0.4
    122, 1.0, 0.7, 0.4
    222, 2.0, 0.7, 0.4
    322, 3.0, 0.7, 0.4
    422, 4.0, 0.7, 0.4
    *ELEMENT, TYPE=C3D8I, ELSET=ALL_ELEM
    500, 111, 211, 221, 121, 112, 212, 222, 122
    501, 411, 412, 422, 421, 311, 312, 322, 321
    *SURFACE, NAME=SURF_A
    500, S1
    500, S2
    500, S3
    500, S4
    501, S3
    501, S4
    501, S5
    *SURFACE, NAME=SURF_B
    500, S2
    500, S3
    501, S4
    501, S6
    **
    *MATERIAL, NAME=STEEL
    *ELASTIC
    210000, 0.3
    *SOLID SECTION, MATERIAL=STEEL, ELSET=ALL_ELEM
    **
    *STEP
    *STATIC
    *BOUNDARY
    111,1,3,0.0
    211,1,3,0.0
    121,1,3,0.0
    *END STEP

  • tinh
    tinh Altair Community Member
    edited December 2020

     

    Hi,

    Sorry i thought you want to update A = A - B

    Creating new C = A - B may use this flow:

    #select A and B *createmark elems 1 "by group name" A B ; #please replace 'A', 'B' with your actual group names *clearmark elems 2 #filter elems shared between A and B to mark 2 *elementtestconnectivity elements 1 2 2 #select A to mark 1 *createmark elems 1 "by group name" A ; #please replace 'A' with your actual group name #do A - (A sharing B) and put to mark 1 *markdifference elems 1 elems 2 if {[hm_marklength elems 1]} {    #mark 1 now is C but we need to find 3d elems to create new C    *findmark elems 1 1 1 elems 0 2    ... Now 3d elems are in mark 2    I don't remember commands to create interfaces    :D    Let's look for them in command.tcl file } *clearmark elems 2

     

     

    *elementtestconnectivity will find overlapping elems of A and B

    AND : *markintersection

    OR : *appendmark

    NOT: *createmark elems 1 "reverse"

    XOR: *marknotintersection

     

    Commands creating new interface are in command.tcl

  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020

    It is not urgent, feel free to wait to reply until you can edit on a computer rather than from a phone.

  • Peter VanWieren
    Peter VanWieren Altair Community Member
    edited December 2020

     

    Almost everything is in place, but alas the call to interfaceadd rejects the integers and SURF_C is empty.  My code for the two element model:

    # template should be ../feoutput/abaqus/standard.3d
    set template [hm_info templatefilename];

    # If group "SURF_C" exists, delete it
    *createmark groups 1
    *clearmark groups 1
    *createmark groups 1 "SURF_C"
    if { [hm_marklength groups 1] } {
    puts "Deleting the interface";
    *deletemark groups 1
    }

    # Create group "SURF_C" of type SURFACE_ELEMENT
    puts "Creating the interface SURF_C";
    *interfacecreate "SURF_C" 3 2 11
    puts "Creating the interface SURF_C";
    *createmark groups 2 "SURF_C"
    set jgroup [hm_getmark groups 2];
    *dictionaryload groups 2 $template "SURFACE_ELEMENT"
    *attributeupdateint groups $jgroup 139 2 2 0 1
    *attributeupdateint groups $jgroup 139 2 2 0 1
    *attributeupdateint groups $jgroup 328 2 2 0 0
    *attributeupdateint groups $jgroup 2806 2 2 0 0
    *attributeupdateint groups $jgroup 2575 2 2 0 0

    #select SURF_A and SURF_B
    *createmark elems 1 "by group name" SURF_A ;
    puts "mark1 elems: (SURF_A)";
    puts [ hm_getmark elems 1 ];

    *createmark elems 1 "by group name" SURF_B ;
    puts "mark1 elems: (SURF_B)";
    puts [ hm_getmark elems 1 ];

    *createmark elems 1 "by group name" SURF_A SURF_B ;
    puts "mark1 elems: (SURF_A AND SURF_B)";
    puts [ hm_getmark elems 1 ];

    #filter elems shared between SURF_A and SURF_B to mark 2
    *clearmark elems 2
    *elementtestconnectivity elements 1 2 2
    #
    puts "mark2 elems: (in BOTH SURF_A AND SURF_B) each face appears twice";
    puts [ hm_getmark elems 2 ];
    #
    # Do the boolen operation after placing SURF_A on mark1
    # AND : *markintersection
    # OR : *appendmark
    # NOT: *createmark elems 1 "reverse"
    # XOR: *marknotintersection
    *createmark elems 1 "by group name" SURF_A ;
    *markdifference elems 1 elems 2
    # #mark 1 now is C

    puts "mark1 elems: result";
    puts [ hm_getmark elems 1 ];

    # If the result is more than zero elements
    if { [ hm_marklength elems 1] } {

    # This fails to create SURF_C based on mark1
    *interfacedefinition "SURF_C" 0 "elem"
    puts "mark1 elems - final:";
    puts [ hm_getmark elems 1 ];
    *interfaceadd "SURF_C" 0 elements 1 0

    }

    *createmark groups 1 "SURF_A" "SURF_B";
    *createstringarray 2 "elements_on" "geometry_on";
    *hideentitybymark 1 1 2;

    # *clearmark elems 2

    puts "Finished";

     

    You'll notice "*findmark elems 1 1 1 elems 0 2" is omitted.  I tried several variants with it included and couldn't get it to work.  I notice that after the call mark1 is altered, and I'm concerned that may be unintended.

    I replaced the code inside "if ( [ hm_marklength elems 1 ] )" with the following and found that SURF_C will be populated with faces when mark1 has very similar contents.  Of course the integers are not those which we computed from preceding operations.  This worked without *findmark, but since 2D quads and tets by findfaces and I'm not expecting similar behavior. 

    Don't feel a need to answer quickly as this isn't urgent.  Thanks so much for your persistence in helping out.

    # This will create SURF_C with some faces - not from boolen operation
    *facesdelete
    *createmark elements 1 "displayed"
    *findfaces elements 1
    *interfacedefinition "SURF_C" 0 "elem"
    *createmark elements 1 516 520 522 524
    puts "mark1 elems - final:";
    puts [ hm_getmark elems 1 ];
    *interfaceadd "SURF_C" 0 elements 1 0

  • tinh
    tinh Altair Community Member
    edited December 2020

    Hi,

    we must find 3d elems and add them & their face nodes

    as you manipulate on panel Tools>interface

    I am modifying your code from "if { [hm_getmark elems 1 ] } {..."

    # template should be ../feoutput/abaqus/standard.3d set template [hm_info templatefilename];  # If group "SURF_C" exists, delete it *createmark groups 1 *clearmark groups 1 *createmark groups 1 "SURF_C" if { [hm_marklength groups 1] } { puts "Deleting the interface"; *deletemark groups 1 }  # Create group "SURF_C" of type SURFACE_ELEMENT puts "Creating the interface SURF_C"; *interfacecreate "SURF_C" 3 2 11 puts "Creating the interface SURF_C"; *createmark groups 2 "SURF_C" set jgroup [hm_getmark groups 2]; *dictionaryload groups 2 $template "SURFACE_ELEMENT" *attributeupdateint groups $jgroup 139 2 2 0 1 *attributeupdateint groups $jgroup 139 2 2 0 1 *attributeupdateint groups $jgroup 328 2 2 0 0 *attributeupdateint groups $jgroup 2806 2 2 0 0 *attributeupdateint groups $jgroup 2575 2 2 0 0  #select SURF_A and SURF_B *createmark elems 1 "by group name" SURF_A ; puts "mark1 elems: (SURF_A)"; puts [ hm_getmark elems 1 ];  *createmark elems 1 "by group name" SURF_B ; puts "mark1 elems: (SURF_B)"; puts [ hm_getmark elems 1 ];  *createmark elems 1 "by group name" SURF_A SURF_B ; puts "mark1 elems: (SURF_A AND SURF_B)"; puts [ hm_getmark elems 1 ];  #filter elems shared between SURF_A and SURF_B to mark 2 *clearmark elems 2 *elementtestconnectivity elements 1 2 2 # puts "mark2 elems: (in BOTH SURF_A AND SURF_B) each face appears twice"; puts [ hm_getmark elems 2 ]; # # Do the boolen operation after placing SURF_A on mark1 # AND : *markintersection # OR : *appendmark # NOT: *createmark elems 1 "reverse" # XOR: *marknotintersection *createmark elems 1 "by group name" SURF_A ; *markdifference elems 1 elems 2 # #mark 1 now is C  puts "mark1 elems: result"; puts [ hm_getmark elems 1 ];  # If the result is more than zero elements if { [ hm_marklength elems 1] } {    set code_with_big_comp {       #it is not simple to just add elems in mark 1 to C       #remember that C is just "slave" elems       #but actual interface C must refer to solid elems and its face nodes        #1. Get face nodes (all nodes of elems in mark 1 are face nodes)       set C_face_nodes [lsort -integer -unique [join [hm_getvalue elems mark=1 dataname=nodes]]]       #2. Find attached elems, put them to mark 2:       *findmark elems 1 1 1 elems 0 2       #3. Filter only 3d elems in mark 2 and put them to mark 1:       *createmark elems 1 "by config" 204 205 206 208       *markintersection elems 1 elems 2       #4. Add solid face to SURF_C:       eval *createmark nodes 1 $C_face_nodes       *interfaceaddsolidface "SURF_C" 0 1 1 30    }    #above code may work well with big comp that surf elems C is continuous (not divided into patches)    #in your example file, C is divided into patches, so we should add one by one solid face:    foreach SlaveElem [hm_getmark elems 1] {       set Face_nodes [hm_getvalue elems id=$SlaveElem dataname=nodes]       #it quite long to find one 3d elem that has nodes in Face_nodes       #and I suddently remember that from HM14 we can make duplicate entities       #so I think it is easier to make duplicate group A (call A') and rename A' to C       #then we can delete slave elems of C that overlapped by B !    } }  *clearmarkall 1 *clearmarkall 2  *createstringarray 2 "elements_on" "geometry_on"; *hideentitybymark 1 1 2;  # *clearmark elems 2  puts "Finished";
  • tinh
    tinh Altair Community Member
    edited December 2020

    Hi Peter,

    as above I said, we can use "Duplicate" function from version HM14

    The code finally is quite simple (I can look for hypermesh *command to do duplicate, but I prefer to use wrapper command, in this case it is an Itcl class named ::hmbr::Duplicate)

    Sample code:

    ::hmbr::Duplicate myDupObj set SURF_A_id [hm_getentityvalue groups SURF_A id 0 -byname] myDupObj perform [list [list groups $SURF_A_id]] focus .hmContainer rename myDupObj "" set dupA_id [hm_latestentityid groups] set dupA_name [hm_getentityvalue groups $dupA_id name 1 -byid] *renamecollector groups $dupA_name SURF_C *createmark elems 1 "by group name" SURF_C SURF_B *clearmark elems 2 *elementtestconnectivity elems 1 2 2 *createmark elems 1 "by group name" SURF_C *markintersection elems 1 elems 2 if {[hm_marklength elems 1]} {    *deletemark elems 1 } *clearmarkall 1 *clearmarkall 2 

     

    Tested on HM2017

    image