void State::run_md(Nuclear& mol, Electronic& el, Hamiltonian& ham){

  if(md==NULL) { std::cout<<"Error: MD parameters have not been defined\n"; exit(1);}
  if(!is_md_initialized){    std::cout<<"Error: Need to call init_md() first. MD is not initialized\n"; exit(2);   }

  int is_thermostat, is_barostat;
  is_thermostat = ((thermostat!=NULL) && ((md->ensemble=="NVT")||(md->ensemble=="NPT")||(md->ensemble=="NPT_FLEX")));
  is_barostat   = ((barostat!=NULL) && ((md->ensemble=="NPT")||(md->ensemble=="NPT_FLEX")||(md->ensemble=="NPH")||(md->ensemble=="NPH_FLEX")));

  double dt = md->dt;
  double dt_half = 0.5*md->dt;
  double Nf = syst->Nf_t + syst->Nf_r;
  int Nf_b = 0;
  if(is_barostat) {Nf_b = barostat->get_Nf_b();}
  double scl,sc3,sc4,ksi_r;
  MATRIX3x3 S,I,sc1,sc2;


  while(md->curr_step<md->max_step){

    // Operator NHCB(dt/2)
    if(is_thermostat){
      double ekin_baro = 0.0;
      if(is_barostat){  ekin_baro = barostat->ekin_baro(); }
      thermostat->update_thermostat_forces(syst->ekin_tr(),syst->ekin_rot(),ekin_baro);
      thermostat->propagate_nhc(dt_half,syst->ekin_tr(),syst->ekin_rot(),ekin_baro);
    }


    if(is_thermostat){  thermostat->propagate_sPs(dt_half);    }

    //bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    // Operator B(dt/2)
    if(is_barostat){
      if(md->ensemble=="NPT"||md->ensemble=="NPH"){ barostat->update_barostat_forces(syst->ekin_tr(),syst->ekin_rot(),curr_V,curr_P);   }
      else if(md->ensemble=="NPT_FLEX"||md->ensemble=="NPH_FLEX"){ barostat->update_barostat_forces(syst->ekin_tr(),syst->ekin_rot(),curr_V,curr_P_tens);   }
      scl = 0.0; if(is_thermostat){ scl = thermostat->get_ksi_b();  }
      barostat->propagate_velocity(dt_half,scl);
    }
    //bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb


    double s_var,Ps,dt_half_s,dt_over_s,dt_over_s2;
    s_var = 1.0; Ps = 0.0;
    dt_half_s = dt_half;
    dt_over_s = dt;
    dt_over_s2 = dt;

    if(md->ensemble=="NVT"||md->ensemble=="NPT"||md->ensemble=="NPT_FLEX"||md->ensemble=="NPH"||md->ensemble=="NPH_FLEX"){
      if(is_thermostat){
        s_var = thermostat->get_s_var(); 
        dt_half_s = dt_half*s_var;
        dt_over_s = (dt/s_var);
        dt_over_s2 = (dt_over_s/s_var);
      }
    }

    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa    
    // Operator A(dt/2)
    //-------------------- Linear momentum propagation --------------------
    S = 0.0; I.identity();
    if(is_barostat){
      if(Nf_b==9){ S = barostat->ksi_eps + (barostat->ksi_eps.tr()/(barostat->get_Nf_t()/*+barostat->get_Nf_r()*/))*I; }
      else if(Nf_b==1){S = barostat->ksi_eps_iso * I + (3.0*barostat->ksi_eps_iso/(barostat->get_Nf_t()/*+barostat->get_Nf_r()*/))*I; }
    }
    if(is_thermostat){   S = S + thermostat->get_ksi_t() * I;      }
    sc1 = (exp_(S,-dt_half));//.symmetrized();
    sc2 = dt_half*(exp1_(S,-dt_half*0.5));//.symmetrized()*dt_half;

    //------------------- Angular momentum propagation -----------------------    
    if(is_thermostat){ ksi_r = thermostat->get_ksi_r();}else{ ksi_r = 0.0;}
    sc3 = exp(-dt_half*ksi_r);
    sc4 = dt_half*exp(-0.5*dt_half*ksi_r)*sinh_(0.5*dt_half*ksi_r);



    for(int i=0;i<syst->Number_of_fragments;i++){
      RigidBody& top = syst->Fragments[i].Group_RB;
      //-------------------- Linear momentum propagation --------------------
      top.scale_linear_(sc1);
      top.apply_force(sc2);
      //------------------- Angular momentum propagation -----------------------
      top.scale_angular_(sc3);
      top.apply_torque(sc4);       
    }// for i
    

//    if(is_thermostat){
//      thermostat->propagate_Ps(-dt_half*E_pot);
//    }
    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

    if(is_thermostat){  thermostat->propagate_Ps(-dt_half*E_pot);    }

    //ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
    //ccccccccccccccccccccccccccccccc Core part ccccccccccccccccccccccccccccccccccccc
    sc1.identity();
    sc2.identity();
    sc2 = sc2 * dt;
    if(is_barostat){
      sc1 = (barostat->pos_scale(dt));
      sc2 = dt*barostat->vpos_scale(dt);
    }

    for(i=0;i<syst->Number_of_fragments;i++){
      RigidBody& top = syst->Fragments[i].Group_RB;
      if(is_thermostat){  thermostat->propagate_Ps( 0.5*dt_over_s2*(top.ekin_rot()+top.ekin_tr()) ); }
      double Ps,s_var;
      s_var = 1.0;  if(is_thermostat){ s_var = thermostat->s_var; }
      Ps = 0.0;
      if(md->integrator=="Jacobi")    { top.propagate_exact_rb(dt_over_s); }
      else if(md->integrator=="DLML")  { top.propagate_dlml(dt_over_s,Ps); }
      else if(md->integrator=="Terec") { top.propagate_terec(dt_over_s);}
      else if(md->integrator=="qTerec") { top.propagate_qterec(dt_over_s);}
      else if(md->integrator=="NO_SQUISH"){ top.propagate_no_squish(dt_over_s);}
      else if(md->integrator=="KLN")   { top.propagate_kln(dt_over_s);}
      else if(md->integrator=="Omelyan"){ top.propagate_omelyan(dt_over_s);}

      if(is_thermostat){  thermostat->propagate_Ps( 0.5*dt_over_s2*(top.ekin_rot()+top.ekin_tr()) ); } 
      if(is_barostat) {  
        top.scale_position(sc1); 
        top.shift_position(sc2*top.rb_p*top.rb_iM);
      }
      else{
        top.shift_position(dt_over_s*top.rb_p*top.rb_iM);
      }        

    }// for i - all fragments

    if(is_thermostat){  thermostat->propagate_Ps(dt*( H0 - Nf*boltzmann*thermostat->Temperature*(log(thermostat->s_var)+1.0) ) ); }


    // Update cell shape
    if(is_barostat){ 
      if(syst->is_Box) {
        VECTOR t1_n,t2_n,t3_n; // new
        VECTOR t1_o,t2_o,t3_o; // old

        syst->Box  =  barostat->pos_scale(dt) * syst->Box;
/*
        system->Boxold.get_vectors(t1_o,t2_o,t3_o);
        system->Box.get_vectors(t1_n,t2_n,t3_n);

        // Find minimal heights of old and new boxes
        double h1_n,h2_n,h3_n;
        double h1_o,h2_o,h3_o;
        double V_n, V_o;  // Volume
        double max_n,min_n,max_o,min_o; // maximal and minimal heights new and old

        V_n = fabs(system->Box.Determinant());
        V_o = fabs(system->Boxold.Determinant());
        VECTOR S;
        S.cross(t2_n,t3_n); h1_n = V_n/fabs(S.length());
        S.cross(t3_n,t1_n); h2_n = V_n/fabs(S.length());
        S.cross(t1_n,t2_n); h3_n = V_n/fabs(S.length());
        max_n = (h1_n>=h2_n)?h1_n:h2_n;      min_n = (h1_n<=h2_n)?h1_n:h2_n;
        max_n = (max_n>=h3_n)?max_n:h3_n;    min_n = (min_n<=h3_n)?min_n:h3_n;

        S.cross(t2_o,t3_o); h1_o = V_o/fabs(S.length());
        S.cross(t3_o,t1_o); h2_o = V_o/fabs(S.length());
        S.cross(t1_o,t2_o); h3_o = V_o/fabs(S.length());
        max_o = (h1_o>=h2_o)?h1_o:h2_o;      min_o = (h1_o<=h2_o)?h1_o:h2_o;
        max_o = (max_o>=h3_o)?max_o:h3_o;    min_o = (min_o<=h3_o)?min_o:h3_o;

        int n_max = ceil((12.0+2.0)/min_n)+1;
        int o_max = ceil((12.0+2.0)/min_o)+1;
        n_max = (n_max>=o_max)?n_max:o_max;

        double dt1,dt2;
        dt1 = (max_n - min_o); dt1 = dt1*dt1;
        dt2 = (max_o - min_n); dt2 = dt2*dt2;
        system->dT_2 = 4.0*3.0*n_max*n_max*((dt1>=dt2)?dt1:dt2);
*/
      }
    }

    // Update atomic positions and calculate interactions
    for(i=0;i<syst->Number_of_fragments;i++){ syst->update_atoms_for_fragment(i);  }
    syst->zero_forces_and_torques();

//!!!!!!!!!!!!!!!!1    E_pot = system->energy(); !!!!!!!!!!!!!!!!1
    syst->extract_atomic_q(mol.q); // syst -> mol
//    E_pot = compute_potential_energy(mol, el, ham, 1); //  # 1 - FSSH forces
    E_pot = compute_forces(mol, el, ham, 1); 
    syst->set_atomic_f(mol.f);    // mol -> syst

    // Update rigid-body variables
    syst->update_fragment_forces_and_torques();


    //cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

    
    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
    // Operator A(dt/2)
    E_kin = 0.0;
    //-------------------- Linear momentum propagation --------------------
    S = 0.0; I.identity();
    if(is_barostat){
      if(Nf_b==9){ S = barostat->ksi_eps + (barostat->ksi_eps.tr()/(barostat->get_Nf_t()/*+barostat->get_Nf_r()*/))*I; }
      else if(Nf_b==1){S = barostat->ksi_eps_iso * I + (3.0*barostat->ksi_eps_iso/(barostat->get_Nf_t()/*+barostat->get_Nf_r()*/))*I; }
    }
    if(is_thermostat){   S = S + thermostat->get_ksi_t() * I;      }
    sc1 = (exp_(S,-dt_half));//.symmetrized();
    sc2 = dt_half*(exp1_(S,-dt_half*0.5));//.symmetrized()*dt_half;

    //------------------- Angular momentum propagation -----------------------
    if(is_thermostat){ ksi_r = thermostat->get_ksi_r();}else{ ksi_r = 0.0;}
    sc3 = exp(-dt_half*ksi_r);
    sc4 = dt_half*exp(-0.5*dt_half*ksi_r)*sinh_(0.5*dt_half*ksi_r);


    for(i=0;i<syst->Number_of_fragments;i++){
      RigidBody& top = syst->Fragments[i].Group_RB;
      //-------------------- Linear momentum propagation --------------------
      top.scale_linear_(sc1);
      top.apply_force(sc2);
      //------------------- Angular momentum propagation -----------------------
      top.scale_angular_(sc3);
      top.apply_torque(sc4);
      E_kin += (top.ekin_rot() + top.ekin_tr());
    }// for i

    //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

    if(is_thermostat){ thermostat->propagate_Ps( -dt_half*E_pot); }
   //------- Update state variables ------------
      curr_P_tens = syst->pressure_tensor();
      curr_P = (curr_P_tens.tr()/3.0);
      curr_V = syst->volume();
//   curr_P_tens = 0.0;
//   curr_P = 0.0;
//   curr_V = 1e+10;
   //-------------------------------------------

    //bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
    // Operator B(dt/2)
    if(is_barostat){
      if(md->ensemble=="NPT"||md->ensemble=="NPH"){ barostat->update_barostat_forces(syst->ekin_tr(),syst->ekin_rot(),curr_V,curr_P);   }
      else if(md->ensemble=="NPT_FLEX"||md->ensemble=="NPH_FLEX"){ barostat->update_barostat_forces(syst->ekin_tr(),syst->ekin_rot(),curr_V,curr_P_tens);   }
      scl = 0.0; if(is_thermostat){ scl = thermostat->get_ksi_b();  }
      barostat->propagate_velocity(dt_half,scl);
    }

    //bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb

    if(is_thermostat){thermostat->propagate_sPs(dt_half); }

    // Operator NHCB(dt/2)
    if(is_thermostat){
      double ekin_baro = 0.0;
      if(is_barostat){  ekin_baro = barostat->ekin_baro(); }
      thermostat->update_thermostat_forces(syst->ekin_tr(),syst->ekin_rot(),ekin_baro);
      thermostat->propagate_nhc(dt_half,syst->ekin_tr(),syst->ekin_rot(),ekin_baro);
    }


    if(md->ensemble=="NVE"){ s_var = 1.0;  Ps = 0.0;}
    if(is_thermostat){   E_kin/=(thermostat->s_var*thermostat->s_var); }

    E_kin_tr = syst->ekin_tr();
    E_kin_rot = syst->ekin_rot();
    E_tot = E_kin + E_pot;
//    if(!is_H0){ H0 = E_tot + thermostat->energy(); is_H0 = 1;}

    if(md->ensemble=="NVE"){  H_NP = E_tot; }
    else if(md->ensemble=="NVT"){
      if(is_thermostat){
        if(!is_H0){ H0 = E_tot + thermostat->energy(); is_H0 = 1;}
        if(thermostat->thermostat_type=="Nose-Poincare"){    H_NP = thermostat->s_var*(E_tot + thermostat->energy() - H0);   }
        else if(thermostat->thermostat_type=="Nose-Hoover"){ H_NP = E_tot + thermostat->energy();    }
      }
    }
    else if(md->ensemble=="NPH"||md->ensemble=="NPH_FLEX"){
      if(is_barostat){  H_NP = E_tot + barostat->ekin_baro() + curr_V * barostat->Pressure;   }
    }
    else if(md->ensemble=="NPT" || md->ensemble=="NPT_FLEX"){
      if(is_barostat){   H_NP = E_tot + barostat->ekin_baro() + curr_V * barostat->Pressure;  }
      if(is_thermostat){ H_NP += thermostat->energy();   }
    }

    curr_T = 2.0*E_kin/(Nf*(boltzmann/hartree));

    //------------- Angular velocity --------------
    L_tot = 0.0; 
    P_tot = 0.0;
    for(i=0;i<syst->Number_of_fragments;i++){
      RigidBody& top = syst->Fragments[i].Group_RB;
      VECTOR tmp; tmp.cross(top.rb_cm,top.rb_p);
      L_tot += top.rb_A_I_to_e_T * top.rb_l_e + tmp;
      P_tot += top.rb_p;
    }

    md->curr_step++;
    md->curr_time+=dt;
      
  }// for s
  md->curr_step = 0;
  md->curr_time = 0.0;
}
 inline void operator()(typename Exp::argument_type val) const {
     print_(exp_(val));
 }