void BlockedOperatorStructure<BasisFunctionType, ResultType>::setBlock(
    size_t row, size_t column,
    const BoundaryOperator<BasisFunctionType, ResultType> &op) {
  if (!op.isInitialized())
    resetBlock(row, column);
  else
    m_blocks[Key(row, column)] = op;
}
BoundaryOperator<BasisFunctionType, ResultType>
modifiedHelmholtz3dSyntheticHypersingularBoundaryOperator(
    const shared_ptr<const Context<BasisFunctionType, ResultType>> &context,
    const shared_ptr<const Space<BasisFunctionType>> &domain,
    const shared_ptr<const Space<BasisFunctionType>> &range,
    const shared_ptr<const Space<BasisFunctionType>> &dualToRange,
    KernelType waveNumber, std::string label, int internalSymmetry,
    bool useInterpolation, int interpPtsPerWavelength,
    const BoundaryOperator<BasisFunctionType, ResultType> &externalSlp) {
  typedef typename ScalarTraits<BasisFunctionType>::RealType CoordinateType;

  typedef Fiber::ScalarFunctionValueFunctor<CoordinateType> ValueFunctor;
  typedef Fiber::ScalarFunctionValueTimesNormalFunctor<CoordinateType>
      ValueTimesNormalFunctor;
  typedef Fiber::SurfaceCurl3dFunctor<CoordinateType> CurlFunctor;
  typedef Fiber::SingleComponentTestTrialIntegrandFunctor<
      BasisFunctionType, ResultType> IntegrandFunctor;

  typedef GeneralElementaryLocalOperator<BasisFunctionType, ResultType> LocalOp;
  typedef SyntheticIntegralOperator<BasisFunctionType, ResultType> SyntheticOp;

  if (!domain || !range || !dualToRange)
    throw std::invalid_argument(
        "modifiedHelmholtz3dSyntheticHypersingularBoundaryOperator(): "
        "domain, range and dualToRange must not be null");

  shared_ptr<const Space<BasisFunctionType>> newDomain = domain;
  shared_ptr<const Space<BasisFunctionType>> newDualToRange = dualToRange;

  bool isBarycentric =
      (domain->isBarycentric() || dualToRange->isBarycentric());

  if (isBarycentric) {
    newDomain = domain->barycentricSpace(domain);
    newDualToRange = dualToRange->barycentricSpace(dualToRange);
  }

  shared_ptr<const Context<BasisFunctionType, ResultType>> internalContext,
      auxContext;
  SyntheticOp::getContextsForInternalAndAuxiliaryOperators(
      context, internalContext, auxContext);
  shared_ptr<const Space<BasisFunctionType>> internalTrialSpace =
      newDomain->discontinuousSpace(newDomain);
  shared_ptr<const Space<BasisFunctionType>> internalTestSpace =
      newDualToRange->discontinuousSpace(newDualToRange);

  // Note: we don't really need to care about ranges and duals to domains of
  // the internal operator. The only range space that matters is that of the
  // leftmost operator in the product.

  const char xyz[] = "xyz";
  const size_t dimWorld = 3;

  if (label.empty())
    label =
        AbstractBoundaryOperator<BasisFunctionType, ResultType>::uniqueLabel();

  BoundaryOperator<BasisFunctionType, ResultType> slp;
  if (!externalSlp.isInitialized()) {

    slp = modifiedHelmholtz3dSingleLayerBoundaryOperator<
        BasisFunctionType, KernelType, ResultType>(
        internalContext, internalTrialSpace,
        internalTestSpace /* or whatever */, internalTestSpace, waveNumber,
        "(" + label + ")_internal_SLP", internalSymmetry, useInterpolation,
        interpPtsPerWavelength);
  } else {

    slp = externalSlp;
  }

  // symmetry of the decomposition
  int syntheseSymmetry = 0; // symmetry of the decomposition
  if (newDomain == newDualToRange && internalTrialSpace == internalTestSpace)
    syntheseSymmetry =
        HERMITIAN | (boost::is_complex<BasisFunctionType>() ? 0 : SYMMETRIC);

  std::vector<BoundaryOperator<BasisFunctionType, ResultType>> testLocalOps;
  std::vector<BoundaryOperator<BasisFunctionType, ResultType>> trialLocalOps;
  testLocalOps.resize(dimWorld);
  for (size_t i = 0; i < dimWorld; ++i)
    testLocalOps[i] = BoundaryOperator<BasisFunctionType, ResultType>(
        auxContext, boost::make_shared<LocalOp>(
                        internalTestSpace, range, newDualToRange,
                        ("(" + label + ")_test_curl_") + xyz[i], NO_SYMMETRY,
                        CurlFunctor(), ValueFunctor(), IntegrandFunctor(i, 0)));

  if (!syntheseSymmetry) {
    trialLocalOps.resize(dimWorld);
    for (size_t i = 0; i < dimWorld; ++i)
      trialLocalOps[i] = BoundaryOperator<BasisFunctionType, ResultType>(
          auxContext,
          boost::make_shared<LocalOp>(
              newDomain, internalTrialSpace /* or whatever */,
              internalTrialSpace, ("(" + label + ")_trial_curl_") + xyz[i],
              NO_SYMMETRY, ValueFunctor(), CurlFunctor(),
              IntegrandFunctor(0, i)));
  }
  // It might be more prudent to distinguish between the symmetry of the total
  // operator and the symmetry of the decomposition
  BoundaryOperator<BasisFunctionType, ResultType> term0(
      context, boost::make_shared<SyntheticOp>(testLocalOps, slp, trialLocalOps,
                                               label, syntheseSymmetry));

  for (size_t i = 0; i < dimWorld; ++i)
    testLocalOps[i] = BoundaryOperator<BasisFunctionType, ResultType>(
        auxContext,
        boost::make_shared<LocalOp>(
            internalTestSpace, range, newDualToRange,
            ("(" + label + ")_test_k_value_n_") + xyz[i], NO_SYMMETRY,
            ValueTimesNormalFunctor(), ValueFunctor(), IntegrandFunctor(i, 0)));
  if (!syntheseSymmetry)
    for (size_t i = 0; i < dimWorld; ++i)
      trialLocalOps[i] = BoundaryOperator<BasisFunctionType, ResultType>(
          auxContext,
          boost::make_shared<LocalOp>(
              newDomain, internalTrialSpace /* or whatever */,
              internalTrialSpace, ("(" + label + ")_trial_k_value_n_") + xyz[i],
              NO_SYMMETRY, ValueFunctor(), ValueTimesNormalFunctor(),
              IntegrandFunctor(0, i)));
  BoundaryOperator<BasisFunctionType, ResultType> slp_waveNumberSq =
      (waveNumber * waveNumber) * slp;
  BoundaryOperator<BasisFunctionType, ResultType> term1(
      context,
      boost::make_shared<SyntheticOp>(testLocalOps, slp_waveNumberSq,
                                      trialLocalOps, label, syntheseSymmetry));

  return term0 + term1;
}
BoundaryOperator<BasisFunctionType, ResultType>
modifiedHelmholtz3dHypersingularBoundaryOperator(
    const shared_ptr<const Context<BasisFunctionType, ResultType>> &context,
    const shared_ptr<const Space<BasisFunctionType>> &domain,
    const shared_ptr<const Space<BasisFunctionType>> &range,
    const shared_ptr<const Space<BasisFunctionType>> &dualToRange,
    KernelType waveNumber, const std::string &label, int symmetry,
    bool useInterpolation, int interpPtsPerWavelength,
    const BoundaryOperator<BasisFunctionType, ResultType> &externalSlp) {
  const AssemblyOptions &assemblyOptions = context->assemblyOptions();
  if ((assemblyOptions.assemblyMode() == AssemblyOptions::ACA &&
       assemblyOptions.acaOptions().mode == AcaOptions::LOCAL_ASSEMBLY) ||
      externalSlp.isInitialized())
    return modifiedHelmholtz3dSyntheticHypersingularBoundaryOperator(
        context, domain, range, dualToRange, waveNumber, label, symmetry,
        useInterpolation, interpPtsPerWavelength, externalSlp);

  typedef typename ScalarTraits<BasisFunctionType>::RealType CoordinateType;

  typedef Fiber::ModifiedHelmholtz3dHypersingularKernelFunctor<KernelType>
      NoninterpolatedKernelFunctor;
  typedef Fiber::ModifiedHelmholtz3dHypersingularKernelInterpolatedFunctor<
      KernelType> InterpolatedKernelFunctor;
  typedef Fiber::ModifiedHelmholtz3dHypersingularTransformationFunctor<
      CoordinateType> TransformationFunctor;
  typedef Fiber::ModifiedHelmholtz3dHypersingularIntegrandFunctor2<
      BasisFunctionType, KernelType, ResultType> IntegrandFunctor;

  typedef Fiber::ModifiedHelmholtz3dHypersingularTransformationFunctor2<
      CoordinateType> TransformationFunctorWithBlas;

  typedef Fiber::
      ModifiedHelmholtz3dHypersingularOffDiagonalInterpolatedKernelFunctor<
          KernelType> OffDiagonalInterpolatedKernelFunctor;
  typedef Fiber::ModifiedHelmholtz3dHypersingularOffDiagonalKernelFunctor<
      KernelType> OffDiagonalNoninterpolatedKernelFunctor;
  typedef Fiber::ScalarFunctionValueFunctor<CoordinateType>
      OffDiagonalTransformationFunctor;
  typedef Fiber::SimpleTestScalarKernelTrialIntegrandFunctorExt<
      BasisFunctionType, KernelType, ResultType, 1> OffDiagonalIntegrandFunctor;

  CoordinateType maxDistance_ =
      static_cast<CoordinateType>(1.1) *
      maxDistance(*domain->grid(), *dualToRange->grid());

  shared_ptr<Fiber::TestKernelTrialIntegral<BasisFunctionType, KernelType,
                                            ResultType>> integral,
      offDiagonalIntegral;
  if (shouldUseBlasInQuadrature(assemblyOptions, *domain, *dualToRange)) {
    integral.reset(new Fiber::TypicalTestScalarKernelTrialIntegral<
        BasisFunctionType, KernelType, ResultType>());
    offDiagonalIntegral = integral;
  } else {
    integral.reset(new Fiber::DefaultTestKernelTrialIntegral<IntegrandFunctor>(
        IntegrandFunctor()));
    offDiagonalIntegral.reset(
        new Fiber::DefaultTestKernelTrialIntegral<OffDiagonalIntegrandFunctor>(
            OffDiagonalIntegrandFunctor()));
  }

  typedef GeneralHypersingularIntegralOperator<BasisFunctionType, KernelType,
                                               ResultType> Op;
  shared_ptr<Op> newOp;
  if (shouldUseBlasInQuadrature(assemblyOptions, *domain, *dualToRange)) {
    shared_ptr<Fiber::TestKernelTrialIntegral<BasisFunctionType, KernelType,
                                              ResultType>> integral,
        offDiagonalIntegral;
    integral.reset(new Fiber::TypicalTestScalarKernelTrialIntegral<
        BasisFunctionType, KernelType, ResultType>());
    offDiagonalIntegral = integral;
    if (useInterpolation)
      newOp.reset(new Op(
          domain, range, dualToRange, label, symmetry,
          InterpolatedKernelFunctor(waveNumber, maxDistance_,
                                    interpPtsPerWavelength),
          TransformationFunctorWithBlas(), TransformationFunctorWithBlas(),
          integral, OffDiagonalInterpolatedKernelFunctor(
                        waveNumber, maxDistance_, interpPtsPerWavelength),
          OffDiagonalTransformationFunctor(),
          OffDiagonalTransformationFunctor(), offDiagonalIntegral));
    else
      newOp.reset(new Op(
          domain, range, dualToRange, label, symmetry,
          NoninterpolatedKernelFunctor(waveNumber),
          TransformationFunctorWithBlas(), TransformationFunctorWithBlas(),
          integral, OffDiagonalNoninterpolatedKernelFunctor(waveNumber),
          OffDiagonalTransformationFunctor(),
          OffDiagonalTransformationFunctor(), offDiagonalIntegral));
  } else { // no blas
    if (useInterpolation)
      newOp.reset(new Op(
          domain, range, dualToRange, label, symmetry,
          InterpolatedKernelFunctor(waveNumber, maxDistance_,
                                    interpPtsPerWavelength),
          TransformationFunctor(), TransformationFunctor(), IntegrandFunctor(),
          OffDiagonalInterpolatedKernelFunctor(waveNumber, maxDistance_,
                                               interpPtsPerWavelength),
          OffDiagonalTransformationFunctor(),
          OffDiagonalTransformationFunctor(), OffDiagonalIntegrandFunctor()));
    else
      newOp.reset(new Op(
          domain, range, dualToRange, label, symmetry,
          NoninterpolatedKernelFunctor(waveNumber), TransformationFunctor(),
          TransformationFunctor(), IntegrandFunctor(),
          OffDiagonalNoninterpolatedKernelFunctor(waveNumber),
          OffDiagonalTransformationFunctor(),
          OffDiagonalTransformationFunctor(), OffDiagonalIntegrandFunctor()));
  }
  return BoundaryOperator<BasisFunctionType, ResultType>(context, newOp);
}