text: """
  ```
  one_draw(m::AbstractDSGEModel, data::Matrix{Float64}; use_chand_recursion::Bool = true,
           verbose::Symbol = :low)
  ```
  Finds and returns one valid draw from parameter distribution, along with its log likelihood and log posterior.
  """
  function one_draw(m::AbstractDSGEModel, data::Matrix{Float64};
                    use_chand_recursion::Bool = true, verbose::Symbol = :low)
      success    = false
      draw       = vec(rand(m.parameters, 1))
      draw_loglh = draw_logpost = 0.0
  
      while !success
          try
              update!(m, draw)
              draw_loglh = likelihood(m, data, catch_errors = true,
                                      use_chand_recursion = use_chand_recursion,
                                      verbose = verbose)
              draw_logpost = prior(m)
              if (draw_loglh == -Inf) | (draw_loglh === NaN)
                  draw_loglh = draw_logpost = -Inf
              end
          catch err
              if isa(err, ParamBoundsError)
                  draw_loglh = draw_logpost = -Inf
              elseif isa(err, PosDefException) || isa(err, SingularException) ||
                     isa(err, LinearAlgebra.LAPACKException) || isa(err, DSGE.SteadyStateConvergenceError)
                  draw_loglh = draw_logpost = -Inf
              else
                  throw(err)
              end
          end
          if any(isinf.(draw_loglh))
              draw = vec(rand(m.parameters, 1))
          else
              success = true
          end
      end
      return vector_reshape(draw, draw_loglh, draw_logpost)
  end
  
  """
  ```
  initial_draw!(m::AbstractDSGEModel, data::Matrix{Float64}, c::ParticleCloud)
  initial_draw!(m::AbstractDSGEModel, data::Matrix{Float64}, c::Cloud)
  ```
  
  Draw from a general starting distribution (set by default to be from the prior) to
  initialize the SMC algorithm. Returns a tuple (logpost, loglh) and modifies the
  particle objects in the particle cloud in place.
  """
  function initial_draw!(m::AbstractModel, data::Matrix{Float64},
                         c::Union{Cloud, ParticleCloud};
                         parallel::Bool = false, use_chand_recursion::Bool = true,
                         verbose::Symbol = :low)
      n_parts = length(c)
  
      # ================== Define closure on one_draw function ==================
      sendto(workers(), m = m)
      sendto(workers(), data = data)
      sendto(workers(), verbose = verbose)
      sendto(workers(), use_chand_recursion = use_chand_recursion)
  
      one_draw_closure() = one_draw(m, data; use_chand_recursion = use_chand_recursion,
                                    verbose = verbose)
      @everywhere one_draw_closure() = one_draw(m, data;
                                                use_chand_recursion = use_chand_recursion,
                                                verbose = verbose)
      # =========================================================================
  
      # For each particle, finds valid parameter draw and returns likelihood & posterior
      draws, loglh, logpost = if parallel
          @sync @distributed (vector_reduce) for i in 1:n_parts
              one_draw_closure()
          end
      else
          vector_reduce([one_draw_closure() for i in 1:n_parts]...)
      end
  
      update_draws!(c, draws)
      update_loglh!(c, vec(loglh))
      update_logpost!(c, vec(logpost))
      update_old_loglh!(c, zeros(n_parts))
      # Need to call `set_weights` as opposed to `update_weights`
      # since update_weights will multiply and 0*anything = 0
      set_weights!(c, ones(n_parts))
  end
  
  """
  ```
  function draw_likelihood(m, data, draw_vec; verbose::Symbol = :low)
  ```
  Computes likelihood of a particular parameter draw; returns loglh and logpost.
  """
  function draw_likelihood(m::AbstractDSGEModel, data::Matrix{Float64},
                           draw_vec::Vector{Float64}; verbose::Symbol = :low)
      update!(m, draw_vec)
      loglh   = likelihood(m, data, verbose = verbose)
      logpost = prior(m)
      return scalar_reshape(loglh, logpost)
  end
  
  """
  ```
  initialize_likelihoods!(m::AbstractDSGEModel, data::Matrix{Float64},
                          c::Union{Cloud, ParticleCloud};
                          parallel::Bool = false, verbose::Symbol = :low)
  ```
  This function is made for transfering the log-likelihood values saved in the
  Cloud from a previous estimation to each particle's respective old_loglh
  field, and for evaluating/saving the likelihood and posterior at the new data, which
  here is just the argument, data.
  """
  function initialize_likelihoods!(m::AbstractDSGEModel, data::Matrix{Float64},
                                   c::Union{Cloud, ParticleCloud};
                                   parallel::Bool = false, verbose::Symbol = :low)
      n_parts = length(c)
      draws = (typeof(c) <: Cloud) ? get_vals(c; transpose = false) : Matrix{Float64}(get_vals(c)')
  
      # Retire log-likelihood values from the old estimation to the field old_loglh
      update_old_loglh!(c, get_loglh(c))
  
      # ============== Define closure on draw_likelihood function ===============
      sendto(workers(), m = m)
      sendto(workers(), data = data)
      sendto(workers(), verbose = verbose)
  
      draw_likelihood_closure(draw::Vector{Float64}) = draw_likelihood(m, data, draw;
                                                                   verbose = verbose)
      @everywhere draw_likelihood_closure(draw::Vector{Float64}) = draw_likelihood(m, data,
                                                                   draw; verbose = verbose)
      # =========================================================================
  
      # TODO: handle when the likelihood with new data cannot be evaluated (returns -Inf),
      # even if the likelihood was not -Inf prior to incorporating new data
      loglh, logpost = if parallel
          @sync @distributed (scalar_reduce) for i in 1:n_parts
              draw_likelihood_closure(draws[i, :])
          end
      else
          scalar_reduce([draw_likelihood_closure(draws[i, :]) for i in 1:n_parts]...)
      end
      update_loglh!(c, loglh)
      update_logpost!(c, logpost)
  end
  
  """
  ```
  function initialize_cloud_settings!(m::AbstractDSGEModel, cloud::ParticleCloud;
                                      tempered_update::Bool = false)
  ```
  Initializes stage index, number of Φ stages, c, resamples, acceptance, and sampling time.
  """
  function initialize_cloud_settings!(m::AbstractDSGEModel,
                                      cloud::Union{ParticleCloud,Cloud};
                                      tempered_update::Bool = false)
      if tempered_update
          cloud.ESS = [cloud.ESS[end]]
      else
          cloud.ESS[1] = get_setting(m, :n_particles)
      end
      cloud.stage_index = 1
      cloud.n_Φ         = get_setting(m, :n_Φ)
      cloud.resamples   = 0
      cloud.c           = get_setting(m, :step_size_smc)
      cloud.accept      = get_setting(m, :target_accept)
      cloud.total_sampling_time = 0.
      cloud.tempering_schedule  = zeros(1)
  end
  