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;
        }
            
      }
    }
  }
}
示例#3
0
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;
}