gsl::vector force(gsl::vector &position, gsl::vector &momentum, double time, int charge)
    {
        //values
        double momentum_squared=momentum.sum_of_squares();
        double momentum_magnitude=sqrt(momentum_squared);
        double G=gamma(momentum_squared);
        double inverse_gamma=1.0/G;

        //electric field
        gsl::vector force=charge*E_field->get(position, time);

        //magnetic field
        gsl::vector B=charge*B_field->get(position, time);
        force[0]+=inverse_gamma*(momentum[1]*B[2]-momentum[2]*B[1]);
        force[1]+=inverse_gamma*(momentum[2]*B[0]-momentum[0]*B[2]);
        force[2]+=inverse_gamma*(momentum[0]*B[1]-momentum[1]*B[0]);

        //ionization friction
        double friction=-1;
        if(charge==-1)
        {
            if(remove_moller==0 or remove_moller==1) //if not removing moller losses, or constant min_energy
            {
                friction=electron_table.electron_lookup(momentum_squared);
            }
            else if(remove_moller==2) //variable min energy
            {
                friction=electron_table.electron_lookup_variable_RML(momentum_squared, min_energy);
            }
        }
        else
        {
            throw gen_exception("positrons not implemented");
            ////positrons not implemented
            //friction=ionization.positron_lookup(momentum_squared);
        }

        //friction*=0.2;

        if(friction>0) //don't want weird stuff
        {
            force[0]-=friction*momentum[0]/momentum_magnitude;
            force[1]-=friction*momentum[1]/momentum_magnitude;
            force[2]-=friction*momentum[2]/momentum_magnitude;
        }

        return force;
    }
    /**
     * C++ version of gsl_eigen_genv_QZ().
     * Computes the eigenvalues of A and stores them (unordered) in eval.
     * The diagonal and lower triangle of A are altered. The workspace should have size
     * @c n, where @c A has @c n rows and columns.
     * @param A A matrix (should be square)
     * @param B A matrix (should be square)
     * @param alpha This is where the eigenvalues are stored
     * @param beta This is where the eigenvalues are stored
     * @param evec This is where the eigenvectors are stored
     * @param Q A matrix (should be square)
     * @param Z A matrix (should be square)
     * @param w A workspace
     * @return Error code on failure
     */
    inline int genv_QZ( gsl::matrix& A, gsl::matrix& B, gsl::vector_complex& alpha,
			gsl::vector& beta, gsl::matrix_complex& evec,
			gsl::matrix& Q, gsl::matrix& Z, genv_workspace& w ){ return
	gsl_eigen_genv_QZ( A.get(), B.get(), alpha.get(), beta.get(), evec.get(), Q.get(), Z.get(), w.get() ); }
    /**
     * C++ version of gsl_eigen_gen().
     * Computes the eigenvalues of A and stores them (unordered) in eval.
     * The diagonal and lower triangle of A are altered. The workspace should have size
     * @c n, where @c A has @c n rows and columns.
     * @param A A matrix (should be square)
     * @param B A matrix (should be square)
     * @param alpha This is where the eigenvalues are stored
     * @param beta This is where the eigenvalues are stored
     * @param w A workspace
     * @return Error code on failure
     */
    inline int gen( gsl::matrix& A, gsl::matrix& B, gsl::vector_complex& alpha, gsl::vector& beta,
		    gen_workspace& w ){ return gsl_eigen_gen( A.get(), B.get(), alpha.get(), beta.get(), w.get() ); }
      /**
       * C++ version of gsl_permute_vector_inverse().
       * @param p A permutation
       * @param v A vector
       * @return Error code on failure
       */
      inline int vector_inverse( permutation const& p, gsl::vector& v ){
	return gsl_permute_vector_inverse( p.get(), v.get() ); }