next up previous contents index
Next: IV.4 An object-oriented post-processing Up: IV. FeResPost Examples with Previous: IV.2 A few small   Contents   Index

Subsections


IV.3 A modular post-processing

In this Chapter, one presents an example of modular automated post-processing program using the ``FeResPost'' ruby library. This Chapter is organized as follows:


IV.3.1 Global structure of the program

Different modules corresponding to the different concepts used in the post-processing.


IV.3.1.1 The ``LoadCases'' module

The ``LoadCase'' modules corresponds to the concept of load case. In our post-processing program, a load case corresponds to the definition of a set of Results, and their association to a DataBase. The Results can be directly read from an ``op2'' Nastran Result file, or produced by linear combination of elementary Results.

LoadCase module has only one member data: @@dbList. This Hash contains a list of DataBases used for the post-processing.

Several methods are defined:


IV.3.2 Two post-processing modules

One defines two-post-processing modules. The first module, described in section IV.3.2.1 uses the Grid Point Forces and Moments to calculate connection margins of safety. The second module, presented in section IV.3.2.3 uses the Cauchy stress tensor to calculate margins of safety.


IV.3.2.1 One using the connection loads

The module ``Post_Connect'' defines a post-processing of connections considered individually. It builds the Results corresponding to forces and moments at connections. Then, up to three criteria can be calculated. The criteria correspond respectively to sliding, gapping, and failure of inserts.

IV.3.2.1.1 Member data

The member data defined in class ``Post_Connect'' are given below:

   @@fAxial=nil
   @@fShear=nil
   @@mTorsion=nil
   @@mBending=nil
``fAxial'', ``fShear'', ``mTorsion'' and ``mBending'' contain scalar Results corresponding to different components of the connection loads. These member data are set by method ``calcOneInterface''.

IV.3.2.1.2 ``calcOneInterface'' method

This methods builds the scalar Results corresponding to connection loads. It works in several phases:

  1. A Group on which the Results shall be retrieved from the DataBase is build:
          grpA = db.getGroupCopy(@@grpNameA)
          grpB = db.getGroupCopy(@@grpNameB)
          tmpGrp = grpA * grpB
          grpC = db.getElementsAssociatedToNodes(tmpGrp)
          grpC += tmpGrp
          grpC *= grpA
    
    ``grpC'' is build in such a way that it contains all the elements and nodes necessary to recover the contributing Grid Point Forces (internal forces and moments). Note that, the Groups defined in the DataBase must be such that ``grpA'' contains all the contributing element and nodes, and ``grpB'' contains all the contributing nodes.
  2. Parameters are retrieved:
          params = getParameters(nil)
          csId = params["csId"]
          direction = params["direction"]
          norme=0.0
          for i in 0..2
             norme+=direction[i]*direction[i]
          end
          norme=Math.sqrt(norme)
          for i in 0..2
             direction[i]/=norme
          end
          criteriaList=params["criteriaList"]
    
    Note that the list of failure criteria that shall be calculated for each connection is defined in the parameters that are retrieved.
  3. Then, Results are retrieved from the DataBase and used to build the four load components:
          tmpForces=db.getResultCopy(lcName,scName,\
             "Grid Point Forces, Internal Forces","ElemNodes",grpC,[])
          tmpMoments=db.getResultCopy(lcName,scName,\
             "Grid Point Forces, Internal Moments","ElemNodes",grpC,[])
             
          tmpForces.modifyRefCoordSys(db,csId)
          tmpMoments.modifyRefCoordSys(db,csId)
          
          tmpForces=tmpForces.deriveByRemapping("CornersToNodes",\
             "sum",db)
          tmpMoments=tmpMoments.deriveByRemapping("CornersToNodes",\
             "sum",db)
          
          @@fAxial=tmpForces*direction
          @@fShear=sqrt(sq(tmpForces)-sq(@@fAxial))
          @@mTorsion=tmpMoments*direction
          @@mBending=sqrt(sq(tmpMoments)-sq(@@mTorsion))
    
  4. Finally, the different criteria in ``criteriaList'' Array are calculated by calls to the appropriate methods:
          criteriaList.each do |critName|
             case critName 
             when "sliding" then
                crit_Sliding(db,lcName,scName)
             when "gapping" then
                crit_Gapping(db,lcName,scName)
             when "insert" then
                crit_Insert(db,lcName,scName)
             end
          end
    
    Criteria methods are described below.

IV.3.2.1.3 Sliding criterion

This criterion, defined by ``crit_Sliding'' method is used to calculate sliding margins of safety with the following expression:

$\displaystyle {\text{MoS}}=\cfrac{C_f*P_{\text{min}}}
{{\text{FoS}}*\left(C_f*\max(F_{\text{axial}},0)+F_{\text{shear}}\right)}-1\ ,
$

in which $ C_f$ is the friction coefficient between assembled elements and $ P_{\text{min}}$ is an estimate of the minimum possible pretension of the bolt.

One gives the lines used for the calculation of margins of safety:

      mos=(cf*pMin/fos)/(max(@@fAxial,0.0)*cf+@@fShear)-1.0
      mosMin=mos.extractResultMin
      rklMin=mosMin.extractRkl
      fAxialMin=@@fAxial.extractResultOnRkl(rklMin)
      fShearMin=@@fShear.extractResultOnRkl(rklMin)
Other programming lines are devoted to the extraction of parameters and printing of Results. One first checks whether the output file exists. If it exists, one opens it in ``append'' mode. If it does not exists, it is opened in ``write'' mode and a title line is printed:
      if (File.exist?(outputFile)) then
         os=File.open(outputFile,"a")
      else
         os=File.open(outputFile,"w")
         os.printf("%30s%40s%10s%8s%10s%8s%8s%14s%14s%8s\n",\
            "LoadCase ID","Interface","Elem ID","FoS",\
            "Type","Pmin","Cf","Faxial","Fshear","MoS")
      end
In either case, the critical margin and corresponding information is printed in the result file:
      interfStr=format("%s/%s",@@grpNameA,@@grpNameB)
      os.printf("%30s%40s%10s%8.2f%10s%8.1f%8.3f%14.1f%14.1f",\
                lcName,interfStr,mosData[1],fos,connectType,pMin,\
                cf,fAxialData[5],fShearData[5])
      if (mosData[5]>1000.0) then
         os.printf("%8s\n",">1000")
      else
         os.printf("%8.2f\n",mosData[5])
      end
Finally, the output stream is closed.

IV.3.2.1.4 Gapping criterion

This criterion, defined by ``crit_Gapping'' method is used to calculate gapping margins of safety with the following expression:

$\displaystyle {\text{MoS}}=\cfrac{P_{\text{min}}}
{{\text{FoS}}*\left(\max(F_{\text{axial}},0)
+M_{\text{bending}}/R\right)}-1\ ,
$

in which $ R$ is a parameter that allows to take into account the prying effect related to the bending moment in the connection and $ P_{\text{min}}$ is an estimate of the minimum possible pretension of the bolt.

One only gives the lines used for the calculation of margins of safety:

         mos=(pMin/fos)/(max(@fAxial,0.0)+@mBending/radius)-1.0
         mosMin=mos.extractResultMin
         rklMin=mosMin.extractRkl
         fAxialMin=@fAxial.extractResultOnRkl(rklMin)
         mBendingMin=@mBending.extractResultOnRkl(rklMin)
Other programming lines are devoted to the extraction of parameters and printing of Results.

IV.3.2.1.5 Insert criterion

This criterion, defined by ``crit_Insert'' method is used to calculate inserts margins of safety with the following expression:

$\displaystyle {\text{MoS}}=
\cfrac{1}{{\text{FoS}}\sqrt{\left(\cfrac{F_{\text{...
...t{PSS}}\right)^2
+\left(\cfrac{F_{\text{shear}}}{\text{QSS}}\right)^2}}-1\ ,
$

In which ``PSS'' is the axial allowable of the insert and ``QSS'' is its shear allowable.

One only gives the lines used for the calculation of margins of safety:

         tmp = sq(@fAxial/pss)+sq(@fShear/qss)
         tmpMax = tmp.extractResultMax
         mosMin = (1.0/fos)/sqrt(tmpMax)-1.0
         rklMin = mosMin.extractRkl
         fAxialMin = @fAxial.extractResultOnRkl(rklMin)
         fShearMin = @fShear.extractResultOnRkl(rklMin)
Other programming lines are devoted to the extraction of parameters and printing of Results.

IV.3.2.1.6 Definition of the list of interfaces

The interfaces (lists of pair of Groups) on which connection margins will be calculated are defined in ``calcAll'' method. This method corresponds to a definition of data. One first defines a list of pair of groups with statement like:

      list = []

      list << ["pan_MX","bar_MXMY"]
      list << ["pan_MX","bar_MXMZ"]
      list << ["pan_MX","bar_MXPY"]
      list << ["pan_MX","bar_MXPZ"]
      list << ["pan_MX","corner_MXMYMZ"]
      ...
Then a loop on these data is done, and method ``calcOneInterface'' is called for each interface:
      list.each do |groupNameA,groupNameB|
         @@grpNameA=groupNameA
         @@grpNameB=groupNameB
         calcOneInterface(db,lcName,scName)
      end
Parameters ``@@grpNameA'' and ``@@grpNameB'' are passed by member data of the module. The other parameters are passed as arguments of the call to ``calcOneInterface''.

IV.3.2.1.7 Definition of parameters

Some parameters depend on the interfaces. For example, the direction of connections, allowables... The method ``getParameters'' is used to produce the parameters corresponding to each interface.

This method has one parameter ``critName'' a String argument corresponding to the criterion that requires the parameters. If the argument is nil, one considers that the method is called by ``calcOneInterface'' and data corresponding to the different orientation of the connection are returned. If the method is called by a criterion method, the data returned correspond to allowables used in the calculation of margins of safety.


IV.3.2.2 Critics on the previous post-processor

The ``Post_Connect'' module defines methods corresponding to the calculation operations, and methods than can be considered as definition of data. Of course, many different types of data definitions are possible. For example, the definition of interfaces, and of the calculation parameters could be read from a file.

The calculation methods as well as the data are defined in a single module. However, it could be interesting to split the definition of data into several files. This could be interesting, for example, when several persons work on the same project. At the same time, the copying of the methods corresponding to calculation methods into different data files is a poor way to use the object-oriented capabilities of ruby language.

One shows in section IV.3.2.3 a different modular design that allows not to repeat the writing of calculation methods, and at the same time to split the module into separate smaller entities. More precisely, one defines a generic ``Post_Cauchy'' module that performs calculations based on the components of Cauchy stress tensor. Then two modules calculating honeycomb margins of safety and skin margins of safety are defined as two specialized modules using ``Post_Cauchy'' capabilities.


IV.3.2.3 One using the Cauchy stress tensor

The module ``Post_Cauchy'' performs the post-processing of Results corresponding to the Cauchy stress tensor. Presently, three criteria corresponding to the stress tensor are available: an ``Airbus'' criterion for the calculation of honeycomb, a ``MaxShear'' criterion for the calculation of honeycomb, and a ``VonMises'' criterion for the calculation of metallic parts.

IV.3.2.3.1 Member data

The class has three member data:

IV.3.2.3.2 ``calcOneGroup'' method

This method has one more argument than the corresponding method in ``Post_Connect'' module:

   def Post_Cauchy::calcOneGroup(db,lcName,scName,paramsMethod)
``paramsMethod'' is the method to be called when one wishes to retrieve calculation parameters.

``calcOneGroup'' performs the building of ``stressTensor'' member data by retrieving the corresponding Results. The first operations performed by the method are programmed as follows:

      grp = db.getGroupCopy(@@groupName)
      
      params = paramsMethod.call(nil)
      interpolation = params["interpolation"]
      layers = params["layers"]
      criteriaList=params["criteriaList"]

      @@stressTensor=db.getResultCopy(lcName,scName,\
         "Stress Tensor",interpolation,grp,layers)
So far, the method is not very different than the corresponding method of ``Post_Connect'' module. Just note the way the parameters method is called.

The rest of the method is similar too:

      criteriaList.each do |critName|
         case critName 
         when "airbus" then
            crit_HoneyAirbus(db,lcName,scName,paramsMethod)
         when "maxShear" then
            crit_HoneyMaxShear(db,lcName,scName,paramsMethod)
         when "vonMises" then
            crit_VonMises(db,lcName,scName,paramsMethod)
         end
      end
The different methods that performs the criteria calculations are called if necessary. Note that the method to be called to retrieve parameters is passed as argument to the different criteria methods.

IV.3.2.3.3 Airbus criterion

This criterion, defined by ``crit_HoneyAirbus'' method is used to calculate margins of safety in the honeycomb with the following expression:

$\displaystyle {\text{MoS}}=
\cfrac{1}{{\text{FoS}}\sqrt{\left(\cfrac{\tau_L}{\sigma_L}\right)^2
+\left(\cfrac{\tau_W}{\sigma_W}\right)^2}}-1\ ,
$

in which $ \tau_L$ and $ \tau_L$ are the honeycomb longitudinal and transversal shear components of Cauchy stress tensor and $ \sigma_L$ and $ \sigma_W$ the corresponding allowables.

As the programming of the criterion is not more complicated than the programming of ``Post_Connect'' module criteria, one does not describe the instructions.

IV.3.2.3.4 MaxShear criterion

This criterion, defined by ``crit_HoneyMaxShear'' method is used to calculate margins of safety in the honeycomb with the following expression:

$\displaystyle {\text{MoS}}=\cfrac{\sigma_W}{{\text{FoS}}*\tau}-1\ ,
$

in which $ \tau$ is the maximum shear stress and $ \sigma_W$ the transverse shear allowable.

IV.3.2.3.5 Von Mises criterion

This criterion, defined by ``crit_VonMises'' method is used to calculate margins of safety in the metallic parts with the following expression:

$\displaystyle {\text{MoS}}=\cfrac{F_t}{{\text{FoS}}*\sigma_{VM}}-1\ ,
$

in which $ \sigma_{VM}$ is the Von Mises equivalent stress and $ F_t$ the material tensile allowable.

IV.3.2.3.6 ``Post_honeycomb'' specialization module

This module includes ``Post_Cauchy'' module:

module Post_honeycomb 

   include Post_Cauchy
   
   ...
This means that the methods of ``Post_Cauchy'' module are now visible in ``Post_honeycomb''. In this example, the module has two specific methods:
  1. ``calcAll'' defines the list of Groups on which honeycomb margins are calculated. Then, a loop on this list is done and the ``calcOneGroup'' of ``Post_Cauchy''
          list = ["pan_MX_Honey_50", "pan_MY_Honey_50", "pan_PX_Honey_50", 
                  "pan_PY_Honey_50", "pan_PZ_Honey_72", "pan_SUP_Honey_50"]
    
          list.each do |groupName|
             @@groupName=groupName
             Post_Cauchy::calcOneGroup(db,lcName,scName,method(:getParameters))
          end
    
    Note that the call to ``calcOneGroup'' has a fourth parameter: the method that shall be called to retrieve the necessary data.
  2. This method ``getParameters'' is the second method defined in ``Post_honeycomb'' module. This method is similar to the corresponding method in ``Post_Connect'' module.

IV.3.2.3.7 ``Post_skins'' specialization module

This module is very similar to `Post_honeycomb'' module.


IV.3.3 Main function

The file ``testSat.rb'' contains the ``testSat'' method that starts the loop on load cases, and where the different post-processing criteria done for each load case are selected.

The different modules that are used in the ``testSat'' method are made visible by several require statements:

require "util"
require "loadCases"

require "data_Post_Connect"
require "data_Post_honeycomb"
require "data_Post_skins"
Then, in ``testSat'' method, a loop on the load cases is started by calling the ``each'' iterator of ``LoadCases'' module with appropriate parameter:
   version="All"
   LoadCases.each(version) do |db,lcName,scName|
      PostConnect.calcAll(db,lcName,scName)
      Post_honeycomb.calcAll(db,lcName,scName)
      Post_skins.calcAll(db,lcName,scName)
      GC.start
   end
The different post-processing criteria are called in the block that follows the iterator. At the end of each load case calculation a call to the garbage collector cleans the memory.


IV.3.4 Conclusions

One presented in the Chapter a finite element post-processing program written by defining modules. This post-processing works and it is possible to trick the language in order to prevent the rewriting of codes. (See the ``Post_Cauchy'' class.)

However, the program written in this example uses poorly the object-oriented capabilities of ruby. One presents in Chapter IV.4 an example of object-oriented post-processing.


next up previous contents index
Next: IV.4 An object-oriented post-processing Up: IV. FeResPost Examples with Previous: IV.2 A few small   Contents   Index
FeResPost 2017-05-28