APSG tutorial - Part 2

[1]:
from apsg import *

Matrix like classes and tensors

APSG provides matrix-like classes to work with tensor quantities used commonly in structural geology analysis. It includes DefGrad3 and VelGrad3 for deformation and velocity gradient, Stress3 for stress tensor, Ellipsoid for quadratic forms and Ortensor3 for orientation tensor. All these classes support common matrix mathematical operations and provide basic methods and properties.

All matrix-like objects could be created either by passing nested list or tuple or providing individual components to class method from_comp

[2]:
F = defgrad([[2, 0, 1], [0, 1, 0], [0, 0, 0.5]])
F
[2]:
DeformationGradient3
[[2.  0.  1. ]
 [0.  1.  0. ]
 [0.  0.  0.5]]
[3]:
F = defgrad.from_comp(xx=2, zz=0.5, xz=1)
F
[3]:
DeformationGradient3
[[2.  0.  1. ]
 [0.  1.  0. ]
 [0.  0.  0.5]]

For multiplifications of matrix or vectors we have to use matmul @ operator

[4]:
v = vec('z') # unit-length vector in direction af axis z
u = F @ v
u
[4]:
Vector3(1, 0, 0.5)

I property returns inverse matrix

[5]:
F.I @ u
[5]:
Vector3(0, 0, 1)

To transpose matrix, we can use T property and for multiplification we have to use @ operator

[6]:
F.T @ F
[6]:
DeformationGradient3
[[4.   0.   2.  ]
 [0.   1.   0.  ]
 [2.   0.   1.25]]
[7]:
v @ F.T @ F @ v
[7]:
1.25

Eigenvalues and eigenvectors could be obtained by methods eigenvalues and eigenvectors. Individual eigenvalues and eigen vectors could be accessed by properties E1, E2, E3 and V1, V2, V3

Deformation gradient and rotations

Deformation gradient DeformationGradient3 could describe distorsion, dilation and rigid-body rotation. All APSG features provides transform method which transform then using provided deformation gradient.

The rigid-body rotation could be either extracted from deformation gradient using R method:

[8]:
R = F.R
R
[8]:
DeformationGradient3
[[ 0.928  0.     0.371]
 [ 0.     1.     0.   ]
 [-0.371  0.     0.928]]

or could be created of one of the class methods like from_axisangle, defining axis of rotation and angle

[9]:
R = defgrad.from_axisangle(lin(120, 50), 60)
R
[9]:
DeformationGradient3
[[ 0.552 -0.753  0.359]
 [ 0.574  0.655  0.492]
 [-0.605 -0.065  0.793]]

from_two_vectors, where axis of rotation is perpendicular to both vectors and angle is angle of vectors

[10]:
R = defgrad.from_two_vectors(lin(120, 50), lin(270, 80))
R
[10]:
DeformationGradient3
[[ 0.938  0.074  0.339]
 [ 0.186  0.718 -0.671]
 [-0.294  0.692  0.66 ]]
[11]:
lin(120, 50).transform(R)
[11]:
L:270/80

or by from_vectors_axis, where axis do not need to by perpendicular to vectors. Note that rotation axis needs to be adjusted to provide correct rotation of vector.

[12]:
R = defgrad.from_vectors_axis(lin(45,30), lin(135, 30), lin(90, 70))
R
[12]:
DeformationGradient3
[[-0.393 -0.864  0.315]
 [ 0.864 -0.23   0.448]
 [-0.315  0.448  0.837]]
[13]:
lin(45,30).transform(R)
[13]:
L:135/30
[14]:
a, ang = R.axisangle()
print(lin(a), ang)
L:90/70 113.1157146919613

from_two_pairs method, to describe rotation between two coordinate systems. Note that pair define X axis as lineation vector and Z axis as foliation vector.

[15]:
p1 = pair(150, 60, 90, 40)
p2 = pair(45, 30, 10, 25)
R = defgrad.from_two_pairs(p1, p2)
R
[15]:
DeformationGradient3
[[-0.071  0.97   0.234]
 [-0.874 -0.174  0.453]
 [ 0.48  -0.173  0.86 ]]
[16]:
p1.transform(R)
[16]:
P:45/30-10/25

Ellipsoid

In deformation analysis, the quadratic forms are represented by Ellipsoid class. It could be used to represents either ellipsoid objects or finite strain ellipsoid.

It provides additional methods and properties including lambda1, lambda2 and lambda3 for square-root of eigenvalues, Woodcock’s shape and strength, k, K, d and D for Flinn’s and Ramsay symmetries and intensities, lode for Lode’s parameter etc. For more check documentation. Eigenvectors could be also represented by linear or planar features using properties eigenlins and eigenfols.

We can create Ellipsoid object similarly to Matrix3 (note that only components of upper triangular part are available in from_comp method due to matrix symmetry), or you can use aditional class methods from_defgrad and from_stretch.

[17]:
B = ellipsoid.from_defgrad(F)  # Finger deformation tensor
B
[17]:
Ellipsoid
[[5.   0.   0.5 ]
 [0.   1.   0.  ]
 [0.5  0.   0.25]]
(S1:2.25, S2:1, S3:0.445)

In above example, the Finger deformation tensor B represents finite strain ellipsoid reulting from deformation described by deformation gradient F. We can explore several parameters:

[18]:
print(f'Principal stretches: Sx={B.S1}, Sy={B.S2}, Sz={B.S3}')
print(f'Principal strain ratios: Rxy={B.Rxy}, Ryz={B.Ryz}')
print(f"Flinn's finite strain parameters: d={B.d}, k={B.k}")
print(f"Ramsay's finite strain parameters: d={B.D}, k={B.K}")
print(f"Woodcock's parameters: strength={B.strength}, shape={B.shape}")
print(f"Watterson's strain intesity: s{B.r}")
print(f"Nadai's natural octahedral unit shear: {B.goct}")
print(f"Nadai's natural octahedral unit strain: {B.eoct}")
print(f"Lode's parameter: {B.lode}")
Principal stretches: Sx=2.2476790206496235, Sy=1.0, Sz=0.44490338291762865
Principal strain ratios: Rxy=2.2476790206496235, Ryz=2.2476790206496235
Flinn's finite strain parameters: d=1.7644845924910786, k=1.0
Ramsay's finite strain parameters: d=1.3118699860194973, k=1.0
Woodcock's parameters: strength=1.6197962748565002, shape=1.0
Watterson's strain intesity: s3.495358041299247
Nadai's natural octahedral unit shear: 1.3225581202197996
Nadai's natural octahedral unit strain: 1.14536893009174
Lode's parameter: 0.0
[19]:
C = ellipsoid.from_defgrad(F, 'right')  # Green's deformation tensor
C
[19]:
Ellipsoid
[[4.   0.   2.  ]
 [0.   1.   0.  ]
 [2.   0.   1.25]]
(S1:2.25, S2:1, S3:0.445)
[20]:
v @ C @ v
[20]:
1.25

Orientation tensor

OrientationTensor3 class represents orientation tensor of set of vectors, linear or planar features. In adition to Ellipsoid methods and properties, it provides properties to describe orientation distribution, e.g. Vollmer’s P, G, R and B indexes, Intensity for Lisle intensity index and MAD for approximate angular deviation.

[21]:
l = linset.random_fisher(position=lin(120,40))
ot = l.ortensor()
# or
ot = ortensor.from_features(l)
ot
[21]:
OrientationTensor3
[[ 0.169 -0.226 -0.218]
 [-0.226  0.423  0.37 ]
 [-0.218  0.37   0.407]]
(S1:0.958, S2:0.214, S3:0.193)
[22]:
ot.eigenvalues()
[22]:
array([0.91691349, 0.04592418, 0.03716233])
[23]:
ot.eigenvectors()
[23]:
(Vector3(-0.387, 0.66, 0.644),
 Vector3(0.194, -0.625, 0.756),
 Vector3(0.901, 0.418, 0.114))
[24]:
ot.kind
[24]:
'L'

The instances of Stress3, Ellipsoid and OrientationTensor3 also provides eigenlins and eigenfols properties to represent principal axes and planes

[25]:
ot.eigenlins
[25]:
(L:120/40, L:287/49, L:25/7)
[26]:
ot.eigenfols
[26]:
(S:300/50, S:107/41, S:205/83)
[27]:
ot.strength, ot.shape
[27]:
(1.6028587004277868, 14.14302389342446)
[28]:
ot.k, ot.d
[28]:
(31.063343962312064, 3.4701087058410436)
[29]:
ot.K, ot.D
[29]:
(14.14302389342446, 2.252244853321263)
[30]:
ot.P, ot.G, ot.R
[30]:
(0.8709893116100177, 0.017523685957085658, 0.11148700243289719)
[31]:
ot.MAD
[31]:
16.75305404050666
[ ]: