def covariantDerivative(T): """ Returns a ``CurvilinearTensor`` that is the covariant derivative of the ``CurvilinearTensor`` argument ``T``. """ n = rank(T.T) ii = indices(n + 2) g = T.g gamma = getChristoffel(g) retval = grad(T.T) for i in range(0, n): # use ii[n] as the new index of the covariant deriv # use ii[n+1] as dummy index if (T.lowered[i]): retval -= as_tensor(T.T[ii[0:i]+(ii[n+1],)+ii[i+1:n]]\ *gamma[(ii[n+1],ii[i],ii[n])],\ ii[0:n+1]) else: retval += as_tensor(T.T[ii[0:i]+(ii[n+1],)+ii[i+1:n]]\ *gamma[(ii[i],ii[n+1],ii[n])],\ ii[0:n+1]) newLowered = T.lowered + [ True, ] return CurvilinearTensor(retval, g, newLowered)
def assemble(e, dx): """Assemble UFL form given by UFL expression e and UFL integration measure dx. The expression can be a tensor quantity of rank 0, 1 or 2. Parameters ---------- e: UFL Expr dx: UFL Measure Returns ------- Assembled form f = e * dx as scalar or numpy array (depends on rank of e). """ import numpy as np from mpi4py import MPI rank = ufl.rank(e) shape = ufl.shape(e) if rank == 0: f_ = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e * dx), op=MPI.SUM) elif rank == 1: f_ = np.zeros(shape) for row in range(shape[0]): f_[row] = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e[row] * dx), op=MPI.SUM) elif rank == 2: f_ = np.zeros(shape) for row in range(shape[0]): for col in range(shape[1]): f_[row, col] = MPI.COMM_WORLD.allreduce(dolfinx.fem.assemble_scalar(e[row, col] * dx), op=MPI.SUM) return f_
def cartesianCurl(f, F): """ The curl operator corresponding to ``cartesianGrad(f,F)``. For ``f`` of rank 1, it returns a vector in 3D or a scalar in 2D. For ``f`` scalar in 2D, it returns a vector. """ n = rank(f) gradf = cartesianGrad(f, F) if (n == 1): m = shape(f)[0] eps = PermutationSymbol(m) if (m == 3): (i, j, k) = indices(3) return as_tensor(eps[i, j, k] * gradf[k, j], (i, )) elif (m == 2): (j, k) = indices(2) return eps[j, k] * gradf[k, j] else: print("ERROR: Unsupported dimension of argument to curl.") exit() elif (n == 0): return as_vector((-gradf[1], gradf[0])) else: print("ERROR: Unsupported rank of argument to curl.") exit()
def cartesianDiv(f, F): """ The divergence operator corresponding to ``cartesianGrad(f,F)`` that sums on the last two indices. """ n = rank(f) ii = indices(n) return as_tensor(cartesianGrad(f, F)[ii + (ii[n - 1], )], ii[0:n - 1])
def flat(self): """ Returns an associated tensor with all indices lowered. """ retval = self for i in range(0, rank(self.T)): retval = retval.lowerIndex(i) return retval
def sharp(self): """ Returns an associated tensor with all indices raised. """ retval = self for i in range(0, rank(self.T)): retval = retval.raiseIndex(i) return retval
def curvilinearInner(T, S): """ Returns the inner product of ``CurvilinearTensor`` objects ``T`` and ``S``, inserting factors of the metric and inverse metric as needed, depending on the co/contra-variant status of corresponding indices. """ Tsharp = T.sharp() Sflat = S.flat() ii = indices(rank(T.T)) return as_tensor(Tsharp.T[ii] * Sflat.T[ii], ())
def curvilinearGrad(T): """ Returns the gradient of ``CurvilinearTensor`` argument ``T``, i.e., the covariant derivative with the last index raised. """ n = rank(T.T) ii = indices(n + 2) g = T.g deriv = covariantDerivative(T) invg = inv(g) # raise last index retval = as_tensor(deriv.T[ii[0:n+1]]*invg[ii[n:n+2]],\ ii[0:n]+(ii[n+1],)) return CurvilinearTensor(retval, g, T.lowered + [ False, ])
def raiseLowerIndex(self, i): """ Flips the raised/lowered status of the ``i``-th index. """ n = rank(self.T) ii = indices(n + 1) mat = self.g if (self.lowered[i]): mat = inv(self.g) else: mat = self.g retval = as_tensor(self.T[ii[0:i]+(ii[i],)+ii[i+1:n]]\ *mat[ii[i],ii[n]],\ ii[0:i]+(ii[n],)+ii[i+1:n]) return CurvilinearTensor(retval,self.g,\ self.lowered[0:i]\ +[not self.lowered[i],]+self.lowered[i+1:])
def __init__(self, T, g, lowered=None): """ Create a ``CurvilinearTensor`` with components given by the UFL tensor ``T``, on a manifold with metric ``g``. The sequence of Booleans ``lowered`` indicates whether or not each index is lowered. The default is for all indices to be lowered. """ self.T = T self.g = g if (lowered != None): self.lowered = lowered else: # default: all lowered indices self.lowered = [] for i in range(0, rank(T)): self.lowered += [ True, ]
def curvilinearDiv(T): """ Returns the divergence of the ``CurvilinearTensor`` argument ``T``, i.e., the covariant derivative, but contracting over the new index and the last raised index. NOTE: This operation is invalid for tensors that do not contain at least one raised index. """ n = rank(T.T) ii = indices(n) g = T.g j = -1 # last raised index for i in range(0, n): if (not T.lowered[i]): j = i if (j == -1): print("ERROR: Divergence operator requires at least one raised index.") exit() deriv = covariantDerivative(T) retval = as_tensor(deriv.T[ii[0:n] + (ii[j], )], ii[0:j] + ii[j + 1:n]) return CurvilinearTensor(retval, g, T.lowered[0:j] + T.lowered[j + 1:n])
def rank(self): """ Returns the rank of the tensor. """ return rank(self.T)