The Artificial Intelligence (AI) large language model (LLM) revolution is in full swing, impacting almost every aspect of the business world and many parts of our personal lives. I still cling to my desire to be a source of content for LLM, but I’m using it more and more every day.
I’m a heavy user of Adobe Firefly for image creation Also, since I don’t program much these days, when I do need a python script or a VBA routine for Excel, I pop into Microsoft CoPilot. I don’t use it to write content, I prefer to be the source of posts rather than a consumer for my writing. However, I leverage LLM to create some outlines, leverage it in my research, and often find it helpful to summarize what I write.
But, what about an obscure, specialist, niche programming language like APDL? Can you use a generative AI chatbot to create APDL code? Why yes, yes you can, sort of. As you will see, APDL is just different enough to trip the LLM up a bit.
To show this, I’m going to bring back my old classic “tower of test” model, run a modal analysis, then ask MS CoPilot Chat to write an APDL script that:
- Gets all the displacements at every node, X, Y, Z, and the total
- Normalizes each to a maximum total displacement of 1
- Writes the results to a text file
Then we will see how it works… and do a bit of debugging.
Which LLM Should You Use?
This is a very important question because many LLM’s out there, especially the free ones, add your prompts into their models. You need to make sure you are using a Generative AI LLM chat tool that keeps your data private to you. The best way to do that is to check out your company’s AI policy for LLMs. Are you even allowed to put product data into a prompt, even on a secure LLM service?
For this example, we are not dealing with company or customer data. We are making a generic APDL script. So you may be able to use the free version of ChatGPT, Claud, Gemini, CoPilot, or LLama. However, just to be safe, here at PADT, we use the Microsoft CoPilot Chat that comes with our business Microsoft 365 license. This version keeps your data secure and out of the model.
CoPilot Chat is the Microsoft version of ChatGPT, and it seems to have scraped Ansys, YouTube, and even PADT’s blog well. I think it is brilliant because if you ask it to recommend a book for learning Ansys APDL, it responds with PADT’s “Introduction to the Ansys Parametric Design Language.”
So let’s move forward with CoPilot Chat for this example.
Prompting an LLM for Ansys APDL Code
Before we get started, here are a few suggestions:
- There is no other “APDL” out there to confuse with, but just to be safe, I always refer to it as “Ansys APDL” in my prompt.
- I use the CoPilot chat that in the Microsoft 365 Web App to make sure I’m not using the consumer version which is not secure.
- I always start with a fresh session, then rename it so I can get to it later
- This can be an iterative process. As you can see below, I added and removed things as I went
Let’s dig in with a nice, long prompt describing what I want, poor grammar and no capitalizing mean nothing to an LLM. With a fresh session, I did my initial prompt:
write me an ansys apdl script that grabs all of the x, y, z, and total deflections of all of the nodes in my model for every mode in a modal analysis. normalize those displacement vectors to a maximum total deflection of 1. write the resulting values to a csv file
Sure, I can help with that! Below is an ANSYS APDL script that performs the tasks you described:
! Initialize parameters
*get,num_modes,active,,set,nsets
! Open CSV file for writing
*cfopen,deflections,txt
! Write header to CSV file
*cfwrite,'Node,X Deflection,Y Deflection,Z Deflection,Total Deflection'
! Loop over each mode
*do,mode,1,num_modes
set,mode
! Get the number of nodes
*get,num_nodes,node,,count
! Loop over each node
*do,node_id,1,num_nodes
! Get node number
nsel,s,node,,node_id
*get,node_num,node,,num,min
! Get deflections
*get,ux,node,node_num,u,x
*get,uy,node,node_num,u,y
*get,uz,node,node_num,u,z
! Calculate total deflection
total_defl = sqrt(ux**2 + uy**2 + uz**2)
! Normalize deflections
if (total_defl != 0) then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
endif
! Write deflections to CSV file
*cfwrite,node_num,ux,uy,uz,total_defl
*enddo
*enddo
! Close CSV file
*cfclose
This script will:
- Loop through each mode in the modal analysis.
- For each mode, it will loop through all nodes and retrieve their x, y, z deflections.
- Calculate the total deflection for each node.
- Normalize the deflections so that the maximum total deflection is 1.
- Write the node number and normalized deflections to a CSV file.
Feel free to adjust the script as needed for your specific model and analysis setup. If you have any questions or need further assistance, just let me know!
add to the script: store the node number with the maximum deflection of each mode in an array then write the contents of that array to a second file.
Sure! I’ll update the script to store the node number with the maximum deflection for each mode in an array and then write the contents of that array to a second file.
Here’s the updated script:
! Initialize parameters
*get,num_modes,active,,set,nsets
! Open CSV file for writing deflections
*cfopen,deflections,txt
! Write header to CSV file
*cfwrite,'Node,X Deflection,Y Deflection,Z Deflection,Total Deflection'
! Initialize array to store node numbers with maximum deflection
*dim,max_defl_nodes,array,num_modes
! Loop over each mode
*do,mode,1,num_modes
set,mode
! Get the number of nodes
*get,num_nodes,node,,count
! Initialize variables for tracking maximum deflection
max_defl = 0
max_node = 0
! Loop over each node
*do,node_id,1,num_nodes
! Get node number
nsel,s,node,,node_id
*get,node_num,node,,num,min
! Get deflections
*get,ux,node,node_num,u,x
*get,uy,node,node_num,u,y
*get,uz,node,node_num,u,z
! Calculate total deflection
total_defl = sqrt(ux**2 + uy**2 + uz**2)
! Normalize deflections
if (total_defl != 0) then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
endif
! Check for maximum deflection
if (total_defl > max_defl) then
max_defl = total_defl
max_node = node_num
endif
! Write deflections to CSV file
*cfwrite,node_num,ux,uy,uz,total_defl
*enddo
! Store node number with maximum deflection in array
max_defl_nodes(mode) = max_node
*enddo
! Close CSV file
*cfclose
! Open second file for writing maximum deflection nodes
*cfopen,max_deflection_nodes,txt
! Write header to second file
*cfwrite,'Mode,Max Deflection Node'
! Write contents of max_defl_nodes array to second file
*do,mode,1,num_modes
*cfwrite,mode,max_defl_nodes(mode)
*enddo
! Close second file
*cfclose
This updated script will:
- Track the node with the maximum deflection for each mode.
- Store these node numbers in an array.
- Write the contents of this array to a second file named
max_deflection_nodes.txt.
If you need any further modifications or have other questions, feel free to ask!
At this point, I realized that my deflection file needs to include the mode number and deflection, so I prompted to add that.
add the mode number and frequency when writing out the deflection at each node
Sure! I’ll update the script to include the mode number and frequency when writing out the deflection at each node. Here’s the updated script:
! Initialize parameters
*get,num_modes,active,,set,nsets
! Open CSV file for writing deflections
*cfopen,deflections,txt
! Write header to CSV file
*cfwrite,'Mode,Frequency,Node,X Deflection,Y Deflection,Z Deflection,Total Deflection'
! Initialize array to store node numbers with maximum deflection
*dim,max_defl_nodes,array,num_modes
! Loop over each mode
*do,mode,1,num_modes
set,mode
! Get the frequency of the current mode
*get,frequency,mode,mode,,freq
! Get the number of nodes
*get,num_nodes,node,,count
! Initialize variables for tracking maximum deflection
max_defl = 0
max_node = 0
! Loop over each node
*do,node_id,1,num_nodes
! Get node number
nsel,s,node,,node_id
*get,node_num,node,,num,min
! Get deflections
*get,ux,node,node_num,u,x
*get,uy,node,node_num,u,y
*get,uz,node,node_num,u,z
! Calculate total deflection
total_defl = sqrt(ux**2 + uy**2 + uz**2)
! Normalize deflections
if (total_defl != 0) then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
endif
! Check for maximum deflection
if (total_defl > max_defl) then
max_defl = total_defl
max_node = node_num
endif
! Write deflections to CSV file
*cfwrite,mode,frequency,node_num,ux,uy,uz,total_defl
*enddo
! Store node number with maximum deflection in array
max_defl_nodes(mode) = max_node
*enddo
! Close CSV file
*cfclose
! Open second file for writing maximum deflection nodes
*cfopen,max_deflection_nodes,txt
! Write header to second file
*cfwrite,'Mode,Max Deflection Node'
! Write contents of max_defl_nodes array to second file
*do,mode,1,num_modes
*cfwrite,mode,max_defl_nodes(mode)
*enddo
! Close second file
*cfclose
This updated script will:
Write the contents of this array to a second file named max_deflection_nodes.txt.
Include the mode number and frequency when writing out the deflection at each node.
Continue to track and store the node with the maximum deflection for each mode.
That is it. It took me maybe 45 seconds to generate that script, including time to check the code visually.
Testing our LLM Generated APDL Script
Let’s make sure it works. I’m going to be lazy and just run it in Mechanical APDL. I bring up my test model, run it, then paste in the script and….
It’s wrong! If you paid attention to the code, for modal results you need set,1,n not set,n.
And this is why creating code with LLMs is great, but you have to be careful!
So I changed set,mode to set, 1, mode and ran it again.
Yikes! If you have written APDL before, you know counting the commas is important. And they got it wrong. There is no space between mode and freq. So I fixed that and tried again.
And, another error. A divide by zero. But if I look at the output, I realize that there is a warning on the if statement. It created an if statement that didn’t match the unique syntax of APDL…
if (total_defl != 0) then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
endif
Should be:
*if,total_defl,ne,0,then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
*endif
Good old *if has stumbled users for decades, and now it confused this particular LLM.
If I make that fix, It runs fine and I get my files. But…
That just isn’t right. First off, it is not using formatting correctly for the header, so it is truncated. Then the lines for each node start with mode.
That is because it used *cfopen and *cfwrite, commands that are used for creating command files. They don’t write text files well. So you should be using *vwrite. Looks like ChatGPT didn’t read PADT’s article on “Writing Text Files with *vwrite“
So I changed the *cfwrite to *vwrite and added formatting. The deflection line now looks like this:
*vwrite,mode,frequency,node_num,ux,uy,uz,total_defl
(G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8)
And it works:
The node with the max deflection is still wrong. And I’ve run out of time so fixing that is left up to the reader. I know a copout.
Here is the script I ended up with. I also added a NALL and *del,all to clean things up, as good practice
! Initialize parameters
*get,num_modes,active,,set,nsets
! Open CSV file for writing deflections
*cfopen,deflections,txt
! Write header to CSV file
*cfwrite,Mode,Frequency,Node,X Deflection,Y Deflection,Z Deflection,Total Deflection
! Initialize array to store node numbers with maximum deflection
*dim,max_defl_nodes,array,num_modes
! Loop over each mode
*do,mode,1,num_modes
set,1,mode
! Get the frequency of the current mode
*get,frequency,mode,mode,freq
! Get the number of nodes
*get,num_nodes,node,,count
! Initialize variables for tracking maximum deflection
max_defl = 0
max_node = 0
! Loop over each node
*do,node_id,1,num_nodes
/out
! Get node number
nsel,s,node,,node_id
*get,node_num,node,,num,min
! Get deflections
*get,ux,node,node_num,u,x
*get,uy,node,node_num,u,y
*get,uz,node,node_num,u,z
! Calculate total deflection
total_defl = sqrt(ux**2 + uy**2 + uz**2)
! Check for maximum deflection
*if,abs(total_defl),gt,max_defl,then
max_defl = abs(total_defl)
max_node = node_num
*endif
! Normalize deflections
*if,total_defl,ne,0,then
ux = ux / total_defl
uy = uy / total_defl
uz = uz / total_defl
total_defl = 1
*endif
! Write deflections to CSV file
*vwrite,mode,frequency,node_num,ux,uy,uz,total_defl
(G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8,",",G16.8)
*enddo
! Store node number with maximum deflection in array
max_defl_nodes(mode) = max_node
*enddo
! Close CSV file
*cfclose
! Open second file for writing maximum deflection nodes
*cfopen,max_deflection_nodes,txt
! Write header to second file
*cfwrite,Mode,Max Deflection Node
! Write contents of max_defl_nodes array to second file
*do,mode,1,num_modes
*vlen,1
*vwrite,mode,max_defl_nodes(mode)
(G16.8,",",G16.8)
*enddo
! Close second file
*cfclose
*del,all
nall
Closing Thoughts on Using an AI LLM for APDL Scripting
I’ll be honest. When I started this post a few hours ago I was all, “let me show you how awesome LLMs are, they can even do APDL scripting!” But the truth is, its not there yet. I suspect that some of it is just the uniqueness of APLD (*if,val1,oper,val2,then vs. if(val1 == val2) then in most languages). And some of it could be poor prompting on my part. I may have been able to prompt it to use *vwrite instead of *cdwrite.
It certainly helped get me 90% there, very quickly. And some more common operations may work. If you don’t know APDL at all, it might be easier to start with a prompt. But I suspect that debugging won’t be easy if you don’t know the language well. If it is a programming language that millions of people use and post about, the model is probably big enough to work. But for a niche scripting language like APDL… well, you may have to buy our book.
So, in the end, I don’t recommend using an AI LLM right now for APDL. I will, however, now use this as an example of why you need to check the results of a Generative AI session. If I remember, I’ll try in a year or two, and see if it got better.
You must be logged in to post a comment.