// @title find the interval 
//
// @description this function is a form of binary search that finds the first 
// occurrence of a value greater than or equal to t in the sorted vector xt. 
// If t is greater than all elements in xt, it returns the last index. 
// If t is less than all elements in xt, it returns 0.
int findfirst(real t, vector xt) {
  int i = 0 ;
  if(t == max(xt)){
    i = num_elements(xt) - 1 ;
    return i ;
  } else if(t < min(xt) || t > max(xt)){
    return i ;
  } else {
    while (t >= xt[i+1]){
      i = i+1 ;
    }
    return i ;
  }
}

// @title linear interpolation with 0.0 at extrapolation
//
// @description linear interpolation at x according to value of (xpt, ypt)
// when x is lower than min of xpt or upper than the max of xpt, then 0.0 is
// returned
//
// @param x float on which interpolating y
// @param xpt vector of float
// @patam ypt vector of float
real interpolate(real x, vector xpt, vector ypt){
  if(x >= min(xpt) && x <= max(xpt)){
    int idx = findfirst(x, xpt) ;
    return ypt[idx] + (x - xpt[idx]) * (ypt[idx+1] - ypt[idx]) / (xpt[idx+1] - xpt[idx]) ;
  } else{
    return 0.0 ;
  }
}

// @title linear interpolation with closest value at extrapolation
//
// @description linear interpolation at x according to value of (xpt, ypt)
// when x is lower than min of xpt, y is ypt at min(xpt), respectivelly, when
// x is upper than the max of xpt, then y is ypt at max(xpt)
//
// @param x float on which interpolating y
// @param xpt vector of float
// @param ypt vector of float
real interpolate_bound(real x, vector xpt, vector ypt){
  if(x >= min(xpt) && x <= max(xpt)){
    int idx = findfirst(x, xpt) ;
    return ypt[idx] + (x - xpt[idx]) * (ypt[idx+1] - ypt[idx]) / (xpt[idx+1] - xpt[idx]) ;
  } else if(x < min(xpt)){
    return ypt[1] ;
  } else {
      int last_idx = num_elements(xpt) ;
      return ypt[last_idx] ;
  }
}
