arma::Mat<ResultType>
ElementaryPotentialOperator<BasisFunctionType, KernelType, ResultType>::
    evaluateAtPoints(
        const GridFunction<BasisFunctionType, ResultType> &argument,
        const arma::Mat<CoordinateType> &evaluationPoints,
        const QuadratureStrategy &quadStrategy,
        const EvaluationOptions &options) const {
  if (evaluationPoints.n_rows != argument.grid()->dimWorld())
    throw std::invalid_argument(
        "ElementaryPotentialOperator::evaluateAtPoints(): "
        "the number of coordinates of each evaluation point must be "
        "equal to the dimension of the space containing the surface "
        "on which the grid function 'argument' is defined");

  if (options.evaluationMode() == EvaluationOptions::DENSE) {
    std::unique_ptr<Evaluator> evaluator =
        makeEvaluator(argument, quadStrategy, options);

    // right now we don't bother about far and near field
    // (this might depend on evaluation options)
    arma::Mat<ResultType> result;
    evaluator->evaluate(Evaluator::FAR_FIELD, evaluationPoints, result);
    return result;
  } else if (options.evaluationMode() == EvaluationOptions::ACA) {
    AssembledPotentialOperator<BasisFunctionType, ResultType> assembledOp =
        assemble(argument.space(), make_shared_from_ref(evaluationPoints),
                 quadStrategy, options);
    return assembledOp.apply(argument);
  } else
    throw std::invalid_argument(
        "ElementaryPotentialOperator::evaluateAtPoints(): "
        "Invalid evaluation mode");
}
std::auto_ptr<InterpolatedFunction<ResultType> >
ElementaryPotentialOperator<BasisFunctionType, KernelType, ResultType>::
evaluateOnGrid(
        const GridFunction<BasisFunctionType, ResultType>& argument,
        const Grid& evaluationGrid,
        const QuadratureStrategy& quadStrategy,
        const EvaluationOptions& options) const
{
    if (evaluationGrid.dimWorld() != argument.grid()->dimWorld())
        throw std::invalid_argument(
                "ElementaryPotentialOperator::evaluateOnGrid(): "
                "the evaluation grid and the surface on which the grid "
                "function 'argument' is defined must be embedded in a space "
                "of the same dimension");

    // Get coordinates of interpolation points, i.e. the evaluationGrid's vertices

    std::auto_ptr<GridView> evalView = evaluationGrid.leafView();
    const int evalGridDim = evaluationGrid.dim();
    const int evalPointCount = evalView->entityCount(evalGridDim);
    arma::Mat<CoordinateType> evalPoints(evalGridDim, evalPointCount);

    const IndexSet& evalIndexSet = evalView->indexSet();
    // TODO: extract into template function, perhaps add case evalGridDim == 1
    if (evalGridDim == 2) {
        const int vertexCodim = 2;
        std::auto_ptr<EntityIterator<vertexCodim> > it =
                evalView->entityIterator<vertexCodim>();
        while (!it->finished()) {
            const Entity<vertexCodim>& vertex = it->entity();
            const Geometry& geo = vertex.geometry();
            const int vertexIndex = evalIndexSet.entityIndex(vertex);
            arma::Col<CoordinateType> activeCol(evalPoints.unsafe_col(vertexIndex));
            geo.getCenter(activeCol);
            it->next();
        }
    } else if (evalGridDim == 3) {
        const int vertexCodim = 3;
        std::auto_ptr<EntityIterator<vertexCodim> > it =
                evalView->entityIterator<vertexCodim>();
        while (!it->finished()) {
            const Entity<vertexCodim>& vertex = it->entity();
            const Geometry& geo = vertex.geometry();
            const int vertexIndex = evalIndexSet.entityIndex(vertex);
            arma::Col<CoordinateType> activeCol(evalPoints.unsafe_col(vertexIndex));
            geo.getCenter(activeCol);
            it->next();
        }
    }

    arma::Mat<ResultType> result;
    result = evaluateAtPoints(argument, evalPoints, quadStrategy, options);

    return std::auto_ptr<InterpolatedFunction<ResultType> >(
                new InterpolatedFunction<ResultType>(evaluationGrid, result));
}