How to extract named nodal selection sets from Nastran bdf input files

M
M Member, Employee Posts: 244
50 Answers 100 Comments 100 Likes Second Anniversary
✭✭✭✭
edited November 28 in General Language Questions

Nastran and Ansys APDL have some slightly different formats for input files but we can use python to translate inputs from NASTRAN to APDL.

For the bulk of the model data, an External Data system in Workbench can be used and then you have the model (but not the named nodal set selections).

The named nodal set selections are in the human readable .brd file in SET blocks.

SET 1 = 1,3,5,7,11,13,15,17,19,21,23,25,
        27,29,31,33,35,37,39,41,43,45,
...
        1001,1003,1005,1007,1009,1011
$HMSET  1        1 "some name"
$HMSETTYPE       1 "regular"
$Node Set: 2  Name: some other name
SET 2 = 1,...

To get out these SETS, a bit of creativity, patience and python is required. The original query was for large models with upwards of 200 million elements, so something reasonably efficient had to be tried.

I was testing on a limited number of nodes/elements and decided to try and find all the SET commands in the input file.

To find the close of the SET block, I just looked for lines that didn't have a comma at the end (see the sample input above).

So the preliminary search (later, to be optimized) finds the set start (SET) and end (no comma) and writes them to two lists, set_list and no_comma.

import time, tempfile

set_list = []
no_comma=[]
file_name = 'Mesh_0/mesh_0.bdf'
t1 = time.time()
with open(file_name,'r') as f:
    ctr = 0
    for line in f:
        if line[0:3] == 'SET':
            set_list.append(ctr)
        if line[-2:] != ',\n':
            no_comma.append(ctr)
        ctr+=1
t2 = time.time()

dt = round(t2-t1,2)
print('Time to get set data = : ' + str(dt) + ' seconds')

No comma has all lines ending without commas so it had to be corrected.
This was simply done by looping through the set_list and finding the next corresponding no_comma value in the no_comma list. That values gets written to the set_end list.

# get set pairs
set_end = []
for s in set_list:
    se = [i for i in no_comma if i > s][0]
    set_end.append(se)

And for actual programmers, yes, there are probably a 1000 better ways to do this.

After the start and end of the SET blocks were identified, the data has to be opened one more time to extract that data. This is written to memory as a dictionary with the dictionary keys being the names of the NASTRAN sets. This part was basically used to get the data into a useable form. Luckily the rows of data are uniform in the bdf files.

apdl_cm_data = {}    
with open(file_name,'r') as f:
    data = f.readlines()

    for start, end in zip(set_list,set_end):
        temp = []
        name = data[start-1].split('Name:')[-1].strip()
        print(name,start,end)
        for line_num in range(start,end+1):
            if line_num == start:
                line = data[line_num].split('=')[-1]
            else: 
                line = data[line_num]

            line = line.split(',')
            line = [i.strip() for i in line]
            line = [int(i) for i in line if i != '']
            temp = temp + line 
        apdl_cm_data[name] = temp

Writing the data to file for APDL read also was a bit of a challenge.

The nodes first need to be written to a parameter using the *DIM command in APDL. And there the limit of the number of values is 10, so you need to loop through the NASTRAN imported nodes in batches of 10 (or check if you have less than 10!) and use the appropriate index in the array name(n) command. ansys apdl documentation link
Then once the array parameter is complete, you loop through those nodes using the NSEL command to select them. Once the entire set is selected, you can create the component (name selection) using the CM command.

with open(r'D://cm.inp', 'w') as f:
    for key in apdl_cm_data:
        ctr=1
        data = apdl_cm_data[key]
        len_data = len(data)
        f.write('*DIM , ' + key + ', ARRAY , ' + str(len_data) + '\n')
        for sub_data in range(0,len(data),10):
            count = len_data - ctr
            if count > 10:
                count = ctr+9
            else:
                count = ctr + count - 1
            f.write(key + '(' + str(ctr) + ')=')
            [f.write(str(i)+',') for i in data[ctr:count]]
            f.write( str(data[count]) + '\n') 
            ctr+=10


        f.write('NSEL , S , , , ' + str(data[0]) + '\n')
        f.write('*DO , I , 2 , ' + str(len(data)) + '\n')
        f.write('NSEL , A , , , ' + key + '(I)\n')
        f.write('*ENDDO\n')
        f.write('CM , ' + key + ', NODE\n\n')

I include the APDL steps in one block because they need to be run that way.
I just wrote the cm.inp file to my D drive and that can be imported in APDL (File - Read Input from...) after you have a Workbench generated APDL input file for the rest of the model.

And that is how you can get your SET selections from a .bdf file to APDL