lib/openagents/capacity/math.ex

58e6347eeb72 · 1 KB

defmodule OpenAgents.Capacity.Math do
  @moduledoc false

  def quantities(class, evidence, config) do
    logical = integer_or_nil(evidence["logical"])
    active = integer_or_nil(evidence["active_reservations"])
    reported_free = integer_or_nil(evidence["reported_free"])
    observed = integer_or_nil(evidence["observed_limit"])
    budget_limit = integer_or_nil(evidence["budget_limit"])
    drain_limit = integer_or_nil(evidence["drain_limit"])
    ceiling = integer_or_nil(Keyword.get(config, :class_ceilings, %{})[class["id"]])
    fraction = Keyword.get(config, :reserved_headroom_fraction, 0.25)
    safety_headroom = if is_integer(observed), do: floor(observed * fraction), else: nil

    effective_limit =
      [ceiling, subtract(observed, safety_headroom), budget_limit, drain_limit]
      |> Enum.reject(&is_nil/1)
      |> case do
        [] -> nil
        values -> Enum.min(values)
      end

    limit_derived = subtract(effective_limit, active)

    allocatable =
      case {limit_derived, reported_free} do
        {nil, _} -> nil
        {derived, nil} -> max(derived, 0)
        {derived, free} -> max(min(derived, free), 0)
      end

    %{
      "logical" => logical,
      "active_reservations" => active,
      "allocatable" => allocatable,
      "queued" => integer_or_nil(evidence["queued"]),
      "safety_headroom" => safety_headroom,
      "configured_ceiling" => ceiling,
      "observed_limit" => observed
    }
  end

  defp subtract(nil, _value), do: nil
  defp subtract(value, nil), do: value
  defp subtract(value, other), do: value - other

  defp integer_or_nil(value) when is_integer(value) and value >= 0, do: value
  defp integer_or_nil(value) when is_float(value) and value >= 0, do: trunc(value)
  defp integer_or_nil(_value), do: nil
end