void EigenvalueProblem<dim>::output_results() const
{
    DataOut<dim> data_out;

    data_out.attach_dof_handler(dof_handler);

    for (size_t i = 0; i < eigenfunctions.size(); ++i) {
        data_out.add_data_vector(eigenfunctions[i],
                                 std::string("eigenfunction_") +
                                 Utilities::int_to_string(i));

    }

    Vector<double> projected_potential (dof_handler.n_dofs());
    {
        FunctionParser<dim> potential;
        potential.initialize (FunctionParser<dim>::default_variable_names (),
                              parameters.get ("Potential"),
                              typename FunctionParser<dim>::ConstMap());
        VectorTools::interpolate (dof_handler, potential, projected_potential);
    }
    data_out.add_data_vector (projected_potential, "interpolated_potential");
    data_out.build_patches ();
    std::ofstream output ("eigenvectors.vtk");
    data_out.write_vtk (output);
}
void EigenvalueProblem<dim>::assemble_system()
{
    QGauss<dim> quadrature_formula(2);

    FEValues<dim> fe_values(fe, quadrature_formula,
                            update_values | update_gradients |
                            update_quadrature_points | update_JxW_values);

    const size_t dofs_per_cell = fe.dofs_per_cell;
    const size_t n_q_points = quadrature_formula.size();

    FullMatrix<double> cell_stiffness_matrix (dofs_per_cell, dofs_per_cell);
    FullMatrix<double> cell_mass_matrix (dofs_per_cell, dofs_per_cell);

    std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);

    FunctionParser<dim> potential;
    potential.initialize(FunctionParser<dim>::default_variable_names(),
                         parameters.get("Potential"),
                         typename FunctionParser<dim>::ConstMap());

    std::vector<double> potential_values(n_q_points);

    for (auto cell : dof_handler.active_cell_iterators()) {
        fe_values.reinit(cell);

        cell_stiffness_matrix = 0;
        cell_mass_matrix = 0;

        potential.value_list(fe_values.get_quadrature_points(),
                             potential_values);
        for (size_t q_point = 0; q_point < n_q_points; ++q_point) {
            for (size_t i = 0; i < dofs_per_cell; ++i) {
                for (size_t j = 0; j < dofs_per_cell; ++j) {
                    cell_stiffness_matrix(i, j) += (fe_values.shape_grad(i, q_point) *
                                                    fe_values.shape_grad(j, q_point)
                                                    +
                                                    potential_values[q_point] *
                                                    fe_values.shape_value(i, q_point) *
                                                    fe_values.shape_value(j, q_point)
                                                   ) * fe_values.JxW(q_point);
                    cell_mass_matrix(i, j) += (fe_values.shape_value(i, q_point) *
                                               fe_values.shape_value(j, q_point)
                                              ) * fe_values.JxW(q_point);
                }
            }
        }

        cell->get_dof_indices(local_dof_indices);

        constraints.distribute_local_to_global(cell_stiffness_matrix,
                                               local_dof_indices,
                                               stiffness_matrix);
        constraints.distribute_local_to_global(cell_mass_matrix,
                                               local_dof_indices,
                                               mass_matrix);
    }

    stiffness_matrix.compress(VectorOperation::add);
    mass_matrix.compress(VectorOperation::add);


    double min_spurious_eigenvalue = std::numeric_limits<double>::max(),
           max_spurious_eigenvalue = -std::numeric_limits<double>::max();
    for (size_t i = 0; i < dof_handler.n_dofs(); ++i) {
        if (constraints.is_constrained(i)) {
            const double ev = stiffness_matrix(i, i) / mass_matrix(i, i);
            min_spurious_eigenvalue = std::min (min_spurious_eigenvalue, ev);
            max_spurious_eigenvalue = std::max (max_spurious_eigenvalue, ev);
        }
    }
    std::cout << "   Spurious eigenvalues are all in the interval "
              << "[" << min_spurious_eigenvalue << "," << max_spurious_eigenvalue << "]"
              << std::endl;
}