External CAD (NX) Integration

PyFemtet allows parametric optimization even for analysis models created with external CAD (NX) and imported into Femtet.

Sample File

Note

Place the sample model and sample project in the same folder. Keep the project open in Femtet, then double-click on the sample code to execute it.

Details as a FEM Problem

../../_images/NX_ex01_analysis.png

Appearance of the Model (and Analysis Conditions)

  • fix … Fully Fixed

  • load … Load in the -Z direction (1N)

  • mirror … Symmetrical to the XZ plane

Design Variables

../../_images/NX_ex01_model_dsgn.png

Appearance of the Model Section (and Design Variables)

Variable Name

Description

A

Web Tickness

B

Flange Tickness

C

Flange Bending

Objective Function

  • Maximum Displacement in the Z direction (set to 0)

  • Volume (minimize)

Sample Code

cad_ex01_NX.py
  1"""External CAD (NX) Integration
  2
  3Using Femtet's stress analysis solver and Siemens' CAD software NX,
  4design a lightweight and high-strength H-shaped beam.
  5
  6As a preliminary step, please perform the following procedures:
  7- Install NX
  8- Create a C:\temp folder
  9    - Note: NX will save a .x_t file in this folder.
 10- Place the following files in the same folder:
 11    - cad_ex01_NX.py (this file)
 12    - cad_ex01_NX.prt
 13    - cad_ex01_NX.femprj
 14"""
 15
 16import os
 17
 18from win32com.client import constants
 19
 20from pyfemtet.opt import FEMOpt
 21from pyfemtet.opt.interface import FemtetWithNXInterface
 22from pyfemtet.opt.exceptions import ModelError
 23
 24
 25here, me = os.path.split(__file__)
 26os.chdir(here)
 27
 28
 29def von_mises(Femtet):
 30    """Obtain the maximum von Mises stress of the model.
 31
 32    Note:
 33        The objective or constraint function should take Femtet
 34        as its first argument and return a float as the output.
 35
 36    Warning:
 37        CAD integration may assign boundary conditions to unintended locations.
 38
 39        In this example, if the boundary conditions are assigned as intended,
 40        the maximum z displacement is always negative.
 41        If the maximum displacement is not negative, it is assumed that
 42        boundary condition assignment has failed.
 43        Then this function raises a ModelError.
 44
 45        If a ModelError, MeshError, or SolveError occurs during optimization,
 46        the optimization process considers the attempt a failure and skips to
 47        the next trial.
 48    """
 49
 50    # Simple check for the correctness of boundary conditions.
 51    dx, dy, dz = Femtet.Gogh.Galileo.GetMaxDisplacement_py()
 52    if dz >= 0:
 53        raise ModelError('Assigning unintended boundary conditions.')
 54
 55    # Von Mises stress calculation.
 56    Gogh = Femtet.Gogh
 57    Gogh.Galileo.Potential = constants.GALILEO_VON_MISES_C
 58    succeed, (x, y, z), mises = Gogh.Galileo.GetMAXPotentialPoint_py(constants.CMPX_REAL_C)
 59
 60    return mises
 61
 62
 63def mass(Femtet):
 64    """Obtain model mass."""
 65    return Femtet.Gogh.Galileo.GetMass('H_beam')
 66
 67
 68def C_minus_B(Femtet, opt):
 69    """Calculate the difference between C and B dimensions.
 70
 71    Another example uses the following snippet to access design variables:
 72
 73        A = Femtet.GetVariableValue('A')
 74    
 75    However, when performing CAD integration, this method does not work
 76    because the variables are not set in the .femprj file.
 77
 78    In CAD integration, design variables are obtained in the following way.
 79
 80        # How to obtain a dictionary with the variable names of parameters
 81        # added by add_parameter() as keys.
 82        params: dict = opt.get_parameter()
 83        A = params['A']
 84
 85    Or
 86
 87        # How to obtain an array of values of parameters added in the order
 88        # by add_parameter().
 89        values: np.ndarray = opt.get_parameter('values')
 90        A, B, C = values
 91
 92    Objective functions and constraint functions can take arbitrary variables
 93    after the first argument.
 94    The FEMOpt member variable `opt` has a method called get_parameter().
 95    This method allows you to retrieve design variables added by add_parameter().
 96    By taking `opt` as the second argument, you can execute get_parameter()
 97    within the objective or constraint function to retrieve design variables.
 98    """
 99    A, B, C = opt.get_parameter('values')
100    return C - B
101
102
103if __name__ == '__main__':
104
105    # Initialize NX-Femtet integration object.
106    # At this point, Python is connected to the Femtet.
107    fem = FemtetWithNXInterface(
108        prt_path='cad_ex01_NX.prt',
109        open_result_with_gui=False,  # To calculate von Mises stress, set this argument to False. See Femtet Macro Help.
110        export_curves=False,
111        export_surfaces=False,
112        export_solids=True,
113        export_flattened_assembly=False,
114    )
115
116    # Initialize the FEMOpt object.
117    # (establish connection between the optimization problem and Femtet)
118    femopt = FEMOpt(fem=fem)
119
120    # Add design variables to the optimization problem.
121    # (Specify the variables registered in the .prt file.)
122    femopt.add_parameter('A', 10, lower_bound=1, upper_bound=59)
123    femopt.add_parameter('B', 10, lower_bound=1, upper_bound=40)
124    femopt.add_parameter('C', 20, lower_bound=5, upper_bound=59)
125
126    # Add the constraint function to the optimization problem.
127    femopt.add_constraint(fun=C_minus_B, name='C>B', lower_bound=1, args=(femopt.opt,))
128
129    # Add the objective function to the optimization problem.
130    femopt.add_objective(fun=von_mises, name='von Mises (Pa)')
131    femopt.add_objective(fun=mass, name='mass (kg)')
132
133    # Run optimization.
134    femopt.set_random_seed(42)
135    femopt.optimize(n_trials=20)

Execution Result of the Sample Code

../../_images/NX_ex01_result.png

Execution result of NX_ex01.py. The horizontal axis is von Mises stress, and the vertical axis is mass.

After the 20 trials, a Pareto set of von Mises stress and mass is obtained.

Note

Results may vary slightly depending on the versions of Femtet, PyFemtet, and the optimization engine it depends on.