Set<MultipleDeriv> applyZx(const Set<MultipleDeriv>& W, const MultiIndex& x) { Set<MultipleDeriv> rtn; TEUCHOS_TEST_FOR_EXCEPTION(x.order() < 0 || x.order() > 1, std::logic_error, "invalid multiindex " << x << " in this context"); for (Set<MultipleDeriv>::const_iterator i=W.begin(); i!=W.end(); i++) { const MultipleDeriv& md = *i; TEUCHOS_TEST_FOR_EXCEPTION(md.order() != 1, std::logic_error, "Only first-order multiple functional derivatives " "should appear in this function. The derivative " << md << " is not first-order."); const Deriv& d = *(md.begin()); if (d.isFunctionalDeriv()) { /* */ TEUCHOS_TEST_FOR_EXCEPTION(!d.canBeDifferentiated(), std::logic_error, "function signature " << d << " cannot be " "differentiated further spatially"); /* accept a functional derivative if the associated function * is not identically zero */ const SymbolicFuncElement* sfe = d.symbFuncElem(); TEUCHOS_TEST_FOR_EXCEPTION(sfe==0, std::logic_error, "can't cast function in " << d << " to a SymbolicFuncElement"); if (sfe && !sfe->evalPtIsZero()) rtn.put(md); } } return rtn; }
Set<MultipleDeriv> Xx(const MultiIndex& x) { Set<MultipleDeriv> rtn; TEUCHOS_TEST_FOR_EXCEPTION(x.order() < 0 || x.order() > 1, std::logic_error, "invalid multiindex " << x << " in this context"); MultipleDeriv xmd = makeMultiDeriv(coordDeriv(x.firstOrderDirection())); rtn.put(xmd); return rtn; }
Expr SpectralPreprocessor::takeDeriv(const Expr& f, const MultiIndex& mi) { TEUCHOS_TEST_FOR_EXCEPT(mi.order() > 1); const SpectralExpr* se = dynamic_cast<const SpectralExpr*>(f.ptr().get()); Expr d = new Derivative(mi.firstOrderDirection()); int n = se->getSpectralBasis().nterms(); if (se) { Array<Expr> c(n); for (int i=0; i<n; i++) { c[i] = d*se->getCoeff(i); } return new SpectralExpr(se->getSpectralBasis(), c); } else { return d*f; } }
void CubicHermite::evalOnTriangle(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { result.resize(10); ADReal x = ADReal(pt[0], 0, 2); ADReal y = ADReal(pt[1], 1, 2); ADReal one(1.0, 2); Array<ADReal> tmp(10); SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y=" << y.value()); tmp[0] = 1 - 3*x*x + 2 * x*x*x - 13*x*y + 13*x*x*y - 3*y*y + 13 *x*y*y + 2 *y*y*y; tmp[1] = x - 2 *x*x + x*x*x - 3*x*y + 3*x*x*y + 2*x*y*y; tmp[2] = y - 3 *x *y + 2* x*x* y - 2* y*y + 3* x*y*y + y*y*y; tmp[3] = 3 * x*x - 2* x*x*x - 7* x* y + 7* x*x *y + 7* x*y*y; tmp[4] = -x*x + x*x*x + 2*x *y - 2* x*x* y - 2* x* y*y; tmp[5] = -x* y + 2* x*x* y + x* y*y; tmp[6] = -7* x* y + 7* x*x*y + 3* y*y + 7* x* y*y - 2* y*y*y; tmp[7] = -x *y + x*x* y + 2* x* y*y; tmp[8] = 2 *x *y - 2* x*x* y - y*y - 2* x* y*y + y*y*y; tmp[9] = 27* x *y - 27* x*x* y - 27* x* y*y; for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } }
void CubicHermite::evalOnLine(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { result.resize(4); ADReal x = ADReal(pt[0],0,1); Array<ADReal> tmp(4); tmp[0] = 1 + x * x * ( -3 + 2 * x ); tmp[1] = x * ( 1 + (x - 2 ) * x ); tmp[2] = ( 3 - 2*x ) * x * x; tmp[3] = (-1+x)*x*x; for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) { result[i] = tmp[i].value(); } else { result[i] = tmp[i].gradient()[0]; } } return; }
void EdgeLocalizedBasis::evalOnTriangle(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { ADReal x = ADReal(pt[0], 0, 2); ADReal y = ADReal(pt[1], 1, 2); ADReal one(1.0, 2); ADReal zero(0.0, 2); Array<ADReal> tmp; SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y=" << y.value()); result.resize(3); tmp.resize(3); bool onEdge2 = std::fabs(pt[1]) < 1.0e-14; bool onEdge0 = std::fabs(1.0-pt[0]-pt[1]) < 1.0e-14; bool onEdge1 = std::fabs(pt[0]) < 1.0e-14; TEUCHOS_TEST_FOR_EXCEPTION(!(onEdge0 || onEdge1 || onEdge2), std::runtime_error, "EdgeLocalizedBasis should not be evaluated at points not on edges"); TEUCHOS_TEST_FOR_EXCEPTION((onEdge0 && onEdge1) || (onEdge1 && onEdge2) || (onEdge2 && onEdge0), std::runtime_error, "Ambiguous edge in EdgeLocalizedBasis::evalOnTriangle()"); if (onEdge0) { tmp[0] = one; tmp[1] = zero; tmp[2] = zero; } if (onEdge1) { tmp[0] = zero; tmp[1] = one; tmp[2] = zero; } if (onEdge2) { tmp[0] = zero; tmp[1] = zero; tmp[2] = one; } for (int i=0; i<tmp.length(); i++) { SUNDANCE_OUT(this->verb() > 3, "tmp[" << i << "]=" << tmp[i].value() << " grad=" << tmp[i].gradient()); if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } }
void Legendre::evalOnLine(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { result.resize(2+nrDOF_edge_); ADReal x = ADReal(pt[0],0,1); Array<ADReal> refAll(7); refAll[0] = 1-x; refAll[1] = x; refAll[2] = 2.44948974278318 * ( (2*x-1)*(2*x-1) - 1 ) / 4; refAll[3] = 3.16227766016838 * ( (2*x-1)*(2*x-1) - 1 ) * (2*x-1) / 4; refAll[4] = 3.74165738677394 * ( 5*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 6*(2*x-1)*(2*x-1) + 1) / 16; refAll[5] = 4.24264068711929 * (2*x-1) * (7*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 10*(2*x-1)*(2*x-1) + 3) / 16; refAll[6] = 4.69041575982343 * (21*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 35*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) + 15*(2*x-1)*(2*x-1) - 1) / 32; for (int i=0; i<result.length(); i++) { if (deriv.order()==0) { result[i] = refAll[i].value(); } else { result[i] = refAll[i].gradient()[0]; } } //SUNDANCE_OUT( true , "Legendre::evalOnLine result.length():" << result.length() ); return; }
void Bernstein::evalOnTet(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { ADReal x = ADReal(pt[0], 0, 3); ADReal y = ADReal(pt[1], 1, 3); ADReal z = ADReal(pt[2], 2, 3); ADReal one(1.0, 3); Array<ADReal> tmp(result.length()); if(order_==0) { tmp.resize(1); result.resize(1); tmp[0] = one; } else { } for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } }
double TestEvalMediator::evalDummyBasis(int m, const MultiIndex& mi) const { TEUCHOS_TEST_FOR_EXCEPTION(mi.order() > 1, std::runtime_error, "TestEvalMediator::evalDummyBasis found multiindex " "order > 1. The bad multiindex was " << mi.toString()); ADReal result = fields_[m].basis().evaluate(ADField::evalPoint()); SUNDANCE_MSG3(verb(), "basis.value() " << result.value()); SUNDANCE_MSG3(verb(), "basis.gradient() " << result.gradient()); if (mi.order()==0) { return result.value(); } else { return result.gradient()[mi.firstOrderDirection()]; } }
void EdgeLocalizedBasis::evalOnLine(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { ADReal one(1.0, 1); result.resize(1); Array<ADReal> tmp(result.length()); tmp[0] = one; for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } }
SpatialDerivSpecifier SpatialDerivSpecifier::derivWrtMultiIndex(const MultiIndex& mi) const { if (isPartial() || isIdentity()) { return SpatialDerivSpecifier(mi_+mi); } else if (mi.order()==0) { return *this; } else { TEST_FOR_EXCEPTION(true, InternalError, "cannot take an arbitrary " "spatial derivative of SDS=" << *this); return *this; // -Wall } }
void Bernstein::evalOnLine(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { ADReal x = ADReal(pt[0], 0, 1); ADReal one(1.0, 1); result.resize(order()+1); Array<ADReal> tmp(result.length()); Array<double> x0(order()+1); if (order_ == 0) { tmp[0] = one; } else { double binom_cur = 1.0; for (int i=0; i<=order_; i++) { tmp[i] = one; for (int j=0;j<order_-i;j++) { tmp[i] *= (1-x); } for (int j=0;j<i;j++) { tmp[i] *= x; } tmp[i] *= binom_cur; binom_cur *= double(order()-i) / double(i+1); } } for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[0]; } }
void Legendre::evalOnQuad(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { result.resize( 4 + 4*nrDOF_edge_ + nrDOF_face_); ADReal x = ADReal(pt[0], 0, 2); ADReal y = ADReal(pt[1], 1, 2); ADReal one(1.0, 2); Array<ADReal> refAllx(7); Array<ADReal> refAlly(7); refAllx[0] = 1-x; refAllx[1] = x; refAllx[2] = 2.44948974278318 * ( (2*x-1)*(2*x-1) - 1 ) / 4; refAllx[3] = 3.16227766016838 * ( (2*x-1)*(2*x-1) - 1 ) * (2*x-1) / 4; refAllx[4] = 3.74165738677394 * ( 5*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 6*(2*x-1)*(2*x-1) + 1) / 16; refAllx[5] = 4.24264068711929 * (2*x-1) * (7*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 10*(2*x-1)*(2*x-1) + 3) / 16; refAllx[6] = 4.69041575982343 * (21*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) - 35*(2*x-1)*(2*x-1)*(2*x-1)*(2*x-1) + 15*(2*x-1)*(2*x-1) - 1) / 32; refAlly[0] = 1-y; refAlly[1] = y; refAlly[2] = 2.44948974278318 * ( (2*y-1)*(2*y-1) - 1 ) / 4; refAlly[3] = 3.16227766016838 * ( (2*y-1)*(2*y-1) - 1 ) * (2*y-1) / 4; refAlly[4] = 3.74165738677394 * ( 5*(2*y-1)*(2*y-1)*(2*y-1)*(2*y-1) - 6*(2*y-1)*(2*y-1) + 1) / 16; refAlly[5] = 4.24264068711929 * (2*y-1) * (7*(2*y-1)*(2*y-1)*(2*y-1)*(2*y-1) - 10*(2*y-1)*(2*y-1) + 3) / 16; refAlly[6] = 4.69041575982343 * (21*(2*y-1)*(2*y-1)*(2*y-1)*(2*y-1)*(2*y-1) - 35*(2*y-1)*(2*y-1)*(2*y-1)*(2*y-1) + 15*(2*y-1)*(2*y-1) - 1) / 32; SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y=" << y.value()); int sideIndex[4][2] = { {0,0} , {1,0} , {0,1} , {1,1}}; int edgeIndex[4] = { 0 , 1 , 1 , 0}; int edgeMultI[4] = { 0 , 0 , 1 , 1}; int offs = 0; Array<ADReal> tmp(4 + 4*nrDOF_edge_ + nrDOF_face_); // loop over vertexes for (int i=0; i < 4 ; i++, offs++){ tmp[offs] = refAllx[sideIndex[i][0]] * refAlly[sideIndex[i][1]]; } // loop over edges for (int i=0; i < 4 ; i++){ // loop over each DOF on the edge if (edgeIndex[i] == 0){ for (int j = 0 ; j < nrDOF_edge_ ; j++ , offs++){ tmp[offs] = refAllx[2+j] * refAlly[edgeMultI[i]]; } } else { for (int j = 0 ; j < nrDOF_edge_ ; j++ , offs++){ tmp[offs] = refAllx[edgeMultI[i]] * refAlly[2+j]; } } } // loop over all internal DOFs if ( nrDOF_face_ > 0 ){ // loop for each hierarchical layer for (int hierarch = 0 ; hierarch < order_ - 3 ; hierarch++) { //SUNDANCE_OUT( true , "Legendre::evalOnQuad hierarch:" << hierarch ); // for each layer add the basis function for (int i=0 ; i < hierarch+1 ; i++ , offs++) { //SUNDANCE_OUT( true , "Legendre::evalOnQuad offs:" << offs << " 2+i:" << 2+i << " , 2+(hierarch-1-i):" << 2+(hierarch-i)); tmp[offs] = refAllx[2+i] * refAlly[2+(hierarch-i)]; } } } // compute the results for (int i=0; i<result.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } //SUNDANCE_OUT( true , "Legendre::evalOnQuad result.length():" << result.length() ); }
void CurveEvalMediator ::evalDiscreteFuncElement(const DiscreteFuncElement* expr, const Array<MultiIndex>& multiIndices, Array<RCP<EvalVector> >& vec) const { int verbo = dfVerb(); Tabs tab1; SUNDANCE_MSG2(verbo , tab1 << "CurveEvalMediator evaluating Discrete Function expr " << expr->toString()); const DiscreteFunctionData* f = DiscreteFunctionData::getData(expr); TEUCHOS_TEST_FOR_EXCEPTION(f==0, std::logic_error, "QuadratureEvalMediator::evalDiscreteFuncElement() called " "with expr that is not a discrete function"); SUNDANCE_MSG2(verbo , tab1 << "After casting DiscreteFunctionData" << expr->toString()); RCP<Array<Array<double> > > localValues; Array<int> cellLIDs_tmp(1); Array<Point> phyPoints; Array<Point> refPoints; Array<Point> refDevs; Array<Point> refNormal; int nCells = cellLID()->size(); RCP<const MapStructure> mapStruct; int myIndex = expr->myIndex(); int nQuad = numQuadPtsForMaxCell_; Array<int> k(multiIndices.size(),0); Teuchos::BLAS<int,double> blas; SUNDANCE_MSG2(verbo , tab1 << "After declaring BLAS: " << expr->toString()); // resize correctly the result vector for (int i=0; i<multiIndices.size(); i++) { vec[i]->resize(nCells*nQuad); } // loop over each cell for (int c=0; c<nCells; c++) { int maxCellLID = (*cellLID())[c]; localValues = rcp(new Array<Array<double> >()); SUNDANCE_MSG2(verbo , tab1 << "Cell:" << c << " of " << nCells << " , maxCellLID:" << maxCellLID ); cellLIDs_tmp[0] = (*cellLID())[c]; SUNDANCE_MSG2(verbo , tab1 << " Before calling f->getLocalValues:" << cellLIDs_tmp.size() << " f==0 : " << (f==0) << " tmp:" << f->mesh().spatialDim()); // - get local values from the DiscreteFunctionElementData mapStruct = f->getLocalValues(maxCellDim(), cellLIDs_tmp , *localValues); SUNDANCE_MSG2(verbo , tab1 << " After getting mapStruct:" << maxCellLID ); SUNDANCE_MSG2(verbo , tab1 << " mapStruct->numBasisChunks():" << mapStruct->numBasisChunks() ); int chunk = mapStruct->chunkForFuncID(myIndex); int funcIndex = mapStruct->indexForFuncID(myIndex); int nFuncs = mapStruct->numFuncs(chunk); SUNDANCE_MSG2(verbo , tab1 << " chunk:" << chunk ); SUNDANCE_MSG2(verbo , tab1 << " funcIndex:" << funcIndex ); SUNDANCE_MSG2(verbo , tab1 << " nFuncs:" << nFuncs ); // the chunk of the function BasisFamily basis = rcp_dynamic_cast<BasisFamilyBase>(mapStruct->basis(chunk)); int nNodesTotal = basis.nReferenceDOFsWithFacets(maxCellType(), maxCellType()); // - get intersection (reference)points from the mesh (if not existent than compute them) if ( mesh().hasCurvePoints( maxCellLID , paramcurve_.myID() )) { mesh().getCurvePoints( maxCellLID , paramcurve_.myID() , refPoints , refDevs , refNormal ); } else // we have to calculate now the points { // calculate the intersection points CurveIntegralCalc::getCurveQuadPoints( maxCellType_ , maxCellLID , mesh() , paramcurve_ , quad_ , refPoints, refDevs , refNormal); // store the intersection point in the mesh mesh().setCurvePoints( maxCellLID , paramcurve_.myID() , refPoints, refDevs , refNormal ); } // loop over each multi-index SUNDANCE_MSG2(verbo , tab1 << " multiIndices.size()" << multiIndices.size() ); for (int i=0; i<multiIndices.size(); i++) { int nDerivResults = 1; if ( multiIndices[i].order() == 1 ) nDerivResults = maxCellDim(); int pDir = 0; int derivNum = 1; MultiIndex mi; SUNDANCE_MSG2(verbo , tab1 << " before asking anything i = " << i); SUNDANCE_MSG2(verbo , tab1 << " multiindex order : " << multiIndices[i].order()); SUNDANCE_MSG2(verbo , tab1 << " multiindex : " << multiIndices[i] ); if (multiIndices[i].order() > 0){ pDir = multiIndices[i].firstOrderDirection(); mi[pDir] = 1; derivNum = mesh().spatialDim(); } Array<Array<double> > result(nQuad*derivNum); Array<Array<Array<double> > > tmp; int offs = nNodesTotal; // resize the result vector for (int deriv = 0 ; deriv < derivNum ; deriv++) { // test weather we have to compute derivative if (multiIndices[i].order() > 0){ // in case of derivatives we set one dimension MultiIndex mi_tmp; mi_tmp[deriv] = 1; SpatialDerivSpecifier deriv(mi_tmp); SUNDANCE_MSG2(verbo , tab1 << "computing derivatives : " << deriv << " on reference cell "); basis.refEval( maxCellType_ , refPoints , deriv, tmp , verbo ); } else { SpatialDerivSpecifier deriv(mi); // --- end eval basis functions SUNDANCE_MSG2(verbo , tab1 << "computing values reference cell "); basis.refEval( maxCellType_ , refPoints , deriv, tmp , verbo ); } SUNDANCE_MSG2(verbo , tab1 << "resize result vector , offs:" << offs); for (int q=0; q<nQuad; q++){ result[nQuad*deriv + q].resize(offs); } // copy the result in an other format SUNDANCE_MSG2(verbo , tab1 << "copy results "); int offs1 = 0; for (int q=0; q<nQuad; q++) { offs1 = 0; for (int d=0; d<basis.dim(); d++) { int nNodes = tmp[d][q].size(); for (int n=0; n<nNodes; n++ , offs1++ ) { result[nQuad*deriv + q][offs1] = tmp[d][q][n]; } } } }// loop over all dimensional derivative // multiply the local results with the coefficients, (matrix vector OP) SUNDANCE_MSG2(verbo , tab1 << "summing up values , funcIndex:" << funcIndex << " offs:" << offs); for (int deriv = 0 ; deriv < derivNum ; deriv++) { for (int q=0; q<nQuad; q++) { double sum = 0.0; // sum over nodes for (int n = 0 ; n < offs ; n++){ sum = sum + result[nQuad*deriv + q][n] * (*localValues)[chunk][funcIndex*offs + n]; } // sum up the result in the 0th element result[nQuad*deriv + q][0] = sum; } } // multiply the result if necesary with the inverse of the Jacobian const CellJacobianBatch& J = JTrans(); if (mi.order()==1) { Tabs tab1; Tabs tab2; SUNDANCE_MSG2(verbo, tab2 << "Jacobian batch nCells=" << J.numCells()); SUNDANCE_MSG2(verbo, tab2 << "Jacobian batch cell dim=" << J.cellDim()); SUNDANCE_MSG2(verbo, tab2 << "Jacobian batch spatial dim=" << J.spatialDim()); // we just multiply the derivative direction component Array<double> invJ; J.getInvJ(c, invJ); for (int q=0; q<nQuad; q++) { double sum = 0.0; for (int deriv = 0 ; deriv < derivNum ; deriv++) { // multiply one row from the J^{-T} matrix with the gradient vector sum = sum + result[nQuad*deriv + q][0] * invJ[derivNum*pDir + deriv]; } // the resulting derivative on the physical cell in the "pDir" direction result[q][0] = sum; } } // --- just copy the result to the "vec" back, the result should be in the "result[q][0]" place---- //SUNDANCE_MSG2(verbo , tab1 << "copy results back "); double* vecPtr = vec[i]->start(); for (int q=0; q<nQuad; q++, k[i]++) { vecPtr[k[i]] = result[q][0]; } SUNDANCE_MSG2(verbo , tab1 << " END copy results back "); } // --- end loop multiindex SUNDANCE_MSG2(verbo , tab1 << " END loop over multiindex "); }// --- end loop over cells SUNDANCE_MSG2(verbo , tab1 << " END loop over cells "); }
void Bernstein::evalOnTriangle(const Point& pt, const MultiIndex& deriv, Array<double>& result) const { ADReal x = ADReal(pt[0], 0, 2); ADReal y = ADReal(pt[1], 1, 2); ADReal one(1.0, 2); Array<ADReal> tmp; SUNDANCE_OUT(this->verb() > 3, "x=" << x.value() << " y=" << y.value()); if(order_==0) { result.resize(1); tmp.resize(1); tmp[0] = one; } else { int N = (order()+1)*(order()+2)/2; result.resize(N); tmp.resize(N); // these are the barycentric coordinates ADReal b1 = 1.0 - x - y; ADReal b2 = x; ADReal b3 = y; // will hold \binom{n}{\alpha_1} int bfcur = 0; for (int alpha1=order();alpha1>=0;alpha1--) { for (int alpha2 = order()-alpha1;alpha2>=0;alpha2--) { int alpha3 = order() - alpha1 - alpha2; tmp[bfcur] = one; for (int i=0;i<alpha1;i++) { tmp[bfcur] *= b1; } for (int i=0;i<alpha2;i++) { tmp[bfcur] *= b2; } for (int i=0;i<alpha3;i++) { tmp[bfcur] *= b3; } for (int i=2;i<=order();i++) { tmp[bfcur] *= (double) i; } for (int i=2;i<=alpha1;i++) { tmp[bfcur] /= (double) i; } for (int i=2;i<=alpha2;i++) { tmp[bfcur] /= (double) i; } for (int i=2;i<=alpha3;i++) { tmp[bfcur] /= (double) i; } bfcur++; } } } for (int i=0; i<tmp.length(); i++) { if (deriv.order()==0) result[i] = tmp[i].value(); else result[i] = tmp[i].gradient()[deriv.firstOrderDirection()]; } }