Set<MultipleDeriv> DiffOpEvaluator ::backedDerivs(const MultipleDeriv& mu, const Set<MultipleDeriv>& W1, int verb) const { Tabs tabs; SUNDANCE_MSG3(verb, tabs << "computing backed-out derivs for mu= " << mu << ", W1=" << W1); Set<MultipleDeriv> rtn; if (mu.order() != 0) { const MultiIndex& alpha = expr()->mi(); for (Set<MultipleDeriv>::const_iterator i=W1.begin(); i!=W1.end(); i++) { const MultipleDeriv& md = *i; TEUCHOS_TEST_FOR_EXCEPT(md.order() != 1); Deriv lambda = *(md.begin()); if (lambda.isCoordDeriv()) continue; TEUCHOS_TEST_FOR_EXCEPT(!lambda.isFunctionalDeriv()); FunctionIdentifier lambda_fid = lambda.fid(); const MultiIndex& lambda_mi = lambda.opOnFunc().mi(); for (MultipleDeriv::const_iterator j=mu.begin(); j!=mu.end(); j++) { const Deriv& d = *j; if (d.isCoordDeriv()) continue; FunctionIdentifier d_fid = d.fid(); const MultiIndex& d_mi = d.opOnFunc().mi(); if (d_fid != lambda_fid) continue; if (!(alpha + lambda_mi == d_mi)) continue; MultipleDeriv z = mu.factorOutDeriv(d); z.put(lambda); rtn.put(z); } } } SUNDANCE_MSG3(verb, tabs << "backed-out derivs = " << rtn); return rtn; }
DiffOpEvaluator ::DiffOpEvaluator(const DiffOp* expr, const EvalContext& context) : UnaryEvaluator<DiffOp>(expr, context), isConstant_(this->sparsity()->numDerivs()), resultIndices_(this->sparsity()->numDerivs()), constantMonomials_(this->sparsity()->numDerivs()), vectorMonomials_(this->sparsity()->numDerivs()), constantFuncCoeffs_(this->sparsity()->numDerivs()), vectorFuncCoeffs_(this->sparsity()->numDerivs()), funcEvaluators_(), constantCoeffFuncIndices_(this->sparsity()->numDerivs()), constantCoeffFuncMi_(this->sparsity()->numDerivs()), vectorCoeffFuncIndices_(this->sparsity()->numDerivs()), vectorCoeffFuncMi_(this->sparsity()->numDerivs()) { int verb = context.setupVerbosity(); Tabs tabs; SUNDANCE_MSG1(verb, tabs << "initializing diff op evaluator for " << expr->toString()); { Tabs tab0; SUNDANCE_MSG2(verb, tab0 << "return sparsity " << std::endl << *(this->sparsity)()); SUNDANCE_MSG2(verb, tab0 << "argument sparsity subset " << std::endl << *(argSparsitySuperset())); Map<const DiscreteFuncElementEvaluator*, int> funcToIndexMap; int vecResultIndex = 0; int constResultIndex = 0; for (int i=0; i<this->sparsity()->numDerivs(); i++) { Tabs tab1; const MultipleDeriv& resultDeriv = this->sparsity()->deriv(i); SUNDANCE_MSG3(verb, tab0 << "working out procedure for computing " << resultDeriv); if (this->sparsity()->state(i)==ConstantDeriv) { Tabs tab2; addConstantIndex(i, constResultIndex); resultIndices_[i] = constResultIndex++; isConstant_[i] = true; SUNDANCE_MSG3(verb, tab2 << "deriv is constant, will be stored at index " << resultIndices_[i] << " in the const result array"); } else { Tabs tab2; addVectorIndex(i, vecResultIndex); resultIndices_[i] = vecResultIndex++; isConstant_[i] = false; SUNDANCE_MSG3(verb, tab2 << "deriv is variable, will be stored at index " << resultIndices_[i] << " in the var result array"); } int order = resultDeriv.order(); const Set<MultipleDeriv>& RArg = argExpr()->findR(order, context); const Set<MultipleDeriv>& RArgPlus = argExpr()->findR(order+1, context); const Set<MultipleDeriv>& W1Arg = argExpr()->findW(1, context); SUNDANCE_MSG3(verb, tab1 << "RArg = " << RArg); SUNDANCE_MSG3(verb, tab1 << "RArgPlus = " << RArgPlus); SUNDANCE_MSG3(verb, tab1 << "W1Arg = " << W1Arg); Set<MultipleDeriv> funcTermCoeffs = RArgPlus.intersection(increasedDerivs(resultDeriv, W1Arg, verb)); SUNDANCE_MSG3(verb, tab1 << "function term coeffs = " << funcTermCoeffs); if (funcTermCoeffs.size()==0) { SUNDANCE_MSG3(verb, tab1 << "no direct chain rule terms"); } else { SUNDANCE_MSG3(verb, tab1 << "getting direct chain rule terms"); } for (Set<MultipleDeriv>::const_iterator j=funcTermCoeffs.begin(); j != funcTermCoeffs.end(); j++) { Tabs tab2; SUNDANCE_MSG3(verb, tab2 << "getting coefficient of " << *j); int argIndex = argSparsitySuperset()->getIndex(*j); TEUCHOS_TEST_FOR_EXCEPTION(argIndex==-1, std::runtime_error, "Derivative " << *j << " expected in argument " "but not found"); Deriv lambda = remainder(*j, resultDeriv, verb); if (lambda.isCoordDeriv()) { Tabs tab3; SUNDANCE_MSG3(verb, tab2 << "detected coordinate deriv"); if (lambda.coordDerivDir()!=expr->mi().firstOrderDirection()) { SUNDANCE_MSG3(verb, tab2 << "direction mismatch, skipping"); continue; } const DerivState& argState = argSparsitySuperset()->state(argIndex); if (argState==ConstantDeriv) { int constArgIndex = argEval()->constantIndexMap().get(argIndex); constantMonomials_[i].append(constArgIndex); } else { int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex); vectorMonomials_[i].append(vectorArgIndex); } } else if (lambda.opOnFunc().isPartial() || lambda.opOnFunc().isIdentity()) { Tabs tab3; SUNDANCE_MSG3(verb, tab3 << "detected functional deriv " << lambda); const SymbolicFuncElement* f = lambda.symbFuncElem(); const MultiIndex& mi = expr->mi() + lambda.opOnFunc().mi(); SUNDANCE_MSG3(verb, tab3 << "modified multiIndex is " << mi); const TestFuncElement* t = dynamic_cast<const TestFuncElement*>(f); if (t != 0) continue; const UnknownFuncElement* u = dynamic_cast<const UnknownFuncElement*>(f); TEUCHOS_TEST_FOR_EXCEPTION(u==0, std::logic_error, "Non-unknown function detected where an unknown " "function was expected in " "DiffOpEvaluator ctor"); const EvaluatableExpr* evalPt = u->evalPt(); const ZeroExpr* z = dynamic_cast<const ZeroExpr*>(evalPt); if (z != 0) continue; TEUCHOS_TEST_FOR_EXCEPTION(z != 0, std::logic_error, "DiffOpEvaluator detected identically zero " "function"); const DiscreteFuncElement* df = dynamic_cast<const DiscreteFuncElement*>(evalPt); TEUCHOS_TEST_FOR_EXCEPTION(df==0, std::logic_error, "DiffOpEvaluator ctor: evaluation point of " "unknown function " << u->toString() << " is not a discrete function"); const SymbolicFuncElementEvaluator* uEval = dynamic_cast<const SymbolicFuncElementEvaluator*>(u->evaluator(context).get()); const DiscreteFuncElementEvaluator* dfEval = uEval->dfEval(); TEUCHOS_TEST_FOR_EXCEPTION(dfEval==0, std::logic_error, "DiffOpEvaluator ctor: evaluator for " "evaluation point is not a " "DiscreteFuncElementEvaluator"); TEUCHOS_TEST_FOR_EXCEPTION(!dfEval->hasMultiIndex(mi), std::logic_error, "DiffOpEvaluator ctor: evaluator for " "discrete function " << df->toString() << " does not know about multiindex " << mi.toString()); int fIndex; int miIndex = dfEval->miIndex(mi); if (funcToIndexMap.containsKey(dfEval)) { fIndex = funcToIndexMap.get(dfEval); } else { fIndex = funcEvaluators_.size(); funcEvaluators_.append(dfEval); funcToIndexMap.put(dfEval, fIndex); } const DerivState& argState = argSparsitySuperset()->state(argIndex); if (argState==ConstantDeriv) { int constArgIndex = argEval()->constantIndexMap().get(argIndex); constantCoeffFuncIndices_[i].append(fIndex); constantCoeffFuncMi_[i].append(miIndex); constantFuncCoeffs_[i].append(constArgIndex); } else { int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex); vectorCoeffFuncIndices_[i].append(fIndex); vectorCoeffFuncMi_[i].append(miIndex); vectorFuncCoeffs_[i].append(vectorArgIndex); } } else { TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error, "DiffOpEvaluator has been asked to preprocess a Deriv that " "is not a simple partial derivative. The problem child is: " << lambda); } } Set<MultipleDeriv> isolatedTerms = RArg.intersection(backedDerivs(resultDeriv, W1Arg, verb)); if (isolatedTerms.size()==0) { SUNDANCE_MSG3(verb, tab1 << "no indirect chain rule terms"); } else { SUNDANCE_MSG3(verb, tab1 << "getting indirect chain rule terms"); SUNDANCE_MSG3(verb, tab1 << "isolated terms = " << isolatedTerms); } for (Set<MultipleDeriv>::const_iterator j=isolatedTerms.begin(); j != isolatedTerms.end(); j++) { int argIndex = argSparsitySuperset()->getIndex(*j); TEUCHOS_TEST_FOR_EXCEPTION(argIndex==-1, std::runtime_error, "Derivative " << *j << " expected in argument " "but not found"); const DerivState& argState = argSparsitySuperset()->state(argIndex); if (argState==ConstantDeriv) { int constArgIndex = argEval()->constantIndexMap().get(argIndex); constantMonomials_[i].append(constArgIndex); } else { int vectorArgIndex = argEval()->vectorIndexMap().get(argIndex); vectorMonomials_[i].append(vectorArgIndex); } } } } if (verb > 2) { Out::os() << tabs << "instruction tables for summing spatial/functional chain rule" << std::endl; for (int i=0; i<this->sparsity()->numDerivs(); i++) { Tabs tab1; Out::os() << tab1 << "deriv " << sparsity()->deriv(i) << std::endl; { Tabs tab2; Out::os() << tab2 << "constant monomials: " << constantMonomials_[i] << std::endl; Out::os() << tab2 << "vector monomials: " << vectorMonomials_[i] << std::endl; Out::os() << tab2 << "constant coeff functions: " << std::endl; for (int j=0; j<constantFuncCoeffs_[i].size(); j++) { Tabs tab3; Out::os() << tab3 << "func=" << constantCoeffFuncIndices_[i][j] << " mi=" << constantCoeffFuncMi_[i][j] << std::endl; } Out::os() << tab2 << "vector coeff functions: " << std::endl; for (int j=0; j<vectorFuncCoeffs_[i].size(); j++) { Tabs tab3; Out::os() << tab3 << "func=" << vectorCoeffFuncIndices_[i][j] << " mi=" << vectorCoeffFuncMi_[i][j] << std::endl; } } } } }
bool testVecFunction() { bool pass = true; Tabs tab; int verb=1; /* make a vector function */ int dim = 3; Expr u = new UnknownFunctionStub("u", 1, 3); Expr phi = new UnknownFunctionStub("u", 0, 1); Expr v = new TestFunctionStub("v", 1, 3); Expr alpha = new UnknownParameter("alpha"); TEUCHOS_TEST_EQUALITY(u.size(), dim, Out::os(), pass); TEUCHOS_TEST_EQUALITY(v.size(), dim, Out::os(), pass); /* Verify that D_mi u fails for nonzero multiindex. */ // MultiIndex m1(0,1,0); // TEST_THROW( // funcDeriv(u, m1), pass // ); Deriv d_du = funcDeriv(u); Deriv d_dAlpha = funcDeriv(alpha); Deriv d_dphi = funcDeriv(phi); Deriv d_dphi_x = d_dphi.derivWrtMultiIndex(MultiIndex(1,0,0)); Deriv divU = divergenceDeriv(u); Deriv divV = divergenceDeriv(v); TEUCHOS_TEST_EQUALITY(divU.fid(), fid(u), Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.fid(), fid(alpha), Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking algSpec for parameter"); TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isScalar(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isVector(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.algSpec().isCoordinateComponent(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking algSpec for divergence"); TEUCHOS_TEST_EQUALITY(divU.algSpec().isScalar(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.algSpec().isVector(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.algSpec().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.algSpec().isCoordinateComponent(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking algSpec for vector operative func"); TEUCHOS_TEST_EQUALITY(d_du.algSpec().isScalar(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.algSpec().isVector(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.algSpec().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.algSpec().isCoordinateComponent(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking algSpec for scalar operative func"); TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isScalar(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isVector(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.algSpec().isCoordinateComponent(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking algSpec for d/d(Dx(phi))"); TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isScalar(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isVector(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.algSpec().isCoordinateComponent(), true, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking distinction between functional and spatial derivs"); TEUCHOS_TEST_EQUALITY(d_dAlpha.isFunctionalDeriv(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.isCoordDeriv(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.isFunctionalDeriv(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.isCoordDeriv(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.isFunctionalDeriv(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.isCoordDeriv(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isFunctionalDeriv(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isCoordDeriv(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.isFunctionalDeriv(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.isCoordDeriv(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking identification of differentiation order"); TEUCHOS_TEST_EQUALITY(divU.opOnFunc().derivOrder(), 1, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.opOnFunc().derivOrder(), 0, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.opOnFunc().derivOrder(), 0, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.opOnFunc().derivOrder(), 0, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.opOnFunc().derivOrder(), 1, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking identification of test and unk funcs"); TEUCHOS_TEST_EQUALITY(d_du.isTestFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.isUnknownFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_du.isParameter(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isTestFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isUnknownFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isParameter(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.isTestFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi_x.isUnknownFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dphi.isParameter(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.isTestFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.isUnknownFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.isParameter(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divV.isTestFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divV.isUnknownFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divV.isParameter(), false, Out::os(), pass); /* unknown parameters are both unknown and parameters */ TEUCHOS_TEST_EQUALITY(d_dAlpha.isTestFunction(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.isUnknownFunction(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(d_dAlpha.isParameter(), true, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking identification of spatial operators acting on operative functions"); TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isDivergence(), true, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isNormal(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isPartial(), false, Out::os(), pass); TEUCHOS_TEST_EQUALITY(divU.opOnFunc().isIdentity(), false, Out::os(), pass); SUNDANCE_BANNER1(verb, tab, "checking that asking for component information from a divergence throws an exception"); TEST_THROW(divU.opOnFunc().normalDerivOrder(), pass); TEST_THROW(divU.opOnFunc().mi(), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a divergence throws an exception"); TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(1,0,0)), pass); TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,1,0)), pass); TEST_THROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,0,1)), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception"); TEST_NOTHROW(divU.opOnFunc().derivWrtMultiIndex(MultiIndex(0,0,0)), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a divergence throws an exception"); TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(1,0,0)), pass); TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(0,1,0)), pass); TEST_THROW(divU.derivWrtMultiIndex(MultiIndex(0,0,1)), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception"); TEST_NOTHROW(divU.derivWrtMultiIndex(MultiIndex(0,0,0)), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a partial derivative to a parameter throws an exception"); TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(1,0,0)), pass); TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,1,0)), pass); TEST_THROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,0,1)), pass); SUNDANCE_BANNER1(verb, tab, "checking that applying a zero-order partial derivative to a divergence does not throw an exception"); TEST_NOTHROW(d_dAlpha.derivWrtMultiIndex(MultiIndex(0,0,0)), pass); SUNDANCE_BANNER1(verb, tab, "all done!"); return pass; }