There are bugs in TexGen's part of code that generates Abaqus voxel file and in the Python script for calculating effective RVE properties, which together result in swapping values of the effective shear moduli G13 and G23. The bug exists in TexGen v3.10.0 (and possible in 3.11.0 - I still can't run it).
To watch the bug you have to create any Abaqus voxel file through TexGen, and then make some modifications to the *.inp file:
- Create an orthotropic material with apparent properties, for example:
E1 = 1111
E2 = 2222
E3 = 3333
G12 = 1212
G13 = 1313
G23 = 2323
nu12 = 0.1212
nu13 = 0.1313
nu23 = 0.2323
- Create a local coordinate system for material orientation with axes parallel to the global axes.
- Create a solid section that references to the new material and to the new coordinate system and assign it to all elements.
- Clear old orientation, section and material data from the model.
Now the model in the *.inp file is just a rectangular brick of material with apparent properties and orientation aligned with the global axes. I attach an example of such file below for your convenience (please change file extension from *.txt to *.inp).
VoxelContinuumTest.txt
Run Abaqus solver and then run the postprocessing script effectiveMatPropRVE.py. The result is:
EXPLANATION WHY THIS HAPPENS
First of all, we meet a "rule" in the *.inp file which states:
************************************
*** PERIODIC BOUNDARY CONDITIONS ***
************************************
*** ConstraintsDriver0 = e_x
*** ConstraintsDriver1 = e_y
*** ConstraintsDriver2 = e_z
*** ConstraintsDriver3 = e_xy
*** ConstraintsDriver4 = e_xz
*** ConstraintsDriver5 = e_yz
Let's memorize that 5th node set ConstraintsDriver4 is responsible for shear 13 and 6th node set ConstraintsDriver5 is for shear 23. Next we go to the output request section, and there we see the following:
***********************
*** OUTPUT REQUESTS ***
***********************
*Output, field
*Element Output, directions=YES
S,
*** FIELD OUTPUT: Output Request Fx ***
*Node Output, nset=ConstraintsDriver0
U,
*** FIELD OUTPUT: Output Request Fy ***
*Node Output, nset=ConstraintsDriver1
U,
*** FIELD OUTPUT: Ouput Request Fz ***
*Node Output, nset=ConstraintsDriver2
U,
*** FIELD OUTPUT: Output Request Shear_xy ***
*Node Output, nset=ConstraintsDriver3
U,
*** FIELD OUTPUT: Output Request Shear_yz ***
*Node Output, nset=ConstraintsDriver5
U,
*** FIELD OUTPUT: Output Request Shear_zx ***
*Node Output, nset=ConstraintsDriver4
U,
Pay attention to the two last requests. Their order is reversed. The order of output requests is very important, as the results in each load case will be saved to the output database in sequential order. There won't be any comments or node set names, so a postprocessing program must know what constraint driver each result corresponds to. Let's memorize that despite the "rule" above, 5th result in each load case corresponds to the displacement of the constraint driver responsible for shear 23, and 6th result corresponds to the displacement of the constraint driver responsible for shear 13.
Load cases order is important too, because the results will be saved to the output database as sequential frames. Here we have:
*Load Case, name=Load4
*Boundary, op=NEW
MasterNode1, 1, 1
MasterNode1, 2, 2
MasterNode1, 3, 3
*Cload
ConstraintsDriver4, 1, 0.88
*End Load Case
*Load Case, name=Load5
*Boundary, op=NEW
MasterNode1, 1, 1
MasterNode1, 2, 2
MasterNode1, 3, 3
*Cload
ConstraintsDriver5, 1, 0.88
*End Load Case
As one can see, load case order is in agreement with the "rule" above, i.e. 5th load case (subsequently 5th frame) is shear 13 and 6th load case (subsequently 6th frame) is shear 23.
Now let's move to the postprocessing script dataHandling.py to see frame extraction.
# 5 holds the Shear_yz load-case.
frameShear_yz = resultODB.steps[isothermalStep.name].frames[5]
# 6 holds the Shear_zx load-case.
frameShear_zx = resultODB.steps[isothermalStep.name].frames[6]
And here is first error: 5th frame holds shear 13, not shear 23. In its turn frame number 6 contains results for shear 23 load case. The next piece of code extracts displacements of the constraint drivers from swapped frames:
# Load case Shear_yz.
Shear_yz_gamma0_yz = frameShear_yz.fieldOutputs['U'].values[5].data[0]
# Load case Shear_zx.
Shear_zx_gamma0_zx = frameShear_zx.fieldOutputs['U'].values[4].data[0]
As mentioned above the results order in each frame doesn't agree with the "rule", therefore these lines of code by accident don't cause an error. It's obvious that Shear_yz_gamma0_yz now contains displacements of ConstraintsDriver4, which as we know corresponds to shear 13. And the value of Shear_zx_gamma0_zx is the displacement of ConstraintsDriver5, in other words shear 23.
As a result, the values of shear moduli G13 and G23 are now swapped.
HOW TO FIX THE BUG
- In the input file modify output requests order:
***********************
*** OUTPUT REQUESTS ***
***********************
*Output, field
*Element Output, directions=YES
S,
*** FIELD OUTPUT: Output Request Fx ***
*Node Output, nset=ConstraintsDriver0
U,
*** FIELD OUTPUT: Output Request Fy ***
*Node Output, nset=ConstraintsDriver1
U,
*** FIELD OUTPUT: Ouput Request Fz ***
*Node Output, nset=ConstraintsDriver2
U,
*** FIELD OUTPUT: Output Request Shear_xy ***
*Node Output, nset=ConstraintsDriver3
U,
*** FIELD OUTPUT: Output Request Shear_zx ***
*Node Output, nset=ConstraintsDriver4
U,
*** FIELD OUTPUT: Output Request Shear_yz ***
*Node Output, nset=ConstraintsDriver5
U,
- In the dataHandling.py file modify frames extraction:
# 5 holds the Shear_zx load-case.
frameShear_zx = resultODB.steps[isothermalStep.name].frames[5]
# 6 holds the Shear_yz load-case.
frameShear_yz = resultODB.steps[isothermalStep.name].frames[6]
- In the dataHandling.py file reorder strings for displacements extraction:
# Load case Shear_zx.
Shear_zx_gamma0_zx = frameShear_zx.fieldOutputs['U'].values[4].data[0]
# Load case Shear_yz.
Shear_yz_gamma0_yz = frameShear_yz.fieldOutputs['U'].values[5].data[0]
Now everything is OK.
Best regards,
Mikhail Kozlov