void DefaultTestTrialIntegral<IntegrandFunctor>::evaluate(
        const GeometricalData<CoordinateType>& geomData,
        const CollectionOf3dArrays<BasisFunctionType>& testValues,
        const CollectionOf3dArrays<BasisFunctionType>& trialValues,
        const std::vector<CoordinateType>& weights,
        arma::Mat<ResultType>& result) const
{
    const size_t pointCount = weights.size();
    assert(testValues.size() == 1);
    assert(trialValues.size() == 1);

    // We don't care about the number of rows of testValues[0] and trialValues[0]
    // -- it's up to the integrand functor
    const size_t testDofCount = testValues[0].extent(1);
    const size_t trialDofCount = trialValues[0].extent(1);
    assert(testValues[0].extent(2) == pointCount);
    assert(trialValues[0].extent(2) == pointCount);
    for (size_t trialDof = 0; trialDof < trialDofCount; ++trialDof)
        for (size_t testDof = 0; testDof < testDofCount; ++testDof) {
            ResultType sum = 0.;
            for (size_t point = 0; point < pointCount; ++point)
                sum += m_functor.evaluate(
                            geomData.const_slice(point),
                            testValues.const_slice(testDof, point),
                            trialValues.const_slice(trialDof, point)) *
                        geomData.integrationElements(point) *
                        weights[point];
            result(testDof, trialDof) = sum;
        }
}
void DefaultTestKernelTrialIntegral<IntegrandFunctor>::
    evaluateWithTensorQuadratureRule(
        const GeometricalData<CoordinateType> &testGeomData,
        const GeometricalData<CoordinateType> &trialGeomData,
        const CollectionOf3dArrays<BasisFunctionType> &testValues,
        const CollectionOf3dArrays<BasisFunctionType> &trialValues,
        const CollectionOf4dArrays<KernelType> &kernelValues,
        const std::vector<CoordinateType> &testQuadWeights,
        const std::vector<CoordinateType> &trialQuadWeights,
        Matrix<ResultType> &result) const {
  // Evaluate constants

  const size_t testDofCount = testValues[0].extent(1);
  const size_t trialDofCount = trialValues[0].extent(1);

  const size_t testPointCount = testQuadWeights.size();
  const size_t trialPointCount = trialQuadWeights.size();

  // Assert that array dimensions are correct

  for (size_t i = 0; i < kernelValues.size(); ++i) {
    assert(kernelValues[i].extent(2) == testPointCount);
    assert(kernelValues[i].extent(3) == trialPointCount);
  }
  for (size_t i = 0; i < testValues.size(); ++i)
    assert(testValues[i].extent(2) == testPointCount);
  for (size_t i = 0; i < trialValues.size(); ++i)
    assert(trialValues[i].extent(2) == trialPointCount);

  assert(result.rows() == testDofCount);
  assert(result.cols() == trialDofCount);

  // Integrate

  for (size_t trialDof = 0; trialDof < trialDofCount; ++trialDof)
    for (size_t testDof = 0; testDof < testDofCount; ++testDof) {
      ResultType sum = 0.;
      for (size_t trialPoint = 0; trialPoint < trialPointCount; ++trialPoint) {
        const CoordinateType trialWeight =
            trialGeomData.integrationElements(trialPoint) *
            trialQuadWeights[trialPoint];
        ResultType partialSum = 0.;
        for (size_t testPoint = 0; testPoint < testPointCount; ++testPoint) {
          const CoordinateType testWeight =
              testGeomData.integrationElements(testPoint) *
              testQuadWeights[testPoint];
          partialSum += m_functor.evaluate(
                            testGeomData.const_slice(testPoint),
                            trialGeomData.const_slice(trialPoint),
                            testValues.const_slice(testDof, testPoint),
                            trialValues.const_slice(trialDof, trialPoint),
                            kernelValues.const_slice(testPoint, trialPoint)) *
                        testWeight;
        }
        sum += partialSum * trialWeight;
      }
      result(testDof, trialDof) = sum;
    }
}
void evaluateOnGridPeter(std::string str, const GeometricalData<CoordinateType> &testGeomData, const GeometricalData<CoordinateType> &trialGeomData, CollectionOf4dArrays<ValueType> &result) const {
  const size_t testPointCount = testGeomData.pointCount();
  const size_t trialPointCount = trialGeomData.pointCount();
  const size_t kernelCount = m_functor.kernelCount();
  result.set_size(kernelCount);
  for (size_t k = 0; k < kernelCount; ++k)
    result[k].set_size(m_functor.kernelRowCount(k), m_functor.kernelColCount(k),
                       testPointCount, trialPointCount);

#pragma ivdep
  for (size_t trialIndex = 0; trialIndex < trialPointCount; ++trialIndex)
    for (size_t testIndex = 0; testIndex < testPointCount; ++testIndex)
//      m_functor.evaluate(testGeomData.const_slice(testIndex), trialGeomData.const_slice(trialIndex), result.slice(testIndex, trialIndex).self());
      m_functor.evaluatePeter(str,testGeomData.const_slice(testIndex), trialGeomData.const_slice(trialIndex), result.slice(testIndex, trialIndex).self());
}
void DefaultTestKernelTrialIntegral<IntegrandFunctor>::
    evaluateWithNontensorQuadratureRule(
        const GeometricalData<CoordinateType> &testGeomData,
        const GeometricalData<CoordinateType> &trialGeomData,
        const CollectionOf3dArrays<BasisFunctionType> &testValues,
        const CollectionOf3dArrays<BasisFunctionType> &trialValues,
        const CollectionOf3dArrays<KernelType> &kernelValues,
        const std::vector<CoordinateType> &quadWeights,
        Matrix<ResultType> &result) const {
  // Evaluate constants

  const size_t testDofCount = testValues[0].extent(1);
  const size_t trialDofCount = trialValues[0].extent(1);

  const size_t pointCount = quadWeights.size();

  // Assert that array dimensions are correct

  for (size_t i = 0; i < kernelValues.size(); ++i)
    assert(kernelValues[i].extent(2) == pointCount);
  for (size_t i = 0; i < testValues.size(); ++i)
    assert(testValues[i].extent(2) == pointCount);
  for (size_t i = 0; i < trialValues.size(); ++i)
    assert(trialValues[i].extent(2) == pointCount);

  // Integrate

  for (size_t trialDof = 0; trialDof < trialDofCount; ++trialDof)
    for (size_t testDof = 0; testDof < testDofCount; ++testDof) {
      ResultType sum = 0.;
      for (size_t point = 0; point < pointCount; ++point)
        sum += m_functor.evaluate(testGeomData.const_slice(point),
                                  trialGeomData.const_slice(point),
                                  testValues.const_slice(testDof, point),
                                  trialValues.const_slice(trialDof, point),
                                  kernelValues.const_slice(point)) *
               (testGeomData.integrationElements(point) *
                trialGeomData.integrationElements(point) * quadWeights[point]);
      result(testDof, trialDof) = sum;
    }
}
void DefaultCollectionOfShapesetTransformations<Functor>::evaluateImpl(
    const BasisData<ValueType> &basisData,
    const GeometricalData<CoordinateType> &geomData,
    CollectionOf3dArrays<ValueType> &result) const {
  const int pointCount = basisData.pointCount();
  const int functionCount = basisData.functionCount();
  const int transformationCount = m_functor.transformationCount();
  result.set_size(transformationCount);
  for (int t = 0; t < transformationCount; ++t)
    result[t].set_size(m_functor.resultDimension(t), functionCount, pointCount);

  for (int p = 0; p < pointCount; ++p)
    for (int f = 0; f < functionCount; ++f)
      m_functor.evaluate(basisData.const_slice(f, p), geomData.const_slice(p),
                         result.slice(f, p).self());
}
void NumericalTestTrialIntegrator<BasisFunctionType, ResultType, GeometryFactory>::integrate(
        const std::vector<int>& elementIndices,
        const Basis<BasisFunctionType>& testBasis,
        const Basis<BasisFunctionType>& trialBasis,
        arma::Cube<ResultType>& result) const
{
    const size_t pointCount = m_localQuadPoints.n_cols;
    const size_t elementCount = elementIndices.size();

    if (pointCount == 0 || elementCount == 0)
        return;
    // TODO: in the (pathological) case that pointCount == 0 but
    // elementCount != 0, set elements of result to 0.

    // Evaluate constants
    const int componentCount = m_testTransformations.resultDimension(0);
    const int testDofCount = testBasis.size();
    const int trialDofCount = trialBasis.size();

//    if (m_trialTransformations.codomainDimension() != componentCount)
//        throw std::runtime_error("NumericalTestTrialIntegrator::integrate(): "
//                                 "test and trial functions "
//                                 "must have the same number of components");

    BasisData<BasisFunctionType> testBasisData, trialBasisData;
    GeometricalData<CoordinateType> geomData;

    size_t testBasisDeps = 0, trialBasisDeps = 0;
    size_t geomDeps = INTEGRATION_ELEMENTS;

    m_testTransformations.addDependencies(testBasisDeps, geomDeps);
    m_trialTransformations.addDependencies(trialBasisDeps, geomDeps);

    typedef typename GeometryFactory::Geometry Geometry;
    std::auto_ptr<Geometry> geometry(m_geometryFactory.make());

    CollectionOf3dArrays<BasisFunctionType> testValues, trialValues;

    result.set_size(testDofCount, trialDofCount, elementCount);

    testBasis.evaluate(testBasisDeps, m_localQuadPoints, ALL_DOFS, testBasisData);
    trialBasis.evaluate(trialBasisDeps, m_localQuadPoints, ALL_DOFS, trialBasisData);

    // Iterate over the elements
    for (size_t e = 0; e < elementCount; ++e)
    {
        m_rawGeometry.setupGeometry(elementIndices[e], *geometry);
        geometry->getData(geomDeps, m_localQuadPoints, geomData);
        m_testTransformations.evaluate(testBasisData, geomData, testValues);
        m_trialTransformations.evaluate(trialBasisData, geomData, trialValues);

        for (int trialDof = 0; trialDof < trialDofCount; ++trialDof)
            for (int testDof = 0; testDof < testDofCount; ++testDof)
            {
                ResultType sum = 0.;
                for (size_t point = 0; point < pointCount; ++point)
                    for (int dim = 0; dim < componentCount; ++dim)
                        sum +=  m_quadWeights[point] *
                                geomData.integrationElements(point) *
                                conjugate(testValues[0](dim, testDof, point)) *
                                trialValues[0](dim, trialDof, point);
                result(testDof, trialDof, e) = sum;
            }
    }
}
//Peter:
//template <typename Functor>
//template <template <typename T> class CollectionOf2dSlicesOfNdArrays>
void evaluateAtPointPairsPeter(std::string str, const GeometricalData<CoordinateType> &testGeomData, const GeometricalData<CoordinateType> &trialGeomData, CollectionOf3dArrays<ValueType> &result) const {
  assert(testGeomData.pointCount() == trialGeomData.pointCount());
  const size_t pointCount = testGeomData.pointCount();
  const size_t kernelCount = m_functor.kernelCount();
  result.set_size(kernelCount);
//std::cout << "evalAtPointPairsPeter\n";
//  CoordinateType m_waveNumber = m_functor.waveNumber();
//  ValueType m_waveNumber = m_functor.waveNumber();
//	std::string::size_type sz;     // alias of size_t
//  double earth = std::stod (orbits,&sz);
//  double moon = std::stod (orbits.substr(sz));
//	ValueType waveK = static_cast<CoordinateType>(std::stod(str,&sz) );
//	std::cerr << "In defColKern, str = " << str << std::endl;
//	ValueType waveK = static_cast<CoordinateType>(str);

  for (size_t k = 0; k < kernelCount; ++k)
    result[k].set_size(m_functor.kernelRowCount(k), m_functor.kernelColCount(k),
                       pointCount);

  for (size_t p = 0; p < pointCount; ++p) {
/*	if(std::is_same<Functor,ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType>>::value) {
		std::cout << "Right kernel" << std::endl;
		m_functor.evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());		
	}
	else {
		std::cerr << "Wrong kernel" << std::endl;
		std::terminate();
	}*/
//		(m_functor*)->evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());		
//std::unique_ptr<ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType> >(m_functor)->evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());
//	const ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType>& tmp = dynamic_cast<const ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType>& >(m_functor);
//	ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType> tmp = static_cast<ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType> >(m_functor);
//		static_cast<ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType> >(m_functor).evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());
		m_functor.evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());

//	const ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType> bla = dynamic_cast<const ModifiedHelmholtz3dSingleLayerPotentialKernelFunctor<ValueType>& > (m_functor);
//	bla.evaluatePeter(str, testGeomData.const_slice(p), trialGeomData.const_slice(p), result.slice(p).self());

////    m_functor.evaluate(testGeomData.const_slice(p),
////                      trialGeomData.const_slice(p), result.slice(p).self());
/*
	const ConstGeometricalDataSlice<CoordinateType> &testGeomDataSl = testGeomData.const_slice(p);
	const ConstGeometricalDataSlice<CoordinateType> &trialGeomDataSl = trialGeomData.const_slice(p);
//	CollectionOf2dSlicesOfNdArrays<ValueType> &resultSl = result.slice(p).self();
	CollectionOf2dSlicesOf3dArrays<ValueType> &resultSl = result.slice(p).self();
	const int coordCount = 3;
	CoordinateType sum = 0;
	for (int coordIndex = 0; coordIndex < coordCount; ++coordIndex) {
		CoordinateType diff = testGeomDataSl.global(coordIndex) - trialGeomDataSl.global(coordIndex);
		sum += diff * diff;
	}
	CoordinateType distance = sqrt(sum);
	if (distance >= 2) {
		std::cerr << "Error, 2 <= distance =" << distance <<  std::endl;
	}
	CoordinateType wind = static_cast<CoordinateType>(1.0);
	CoordinateType cuto = static_cast<CoordinateType>(0.1);
	CoordinateType cutoSP = static_cast<CoordinateType>(0.3);
	if (false) {
		if (distance >= cuto*2) {
			wind = static_cast<CoordinateType>(0.0);
		}
		else if (distance >= cuto) {
			wind = exp(2*exp(-cuto/(distance-2*cuto) )/( (distance-2*cuto)/cuto-1) );
		} 
	}
//	result[0](0, 0) = static_cast<CoordinateType>(1.0 / (4.0 * M_PI)) / distance * exp(-m_waveNumber * distance)*wind;
//    result(0, 0) = static_cast<CoordinateType>(1.0 / (4.0 * M_PI)) / distance * exp(-m_waveNumber * distance)*wind;
	resultSl[0](0, 0) = static_cast<CoordinateType>(1.0 / (4.0 * M_PI)) / distance * exp(-waveK * distance)*wind;
*/
	}
}