next up previous contents index
Next: V. FeResPost as COM Up: IV. FeResPost Examples with Previous: IV.4 An object-oriented post-processing   Contents   Index

Subsections


IV.5 Using the composite classes

One presents here small examples illustrating the use of FeResPost composite classes. As the classes are still under construction, the examples might be modified in future versions of the program. Also, additional examples will be presented when new feature of the composite classes are available.


IV.5.1 Importing and exporting data

The first examples are presented in directory ``TESTSAT/SMALLEX/EX12'' and illustrate the importation of data, and the saving of data.

One example is contained in file ``testNeutral.rb''. The three first instructions, create a ``ClaDb'' object and initialize it by reading the ESAComp file ``test.edf''. Then the content of the ClaDb object is saved into a neutral file.

   dbA=ClaDb.new
   dbA.readEdf("test.edf")
   dbA.writeNeutral("NeutralA.ndf")
Then, a new ``ClaDb'' object is created and initialized by reading the previously created neutral file.
   dbB=ClaDb.new
   dbB.readNeutral("NeutralA.ndf")
   dbB.writeNeutral("NeutralB.ndf")
We advise the reader to read and compare the two neutral files. A comparison with ESAComp file might be useful too.

Another example illustrates the possibility of defining a composite database corresponding to the materials and laminates defined in a finite element model. The example is programmed in file ``testNastran.rb''. The model DataBase is produced ``as usual''. Then the corresponding ClaDb object is returned:

   compDb=db.getClaDb
Finally, the composite database is saved in ``nast.ndf'' neutral file:
   compDb.writeNeutral("nast.ndf")
(In this case, the database is not a very interesting one because only one laminate is defined, and it is not a very interesting one.)


IV.5.2 Manipulating composite entities

The example illustrates the manipulation of objects of the classes defined in FeResPost. The example is presented in directory ``TESTSAT/SMALLEX/EX12'', in file ``testCla.rb''.

One first creates a ClaDb and initializes it by reading an ESAComp data file:

   db=ClaDb.new
   db.Id="testDB"
   db.readEdf("test.edf")
Then, a new ClaMat ``mat1'' is created. Its data are initialized by calls to the appropriate methods, and the material is inserted into the ClaDb:
   mat1=ClaMat.new
   mat1.Id="mat1"
   mat1.Type="isotropic"
   mat1.fillModuli({"E"=>72e9,"nu"=>0.33})
   mat1.fillCTEs({"alfa"=>2.3e-5})
   db.insertMaterial(mat1)
The ClaMat object previously stored into the ClaDb is retrieved into ``mat2'' variable. The material stiffness matrix is requested and its components are printed:
   mat2=db.getMaterialCopy("mat1")
   stiffMat = mat2.getStiffness
   printf("\n\n   stiffMat:\n\n")
   stiffMat.each do |line|
      line.each do |cell|
         printf("%14g",cell)
      end
      printf("\n")
   end
(Similarly, the compliance matrix is printed for the same material.) The following instructions illustrate the creation of a ClaLam object that is stored in the ClaDb:
   lam=ClaLam.new
   lam.Id="testLam"
   lam.addPly( 1,"mat1",0.00037,  0.0,30e6)
   lam.addPly( 2,"mat1",0.00037, 45.0,30e6)
   lam.addPly( 3,"mat1",0.00037,-45.0,30e6)
   lam.addPly( 4,"mat1",0.00037, 90.0,30e6)
   lam.addPly(15,"mat1",0.00037, 90.0,30e6)
   lam.addPly( 6,"mat1",0.00037,-45.0,30e6)
   lam.addPly( 7,"mat1",0.00037, 45.0,30e6)
   lam.addPly( 8,"mat1",0.00037,  0.0,30e6)
   lam.addPly(16,"mat1",0.00037,  0.0,30e6)
   db.insertLaminate(lam)
Then, characteristics of the laminate like the stiffness and compliance matrices are printed. the following lines illustrate the printing of the laminate ABBD (stiffness) matrix:
   ABBD = lam.get_ABBD
   printf("\n\n   ABBD:\n\n")
   ABBD.each do |line|
      line.each do |cell|
         printf("%14g",cell)
      end
      printf("\n")
   end
Note that the quantities can be printed in any direction wrt laminate axes. For example, the following lines illustrate the printing of laminate thermal expansion coefficient in direction 45$ \o$ wrt laminate axes:
   alfaEh1 = lam.get_alfaEh1(45.0)
   printf("\n\n   alfaEh1 (45):\n\n")
   alfaEh1.each do |cell|
      printf("%14g\n",cell)
   end
Similarly, the vector $ \left\{\alpha_0^\epsilon\right\}$ is printed. Finally, the ClaDb is saved into a neutral file. (This neutral file ``test.ndf'' is used in the other composite examples.)


IV.5.3 Composite thermal properties

The example illustrates the calculation of laminate thermal properties. The example is presented in directory ``TESTSAT/SMALLEX/EX12'', in file ``testClaTherm.rb''.

The following statements correspond to the introduction of isotropic thermal properties in a material:

   mat1=ClaMat.new
   mat1.Id="mat1"
   mat1.Type="isotropic"
   mat1.fillThermalData({"lambdaT"=>170.0,"rho"=>2700.0,"Cp"=>17.0})
   db.insertMaterial(mat1)
similarly, one defines an anisotropic material as follows:
   mat1=ClaMat.new
   mat1.Id="mat_aniso"
   mat1.Type="anisotropic"
   mat1.fillThermalData({"lambdaT1"=>170.0,"lambdaT2"=>17.0,
      "lambdaT3"=>17.0,"lambdaT12"=>0.0,"lambdaT23"=>0.0,
      "lambdaT31"=>0.0,"rho"=>50.0,"Cp"=>17.0})
   db.insertMaterial(mat1)
The thermal properties stored in a ClaMat object can be printed with the following statements:
   lambdaMat = mat2.getInPlaneLambdaT
   printf("\n\n   lambdaMat:\n\n")
   lambdaMat.each do |line|
      line.each do |cell|
         printf("%14g",cell)
      end
      printf("\n")
   end
   printf("\n")
   printf("   rho = %g\n",mat2.getRho)
   printf("   Cp = %g\n",mat2.getCp)
   printf("   rho * Cp = %g\n",mat2.getRhoCp)
One also defines a method that calculates and prints laminate thermal properties:
   def writeLamThermalProperties(os,lam,db)
      lam.calcLaminateProperties(db)
      mat = lam.get_LambdaT
      os.printf("\n\n   LambdaT:\n\n")
      mat.each do |line|
         line.each do |cell|
            os.printf("%14g",cell)
         end
         os.printf("\n")
      end
      os.printf("\n   R33T = %g\n",lam.get_R33T)
      os.printf("   RhoCpH = %g\n",lam.get_RhoCpH)
   end
This method is called with the following statement:
   writeLamThermalProperties(STDOUT,lam,db)


IV.5.4 Extending composite classes

In the example of section IV.5.2, one illustrated basically how the composite classes and their methods can be used to calculate composite properties. The example involved the printing of matrices and vectors corresponding to material or laminate properties.

To write the ruby lines devoted to the printing or manipulation of composite entities can be tedious because it is a repetitive task. As for many users, the same composite results are often requested, this may justify the development of Modules or Classes devoted to the most common operations.

One illustrates in this section the extension of the composite classes and of its classes. All these examples are to be found in ``TESTSAT/SMALLEX/EX13'' directory.


IV.5.4.1 Extension ``extendedCLA.rb''

Presently, only ``ClaMat'' and ``ClaLam'' classes have been modified in ``extendedCLA.rb''.

IV.5.4.1.1 Modification of ``ClaLam'' class

One adds methods devoted to the printing of stiffness and compliance matrices, laminate engineering constants... The list of these functions include:

Each of these diagnostic functions has two arguments: an ostream object corresponding to the File in which Results are printed, and a Real value corresponding to the angle wrt laminate axes for which the diagnostic is to be written. The following lines show the programming of ``write_engineering'' method:
   class ClaLam 
   
      ...
   
      def write_engineering(os,theta=0.0)
         constants=get_engineering(theta)
         tab=["E_xx", "E_k0_xx", "E_f_xx",\
              "E_yy", "E_k0_yy","E_f_yy",\
              "G_xy", "G_k0_xy", "G_f_xy",\
              "nu_xy", "nu_k0_xy", "nu_f_xy",\
              "nu_yx", "nu_k0_yx", "nu_f_yx",\
              "G_xz", "G_yz"]
         counter=0
         tab.each do |elem|
            if (counter.modulo(3)==0) then
               os.printf("   ")
            end
            str=format("%s = %11g",elem,constants[elem])
            os.printf("%25s",str)
            counter+=1
            if (counter.modulo(3)==0||counter==tab.size) then
               os.printf("\n")
            end
         end
      end
      
      ...
            
   end # class ClaLam
The programming of the other diagnostic methods is very similar to this one.

The following method writes the laminate load response at laminate level (i.e. no ply results):

    def write_loadResponse(os,theta=0.0)
        if (!isMechanicalLoadingDefined()) then
            raise "No load response has been calculated."
        end
         
        if (isThermalLoadingDefined()) then 
            deltaT=getDeltaT
            os.printf("   %14s%14g\n","deltaT",deltaT)
            t0=getT0()
            os.printf("   %14s%14g\n","T0",t0)
            gradT=getGradT
            os.printf("   %14s%14g\n\n","gradT",gradT)
        end
        
        if (isMoistureLoadingDefined()) then 
            deltaH=getDeltaH
            os.printf("   %14s%14g\n","deltaH",deltaH)
            h0=getH0
            os.printf("   %14s%14g\n","H0",h0)
            gradH=getGradH
            os.printf("   %14s%14g\n\n","gradH",gradH)
        end
      
        os.printf("   %30s%14s%14s%14s\n","type","XX","YY","XY")
        f=getNormalForces(theta)
        m=getMoments(theta)
        s=getNormalStrains(theta)
        c=getCurvatures(theta)
        os.printf("   %30s%14g%14g%14g\n","Normal Forces",f[0],f[1],f[2])
        os.printf("   %30s%14g%14g%14g\n","Moments",m[0],m[1],m[2])
        os.printf("   %30s%14g%14g%14g\n","Normal Strains",s[0],s[1],s[2])
        os.printf("   %30s%14g%14g%14g\n","Curvatures",c[0],c[1],c[2])
        f=getAverageInPlaneStresses(theta)
        m=getFlexuralStresses(theta)
        s=getAverageInPlaneStrains(theta)
        c=getFlexuralStrains(theta)
        os.printf("   %30s%14g%14g%14g\n","Average in-plane stresses",f[0],f[1],f[2])
        os.printf("   %30s%14g%14g%14g\n","Flexural stresses",m[0],m[1],m[2])
        os.printf("   %30s%14g%14g%14g\n","Average strains",s[0],s[1],s[2])
        os.printf("   %30s%14g%14g%14g\n","Flexural in-plane strains",c[0],c[1],c[2])

        os.printf("\n   %30s%14s%14s\n","type","XZ","YZ")
        q=getShearForces(theta)
        g=getShearStrains(theta)
        os.printf("   %30s%14g%14g\n","Shear Forces",q[0],q[1])
        os.printf("   %30s%14g%14g\n","Shear Strains",q[0],q[1])
        q=getAverageShearStresses(theta)
        g=getAverageShearStrains(theta)
        os.printf("   %30s%14g%14g\n","Average shear stresses",q[0],q[1])
        os.printf("   %30s%14g%14g\n","Average shear strains",g[0],g[1])
   end
Again, in this case, the method has two arguments. Indeed, the components of Laminate load response can be obtained in any direction. Note that this method gives sensible results, only if the ``calcResponse'' method has been called on the ClaLam object. This remark is valid for all the methods that return information related to a peculiar loading.

The method ``write_PliesInPlaneStrainsAndStresses'' has only one argument and writes plies in-plane stresses and strains:

    def write_PliesInPlaneStrainsAndStresses(os)
        if (!isMechanicalLoadingDefined()) then
            raise "No load response has been calculated."
        end
         
        epsTab=getPliesStrains
        sigTab=getPliesStresses
        epsMechTab=getPliesMechanicalStrains
        os.printf("   %8s%5s","layer","loc")
        os.printf("%14s%14s%14s","eps_11","eps_22","gamma_12")
        os.printf("%14s%14s%14s","sig_11","sig_22","sig_12")
        os.printf("%14s%14s%14s","eps_mech_11","eps_mech_22","gamma_mech_12")
        os.printf("\n")
        (0...epsTab.size).each do |i|
            os.printf("   %8d%5s",epsTab[i][0],epsTab[i][1])
            os.printf("%14g%14g%14g",epsTab[i][2],epsTab[i][3],epsTab[i][7])
            os.printf("%14g%14g%14g",sigTab[i][2],sigTab[i][3],sigTab[i][7])
            os.printf("%14g%14g%14g",epsMechTab[i][2],epsMechTab[i][3],epsMechTab[i][7])
            os.printf("\n")
        end
    end
One also defines methods ``write_PliesTemperatures'' and ``write_PliesMoistures'' that write thermal and hygrometric laminate states at ply level. These methods are very similar to ``write_PliesInPlaneStrainsAndStresses''.

Correspondingly, the ply failure indices and reserve factors can be calculated and written:

   def write_crit(os,db,criteria,fos=1.0)
        if (!isMechanicalLoadingDefined()) then
            raise "No load response has been calculated."
        end
        
        if (db==nil) then
            sdRes=getDerived(criteria)
            fiRes=getFailureIndices(criteria)
            rfRes=getReserveFactors(criteria,fos)
        else
            sdRes=getDerived(db,criteria)
            fiRes=getFailureIndices(db,criteria)
            rfRes=getReserveFactors(db,criteria,fos)
        end

        ...
   end
This last method has several arguments:
  1. ``os'' specifies where the results are written.
  2. ``db'' is the ClaDb that is used to calculate failure indices and reserve factors. This argument may be necessary to retrieve plies material allowables and calculate the failure indices. If the argument is nil, then the laminate allowables are used to estimate failure indices.
  3. ``criteria'' is an Array of strings corresponding to the criteria for which reserve factors and failure indices are requested.
  4. ``fos'' is an optional argument corresponding to the factor of safety used in the calculation of reserve factors. Its default value is 1.
Note that all the methods added to the ClaLam class perform write operations only. Obviously, methods returning values can also be defined and will ultimately be more useful. But the examples above show that FeResPost is highly customizable and can be adapted to the needs of nearly any user. For example, it should be possible to interface it with graphical packages like ImageMagick or Gnuplot, or with spreadsheets like excel through the win32ole package. Using the Tcl/Tk, it should even be possible to create an interactive program with graphical interfaces.

IV.5.4.1.2 Modification of ``ClaMat'' class

Similarly, in ``ClaMat'' class, several printing methods have been defined. A list of these methods follows:

Each of these methods has two arguments: an output stream object, and an optional angle $ \theta$ . (Its default value is 0.)


IV.5.4.2 A very simple example of use

The following example illustrates the use of the new methods in ClaLam class:

require "FeResPost"
require "extendedCLA"
include FeResPost

   db=ClaDb.new
   db.Id="testDB"
   db.readEdf("test.edf")

   lam=db.getLaminateCopy("testLam2")
   ld=db.getLoadCopy("testFM")
   theta=10.0

   lam.calcResponse(db,theta,ld,true,false,true)
   lam.write_loadResponse(STDOUT,theta)
   lam.write_loadResponse(STDOUT,0.0)

   STDOUT.printf("\n")
   lam.write_PliesInPlaneStrainsAndStresses(STDOUT)
   STDOUT.printf("\n")
The main steps of the example are the following:
  1. One first requests the ``FeResPost'' module and the ``extendedCLA'' extension of the ClaLam class.
  2. A ClaDb object is created and initialized as usual.
  3. Then, one retrieves the laminate ``testLam2'' and the load ``testFM'' from the ClaDb.
  4. The laminate load response is calculated and some results are printed. (Note that the calculation of laminate load response is done first by the call to ``calcResponse''.)
The example is contained in the ruby program file ``testCla.rb''.


IV.5.4.3 Properties of the laminates defined in an ESAComp file

The second example, defined in file ``testCla2.rb'' illustrates the use of a iterators. For each laminate defined in a ClaDb, one prints several properties. These properties are printed in several directions by rotations of $ 30^o$ . Part of the program is reproduced below:

def diagnostic(edfName,os)

   db=ClaDb.new
   db.Id="testDB"
   db.readEdf("test.edf")
      
   db.each_laminate do |lamId,lam|
      (0..360).step(30) do |i|
         theta=1.0*i
         
         os.printf("\nlaminate = \"%s\" -- theta = %g\n\n",lamId.to_s,theta)
         
         os.printf("\n   Stiffness matrix : \n\n");
         lam.write_ABBD(os,theta)
         os.printf("\n");
         
         ...
      end
   end
end

os=File.open("test.txt","w")
diagnostic("test.edf",os)
os.close


IV.5.4.4 Properties of the laminates defined in an ESAComp file

The third example, defined in file ``testCla3.rb'' illustrates the creation of a ClaLoad object and the calculation of corresponding ply stresses and strains. It is reproduced extensively below:

require "FeResPost"
require "extendedCLA"
include FeResPost

   db=ClaDb.new
   db.Id="testDB"
   db.readEdf("test.edf")

   tmpLoad=ClaLoad.new
   tmpLoad.Id="testF0T"
   tmpLoad.setT(20.0)
   tmpLoad.setMembrane([0.03,0.0,0.1],"SC","SC","SC")
   tmpLoad.setFlexural([0.000000e+00,0.000000e+00,0.000000e+00],"SC","SC","SC")
   tmpLoad.setOutOfPlane([100.0,200.0],"FM","FM")

   lam=db.getLaminateCopy("testLam2")
   lam.setAllPliesIlss(3.0e+7)
   lam.setLaminateIlss(3.0e+7)

   theta=45.0
   lam.calcResponse(db,theta,tmpLoad,true,false,true)
   lam.write_loadResponse(STDOUT,theta)
   STDOUT.printf("\n")
   lam.write_loadResponse(STDOUT,0.0)
   STDOUT.printf("\n")
   
   lam.write_PliesInPlaneStrainsAndStresses(STDOUT)
   STDOUT.printf("\n")
   lam.write_PliesTemperatures(STDOUT)
   STDOUT.printf("\n")
   
   criteria=["Tresca2D","VonMises2D","MaxStress","MaxStrain",\
      "TsaiHill","TsaiWu","Hoffman","Puck","Puck_b","Puck_c",\
      "Hashin","YamadaSun","CombStrain2D","Ilss"]
   lam.write_crit(STDOUT,db,criteria)
   STDOUT.printf("\n")
This example has been used for mainly debugging composite classes. It illustrates the calculation of failure indices, reserve factors and equivalent stresses in a laminate for a given loading. The reader should examine carefully the result for interlaminar shear.

Note that some criterion may give infinite or NaN values because all the material allowables have not been initialized. (See for example the failure indices of Tresca and Von Mises criteria.)


IV.5.4.5 Properties of the materials defined in an ESAComp file

Another example defined in file ``testCla4.rb'' illustrates the printing of material matrices and vectors as a function of the orientation. The most important lines look as follows:

   mat=db.getMaterialCopy("testPly2")
   
   (0..360).step(15) do |iAngle|
      theta=1.0*iAngle
      STDOUT.printf("Angle = %g\n\n",theta)
      
      STDOUT.printf("   In-plane compliance matrix :\n\n")
      mat.write_InPlaneCompliance(STDOUT,theta)
      STDOUT.printf("\n")
   
      STDOUT.printf("   In-plane alfa*E :\n\n")
      mat.write_InPlaneAlfaE(STDOUT,theta)
      STDOUT.printf("\n")
   
      STDOUT.printf("   In-plane alfa :\n\n")
      mat.write_InPlaneAlfa(STDOUT,theta)
      STDOUT.printf("\n")
   
      STDOUT.printf("   Out-of-plane compliance matrix :\n\n")
      mat.write_OOPSCompliance(STDOUT,theta)
      STDOUT.printf("\n")
   
      STDOUT.printf("\n")
   end


IV.5.5 Out-of-plane laminate shear response

The first example is presented in directory ``TESTSAT/SMALLEX/EX14'' and illustrates the out-of-plane shear calculations. The example is contained in file ``testShear.rb''. This example has been developed for debugging purposes and is meant to compare the results of FeResPost with those of ESAComp. After some research one identified what ESAComp does and reproduced its behavior with FeResPost.

One first defines a function that calculations the ESAComp components of out-of-plane shear stiffness matrix kA_44, kA_55, kA_45:

   def getESACompG(db,lam,theta)
      tmpLam=ClaLam.new
      tmpLam.Id="tmpLam"
      lam.each_ply do |plyIndex,plyData|
         tmpLam.addPly(plyIndex,plyData[1],plyData[2],\
                       plyData[3]+theta,plyData[4])
      end
      tmpLam.calcLaminateProperties(db)
      shearMat=tmpLam.get_G
      ret={"kA_44"=>shearMat[1][1], "kA_55"=>shearMat[0][0],\
           "kA_45"=>shearMat[0][1]}
   end
The arguments of the function are: The function returns a Hash containing the components of shear stiffness matrix associated to their names. The function works as follows: one defines a new ClaLam identical to the argument ClaLam, except that all the plies are rotated by the $ \theta$ argument angle. Then the laminate properties are calculated and the stiffness matrix components are extracted at $ 0^o$ (default direction in laminate axes for extraction function get_G).

Similarly, one defines a function supposed to return similar values in a more ``classical'' way (according to FeResPost philosophy):

   def getNormalG(db,lam,theta)
      lam.calcLaminateProperties(db)
      shearMat=lam.get_G(theta)
      ret={"kA_44"=>shearMat[1][1], "kA_55"=>shearMat[0][0],\
           "kA_45"=>shearMat[0][1]}
   end
The methods ``getESACompG'' and ``getNormalG'' are used to print the components of shear stiffness matrix according to the two calculation methods and as a function of the orientation $ \theta$ . For example, one prints the ESAComp results with the following ruby lines:
   os.printf("\n")
   os.printf("Laminate stiffness as a function of theta :\n\n")
   os.printf("%14s%14s%14s%14s\n","Theta","kA_44","kA_55","kA_45")
   (-90..90).step(5) do |i|
      theta=1.0*i
      ret=getESACompG(db,lam,theta)
      os.printf("%14d%14g%14g%14g\n",i,ret["kA_44"],ret["kA_55"],\
                   ret["kA_45"])
   end
   os.printf("\n\n")
One observes differences between the results obtained with ``getESACompG'' and ``getNormalG'':
  1. Note that in the ``ESAComp'' version the angle $ \theta$ is the angle by which the laminate is rotated. In the ``Normal'' version, it is the angle at which the shear stiffness components are recovered (angle wrt laminate axes). So the ESAComp results for an angle $ \theta$ should be compared to the ``Normal'' results for an angle $ -\theta$ . However in this case the dependence on $ \theta$ is even and no difference can be observed.
  2. For angles $ \theta$ other than $ -90^o$ , $ 0^o$ or $ 90^o$ , the results obtained with ``getESACompG'' and ``getNormalG'' are different. This difference is explained by the approximation:

    $\displaystyle Q_{xz}=M_{xx,x}\ ,
$

    $\displaystyle Q_{yz}=M_{yy,y}\ ,
$

    that has been done in section II.1.6.3. The example illustrates one of the consequences of the approximation: the loss of objectivity in out-of-plane shear equations.

One also performs the calculation of out-of-plane shear stresses in laminate for a simple loading in three different directions: $ -45^o$ , $ 0^o$ or $ 45^o$ . Here again the loading is applied in two ways: with the ``ESAComp'' method or the ``Normal'' one. For example, the printing of ply stresses with ``ESAComp'' method is done as follows:

    def writeESACompShearStresses(os,db,lam,theta,ld)
        tmpLam=ClaLam.new
        tmpLam.Id="tmpLam"
        lam.each_ply do |plyIndex,plyData|
        tmpLam.addPly(plyIndex,plyData[1],plyData[2],\
            plyData[3]+theta,plyData[4])
        end
        
        tmpLam.calcLaminateProperties(db)
        tmpLam.calcResponse(db,0.0,ld,true,false,true)
        sigTab=tmpLam.getPliesStresses
        os.printf("   %8s%5s%14s%14s\n","Ply","Pos.","tau_13","tau_23")
        (0...sigTab.size).each do |i|
            os.printf("   %8d%5s",sigTab[i][0],sigTab[i][1])
            os.printf("%14g%14g",sigTab[i][6],sigTab[i][5])
            os.printf("\n")
        end
    end
The loading applied to laminate is defined by a pure out-of-plane shear force components $ Q_{xz}=1000000$ and $ Q_{yz}=0$ . One also defines a corresponding loading rotated by $ 45^o$ and defined by its components $ Q_{xz}=Q_{yz}=707107$ . This new loading is tested for direction $ \theta=0^o$ only. The ply stress results obtained with the different versions of loading and calculations methods can be compared and the following comments are made:
  1. Here again, the ``ESAComp'' results are obtained by rotating the laminate by an angle $ \theta$ . For ``Normal'' results, the loading is rotated by an angle $ \theta$ . Therefore ``ESAComp'' results at $ \theta=-45^o$ are to be compared to ``Normal'' results at $ \theta=45^o$ (and vice versa).
  2. When $ \theta=0^o$ , ``ESAComp'' results and ``Normal'' results for a same loading are identical. Otherwise, one observes difference between ``ESAComp'' results at $ \theta=-45^o$ ``Normal'' results at $ \theta=45^o$ (and reversely).
  3. For ``Normal'' calculation method the loading ld45 at $ \theta=0^o$ gives the same results as ld at $ \theta=45^o$ . For ``ESAComp'' calculation method the loading ld45 at $ \theta=0^o$ does not give the same results as ld at $ \theta=-45^o$ . ``Normal'' calculation method is more in line with usual expectations.
Actually, none of the two calculation methods can be considered as better than the other. (At least, as far as the precision of results is concerned.) We think however that ``Normal'' calculation method is better because it is likely to give unexpected results as shown in the example. Moreover, the associated computation cost is lower. (This will be important when finite element results are post-processed.) Note however, that the ``Normal'' calculation method also suffers from a lack of objectivity wrt to ply orientations in the laminate.


IV.5.6 Producing composite finite element Results

The examples presented in this section are presented in directory ``TESTSAT/SMALLEX/EX15''.

One presents here an example in which composite classes interact with finite element Result class. One first defines a ``bottom'' Group containing four elements of the bottom panel, which has a PCOMPG property. A load object, some components of which correspond to finite element Results is defined:

   ld=ClaLoad.new
   ld.Id="testLoad"
   ld.setMembrane([0.03,0.0,0.1],"femFM","femSC","femFM")
   ld.setFlexural([0.0,0.0,0.0],"femFM","femSC","femSC")
   ld.setOutOfPlane([100.0,200.0],"femFM","femFM")

   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Shell Forces",
                        "ElemCenters",bottom,[])
   res.modifyRefCoordSys(db,"lamCS")
   ld.setShellForces(res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Shell Moments",
                        "ElemCenters",bottom,[])
   res.modifyRefCoordSys(db,"lamCS")
   ld.setShellMoments(res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Strain Tensor",
                        "ElemCenters",bottom,["NONE"])
   res.modifyRefCoordSys(db,"lamCS")
   ld.setShellStrains(res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Curvature Tensor",
                        "ElemCenters",bottom,["NONE"])
   res.modifyRefCoordSys(db,"lamCS")
   ld.setShellCurvatures(res)
In the example, no thermal or moisture contribution has been taken into account in the loading. Only mechanical components have been defined. The example, is defined in such a way that all possible mechanical contributions are used: in-plane forces, out-of-plane forces, bending moments, average in-plane strain and curvature. All these components are defined as finite element Results. (This allows us later to compare the Results produced by FeResPost with those directly output by Nastran.) The modification of coordinate system is necessary because one wants the loading components to be expressed in laminate axes. (The Nastran shell forces, moments, curvatures... are given in element axes.)

For later comparison of Results, several Results directly extracted from Nastran ``op2'' file are directly output in file ``Reference.txt''.

   os=File.open("Reference.txt","w")
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Shell Forces",
                        "ElemCenters",bottom,[])
   res.modifyRefCoordSys(db,"lamCS")
   Util::printRes(os,"Shell Forces",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Shell Moments",
                        "ElemCenters",bottom,[])
   res.modifyRefCoordSys(db,"lamCS")
   Util::printRes(os,"Shell Moments",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Strain Tensor",
                        "ElemCenters",bottom,["NONE"])
   res.modifyRefCoordSys(db,"lamCS")
   Util::printRes(os,"Strain Tensor",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Curvature Tensor",
                        "ElemCenters",bottom,[])
   res.modifyRefCoordSys(db,"lamCS")
   Util::printRes(os,"Curvature Tensor",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Stress Tensor",
                        "ElemCenters",bottom,[])
   Util::printRes(os,"Stress Tensor",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics","Strain Tensor",
                        "ElemCenters",bottom,[])
   Util::printRes(os,"Strain Tensor",res)
   
   res=db.getResultCopy("ORBIT_ONE_MS2_Z","Statics",
                        "Composite Failure Index, Tsai-Hill",
                        "ElemCenters",bottom,[])
   Util::printRes(os,"Composite Failure Index, Tsai-Hill",res)
   
   os.close()
As laminate allowables are not defined in Nastran, one modifies the laminate corresponding to the unique PCOMPG property by adding laminate allowables to it. Then the modified ClaLam is reinserted in the database, where it replaces the original one:
   lam=compDb.getLaminateCopy(6)
   allowables={}
   allowables["sc"]=200.0e6
   allowables["s1c"]=200.0e6
   allowables["s2c"]=200.0e6
   allowables["st"]=300.0e6
   allowables["s1t"]=300.0e6
   allowables["s2t"]=300.0e6
   allowables["ss"]=100.0e6
   allowables["s12"]=100.0e6
   allowables["ilss"]=30.0e6
   lam.insertAllowables(allowables)
   compDb.insertLaminate(lam)
One also selects the failure indices that shall be calculated. The first one is calculated using ply material allowables, the others with the laminate allowables defined above. For the two last criteria, the most critical layer only is recovered for each element. The definition looks as follows:
   criteria = []
   criteria << ["TS FI","TsaiHill_c","FI",false,true]
   criteria << ["TW FI","TsaiWu","FI",true,true]
   criteria << ["TW FI Critical","TsaiWu","FI",true,false]
   criteria << ["ILSS FI Critical","Ilss","FI",true,false]
The following call to method ``calcFiniteElementResponse'' produces Results corresponding to the ClaLam object for which the method is called and writes Results in file ``OneLaminate.txt''
   theta=0.0
   outputs=lam.calcFiniteElementResponse(ClaDb,theta,ld,[true,true,true],
      ["Shell Forces","Shell Moments", "Shell Curvatures",
       "Average Strain Tensor"],
      ["Stress Tensor","Strain Tensor","Mechanical Strain Tensor"],
      1.0,criteria)
   
   os=File.open("OneLaminate.txt","w")
   outputs.each do |id,res|
      Util::printRes(os,id,res)
   end
   os.close
The following sequence does the same operation, but the method ``calcFiniteElementResponse'' is called for the DataBase object ``db''.
   theta=0.0
   outputs=db.calcFiniteElementResponse(compDb,theta,ld,[true,true,true],
      ["Shell Forces","Shell Moments", "Shell Curvatures",
       "Average Strain Tensor"],
      ["Stress Tensor","Strain Tensor","Mechanical Strain Tensor"],
      1.0,criteria)
   
   os=File.open("SeveralLaminates.txt","w")
   outputs.each do |id,res|
      Util::printRes(os,id,res)
   end
   os.close
For each element, ``db'' retrieves the property ID and selects in ``compDb'' the appropriate laminate with which the calculations are done. Of course, in this case, a single laminate is used and the Results should be the same as when the method is called for the ``lam'' laminate.

A few remarks can be done about the example:

A simplified variant of the example is presented in ``testCriteria.rb'' file. There the failure indices are calculated using directly layered stresses read from Nastran op2 file. For example, one calculates the failure indices using the ClaLam method as follows:

   outputs=lam.calcFiniteElementCriteria(compDb,stressRes,1.0,criteria)


IV.5.7 Modifying units

The example illustrates the manipulation of CLA objects units. The example is presented in directory ``TESTSAT/SMALLEX/EX18', in file ``testMatUnits.rb''.

The sequence of operations is simple:

The two files ``oldUnits.txt'' and ``newUnits.txt'' may be compared. They should contain equivalent results.

The part of interest of the example is the modification units for all the materials in the database:

    oldUnits=db.getUnits

    newUnits=oldUnits.clone
    newUnits["F"]="lbf"
    newUnits["L"]="mm"
    newUnits["T"]="F"

    puts oldUnits
    puts newUnits

    db.each_material do |id,mat|
        mat.changeUnits(newUnits)
        db.insertMaterial(mat)
    end
(Note that in the example, one deliberately decided not to use the ``changeUnitsAllMaterials'' method of the ClaDb class.)

The user may test the outputs with or without units systems modifications to verify if the results are affected by the modification of units. (They should not be modified.)


next up previous contents index
Next: V. FeResPost as COM Up: IV. FeResPost Examples with Previous: IV.4 An object-oriented post-processing   Contents   Index
FeResPost 2017-05-28