Beispiel #1
0
/* Normalize a given vector in 3D. */
void normalize(GLdouble *v){
    GLdouble norm = calculate_norm(v[0], v[1], v[2]);

    v[0] = v[0] / norm;
    v[1] = v[1] / norm;
    v[2] = v[2] / norm;
}
Beispiel #2
0
std::set<int>& DiscontinuityDetector::get_discontinuous_element_ids(double threshold)
{
  Element* e;
  for_all_active_elements(e, mesh) {
    for(int edge_i = 0; edge_i < e->get_num_surf(); edge_i++)
      if(calculate_relative_flow_direction(e, edge_i) < -1e-3 && !e->en[edge_i]->bnd) {
        double jump = calculate_jumps(e, edge_i);
        double diameter_indicator = std::pow(e->get_diameter(), (H2D_GET_H_ORDER(spaces[0]->get_element_order(e->id)) + 1) / 2);
        double edge_length = std::sqrt(std::pow(e->vn[(edge_i + 1) % 4]->x - e->vn[edge_i]->x, 2) + std::pow(e->vn[(edge_i + 1) % 4]->y - e->vn[edge_i]->y, 2));
        double norm = calculate_norm(e, edge_i);
        double discontinuity_detector = jump / (diameter_indicator * edge_length * norm);
        if(discontinuity_detector > threshold)
          discontinuous_element_ids.insert(e->id);
      }
  }
  return discontinuous_element_ids;
};
void TwostepTimeSolver::solve()
{
  libmesh_assert(core_time_solver.get());

  // The core_time_solver will handle any first_solve actions
  first_solve = false;

  // We may have to repeat timesteps entirely if our error is bad
  // enough
  bool max_tolerance_met = false;

  // Calculating error values each time
  Real single_norm(0.), double_norm(0.), error_norm(0.),
    relative_error(0.);

  while (!max_tolerance_met)
    {
      // If we've been asked to reduce deltat if necessary, make sure
      // the core timesolver does so
      core_time_solver->reduce_deltat_on_diffsolver_failure =
        this->reduce_deltat_on_diffsolver_failure;

      if (!quiet)
        {
          libMesh::out << "\n === Computing adaptive timestep === "
                       << std::endl;
        }

      // Use the double-length timestep first (so the
      // old_nonlinear_solution won't have to change)
      core_time_solver->solve();

      // Save a copy of the double-length nonlinear solution
      // and the old nonlinear solution
      std::unique_ptr<NumericVector<Number>> double_solution =
        _system.solution->clone();
      std::unique_ptr<NumericVector<Number>> old_solution =
        _system.get_vector("_old_nonlinear_solution").clone();

      double_norm = calculate_norm(_system, *double_solution);
      if (!quiet)
        {
          libMesh::out << "Double norm = " << double_norm << std::endl;
        }

      // Then reset the initial guess for our single-length calcs
      *(_system.solution) = _system.get_vector("_old_nonlinear_solution");

      // Call two single-length timesteps
      // Be sure that the core_time_solver does not change the
      // timestep here.  (This is unlikely because it just succeeded
      // with a timestep twice as large!)
      // FIXME: even if diffsolver failure is unlikely, we ought to
      // do *something* if it happens
      core_time_solver->reduce_deltat_on_diffsolver_failure = 0;

      Real old_time = _system.time;
      Real old_deltat = _system.deltat;
      _system.deltat *= 0.5;
      core_time_solver->solve();
      core_time_solver->advance_timestep();
      core_time_solver->solve();

      single_norm = calculate_norm(_system, *_system.solution);
      if (!quiet)
        {
          libMesh::out << "Single norm = " << single_norm << std::endl;
        }

      // Reset the core_time_solver's reduce_deltat... value.
      core_time_solver->reduce_deltat_on_diffsolver_failure =
        this->reduce_deltat_on_diffsolver_failure;

      // But then back off just in case our advance_timestep() isn't
      // called.
      // FIXME: this probably doesn't work with multistep methods
      _system.get_vector("_old_nonlinear_solution") = *old_solution;
      _system.time = old_time;
      _system.deltat = old_deltat;

      // Find the relative error
      *double_solution -= *(_system.solution);
      error_norm  = calculate_norm(_system, *double_solution);
      relative_error = error_norm / _system.deltat /
        std::max(double_norm, single_norm);

      // If the relative error makes no sense, we're done
      if (!double_norm && !single_norm)
        return;

      if (!quiet)
        {
          libMesh::out << "Error norm = " << error_norm << std::endl;
          libMesh::out << "Local relative error = "
                       << (error_norm /
                           std::max(double_norm, single_norm))
                       << std::endl;
          libMesh::out << "Global relative error = "
                       << (error_norm / _system.deltat /
                           std::max(double_norm, single_norm))
                       << std::endl;
          libMesh::out << "old delta t = " << _system.deltat << std::endl;
        }

      // If our upper tolerance is negative, that means we want to set
      // it based on the first successful time step
      if (this->upper_tolerance < 0)
        this->upper_tolerance = -this->upper_tolerance * relative_error;

      // If we haven't met our upper error tolerance, we'll have to
      // repeat this timestep entirely
      if (this->upper_tolerance && relative_error > this->upper_tolerance)
        {
          // Reset the initial guess for our next try
          *(_system.solution) =
            _system.get_vector("_old_nonlinear_solution");

          // Chop delta t in half
          _system.deltat /= 2.;

          if (!quiet)
            {
              libMesh::out << "Failed to meet upper error tolerance"
                           << std::endl;
              libMesh::out << "Retrying with delta t = "
                           << _system.deltat << std::endl;
            }
        }
      else
        max_tolerance_met = true;
    }


  // Otherwise, compare the relative error to the tolerance
  // and adjust deltat
  last_deltat = _system.deltat;

  // If our target tolerance is negative, that means we want to set
  // it based on the first successful time step
  if (this->target_tolerance < 0)
    this->target_tolerance = -this->target_tolerance * relative_error;

  const Real global_shrink_or_growth_factor =
    std::pow(this->target_tolerance / relative_error,
             static_cast<Real>(1. / core_time_solver->error_order()));

  const Real local_shrink_or_growth_factor =
    std::pow(this->target_tolerance /
             (error_norm/std::max(double_norm, single_norm)),
             static_cast<Real>(1. / (core_time_solver->error_order()+1.)));

  if (!quiet)
    {
      libMesh::out << "The global growth/shrink factor is: "
                   << global_shrink_or_growth_factor << std::endl;
      libMesh::out << "The local growth/shrink factor is: "
                   << local_shrink_or_growth_factor << std::endl;
    }

  // The local s.o.g. factor is based on the expected **local**
  // truncation error for the timestepping method, the global
  // s.o.g. factor is based on the method's **global** truncation
  // error.  You can shrink/grow the timestep to attempt to satisfy
  // either a global or local time-discretization error tolerance.

  Real shrink_or_growth_factor =
    this->global_tolerance ? global_shrink_or_growth_factor :
    local_shrink_or_growth_factor;

  if (this->max_growth && this->max_growth < shrink_or_growth_factor)
    {
      if (!quiet && this->global_tolerance)
        {
          libMesh::out << "delta t is constrained by max_growth" << std::endl;
        }
      shrink_or_growth_factor = this->max_growth;
    }

  _system.deltat *= shrink_or_growth_factor;

  // Restrict deltat to max-allowable value if necessary
  if ((this->max_deltat != 0.0) && (_system.deltat > this->max_deltat))
    {
      if (!quiet)
        {
          libMesh::out << "delta t is constrained by maximum-allowable delta t."
                       << std::endl;
        }
      _system.deltat = this->max_deltat;
    }

  // Restrict deltat to min-allowable value if necessary
  if ((this->min_deltat != 0.0) && (_system.deltat < this->min_deltat))
    {
      if (!quiet)
        {
          libMesh::out << "delta t is constrained by minimum-allowable delta t."
                       << std::endl;
        }
      _system.deltat = this->min_deltat;
    }

  if (!quiet)
    {
      libMesh::out << "new delta t = " << _system.deltat << std::endl;
    }
}
Beispiel #4
0
int main(int argc, char *argv[]) {

    struct        RNAfold_args_info args_info;
    char          *string, *input_string, *structure=NULL, *cstruc=NULL;
    char          fname[80], ffname[80], gfname[80], *ParamFile=NULL;
    char          *ns_bases=NULL, *c;
    int           i, j, ii, jj, mu, length, l, sym, r, pf=0, noconv=0;
    unsigned int  input_type;
    double        energy, min_en, kT, sfact=1.07;
    int           doMEA=0, circular = 0, N;
    char *pf_struc;
    double dist;
    plist *pl;

    FILE * filehandle;
    FILE * statsfile;
    char* line;

    double tau   = 0.01; /* Variance of energy parameters */
    double sigma = 0.01; /* Variance of experimental constraints */
    double *gradient;           /* Gradient for steepest descent search
                                 epsilon[i+1]= epsilon[i] - gradient *
                                 step_size */
    double initial_step_size = 0.5;  /* Initial step size for steepest
                                      descent search */
    double step_size;
    double D;                  /* Discrepancy (i.e. value of objective
                                function) for the current
                                prediction */
    int iteration, max_iteration = 2000; /* Current and maximum number of
                                         iterations after which
                                         algorithm stops */

    double precision = 0.1; /* cutoff used for stop conditions */
    double tolerance = 0.1;   /* Parameter used by various GSL minimizers */
    int method_id = 1;        /* Method to use for minimization, 0 and 1
                               are custom steepest descent, the rest
                               are GSL implementations (see below)*/

    int initial_guess_method = 0;

    int sample_N = 1000;

    double *prev_epsilon;
    double *prev_gradient;
    double DD, prev_D, sum, norm;
    int status;
    double* gradient_numeric;
    double* gradient_numeric_gsl;

    /* Minimizer vars */
    const gsl_multimin_fdfminimizer_type *T;
    gsl_multimin_fdfminimizer *minimizer;
    gsl_vector *minimizer_x;
    gsl_vector *minimizer_g;
    gsl_multimin_function_fdf minimizer_func;
    minimizer_pars_struct minimizer_pars;

    char *constraints;
    char outfile[256];
    char constraints_file[256];
    char epsilon_file[256];
    FILE* fh;

    double last_non_nan_lnQ;

    pf_overflow = 0;
    pf_underflow = 0;

    dangles=2;

    do_backtrack  = 1;
    string        = NULL;

    noPS = 0;
    outfile[0]='\0';
    epsilon_file[0]='\0';
    strcpy(psDir, "dotplots");

    if(RNAfold_cmdline_parser (argc, argv, &args_info) != 0) exit(1);

    /* RNAbpfold specific options */

    if (args_info.tau_given) tau = args_info.tau_arg;
    if (args_info.sigma_given) sigma = args_info.sigma_arg;
    if (args_info.precision_given) precision = args_info.precision_arg;
    if (args_info.step_given) initial_step_size = args_info.step_arg;
    if (args_info.maxN_given) max_iteration = args_info.maxN_arg;
    if (args_info.minimization_given) method_id = args_info.minimization_arg;
    if (args_info.init_given) initial_guess_method = args_info.init_arg;
    if (args_info.tolerance_given) tolerance = args_info.tolerance_arg;
    if (args_info.outfile_given) strcpy(outfile, args_info.outfile_arg);
    if (args_info.constraints_given) strcpy(constraints_file, args_info.constraints_arg);
    if (args_info.epsilon_given) strcpy(epsilon_file, args_info.epsilon_arg);
    if (args_info.sampleGradient_given) sample_conditionals=1;
    if (args_info.hybridGradient_given) {
        sample_conditionals=1;
        hybrid_conditionals=1;
    }
    if (args_info.numericalGradient_given) numerical=1;
    if (args_info.sampleStructure_given) sample_structure=1;
    if (args_info.psDir_given) strcpy(psDir, args_info.psDir_arg);
    if (args_info.sparsePS_given) sparsePS=args_info.sparsePS_arg;
    if (args_info.gridSearch_given) grid_search = 1;


    /* Generic RNAfold options */

    if (args_info.temp_given)        temperature = args_info.temp_arg;
    if (args_info.reference_given)  fold_constrained=1;
    if (args_info.noTetra_given)     tetra_loop=0;
    if (args_info.dangles_given)     dangles = args_info.dangles_arg;
    if (args_info.noLP_given)        noLonelyPairs = 1;
    if (args_info.noGU_given)        noGU = 1;
    if (args_info.noClosingGU_given) no_closingGU = 1;
    if (args_info.noconv_given)      noconv = 1;
    if (args_info.energyModel_given) energy_set = args_info.energyModel_arg;
    if (args_info.paramFile_given)   ParamFile = strdup(args_info.paramFile_arg);
    if (args_info.nsp_given)         ns_bases = strdup(args_info.nsp_arg);
    if (args_info.pfScale_given)     sfact = args_info.pfScale_arg;
    if (args_info.noPS_given)        noPS=1;



    /* Create postscript directory */
    if (!noPS) {
        struct stat stat_p;
        if (stat (psDir, &stat_p) != 0) {
            if (mkdir(psDir, S_IRWXU|S_IROTH|S_IRGRP ) !=0) {
                fprintf(stderr, "WARNING: Could not create directory: %s", psDir);
            }
        }
    }

    if (ParamFile != NULL) {
        read_parameter_file(ParamFile);
    }

    if (ns_bases != NULL) {
        nonstandards = space(33);
        c=ns_bases;
        i=sym=0;
        if (*c=='-') {
            sym=1;
            c++;
        }
        while (*c!='\0') {
            if (*c!=',') {
                nonstandards[i++]=*c++;
                nonstandards[i++]=*c;
                if ((sym)&&(*c!=*(c-1))) {
                    nonstandards[i++]=*c;
                    nonstandards[i++]=*(c-1);
                }
            }
            c++;
        }
    }

    /*Read sequence*/
    fname[0] = '\0';
    while((input_type = get_input_line(&input_string, 0)) & VRNA_INPUT_FASTA_HEADER) {
        (void) sscanf(input_string, "%42s", fname);
        free(input_string);
    }

    length = (int)    strlen(input_string);
    string = strdup(input_string);
    free(input_string);
    structure = (char *) space((unsigned) length+1);

    /* For testing purpose pass dot bracket structure of reference structure via -C */
    if (fold_constrained) {
        input_type = get_input_line(&input_string, VRNA_INPUT_NOSKIP_COMMENTS);
        if(input_type & VRNA_INPUT_QUIT) {
            exit(1);
        }
        else if((input_type & VRNA_INPUT_MISC) && (strlen(input_string) > 0)) {
            cstruc = strdup(input_string);
            free(input_string);
        }
        else warn_user("-C was given but reference structure is missing");
    }

    if(noconv) {
        str_RNA2RNA(string);
    } else {
        str_DNA2RNA(string);
    }

    /* Allocating space */

    epsilon =     (double *) space(sizeof(double)*(length+1));

    exp_pert =  (double **)space(sizeof(double *)*(length+1));
    perturbations =  (double **)space(sizeof(double *)*(length+1));
    prev_epsilon = (double *) space(sizeof(double)*(length+1));
    gradient =    (double *) space(sizeof(double)*(length+1));
    gradient_numeric =    (double *) space(sizeof(double)*(length+1));
    gradient_numeric_gsl =    (double *) space(sizeof(double)*(length+1));
    prev_gradient = (double *) space(sizeof(double)*(length+1));

    q_unpaired = (double *) space(sizeof(double)*(length+1));
    p_unpaired_cond = (double **)space(sizeof(double *)*(length+1));
    p_unpaired_cond_sampled = (double **)space(sizeof(double *)*(length+1));
    p_pp =  (double **)space(sizeof(double *)*(length+1));
    p_unpaired =  (double *) space(sizeof(double)*(length+1));
    p_unpaired_tmp = (double *) space(sizeof(double)*(length+1));

    for (i=0; i <= length; i++) {
        epsilon[i] = gradient[i] = q_unpaired[i] = 0.0;
        p_unpaired_cond[i] = (double *) space(sizeof(double)*(length+1));
        p_unpaired_cond_sampled[i] = (double *) space(sizeof(double)*(length+1));
        p_pp[i] = (double *) space(sizeof(double)*(length+1));
        exp_pert[i] = (double *) space(sizeof(double)*(length+1));
        perturbations[i] = (double *) space(sizeof(double)*(length+1));
        for (j=0; j <= length; j++) {
            p_pp[i][j]=p_unpaired_cond[i][j] = 0.0;
            p_unpaired_cond_sampled[i][j] = 0.0;
        }
    }


    /*** If file with perturbation vector epsilon is given we fold using
         this epsilon and are done ***/

    if (args_info.epsilon_given) {
        plist *pl, *pl1,*pl2;

        filehandle = fopen (epsilon_file,"r");

        if (filehandle == NULL) {
            nrerror("Could not open file with perturbation vector.");
        }

        i=1;
        while (1) {
            double t;
            line = get_line(filehandle);
            if (line == NULL) break;
            if (i>length) nrerror("Too many values in perturbation vector file.");
            if (sscanf(line, "%lf", &epsilon[i]) !=1) {
                nrerror("Error while reading perturbation vector file.");
            }
            i++;
        }

        if (i-1 != length) {
            nrerror("Too few values in perturbation vector file.");
        }

        init_pf_fold(length);
        pf_fold_pb(string, NULL);

        sprintf(fname,"%s/dot.ps", psDir);
        pl1 = make_plist(length, 1e-5);

        (void) PS_dot_plot_list_epsilon(string, fname, NULL, pl1, epsilon, "");

        exit(0);
    }



    /*** Get constraints from reference structure or from external file ***/

    /* Structure was given by -C */
    if (fold_constrained) {
        for (i=0; i<length; i++) {
            if (cstruc[i] == '(' || cstruc[i] == ')') {
                q_unpaired[i+1] = 0.0;
            } else {
                q_unpaired[i+1] = 1.0;
            }
        }

        /*Read constraints from file*/
    } else {

        filehandle = fopen (constraints_file,"r");

        if (filehandle == NULL) {
            nrerror("No constraints given as dot bracket or wrong file name");
        }

        i=1;
        while (1) {
            double t;
            line = get_line(filehandle);
            if (line == NULL) break;
            if (i>length) nrerror("Too many values in constraints.dat");
            if (sscanf(line, "%lf", &q_unpaired[i]) !=1) {
                nrerror("Error while reading constraints.dat");
            }
            i++;
        }

        if (i-1 != length) {
            nrerror("Too few values in constraints.dat");
        }
    }

    /* Create file handle */
    if (outfile[0] !='\0') {
        statsfile = fopen (outfile,"w");
    } else {
        statsfile = fopen ("stats.dat","w");
    }

    setvbuf(statsfile, NULL, _IONBF, 0);

    if (!grid_search) {
        fprintf(statsfile, "Iteration\tDiscrepancy\tNorm\tdfCount\tMEA\tSampled_structure\tSampled_energy\tSampled_distance\tEpsilon\ttimestamp\n");
    } else {
        /* If we do a grid search we have a different output. */
        fprintf(statsfile, "Dummy\tm\tb\tdummy\tMEA\tepsilon\n");
    }

    if (statsfile == NULL) {
        nrerror("Could not open stats.dat for writing.");
    }

    fprintf(stderr, "tau^2 = %.4f; sigma^2 = %.4f; precision = %.4f; tolerance = %.4f; step-size: %.4f\n\n",
            tau, sigma, precision, tolerance, initial_step_size);

    st_back=1;
    min_en = fold(string, structure);

    (void) fflush(stdout);

    if (length>2000) free_arrays();

    pf_struc = (char *) space((unsigned) length+1);

    kT = (temperature+273.15)*1.98717/1000.; /* in Kcal */
    pf_scale = exp(-(sfact*min_en)/kT/length);

    /* Set up minimizer */

    minimizer_x = gsl_vector_alloc (length+1);
    minimizer_g = gsl_vector_alloc (length+1);

    for (i=0; i <= length; i++) {
        epsilon[i] = 0.0;
        gsl_vector_set (minimizer_g, i, 0.0);
        gsl_vector_set (minimizer_x, i, epsilon[i]);
    }

    minimizer_pars.length=length;
    minimizer_pars.seq = string;
    minimizer_pars.tau=tau;
    minimizer_pars.sigma=sigma;
    minimizer_pars.kT=kT;

    minimizer_func.n = length+1;
    minimizer_func.f = calculate_f;
    minimizer_func.df = numerical ? calculate_df_numerically: calculate_df;
    minimizer_func.fdf = calculate_fdf;
    minimizer_func.params = &minimizer_pars;


    //min_en = fold_pb(string, structure);
    //fprintf(stderr, "%f", min_en);
    //exit(0);

    /* Calling test functions for debugging */
    for (i=1; i <= length; i++) {
        if (i%2==0) {
            epsilon[i] = +0.2*i;
        } else {
            epsilon[i] = -0.2*i;
        }
    }

    //test_folding(string, length);
    /* //test_stochastic_backtracking(string, length); */
    /* //test_gradient(minimizer_func, minimizer_pars); */
    /* //test_gradient_sampling(minimizer_func, minimizer_pars); */
    //exit(1);


    count_df_evaluations=0;

    /* Initial guess for epsilon */

    if (initial_guess_method !=0 && initial_guess_method !=3) {

        /* Vars for inital guess methods */
        double m,b;
        double* curr_epsilon;
        double* best_epsilon;
        double best_m, best_b, best_scale;
        double curr_D;
        double min_D = 999999999.0;
        double inc = +0.25;
        double cut;

        if (initial_guess_method == 1) fprintf(stderr, "Mathew's constant perturbations\n");
        if (initial_guess_method == 2) fprintf(stderr, "Perturbations proportional to q-p\n");

        curr_epsilon = (double *) space(sizeof(double)*(length+1));
        best_epsilon = (double *) space(sizeof(double)*(length+1));

        last_non_nan_lnQ = min_en;

        // Calculate p_unpaired for unperturbed state which we need later
        // for the proportinal method
        if (initial_guess_method == 2) {

            init_pf_fold(length);

            for (i=0; i <= length; i++) {
                epsilon[i] = 0.0;
            }

            pf_fold_pb(string, NULL);
            for (i = 1; i < length; i++) {
                for (j = i+1; j<= length; j++) {
                    p_pp[i][j]=p_pp[j][i]=pr[iindx[i]-j];
                }
            }
            get_pair_prob_vector(p_pp, p_unpaired_tmp, length, 1);
            free_pf_arrays();
        }

        /* We do the same grid search as in the Mathews paper Fig. 4*/
        for (m=0.25; m <=7.0; m+=0.25) {

            // Weird way of writing this inner loop for the grid search. We
            // traverse the grid without big jumps in the parameters to make
            // sure that the updated scaling factor is accurate all the time.
            inc*=-1;

            for (b = inc < 0.0 ? 0.0 : -3.0; inc < 0.0 ? b >= -3.0 : b<= 0.0 ; b+=inc) {

                // calculate cut point with x-axis and skip parameter pairs
                // which give a cut point outside the range of
                // q_unpaired (0 to 1). They gave frequently overflows and the
                // idea is that we both want positive and negative perturbations
                cut = exp( (-1) * b / m ) - 1;

                fprintf(stderr, "\nm = %.2f, b = %.2f, cut=%.2f\n", m, b, cut);

                if (cut > 1.0 || cut < 0.01) {
                    fprintf(stderr, "\nSkipping m = %.2f, b = %.2f\n", m, b);
                    continue;
                }

                /* Mathew's constant perturbations */
                if (initial_guess_method == 1) {
                    for (i=0; i <= length; i++) {

                        /* We add epsilon to unpaired regions (as opposed to
                           paired regions as in the Mathews paper) so we multiply
                           by -1; if missing data we set it to 0.0 */

                        if (q_unpaired[i] < -0.5) {
                            curr_epsilon[i] = 0.0;
                        } else {
                            curr_epsilon[i] = (m *(log(q_unpaired[i]+1))+b) *(-1);
                        }

                        gsl_vector_set (minimizer_x, i, curr_epsilon[i]);
                    }
                    /* Perturbations proportional to q-p */
                } else {

                    for (i=0; i <= length; i++) {
                        curr_epsilon[i] = (m *(log(q_unpaired[i]+1)-log(p_unpaired_tmp[i]+1))+ b ) * (-1);
                        gsl_vector_set (minimizer_x, i, curr_epsilon[i]);
                    }
                }

                // Repeat and adjust scaling factor until we get result without over-/underflows
                do {

                    // First we use default scaling factor
                    if (pf_underflow == 0 && pf_overflow == 0) {
                        sfact = 1.070;
                    }

                    if (pf_underflow) {
                        sfact *= 0.8;
                        fprintf(stderr,"Underflow, adjusting sfact to %.4f\n", sfact );
                    }

                    if (pf_overflow) {
                        sfact *= 1.2;
                        fprintf(stderr,"Overflow, adjusting sfact to %.4f\n", sfact );
                    }

                    pf_scale = exp(-(sfact*last_non_nan_lnQ)/kT/length);

                    //fprintf(stderr,"Scaling factor is now: %.4e\n", pf_scale);

                    curr_D = calculate_f(minimizer_x, (void*)&minimizer_pars);

                    if (!isnan(last_lnQ)) last_non_nan_lnQ = last_lnQ;

                    // Give up when even extreme scaling does not give results
                    // (for some reason I could not get rid of overflows even with high scaling factors)
                    if (sfact < 0.1 || sfact > 2.0) break;

                } while (pf_underflow == 1 || pf_overflow == 1);

                // We have not given up so everything is ok now
                if (!(sfact < 0.1 || sfact > 2.0)) {

                    if (curr_D < min_D) {
                        min_D = curr_D;
                        for (i=0; i <= length; i++) {
                            best_epsilon[i] = curr_epsilon[i];
                        }
                        best_m = m;
                        best_b = b;
                        best_scale = pf_scale;
                    }

                    /*If we are interested in the grid search we misuse the
                      print_stats function and report m and b together with MEA*/
                    if (grid_search) {
                        for (i=0; i <= length; i++) {
                            epsilon[i] = curr_epsilon[i];
                        }
                        print_stats(statsfile, string, cstruc, length, 0, 0, m, 0.0, b, 0);
                    }

                    fprintf(stderr, "curr D: %.2f, minimum D: %.2f\n", curr_D, min_D);

                    // Adjust pf_scale with default scaling factor but lnQ from
                    // previous step
                    sfact = 1.070;
                    pf_scale = exp(-(sfact*last_lnQ)/kT/length);

                } else {
                    sfact = 1.070;
                    fprintf(stderr, "Skipping m = %.2f, b = %.2f; did not get stable result.\n", m, b);
                }
            } // for b
        } // for m

        fprintf(stderr, "Minimum found: m=%.2f, b=%.2f: %.2f\n", best_m, best_b, min_D);

        for (i=0; i <= length; i++) {
            epsilon[i] = best_epsilon[i];
            gsl_vector_set (minimizer_x, i, best_epsilon[i]);
        }
        pf_scale = best_scale;
    }

    if (initial_guess_method == 3) {
        srand((unsigned)time(0));
        for (i=0; i <= length; i++) {
            double r = (double)rand()/(double)RAND_MAX * 4 - 2;
            epsilon[i] = r;
            gsl_vector_set (minimizer_x, i, epsilon[i]);
        }
    }

    /* If we just wanted a grid search we are done now. */
    if (grid_search) {
        exit(0);
    }

    prev_D = calculate_f(minimizer_x, (void*)&minimizer_pars);

    print_stats(statsfile, string, cstruc, length, 0 , count_df_evaluations , prev_D, -1.0, 0.0,1);

    /* GSL minimization */

    if (method_id !=0) {

        if (method_id > 2) {
            char name[100];
            // Available algorithms
            //  3  gsl_multimin_fdfminimizer_conjugate_fr
            //  4  gsl_multimin_fdfminimizer_conjugate_pr
            //  5  gsl_multimin_fdfminimizer_vector_bfgs
            //  6  gsl_multimin_fdfminimizer_vector_bfgs2
            //  7  gsl_multimin_fdfminimizer_steepest_descent

            //   http://www.gnu.org/software/gsl/manual/html_node/Multimin-Algorithms-with-Derivatives.html

            switch (method_id) {
            case 2:
                minimizer = gsl_multimin_fdfminimizer_alloc (gsl_multimin_fdfminimizer_conjugate_fr, length+1);
                strcpy(name, "Fletcher-Reeves conjugate gradient");
                break;
            case 3:
                minimizer = gsl_multimin_fdfminimizer_alloc (gsl_multimin_fdfminimizer_conjugate_pr, length+1);
                strcpy(name, "Polak-Ribiere conjugate gradient");
                break;
            case 4:
                minimizer = gsl_multimin_fdfminimizer_alloc ( gsl_multimin_fdfminimizer_vector_bfgs, length+1);
                strcpy(name, "Broyden-Fletcher-Goldfarb-Shanno");
                break;
            case 5:
                minimizer = gsl_multimin_fdfminimizer_alloc ( gsl_multimin_fdfminimizer_vector_bfgs2, length+1);
                strcpy(name, "Broyden-Fletcher-Goldfarb-Shanno (improved version)");
                break;
            case 6:
                minimizer = gsl_multimin_fdfminimizer_alloc (gsl_multimin_fdfminimizer_steepest_descent, length+1);
                strcpy(name, "Gradient descent (GSL implmementation)");
                break;
            }

            fprintf(stderr, "Starting minimization via GSL implementation of %s...\n\n", name);

            // The last two parmeters are step size and tolerance (with
            // different meaning for different algorithms

            gsl_multimin_fdfminimizer_set (minimizer, &minimizer_func, minimizer_x, initial_step_size, tolerance);

            iteration = 1;

            do {

                status = gsl_multimin_fdfminimizer_iterate (minimizer);
                D = minimizer->f;
                norm = gsl_blas_dnrm2(minimizer->gradient);

                print_stats(statsfile, string, cstruc, length,iteration, count_df_evaluations, D, prev_D, norm, iteration%sparsePS == 0);

                prev_D = D;

                if (status) {
                    fprintf(stderr, "An unexpected error has occured in the iteration (status:%i)\n", status);
                    break;
                }

                status = gsl_multimin_test_gradient (minimizer->gradient, precision);
                if (status == GSL_SUCCESS) fprintf(stderr, "Minimum found stopping.\n");

                iteration++;

            } while (status == GSL_CONTINUE && iteration < max_iteration);

            gsl_multimin_fdfminimizer_free (minimizer);
            gsl_vector_free (minimizer_x);

            /* Custom implementation of steepest descent */
        } else {

            if (method_id == 1) {
                fprintf(stderr, "Starting custom implemented steepest descent search...\n\n");
            } else {
                fprintf(stderr, "Starting custom implemented steepest descent search with Barzilai Borwein step size...\n\n");
            }

            iteration = 0;
            D = 0.0;

            while (iteration++ < max_iteration) {

                for (i=1; i <= length; i++) {
                    gsl_vector_set (minimizer_x, i, epsilon[i]);
                }

                D = calculate_f(minimizer_x, (void*)&minimizer_pars);

                if (numerical) {
                    calculate_df_numerically(minimizer_x, (void*)&minimizer_pars, minimizer_g);
                } else {
                    calculate_df(minimizer_x, (void*)&minimizer_pars, minimizer_g);
                }

                for (i=1; i <= length; i++) {
                    gradient[i] = gsl_vector_get (minimizer_g, i);
                }

                // Do line search

                fprintf(stderr, "\nLine search:\n");

                // After the first iteration, use Barzilai-Borwain (1988) step size (currently turned off)
                if (iteration>1 && method_id==2) {

                    double denominator=0.0;
                    double numerator=0.0;

                    for (i=1; i <= length; i++) {
                        numerator += (epsilon[i]-prev_epsilon[i]) * (gradient[i]-prev_gradient[i]);
                        denominator+=(gradient[i]-prev_gradient[i]) * (gradient[i]-prev_gradient[i]);
                    }

                    step_size = numerator / denominator;

                    norm =1.0;
                } else {
                    // Use step sized given by the user (normalize it first)
                    step_size = initial_step_size / calculate_norm(gradient, length);
                }

                for (i=1; i <= length; i++) {
                    prev_epsilon[i] = epsilon[i];
                    prev_gradient[i] = gradient[i];
                }

                do {

                    for (mu=1; mu <= length; mu++) {
                        epsilon[mu] = prev_epsilon[mu] - step_size * gradient[mu];
                    }

                    for (i=1; i <= length; i++) {
                        gsl_vector_set (minimizer_x, i, epsilon[i]);
                    }

                    DD = calculate_f(minimizer_x, (void*)&minimizer_pars);

                    if (step_size > 0.0001) {
                        fprintf(stderr, "Old D: %.4f; New D: %.4f; Step size: %.4f\n", D, DD, step_size);
                    } else {
                        fprintf(stderr, "Old D: %.4f; New D: %.4f; Step size: %.4e\n", D, DD, step_size);
                    }

                    step_size /= 2;
                } while (step_size > 1e-12 && DD > D);

                norm = calculate_norm(gradient,length);

                if (DD > D) {
                    fprintf(stderr, "Line search did not improve D in iteration %i. Stop.\n", iteration);

                    if (hybrid_conditionals) {
                        sample_conditionals=0;
                    } else {
                        break;
                    }
                }

                print_stats(statsfile, string, cstruc, length,iteration, count_df_evaluations, DD, prev_D, norm, iteration%sparsePS == 0);

                if (norm<precision && iteration>1) {
                    fprintf(stderr, "Minimum found stopping.\n");
                    break;
                }

                prev_D = DD;

            }
        }

        /* Force last dotplot to be printed */
        print_stats(statsfile, string, cstruc, length,iteration, count_df_evaluations, DD, prev_D, norm, 1);
    }

    free(pf_struc);
    if (cstruc!=NULL) free(cstruc);
    (void) fflush(stdout);
    free(string);
    free(structure);
    RNAfold_cmdline_parser_free (&args_info);


    return 0;
}