text:
// SS_Label_file  #13. **SS_recruit.tpl**
// SS_Label_file  # * Spawn_Recr()  //  gets expected mean recruits from input spawning biomass
// SS_Label_file  # * apply_recdev()  //  applies recdev to the expected mean recruits
// SS_Label_file  # * Equil_Spawn_Recr_Fxn()  // gets equilibrium recruitment and spawning biomass from an input SPR

//********************************************************************
 /*  SS_Label_FUNCTION 43 Spawner-recruitment function */
//  SPAWN-RECR:   function: to calc R from S
FUNCTION dvariable Spawn_Recr(const prevariable& SSB_virgin_adj, const prevariable& Recr_virgin_adj, const prevariable& SSB_current)
  {
  RETURN_ARRAYS_INCREMENT();
  dvariable NewRecruits;
  dvariable SSB_BH1;
  dvariable recdev_offset;
  dvariable steepness;
  dvariable Shepherd_c;
  dvariable Shepherd_c2;
  dvariable Hupper;
  dvariable steep2;
  dvariable SSB_curr_adj;
  dvariable join;
  dvariable SRZ_0;
  dvariable srz_min;
  dvariable SRZ_surv;

  //  SS_Label_43.1  add 0.1 to input spawning biomass value to make calculation more rebust
  SSB_curr_adj = SSB_current + 0.100; // robust

  regime_change = SR_parm_work(N_SRparm2 - 1); //  this is a persistent deviation off the S/R curve

  //  SS_Label_43.3  calculate expected recruitment from the input spawning biomass and the SR curve
  // functions below use Recr_virgin_adj,SSB_virgin_adj which could have been adjusted adjusted above from R0,SSB_virgin
  switch (SR_fxn)
  {
    case 1: // previous placement for B-H constrained
    {
      warnstream << "B-H constrained curve is now Spawn-Recr option #6";
      write_message (FATAL, 0); // EXIT!
      break;
    }
    //  SS_Label_43.3.2  Ricker
    case 2: // ricker
    {
      steepness = SR_parm_work(2);
      NewRecruits = Recr_virgin_adj * SSB_curr_adj / SSB_virgin_adj * mfexp(steepness * (1. - SSB_curr_adj / SSB_virgin_adj));
      break;
    }
    //  SS_Label_43.3.3  Beverton-Holt
    case 3: // Beverton-Holt
    {
      steepness = SR_parm_work(2);
      alpha = 4.0 * steepness * Recr_virgin / (5. * steepness - 1.);
      beta = (SSB_virgin_adj * (1. - steepness)) / (5. * steepness - 1.);
      NewRecruits = (4. * steepness * Recr_virgin_adj * SSB_curr_adj) /
          (SSB_virgin_adj * (1. - steepness) + (5. * steepness - 1.) * SSB_curr_adj);
      break;
    }

    // Beverton-Holt with alpha beta
    /*
      case 3: // Beverton-Holt
      {
        steepness=SR_parm_work(2);
        alpha = 4.0 * steepness*Recr_virgin / (5.*steepness-1.);
        beta = (SSB_virgin_adj*(1.-steepness)) / (5.*steepness-1.);
        NewRecruits =  (alpha*SSB_curr_adj) / (beta+SSB_curr_adj);
        break;
      }
   */

    //  SS_Label_43.3.4  constant expected recruitment
    case 4: // none
    {
      NewRecruits = Recr_virgin_adj;
      break;
    }
    //  SS_Label_43.3.5  Hockey stick
    case 5: // hockey stick  where "steepness" is now the fraction of B0 below which recruitment declines linearly
      //  the 3rd parameter allows for a minimum recruitment level
      {
        steepness = SR_parm_work(2);
        temp = SR_parm_work(3) * Recr_virgin_adj + SSB_curr_adj / (steepness * SSB_virgin_adj) * (Recr_virgin_adj - SR_parm_work(3) * Recr_virgin_adj); //  linear decrease below steepness*SSB_virgin_adj
        NewRecruits = Join_Fxn(0.0 * SSB_virgin_adj, SSB_virgin_adj, steepness * SSB_virgin_adj, SSB_curr_adj, temp, Recr_virgin_adj);
        break;
      }

    //  SS_Label_43.3.6  Beverton-Holt, with constraint to have constant R about Bzero
    case 6: //Beverton-Holt constrained
    {
      steepness = SR_parm_work(2);
      alpha = 4.0 * steepness * Recr_virgin / (5. * steepness - 1.);
      beta = (SSB_virgin_adj * (1. - steepness)) / (5. * steepness - 1.);
      if (SSB_curr_adj > SSB_virgin_adj)
      {
        SSB_BH1 = SSB_virgin_adj;
      }
      else
      {
        SSB_BH1 = SSB_curr_adj;
      }
      NewRecruits = (4. * steepness * Recr_virgin_adj * SSB_BH1) / (SSB_virgin_adj * (1. - steepness) + (5. * steepness - 1.) * SSB_BH1);
      break;
    }

    //  SS_Label_43.3.7  survival based
    case 7: // survival based, so constrained such that recruits cannot exceed fecundity
    {
      // PPR_0=SSB_virgin_adj/Recr_virgin_adj;  //  pups per recruit at virgin
      // Surv_0=1./PPR_0;   //  recruits per pup at virgin
      // Pups_0=SSB_virgin_adj;  //  total population fecundity is the number of pups produced
      // Sfrac=SR_parm(2);
      SRZ_0 = log(1.0 / (SSB_virgin_adj / Recr_virgin_adj));
      steepness = SR_parm_work(2);
      srz_min = SRZ_0 * (1.0 - steepness);
      SRZ_surv = mfexp((1. - pow((SSB_curr_adj / SSB_virgin_adj), SR_parm_work(3))) * (srz_min - SRZ_0) + SRZ_0); //  survival
      NewRecruits = SSB_curr_adj * SRZ_surv;
      exp_rec(y, 1) = NewRecruits; // expected arithmetic mean recruitment
      //  SS_Label_43.3.7.1  Do variation in recruitment by adjusting survival
      //        if(SR_env_target==1) SRZ_surv*=mfexp(SR_parm(N_SRparm2-2)* env_data(y,SR_env_link));   // environ effect on survival
      if (recdev_cycle > 0)
      {
        gg = y - (styr + (int((y - styr) / recdev_cycle)) * recdev_cycle) + 1;
        SRZ_surv *= mfexp(recdev_cycle_parm(gg));
      }
      exp_rec(y, 2) = SSB_curr_adj * SRZ_surv;
      exp_rec(y, 2) *= mfexp(regime_change); //  adjust for regime which includes env and block effects; and forecast adjustments
      SRZ_surv *= mfexp(-biasadj(y) * half_sigmaRsq); // bias adjustment
      exp_rec(y, 3) = SSB_curr_adj * SRZ_surv;
      if (y <= recdev_end)
      {
        if (recdev_doit(y) > 0)
          SRZ_surv *= mfexp(recdev(y)); //  recruitment deviation
      }
      else if (Do_Forecast > 0)
      {
        SRZ_surv *= mfexp(Fcast_recruitments(y));
      }
      join = 1. / (1. + mfexp(100 * (SRZ_surv - 1.)));
      SRZ_surv = SRZ_surv * join + (1. - join) * 1.0;
      NewRecruits = SSB_curr_adj * SRZ_surv;
      exp_rec(y, 4) = NewRecruits;
      break;
    }

    //  SS_Label_43.3.8  Shepherd
    case 8: // Shepherd 3-parameter SRR. per Punt & Cope 2017
    {
      Shepherd_c = SR_parm_work(3);
      Shepherd_c2 = pow(0.2, SR_parm_work(3));
      Hupper = 1.0 / (5.0 * Shepherd_c2);
      steepness = 0.2 + (SR_parm_work(2) - 0.2) / (0.8) * (Hupper - 0.2);
      temp = (SSB_curr_adj) / (SSB_virgin_adj);
      NewRecruits = (5. * steepness * Recr_virgin_adj * (1. - Shepherd_c2) * temp) /
          (1.0 - 5.0 * steepness * Shepherd_c2 + (5. * steepness - 1.) * pow(temp, Shepherd_c));
      break;
    }

    //  SS_Label_43.3.8  Ricker-power
    case 9: // Ricker power 3-parameter SRR.  per Punt & Cope 2017
    {
      steepness = SR_parm_work(2);
      dvariable RkrPower = SR_parm_work(3);
      temp = SSB_curr_adj / SSB_virgin_adj;
      temp2 = posfun(1.0 - temp, 0.0000001, temp3);
      temp = 1.0 - temp2; //  Rick's new line to stabilize recruitment at R0 if B>B0
      dvariable RkrTop = log(5.0 * steepness) * pow(temp2, RkrPower) / pow(0.8, RkrPower);
      NewRecruits = Recr_virgin_adj * temp * mfexp(RkrTop);
      break;
    }
  }
  RETURN_ARRAYS_DECREMENT();
  return NewRecruits;
  } //  end spawner_recruitment

FUNCTION void apply_recdev(prevariable& NewRecruits, const prevariable& Recr_virgin_adj)
  {
  RETURN_ARRAYS_INCREMENT();
  //  SS_Label_43.4  For non-survival based SRR, get recruitment deviations by adjusting recruitment itself
  exp_rec(y, 1) = NewRecruits; // expected arithmetic mean recruitment
  //    exp_rec(y,2) is with regime shift or other env effect;
  //    exp_rec(y,3) is with bias adjustment
  //    exp_rec(y,4) is with dev
  regime_change = SR_parm_work(N_SRparm2 - 1); //  this is a persistent deviation off the S/R curve

  if (recdev_cycle > 0)
  {
    gg = y - (styr + (int((y - styr) / recdev_cycle)) * recdev_cycle) + 1;
    NewRecruits *= mfexp(recdev_cycle_parm(gg));
  }
  NewRecruits *= mfexp(regime_change); //  adjust for regime which includes env and block effects; and forecast adjustments
  exp_rec(y, 2) = NewRecruits; //  adjusted for env and special forecast conditions
  if (SR_fxn != 4)
    NewRecruits *= mfexp(-biasadj(y) * half_sigmaRsq); // bias adjustment
  exp_rec(y, 3) = NewRecruits;

  if (y <= recdev_end)
  {
    if (recdev_doit(y) > 0)
    {
      if (do_recdev >= 3)
      {
        NewRecruits = Recr_virgin_adj * mfexp(recdev(y)); //  recruitment deviation
      }
      else if (SR_fxn != 7)
      {
        NewRecruits *= mfexp(recdev(y)); //  recruitment deviation
      }
    }
  }

  else if (Do_Forecast > 0)
  {
    switch (int(Fcast_Loop_Control(3)))
    {
      case 0:
      {
        NewRecruits = exp_rec(y, 2);
        if (SR_fxn != 4)
          NewRecruits *= mfexp(-biasadj(y) * half_sigmaRsq); // bias adjustment
        exp_rec(y, 3) = NewRecruits;
        break;
      }
      case 1:
      {
        exp_rec(y, 2) *= Fcast_Loop_Control(4); //  apply fcast multiplier to the regime-adjusted expected value
        NewRecruits = exp_rec(y, 2);
        if (SR_fxn != 4)
          NewRecruits *= mfexp(-biasadj(y) * half_sigmaRsq); // bias adjustment
        exp_rec(y, 3) = NewRecruits;
        break;
      }
      case 2: //  use multiplier of R0
      {
        exp_rec(y, 2) = Recr_virgin_adj * Fcast_Loop_Control(4); //  apply fcast multiplier to the virgin recruitment
        NewRecruits = exp_rec(y, 2);
        if (SR_fxn != 4)
          NewRecruits *= mfexp(-biasadj(y) * half_sigmaRsq); // bias adjustment
        exp_rec(y, 3) = NewRecruits;
        break;
      }
      case 4:
      {
        //  fall through to case 3
        //  case 3 also will do averaging of recr_dist in another section of code
      }
      case 3: //  use recent mean
      {
        //  values going into the mean have already been bias adjusted and had dev applied, so take straight mean
        NewRecruits = 0.0;
        for (j = Fcast_Rec_yr1; j <= Fcast_Rec_yr2; j++)
        {
          NewRecruits += exp_rec(j, 4);
        }
        NewRecruits /= (Fcast_Rec_yr2 - Fcast_Rec_yr1 + 1);
        if(Fcast_Loop_Control(3) == 4) NewRecruits *= Fcast_Loop_Control(4);  //  apply multiplier
        exp_rec(y, 2) = NewRecruits;
        exp_rec(y, 3) = NewRecruits; //  store in the bias-adjusted field
        break;
      }
    }
    if (do_recdev > 0)
      NewRecruits *= mfexp(Fcast_recruitments(y)); //  recruitment deviation
  }
  exp_rec(y, 4) = NewRecruits;
  RETURN_ARRAYS_DECREMENT();
  } //  end spawner_recruitment

//********************************************************************
 /*  SS_Label_FUNCTION 44 Equil_Spawn_Recr_Fxn */
//  SPAWN-RECR:   function  Equil_Spawn_Recr_Fxn
FUNCTION dvar_vector Equil_Spawn_Recr_Fxn(const prevariable& SRparm2, const prevariable& SRparm3,
    const prevariable& SSB_virgin, const prevariable& Recr_virgin, const prevariable& SPR_temp)
  {
  RETURN_ARRAYS_INCREMENT();
  dvar_vector Equil_Spawn_Recr_Calc(1, 2); // values to return 1 is B_equil, 2 is R_equil
  dvariable B_equil;
  dvariable R_equil;
  dvariable temp;
  dvariable steepness;
  dvariable join;
  dvariable Shepherd_c;
  dvariable Shepherd_c2;
  dvariable SRZ_0;
  dvariable srz_min;
  dvariable SRZ_surv;

  steepness = SRparm2; //  common usage but some different
  //  SS_Label_44.1  calc equilibrium SpawnBio and Recruitment from input SPR_temp, which is spawning biomass per recruit at some given F level
  switch (SR_fxn)
  {
    case 1: // previous placement for B-H constrained
    {
      warnstream << "B-H constrained curve is now Spawn-Recr option #6";
      write_message (FATAL, 0); // EXIT!
      break;
    }
    //  SS_Label_44.1.1  Beverton-Holt with flattop beyond Bzero
    case 6: //Beverton-Holt
    {
      alpha = 4.0 * steepness * Recr_virgin / (5. * steepness - 1.);
      beta = (SSB_virgin * (1. - steepness)) / (5. * steepness - 1.);
      B_equil = alpha * SPR_temp - beta;
      B_equil = posfun(B_equil, 0.0001, temp);
      R_equil = (4. * steepness * Recr_virgin * B_equil) / (SSB_virgin * (1. - steepness) + (5. * steepness - 1.) * B_equil);
      break;
    }
    //  SS_Label_44.1.2  Ricker
    case 2: // Ricker
    {
      B_equil = SSB_virgin * (1. + (log(Recr_virgin / SSB_virgin) + log(SPR_temp)) / steepness);
      R_equil = Recr_virgin * B_equil / SSB_virgin * mfexp(steepness * (1. - B_equil / SSB_virgin));

      break;
    }
    //  SS_Label_44.1.3  Beverton-Holt
    case 3: // same as case 6
    {
      alpha = 4.0 * steepness * Recr_virgin / (5. * steepness - 1.);
      beta = (SSB_virgin * (1. - steepness)) / (5. * steepness - 1.);
      B_equil = alpha * SPR_temp - beta;
      B_equil = posfun(B_equil, 0.0001, temp);
      R_equil = (4. * steepness * Recr_virgin * B_equil) / (SSB_virgin * (1. - steepness) + (5. * steepness - 1.) * B_equil); //Beverton-Holt
      break;
    }

    //  SS_Label_44.1.4  constant recruitment
    case 4: // constant; no bias correction
    {
      B_equil = SPR_temp * Recr_virgin;
      R_equil = Recr_virgin;
      break;
    }
    //  SS_Label_44.1.5  Hockey Stick
    case 5: // hockey stick
    {
      alpha = SRparm3 * Recr_virgin; // min recruitment level
      //        temp=SSB_virgin/R0*steepness;  // spawners per recruit at inflection
      beta = (Recr_virgin - alpha) / (steepness * SSB_virgin); //  slope of recruitment on spawners below the inflection
      B_equil = Join_Fxn(0.0 * SSB_virgin / Recr_virgin, SSB_virgin / Recr_virgin, SSB_virgin / Recr_virgin * steepness, SPR_temp, alpha / ((1. / SPR_temp) - beta), SPR_temp * Recr_virgin);
      R_equil = Join_Fxn(0.0 * SSB_virgin, SSB_virgin, SSB_virgin * steepness, B_equil, alpha + beta * B_equil, Recr_virgin);
      break;
    }
    //  SS_Label_44.1.7  3 parameter survival based
    case 7: // survival
    {
      SRZ_0 = log(1.0 / (SSB_virgin / Recr_virgin));
      srz_min = SRZ_0 * (1.0 - steepness);
      B_equil = SSB_virgin * (1. - (log(1. / SPR_temp) - SRZ_0) / pow((srz_min - SRZ_0), (1. / SRparm3)));
      B_equil = posfun(B_equil, 0.0001, temp);
      SRZ_surv = mfexp((1. - pow((B_equil / SSB_virgin), SRparm3)) * (srz_min - SRZ_0) + SRZ_0); //  survival
      R_equil = B_equil * SRZ_surv;
      break;
    }

    //  SS_Label_44.1.8  3 parameter Shepherd
    case 8: // Shepherd
    {
      dvariable Shep_top;
      dvariable Shep_bot;
      dvariable Hupper;
      dvariable Shep_top2;
      //  Andre's FORTRAN
      //        TOP = 5*Steep*(1-0.2**POWER)*SPR/SPRF0-(1-5*Steep*0.2**POWER)
      //      BOT = (5*Steep-1)
      //       REC = (TOP/BOT)**(1.0/POWER)*SPRF0/SPR
      // Power = exp(logC);
      // Hupper = 1.0/(5.0 * pow(0.2,Power));
      Shepherd_c = SRparm3;
      Shepherd_c2 = pow(0.2, SRparm3);
      Hupper = 1.0 / (5.0 * Shepherd_c2);
      steepness = 0.2 + (SRparm2 - 0.2) / (0.8) * (Hupper - 0.2);
      Shep_top = 5.0 * steepness * (1.0 - Shepherd_c2) * (SPR_temp * Recr_virgin) / SSB_virgin - (1.0 - 5.0 * steepness * Shepherd_c2);
      Shep_bot = 5.0 * steepness - 1.0;
      Shep_top2 = posfun(Shep_top, 0.001, temp);
      R_equil = (SSB_virgin / SPR_temp) * pow((Shep_top2 / Shep_bot), (1.0 / SRparm3));
      B_equil = R_equil * SPR_temp;
      break;
    }

    //  SS_Label_43.3.8  Ricker-power
    case 9: // Ricker power 3-parameter SRR.  per Punt & Cope 2017
    {
      steepness = SRparm2;
      dvariable RkrPower = SRparm3;
      temp = SSB_virgin / (SPR_temp * Recr_virgin);
      dvariable RkrTop = pow(0.8, RkrPower) * log(temp) / log(5.0 * steepness);
      RkrTop = posfun(RkrTop, 0.000001, CrashPen);
      R_equil = temp * Recr_virgin * (1.0 - pow(RkrTop, 1.0 / RkrPower));
      B_equil = R_equil * SPR_temp;
      break;
    }

      /*
      case 19:  // re-parameterized Shepherd
      {
        dvariable Shep_top;
        dvariable Shep_bot;
        dvariable Hupper;
        dvariable Shep_top2;
//  Andre's FORTRAN
//        TOP = 5*Steep*(1-0.2**POWER)*SPR/SPRF0-(1-5*Steep*0.2**POWER)
//      BOT = (5*Steep-1)
//       REC = (TOP/BOT)**(1.0/POWER)*SPRF0/SPR
// Power = exp(logC);
// Hupper = 1.0/(5.0 * pow(0.2,Power));
        Shepherd_c=exp(SRparm3);
        Shepherd_c2=pow(0.2,Shepherd_c);
        Hupper=1.0/(5.0*Shepherd_c2);
        steepness=0.20001+((0.8)/(1.0+exp(-SRparm2))-0.2)/(0.8)*(Hupper-0.2);
//        steep2=0.20001+(steepness-0.2)/(0.8)*(Hupper-0.2);
        Shep_top=5.0*steepness*(1.0-Shepherd_c2)*(SPR_temp*Recr_virgin)/SSB_virgin-(1.0-5.0*steepness*Shepherd_c2);
        Shep_bot=5.0*steepness-1.0;
        Shep_top2=posfun(Shep_top,0.001,temp);
        R_equil=(SSB_virgin/SPR_temp) * pow((Shep_top2/Shep_bot),(1.0/Shepherd_c));
        B_equil=R_equil*SPR_temp;
        break;
      }

//  SS_Label_43.3.8  Ricker-power
      case 20:  // Ricker power 3-parameter SRR.  per Punt & Cope 2017
      {
//   Hupper = 10.0;
//   Steep = 0.2 + (Hupper - 0.2)/(1+exp(-1*Steep2))+1.0e-5;
//   Top =  pow(0.8,Power)*log(SPRF0/SPR)/log(5.0*Steep);
//   Top = posfun(Top,0.000001,Penal);
//   Recs = (SPRF0/SPR) * (1.0 - pow(Top,1.0/Power));
//   Recs = posfun(Recs,0.0001,Penal);
//   if (Recs < 0) Rec2 = 0; else Rec2 = Recs;
        steepness = 0.2 + (10.0 - 0.2)/(1+exp(-SR_parm_work(2)));
        dvariable RkrPower=exp(SR_parm_work(3));
        temp=SSB_virgin/(SPR_temp*Recr_virgin);
        dvariable RkrTop =  pow(0.8,RkrPower)*log(temp)/log(5.0*steepness);
        RkrTop = posfun(RkrTop,0.000001,CrashPen);
        R_equil = temp *Recr_virgin * (1.0 - pow(RkrTop,1.0/RkrPower));
        B_equil=R_equil*SPR_temp;
        break;
      }
   */
  }
  Equil_Spawn_Recr_Calc(1) = B_equil;
  Equil_Spawn_Recr_Calc(2) = R_equil;
  RETURN_ARRAYS_DECREMENT();
  return Equil_Spawn_Recr_Calc;
  } //  end Equil_Spawn_Recr_Fxn


text:
::compiling ss.exe (safe executable) with generic path
::requires "Compile" directory in the same directory as the .tpl files and this .bat file
cd ..
::deleted temporary file
del SS_functions.temp

::create SS_functions.temp file combining various functions
copy/b SS_biofxn.tpl+SS_miscfxn.tpl+SS_selex.tpl+SS_popdyn.tpl+SS_recruit.tpl+SS_benchfore.tpl+SS_expval.tpl+SS_objfunc.tpl+SS_write.tpl+SS_write_ssnew.tpl+SS_write_report.tpl+SS_ALK.tpl+SS_timevaryparm.tpl+SS_tagrecap.tpl SS_functions.temp

::combine remaining files to create ss.tpl
copy/b SS_versioninfo_330safe.tpl+SS_readstarter.tpl+SS_readdata_330.tpl+SS_readcontrol_330.tpl+SS_param.tpl+SS_prelim.tpl+SS_global.tpl+SS_proced.tpl+SS_functions.temp "Compile\ss.tpl"

::path=c:\admb;C:\rtools40\mingw64\bin;%path%

cd "Compile"
::set CXX=cl
set CXX=g++

admb ss

repo_name: nmfs-stock-synthesis/stock-synthesis

mime_type: text/plain


text:
REM compiling ss.exe (safe executable) with generic path
REM requires "Compile" directory in the same directory where
REM the .tpl files and this .bat file sit.

cd ..
REM deleted temporary file
del SS_functions.temp

REM create SS_functions.temp file combining various functions
copy/b SS_biofxn.tpl+SS_miscfxn.tpl+SS_selex.tpl+SS_popdyn.tpl+SS_recruit.tpl+SS_benchfore.tpl+SS_expval.tpl+SS_objfunc.tpl+SS_write.tpl+SS_write_ssnew.tpl+SS_write_report.tpl+SS_ALK.tpl+SS_timevaryparm.tpl+SS_tagrecap.tpl SS_functions.temp

REM combine remaining files to create ss.tpl
copy/b SS_versioninfo_330opt.tpl+SS_readstarter.tpl+SS_readdata_330.tpl+SS_readcontrol_330.tpl+SS_param.tpl+SS_prelim.tpl+SS_global.tpl+SS_proced.tpl+SS_functions.temp "Compile\ss_opt.tpl"

REM compile executable
cd "Compile"
set CXX=g++
admb -f ss_opt


text:
<!-- General instructions -->
<!--
* Please read the html comment under each heading and follow the instructions.
* For smaller changes, feel free to skip sections flagged as "optional".
* Before opening the pull request (PR), make sure all the GitHub actions are
  passing on the remote feature branch.
* Make sure this PR has an informative title rather than the default text.
* Lastly, before closing the PR, **please make sure that all comments/discussion in this PR that are related to an issue are placed in the summary of that issue**.
-->

## Concisely describe what has been changed/addressed in the pull request.
<!--- In less than 20 words describe this PR and link related issues.-->
<!--- A summary is important if there is no issue related to the PR, otherwise the summary should be in the issue.-->

<!-- Link related issue(s) using a bulleted list. -->
<!-- Remove the following bullet if no issues are linked to this PR. -->
* Resolves issue #

## What tests have been done?
### Where are the relevant files?
<!-- Uncomment the option below that best fits the situation and upload the necessary files to the correct location, preferably the associated issue(s). -->

<!-- - [x] Test files are in the issue. -->
<!-- - [x] There is no issue related to this pull request so the files are attached below. -->
<!-- - [x] No test files are required for this pull request. -->

### What tests/review still need to be done?
<!-- If no additional tests are needed, please put None.-->
<!-- Provide information on who/when for uncompleted tasks -->

## Is there an input change for users to Stock Synthesis?
<!-- Uncomment the option below that best fits the situation. -->
<!-- If needed, uncomment the code block and replace the text. -->

<!-- - [x] The input change is in the related issue(s). -->
<!-- - [x] There is no issue related to this pull request so the input change is below. -->
<!-- - [x] No, there was no input change. -->

<!---
```
If there is no issue related to this PR, replace this text with your example stock synthesis input.
```
-->

## Additional information (optional).
<!--- Any additional information goes here. -->


text:
---
name: SS3 release checklist
about: SS3 dev team only - Checklist for steps needed to release a version of SS3
title: Release v3.30.[xx] checklist
labels: request
assignees:
  - Rick-Methot-NOAA
  - chantelwetzel-noaa
  - iantaylor-NOAA
  - kellijohnson-NOAA
  - nschindler-noaa
  - e-gugliotti-NOAA

---

# Release checklist

Note all instances of xx should be replaced with the version number (e.g., the release for 3.30.20 would replace xx with 20)

## Checklist for before prerelease
- [ ] SS testing and debugging completed (RM and IT)
- [ ] Check artifact from the `call-build-ss3-warnings` github action for useful warnings (RM and IT)
- [ ] r4ss updated (IT)
- [ ] Put together pre-release announcement (RM)
- [ ] code committed and tagged in repo as `v3.30.xx-prerel` (RM)
- [ ] All exes added to github releases as `v3.30.xx-prerel` (RM)
- [ ] Announce prerelease (RM)

## Checklist for before release
- [ ] Manual updated and tagged in repo (CW) - address at least issues with the [`v3.30.xx` release label](add correct link to github issues using filter: is:issue is:open label:"3.30.xx release" when available)
- [ ] Manual added to a github release, include attaching a pdf version (EG and CW)
- [ ] Manual release version on website updated once pdf and html built (EG) (update https://github.com/nmfs-stock-synthesis/doc/blob/main/docs/SS330_User_Manual_release.html to the `v3.30.xx` version; update links to link to `v3.30.xx` in https://github.com/nmfs-stock-synthesis/doc/blob/main/docs/index.md#links-to-documentation)
- [ ] SSI updated (NS)
- [ ] Make changes to SS3 if any bugs caught in prerelease (RM)
- [ ] [Change log project board](https://github.com/orgs/nmfs-stock-synthesis/projects/11) updated with any issues labelled "change log" (RM)
- [ ] Code committed and tagged in repo as `v3.30.xx`, which will trigger a gha to build the release executables (EG) (Instructions on [how to push a a local tag to a remote](https://github.com/nmfs-stock-synthesis/stock-synthesis/wiki/Stock-Synthesis:-practices-for-maintainers#how-to-push-a-local-tag-up-to-github))
- [ ] Exe and .tpl archived on [Google drive](https://drive.google.com/drive/folders/1Gh_dXi8v3rqawpwn2N6yaaEXZPq6G2io) (EG)
- [ ] All exes added to github releases as `v3.30.xx` (EG) (get exes in the artifacts of the gha that built the release exes)
- [ ] Send out release announcement msg (RM)
- [ ] Add to release discussion on github repository (EG)

## Checklist for after release
- [ ] Update user-example models using [this github action](https://github.com/nmfs-stock-synthesis/user-examples/blob/main/R/update_examples.R) and tag with new release number after updating (EG)
- [ ] Update test models using [this github action](https://github.com/nmfs-stock-synthesis/test-models/actions/workflows/update-ss3-models.yml) and tag with new release number after updating (EG)
- [ ] Removed "resolved" tag and close all issues worked in the milestone for this release (RM)
- [ ] Move unworked issues for the release milestone to the next milestone (RM)


text:
name: Refactor
description: Change the current structure of the code or workflows
title: "[Refactor]: "
labels: ["New_Request"]
assignees:
  - Rick-Methot-NOAA
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this refactor request!
  - type: textarea
    id: describe
    attributes:
      label: Refactor request
      description: Describe what needs to be refactored and why
    validations:
      required: true
  - type: textarea
    id: reproduce
    attributes:
      label: Expected behavior
      description: A clear and concise description of what you expected to happen.
      placeholder: I expect ...
    validations:
      required: true


text:
name: SS3 Team Issues - New Template
description: Issue template for SS3 team members ONLY
title: "[Prefix for Issue Here]: Title of Issue Here"
assignees:
  - Rick-Methot-NOAA
body:
- type: markdown
  attributes:
    value: |
      # **Main Issue Information**
      **Instructions**
        - Add a label prefix in the brackets "[ ]". This should be 1 - 2 words that helps categorize the issue (e.g. [Bug], [Feature Request], [Refactor]).
        - Add a title after the colon ":". This should be a short phrase that describes the issue. It should be suitable for display in the change log.
        - In the sidebar, add labels that apply to this issue.
        - Fill out information below and update the summary with pertinent information from the comments/discussion.
- type: textarea
  id: describe
  attributes:
    label: Issue description
    description: Please provide a description of the issue.
  validations:
    required: true
- type: textarea
  id: summary
  attributes:
    label: Summary of issue history, discussion, and major aspects of code development
    description: A summary of pertinent information on this issue, including major aspects of code development, that occurred in the discussion or via email. This section can be added on to/edited at any time and should be completely summarized prior to closing by the person that created the issue.
    placeholder: |
      - This issue is related to issue #X.
      - Will need to create an example vignette for this feature.
      - Below is example input change.
        ```
        #_MG_type method st_year end_year
        1 1 2002 2003 # (M) NatMort
        4 1 2016 2018 # RecrDist
        -9999 -1 -1 -1
        ```
  validations:
    required: true
- type: textarea
  id: tasks
  attributes:
    label: Items to do
    description: Please create a list of tasks to be completed for this issue with the checkboxes.
    value: "- [ ] First Item"
  validations:
    required: true
- type: markdown
  attributes:
    value: |
      ___

      # **Other Issue Considerations**
- type: dropdown
  id: documentation
  attributes:
    label: Does documentation already exist in the SS3 User Manual?
    description: Please review the [SS3 User Manual](https://nmfs-stock-synthesis.github.io/doc/SS330_User_Manual.html) and check the box within the text area that applies.
    options:
      - Yes, the link to the section in the SS3 User Manual is provided below.
      - Yes, but further documentation needs to be added and is provided below.
      - No, the documentation that should be added to the SS3 User Manual pertaining to this issue is provided below.
  validations:
    required: true
- type: textarea
  id: add-doc
  attributes:
    label: Documentation to add to the SS3 User Manual OR link to existing documentation
    description: Please add the text that needs to be added to the SS3 User Manual along with which section it should be added to.
    placeholder: |
      - Documentation can be found in section 8.4.2 of the SS3 User Manual [here](link)
      - The following text should be added at the end of the second paragraph in that section: "add text"
  validations:
    required: true
- type: dropdown
  id: r4ss
  attributes:
    label: Are r4ss changes needed?
    description: Please check one of the boxes to indicate if r4ss changes are needed.
    options:
      - No, this issue doesn't require changes to r4ss
      - Yes, this issue requires changes to r4ss (if selecting this, please add iantaylor-NOAA as an Assignee in the panel to the right).
      - I don't know and would like an r4ss consult (if selecting this, please add iantaylor-NOAA as an Assignee in the panel to the right).
  validations:
    required: true
- type: dropdown
  id: SSI
  attributes:
    label: Are SSI changes needed?
    description: Please check one of the boxes to indicate if SSI changes are needed.
    options:
      - No, this issue doesn't require changes to SSI
      - Yes, this issue requires changes to SSI (if selecting this, please add nschindler-noaa as an Assignee in the panel to the right).
      - I don't know and would like an SSI consult (if selecting this, please add nschindler-noaa as an Assignee in the panel to the right).
  validations:
    required: true


text:
name: Bug Report
description: Report a potential bug
title: "[Bug]: "
labels: ["kind: bug", "New_Request"]
assignees:
  - Rick-Methot-NOAA
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this bug report!
  - type: textarea
    id: describe
    attributes:
      label: Describe the bug
      description: A clear and concise description of what the bug is.
    validations:
      required: true
  - type: textarea
    id: reproduce
    attributes:
      label: To Reproduce
      description: Steps to reproduce the behavior
      placeholder: |
        1. Go to '...'
        2. Click on '....'
        3. Scroll down to '....'
        4. See error
    validations:
      required: true
  - type: textarea
    id: expected
    attributes:
      label: Expected behavior
      description: A clear and concise description of what you expected to happen.
      placeholder: I expected ...
    validations:
      required: true
  - type: textarea
    id: screenshots
    attributes:
      label: Screenshots
      description: If applicable, add screenshots to help explain your problem.
    validations:
      required: false
  - type: dropdown
    id: os
    attributes:
      label: Which OS are you seeing the problem on?
      multiple: true
      options:
        - Windows
        - Mac
        - Linux
        - Other
    validations:
      required: false
  - type: input
    id: version
    attributes:
      label: Which version of SS3 are you seeing the problem on?
    validations:
      required: false
  - type: textarea
    id: context
    attributes:
      label: Additional Context
      description: Add any other context about the problem here.
    validations:
      required: false


text:
name: Feature Request
description: Request new features or changes to features
title: "[Feature]: "
labels: ["New_Request"]
assignees:
  - Rick-Methot-NOAA
body:
  - type: markdown
    attributes:
      value: |
        Thanks for taking the time to fill out this feature request!
  - type: textarea
    id: solution
    attributes:
      label: Describe the solution you would like.
      description: A clear and concise description of what you want to happen.
    validations:
      required: true
  - type: textarea
    id: alternatives
    attributes:
      label: Describe alternatives you have considered
      description: A clear and concise description of any alternative solutions or features you have considered.
      placeholder: Other solutions include ...
    validations:
      required: true
  - type: textarea
    id: stats
    attributes:
      label: Statistical validity, if applicable
      description: Please link to a paper or reference that describes how this approach improves accuracy or statistical power.
    validations:
      required: false
  - type: textarea
    id: management
    attributes:
      label: Describe if this is needed for a management application
      description: If this feature is necessary to satisfy the Terms of Reference for your fishery management body, please explain why here and describe which management body.
    validations:
      required: false
  - type: textarea
    id: context
    attributes:
      label: Additional context
      description: Add any other context or screenshots about the feature request here.
    validations:
      required: false


text:
name: email_when_close_pr

on:
  pull_request:
    types: [ closed ]

jobs:
  email_when_close_pr:
    runs-on: ubuntu-latest
    steps:
      - name: Get Pull Request Number
        run: |
          echo github.event.pull_request.number = ${{ github.event.pull_request.number }}
          echo github.event.pull_request.html_url = ${{ github.event.pull_request.html_url }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Get issues
        id: get-issues
        uses: mondeja/pr-linked-issues-action@v2
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Print linked issue numbers
        run: echo ${{ steps.get-issues.outputs.issues }}

      - name: get email
        id: test
        uses: evvanErb/get-github-email-by-username-action@v1.25
        with:
          github-username: ${{ github.triggering_actor }}

      # send an email; cannot figure out how to get correct url to PR even just pasting in the link
      - name: send email
        uses: cinotify/github-action@main
        if: ${{ steps.get-issues.outputs.issues != null }}
        with:
          to: ${{ steps.test.outputs.email }}
          subject: 'PR in stock synthesis repository is closed; reminder to fill out info in associated issue'
          body: "PR #${{ github.event.pull_request.number }} in the nmfs-stock-synthesis/stock-synthesis repository has been closed, please remember to move any pertinent information to the following linked issue(s): #${{ steps.get-issues.outputs.issues }}"


text:
# Build stock synthesis with all c++ compiler warnings, and fail job if the
# number of warnings has increased.
name: build-ss3-warnings

# Controls when the action will run.
on:
  workflow_dispatch:
  push:
    paths:
      - '**.tpl'
    branches:
      - main
  pull_request:
    paths:
      - '**.tpl'
    branches:
      - main

jobs:
  build-warnings:
    runs-on: ubuntu-latest
    env:
      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
      RSPM: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"

    steps:
      - name: Checkout ss repo
        uses: actions/checkout@v3

      - name: Update Ubuntu packages
        run: sudo apt-get update

      - name: setup R
        uses: r-lib/actions/setup-r@v2

      - name: Get admb and put in path, linux
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Build stock synthesis with warnings displayed in console
        run: |
          rm -rf SS330
          rm -rf ss_osx.tar
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -a /usr/local/bin/admb-13.1 -b SS330 -w

      - name: Build stock synthesis with warnings again to save to file
        run: |
          rm -rf SS330
          rm -rf ss_osx.tar
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -a /usr/local/bin/admb-13.1 -b SS330 -w &> warnings.txt

      # Runs a set of commands using the runners shell
      - name: Use R to parse warnings output
        run: |
          txt <- readLines("warnings.txt", encoding = "UTF-8" )
          warn_line <- grep(pattern = "compiling a second time to get warnings",
            x = txt,
            fixed = TRUE)
          txt <- txt[(warn_line+1):length(txt)]
          rm_warn_start_lines <- grep(pattern = "/usr/local/bin/admb-13.1", x = txt,
            fixed = TRUE)
          all_warning_end_lines <- grep(pattern = "^", x = txt, fixed = TRUE)
          to_rm <- NULL
          for (l in rm_warn_start_lines) {
            tmp_end_line <- min(all_warning_end_lines[all_warning_end_lines > l])
            to_rm <- c(to_rm, l:tmp_end_line)
          }
          txt <- txt[-to_rm]
          n_errors <- length(grep(pattern = "^", x = txt, fixed = TRUE))
          message("There are ", n_errors, " warning messages related to SS.")
          write.table(n_errors, "n_warn.txt")
          writeLines(txt, "warnings_ss.txt")
        shell: Rscript {0}

      - name:  Print warnings
        run: cat warnings_ss.txt

      - name: determine if fails/passes
        run: |
          n_warn <- read.table("n_warn.txt")
          n_warn <- as.integer(n_warn[1,1])
          if (n_warn > 68) {
            stop("Increased number of warnings")
          } else {
            message("Acceptable number of warnings")
          }
        shell: Rscript {0}

      - name: Archive warnings text file
        if: always()
        uses: actions/upload-artifact@main
        with:
          name: 'warnings_ss.txt'
          path: warnings_ss.txt


text:
# Opens issues to r4ss, SSI, and doc repos when changes occur in SS3.
name: ss3-pr-open-issues.yml
on:
  pull_request:
    types: [opened]
#  pull_request_target:
#    types:
#      - closed
jobs:
  ss3-pr-open-issues:
    runs-on: ubuntu-latest
    env:
      GITHUB_PAT: ${{ secrets.GH_PAT }}
    #if: github.event.pull_request.merged == true
    steps:
      - uses: actions/checkout@v3
      - uses: r-lib/actions/setup-r@v2
        with:
          use-public-rspm: true
      - name: install the gh pkg
        run: install.packages("gh")
        shell: Rscript {0}
      - name: Get pr info and save
        run: |
          Rscript -e 'info <- gh::gh("GET /repos/{owner}/{repo}/pulls/{pull_number}",
            owner = "nmfs-stock-synthesis",
            repo = "stock-synthesis",
            pull_number = "${{ github.event.pull_request.number }}")
          saveRDS(info, file = "info.RDS")'
      - name: Post issues, if needed
        run: |
          info <- readRDS("info.RDS")
          pr_body  <- strsplit(info$body, "\n" )[[1]]
          pr_body <- gsub("\r", "",  pr_body, fixed = TRUE)
          # Get info on which repos need open issues, if a change log entry is needed.
          # allow some flexibility for getting the spacing wrong, which is easy to do.
          # look for checklist items like - []
          needs_changes <- grep("-\\s*\\[\\s*\\]", pr_body, ignore.case = TRUE, value = TRUE)
          issue_title <- paste0("Changes need for SS3 PR ",  info$number)
          issue_body <- paste0("Changes will be needed in this ",
            "repository due to the opening of SS3 Pull Request ",
            info$number, ".\n",
            "Please see ",
            "https://github.com/nmfs-stock-synthesis/stock-synthesis/pull/",
            info$number, " and its associated issues for more information.",
            "\n\nNote: this issue was created automatically via GitHub ",
            "Action using the workflow in \n",
            "https://github.com/nmfs-stock-synthesis/stock-synthesis/blob/main/.github/workflows/ss3-pr-open-issues.yml")
          # post r4ss issue if needed
          if (length(grep("r4ss", needs_changes)) == 1) {
            gh::gh("POST /repos/{owner}/{repo}/issues",
             owner = "r4ss",
             repo = "r4ss",
             title = issue_title,
             body = issue_body)
          }
          # post SSI issue if needed
          if (length(grep("SSI", needs_changes)) == 1) {
                      gh::gh("POST /repos/{owner}/{repo}/issues",
             owner = "nmfs-stock-synthesis",
             repo = "ssi",
             title = issue_title,
             body = issue_body)
          }
          # post documentation issue, if needed
          if (length(grep("manual", needs_changes)) == 1) {
            gh::gh("POST /repos/{owner}/{repo}/issues",
             owner = "nmfs-stock-synthesis",
             repo = "doc",
             title = issue_title,
             body = issue_body)
          }
        shell: Rscript {0}


text:
# Build SS3 and run models without estimation (from .par) and no hessian
name: run-ss3-no-est
on:
  workflow_dispatch:
  push:
    paths:
      - '**.tpl'
    branches:
      - main
  pull_request:
    paths:
      - '**.tpl'
    branches:
      - main

# run models without estimation, then try to run again with .ss_new
jobs:
  run-ss3-no-est:
    runs-on: ubuntu-latest
    env:
      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
      RSPM: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"

    steps:
      - name: Checkout ss repo
        uses: actions/checkout@v3

 #     - name: Get last compiled version of SS; alternative to compiling in same wkflow
 #       uses: dawidd6/action-download-artifact@v2
 #       with:
 #         workflow: build-centos.yml
 #         workflow_conclusion: success
 #         name: ss_linux
 #         path: ss_linux

      - name: Checkout models repo
        uses: actions/checkout@v3
        with:
          repository: 'nmfs-stock-synthesis/test-models'
          path: test-models-repo

      - name: Update Ubuntu packages
        run: sudo apt-get update

      - name: setup R
        uses: r-lib/actions/setup-r@v2

      - name: Get admb and put in path, linux
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Build stock synthesis
        run: |
          rm -rf SS330
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330

      - name: move exes, scripts to needed locations
        run: |
          mv test-models-repo/models test-models-repo/model_runs
          mv SS330/ss test-models-repo/model_runs/ss
          mv test-models-repo/.github/r_scripts/run_from_par.R test-models-repo/run_from_par.R
          mv test-models-repo/.github/r_scripts/run_compare_noest.R test-models-repo/run_compare_noest.R

      - name: change permissions on ss exes
        run: chmod a+x test-models-repo/model_runs/ss

      - name: run models without estimation
        run: |
         cd test-models-repo && Rscript run_from_par.R

      - name: Run comparison
        run: |
          mkdir test-models-repo/run_R
          cd test-models-repo && Rscript run_compare_noest.R

      - name: Determine results of test
        run: cd test-models-repo && Rscript .github/r_scripts/check_failed.R

      - name: Run .ss_new
        run: |
          # code to run the ss_new models
          mod_names <- list.dirs("test-models-repo/model_runs",
            full.names = FALSE, recursive = FALSE)
          mod_paths <- list.dirs("test-models-repo/model_runs",
            full.names = TRUE, recursive = FALSE)
          print(mod_names)

          run_ssnew <- function(dir) {
            wd <- getwd()
            print(wd)
            on.exit(system(paste0("cd ", wd)))
            # delete old starter files, rename forecast.ss_new and starter.ss_new files
            file.remove(file.path(dir, "starter.ss"))
            file.remove(file.path("forecast.ss"))
            file.rename(file.path(dir, "starter.ss_new"), file.path(dir,"starter.ss"))
            file.rename(file.path(dir, "forecast.ss_new"), file.path(dir,"forecast.ss"))
            # rename control and data files to standardized names (from the starter files)
            start <- readLines(file.path(dir, "starter.ss"))
            first_val_line <- grep("0=use init values in control file", start, fixed = TRUE)
            datname <- start[first_val_line-2]
            ctlname <- start[first_val_line-1]
            print(datname)
            print(ctlname)
            file.remove(file.path(dir, datname))
            file.remove(file.path(dir, ctlname))
            file.rename(file.path(dir,"data_echo.ss_new"), file.path(dir, datname))
            file.rename(file.path(dir, "control.ss_new"), file.path(dir, ctlname))
            # run the models without estimation
            file.remove(file.path(dir, "Report.sso"))
            # see if model finishes without error
            system(paste0("cd ", dir, " && ../ss -stopph 0 -nohess")) # may need to change path to ss exe
            model_ran <- file.exists(file.path(dir, "control.ss_new"))
            return(model_ran)
          }

          mod_ran <- lapply(mod_paths, function(x) tryCatch(run_ssnew(x),
                                                 error = function(e) print(e)
                                                 )
                     )
          mod_errors <- mod_names[unlist(lapply(mod_ran, function(x) "simpleError" %in% class(x)))]
          success <- TRUE
          if(length(mod_errors) > 0) {
            message("Model code with errors were: ", paste0(mod_errors, collapse = ", "),
                    ". See error list above for more details.")
            success <- FALSE
          } else {
            message("All code ran without error, but model runs may still have failed.")
          }
          mod_no_run <- mod_names[unlist(lapply(mod_ran, function(x) isFALSE(x)))] #false means model didn't run
          if(length(mod_no_run) > 0) {
            message("Models that didn't run are ", paste0(mod_no_run, collapse = ", "))
            success <- FALSE
          } else {
            message("All models ran without error.")
          }

          # determine if job fails or passes
          if(success == FALSE) {
            stop("Job failed due to code with errors or models that didn't run.")
          } else {
            message("Job passed! All models successfully ran.")
          }
        shell: Rscript {0}

      - name: Archive results
        uses: actions/upload-artifact@main
        if: always()
        with:
          name: 'result_textfiles'
          path: test-models-repo/run_R/


text:
# Check that the NUTS algorithim in ADMB is reproducible with SS3.
# Developed with Cole Monnahan.
name: run-ss3-mcmc
on:
  workflow_dispatch:
  push:
    paths:
      - '**.tpl'
    branches:
      - main
  pull_request:
    paths:
      - '**.tpl'
    branches:
      - main

# Check mcmc works
jobs:
  run-ss3-no-est:
    runs-on: ubuntu-latest
    env:
      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
      RSPM: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"

    steps:
      - name: Checkout ss repo
        uses: actions/checkout@v3

      - name: Checkout models repo
        uses: actions/checkout@v3
        with:
          repository: 'nmfs-stock-synthesis/test-models'
          path: test-models-repo

      - name: Update Ubuntu packages
        run: sudo apt-get update

      - name: setup R
        uses: r-lib/actions/setup-r@v2

      - name: Get admb and put in path, linux
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Build stock synthesis
        run: |
          rm -rf SS330
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330

      - name: move exes, scripts to needed locations
        run: |
          mv test-models-repo/models/Simple/starter.ss starter.ss
          mv test-models-repo/models/Simple/forecast.ss forecast.ss
          mv test-models-repo/models/Simple/control.ss control.ss
          mv test-models-repo/models/Simple/data.ss data.ss
          mv SS330/ss ss
          ls

      - name: change permissions on ss exe
        run: chmod a+x ss

      - name: run models without estimation
        run: |
          # Run NUTS algorithim in ADMB to make sure still works with stock synthesis
          # run the simple model with -hbf option to get the necessary files
          system("./ss -hbf")
          # run the simple model 30 times using the NUTS algorithim
          niters <- 100
          for (i in 1:niters) {
            message("Running iteration ", i)
            # run simple model
            system("./ss  -maxfn 0 -phase 40 -nohess -mcmc 10 -nuts -mcseed 1 -max_treedepth 3")
            # read in adaption.csv
            adapt_df <- read.csv("adaptation.csv")
            if(i == 1) {
              compare_val <- adapt_df[nrow(adapt_df), "stepsize__"]
              message("Getting ref value from iteration ", i, ". Ref value is " ,
                      compare_val)
            } else {
              message("Checking iteration ", i)
              val_to_check <- adapt_df[nrow(adapt_df), "stepsize__"]
            	if(!identical(val_to_check, compare_val)) {
                stop("First step size for iteration ", i ," (step size =",
                     val_to_check,
                     ")", " was not equal to values in the first iteration (",
                     compare_val, ").")
            	}
            }
          }
          message("No differences in step size among stock synthesis runs.")
        shell: Rscript {0}


text:
# Check that SS_output and SS_plots run with changes in ss3.
name: test-r4ss-with-ss3
on:
  workflow_dispatch:
  push:
    paths:
      - '**.tpl'
    branches:
      - main
  pull_request:
    paths:
      - '**.tpl'
    branches:
      - main

# run models without estimation, then run r4ss SS_plots and SS_output
jobs:
  test-r4ss-with-ss3:
    runs-on: ubuntu-latest
    env:
      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
      R_KEEP_PKG_SOURCE: yes

    steps:
      - name: Checkout ss repo
        uses: actions/checkout@v3

      - name: Checkout models repo
        uses: actions/checkout@v3
        with:
          repository: 'nmfs-stock-synthesis/test-models'
          path: test-models-repo

      - name: install libcurl
        run: |
          sudo apt-get update
          sudo apt-get install -y libcurl4-openssl-dev

      - name: setup R
        uses: r-lib/actions/setup-r@v2

      - name: install remotes
        run: Rscript -e 'install.packages("remotes")'

      - name: install r4ss
        run: Rscript -e 'remotes::install_github("r4ss/r4ss")'

      - name: Get admb and put in path, linux
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Build stock synthesis
        run: |
          rm -rf SS330
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330

      - name: move exes, scripts to needed locations
        run: |
          mv test-models-repo/models test-models-repo/model_runs
          mv SS330/ss test-models-repo/model_runs/ss
          mv test-models-repo/.github/r_scripts/run_from_par.R test-models-repo/run_from_par.R
          mv test-models-repo/.github/r_scripts/run_compare_noest.R test-models-repo/run_compare_noest.R

      - name: change permissions on ss exes
        run: chmod a+x test-models-repo/model_runs/ss

      - name: run models without estimation
        run: |
         cd test-models-repo && Rscript run_from_par.R

      - name: run SS output and SS plots
        run: |
          mod_names <- list.dirs("test-models-repo/model_runs", full.names = FALSE, recursive = FALSE)
          print(mod_names)
          if(length(mod_names) == 0) {
            stop("Did not r4ss on any models; perhaps path to models is not correct?")
          }

          out <- lapply(mod_names, function(i) {
            tryCatch(r4ss::SS_output(file.path("test-models-repo", "model_runs", i),
                                     verbose = FALSE, hidewarn = TRUE, printstats = FALSE),
                     error = function(e) {
                       print(e)
                     }
             )
           })

          plots <- lapply(out, function(x) {
            tryCatch(r4ss::SS_plots(x, verbose = FALSE, openfile = FALSE),
          			   error = function(e) {
          			 print(e)
          			   })
            })

          # determine if job fails or not
          out_issues <- mod_names[unlist(lapply(out, function(x) "error" %in% class(x)))]
          plotting_issues<- mod_names[unlist(lapply(plots, function(x) "error" %in% class(x)))]

          if(length(out_issues) == 0 & length(plotting_issues) == 0) {
            message("all r4ss functions completed successfully")
          } else {
            message("There were some errors. SS_output failed to run for model_runs ",
                    paste0(out_issues, collapse = ", "), "; SS_plots failed to run for ",
                    "models ", paste0(plotting_issues, collapse = " ,"), ". More info ",
                    "below.")
            message("Problems with SS_output:")
            for(i in out_issues) {
              message(i)
              tmp_loc <- which(mod_names == i)
              print(out[[tmp_loc]])
            }
            for(p in plotting_issues) {
              message(p)
              tmp_loc <- which(mod_names == p)
              print(plots[[tmp_loc]])
            }
            q(status = 1)
          }
        shell: Rscript {0}

# could archive files, but the archive will be large, so may not be worth it.


text:
# Build SS3 and run models with estimation and hessian
name: run-ss3-with-est
on:
  workflow_dispatch:
  push:
    paths:
      - '**.tpl'
    branches:
      - main
  pull_request:
    paths:
      - '**.tpl'
    branches:
      - main

# run fast running SS models with estimation
jobs:
  run-ss3-with-est:
    runs-on: ubuntu-latest
    env:
      R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
      RSPM: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"

    steps:
      - name: Checkout ss repo
        uses: actions/checkout@v3

      - name: Checkout models repo
        uses: actions/checkout@v3
        with:
          repository: 'nmfs-stock-synthesis/test-models'
          path: test-models-repo

      - name: setup R
        uses: r-lib/actions/setup-r@v2

      - name: Get admb and put in path, linux
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Build stock synthesis
        run: |
          rm -rf SS330
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330

      - name: move exes, scripts to needed locations
        run: |
          mv test-models-repo/models test-models-repo/model_runs
          mv SS330/ss test-models-repo/model_runs/ss

      - name: change permissions on ss exes
        run: chmod a+x test-models-repo/model_runs/ss

      - name: run models
        run: |
          mod_names <- list.dirs(file.path("test-models-repo", "model_runs"), full.names = FALSE, recursive = FALSE)
          mod_paths <- list.dirs(file.path("test-models-repo", "model_runs"), full.names = TRUE, recursive = FALSE)
          print(mod_names)
          run_ss <- function(dir) {
            wd <- getwd()
            print(wd)
            on.exit(system(paste0("cd ", wd)))
            # rename the reference files
            file.rename(file.path(dir, "ss_summary.sso"),
                        file.path(dir, "ss_summary_ref.sso"))
            file.rename(file.path(dir, "warning.sso"),
                        file.path(dir, "warning_ref.sso"))
            file.copy(file.path(dir, "ss.par"), file.path(dir, "ss_ref.par"))
            # run the models with estimation and see if model finishes without error
            message("running ss on ", basename(dir))
            system(paste0("cd ", dir, " && ../ss -nox"))
            model_ran <- file.exists(file.path(dir, "control.ss_new"))
            return(model_ran)
          }

          mod_ran <- lapply(mod_paths, function(x) tryCatch(run_ss(x),
                                                   error = function(e) print(e)
                                                   ))
          mod_errors <- mod_names[unlist(lapply(mod_ran, function(x) "simpleError" %in% class(x)))]
          success <- TRUE
          if(length(mod_errors) > 0) {
            message("Model code with errors were: ", paste0(mod_errors, collapse = ", "),
                    ". See error list above for more details.")
            success <- FALSE
          } else {
            message("All code ran without error, but model runs may still have failed.")
          }
          mod_no_run <- mod_names[unlist(lapply(mod_ran, function(x) isFALSE(x)))] # false means model didn't run
          if(length(mod_no_run) > 0) {
            message("Models that didn't run are ", paste0(mod_no_run, collapse = ", "))
            success <- FALSE
          } else {
            message("All models ran without error.")
          }
          # determine if job fails or passes
          if(success == FALSE) {
            stop("Job failed due to code with errors or models that didn't run.")
          } else {
            message("All models successfully ran.")
          }
        shell: Rscript {0}

      - name: Run comparison
        run: |
          source("test-models-repo/.github/r_scripts/compare.R")
          orig_wd <- getwd()
          setwd("test-models-repo")
          on.exit(orig_wd)
          dir.create("run_R")
          # get model folder names
          mod_fold <- file.path("model_runs")
          mod_names <- list.dirs(mod_fold, full.names = FALSE, recursive = FALSE)
          message("Will compare ref runs to new results for these models:")
          print(mod_names)
          message("Notable changes in total likelihood, max gradients, ",
                  " and number of warnings:")
          compare_list <- vector(mode = "list", length = length(mod_names))
          for(i in mod_names) {
            pos <- which(mod_names == i)
            sum_file <- file.path(mod_fold, i, "ss_summary.sso")
            if (i == "Simple") {
              file.copy(sum_file, file.path("run_R", paste0(i, "_ss_summary.sso")))
            }
            ref_sum_file <- file.path(mod_fold, i, "ss_summary_ref.sso")

            par_file <- file.path(mod_fold, i, "ss.par")
            ref_par_file <- file.path(mod_fold, i, "ss_ref.par")

            warn_file <- file.path(mod_fold, i, "warning.sso")
            ref_warn_file <- file.path(mod_fold, i, "warning_ref.sso")

            fail_file <- file.path("run_R", "test_failed.csv")

            compare_list[[pos]] <- compare_ss_runs(mod_name = i,
                          sum_file = sum_file, ref_sum_file = ref_sum_file,
                          par_file = par_file, ref_par_file = ref_par_file,
                          warn_file = warn_file, ref_warn_file = ref_warn_file,
                          hessian = TRUE,
                          new_file = NULL, fail_file = fail_file)
          }
          # write out all model results
          compare_df <- do.call("rbind", compare_list)
          compare_df_print <- format(compare_df, digits = 6, nsmall = 3,
                                   justify = "left")
          message("see saved artifact all_results.csv for all compared values and their differences.")
          # write all model comparison results to csv
          write.csv(compare_df_print, "run_R/all_results.csv", row.names = FALSE)
          # write all
          message("see saved artifact all_changes.csv for only changed values (even if the threshold was too low to fail the job)")
          filtered_df <- compare_df[compare_df$diff != 0, ]
          filtered_df <- format(filtered_df, digits = 6, nsmall = 3,
                                   justify = "left")
          write.csv(filtered_df, "run_R/all_changes.csv", row.names = FALSE)
        shell: Rscript {0}

      - name: Determine results of test
        run: cd test-models-repo && Rscript .github/r_scripts/check_failed.R

      - name: Archive results
        uses: actions/upload-artifact@main
        if: always()
        with:
          name: 'result_textfiles'
          path: test-models-repo/run_R/


text:
# Builds the stock synthesis executables for testing and distribution.
# for mac, linux, windows
name: build-ss3

on:
    push:
      paths:
      - '**.tpl'
      - '**.sh'
    workflow_dispatch:

jobs:
  build-ss3:
    runs-on: ${{ matrix.config.os }}
    name: ${{ matrix.config.os }}
    strategy:
      fail-fast: false
      matrix:
        config:
          - {os: windows-latest}
          - {os: macos-latest}
          - {os: ubuntu-latest}
    # Limit run time to 90 min to avoid wasting action minutes.
    # was set to 15 and then 30 minutes previously, but compiling admb
    # on mac took too long
    timeout-minutes: 90
    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3

      - name: Update Ubuntu packages
        if: matrix.config.os == 'ubuntu-latest'
        run: sudo apt-get update

      - name: Get admb and put in path, windows
        if: matrix.config.os == 'windows-latest'
        run: |
          Invoke-WebRequest -Uri https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-windows.zip -OutFile "D:\a\stock-synthesis\stock-synthesis\admb-13.1.zip"
          Expand-Archive -LiteralPath "D:\a\stock-synthesis\stock-synthesis\admb-13.1.zip" -DestinationPath "D:\a\stock-synthesis\stock-synthesis\"
          echo "D:\a\stock-synthesis\stock-synthesis\admb-13.1\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append

      - name: checkout admb, mac
        if: matrix.config.os == 'macos-latest'
        uses: actions/checkout@v3
        with:
          repository: admb-project/admb
          path: admb
          ref: admb-13.1
      - name: clean, mac
        if: matrix.config.os == 'macos-latest'
        run: cd admb && make clean
      - name: see where admb is, mac
        if: matrix.config.os == 'macos-latest'
        run: |
          ls
          cd admb && ls
      - name: compile admb, mac
        if: matrix.config.os == 'macos-latest'
        run: |
          cd admb && make
      - name: see where admb is, mac
        if: matrix.config.os == 'macos-latest'
        run: |
          cd admb && ls -l
      - name: put admb in path, mac
        if: matrix.config.os == 'macos-latest'
        run: |
          sudo mv admb /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb
          echo "/usr/local/bin/admb" >> $GITHUB_PATH

      - name: Get admb and put in path, linux
        if: matrix.config.os == 'ubuntu-latest'
        run: |
          wget https://github.com/admb-project/admb/releases/download/admb-13.1/admb-13.1-linux.zip
          sudo unzip admb-13.1-linux.zip -d /usr/local/bin
          sudo chmod 755 /usr/local/bin/admb-13.1/bin/admb
          echo "/usr/local/bin/admb-13.1/bin" >> $GITHUB_PATH

      - name: Set up R
        uses: r-lib/actions/setup-r@v2

      - name: get info on gcc version and path
        if: matrix.config.os == 'windows-latest'
        run: |
          g++ -v
          echo $env:GITHUB_PATH

      - name: Fetch tags
        run: |
          git fetch --tags
          git fetch --prune --unshallow || true

      - name: Get the last tag on windows
        id: get-latest-tag-win
        if: matrix.config.os == 'windows-latest'
        run: |
          git tag
          $latest_tag = (git describe --abbrev=0 --tags)
          $latest_tag_commit = ( git rev-list -n 1 $latest_tag)
          $latest_commit = (git rev-list HEAD -n 1)
          echo "tag=${latest_tag}" >> $env:GITHUB_OUTPUT
          echo "tag_commit=${latest_tag_commit}" >> $env:GITHUB_OUTPUT
          echo "commit=${latest_commit}" >> $env:GITHUB_OUTPUT

       # uses: actions-ecosystem/action-get-latest-tag@v1 # for linux

      - name: pull the last tag value to use in the Rscript on windows
        id: get-version-win
        if: matrix.config.os == 'windows-latest'
        run: |
          Out-File -InputObject ${{ steps.get-latest-tag-win.outputs.tag }} -FilePath .github/last_tag.txt
          Out-File -InputObject ${{ steps.get-latest-tag-win.outputs.tag_commit }} -FilePath .github/last_tag_commit.txt
          Out-File -InputObject ${{ steps.get-latest-tag-win.outputs.commit}} -FilePath .github/last_commit.txt

      - name: Get the last tag on unix
        id: get-latest-tag-unix
        if: matrix.config.os == 'macos-latest' || matrix.config.os == 'ubuntu-latest'
        run: |
          git tag
          latest_tag=$(git describe --abbrev=0 --tags)
          latest_tag_commit=$(git rev-list -n 1 $latest_tag)
          latest_commit=$(git rev-list HEAD -n 1)
          echo "tag=${latest_tag}" >> $GITHUB_OUTPUT
          echo "tag_commit=${latest_tag_commit}" >> $GITHUB_OUTPUT
          echo "commit=${latest_commit}" >> $GITHUB_OUTPUT

       # uses: actions-ecosystem/action-get-latest-tag@v1 # for linux

      - name: pull the last tag value to use in the Rscript on unix
        id: get-version-unix
        if: matrix.config.os == 'macos-latest' || matrix.config.os == 'ubuntu-latest'
        run: |
          echo "${{ steps.get-latest-tag-unix.outputs.tag }}" > .github/last_tag.txt
          echo "${{ steps.get-latest-tag-unix.outputs.tag_commit }}" > .github/last_tag_commit.txt
          echo "${{ steps.get-latest-tag-unix.outputs.commit }}" >  .github/last_commit.txt

      - name: Edit the version info for safe version using R code
        run: |
          # Get the version
          # get the last tag from the repository
          tag_label <- readLines(".github/last_tag.txt")
          # get commits from from the repository
          tag_commit <- readLines(".github/last_tag_commit.txt")
          last_commit <- readLines(".github/last_commit.txt")
          message("The tag_label is ", tag_label)
          if (substr(tag_label, start = 1, stop = 6) == "v3.30.") {
            ver_num_full <- strsplit(tag_label, split = "v3.30", fixed = TRUE)[[1]][2]
            ver_num <- strsplit(ver_num_full, split = ".", fixed = TRUE)[[1]][2]
            if(length(grep("-", ver_num)) > 0) {
              ver_num <- strsplit(ver_num, split = "-", fixed = TRUE)[[1]][1]
            }
          } else {
            ver_num <- "unknown"
          }
          message("tag commit: ", tag_commit)
          message("last  commit: ", last_commit)
          if(tag_commit == last_commit) {
            # figure out the version using the tag
            if(ver_num == "unknown") {
            fix_ver_num <- "unknown"
            } else {
              ver_num_full_split <- strsplit(ver_num_full, split = ".", fixed = TRUE)[[1]]
              if(length(ver_num_full_split) == 3) {
                fix_ver_num <- ver_num_full_split[3]
              } else if(length(ver_num_full_split) == 2) {
                if(length(grep("-", ver_num_full_split, fixed = TRUE)) > 0) {
                  fix_ver_num <- strsplit(ver_num_full_split[2], split = "-", fixed = TRUE)[[1]][2]
                  fix_ver_num <- paste0("00-", fix_ver_num)
                } else {
                  fix_ver_num <- "00"
                }
              } else {
                fix_ver_num <- "unknown"
              }
            }
          } else {
           fix_ver_num <- "beta: not an official version of SS"
          }
          message("The minor version label is ", ver_num)
          message("The patch version label is ", fix_ver_num)

          # add version numbers to files
          # safe file
          ver_info <- readLines("SS_versioninfo_330safe.tpl")
          ver_info_start <- grep('Create string with version info', ver_info, fixed = TRUE)
          ver_info[ver_info_start + 1] <-
            gsub('\\.xx', paste0('\\.', ver_num), ver_info[ver_info_start + 1])
          ver_info[ver_info_start + 1] <-
            gsub('\\.yy', paste0('\\.', fix_ver_num), ver_info[ver_info_start+1])
          writeLines(ver_info, "SS_versioninfo_330safe.tpl")
          #opt file
          ver_info <- readLines("SS_versioninfo_330opt.tpl")
          ver_info_start <- grep('Create string with version info', ver_info, fixed = TRUE)
          ver_info[ver_info_start + 1] <-
            gsub('\\.xx', paste0('\\.', ver_num), ver_info[ver_info_start + 1])
          ver_info[ver_info_start + 1] <-
            gsub('\\.yy', paste0('\\.', fix_ver_num), ver_info[ver_info_start+1])
          writeLines(ver_info, "SS_versioninfo_330opt.tpl")
        shell: Rscript {0}

      - name: Build stock synthesis for windows
        if: matrix.config.os == 'windows-latest'
        run: |
          cd Compile
          ./Make_SS_safe.bat
          ./Make_SS_fast.bat

      - name: Move exes to a new folder on windows
        if: matrix.config.os == 'windows-latest'
        run: |
          mkdir SS330
          mv Compile/ss.exe SS330/
          mv Compile/ss_opt.exe SS330/
          mv SS330/ss.exe SS330/ss_win.exe
          mv SS330/ss_opt.exe SS330/ss_opt_win.exe

      - name: Build stock synthesis for mac
        if: matrix.config.os == 'macos-latest'
        run: |
          rm -rf SS330
          rm -rf ss_osx.tar
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330 -o

      - name: Build stock synthesis for linux with p flag
        if:  matrix.config.os == 'ubuntu-latest'
        run: |
          rm -rf SS330
          rm -rf ss_osx.tar
          mkdir SS330
          /bin/bash ./Make_SS_330_new.sh -b SS330 -p
          /bin/bash ./Make_SS_330_new.sh -b SS330 -o -p

      - name: Verify binary on mac
        if: matrix.config.os == 'macos-latest'
        run: |
          shasum -a 256 SS330/ss
          shasum -a 256 SS330/ss_opt

      - name: Delete unneeded files and change exe names on mac
        if: matrix.config.os == 'macos-latest'
        run: |
          cd SS330
          rm *.obj *.htp *.cpp ss_opt.tpl
          mv ss ss_osx
          mv ss_opt ss_opt_osx

      - name: Verify binary on linux
        if: matrix.config.os == 'ubuntu-latest'
        run: |
          sha256sum SS330/ss
          sha256sum SS330/ss_opt

      - name: Delete unneeded files and change exe names on linux
        if: matrix.config.os == 'ubuntu-latest'
        run: |
          cd SS330
          rm *.obj *.htp *.cpp ss_opt.tpl ss.tpl
          mv ss ss_linux
          mv ss_opt ss_opt_linux

      - name: Archive binaries
        if: success()
        uses: actions/upload-artifact@main
        with:
          name: 'ss3'
          path: SS330/