double get_terminal_current(DeviceT const & device,
                              CurrentAccessorT const & current_accessor,
                              SegmentT const & semiconductor,
                              SegmentT const & terminal)
  {
    typedef typename DeviceT::mesh_type     MeshType;

    typedef typename viennagrid::result_of::point<MeshType> ::type      PointType;
    typedef typename viennagrid::result_of::facet<MeshType> ::type      FacetType;
    typedef typename viennagrid::result_of::cell<MeshType> ::type       CellType;

    typedef typename viennagrid::result_of::const_cell_range<SegmentT>::type      CellContainer;
    typedef typename viennagrid::result_of::iterator<CellContainer>::type         CellIterator;

    typedef typename viennagrid::result_of::const_facet_range<CellType>::type     FacetOnCellContainer;
    typedef typename viennagrid::result_of::iterator<FacetOnCellContainer>::type  FacetOnCellIterator;

    typedef typename viennagrid::result_of::const_coboundary_range<SegmentT, FacetType, CellType>::type     CellOnFacetContainer;

    double current = 0;

    CellContainer cells(terminal);
    for (CellIterator cit = cells.begin(); cit != cells.end(); ++cit)
    {
      PointType centroid_cell = viennagrid::centroid(*cit);

      FacetOnCellContainer facets_on_cell(*cit);
      for (FacetOnCellIterator focit = facets_on_cell.begin();
          focit != facets_on_cell.end();
          ++focit)
      {
        if ( viennagrid::is_interface(terminal, semiconductor, *focit) )
        {
          CellOnFacetContainer cells_on_facet(device.mesh(), focit.handle());

          CellType const *other_cell_ptr = util::get_other_cell_of_facet(device.mesh(), *focit, *cit);

          if (!other_cell_ptr) continue;  //Facet is on the boundary of the simulation domain -> homogeneous Neumann conditions

          PointType centroid_other_cell = viennagrid::centroid(*other_cell_ptr);
          PointType cell_connection = centroid_other_cell - centroid_cell;
          PointType cell_connection_normalized = cell_connection / viennagrid::norm(cell_connection);
          PointType facet_unit_normal = viennashe::util::outer_cell_normal_at_facet(*cit, *focit);
          const double weighted_interface_area = viennagrid::volume(*focit) * viennagrid::inner_prod(facet_unit_normal, cell_connection_normalized);

          if ( &(*cit) == &(cells_on_facet[0]) )
            current += current_accessor(*focit) * weighted_interface_area;
          else  //reference direction is opposite of what we need
            current -= current_accessor(*focit) * weighted_interface_area;

          //log::info() << *eovit << std::endl;
          //log::info() << current_density_accessor( *eovit ) << " * " << effective_interface << " = " << current << std::endl;
        }// for edges
      }
    } // for vertices

    return current;
  } // get_terminal_current
    value_type operator()(CellType const & cell) const
    {
      typedef typename viennagrid::result_of::const_facet_range<CellType>::type   FacetOnCellContainer;
      typedef detail::electric_field_on_facet<DeviceType, PotentialAccessorType>  FieldOnFacetEvaluator;

      viennashe::materials::checker no_conductor_filter(MATERIAL_NO_CONDUCTOR_ID);

      std::vector<double> E(3);

      if (!no_conductor_filter(device_.get_material(cell))) return E;

      viennashe::util::value_holder_functor<std::vector<double> > result;

      FieldOnFacetEvaluator facet_evaluator(device_, potential_);

      FacetOnCellContainer facets_on_cell(cell);
      viennashe::util::dual_box_flux_to_cell(device_,
                                             cell, facets_on_cell,
                                             result, facet_evaluator);

      return result();
    } // operator()
      void assemble(PDESystemType const & pde_system,
                    std::size_t           pde_index,
                    SegmentT      const & segment,
                    StorageType & storage,
                    MatrixT             & system_matrix,
                    VectorT             & load_vector)
      {
        typedef typename SegmentT::config_type                config_type;
        typedef viennamath::equation                          equ_type;
        typedef viennamath::expr                              expr_type;
        typedef typename expr_type::interface_type            interface_type;
        typedef typename expr_type::numeric_type              numeric_type;

        typedef typename viennagrid::result_of::cell_tag<SegmentT>::type CellTag;
        typedef typename viennagrid::result_of::facet_tag<CellTag>::type FacetTag;

        typedef typename viennagrid::result_of::element<SegmentT, FacetTag>::type                FacetType;
        typedef typename viennagrid::result_of::element<SegmentT, CellTag  >::type                CellType;

        typedef typename viennagrid::result_of::const_element_range<SegmentT, CellTag>::type    CellContainer;
        typedef typename viennagrid::result_of::iterator<CellContainer>::type                      CellIterator;

        typedef typename viennagrid::result_of::const_element_range<CellType, FacetTag>::type  FacetOnCellContainer;
        typedef typename viennagrid::result_of::iterator<FacetOnCellContainer>::type               FacetOnCellIterator;

        viennamath::equation          const & pde         = pde_system.pde(pde_index);
        viennamath::function_symbol   const & u           = pde_system.unknown(pde_index)[0];
        viennafvm::linear_pde_options const & pde_options = pde_system.option(pde_index);

        viennafvm::mapping_key   map_key(u.id());
        viennafvm::boundary_key  bnd_key(u.id());


#ifdef VIENNAFVM_DEBUG
        std::cout << " - Strong form: " << pde << std::endl;
#endif

        equ_type integral_form = viennafvm::make_integral_form( pde );

#ifdef VIENNAFVM_DEBUG
        std::cout << " - Integral form: " << integral_form << std::endl;
#endif

        //
        // Preprocess symbolic representation:
        //

        //Note: Assuming that LHS holds all matrix terms, while RHS holds all load vector terms
        expr_type  partial_omega_integrand = extract_surface_integrand<FacetType>(storage, integral_form.lhs(), u);
        expr_type   matrix_omega_integrand = extract_volume_integrand<CellType>(storage, integral_form.lhs(), u);
        expr_type      rhs_omega_integrand = extract_volume_integrand<CellType>(storage, integral_form.rhs(), u);
        expr_type  stabilization_integrand = prepare_for_evaluation<CellType>(storage, pde_options.damping_term(), u);

#ifdef VIENNAFVM_DEBUG
        std::cout << " - Surface integrand for matrix: " << partial_omega_integrand << std::endl;
        std::cout << " - Volume integrand for matrix:  " <<  matrix_omega_integrand << std::endl;
        std::cout << " - Stabilization for matrix:     " << stabilization_integrand << std::endl;
        std::cout << " - Volume integrand for rhs:     " <<     rhs_omega_integrand << std::endl;
#endif

        viennafvm::flux_handler<StorageType, CellType, FacetType, interface_type>  flux(storage, partial_omega_integrand, u);

        expr_type substituted_matrix_omega_integrand  = viennamath::diff(matrix_omega_integrand, u);

        std::vector<double> p(3); //dummy vector for evaluation

        //
        // Preprocess domain
        //
        setup(segment, storage);


        typename viennadata::result_of::accessor<StorageType, viennafvm::mapping_key, long, CellType>::type cell_mapping_accessor =
            viennadata::make_accessor(storage, map_key);

        typename viennadata::result_of::accessor<StorageType, viennafvm::facet_area_key, double, FacetType>::type facet_area_accessor =
            viennadata::make_accessor(storage, viennafvm::facet_area_key());

        typename viennadata::result_of::accessor<StorageType, viennafvm::boundary_key, double, CellType>::type boundary_accessor =
            viennadata::make_accessor(storage, bnd_key);

        typename viennadata::result_of::accessor<StorageType, viennafvm::current_iterate_key, double, CellType>::type current_iterate_accessor =
            viennadata::make_accessor(storage, viennafvm::current_iterate_key(u.id()));

        //
        // Actual assembly:
        //
        CellContainer cells(segment);
        for (CellIterator cit = cells.begin(); cit != cells.end(); ++cit)
        {
          long row_index = cell_mapping_accessor(*cit);

          if (row_index < 0)
            continue;

          // update ncell quantities in expressions for current cell:
          viennamath::rt_traversal_wrapper<interface_type> cell_updater( new detail::ncell_updater<CellType, interface_type>(*cit) );

          substituted_matrix_omega_integrand.get()->recursive_traversal(cell_updater);
          stabilization_integrand.get()->recursive_traversal(cell_updater);
          rhs_omega_integrand.get()->recursive_traversal(cell_updater);



          typename viennadata::result_of::accessor<StorageType, facet_distance_key, double, FacetType>::type facet_distance_accessor =
              viennadata::make_accessor(storage, facet_distance_key());

          //
          // Boundary integral terms:
          //
          FacetOnCellContainer facets_on_cell(*cit);
          for (FacetOnCellIterator focit  = facets_on_cell.begin();
                                   focit != facets_on_cell.end();
                                 ++focit)
          {
            CellType const * other_cell = util::other_cell_of_facet(*focit, *cit, segment);

            if (other_cell)
            {
              long col_index = cell_mapping_accessor(*other_cell);
              double effective_facet_area = facet_area_accessor(*focit);

              for (std::size_t i=0; i<pde_system.size(); ++i)
                compute_gradients_for_cell(*cit, *focit, *other_cell,
                                           viennadata::make_accessor<current_iterate_key, double, CellType>(storage, current_iterate_key(pde_system.unknown(i)[0].id())),
                                           viennadata::make_accessor<current_iterate_key, double, FacetType>(storage, current_iterate_key(pde_system.unknown(i)[0].id())),
                                           facet_distance_accessor);

              if (col_index == viennafvm::DIRICHLET_BOUNDARY)
              {
                double boundary_value = boundary_accessor(*other_cell);
                double current_value  = current_iterate_accessor(*cit);

                // updates are homogeneous, hence no direct contribution to RHS here. Might change later when boundary values are slowly increased.
                load_vector(row_index)              -= flux.out(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area * (boundary_value - current_value);
                system_matrix(row_index, row_index) -= flux.in(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area;

                load_vector(row_index) -= flux.out(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area * current_value;
                load_vector(row_index) += flux.in(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area * current_iterate_accessor(*cit);
              }
              else if (col_index >= 0)
              {
                system_matrix(row_index, col_index) += flux.out(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area;
                system_matrix(row_index, row_index) -= flux.in(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area;

                load_vector(row_index) -= flux.out(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area * current_iterate_accessor(*other_cell);
                load_vector(row_index) += flux.in(*cit, *focit, *other_cell, facet_distance_accessor) * effective_facet_area * current_iterate_accessor(*cit);
              }
              // else: nothing to do because other cell is not considered for this quantity

            }
          }

          //
          // Volume terms
          //
          double cell_volume      = viennagrid::volume(*cit);

          // Matrix (including residual contributions)
          system_matrix(row_index, row_index) += viennamath::eval(substituted_matrix_omega_integrand, p) * cell_volume;
          load_vector(row_index) -= viennamath::eval(substituted_matrix_omega_integrand, p) * cell_volume * current_iterate_accessor(*cit);

          system_matrix(row_index, row_index) += viennamath::eval(stabilization_integrand, p) * cell_volume;

          // RHS
          load_vector(row_index) += viennamath::eval(rhs_omega_integrand, p) * cell_volume;
          //std::cout << "Writing " << viennamath::eval(omega_integrand, p) << " * " << cell_volume << " to rhs at " << row_index << std::endl;

        } // for cells

      } // assemble
    void assemble( DeviceType & device,
                   TimeStepQuantitiesT & old_quantities,
                   TimeStepQuantitiesT & quantities,
                   viennashe::config const & conf,
                   viennashe::she::unknown_she_quantity<VertexT, EdgeT> const & quan,
                   MatrixType & A,
                   VectorType & b,
                   bool use_timedependence, bool quan_valid)
    {
      typedef typename DeviceType::mesh_type              MeshType;

      typedef typename viennagrid::result_of::facet<MeshType>::type                 FacetType;
      typedef typename viennagrid::result_of::cell<MeshType>::type                  CellType;

      typedef typename viennagrid::result_of::const_facet_range<MeshType>::type     FacetContainer;
      typedef typename viennagrid::result_of::iterator<FacetContainer>::type        FacetIterator;

      typedef typename viennagrid::result_of::const_cell_range<MeshType>::type      CellContainer;
      typedef typename viennagrid::result_of::iterator<CellContainer>::type         CellIterator;

      typedef typename viennagrid::result_of::const_facet_range<CellType>::type     FacetOnCellContainer;
      typedef typename viennagrid::result_of::iterator<FacetOnCellContainer>::type  FacetOnCellIterator;

      typedef typename viennagrid::result_of::const_coboundary_range<MeshType, FacetType, CellType>::type     CellOnFacetContainer;
      typedef typename viennagrid::result_of::iterator<CellOnFacetContainer>::type                            CellOnFacetIterator;

      typedef viennashe::math::sparse_matrix<double>   CouplingMatrixType;

      typedef typename viennashe::she::timestep_quantities<DeviceType>::unknown_quantity_type      SpatialUnknownType;

      std::vector< scattering_base<DeviceType> * > scattering_processes;

      if (conf.with_traps())
      {
        if (! conf.with_electrons() || ! conf.with_holes())
          throw viennashe::unavailable_feature_exception("Trapping without considering electrons or holes is not supported!");
        if ( conf.get_electron_equation() != viennashe::EQUATION_SHE)
          throw viennashe::unavailable_feature_exception("Trapping without SHE for electrons is not supported!");
        if ( conf.get_hole_equation() != viennashe::EQUATION_SHE)
          throw viennashe::unavailable_feature_exception("Trapping without SHE for holes is not supported!");
      }

//      try
//      {
        MeshType const & mesh = device.mesh();

        SpatialUnknownType const &     potential =     quantities.get_unknown_quantity(viennashe::quantity::potential());
        SpatialUnknownType const & old_potential = old_quantities.get_unknown_quantity(viennashe::quantity::potential());  //TODO: Take old timestep

        viennashe::she::unknown_she_quantity<VertexT, EdgeT> const & old_quan = old_quantities.she_quantity(quan.get_name());

        //
        // Set up scatter matrices:
        //
        const std::size_t L_max = static_cast<std::size_t>(conf.max_expansion_order());
        const std::size_t num_harmonics = std::size_t(L_max+1) * std::size_t(L_max+1);
        CouplingMatrixType scatter_op_in(num_harmonics, num_harmonics);
        CouplingMatrixType scatter_op_out(num_harmonics, num_harmonics);

        for (std::size_t i=0; i < std::size_t(L_max+1) * std::size_t(L_max+1); ++i)
          scatter_op_out(i,i) += 1.0;
        scatter_op_in(0,0) += 1.0;

        //// preprocessing: compute coefficients a_{l,m}^{l',m'} and b_{l,m}^{l',m'}
        std::size_t Lmax = static_cast<std::size_t>(conf.max_expansion_order());            //maximum expansion order
        std::size_t coupling_rows = static_cast<std::size_t>((Lmax+1) * (Lmax+1));
        std::size_t coupling_cols = coupling_rows;

        log::debug<log_assemble_all>() << "* assemble_all(): Computing coupling matrices..." << std::endl;
        CouplingMatrixType identity(coupling_rows, coupling_cols);
        for (std::size_t i=0; i<coupling_rows; ++i)
          for (std::size_t j=0; j<coupling_cols; ++j)
            identity(i,j) = (i == j) ? 1.0 : 0.0;

        CouplingMatrixType a_x(coupling_rows, coupling_cols);
        CouplingMatrixType a_y(coupling_rows, coupling_cols);
        CouplingMatrixType a_z(coupling_rows, coupling_cols);


        CouplingMatrixType b_x(coupling_rows, coupling_cols);
        CouplingMatrixType b_y(coupling_rows, coupling_cols);
        CouplingMatrixType b_z(coupling_rows, coupling_cols);

        //note: interchanged coordinates
        fill_coupling_matrices(a_x, a_y, a_z,
                               b_x, b_y, b_z,
                               static_cast<int>(Lmax));

        CouplingMatrixType a_x_transposed = a_x.trans();
        CouplingMatrixType a_y_transposed = a_y.trans();
        CouplingMatrixType a_z_transposed = a_z.trans();

        CouplingMatrixType b_x_transposed = b_x.trans();
        CouplingMatrixType b_y_transposed = b_y.trans();
        CouplingMatrixType b_z_transposed = b_z.trans();

        if (log_assemble_all::enabled && log_assemble_all::debug)
        {
          log::debug<log_assemble_all>() << "a_x: " << a_x << std::endl;
          log::debug<log_assemble_all>() << "a_y: " << a_y << std::endl;
          log::debug<log_assemble_all>() << "a_z: " << a_z << std::endl;
          log::debug<log_assemble_all>() << "b_x: " << b_x << std::endl;
          log::debug<log_assemble_all>() << "b_y: " << b_y << std::endl;
          log::debug<log_assemble_all>() << "b_z: " << b_z << std::endl;

          log::debug<log_assemble_all>() << "identity: " << identity << std::endl;

          log::debug<log_assemble_all>() << "scatter_op_out: " << scatter_op_out << std::endl;
          log::debug<log_assemble_all>() << "scatter_op_in: "  << scatter_op_in << std::endl;
        }

        //
        // Setup vector of scattering processes:
        //


        if (conf.scattering().acoustic_phonon().enabled())
        {
          log::debug<log_assemble_all>() << "assemble(): Acoustic phonon scattering is ENABLED!" << std::endl;
          scattering_processes.push_back(new acoustic_phonon_scattering<DeviceType>(device, conf));
        }

        if (conf.scattering().optical_phonon().enabled())
        {
          log::debug<log_assemble_all>() << "assemble(): Optical phonon scattering is ENABLED!" << std::endl;
          scattering_processes.push_back(new optical_phonon_scattering<DeviceType>(device, conf, conf.energy_spacing()));
        }

        if (conf.scattering().ionized_impurity().enabled())
        {
          log::debug<log_assemble_all>() << "assemble(): Ionized impurity scattering is ENABLED!" << std::endl;
          scattering_processes.push_back(new ionized_impurity_scattering<DeviceType>(device, conf));
        }

        if (conf.scattering().impact_ionization().enabled())
        {
          // Warn the user if we already know that he/she is going to simulate bullshit.
          if ( ! conf.with_holes() || conf.get_hole_equation() != viennashe::EQUATION_SHE )
            log::warn() << std::endl << "WARNING: II scattering enabled, but 'BTE for holes' is disabled! Expect inconsistent results!" << std::endl;
          if ( ! conf.with_electrons() || conf.get_electron_equation() != viennashe::EQUATION_SHE )
            log::warn() << std::endl << "WARNING: II scattering enabled, but 'BTE for electrons' is disabled! Expect inconsistent results!" << std::endl;

          scattering_processes.push_back(new impact_ionization_scattering<DeviceType>(device, conf));
        }

        if (conf.with_traps() && conf.scattering().trapped_charge().enabled())
        {
          log::debug<log_assemble_all>() << "assemble(): Trapped charge scattering is ENABLED!" << std::endl;
          scattering_processes.push_back(new trapped_charge_scattering<DeviceType, TimeStepQuantitiesT>(device, conf, quantities));
        }

        typedef typename viennashe::electric_field_wrapper<DeviceType, SpatialUnknownType> ElectricFieldAccessor;
        ElectricFieldAccessor Efield(device, potential);

        if (conf.scattering().surface().enabled())
        {
          log::debug<log_assemble_all>() << "assemble(): Surface roughness scattering is ENABLED!" << std::endl;
          scattering_processes.push_back(new surface_scattering<DeviceType, ElectricFieldAccessor>(device, conf, Efield));
        }


        //
        // Assemble SHE system:
        //    - scattering operators on vertices
        //    - free streaming operator on vertices
        //    - scattering operators on edges
        //    - free streaming operator on edges
        //    - any other stuff (traps on cells, etc.)
        //

        if (quan_valid && conf.scattering().electron_electron() && conf.with_electrons())
        {
          log::debug<log_assemble_all>() << "assemble(): Electron electron scattering is ENABLED!" << std::endl;
          assemble_ee_scattering(device, conf, quan, old_quan, A, b);
        }

        //
        // Step 1: Assemble on even nodes
        //
        log::debug<log_assemble_all>() << "* assemble_all(): Even unknowns..." << std::endl;

        CellContainer cells(mesh);
        for (CellIterator cit = cells.begin();
            cit != cells.end();
            ++cit)
        {
          log::debug<log_assemble_all>() << "* assemble_all(): Assembling on cell " << *cit << std::endl;

          for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
          {
            if (log_assemble_all::enabled)
              log::debug<log_assemble_all>() << "* assemble_all(): Assembling on energy index " << index_H << std::endl;

            assemble_boundary_on_box(device, conf, quan,
                                     A, b,
                                     *cit, index_H,
                                     identity);

            if (viennashe::materials::is_conductor(device.get_material(*cit)))
              continue;

            //
            // Scattering operator Q{f}
            //
            assemble_scattering_operator_on_box( scattering_processes,
                                                 device, conf, quan,
                                                 A, b,
                                                 *cit, index_H,
                                                 scatter_op_in, scatter_op_out);
          }

          //
          // Free streaming operator L{f}
          //

          // iterate over neighbor cells holding the odd unknowns:
          FacetOnCellContainer facets_on_cell(*cit);
          for (FacetOnCellIterator focit = facets_on_cell.begin();
              focit != facets_on_cell.end();
              ++focit)
          {
            if (log_assemble_all::enabled)
              log::debug<log_assemble_all>() << "* assemble_all(): Assembling coupling with facet " << *focit << std::endl;

            CellType const *other_cell_ptr = util::get_other_cell_of_facet(mesh, *focit, *cit);
            if (!other_cell_ptr) continue;  //Facet is on the boundary of the simulation domain -> homogeneous Neumann conditions

            CouplingMatrixType coupling_matrix_diffusion = coupling_matrix_in_direction(a_x, a_y, a_z,
                                                                                        *cit,
                                                                                        *other_cell_ptr,
                                                                                        quan.get_carrier_type_id());

            // note that the sign change due to MEDS is included in the choice of the normal vector direction (order of vertex vs. other_vertex):
            // - B \cdot n   for even unknowns,
            // + B \cdot n   for odd unknowns
            CouplingMatrixType coupling_matrix_drift = coupling_matrix_in_direction(b_x, b_y, b_z, *other_cell_ptr, *cit, quan.get_carrier_type_id());

            for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
            {
              assemble_free_streaming_operator_on_box( device, conf, quan,
                                                       A, b,
                                                       *cit, *focit, index_H,
                                                       coupling_matrix_diffusion,
                                                       coupling_matrix_drift,
                                                       false);
            }
          } //for edges

          //
          // Time dependence df/dt (and possibly df/dH * dH/dt)
          //
          if (use_timedependence)
          {
            for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
            {
              viennashe::she::assemble_timederivative(device, conf, quan, old_quan,
                                                      A, b,
                                                      *cit, index_H,
                                                      identity,
                                                      potential,
                                                      old_potential);
            }
          }
        } //for cells


        //
        // Step 2: Assemble on odd 'nodes' (i.e. facets). TODO: Resolve code duplication w.r.t. above
        //
        log::info<log_assemble_all>() << "* assemble_all(): Odd unknowns..." << std::endl;

        FacetContainer facets(mesh);
        for (FacetIterator fit = facets.begin();
             fit != facets.end();
             ++fit)
        {
          if (log_assemble_all::enabled)
            log::debug<log_assemble_all>() << "* assemble_all(): Assembling on facet " << *fit << std::endl;

          for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
          {
            if (log_assemble_all::enabled)
              log::debug<log_assemble_all>() << "* assemble_all(): Assembling on energy index " << index_H << std::endl;

            //
            // Scattering operator Q{f}
            //
            assemble_scattering_operator_on_box(scattering_processes,
                                                device, conf, quan,
                                                A, b,
                                                *fit, index_H,
                                                scatter_op_in, scatter_op_out);
          }

          //
          // Free streaming operator L{f}
          //

          // iterate over cells of facet
          CellOnFacetContainer cells_on_facet(mesh, fit.handle());
          for (CellOnFacetIterator cofit  = cells_on_facet.begin();
                                   cofit != cells_on_facet.end();
                                 ++cofit)
          {
            if (log_assemble_all::enabled)
              log::debug<log_assemble_all>() << "* assemble_all(): Assembling coupling with cell " << *cofit << std::endl;

            CellType const *other_cell_ptr = util::get_other_cell_of_facet(mesh, *fit, *cofit);
            if (!other_cell_ptr) continue;  //Facet is on the boundary of the simulation domain -> homogeneous Neumann conditions

            CouplingMatrixType coupling_matrix_diffusion = coupling_matrix_in_direction(a_x_transposed, a_y_transposed, a_z_transposed,
                                                                                        *other_cell_ptr,
                                                                                        *cofit,
                                                                                        quan.get_carrier_type_id());

            // note that the sign change due to MEDS is included in the choice of the normal vector direction (order of vertex vs. other_vertex):
            // - B \cdot n   for even unknowns,
            // + B \cdot n   for odd unknowns
            CouplingMatrixType coupling_matrix_drift = coupling_matrix_in_direction(b_x_transposed, b_y_transposed, b_z_transposed, *other_cell_ptr, *cofit, quan.get_carrier_type_id());

            for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
            {
              assemble_free_streaming_operator_on_box( device, conf, quan,
                                                       A, b,
                                                       *cofit, *fit, index_H,
                                                       coupling_matrix_diffusion,
                                                       coupling_matrix_drift,
                                                       true);
            }
          } //for vertices

          //
          // Time dependence df/dt (and possibly df/dH * dH/dt)
          //
          if (use_timedependence)
          {
            for (std::size_t index_H = 0; index_H < quan.get_value_H_size(); ++index_H)
            {
              viennashe::she::assemble_timederivative(device, conf, quan, old_quan,
                                                      A, b,
                                                      *fit, index_H,
                                                      identity,
                                                      potential,
                                                      old_potential);
            }
          }

        } //for facets


        // Assemble traps on cells (to be integrated into the assembly above):
        if (conf.with_traps())
        {
          log::debug<log_assemble_all>() << "assemble(): Assembly for traps ..." << std::endl;
          viennashe::she::assemble_traps(device, quantities, conf, quan, A, b);
        }

        //
        // Cleanup:
        //
        for (std::size_t i=0; i<scattering_processes.size(); ++i)
        {
          if ( scattering_processes[i] ) delete scattering_processes[i];
          scattering_processes[i] = 0;
        }
/*      }
      catch (...)
      {
        //
        // Cleanup:
        //
        for (std::size_t i=0; i<scattering_processes.size(); ++i)
          if ( scattering_processes[i] ) delete scattering_processes[i];
        // Rethrow
        throw;
      }
*/

    }