Vector Fields in Orientation Space edit page

Vector fields in orientation space model orientation dependent spin as it occurs for instance in the Taylor or Sachs model. Another typical example are gradients of orientation distribution functions.

Orientation Dependent Spin Tensors as Vector Fields

According to Taylor theory the strain acting on a crystal with orientation ori is compensated by the action of different slip systems. The antisymmetric portion of deformation tensors of these active slip systems gives a spin tensors that describes the local misorientation the crystal undergoes under deformation. In MTEX the spin tensor W as a function of the orientation ori is computed as a variable of type SO3VectorField by the command calcTaylor.

% consider bcc symmetry and slip systems
cs = crystalSymmetry('432');
sS = slipSystem.bcc(cs)

% consider plane stain
q = 0;
epsilon = strainTensor(diag([1 -q -(1-q)]))

% compute the orientation depended spin tensor
[~,~,W] = calcTaylor(epsilon,sS.symmetrise)
sS = slipSystem (432)
 size: 1 x 3
 
   u    v    w  | h    k    l CRSS
   1   -1    1    0    1    1    1
  -1    1    1    2    1    1    1
  -1    1    1    3    2    1    1
 
epsilon = strainTensor (xyz)
  type: Lagrange 
  rank: 2 (3 x 3)
 
  1  0  0
  0  0  0
  0  0 -1
 
W = SO3VectorFieldHarmonic (432 → xyz)
  bandwidth: 32
  tangent space: rightSpinTensor

Lets visualize the spin tensor in Euler angle sections

sP = phi1Sections(cs,specimenSymmetry('222'));
sP.phi1 = (10:20:70)*degree;

% plot the Taylor factor
plot(W,sP,'resolution',7.5*degree,'layout',[2 2])

We observe how according to the orientation the Taylor model predicts a misorientation of the corresponding crystal. For a specific (set of) orientation ori we can retrieve the spin tensor by evaluating the vector field W at this position

% the spin tensor for the copper orientation
WCopper = W.eval(orientation.copper(cs))
WCopper = spinTensor (432)
  rank: 2 (3 x 3)
 
 *10^-2
      0      0  32.15
      0      0  32.15
 -32.15 -32.15      0

The Norm of a Vector Field

The norm of the spin tensor directly relates to the amount of misorientation. We may compute the amount of misorientations as a function of orientation by the command norm and determine the orientation of maximum misorientation by

% determine the orientation of maximum misorientation
[~,oriMax] = max(norm(W))

% visualize the amount of misorientation
plot(norm(W),sP,'resolution',0.5*degree,'layout',[2 2])
mtexColorMap LaboTeX

% plot the vector field on top
hold on
plot(W,sP,'resolution',7.5*degree,'color','black')
hold off

annotate(oriMax)
oriMax = misorientation (432 → 1)
 
  Bunge Euler angles in degree
     phi1     Phi    phi2
  271.318 45.3713 116.559

As the vector field W corresponds to the rotational axis of the local misorientation we may check how much this axis corresponds with a predefined axis, e.g. [100], by computing the inner product dot(W,d) between the vector field W and the predefined axis d.

plot(dot(W,Miller(1,0,0,cs)),sP,'layout',[2 2])
mtexColorMap blue2red
mtexColorbar

The Flux of a Vector Field

If we interpret the vector field W as a velocity field for the different crystal orientations. Then its divergence is a scalar field that indicates where orientations condense. In this interpretation a sink corresponds to negative flux / divergence and a source to positive flux / divergence.

flux = W.div

plot(flux,sP,'resolution',0.5*degree,'layout',[2 2],'faceAlpha',0.5)
mtexColorMap blue2red
mtexColorbar

hold on
plot(W,sP,'resolution',7.5*degree,'color','black')
hold off
flux = SO3FunHarmonic (432 → xyz)
  bandwidth: 32
  weight: 0

The Curl of a Vector Field

The counterpart of the flux is the curl of a vector field which describes the axis of local rotation within the crystal orientations

c = W.curl

plot(c,sP,'resolution',7.5*degree,'layout',[2 2],'color','black')
c = SO3VectorFieldHarmonic (432 → xyz)
  bandwidth: 32
  tangent space: leftVector

The Gradient of Orientation distribution Functions

A second natural usage of vector fields is as gradients of orientation dependent functions, e.g. ODF. Lets consider the following ODF of a quartz specimen

odf = SO3Fun.dubna
odf = SO3FunRBF (Quartz → xyz)
 
  <strong>multimodal components</strong>
  kernel: de la Vallee Poussin, halfwidth 5°
  center: 19848 orientations, resolution: 5°
  weight: 1

Then its gradient is computed by the command odf.grad

g = odf.grad
g = SO3VectorFieldHarmonic (Quartz → xyz)
  bandwidth: 48
  tangent space: leftVector

Lets visualize the ODF together with its gradient in a sigma section plot

plot(odf,'sigma')
hold on
plot(g,'linewidth',1.5,'color','black','resolution',7.5*degree)
hold off

We observe how the gradients all points towards the closest local maximum. This is actually the foundation of the steepest descent algorithm used by MTEX in the commands max(odf) and calcComponents(odf)

As the gradient of a function is a vector field we may compute its curl and divergence. From mathematics we know that the curl must be zero

plot(g.curl,'sigma')

and the divergence coincides with the Laplacian of the

plot(g.div,'sigma',60*degree)
nextAxis
plot(laplace(SO3FunHarmonic(odf)),'sigma',60*degree)
mtexColorbar

The fact that the curl of a vector field is zero is actually equivalent to the fact that the vector field is the gradient of some potential field, which can be computed by the command antiderivative(g) and coincides exactly with the original ODF odf.

odf2 = g.antiderivative

plot(odf2,'sigma')
odf2 = SO3FunHarmonic (Quartz → xyz)
  bandwidth: 48
  weight: 0

Overview of Operations for Orientational Vector Fields

The following operations are defined for vector fields VF, VF1, VF2

Definition of Orientational Vector Fields

Explicitly by an Anonymous Function

Analogous to SO3FunHandle we are able to define SO3VectorFields by an anonymous function.

% cubic symmetry
cs = crystalSymmetry('432')

% product of rotational axis and rotational angle
f = @(mori) axis(mori) .* angle(mori);

% define the vector field
VF = SO3VectorFieldHandle(f,cs,cs)

% evaluating the vector field gives what we expect
round(VF.eval(orientation.byAxisAngle(vector3d(1,2,3),10*degree)))
cs = crystalSymmetry
 
  symmetry: 432    
  elements: 24     
  a, b, c : 1, 1, 1
 
 
VF = SO3VectorFieldHandle (432 → 432)
  tangent space: leftVector
 
 
ans = SO3TangentVector
 TagentSpace: leftVector
  x y z
  1 2 3

But plotting does not -- TODO!!!

% plot it
quiver3(VF,'axisAngle','resolution',7.5*degree,'color','black','linewidth',2)

Definition via SO3VectorField

We can expand any SO3VectorField in an SO3VectorFieldHarmonic directly by the command SO3VectorFieldHarmonic

SO3VectorFieldHarmonic(VF)
ans = SO3VectorFieldHarmonic (432 → 432)
  bandwidth: 64
  tangent space: leftVector

Definition via function values

At first we need some example rotations

nodes = equispacedSO3Grid(specimenSymmetry('1'),'points',1e3);
nodes = nodes(:);

Next, we define function values for the rotations

y = vector3d.byPolar(sin(3*nodes.angle), nodes.phi2+pi/2);

Now the actual command to get SO3VF1 of type SO3VectorFieldHarmonic

SO3VF1 = SO3VectorFieldHarmonic.approximation(nodes, y)
Warning: The given vector3d values v are assumed to
describe elements w.r.t. the left side tangent space. If
you want them to be right sided use
SO3TangentVector(v,SO3TangentSpace.rightVector) instead. 
 
SO3VF1 = SO3VectorFieldHarmonic (xyz → xyz)
  bandwidth: 8
  tangent space: leftVector

Definition via function handle

If we have a function handle for the function we could create a S2VectorFieldHarmonic via quadrature. At first lets define a function handle which takes rotation as an argument and returns a vector3d:

Now we can call the quadrature command to get SO3VF2 of type SO3VectorFieldHarmonic

SO3VF2 = SO3VectorFieldHarmonic.quadrature(@(v) f(v))
SO3VF2 = SO3VectorFieldHarmonic (xyz → xyz)
  bandwidth: 64
  tangent space: leftVector

Definition via SO3FunHarmonic

If we directly call the constructor with a multivariate SO3FunHarmonic with three entries it will create a SO3VectorFieldHarmonic with SO3F(1), SO3F(2), and SO3F(3) the \(x\), \(y\), and \(z\) component.

SO3F = SO3FunHarmonic(rand(1e3, 3))
SO3VF3 = SO3VectorFieldHarmonic(SO3F)
SO3F = SO3FunHarmonic (xyz → xyz)
  isReal: false
  size: 3 x 1
  bandwidth: 9
  weight: 0.88
 
 
SO3VF3 = SO3VectorFieldHarmonic (xyz → xyz)
  isReal: false
  bandwidth: 9
  tangent space: leftVector