示例#1
0
文件: ReadSTP3.cpp 项目: nixz/covise
int read_ct_tran(struct patient_struct *ppatient, QString *Result)
{
    FILE *f_tran = NULL;
    uint32_t file_typ, ser_head_length, block_length, ser_number, numb_of_slices;
    char pat_name[80], comm[80], date[80];
    uint32_t trafo_type;
    uint32_t calculated;
    uint32_t is_axial;
    double marker[12][2];
    double plate[16][2];
    uint32_t missing;
    uint32_t all_slices;
    uint32_t elements_v_rev_mat;
    uint32_t i, j, n;
    double fov_by_2;
    double global_inv_mat[4][4];

    mat44_t mat;
    mat44_t rev_mat;
    vector<mat44_t> v_mat, v_rev_mat;

    xyze Stereo_point_0;
    xyze Stereo_point_1;
    xyze Stereo_point_2;
    xyze Stereo_point_3;

    const int imax = 4;

    double Edge_point_a[imax] = { 0.0, 0.0, 1.0, 1.0 };
    double Edge_point_b[imax] = { 0.0, 1023.0, 1.0, 1.0 };
    double Edge_point_c[imax] = { 1023.0, 1023.0, 1.0, 1.0 };
    double Edge_point_d[imax] = { 1023.0, 0.0, 1.0, 1.0 };
    double last_col_glo_matrix[imax] = { 0.0, 0.0, 0.0, 1.0 };

    QTextStream ts(Result, IO_WriteOnly);

    ts << "<B>Loading " << ppatient->Tra_File;

    if ((f_tran = fopen(ppatient->Tra_File, "rb")) == NULL)
    {
        ts << ": failed!</B><br><br>";
        return 1;
    }

    // read transformation header
    if (fread(&file_typ, 4, 1, f_tran) != 4)
    {
        fprintf(stderr, "fread_52 failed in ReadSTP3.cpp");
    }
    if (fread(&ser_head_length, 4, 1, f_tran) != 4)
    {
        fprintf(stderr, "fread_53 failed in ReadSTP3.cpp");
    }
    if (fread(&block_length, 4, 1, f_tran) != 4)
    {
        fprintf(stderr, "fread_54 failed in ReadSTP3.cpp");
    }
    if (fread(pat_name, 1, 80, f_tran) != 1)
    {
        fprintf(stderr, "fread_55 failed in ReadSTP3.cpp");
    }
    if (fread(comm, 1, 80, f_tran) != 1)
    {
        fprintf(stderr, "fread_56 failed in ReadSTP3.cpp");
    }
    if (fread(date, 1, 80, f_tran) != 1)
    {
        fprintf(stderr, "fread_57 failed in ReadSTP3.cpp");
    }
    if (fread(&ser_number, 4, 1, f_tran) != 4)
    {
        fprintf(stderr, "fread_58 failed in ReadSTP3.cpp");
    }
    if (fread(&numb_of_slices, 4, 1, f_tran) != 4)
    {
        fprintf(stderr, "fread_59 failed in ReadSTP3.cpp");
    }

    // read transformation for each slice
    for (j = 1; j < numb_of_slices + 1; j++)
    {
        fseek(f_tran, block_length * j + ser_head_length, SEEK_SET);
        if (fread(&trafo_type, 4, 1, f_tran) != 4)
        {
            fprintf(stderr, "fread_60 failed in ReadSTP3.cpp");
        }
        if (fread(&calculated, 4, 1, f_tran) != 4)
        {
            fprintf(stderr, "fread_61 failed in ReadSTP3.cpp");
        }
        if (fread(&is_axial, 4, 1, f_tran) != 4)
        {
            fprintf(stderr, "fread_62 failed in ReadSTP3.cpp");
        }
        if (fread(marker, sizeof(marker), 1, f_tran) != sizeof(marker))
        {
            fprintf(stderr, "fread_63 failed in ReadSTP3.cpp");
        }
        if (fread(plate, sizeof(plate), 1, f_tran) != sizeof(plate))
        {
            fprintf(stderr, "fread_64 failed in ReadSTP3.cpp");
        }
        if (fread(&missing, 4, 1, f_tran) != 4)
        {
            fprintf(stderr, "fread_65 failed in ReadSTP3.cpp");
        }
        if (fread(mat.mat, sizeof(mat.mat), 1, f_tran) != sizeof(mat.mat))
        {
            fprintf(stderr, "fread_66 failed in ReadSTP3.cpp");
        }
        if (fread(rev_mat.mat, sizeof(rev_mat.mat), 1, f_tran) != sizeof(rev_mat.mat))
        {
            fprintf(stderr, "fread_67 failed in ReadSTP3.cpp");
        }
        v_mat.push_back(mat);
        v_rev_mat.push_back(rev_mat);
    }

    fclose(f_tran);
    all_slices = v_mat.size();
    elements_v_rev_mat = v_rev_mat.size();
    fov_by_2 = ppatient->Pixel_size * ppatient->Resolution / 2.0;
    n = ppatient->No_Slices * 4;

    // define for geting the glogal transformation matrix, using the
    // singular value decomposition NR::svdcmp(x,w,v), and backsustitution NR::svbksb(x,w,v,b_x,x_x);
    // here we used matrix defined in Numerical Recipes because are dinamics(we dont know how many members have)

    Mat_DP x(n, 4), u(n, 4), v(4, 4);
    Vec_DP w(4), b(n);
    Vec_DP b_x(n), b_y(n), b_z(n);
    Vec_DP x_x(n), x_y(n), x_z(n);

    // define for geting the inverse glogal transformation matrix, using the Lower Up decomposition
    // NR::ludcmp(global_mat,indx,d), and backsustitution NR::lubksb(global_mat,indx,col);

    Mat_DP global_mat(4, 4);
    Vec_DP col(4);
    Vec_INT indx(4);
    DP d;

    for (i = 0; i < all_slices; i++)
    {
        // image coordinates
        x[i * 4 + 0][0] = fov_by_2;
        x[i * 4 + 0][1] = fov_by_2;
        x[i * 4 + 0][2] = ppatient->Z_Table[i];
        x[i * 4 + 0][3] = 1.0;

        x[i * 4 + 1][0] = fov_by_2;
        x[i * 4 + 1][1] = -fov_by_2;
        x[i * 4 + 1][2] = ppatient->Z_Table[i];
        x[i * 4 + 1][3] = 1.0;

        x[i * 4 + 2][0] = -fov_by_2;
        x[i * 4 + 2][1] = -fov_by_2;
        x[i * 4 + 2][2] = ppatient->Z_Table[i];
        x[i * 4 + 2][3] = 1.0;

        x[i * 4 + 3][0] = -fov_by_2;
        x[i * 4 + 3][1] = fov_by_2;
        x[i * 4 + 3][2] = ppatient->Z_Table[i];
        x[i * 4 + 3][3] = 1.0;

        // Stereotactic coordinates
        Stereo_point_0.x = 0.0;
        Stereo_point_0.y = 0.0;
        Stereo_point_0.z = 0.0;
        Stereo_point_1.x = 0.0;
        Stereo_point_1.y = 0.0;
        Stereo_point_1.z = 0.0;
        Stereo_point_2.x = 0.0;
        Stereo_point_2.y = 0.0;
        Stereo_point_2.z = 0.0;
        Stereo_point_3.x = 0.0;
        Stereo_point_3.y = 0.0;
        Stereo_point_3.z = 0.0;

        for (int f = 0; f <= 3; f++)
        {
            Stereo_point_0.x += v_mat[i].mat[f][1] * Edge_point_a[f];
            Stereo_point_0.y += v_mat[i].mat[f][2] * Edge_point_a[f];
            Stereo_point_0.z += v_mat[i].mat[f][3] * Edge_point_a[f];
            Stereo_point_0.err = 1.0; // [0.0, 0.0, 1.0, 1,0]

            Stereo_point_1.x += v_mat[i].mat[f][1] * Edge_point_b[f];
            Stereo_point_1.y += v_mat[i].mat[f][2] * Edge_point_b[f];
            Stereo_point_1.z += v_mat[i].mat[f][3] * Edge_point_b[f];
            Stereo_point_1.err = 1.0; // [0.0, 1024.0, 1.0, 1,0]

            Stereo_point_2.x += v_mat[i].mat[f][1] * Edge_point_c[f];
            Stereo_point_2.y += v_mat[i].mat[f][2] * Edge_point_c[f];
            Stereo_point_2.z += v_mat[i].mat[f][3] * Edge_point_c[f];
            Stereo_point_2.err = 1.0; // [1024.0, 1024.0, 1.0, 1,0]

            Stereo_point_3.x += v_mat[i].mat[f][1] * Edge_point_d[f];
            Stereo_point_3.y += v_mat[i].mat[f][2] * Edge_point_d[f];
            Stereo_point_3.z += v_mat[i].mat[f][3] * Edge_point_d[f];
            Stereo_point_3.err = 1.0; // [1024.0, 0.0, 1.0, 1,0]
        }

        b_x[i * 4 + 0] = Stereo_point_0.x;
        b_x[i * 4 + 1] = Stereo_point_1.x;
        b_x[i * 4 + 2] = Stereo_point_2.x;
        b_x[i * 4 + 3] = Stereo_point_3.x;

        b_y[i * 4 + 0] = Stereo_point_0.y;
        b_y[i * 4 + 1] = Stereo_point_1.y;
        b_y[i * 4 + 2] = Stereo_point_2.y;
        b_y[i * 4 + 3] = Stereo_point_3.y;

        b_z[i * 4 + 0] = Stereo_point_0.z;
        b_z[i * 4 + 1] = Stereo_point_1.z;
        b_z[i * 4 + 2] = Stereo_point_2.z;
        b_z[i * 4 + 3] = Stereo_point_3.z;
    }

    // solve linear equation
    NR::svdcmp(x, w, v); // here we make the decomposition of the matrix X (image coordinate,for the for points in each slices)!

    NR::svbksb(x, w, v, b_x, x_x);
    NR::svbksb(x, w, v, b_y, x_y);
    NR::svbksb(x, w, v, b_z, x_z);

    // transformation matrix
    for (i = 0; i < 4; i++)
    {
        ppatient->Global_Tra_Matrix[i][0] = x_x[i];
        ppatient->Global_Tra_Matrix[i][1] = x_y[i];
        ppatient->Global_Tra_Matrix[i][2] = x_z[i];
        ppatient->Global_Tra_Matrix[i][3] = last_col_glo_matrix[i];

        for (j = 0; j < 4; j++)
            global_mat[i][j] = ppatient->Global_Tra_Matrix[i][j];
    }

    // calculate inverse matrix
    NR::ludcmp(global_mat, indx, d);

    for (j = 0; j < 4; j++)
    {
        for (i = 0; i < 4; i++)
            col[i] = 0.0;
        col[j] = 1.0;
        NR::lubksb(global_mat, indx, col);
        for (i = 0; i < 4; i++)
            global_inv_mat[i][j] = col[i];
    }

    // print transformation info
    ts << ": Ok</B>";
    ts << "<br><br><B>Transformation Info</B>"; // <br> te salta una linea, con el primer B me lo escribiria to en negro pa especificar q solo queremos la linea esa se pone al final </B>
    ts << "<pre>"; // si omito esta linea me escribe la dos matrices juntas sin ningun sentido!, y pq el otro no pasa na cuando se omite, ver #
    ts << "Mat = <br>";

    for (i = 0; i < 4; i++)
    {
        for (j = 0; j < 4; j++)
            ppatient->Rev_Global_Tra_Matrix[i][j] = global_inv_mat[i][j];

        ts << "       " << ppatient->Global_Tra_Matrix[i][0]
           << "       " << ppatient->Global_Tra_Matrix[i][1]
           << "       " << ppatient->Global_Tra_Matrix[i][2]
           << "       " << ppatient->Global_Tra_Matrix[i][3]
           << "<br>";
    }
    ts << "RevMat = <br>";

    for (i = 0; i < 4; i++)
        ts << "       " << ppatient->Rev_Global_Tra_Matrix[i][0]
           << "       " << ppatient->Rev_Global_Tra_Matrix[i][1]
           << "       " << ppatient->Rev_Global_Tra_Matrix[i][2]
           << "       " << ppatient->Rev_Global_Tra_Matrix[i][3]
           << "<br>";

    ts << "<br></pre>";

    return 0;
}
示例#2
0
    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;
      }
*/

    }