next up previous contents index
Next: System Size Dependence Up: On Various Questions in Previous: Invariance of

Isotropic Tensors

    In a fluid, there is no preferred direction, and consequently any property of the fluid with tensorial character must be isotropic, i.e. the components of the tensor have the same value regardless of the coordinate system used, provided that the same metric is used. Isotropic tensors up to rank four are given in the little monograph by Temple [1960]. Eu [1979] give the complete set of isotropic six rank tensors. Other than these, there appears to be no generally available source of isotropic tensors. One approach to generating isotropic tensors of arbitrary rank in three dimensions is to note that any even rank isotropic tensor must be expressed as a linear combination of products of the unit tensor (), and odd tensors as a linear combination of products of the    unit tensor and the Levi-Cevita, or determinant tensor (). This result is based on Weyl's theory of invariant polynomials [see Temple [1960] for a discussion] . In practice, this means finding every possible way of writing products of inner products between pairs of vectors, so that for example, the space of isotropic rank four tensors will be spanned by:

and that the space of rank five isotropic tensors is spanned by:

Because the generalized constitutive relation (gif) must be symmetric with respect to changes in sign of the thermodynamic force and flux, we are only interested in even rank tensors. I have written a program that generates the isotropic tensors of arbitrary even rank, and then proceeds to apply symmetrization operations to the tensors to produce the final set of independent tensors. Modifying it to produce odd rank tensors should not be too difficult a task. An example of its use, may be found in finding the number of transport coefficients used to describe the second order Burnett coefficient between stress and strain. This coefficient connects a second rank stress tensor with the square of a second rank strain tensor. The coefficient is thus of sixth rank. There are fifteen sixth rank isotropic tensors, but not all of them are valid candidates because the only non-vanishing components must be symmetric with respect to interchanges of the third and fifth argument, as well as the fourth and the sixth. This is the case because in the expression , interchanging the two s produces no effect, neither the two s. In the program, this is performed by the lines

  Symmetrize(LinComb[i], 3, 5);
  Symmetrize(LinComb[i], 4, 6);
In the case of a monatomic fluid, we may further expect that the tensor should be symmetric with respect to the first two indices.

The program listing following can be used for arbitrary rank by changing the constants rank, NoComp and NoCompp1. Rank is fairly obviously the tensorial rank of the tensor under study. NoComp is the number of independent isotropic tensors of that rank, given by .

In the program, the basis tensors are represented as an array with rank components of type integer, which contain the sequence of vectors involved in the inner products. For example, in the rank four case would be represented by the integer sequence 1423. The complete basis is generated in the calcTensors procedure, and stored in Tensors. It does this by generating all possible permutations of the rank vectors, then expressing them all in a canonical form in which each pair is ordered so that the lowest index comes first within the pairs, and the pairs are then ordered according to the first index in each pair. When the canonical form is found, it is checked against a list of all previous canonical tensors found, and only added to the list if it is found to be distinct.

To generate the symmetrized tensors, we store the coefficients of a linear combination of the basis tensors in variables of type LinType. The algorithm proceeds by taking every basis tensor corresponding to non-zero coefficients, swapping the indices to be symmetrized, placing the tensor in canonical form, comparing this result against the basis list to find which tensor it corresponds to, then adding the original non-zero coefficient to the slot corresponding to the swapped basis tensor.

program tensors;
{even rank version}
  const
    rank = 6;
    NoComp = 15;    {NoComp = (rank-1)(rank-3)...3}
    NoCompp1 = 16; {NoComp+1}
  type
    jvalType = set of 2..rank;
    TensorType = array[1..rank] of integer;
    LinType = array[1..NoComp] of integer;
  var
    tensor: array[1..NoCompp1] of TensorType;
    i, j: integer;
    TensorIndex: integer;
    zero: LinType;
    LinComb: array[1..NoComp] of LinType;
    out: text;

  procedure swap (var x, y: integer);
    var
      t: integer;
  begin
    t := x;
    x := y;
    y := t;
  end;

  procedure Sort (left, right: integer; var Tensor: TensorType);
{Yep, the good old Qsort routine copied from ATPUG issue 1}
    var
      II, JJ, temp: integer;
      Pivot: integer;
      IIisGTright, JJisLTleft, IIgreatThan: boolean;

  begin
    II := left;
    JJ := right;
    pivot := Tensor[pred(2 * ((II + JJ) div 2))];
    repeat
      while Tensor[pred(2 * II)] < pivot do
        II := succ(II);
      while Tensor[pred(2 * JJ)] > pivot do
        JJ := pred(JJ);
      if II <= JJ then
        begin
          swap(Tensor[2 * II - 1], Tensor[2 * JJ - 1]);
          swap(Tensor[2 * II], Tensor[2 * JJ]);
          II := succ(II);
          JJ := pred(JJ);
        end;
    until II > JJ;
    if JJ > left then
      Sort(left, JJ, Tensor);
    if II < right then
      Sort(II, right, Tensor)
  end;

  function eq (x, y: tensorType): boolean;
    var
      i: integer;
      result: boolean;
  begin
    result := true;
    for i := 1 to rank do
      result := result and (x[i] = y[i]);
    eq := result;
  end;

  function eqL (x, y: LinType): boolean;
    var
      i: integer;
      result: boolean;
  begin
    result := true;
    for i := 1 to NoComp do
      result := result and (x[i] = y[i]);
    eqL := result;
  end;

  procedure canonical (var tensor: tensortype);
    var
      j: integer;
  begin
{order each pair}
    for j := 1 to rank div 2 do
      if tensor[2 * j - 1] > tensor[2 * j] then
        swap(Tensor[2 * j - 1], Tensor[2 * j]);
    sort(1, rank div 2, Tensor);
  end;

  procedure calcTensors;
    var
      TTensor: TensorType;
{TensorIndex: integer;}

      procedure GenerLoop (nest: integer; jvals: jvaltype; TTensor: tensorType);
      var
        j, k: integer;
    begin
      for j := (nest + 2) div 2 to rank do
        if not (j in jvals) then
          begin
            TTensor[nest] := j;
            if nest < rank then
              GenerLoop(succ(nest), jvals + [j], TTensor)
            else
              begin
                canonical(TTensor);
                k := 1;
                while not eq(TTensor, Tensor[k]) and (k < TensorIndex) do
                  k := succ(k);
                if k = TensorIndex then
                  begin
                    if TensorIndex > NoComp then
                      writeln('Either I stuffed up,',
                         ' or you guessed the wrong value for NoComp');
                    tensor[k] := TTensor;
                    TensorIndex := succ(TensorIndex);
                  end;
              end; {of else}
          end; {of if not (j in jval)}
    end; {of GenerLoop}

  begin
    TensorIndex := 1;
    TTensor[1] := 1;
    GenerLoop(2, [], TTensor);
  end;

  procedure symmetrizePairs (var LinComb: LinType; pr1, pr2: integer);
{Symmetrize tensor with respect to two pairs of indices}
    var
      NewLin: LinType;
      i, j: integer;
      TTensor: TensorType;
  begin
    NewLin := zero;
    for i := 1 to NoComp do
      if LinComb[i] > 0 then
        begin
{get representation of component}
          TTensor := Tensor[i];
{swap pairs 1 and 2}
          for j := 1 to rank do
            if TTensor[j] = 2 * pr1 then
              TTensor[j] := 2 * pr2
            else if TTensor[j] = pred(2 * pr1) then
              TTensor[j] := pred(2 * pr2)
            else if TTensor[j] = 2 * pr2 then
              TTensor[j] := 2 * pr1
            else if TTensor[j] = pred(2 * pr2) then
              TTensor[j] := pred(2 * pr1);
          canonical(TTensor);
{find TTensor in the list}
          j := 0;
          repeat
            j := j + 1
          until eq(TTensor, Tensor[j]);
{add the swapped part to make it symmetric}
          NewLin[j] := NewLin[j] + LinComb[i];
        end; {of for i:=1 to NoComp}
{add NewLin to LinComb}
    for i := 1 to NoComp do
      LinComb[i] := LinComb[i] + NewLin[i];
  end; {of symmetrizePairs}

  procedure symmetrize (var LinComb: LinType; Index1, Index2: integer);
{Symmetrize tensor with respect to two indices}
    var
      NewLin: LinType;
      i, j: integer;
      TTensor: TensorType;
  begin
    NewLin := zero;
    for i := 1 to NoComp do
      if LinComb[i] > 0 then
        begin
{get representation of component}
          TTensor := Tensor[i];
{swap pairs 1 and 2}
          for j := 1 to rank do
            if TTensor[j] = Index1 then
              TTensor[j] := Index2
            else if TTensor[j] = Index2 then
              TTensor[j] := Index1;
          canonical(TTensor);
{find TTensor in the list}
          j := 0;
          repeat
            j := j + 1
          until eq(TTensor, Tensor[j]);
{add the swapped part to make it symmetric}
          NewLin[j] := NewLin[j] + LinComb[i];
        end; {of for i:=1 to NoComp}
{add NewLin to LinComb}
    for i := 1 to NoComp do
      LinComb[i] := LinComb[i] + NewLin[i];
  end; {of symmetrize}

begin
  CalcTensors;
  for i := 1 to NoComp do
    zero[i] := 0;
  for i := 1 to NoComp do
    begin
      LinComb[i] := zero;
      LinComb[i][i] := 1;
      Symmetrize(LinComb[i], 1, 2);
      Symmetrize(LinComb[i], 3, 5);
      Symmetrize(LinComb[i], 4, 6);
      j := 0;
      repeat
        j := succ(j)
      until eqL(LinComb[j], LinComb[i]);
      if i = j then {the linear combination is unique, so output it}
        begin
          for j := 1 to NoComp do
            if LinComb[i][j] <> 0 then
              write(LinComb[i][j] : 1, '*I(', j : 3, ')+');
          writeln;
        end;
    end;
end.



next up previous contents index
Next: System Size Dependence Up: On Various Questions in Previous: Invariance of



Russell Standish
Thu May 18 11:43:52 EST 1995