The billboard pillar diameter optimization using Fidesys Python API

To carry out the optimization calculation, it is necessary that the following conditions are met:

  • Installed Python v.3.8 or higher;
  • Installed vtk library for Python;
  • Installed numpy library for Python.

To meet these conditions, you must do the following::

  • Download Python 3.8 or higher from python.org and install.
  • Open the Windows command line (cmd.exe) and write:
    pip3 install numpy (then press Enter and let the installation complete);
    pip3 install vtk (then press Enter and let the installation complete).

After all the necessary steps have been completed, you can start solving the problem.

The problem of optimization of the diameter of the base of a billboard pillar, loaded with a wind load, is considered.

Geometry Creation

1. Create a brick.

Select volume geometry generation section on Command Panel (Mode — Geometry, Entity — Volume, Action — Create).

From the list of geometric primitives, select Brick.

Set the following parameters:

  • X (width): 20;
  • Y (heigtht): 0.5;
  • Z (depth): 10;

Click Apply.

Then the volume needs to be moved.

Go to (Mode — Geometry, Entity — Volume, Action — Transform).

Select Move from the list of operations.

Set the following parameters:

  • Volume ID's: 1;
  • Method: Distance
  • X Distance: 0;
  • Y Distance: 0;
  • Z Distance: 30.

Click Apply.

2. Create a frusto-cone pillar.

Go to (Mode — Geometry, Entity — Volume, Action — Create).

Select Cone from the list of geometric primitives.

Set the following parameters:

  • Height: 25;
  • Top radius: 0.25;
  • Circular;
  • Radius: 0.3.

Click Apply.

Next, the pillar must be moved.

Go to (Mode — Geometry, Entity — Volume, Action — Transform).

Select Move from the list of operations.

Set the following parameters:

  • Volume ID's: 2;
  • Method: Distance ;
  • X Distance: 0;
  • Y Distance: 0;
  • Z Distance: 12.5.

Click Apply.

3. Create common surfaces to generate the correct mesh.

Go to (Mode — Geometry, Entity — Volume, Action — Imprint and Merge).

Select Imprint/Merge Volumes from the list of operations.

Set the following parameters:

  • Volume ID's: all

Click Apply.

Meshing

1. Create a mesh.

Go to (Mode — Mesh, Entity — Volume, Action — Mesh).

Select Tetmesh from the list of algorithms.

Set the following parameters:

  • Select volumes: all

Click Mesh.

If everything was done correctly, you will see a model like this:

Specifying the material

1. Create the material.

Go to (Mode — Material, Entity — Materials Management).

In the Material Management window, drag&drop "Steel" from the third column to the second.

Click Apply.

2. Create a block.

Go to (Mode — Blocks, Entity — Block, Action — Add).

Select Volume in the Entity List.

Set the following parameters:

  • Entity ID's: all

Click Apply.

3. Set the block properties.

Go to (Mode — Blocks, Entity — Block, Action — Block properties/parameters).

Set the following parameters:

  • Block ID's: 1
  • Material: Steel;
  • Coordinate system: Global Cartesian;
  • Категория: Solid;
  • Order: 1.

Click Apply.

Setting boundary conditions

1. Fix all displacements of the surface of the base of the pillar

Go to (Mode — Boundary Conditions, Entity — Displacement, Action — Create).

Set the following parameters:

  • Entity list: Surface;
  • Entity ID's: 8;
  • Degrees Of Freedom: All;
  • DOF Value: 0.

Click Apply.

2. Set the distributed wind force on the billboard surface to p = 230 N/m^2.

Go to (Mode — Boundary Conditions, Entity — Distributed force, Action — Create).

Select Surface from the Entity List.

Set the following parameters:

  • Entity ID(s): 3;
  • Force type: Distributed Force;
  • Force: 230;
  • Direction Vector: (X: 0, Y: 1, Z: 0).

Click Apply.

3. Add gravity.

Go to (Mode — Boundary Conditions, Entity — Gravity, Action — Create).

Select Global from the Entity List.

Set the following parameters:

  • Directions: Z -9.81.

Click Apply.

Preparing for calculation

1. Set the calculation settings.

Go to (Mode — Calculation Settings, Calculation settings — Static, Static — General).

Set the following parameters:

  • Dimensions: 3D;
  • Model: Elasticity.

Click Apply.

Extracting and Transforming of the Script

1. Extract the model script from History.

Go to the Command line and switch the tab to "History" , where you will see the script of the model you generated:

reset
brick x 20 y 0.5 z 10
move Volume 1  x 0 y 0 z 30 include_merged 
create frustum height 25 radius 0.25 top 0.25
move Volume 2 x 0 y 0 z 12.5 include_merged 
undo group begin
imprint volume all 
merge volume all 
undo group end
volume all scheme tetmesh
mesh volume all
create material 1 from 'Steel'
set duplicate block elements off
block 1 add volume all
block 'Block 1' material 1 cs 1 element solid order 1
create displacement  on surface 8  dof all fix  
create distributed force on surface 3  force value 230 moment value 0 direction 0 1 0 specific
create gravity global
modify gravity 1 dof 3 value -9.81
analysis type static elasticity dim3

Right-click anywhere on the command line and select Select All , then right-click the selected script again and select Copy .

This is how you copied the script to the clipboard.

2. Convert the script to Python syntax.

Open the Journal Editor and paste the script you copied earlier into its window.

Convert the script to Python syntax via Tools - Translate - Python.

If everything is done correctly, then you will get the following script in the window:

Copy the resulting Python script from the Journal Editor.

Create and run a Python script

1. Create a Python script file.

Start Python IDLE, select File - New File from the menu, and a window for editing the script will open.

2. Copy and paste the script below into a blank window that opens.

This Python script already contains the portion of the Fidesys model script that we got earlier. The place where the Fidesys model script is inserted is marked with appropriate comments.

Please note that the bottom diameter of the pillar is varied by modifying of the cone creating command:

- the initial view of the command:  fidesys.cmd("create frustum height 25 radius 0.25 top 0.25")

- view of the changed command:  fidesys.cmd("create frustum height 25 radius "+str(r)+"top 0.25").

Inserting "+str(r)+" adds a radius value to the text command break.

Script for Fidesys 4.1:

import vtk        # Library for working with output data
from vtk.util.numpy_support import vtk_to_numpy # Library for converting results
import sys        # System library
import os         # System library
        
fidesys_path = r'C:\Program Files\Fidesys\CAE-Fidesys-4.1' # Location of Fidesys
base_dir = os.path.dirname(os.path.abspath(__file__))      # Directory where the script is located
pvd_file = os.path.join(base_dir, '1.pvd') # Results Links File
prep_path = os.path.join(fidesys_path, 'preprocessor', 'bin')    # Directory where the preprocessor is
os.environ['PATH'] += prep_path  # Adding preprocessor path to PATH
sys.path.append(prep_path)       # Adding preprocessor path to PATH

import cubit                     # Preprocessing library
import fidesys                   # Library of Fidesys

cubit.init([""])                 # Initializing the preprocessor
fc = fidesys.FidesysComponent()  # Create a required Fidesys fc component
fc.initApplication(prep_path)    # Initializing the path to the preprocessor
fc.start_up_no_args()            # Launch of the required Fidesys fc component

r = 0.25           # Initial bottom radius of the pillar
print("Initial bottom diameter: ", 2*r)  # Output to the data console - the initial value of the diameter

isOptimized = False  # Initially False - initial construction is not optimized
iteration = 1           # Initial value of the counter of passes (iterations)
while isOptimized == False: # The loop repeats until the condition isOptimized == True
    print("Iteration № ",iteration) # Write to the console which iteration
    overstressed = [] # Create an empty array to fill with overstressed nodes
    
    # ---------Start script from Fidesys-------------
    fidesys.cmd('reset')
    fidesys.cmd('brick x 20 y 0.5 z 10')
    fidesys.cmd('move Volume 1  x 0 y 0 z 30 include_merged ')
    fidesys.cmd("create frustum height 25 radius "+str(r)+"top 0.25")
    fidesys.cmd('move Volume 2 x 0 y 0 z 12.5 include_merged ')
    fidesys.cmd('undo group begin')
    fidesys.cmd('imprint volume all ')
    fidesys.cmd('merge volume all ')
    fidesys.cmd('undo group end')
    fidesys.cmd('volume all scheme tetmesh')
    fidesys.cmd('mesh volume all')
    fidesys.cmd('create material 1 from \'Steel\'')
    fidesys.cmd('set duplicate block elements off')
    fidesys.cmd('block 1 add volume all')
    fidesys.cmd('block \'Block 1\' material 1 cs 1 element solid order 1')
    fidesys.cmd('create displacement  on surface 8  dof all fix  ')
    fidesys.cmd('create distributed force on surface 3  force value 230 moment value 0 direction 0 1 0 specific')
    fidesys.cmd('create gravity global')
    fidesys.cmd('modify gravity 1 dof 3 value -9.81')
    fidesys.cmd('analysis type static elasticity dim3')
    # ---------End script from Fidesys-------------
        
    output_pvd_path = os.path.join(base_dir + "\\" + "1.pvd")       # We declare the directory and the save file
    print("strarting calculation to " + output_pvd_path)            # We output the directory and the save file to the console
    fidesys.cmd("calculation start path '" + output_pvd_path + "'") # We ask Fidesys to start the calculation in the specified directory
        
    print("                  ")
    print("Calculation completed successfully!")
    print("                  ")
    reader = vtk.vtkXMLUnstructuredGridReader()                             # Connect the reader
    print("Reading the results from ",str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Writes where we get the results from
    filename = os.path.join(str(base_dir)+r"\1\case1_step0001_substep0001.vtu") # Specifying the path to the file
    reader.SetFileName(filename)                                            # We connect the path to the reader and read
    reader.Update()                                                         # Needed because of GetScalarRange
    grid = reader.GetOutput()                                               # We take the output
    point_data = grid.GetPointData()                                        # We collect data for points
    arrayOfStress = vtk_to_numpy(point_data.GetArray("Stress")) # Reading stresses from the array of results
    node_id = vtk_to_numpy(point_data.GetArray("Node ID"))      # Reading node numbers from the result array
    print("Start searching for overstressed nodes")
    print("                  ")
    for point in range(len(arrayOfStress)):
            if arrayOfStress[point][6] > 106e6:     # Checking the von Mises stresses in the nodes
                overstressed.append(node_id[point]) # Fill the array with numbers of overstressed nodes
    if len(overstressed) == 0:  # The size of the array of overstressed nodes is checked, if it is 0 then
        isOptimized = True      # set the variable isOptimized = True to exit the loop
        print("Design optimized!")
    else:
        print("Overstressed nodes: ",len(overstressed)) # Displaying information about the number of overstressed nodes
        print("                  ")
        r = r + 0.05    # Increase the radius by 0.05
        iteration = iteration + 1 # Increasing the value of the iteration counter           
fc.deleteApplication() # Removing the completed task from memory
print("                  ")
print("Complete! Optimal diameter is at least: ", 2*r)

3. Run the script.

Select Run - Run Module from the menu and when the system asks to save this file, save it to the "Example" folder created in a directory with no Cyrillic characters in its path to avoid errors.

The following messages will appear in the console.

The results will be saved to the folder where the script file was located. Upon completion of the calculation, you can open and view the 1.pvd results file.