<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html

/* --- automation setup editor --- */
#include "bstprocedure.hh"

static GParamSpec*
param_automation_pspec_midi_channel()
{
  static GParamSpec *midi_channel_pspec =
    g_param_spec_ref_sink (sfi_pspec_int ("midi_channel", _("MIDI Channel"),
                                          _("The MIDI Channel from which automation events should be received, 0 designates the default MIDI channel"),
                                          0, 0, 99 /* FIXME: BSE_MIDI_MAX_CHANNELS */, 1, SFI_PARAM_STANDARD ":scale:unprepared"));
  return g_param_spec_ref (midi_channel_pspec);
}

static GParamSpec*
param_automation_pspec_control_type()
{
  static GParamSpec *control_type_pspec =
    g_param_spec_ref_sink (sfi_pspec_choice ("control_type", _("Control Type"),
                                             _("The type of control events used for automation"),
                                             Aida::enum_value_to_string (Bse::MidiControl::CONTINUOUS_16).c_str(),
                                             Bse::choice_values_from_enum<Bse::MidiControl>(),
                                             SFI_PARAM_STANDARD));
  return g_param_spec_ref (control_type_pspec);
}

static void
param_automation_dialog_cancel (GxkDialog *dialog)
{
  g_object_set_data ((GObject*) dialog, "beast-GxkParam", NULL);
  gxk_toplevel_delete (GTK_WIDGET (dialog));
}

static void
param_automation_dialog_ok (GxkDialog *dialog)
{
  GxkParam *param = (GxkParam*) g_object_get_data ((GObject*) dialog, "beast-GxkParam");
  g_object_set_data ((GObject*) dialog, "beast-GxkParam", NULL);
  if (param)
    {
      SfiProxy proxy = bst_param_get_proxy (param);
      GxkParam *param_channel = (GxkParam*) g_object_get_data ((GObject*) dialog, "GxkParam-automation-channel");
      GxkParam *param_control = (GxkParam*) g_object_get_data ((GObject*) dialog, "GxkParam-automation-control");
      gint midi_channel = sfi_value_get_int (&param_channel->value);
      Bse::MidiControl control_type = Aida::enum_value_from_string<Bse::MidiControl> (sfi_value_get_choice (&param_control->value));
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      source.set_automation (param->pspec->name, midi_channel, control_type);
    }
  gxk_toplevel_delete (GTK_WIDGET (dialog));
}

static void
param_automation_popup_editor (GtkWidget *widget,
                               GxkParam  *param)
{
  SfiProxy proxy = bst_param_get_proxy (param);
  if (proxy)
    {
      static GxkDialog *automation_dialog = NULL;
      if (!automation_dialog)
        {
          automation_dialog = (GxkDialog*) g_object_new (GXK_TYPE_DIALOG, NULL);
          /* configure dialog */
          g_object_set (automation_dialog,
                        "flags", (GXK_DIALOG_HIDE_ON_DELETE |
                                  GXK_DIALOG_PRESERVE_STATE |
                                  GXK_DIALOG_POPUP_POS |
                                  GXK_DIALOG_MODAL),
                        NULL);
          // gxk_dialog_set_sizes (automation_dialog, 550, 300, 600, 320);
          GtkBox *vbox = (GtkBox*) g_object_new (GTK_TYPE_VBOX, "visible", TRUE, "border-width", 5, NULL);
          /* setup parameter: midi_channel */
          GParamSpec *pspec = g_param_spec_ref (param_automation_pspec_midi_channel());
          GxkParam *dialog_param = bst_param_new_value (pspec, NULL, NULL);
          g_param_spec_unref (pspec);
          bst_param_create_gmask (dialog_param, NULL, GTK_WIDGET (vbox));
          g_object_set_data_full ((GObject*) automation_dialog, "GxkParam-automation-channel", dialog_param, (GDestroyNotify) gxk_param_destroy);
          /* setup parameter: control_type */
          pspec = g_param_spec_ref (param_automation_pspec_control_type());
          dialog_param = bst_param_new_value (pspec, NULL, NULL);
          g_param_spec_unref (pspec);
          bst_param_create_gmask (dialog_param, NULL, GTK_WIDGET (vbox));
          g_object_set_data_full ((GObject*) automation_dialog, "GxkParam-automation-control", dialog_param, (GDestroyNotify) gxk_param_destroy);
          /* dialog contents */
          gxk_dialog_set_child (GXK_DIALOG (automation_dialog), GTK_WIDGET (vbox));
          /* provide buttons */
          gxk_dialog_default_action_swapped (automation_dialog, BST_STOCK_OK, (void*) param_automation_dialog_ok, automation_dialog);
          gxk_dialog_action_swapped (automation_dialog, BST_STOCK_CANCEL, (void*) param_automation_dialog_cancel, automation_dialog);
        }
      g_object_set_data ((GObject*) automation_dialog, "beast-GxkParam", param);
      GxkParam *param_channel = (GxkParam*) g_object_get_data ((GObject*) automation_dialog, "GxkParam-automation-channel");
      GxkParam *param_control = (GxkParam*) g_object_get_data ((GObject*) automation_dialog, "GxkParam-automation-control");
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      sfi_value_set_int (&param_channel->value, source.get_automation_channel (param->pspec->name));
      Bse::MidiControl control_type = source.get_automation_control (param->pspec->name);
      sfi_value_set_choice (&param_control->value, Aida::enum_value_to_string (control_type).c_str());
      gxk_param_apply_value (param_channel); /* update model, auto updates GUI */
      gxk_param_apply_value (param_control); /* update model, auto updates GUI */
      g_object_set_data ((GObject*) widget, "GxkParam-automation-channel", param_channel);
      g_object_set_data ((GObject*) widget, "GxkParam-automation-control", param_control);
      /* setup for proxy */
      bst_window_sync_title_to_proxy (automation_dialog, proxy,
                                      /* TRANSLATORS: this is a dialog title and %s is replaced by an object name */
                                      _("Control Automation: %s"));
      /* cleanup connections to old parent_window */
      if (GTK_WINDOW (automation_dialog)->group)
        gtk_window_group_remove_window (GTK_WINDOW (automation_dialog)->group, GTK_WINDOW (automation_dialog));
      gtk_window_set_transient_for (GTK_WINDOW (automation_dialog), NULL);
      /* setup connections to new parent_window */
      GtkWindow *parent_window = (GtkWindow*) gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
      if (parent_window)
        {
          gtk_window_set_transient_for (GTK_WINDOW (automation_dialog), parent_window);
          if (parent_window->group)
            gtk_window_group_add_window (parent_window->group, GTK_WINDOW (automation_dialog));
        }
      gxk_widget_showraise (GTK_WIDGET (automation_dialog));
    }
}

static void
param_automation_unrequest_focus_space (GtkWidget      *button,  // GTKFIX: GtkButton requests focus space for !CAN_FOCUS
                                        GtkRequisition *requisition)
{
  gint focus_width = 0, focus_pad = 0;
  gtk_widget_style_get (button, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL);
  if (requisition->width > 2 * (focus_width + focus_pad) &&
      requisition->height > 2 * (focus_width + focus_pad))
    {
      requisition->width -= 2 * (focus_width + focus_pad);
      requisition->height -= 2 * (focus_width + focus_pad);
    }
}

static GtkWidget*
param_automation_create (GxkParam    *param,
                         const gchar *tooltip,
                         guint        variant)
{
  /* create fake-entry dialog-popup button */
  GtkWidget *widget = (GtkWidget*) g_object_new (GTK_TYPE_EVENT_BOX, NULL);
  gxk_widget_modify_normal_bg_as_base (widget);
  GtkWidget *button = (GtkWidget*) g_object_new (GTK_TYPE_BUTTON,
                                    "can-focus", 0,
                                    "parent", widget,
                                    NULL);
  gxk_widget_modify_normal_bg_as_base (button);
  g_object_connect (button, "signal_after::size-request", param_automation_unrequest_focus_space, button, NULL);
  GtkWidget *label = (GtkWidget*) g_object_new (GTK_TYPE_LABEL,
                                   "label", "88",
                                   "xpad", 2,
                                   "parent", button,
                                   NULL);
  gtk_widget_show_all (widget);
  /* store handles */
  g_object_set_data ((GObject*) widget, "beast-GxkParam", param);
  g_object_set_data ((GObject*) widget, "beast-GxkParam-label", label);
  /* connections */
  g_object_connect (button, "signal::clicked", param_automation_popup_editor, param, NULL);
  return widget;
}

static const SfiChoiceValue*
param_automation_find_choice_value (const gchar *choice,
                                    GParamSpec  *pspec)
{
  SfiChoiceValues cvalues = sfi_pspec_get_choice_values (pspec);
  guint i;
  for (i = 0; i < cvalues.n_values; i++)
    if (sfi_choice_match (cvalues.values[i].choice_ident, choice))
      return &cvalues.values[i];
  return NULL;
}

static void
param_automation_update (GxkParam  *param,
                         GtkWidget *widget)
{
  SfiProxy proxy = bst_param_get_proxy (param);
  gchar *content = NULL, *tip = NULL;
  if (proxy)
    {
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      const gchar *prefix = "";
      int midi_channel = source.get_automation_channel (param->pspec->name);
      Bse::MidiControl control_type = source.get_automation_control (param->pspec->name);
      GParamSpec *control_pspec = g_param_spec_ref (param_automation_pspec_control_type());
      const SfiChoiceValue *cv = param_automation_find_choice_value (Aida::enum_value_to_string (control_type).c_str(), control_pspec);
      g_param_spec_unref (control_pspec);
      if (control_type >= Bse::MidiControl::CONTINUOUS_0 && control_type <= Bse::MidiControl::CONTINUOUS_31)
        {
          prefix = "c";
          control_type = Bse::MidiControl (int64 (control_type) - int64 (Bse::MidiControl::CONTINUOUS_0));
        }
      else if (control_type >= Bse::MidiControl::CONTROL_0 && control_type <= Bse::MidiControl::CONTROL_127)
        control_type = Bse::MidiControl (int64 (control_type) - int64 (Bse::MidiControl::CONTROL_0));
      else if (control_type == Bse::MidiControl::NONE)
        control_type = Bse::MidiControl (-1);
      else
        control_type = Bse::MidiControl (int64 (control_type) + 10000); /* shouldn't happen */
      if (int64 (control_type) < 0)     /* none */
        {
          content = g_strdup ("--");
          /* TRANSLATORS: %s is substituted with a property name */
          tip = g_strdup_format (_("%s: automation disabled"), g_param_spec_get_nick (param->pspec));
        }
      else if (midi_channel)
        {
          content = g_strdup_format ("%u:%s%02d", midi_channel, prefix, control_type);
          if (cv)
            {
              /* TRANSLATORS: %s is substituted with a property name, %s is substituted with midi control type */
              tip = g_strdup_format (_("%s: automation from MIDI control: %s (MIDI channel: %d)"),
                                     g_param_spec_get_nick (param->pspec),
                                     cv->choice_label ? cv->choice_label : cv->choice_ident,
                                     midi_channel);
            }
        }
      else
        {
          content = g_strdup_format ("%s%02d", prefix, control_type);
          if (cv)
            {
              /* TRANSLATORS: %s is substituted with a property name, %s is substituted with midi control type */
              tip = g_strdup_format (_("%s: automation from MIDI control: %s"),
                                     g_param_spec_get_nick (param->pspec),
                                     cv->choice_label ? cv->choice_label : cv->choice_ident);
            }
        }
    }
  GtkWidget *label = (GtkWidget*) g_object_get_data ((GObject*) widget, "beast-GxkParam-label");
  g_object_set (label,
                "label", content ? content : "--",
                NULL);
  g_free (content);
  gxk_widget_set_tooltip (widget, tip);
  gxk_widget_set_tooltip (gxk_parent_find_descendant (widget, GTK_TYPE_BUTTON), tip);
  g_free (tip);
  Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
  gtk_widget_set_sensitive (GTK_BIN (widget)->child, proxy && !source.is_prepared());
}

static GxkParamEditor param_automation = {
  { "automation",       N_("Control Automation"), },
  { 0, },
  { "automate",         -5,     TRUE, },        /* options, rating, editing */
  param_automation_create, param_automation_update,
};
<commit_msg>BST: small coment fixup<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html

/* --- automation setup editor --- */
#include "bstprocedure.hh"

static GParamSpec*
param_automation_pspec_midi_channel()
{
  static GParamSpec *midi_channel_pspec =
    g_param_spec_ref_sink (sfi_pspec_int ("midi_channel", _("MIDI Channel"),
                                          _("The MIDI Channel from which automation events should be received, 0 designates the default MIDI channel"),
                                          0, 0, 99 /* FIXME: BSE_MIDI_MAX_CHANNELS */, 1, SFI_PARAM_STANDARD ":scale:unprepared"));
  return g_param_spec_ref (midi_channel_pspec);
}

static GParamSpec*
param_automation_pspec_control_type()
{
  static GParamSpec *control_type_pspec =
    g_param_spec_ref_sink (sfi_pspec_choice ("control_type", _("Control Type"),
                                             _("The type of control events used for automation"),
                                             Aida::enum_value_to_string (Bse::MidiControl::CONTINUOUS_16).c_str(),
                                             Bse::choice_values_from_enum<Bse::MidiControl>(),
                                             SFI_PARAM_STANDARD));
  return g_param_spec_ref (control_type_pspec);
}

static void
param_automation_dialog_cancel (GxkDialog *dialog)
{
  g_object_set_data ((GObject*) dialog, "beast-GxkParam", NULL);
  gxk_toplevel_delete (GTK_WIDGET (dialog));
}

static void
param_automation_dialog_ok (GxkDialog *dialog)
{
  GxkParam *param = (GxkParam*) g_object_get_data ((GObject*) dialog, "beast-GxkParam");
  g_object_set_data ((GObject*) dialog, "beast-GxkParam", NULL);
  if (param)
    {
      SfiProxy proxy = bst_param_get_proxy (param);
      GxkParam *param_channel = (GxkParam*) g_object_get_data ((GObject*) dialog, "GxkParam-automation-channel");
      GxkParam *param_control = (GxkParam*) g_object_get_data ((GObject*) dialog, "GxkParam-automation-control");
      gint midi_channel = sfi_value_get_int (&param_channel->value);
      Bse::MidiControl control_type = Aida::enum_value_from_string<Bse::MidiControl> (sfi_value_get_choice (&param_control->value));
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      source.set_automation (param->pspec->name, midi_channel, control_type);
    }
  gxk_toplevel_delete (GTK_WIDGET (dialog));
}

static void
param_automation_popup_editor (GtkWidget *widget,
                               GxkParam  *param)
{
  SfiProxy proxy = bst_param_get_proxy (param);
  if (proxy)
    {
      static GxkDialog *automation_dialog = NULL;
      if (!automation_dialog)
        {
          automation_dialog = (GxkDialog*) g_object_new (GXK_TYPE_DIALOG, NULL);
          /* configure dialog */
          g_object_set (automation_dialog,
                        "flags", (GXK_DIALOG_HIDE_ON_DELETE |
                                  GXK_DIALOG_PRESERVE_STATE |
                                  GXK_DIALOG_POPUP_POS |
                                  GXK_DIALOG_MODAL),
                        NULL);
          // gxk_dialog_set_sizes (automation_dialog, 550, 300, 600, 320);
          GtkBox *vbox = (GtkBox*) g_object_new (GTK_TYPE_VBOX, "visible", TRUE, "border-width", 5, NULL);
          /* setup parameter: midi_channel */
          GParamSpec *pspec = g_param_spec_ref (param_automation_pspec_midi_channel());
          GxkParam *dialog_param = bst_param_new_value (pspec, NULL, NULL);
          g_param_spec_unref (pspec);
          bst_param_create_gmask (dialog_param, NULL, GTK_WIDGET (vbox));
          g_object_set_data_full ((GObject*) automation_dialog, "GxkParam-automation-channel", dialog_param, (GDestroyNotify) gxk_param_destroy);
          /* setup parameter: control_type */
          pspec = g_param_spec_ref (param_automation_pspec_control_type());
          dialog_param = bst_param_new_value (pspec, NULL, NULL);
          g_param_spec_unref (pspec);
          bst_param_create_gmask (dialog_param, NULL, GTK_WIDGET (vbox));
          g_object_set_data_full ((GObject*) automation_dialog, "GxkParam-automation-control", dialog_param, (GDestroyNotify) gxk_param_destroy);
          /* dialog contents */
          gxk_dialog_set_child (GXK_DIALOG (automation_dialog), GTK_WIDGET (vbox));
          /* provide buttons */
          gxk_dialog_default_action_swapped (automation_dialog, BST_STOCK_OK, (void*) param_automation_dialog_ok, automation_dialog);
          gxk_dialog_action_swapped (automation_dialog, BST_STOCK_CANCEL, (void*) param_automation_dialog_cancel, automation_dialog);
        }
      g_object_set_data ((GObject*) automation_dialog, "beast-GxkParam", param);
      GxkParam *param_channel = (GxkParam*) g_object_get_data ((GObject*) automation_dialog, "GxkParam-automation-channel");
      GxkParam *param_control = (GxkParam*) g_object_get_data ((GObject*) automation_dialog, "GxkParam-automation-control");
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      sfi_value_set_int (&param_channel->value, source.get_automation_channel (param->pspec->name));
      Bse::MidiControl control_type = source.get_automation_control (param->pspec->name);
      sfi_value_set_choice (&param_control->value, Aida::enum_value_to_string (control_type).c_str());
      gxk_param_apply_value (param_channel); /* update model, auto updates GUI */
      gxk_param_apply_value (param_control); /* update model, auto updates GUI */
      g_object_set_data ((GObject*) widget, "GxkParam-automation-channel", param_channel);
      g_object_set_data ((GObject*) widget, "GxkParam-automation-control", param_control);
      /* setup for proxy */
      bst_window_sync_title_to_proxy (automation_dialog, proxy,
                                      /* TRANSLATORS: this is a dialog title and %s is replaced by an object name */
                                      _("Control Automation: %s"));
      /* cleanup connections to old parent_window */
      if (GTK_WINDOW (automation_dialog)->group)
        gtk_window_group_remove_window (GTK_WINDOW (automation_dialog)->group, GTK_WINDOW (automation_dialog));
      gtk_window_set_transient_for (GTK_WINDOW (automation_dialog), NULL);
      /* setup connections to new parent_window */
      GtkWindow *parent_window = (GtkWindow*) gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
      if (parent_window)
        {
          gtk_window_set_transient_for (GTK_WINDOW (automation_dialog), parent_window);
          if (parent_window->group)
            gtk_window_group_add_window (parent_window->group, GTK_WINDOW (automation_dialog));
        }
      gxk_widget_showraise (GTK_WIDGET (automation_dialog));
    }
}

static void
param_automation_unrequest_focus_space (GtkWidget      *button,  // GTKFIX: GtkButton requests focus space for !CAN_FOCUS
                                        GtkRequisition *requisition)
{
  gint focus_width = 0, focus_pad = 0;
  gtk_widget_style_get (button, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL);
  if (requisition->width > 2 * (focus_width + focus_pad) &&
      requisition->height > 2 * (focus_width + focus_pad))
    {
      requisition->width -= 2 * (focus_width + focus_pad);
      requisition->height -= 2 * (focus_width + focus_pad);
    }
}

static GtkWidget*
param_automation_create (GxkParam    *param,
                         const gchar *tooltip,
                         guint        variant)
{
  /* create fake-entry dialog-popup button */
  GtkWidget *widget = (GtkWidget*) g_object_new (GTK_TYPE_EVENT_BOX, NULL);
  gxk_widget_modify_normal_bg_as_base (widget);
  GtkWidget *button = (GtkWidget*) g_object_new (GTK_TYPE_BUTTON,
                                    "can-focus", 0,
                                    "parent", widget,
                                    NULL);
  gxk_widget_modify_normal_bg_as_base (button);
  g_object_connect (button, "signal_after::size-request", param_automation_unrequest_focus_space, button, NULL);
  GtkWidget *label = (GtkWidget*) g_object_new (GTK_TYPE_LABEL,
                                   "label", "88",
                                   "xpad", 2,
                                   "parent", button,
                                   NULL);
  gtk_widget_show_all (widget);
  /* store handles */
  g_object_set_data ((GObject*) widget, "beast-GxkParam", param);
  g_object_set_data ((GObject*) widget, "beast-GxkParam-label", label);
  /* connections */
  g_object_connect (button, "signal::clicked", param_automation_popup_editor, param, NULL);
  return widget;
}

static const SfiChoiceValue*
param_automation_find_choice_value (const gchar *choice,
                                    GParamSpec  *pspec)
{
  SfiChoiceValues cvalues = sfi_pspec_get_choice_values (pspec);
  guint i;
  for (i = 0; i < cvalues.n_values; i++)
    if (sfi_choice_match (cvalues.values[i].choice_ident, choice))
      return &cvalues.values[i];
  return NULL;
}

static void
param_automation_update (GxkParam  *param,
                         GtkWidget *widget)
{
  SfiProxy proxy = bst_param_get_proxy (param);
  gchar *content = NULL, *tip = NULL;
  if (proxy)
    {
      Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
      const gchar *prefix = "";
      int midi_channel = source.get_automation_channel (param->pspec->name);
      Bse::MidiControl control_type = source.get_automation_control (param->pspec->name);
      GParamSpec *control_pspec = g_param_spec_ref (param_automation_pspec_control_type());
      const SfiChoiceValue *cv = param_automation_find_choice_value (Aida::enum_value_to_string (control_type).c_str(), control_pspec);
      g_param_spec_unref (control_pspec);
      if (control_type >= Bse::MidiControl::CONTINUOUS_0 && control_type <= Bse::MidiControl::CONTINUOUS_31)
        {
          prefix = "c";
          control_type = Bse::MidiControl (int64 (control_type) - int64 (Bse::MidiControl::CONTINUOUS_0));
        }
      else if (control_type >= Bse::MidiControl::CONTROL_0 && control_type <= Bse::MidiControl::CONTROL_127)
        control_type = Bse::MidiControl (int64 (control_type) - int64 (Bse::MidiControl::CONTROL_0));
      else if (control_type == Bse::MidiControl::NONE)
        control_type = Bse::MidiControl (-1);
      else
        control_type = Bse::MidiControl (int64 (control_type) + 10000); /* shouldn't happen */
      if (int64 (control_type) < 0)     /* none */
        {
          content = g_strdup ("--");
          /* TRANSLATORS: %s is substituted with a property name */
          tip = g_strdup_format (_("%s: automation disabled"), g_param_spec_get_nick (param->pspec));
        }
      else if (midi_channel)
        {
          content = g_strdup_format ("%u:%s%02d", midi_channel, prefix, control_type);
          if (cv)
            {
              /* TRANSLATORS: %s is substituted with a property name, %d is substituted with midi control type */
              tip = g_strdup_format (_("%s: automation from MIDI control: %s (MIDI channel: %d)"),
                                     g_param_spec_get_nick (param->pspec),
                                     cv->choice_label ? cv->choice_label : cv->choice_ident,
                                     midi_channel);
            }
        }
      else
        {
          content = g_strdup_format ("%s%02d", prefix, control_type);
          if (cv)
            {
              /* TRANSLATORS: %s is substituted with a property name, %s is substituted with midi control type */
              tip = g_strdup_format (_("%s: automation from MIDI control: %s"),
                                     g_param_spec_get_nick (param->pspec),
                                     cv->choice_label ? cv->choice_label : cv->choice_ident);
            }
        }
    }
  GtkWidget *label = (GtkWidget*) g_object_get_data ((GObject*) widget, "beast-GxkParam-label");
  g_object_set (label,
                "label", content ? content : "--",
                NULL);
  g_free (content);
  gxk_widget_set_tooltip (widget, tip);
  gxk_widget_set_tooltip (gxk_parent_find_descendant (widget, GTK_TYPE_BUTTON), tip);
  g_free (tip);
  Bse::SourceH source = Bse::SourceH::down_cast (bse_server.from_proxy (proxy));
  gtk_widget_set_sensitive (GTK_BIN (widget)->child, proxy && !source.is_prepared());
}

static GxkParamEditor param_automation = {
  { "automation",       N_("Control Automation"), },
  { 0, },
  { "automate",         -5,     TRUE, },        /* options, rating, editing */
  param_automation_create, param_automation_update,
};
<|endoftext|>


<commit_before>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>

#include <pdal/SpatialReference.hpp>
#include <pdal/drivers/pipeline/Reader.hpp>
#include <pdal/filters/Selector.hpp>
#include <pdal/StageIterator.hpp>
#include <pdal/Schema.hpp>
#include <pdal/PointBuffer.hpp>
#include <pdal/Options.hpp>

#include "Support.hpp"

BOOST_AUTO_TEST_SUITE(SelectorFilterTest)

BOOST_AUTO_TEST_CASE(test1)
{
    pdal::Option option("filename", Support::datapath("pipeline/pipeline_selector.xml"));
    pdal::Options options(option);

    pdal::drivers::pipeline::Reader reader(options);
    reader.initialize();

    pdal::Schema const& schema = reader.getSchema();
    pdal::PointBuffer data(schema, 1000);

    boost::scoped_ptr<pdal::StageSequentialIterator> iter(reader.createSequentialIterator(data));

    {
        boost::uint32_t numRead = iter->read(data);
        BOOST_CHECK_EQUAL(numRead, 1000u);
    }

    pdal::Schema const& new_schema = data.getSchema();

    // These were ignored. The iterator will modify the schema of the PointBuffer
    // to mark these dimension as ignored, and these dimensions will not be
    // available to select via getDimension or getDimensionOptional.  They
    // will be available to the *entire* list of dimensions for the PointBuffer,
    // however
    BOOST_CHECK_THROW(new_schema.getDimension("Red"), pdal::dimension_not_found);
    BOOST_CHECK_THROW(new_schema.getDimension("Green"), pdal::dimension_not_found);
    BOOST_CHECK_THROW(new_schema.getDimension("Blue"), pdal::dimension_not_found);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>turn off for now<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <boost/test/unit_test.hpp>

#include <pdal/SpatialReference.hpp>
#include <pdal/drivers/pipeline/Reader.hpp>
#include <pdal/filters/Selector.hpp>
#include <pdal/StageIterator.hpp>
#include <pdal/Schema.hpp>
#include <pdal/PointBuffer.hpp>
#include <pdal/Options.hpp>

#include "Support.hpp"

BOOST_AUTO_TEST_SUITE(SelectorFilterTest)

BOOST_AUTO_TEST_CASE(test1)
{
    pdal::Option option("filename", Support::datapath("pipeline/pipeline_selector.xml"));
    pdal::Options options(option);

    pdal::drivers::pipeline::Reader reader(options);
    reader.initialize();

    pdal::Schema const& schema = reader.getSchema();
    pdal::PointBuffer data(schema, 1000);

    boost::scoped_ptr<pdal::StageSequentialIterator> iter(reader.createSequentialIterator(data));

    {
        boost::uint32_t numRead = iter->read(data);
        BOOST_CHECK_EQUAL(numRead, 1000u);
    }

    // pdal::Schema const& new_schema = data.getSchema();

    // FIXME: not done yet
    // BOOST_CHECK_THROW(new_schema.getDimension("Red"), pdal::dimension_not_found);
    // BOOST_CHECK_THROW(new_schema.getDimension("Green"), pdal::dimension_not_found);
    // BOOST_CHECK_THROW(new_schema.getDimension("Blue"), pdal::dimension_not_found);

    return;
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>// Raster Library
// Copyright (c) 2019 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "raster/raster.h"
#include <benchmark/benchmark.h>

using namespace raster;

template<typename Color>
static void BM_RasterForEach(benchmark::State& state) {
  image img(image_spec(state.range(0),
                       state.range(0), Color::bits_per_pixel));
  for (auto _ : state) {
    state.ResumeTiming();
    {
      int n = 0;
      for_each_pixel<Color>(
        img, [&n](int value) { n += value; });
    }
    state.PauseTiming();
  }
}
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel32bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel24bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel16bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel8bpp)->Range(256, 512);

template<typename Color>
static void BM_RasterForEach2(benchmark::State& state) {
  image img(image_spec(state.range(0),
                       state.range(0), Color::bits_per_pixel));
  for (auto _ : state) {
    state.ResumeTiming();
    {
      int n = 0;
      for_each_pixel2<Color>(
        img, [&n](int value) { n += value; });
    }
    state.PauseTiming();
  }
}
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel32bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel24bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel16bpp)->Range(256, 512);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel8bpp)->Range(256, 512);

BENCHMARK_MAIN();
<commit_msg>Change ranges for benchmarks<commit_after>// Raster Library
// Copyright (c) 2019 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#include "raster/raster.h"
#include <benchmark/benchmark.h>

using namespace raster;

template<typename Color>
static void BM_RasterForEach(benchmark::State& state) {
  image img(image_spec(state.range(0),
                       state.range(0), Color::bits_per_pixel));
  for (auto _ : state) {
    state.ResumeTiming();
    {
      int n = 0;
      for_each_pixel<Color>(
        img, [&n](int value) { n += value; });
    }
    state.PauseTiming();
  }
}
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel32bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel24bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel16bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach, Pixel8bpp)->Range(32, 4096);

template<typename Color>
static void BM_RasterForEach2(benchmark::State& state) {
  image img(image_spec(state.range(0),
                       state.range(0), Color::bits_per_pixel));
  for (auto _ : state) {
    state.ResumeTiming();
    {
      int n = 0;
      for_each_pixel2<Color>(
        img, [&n](int value) { n += value; });
    }
    state.PauseTiming();
  }
}
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel32bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel24bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel16bpp)->Range(32, 4096);
BENCHMARK_TEMPLATE(BM_RasterForEach2, Pixel8bpp)->Range(32, 4096);

BENCHMARK_MAIN();
<|endoftext|>


<commit_before>#include <deferred_renderer.hpp>

#ifdef BUILD_DEFERRED_RENDERER

#include <limits>

extern "C" {
#include <rgbe/rgbe.h>
}

namespace harmont {

deferred_renderer::deferred_renderer(const render_parameters_t& render_parameters, const shadow_parameters_t& shadow_parameters, int width, int height) : point_size_(1.f) {
    exposure_ = render_parameters.exposure;
    two_sided_ = render_parameters.two_sided;
    light_dir_ = render_parameters.light_dir;
    background_color_ = render_parameters.background_color;
    shadow_bias_ = render_parameters.shadow_bias;

    shadow_pass_ = std::make_shared<shadow_pass>(
        shadow_parameters.resolution,
        shadow_parameters.sample_count
    );

    ssdo_pass_ = std::make_shared<ssdo>(4, 40, 2.1f);
    ssdo_pass_->init(width, height);

    load_hdr_map_(render_parameters.hdr_map);

    depth_tex_ = texture::depth_texture<float>(width, height);
    gbuffer_tex_ = texture::texture_2d<unsigned int>(width, height, 3);

    vertex_shader::parameters_t params = {{"sample_count", std::to_string(shadow_parameters.sample_count)}, {"shadow_res", std::to_string(shadow_parameters.resolution)}};
    vertex_shader::ptr full_quad_vert = vertex_shader::from_file(std::string(GLSL_PREFIX)+"full_quad.vert");
    vertex_shader::ptr   gbuffer_vert = vertex_shader::from_file(std::string(GLSL_PREFIX)+"gbuffer.vert");
    fragment_shader::ptr clear_frag   = fragment_shader::from_file(std::string(GLSL_PREFIX)+"clear.frag");
    fragment_shader::ptr gbuffer_frag = fragment_shader::from_file(std::string(GLSL_PREFIX)+"gbuffer.frag");
    fragment_shader::ptr compose_frag = fragment_shader::from_file(std::string(GLSL_PREFIX)+"compose.frag", params);

    auto ssdo_clear_textures = ssdo_pass_->clear_textures();
    render_pass::textures clear_textures({gbuffer_tex_});
    clear_textures.insert(clear_textures.end(), ssdo_clear_textures.begin(), ssdo_clear_textures.end());
    clear_pass_ = std::make_shared<render_pass_2d>(full_quad_vert, clear_frag, clear_textures);
    geom_pass_ = std::make_shared<render_pass>(gbuffer_vert, gbuffer_frag, render_pass::textures({gbuffer_tex_}), depth_tex_);
    compose_pass_ = std::make_shared<render_pass_2d>(full_quad_vert, compose_frag);
}

deferred_renderer::~deferred_renderer() {
}

void deferred_renderer::set_light_dir(const Eigen::Vector3f& light_dir) {
    light_dir_ = light_dir;
}

void deferred_renderer::set_background_color(const Eigen::Vector3f& color) {
    background_color_ = color;
}

float deferred_renderer::exposure() const {
    return exposure_;
}

void deferred_renderer::set_exposure(float exposure) {
    exposure_ = exposure;
    if (exposure_ < 0.0001f) exposure_ = 0.0001f;
    if (exposure_ > 1.f) exposure_ = 1.f;
}

void deferred_renderer::delta_exposure(float delta) {
    set_exposure(exposure_ + delta);
}

float deferred_renderer::shadow_bias() const {
    return shadow_bias_;
}

void deferred_renderer::set_shadow_bias(float bias) {
    shadow_bias_ = bias;
}

void deferred_renderer::delta_shadow_bias(float delta) {
    shadow_bias_ += delta;
    if (shadow_bias_ < 0.f) shadow_bias_ = 0.f;
}

bool deferred_renderer::two_sided() const {
    return two_sided_;
}

void deferred_renderer::set_two_sided(bool two_sided) {
    two_sided_ = two_sided;
}

void deferred_renderer::toggle_two_sided() {
    two_sided_ = !!two_sided_;
}

float deferred_renderer::ssdo_radius() const {
    return ssdo_pass_->radius();
}

void deferred_renderer::set_ssdo_radius(float radius) {
    ssdo_pass_->set_radius(radius);
}

void deferred_renderer::delta_ssdo_radius(float delta) {
    ssdo_pass_->delta_radius(delta);
}

float deferred_renderer::ssdo_exponent() const {
    return ssdo_pass_->exponent();
}

void deferred_renderer::set_ssdo_exponent(float exponent) {
    ssdo_pass_->set_exponent(exponent);
}

void deferred_renderer::delta_ssdo_exponent(float delta) {
    ssdo_pass_->delta_exponent(delta);
}

float deferred_renderer::ssdo_reflective_albedo() const {
    return ssdo_pass_->reflective_albedo();
}

void deferred_renderer::set_ssdo_reflective_albedo(float reflective_albedo) {
    ssdo_pass_->set_reflective_albedo(reflective_albedo);
}

void deferred_renderer::delta_ssdo_reflective_albedo(float delta) {
    ssdo_pass_->delta_reflective_albedo(delta);
}

float deferred_renderer::point_size() const {
    return point_size_;
}

void deferred_renderer::set_point_size(float point_size) {
    point_size_ = point_size;
    if (point_size_ < 0.f) point_size_ = 0.f;
}

void deferred_renderer::delta_point_size(float delta) {
    set_point_size(point_size_ + delta);
}

render_pass::ptr deferred_renderer::geometry_pass() {
    return geom_pass_;
}

render_pass::const_ptr deferred_renderer::geometry_pass() const {
    return geom_pass_;
}

renderable::ptr_t deferred_renderer::object(std::string identifier) {
    auto find_it = objects_.find(identifier);
    if (find_it == objects_.end()) throw std::runtime_error("deferred_renderer::object(): Object \""+identifier+"\" does not exist"+SPOT);
    return find_it->second;
}

renderable::const_ptr_t deferred_renderer::object(std::string identifier) const {
    auto find_it = objects_.find(identifier);
    if (find_it == objects_.end()) throw std::runtime_error("deferred_renderer::object(): Object \""+identifier+"\" does not exist"+SPOT);
    return find_it->second;
}

const deferred_renderer::object_map_t& deferred_renderer::objects() const {
    return objects_;
}

void deferred_renderer::add_object(std::string identifier, renderable::ptr_t object) {
    if (objects_.find(identifier) != objects_.end()) {
        throw std::runtime_error("deferred_renderer::add_object(): Trying to add already existing object \""+identifier+"\""+SPOT);
    }

    objects_[identifier] = object;

    vertex_buffer<float>::layout_t vbo_layout;

    // shadow pass
    vbo_layout = {{"position", 3}};
    object->shadow_vertex_array()->bind();
    object->shadow_vertex_buffer()->bind_to_array(vbo_layout, shadow_pass_->program());
    object->shadow_vertex_array()->release();

    // display pass
    vbo_layout = {{"position", 3}, {"color", 1}, {"normal", 3}, {"tex_coords", 2}};
    object->display_vertex_array()->bind();
    object->display_vertex_buffer()->bind_to_array(vbo_layout, geom_pass_->program());
    object->display_vertex_array()->release();
}

void deferred_renderer::remove_object(std::string identifier) {
    auto find_iter = objects_.find(identifier);
    if (find_iter == objects_.end()) {
        throw std::runtime_error("deferred_renderer::remove_object: Trying to remove non-existent object \""+identifier+"\""+SPOT);
    }
    objects_.erase(find_iter);
}

void deferred_renderer::render(camera::ptr cam) {
    if (!objects_.size()) {
        glClearColor(background_color_[0], background_color_[1], background_color_[2], 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        return;
    }
    glEnable(GL_DEPTH_TEST);

    // compute bounding box
    bbox_ = bbox_t();
    for (const auto& obj : objects_) {
        bbox_.extend(obj.second->bounding_box());
    }
    shadow_pass_->update(bbox_, light_dir_);

    // update near/far values
    float near, far;
    std::tie(near, far) = get_near_far(cam, bbox_);
    cam->set_near_far(near, far);

    geometry_callback_t geom_callback = [&] (shader_program::ptr program, pass_type_t type) { render_geometry(program, type); };

    // update clear pass
    //clear_pass_->set_uniform("far", shadow_pass_->far());

    // update geometry pass
    geom_pass_->set_uniform("projection_matrix", cam->projection_matrix());
    geom_pass_->set_uniform("view_matrix", cam->view_matrix());
    geom_pass_->set_uniform("normal_matrix", cam->view_normal_matrix());
    geom_pass_->set_uniform("two_sided", static_cast<int>(two_sided_));
    float vp_ratio = -2.f * point_size_ * cam->near() * cam->height() / (cam->frustum_height() * 100.f);
    geom_pass_->set_uniform("vp_ratio", vp_ratio);

    // update compose pass
    auto eye = cam->forward().normalized();
    std::vector<float> eye_dir = { eye[0], eye[1], eye[2] };
    std::vector<float> light_dir_vec(light_dir_.data(), light_dir_.data()+3);
    std::vector<float> bg_col_vec(background_color_.data(), background_color_.data()+3);
    compose_pass_->set_uniform("light_dir", light_dir_vec);
    compose_pass_->set_uniform("eye_dir", eye_dir);
    compose_pass_->set_uniform("l_white", 1.f / exposure_ - 1.f);
    compose_pass_->set_uniform("shadow_matrix", shadow_pass_->transform());
    compose_pass_->set_uniform("inv_view_proj_matrix", cam->inverse_view_projection_matrix());
	compose_pass_->set_uniform("shadow_bias", shadow_bias_);
	compose_pass_->set_uniform("background_color", bg_col_vec);
	compose_pass_->set_uniform("poisson_disk[0]", shadow_pass_->poisson_disk());

    clear_pass_->render([&] (shader_program::ptr) { });

    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
    glEnable(GL_PROGRAM_POINT_SIZE);
    shadow_pass_->render(geom_callback, cam->width(), cam->height(), vp_ratio);

    geom_pass_->render([&] (shader_program::ptr program) { geom_callback(program, DISPLAY_GEOMETRY); });
    glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
    glDisable(GL_PROGRAM_POINT_SIZE);

    ssdo_pass_->compute(gbuffer_tex_, diff_tex_, cam, 1);
    compose_pass_->render([&] (shader_program::ptr) { }, {{gbuffer_tex_, "map_gbuffer"}, {shadow_pass_->shadow_texture(), "map_shadow"}, {ssdo_pass_->ssdo_texture(), "map_ssdo"}});
}

void deferred_renderer::reshape(camera::ptr cam) {
    int width = cam->width();
    int height = cam->height();
    geom_pass_->set_uniform("projection_matrix", cam->projection_matrix());
    depth_tex_->resize(width, height);
    gbuffer_tex_->resize(width, height);
    ssdo_pass_->reshape(width, height);
}

void deferred_renderer::render_geometry(shader_program::ptr program, pass_type_t type) {
    for (const auto& obj : objects_) {
        if (!obj.second->active()) continue;
        if (type != SHADOW_GEOMETRY || obj.second->casts_shadows()) {
            obj.second->render(program, type, bbox_);
        }
    }
}

void deferred_renderer::load_hdr_map_(std::string filename) {
	FILE *f;

	f = fopen(filename.c_str(), "rb");
	if (f == NULL) {
        std::cout << "Cannot open hdr file \"" << filename << "\" for reading." << "\n";
        exit(1);
	}

	rgbe_header_info header;
    int width, height;
	RGBE_ReadHeader(f, &width, &height, &header);
    float* data = new float[width*height*3];
	RGBE_ReadPixels_RLE(f, data, width, height);
	fclose(f);
    diff_tex_ = texture::texture_2d(width, height, 3, data, GL_RGB, GL_LINEAR, GL_LINEAR);
    delete [] data;
}

std::pair<float, float> deferred_renderer::get_near_far(camera::const_ptr cam, const bounding_box_t& bbox) {
    Eigen::Vector3f bb_min = bbox.min(), bb_max = bbox.max();
    float near = std::numeric_limits<float>::max(), far = 0.f;
    Eigen::Matrix4f vm = cam->view_matrix();
    for (uint32_t c=0; c<8; ++c) {
        // compute corner
        Eigen::Vector3f corner;
        for (uint32_t i = 0; i < 3; ++i) {
            corner[i] = (c & 1 << i) ? bb_max[i] : bb_min[i];
        }
        // compute depth
        Eigen::Vector3f proj = (vm * corner.homogeneous()).head(3);
        float depth = fabs(proj[2]);
        if (depth < near) near = depth;
        if (depth > far)  far = depth;
    }
    near = std::max(near, 0.01f);

    return {near, far};
}

} // harmont

#endif // BUILD_DEFERRED_RENDERER
<commit_msg>bbox fix for inactive objects<commit_after>#include <deferred_renderer.hpp>

#ifdef BUILD_DEFERRED_RENDERER

#include <limits>

extern "C" {
#include <rgbe/rgbe.h>
}

namespace harmont {

deferred_renderer::deferred_renderer(const render_parameters_t& render_parameters, const shadow_parameters_t& shadow_parameters, int width, int height) : point_size_(1.f) {
    exposure_ = render_parameters.exposure;
    two_sided_ = render_parameters.two_sided;
    light_dir_ = render_parameters.light_dir;
    background_color_ = render_parameters.background_color;
    shadow_bias_ = render_parameters.shadow_bias;

    shadow_pass_ = std::make_shared<shadow_pass>(
        shadow_parameters.resolution,
        shadow_parameters.sample_count
    );

    ssdo_pass_ = std::make_shared<ssdo>(4, 40, 2.1f);
    ssdo_pass_->init(width, height);

    load_hdr_map_(render_parameters.hdr_map);

    depth_tex_ = texture::depth_texture<float>(width, height);
    gbuffer_tex_ = texture::texture_2d<unsigned int>(width, height, 3);

    vertex_shader::parameters_t params = {{"sample_count", std::to_string(shadow_parameters.sample_count)}, {"shadow_res", std::to_string(shadow_parameters.resolution)}};
    vertex_shader::ptr full_quad_vert = vertex_shader::from_file(std::string(GLSL_PREFIX)+"full_quad.vert");
    vertex_shader::ptr   gbuffer_vert = vertex_shader::from_file(std::string(GLSL_PREFIX)+"gbuffer.vert");
    fragment_shader::ptr clear_frag   = fragment_shader::from_file(std::string(GLSL_PREFIX)+"clear.frag");
    fragment_shader::ptr gbuffer_frag = fragment_shader::from_file(std::string(GLSL_PREFIX)+"gbuffer.frag");
    fragment_shader::ptr compose_frag = fragment_shader::from_file(std::string(GLSL_PREFIX)+"compose.frag", params);

    auto ssdo_clear_textures = ssdo_pass_->clear_textures();
    render_pass::textures clear_textures({gbuffer_tex_});
    clear_textures.insert(clear_textures.end(), ssdo_clear_textures.begin(), ssdo_clear_textures.end());
    clear_pass_ = std::make_shared<render_pass_2d>(full_quad_vert, clear_frag, clear_textures);
    geom_pass_ = std::make_shared<render_pass>(gbuffer_vert, gbuffer_frag, render_pass::textures({gbuffer_tex_}), depth_tex_);
    compose_pass_ = std::make_shared<render_pass_2d>(full_quad_vert, compose_frag);
}

deferred_renderer::~deferred_renderer() {
}

void deferred_renderer::set_light_dir(const Eigen::Vector3f& light_dir) {
    light_dir_ = light_dir;
}

void deferred_renderer::set_background_color(const Eigen::Vector3f& color) {
    background_color_ = color;
}

float deferred_renderer::exposure() const {
    return exposure_;
}

void deferred_renderer::set_exposure(float exposure) {
    exposure_ = exposure;
    if (exposure_ < 0.0001f) exposure_ = 0.0001f;
    if (exposure_ > 1.f) exposure_ = 1.f;
}

void deferred_renderer::delta_exposure(float delta) {
    set_exposure(exposure_ + delta);
}

float deferred_renderer::shadow_bias() const {
    return shadow_bias_;
}

void deferred_renderer::set_shadow_bias(float bias) {
    shadow_bias_ = bias;
}

void deferred_renderer::delta_shadow_bias(float delta) {
    shadow_bias_ += delta;
    if (shadow_bias_ < 0.f) shadow_bias_ = 0.f;
}

bool deferred_renderer::two_sided() const {
    return two_sided_;
}

void deferred_renderer::set_two_sided(bool two_sided) {
    two_sided_ = two_sided;
}

void deferred_renderer::toggle_two_sided() {
    two_sided_ = !!two_sided_;
}

float deferred_renderer::ssdo_radius() const {
    return ssdo_pass_->radius();
}

void deferred_renderer::set_ssdo_radius(float radius) {
    ssdo_pass_->set_radius(radius);
}

void deferred_renderer::delta_ssdo_radius(float delta) {
    ssdo_pass_->delta_radius(delta);
}

float deferred_renderer::ssdo_exponent() const {
    return ssdo_pass_->exponent();
}

void deferred_renderer::set_ssdo_exponent(float exponent) {
    ssdo_pass_->set_exponent(exponent);
}

void deferred_renderer::delta_ssdo_exponent(float delta) {
    ssdo_pass_->delta_exponent(delta);
}

float deferred_renderer::ssdo_reflective_albedo() const {
    return ssdo_pass_->reflective_albedo();
}

void deferred_renderer::set_ssdo_reflective_albedo(float reflective_albedo) {
    ssdo_pass_->set_reflective_albedo(reflective_albedo);
}

void deferred_renderer::delta_ssdo_reflective_albedo(float delta) {
    ssdo_pass_->delta_reflective_albedo(delta);
}

float deferred_renderer::point_size() const {
    return point_size_;
}

void deferred_renderer::set_point_size(float point_size) {
    point_size_ = point_size;
    if (point_size_ < 0.f) point_size_ = 0.f;
}

void deferred_renderer::delta_point_size(float delta) {
    set_point_size(point_size_ + delta);
}

render_pass::ptr deferred_renderer::geometry_pass() {
    return geom_pass_;
}

render_pass::const_ptr deferred_renderer::geometry_pass() const {
    return geom_pass_;
}

renderable::ptr_t deferred_renderer::object(std::string identifier) {
    auto find_it = objects_.find(identifier);
    if (find_it == objects_.end()) throw std::runtime_error("deferred_renderer::object(): Object \""+identifier+"\" does not exist"+SPOT);
    return find_it->second;
}

renderable::const_ptr_t deferred_renderer::object(std::string identifier) const {
    auto find_it = objects_.find(identifier);
    if (find_it == objects_.end()) throw std::runtime_error("deferred_renderer::object(): Object \""+identifier+"\" does not exist"+SPOT);
    return find_it->second;
}

const deferred_renderer::object_map_t& deferred_renderer::objects() const {
    return objects_;
}

void deferred_renderer::add_object(std::string identifier, renderable::ptr_t object) {
    if (objects_.find(identifier) != objects_.end()) {
        throw std::runtime_error("deferred_renderer::add_object(): Trying to add already existing object \""+identifier+"\""+SPOT);
    }

    objects_[identifier] = object;

    vertex_buffer<float>::layout_t vbo_layout;

    // shadow pass
    vbo_layout = {{"position", 3}};
    object->shadow_vertex_array()->bind();
    object->shadow_vertex_buffer()->bind_to_array(vbo_layout, shadow_pass_->program());
    object->shadow_vertex_array()->release();

    // display pass
    vbo_layout = {{"position", 3}, {"color", 1}, {"normal", 3}, {"tex_coords", 2}};
    object->display_vertex_array()->bind();
    object->display_vertex_buffer()->bind_to_array(vbo_layout, geom_pass_->program());
    object->display_vertex_array()->release();
}

void deferred_renderer::remove_object(std::string identifier) {
    auto find_iter = objects_.find(identifier);
    if (find_iter == objects_.end()) {
        throw std::runtime_error("deferred_renderer::remove_object: Trying to remove non-existent object \""+identifier+"\""+SPOT);
    }
    objects_.erase(find_iter);
}

void deferred_renderer::render(camera::ptr cam) {
    if (!objects_.size()) {
        glClearColor(background_color_[0], background_color_[1], background_color_[2], 1.0);
        glClear(GL_COLOR_BUFFER_BIT);
        return;
    }
    glEnable(GL_DEPTH_TEST);

    // compute bounding box
    bbox_ = bbox_t();
    for (const auto& obj : objects_) {
        if (!obj.second->active()) continue;
        bbox_.extend(obj.second->bounding_box());
    }
    shadow_pass_->update(bbox_, light_dir_);

    // update near/far values
    float near, far;
    std::tie(near, far) = get_near_far(cam, bbox_);
    cam->set_near_far(near, far);

    geometry_callback_t geom_callback = [&] (shader_program::ptr program, pass_type_t type) { render_geometry(program, type); };

    // update clear pass
    //clear_pass_->set_uniform("far", shadow_pass_->far());

    // update geometry pass
    geom_pass_->set_uniform("projection_matrix", cam->projection_matrix());
    geom_pass_->set_uniform("view_matrix", cam->view_matrix());
    geom_pass_->set_uniform("normal_matrix", cam->view_normal_matrix());
    geom_pass_->set_uniform("two_sided", static_cast<int>(two_sided_));
    float vp_ratio = -2.f * point_size_ * cam->near() * cam->height() / (cam->frustum_height() * 100.f);
    geom_pass_->set_uniform("vp_ratio", vp_ratio);

    // update compose pass
    auto eye = cam->forward().normalized();
    std::vector<float> eye_dir = { eye[0], eye[1], eye[2] };
    std::vector<float> light_dir_vec(light_dir_.data(), light_dir_.data()+3);
    std::vector<float> bg_col_vec(background_color_.data(), background_color_.data()+3);
    compose_pass_->set_uniform("light_dir", light_dir_vec);
    compose_pass_->set_uniform("eye_dir", eye_dir);
    compose_pass_->set_uniform("l_white", 1.f / exposure_ - 1.f);
    compose_pass_->set_uniform("shadow_matrix", shadow_pass_->transform());
    compose_pass_->set_uniform("inv_view_proj_matrix", cam->inverse_view_projection_matrix());
	compose_pass_->set_uniform("shadow_bias", shadow_bias_);
	compose_pass_->set_uniform("background_color", bg_col_vec);
	compose_pass_->set_uniform("poisson_disk[0]", shadow_pass_->poisson_disk());

    clear_pass_->render([&] (shader_program::ptr) { });

    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
    glEnable(GL_PROGRAM_POINT_SIZE);
    shadow_pass_->render(geom_callback, cam->width(), cam->height(), vp_ratio);

    geom_pass_->render([&] (shader_program::ptr program) { geom_callback(program, DISPLAY_GEOMETRY); });
    glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
    glDisable(GL_PROGRAM_POINT_SIZE);

    ssdo_pass_->compute(gbuffer_tex_, diff_tex_, cam, 1);
    compose_pass_->render([&] (shader_program::ptr) { }, {{gbuffer_tex_, "map_gbuffer"}, {shadow_pass_->shadow_texture(), "map_shadow"}, {ssdo_pass_->ssdo_texture(), "map_ssdo"}});
}

void deferred_renderer::reshape(camera::ptr cam) {
    int width = cam->width();
    int height = cam->height();
    geom_pass_->set_uniform("projection_matrix", cam->projection_matrix());
    depth_tex_->resize(width, height);
    gbuffer_tex_->resize(width, height);
    ssdo_pass_->reshape(width, height);
}

void deferred_renderer::render_geometry(shader_program::ptr program, pass_type_t type) {
    for (const auto& obj : objects_) {
        if (!obj.second->active()) continue;
        if (type != SHADOW_GEOMETRY || obj.second->casts_shadows()) {
            obj.second->render(program, type, bbox_);
        }
    }
}

void deferred_renderer::load_hdr_map_(std::string filename) {
	FILE *f;

	f = fopen(filename.c_str(), "rb");
	if (f == NULL) {
        std::cout << "Cannot open hdr file \"" << filename << "\" for reading." << "\n";
        exit(1);
	}

	rgbe_header_info header;
    int width, height;
	RGBE_ReadHeader(f, &width, &height, &header);
    float* data = new float[width*height*3];
	RGBE_ReadPixels_RLE(f, data, width, height);
	fclose(f);
    diff_tex_ = texture::texture_2d(width, height, 3, data, GL_RGB, GL_LINEAR, GL_LINEAR);
    delete [] data;
}

std::pair<float, float> deferred_renderer::get_near_far(camera::const_ptr cam, const bounding_box_t& bbox) {
    Eigen::Vector3f bb_min = bbox.min(), bb_max = bbox.max();
    float near = std::numeric_limits<float>::max(), far = 0.f;
    Eigen::Matrix4f vm = cam->view_matrix();
    for (uint32_t c=0; c<8; ++c) {
        // compute corner
        Eigen::Vector3f corner;
        for (uint32_t i = 0; i < 3; ++i) {
            corner[i] = (c & 1 << i) ? bb_max[i] : bb_min[i];
        }
        // compute depth
        Eigen::Vector3f proj = (vm * corner.homogeneous()).head(3);
        float depth = fabs(proj[2]);
        if (depth < near) near = depth;
        if (depth > far)  far = depth;
    }
    near = std::max(near, 0.01f);

    return {near, far};
}

} // harmont

#endif // BUILD_DEFERRED_RENDERER
<|endoftext|>


<commit_before>#include "RapidHistWriter.h"

#include "RapidParam.h"
#include "RapidParticle.h"

RapidHistWriter::~RapidHistWriter() {
	if(tree_) {
		tree_->AutoSave();
		treeFile_->Close();
	}
	while(!histos_.empty()) {
		delete histos_[histos_.size()-1];
		histos_.pop_back();
	}
}

void RapidHistWriter::setup(bool saveTree) {
	//get the subset of particles that have more than one mass hypothesis
	std::vector<RapidParticle*>::const_iterator it = parts_.begin();
	for( ; it!=parts_.end(); ++it) {
		RapidParticle* part = *it;
		if(part->nMassHypotheses()>1) {
			altHypothesisParts_.push_back(part);
		}
	}

	setupHistos();
	if(saveTree) setupTree(); //called after setupHistos so we know the number of parameters
}

void RapidHistWriter::fill() {
	unsigned int offset(0);

	//first fill for the default hypothesis
	offset = fillSingleHypothesis(offset);

	RapidParticle *part1(0), *part2(0);

	//now loop over all single mis-IDs
	std::vector<RapidParticle*>::const_iterator it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
			part1->setMassHypothesis(i);
			offset = fillSingleHypothesis(offset);
		}
		part1->setMassHypothesis(0);
	}

	//now loop over all double mis-IDs
	it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		std::vector<RapidParticle*>::const_iterator it2 = it1+1;
		for( ; it2!=altHypothesisParts_.end(); ++it2) {
			part2 = *it2;
			for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
				part1->setMassHypothesis(i);
				for(unsigned int j=1; j<part2->nMassHypotheses(); ++j) {
					part2->setMassHypothesis(j);
					offset = fillSingleHypothesis(offset);
				}
				part2->setMassHypothesis(0);
			}
			part1->setMassHypothesis(0);
		}
	}
}

void RapidHistWriter::save() {
	std::cout << "INFO in RapidHistWriter::save : saving histograms to file: " << name_ << "_hists.root" << std::endl;
	TFile* histFile = new TFile(name_+"_hists.root", "RECREATE");

	for(unsigned int i=0; i<histos_.size(); ++i) {
		histos_[i]->Write();
	}
	histFile->Close();

	if(tree_) {
		tree_->AutoSave();
	}
}

void RapidHistWriter::setupHistos() {
	//first setup histograms for default mass hypothesis
	setupSingleHypothesis();

	RapidParticle *part1(0), *part2(0);

	//now loop over all single mis-IDs
	std::vector<RapidParticle*>::const_iterator it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
			part1->setMassHypothesis(i);
			TString suffix("_"); suffix+=part1->name() + "2" + part1->massHypothesisName();
			setupSingleHypothesis(suffix);
		}
		part1->setMassHypothesis(0);
	}

	//now loop over all double mis-IDs
	it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		std::vector<RapidParticle*>::const_iterator it2 = it1+1;
		for( ; it2!=altHypothesisParts_.end(); ++it2) {
			part2 = *it2;
			for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
				part1->setMassHypothesis(i);
				for(unsigned int j=1; j<part2->nMassHypotheses(); ++j) {
					part2->setMassHypothesis(j);
					TString suffix("_"); suffix+=part1->name() + "2" + part1->massHypothesisName();
					suffix+="_"; suffix+=part2->name() + "2" + part2->massHypothesisName();
					setupSingleHypothesis(suffix);
				}
				part2->setMassHypothesis(0);
			}
			part1->setMassHypothesis(0);
		}
	}

	vars_ = std::vector<double>(histos_.size(), 0);
}

void RapidHistWriter::setupSingleHypothesis(TString suffix) {
	std::vector<RapidParam*>::iterator itParam;

	TString baseName;
	TString histName;
	TString axisTitle;
	TH1F* hist(0);

	double min(0), max(0);

	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		baseName = part->name();

		if(part->nDaughters()==0) {
			for(itParam=paramsStable_.begin(); itParam!=paramsStable_.end(); ++itParam) {
				RapidParam* param = *itParam;
				histName  = baseName+"_"+param->name();
				histName += suffix;
				axisTitle = param->name() + "(" + baseName + ")";
				param->getMinMax(part,min,max);
				hist = new TH1F(histName, "", 100, min, max);
				hist->GetXaxis()->SetTitle(axisTitle);
				histos_.push_back(hist);
			}
		} else {
			for(itParam=paramsDecaying_.begin(); itParam!=paramsDecaying_.end(); ++itParam) {
				RapidParam* param = *itParam;
				histName  = baseName+"_"+param->name();
				histName += suffix;
				axisTitle = param->name() + "(" + baseName + ")";
				param->getMinMax(part,min,max);
				hist = new TH1F(histName, "", 100, min, max);
				hist->GetXaxis()->SetTitle(axisTitle);
				histos_.push_back(hist);
			}

			//2-body IMs
			if(part->nDaughters() > 2) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(itParam=paramsTwoBody_.begin(); itParam!=paramsTwoBody_.end(); ++itParam) {
							RapidParam* param = *itParam;
							histName  = jDaug->name()+"_";
							histName += kDaug->name()+"_";
							histName += param->name();
							histName += suffix;
							axisTitle = param->name() + "(" + jDaug->name() + "_" + kDaug->name() + ")";
							param->getMinMax(jDaug,kDaug,min,max);
							hist = new TH1F(histName, "", 100, min, max);
							hist->GetXaxis()->SetTitle(axisTitle);
							histos_.push_back(hist);
						}
					}
				}
			}

			//3-body IMs
			if(part->nDaughters() > 3) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(RapidParticle* lDaug=kDaug->next(); lDaug!=0; lDaug=lDaug->next()) {
							for(itParam=paramsThreeBody_.begin(); itParam!=paramsThreeBody_.end(); ++itParam) {
								RapidParam* param = *itParam;
								histName  = jDaug->name()+"_";
								histName += kDaug->name()+"_";
								histName += lDaug->name()+"_";
								histName += param->name();
								histName += suffix;
								axisTitle = param->name() + "(" + jDaug->name() + "_" + kDaug->name() + "_" + lDaug->name() + ")";
								param->getMinMax(jDaug,kDaug,lDaug,min,max);
								hist = new TH1F(histName, "", 100, min, max);
								hist->GetXaxis()->SetTitle(axisTitle);
								histos_.push_back(hist);
							}
						}

					}
				}
			}
		}
	}

	for( itParam=params_.begin(); itParam!= params_.end(); ++itParam) {
		RapidParam* param = (*itParam);
		param->getMinMax(min,max,true);
		TH1F* hist = new TH1F(param->name()+suffix, "", 100, min, max);
		histos_.push_back(hist);
	}
}

void RapidHistWriter::setupTree() {
	std::cout << "INFO in RapidHistWriter::setupTree : tree will be saved to file: " << name_ << "_tree.root" << std::endl;
	std::cout << "                                     This will slow down generation." << std::endl;

	treeFile_ = new TFile(name_+"_tree.root", "RECREATE");
	tree_ = new TTree("DecayTree","DecayTree");
	tree_->SetDirectory(treeFile_);

	for(unsigned int i=0; i<histos_.size(); ++i) {
		tree_->Branch(histos_[i]->GetName(), &vars_[i]);
	}

}

unsigned int RapidHistWriter::fillSingleHypothesis(unsigned int offset) {

	std::vector<RapidParam*>::iterator itParam;
	TLorentzVector pSumTruth;
	TLorentzVector pSum;

	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];

		if(part->nDaughters() < 2) {
			for(itParam=paramsStable_.begin(); itParam!=paramsStable_.end(); ++itParam) {
				RapidParam* param = *itParam;
				if(param->truth()) {
					vars_[offset] = param->eval(part->getP());
				} else {
					vars_[offset] = param->eval(part->getPSmeared());
				}

				histos_[offset]->Fill(vars_[offset]);
				++offset;
			}
		} else {
			for(itParam=paramsDecaying_.begin(); itParam!=paramsDecaying_.end(); ++itParam) {
				RapidParam* param = *itParam;
				if(param->truth()) {
					vars_[offset] = param->eval(part->getP());
				} else {
					vars_[offset] = param->eval(part->getPSmeared());
				}
				histos_[offset]->Fill(vars_[offset]);
				++offset;
			}

			//2-body IMs
			if(part->nDaughters() > 2) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						pSumTruth = jDaug->getP() + kDaug->getP();
						pSum = jDaug->getPSmeared() + kDaug->getPSmeared();

						for(itParam=paramsTwoBody_.begin(); itParam!=paramsTwoBody_.end(); ++itParam) {
							RapidParam* param = *itParam;
							if(param->truth()) {
								vars_[offset] = param->eval(pSumTruth);
							} else {
								vars_[offset] = param->eval(pSum);
							}
							histos_[offset]->Fill(vars_[offset]);
							++offset;
						}
					}
				}
			}

			//3-body IMs
			if(part->nDaughters() > 3) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(RapidParticle* lDaug=kDaug->next(); lDaug!=0; lDaug=lDaug->next()) {
							pSumTruth = jDaug->getP() + kDaug->getP() + lDaug->getP();
							pSum = jDaug->getPSmeared() + kDaug->getPSmeared() + lDaug->getPSmeared();

							for(itParam=paramsTwoBody_.begin(); itParam!=paramsTwoBody_.end(); ++itParam) {
								RapidParam* param = *itParam;
								if(param->truth()) {
									vars_[offset] = param->eval(pSumTruth);
								} else {
									vars_[offset] = param->eval(pSum);
								}
								histos_[offset]->Fill(vars_[offset]);
								++offset;
							}
						}
					}
				}
			}
		}
	}

	std::vector<RapidParam*>::iterator it = params_.begin();
	for( ; it!= params_.end(); ++it) {
		vars_[offset] = (*it)->eval();
		histos_[offset]->Fill(vars_[offset]);
		++offset;
	}

	if(tree_) tree_->Fill();

	return offset;
}
<commit_msg>fixed bug in 3-body parameters<commit_after>#include "RapidHistWriter.h"

#include "RapidParam.h"
#include "RapidParticle.h"

RapidHistWriter::~RapidHistWriter() {
	if(tree_) {
		tree_->AutoSave();
		treeFile_->Close();
	}
	while(!histos_.empty()) {
		delete histos_[histos_.size()-1];
		histos_.pop_back();
	}
}

void RapidHistWriter::setup(bool saveTree) {
	//get the subset of particles that have more than one mass hypothesis
	std::vector<RapidParticle*>::const_iterator it = parts_.begin();
	for( ; it!=parts_.end(); ++it) {
		RapidParticle* part = *it;
		if(part->nMassHypotheses()>1) {
			altHypothesisParts_.push_back(part);
		}
	}

	setupHistos();
	if(saveTree) setupTree(); //called after setupHistos so we know the number of parameters
}

void RapidHistWriter::fill() {
	unsigned int offset(0);

	//first fill for the default hypothesis
	offset = fillSingleHypothesis(offset);

	RapidParticle *part1(0), *part2(0);

	//now loop over all single mis-IDs
	std::vector<RapidParticle*>::const_iterator it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
			part1->setMassHypothesis(i);
			offset = fillSingleHypothesis(offset);
		}
		part1->setMassHypothesis(0);
	}

	//now loop over all double mis-IDs
	it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		std::vector<RapidParticle*>::const_iterator it2 = it1+1;
		for( ; it2!=altHypothesisParts_.end(); ++it2) {
			part2 = *it2;
			for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
				part1->setMassHypothesis(i);
				for(unsigned int j=1; j<part2->nMassHypotheses(); ++j) {
					part2->setMassHypothesis(j);
					offset = fillSingleHypothesis(offset);
				}
				part2->setMassHypothesis(0);
			}
			part1->setMassHypothesis(0);
		}
	}
}

void RapidHistWriter::save() {
	std::cout << "INFO in RapidHistWriter::save : saving histograms to file: " << name_ << "_hists.root" << std::endl;
	TFile* histFile = new TFile(name_+"_hists.root", "RECREATE");

	for(unsigned int i=0; i<histos_.size(); ++i) {
		histos_[i]->Write();
	}
	histFile->Close();

	if(tree_) {
		tree_->AutoSave();
	}
}

void RapidHistWriter::setupHistos() {
	//first setup histograms for default mass hypothesis
	setupSingleHypothesis();

	RapidParticle *part1(0), *part2(0);

	//now loop over all single mis-IDs
	std::vector<RapidParticle*>::const_iterator it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
			part1->setMassHypothesis(i);
			TString suffix("_"); suffix+=part1->name() + "2" + part1->massHypothesisName();
			setupSingleHypothesis(suffix);
		}
		part1->setMassHypothesis(0);
	}

	//now loop over all double mis-IDs
	it1 = altHypothesisParts_.begin();
	for( ; it1!=altHypothesisParts_.end(); ++it1) {
		part1 = *it1;
		std::vector<RapidParticle*>::const_iterator it2 = it1+1;
		for( ; it2!=altHypothesisParts_.end(); ++it2) {
			part2 = *it2;
			for(unsigned int i=1; i<part1->nMassHypotheses(); ++i) {
				part1->setMassHypothesis(i);
				for(unsigned int j=1; j<part2->nMassHypotheses(); ++j) {
					part2->setMassHypothesis(j);
					TString suffix("_"); suffix+=part1->name() + "2" + part1->massHypothesisName();
					suffix+="_"; suffix+=part2->name() + "2" + part2->massHypothesisName();
					setupSingleHypothesis(suffix);
				}
				part2->setMassHypothesis(0);
			}
			part1->setMassHypothesis(0);
		}
	}

	vars_ = std::vector<double>(histos_.size(), 0);
}

void RapidHistWriter::setupSingleHypothesis(TString suffix) {
	std::vector<RapidParam*>::iterator itParam;

	TString baseName;
	TString histName;
	TString axisTitle;
	TH1F* hist(0);

	double min(0), max(0);

	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];
		baseName = part->name();

		if(part->nDaughters()==0) {
			for(itParam=paramsStable_.begin(); itParam!=paramsStable_.end(); ++itParam) {
				RapidParam* param = *itParam;
				histName  = baseName+"_"+param->name();
				histName += suffix;
				axisTitle = param->name() + "(" + baseName + ")";
				param->getMinMax(part,min,max);
				hist = new TH1F(histName, "", 100, min, max);
				hist->GetXaxis()->SetTitle(axisTitle);
				histos_.push_back(hist);
			}
		} else {
			for(itParam=paramsDecaying_.begin(); itParam!=paramsDecaying_.end(); ++itParam) {
				RapidParam* param = *itParam;
				histName  = baseName+"_"+param->name();
				histName += suffix;
				axisTitle = param->name() + "(" + baseName + ")";
				param->getMinMax(part,min,max);
				hist = new TH1F(histName, "", 100, min, max);
				hist->GetXaxis()->SetTitle(axisTitle);
				histos_.push_back(hist);
			}

			//2-body IMs
			if(part->nDaughters() > 2) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(itParam=paramsTwoBody_.begin(); itParam!=paramsTwoBody_.end(); ++itParam) {
							RapidParam* param = *itParam;
							histName  = jDaug->name()+"_";
							histName += kDaug->name()+"_";
							histName += param->name();
							histName += suffix;
							axisTitle = param->name() + "(" + jDaug->name() + "_" + kDaug->name() + ")";
							param->getMinMax(jDaug,kDaug,min,max);
							hist = new TH1F(histName, "", 100, min, max);
							hist->GetXaxis()->SetTitle(axisTitle);
							histos_.push_back(hist);
						}
					}
				}
			}

			//3-body IMs
			if(part->nDaughters() > 3) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(RapidParticle* lDaug=kDaug->next(); lDaug!=0; lDaug=lDaug->next()) {
							for(itParam=paramsThreeBody_.begin(); itParam!=paramsThreeBody_.end(); ++itParam) {
								RapidParam* param = *itParam;
								histName  = jDaug->name()+"_";
								histName += kDaug->name()+"_";
								histName += lDaug->name()+"_";
								histName += param->name();
								histName += suffix;
								axisTitle = param->name() + "(" + jDaug->name() + "_" + kDaug->name() + "_" + lDaug->name() + ")";
								param->getMinMax(jDaug,kDaug,lDaug,min,max);
								hist = new TH1F(histName, "", 100, min, max);
								hist->GetXaxis()->SetTitle(axisTitle);
								histos_.push_back(hist);
							}
						}

					}
				}
			}
		}
	}

	for( itParam=params_.begin(); itParam!= params_.end(); ++itParam) {
		RapidParam* param = (*itParam);
		param->getMinMax(min,max,true);
		TH1F* hist = new TH1F(param->name()+suffix, "", 100, min, max);
		histos_.push_back(hist);
	}
}

void RapidHistWriter::setupTree() {
	std::cout << "INFO in RapidHistWriter::setupTree : tree will be saved to file: " << name_ << "_tree.root" << std::endl;
	std::cout << "                                     This will slow down generation." << std::endl;

	treeFile_ = new TFile(name_+"_tree.root", "RECREATE");
	tree_ = new TTree("DecayTree","DecayTree");
	tree_->SetDirectory(treeFile_);

	for(unsigned int i=0; i<histos_.size(); ++i) {
		tree_->Branch(histos_[i]->GetName(), &vars_[i]);
	}

}

unsigned int RapidHistWriter::fillSingleHypothesis(unsigned int offset) {

	std::vector<RapidParam*>::iterator itParam;
	TLorentzVector pSumTruth;
	TLorentzVector pSum;

	for(unsigned int i=0; i<parts_.size(); ++i) {
		RapidParticle* part = parts_[i];

		if(part->nDaughters() < 2) {
			for(itParam=paramsStable_.begin(); itParam!=paramsStable_.end(); ++itParam) {
				RapidParam* param = *itParam;
				if(param->truth()) {
					vars_[offset] = param->eval(part->getP());
				} else {
					vars_[offset] = param->eval(part->getPSmeared());
				}

				histos_[offset]->Fill(vars_[offset]);
				++offset;
			}
		} else {
			for(itParam=paramsDecaying_.begin(); itParam!=paramsDecaying_.end(); ++itParam) {
				RapidParam* param = *itParam;
				if(param->truth()) {
					vars_[offset] = param->eval(part->getP());
				} else {
					vars_[offset] = param->eval(part->getPSmeared());
				}
				histos_[offset]->Fill(vars_[offset]);
				++offset;
			}

			//2-body IMs
			if(part->nDaughters() > 2) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						pSumTruth = jDaug->getP() + kDaug->getP();
						pSum = jDaug->getPSmeared() + kDaug->getPSmeared();

						for(itParam=paramsTwoBody_.begin(); itParam!=paramsTwoBody_.end(); ++itParam) {
							RapidParam* param = *itParam;
							if(param->truth()) {
								vars_[offset] = param->eval(pSumTruth);
							} else {
								vars_[offset] = param->eval(pSum);
							}
							histos_[offset]->Fill(vars_[offset]);
							++offset;
						}
					}
				}
			}

			//3-body IMs
			if(part->nDaughters() > 3) {
				RapidParticle* jDaug = part->daughter(0);

				for( ; jDaug!=0; jDaug=jDaug->next()) {
					for(RapidParticle* kDaug=jDaug->next(); kDaug!=0; kDaug=kDaug->next()) {
						for(RapidParticle* lDaug=kDaug->next(); lDaug!=0; lDaug=lDaug->next()) {
							pSumTruth = jDaug->getP() + kDaug->getP() + lDaug->getP();
							pSum = jDaug->getPSmeared() + kDaug->getPSmeared() + lDaug->getPSmeared();

							for(itParam=paramsThreeBody_.begin(); itParam!=paramsThreeBody_.end(); ++itParam) {
								RapidParam* param = *itParam;
								if(param->truth()) {
									vars_[offset] = param->eval(pSumTruth);
								} else {
									vars_[offset] = param->eval(pSum);
								}
								histos_[offset]->Fill(vars_[offset]);
								++offset;
							}
						}
					}
				}
			}
		}
	}

	std::vector<RapidParam*>::iterator it = params_.begin();
	for( ; it!= params_.end(); ++it) {
		vars_[offset] = (*it)->eval();
		histos_[offset]->Fill(vars_[offset]);
		++offset;
	}

	if(tree_) tree_->Fill();

	return offset;
}
<|endoftext|>


<commit_before>#include "caffe2/core/net.h"
#include "caffe2/core/operator.h"
#include "caffe2/proto/caffe2.pb.h"

namespace caffe2 {

NetBase* CreateNet(const NetDef& net_def, Workspace* ws) {
  if (!net_def.has_net_type() || net_def.net_type() == "simple") {
    VLOG(1) << "Creating simple net.";
    return new SimpleNet(net_def, ws);
  } else if (net_def.net_type() == "parallel") {
    VLOG(1) << "Creating parallel net.";
    return new ParallelNet(net_def, ws);
  } else {
    LOG(ERROR) << "Unknown net type: " << net_def.net_type();
    return nullptr;
  }
  // Just to suppress compiler warning
  return nullptr;
}

SimpleNet::SimpleNet(const NetDef& net_def, Workspace* ws)
    : NetBase(net_def, ws) {
  bool net_def_has_device_option = net_def.has_device_option();
  // Initialize the operators
  for (const OperatorDef& operator_def : net_def.operators()) {
    VLOG(1) << "Creating operator " << operator_def.name()
            << ":" << operator_def.type();
    if (!operator_def.has_device_option() && net_def_has_device_option) {
      // In the case that the operator def does not specify a device option but
      // the net def has a default option, we copy the device option over to the
      // operator def.
      OperatorDef temp_def(operator_def);
      temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
      operators_.emplace_back(CreateOperator(temp_def, ws));
    } else {
      operators_.emplace_back(CreateOperator(operator_def, ws));
    }
  }
}

bool SimpleNet::Verify() {
  for (auto& op : operators_) {
    VLOG(1) << "Verifying operator " << op->def().name()
            << "(" << op->def().type() << ").";
    if (op.get() == nullptr || !op->Verify()) {
      return false;
    }
  }
  return true;
}

bool SimpleNet::Run() {
  VLOG(1) << "Running net.";
  for (const auto& op : operators_) {
    VLOG(1) << "Running operator " << op->def().name()
            << "(" << op->def().type() << ").";
    // TODO(Yangqing): convert this sequential run to event-based.
    if (!op->Run()) return false;
  }
  return true;
}

ParallelNet::ParallelNet(const NetDef& net_def, Workspace* ws)
    : NetBase(net_def, ws), operator_nodes_(net_def.operators_size()) {
  // Blob creator allows us to track which operator created which blob.
  std::map<string, int> blob_creator;
  bool net_def_has_device_option = net_def.has_device_option();
  // Initialize the operators
  for (int idx = 0; idx < net_def.operators_size(); ++idx) {
    const OperatorDef& op_def = net_def.operators(idx);
    VLOG(1) << "Creating operator #" << idx << ": "
            << op_def.name() << ":" << op_def.type();
    if (!op_def.has_device_option() && net_def_has_device_option) {
      OperatorDef temp_def(op_def);
      temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
      operator_nodes_[idx].operator_.reset(CreateOperator(temp_def, ws));
    } else {
      operator_nodes_[idx].operator_.reset(CreateOperator(op_def, ws));
    }
    // Check the inputs, and set up parents if necessary.
    for (const string& input : op_def.inputs()) {
      if (blob_creator.count(input) == 0) {
        VLOG(1) << "Input " << input << " not produced by this net. "
                << "Assuming it is pre-existing.";
      } else {
        int parent = blob_creator[input];
        VLOG(1) << "op dependency: " << parent << "->" << idx;
        operator_nodes_[idx].parents_.push_back(parent);
        operator_nodes_[parent].children_.push_back(idx);
      }
    }
    for (const string& output : op_def.outputs()) {
      if (blob_creator.count(output) != 0) {
        LOG(WARNING) << "Output " << output << " produced again. "
                     << "Such operation is not strictly tested. "
                     << "Use at your own risk.";
      }
      blob_creator[output] = idx;
    }
  }
  // Figure out the initial frontier - this is the one we will feed into the job
  // queue to start a run.
  for (int idx = 0; idx < operator_nodes_.size(); ++idx) {
    if (operator_nodes_[idx].parents_.size() == 0) {
      initial_frontier_.push_back(idx);
    }
  }
  // Finally, start the workers.
  CHECK_GT(net_def.num_workers(), 0) << "Must specify the number of workers.";
  for (int i = 0; i < net_def.num_workers(); ++i) {
    VLOG(1) << "Start worker #" << i;
    workers_.push_back(std::thread(&ParallelNet::WorkerFunction, this));
  }
}

ParallelNet::~ParallelNet() {
  // Safely join all the workers before exiting.
  job_queue_.NoMoreJobs();
  VLOG(1) << "Joining workers.";
  for (auto& worker : workers_) {
    worker.join();
  }
}

bool ParallelNet::Verify() {
  for (auto& op_node : operator_nodes_) {
    auto& op = op_node.operator_;
    VLOG(1) << "Verifying operator " << op->def().name()
            << "(" << op->def().type() << ").";
    if (op.get() == nullptr || !op->Verify()) {
      return false;
    }
  }
  return true;
}

bool ParallelNet::Run() {
  VLOG(1) << "Running parallel net.";
  // First, set up job queue.
  remaining_ops_ = operator_nodes_.size();
  success_ = true;
  // TODO(jiayq): Start all worker threads.
  // Initialize the runtime parent count.
  for (auto& node : operator_nodes_) {
    node.runtime_parent_count_ = node.parents_.size();
  }
  // Kickstart the job queue.
  for (auto& value : initial_frontier_) {
    job_queue_.Push(value);
  }
  std::unique_lock<std::mutex> mutex_lock(remaining_ops_mutex_);
  while (remaining_ops_ > 0) {
    VLOG(2) << "Remaining ops to run: " << remaining_ops_;
    cv_.wait(mutex_lock);
  }
  VLOG(2) << "All ops finished running.";
  // If the above while loop finished, we know that the current run finished.
  return success_;
}

void ParallelNet::WorkerFunction() {
  // WorkerFunctions() is an infinite loop until there are no more jobs to run.
  while (true) {
    int idx;
    // If there is no more jobs - meaning that the ParallelNet is destructing -
    // we will exit safely.
    if (!job_queue_.Pop(&idx)) {
      return;
    }
    VLOG(1) << "Running operator #" << idx << " "
            << operator_nodes_[idx].operator_->def().name()
            << "(" << operator_nodes_[idx].operator_->def().type() << ").";
    bool this_success = operator_nodes_[idx].operator_->Run();
    for (int child : operator_nodes_[idx].children_) {
      int count = --operator_nodes_[child].runtime_parent_count_;
      // The count should never be smaller than zero.
      DCHECK_GE(count, 0)
          << "Found runtime parent count smaller than zero for "
          << "operator node "
          << operator_nodes_[child].operator_->def().name()
          << "(" << operator_nodes_[child].operator_->def().type() << ").";
      if (count == 0) {
        VLOG(2) << "Pushing operator #" << child << " to queue.";
        job_queue_.Push(child);
      }
    }
    // Notify that the processed op is incremented by one.
    std::unique_lock<std::mutex> mutex_lock(remaining_ops_mutex_);
    --remaining_ops_;
    success_ &= this_success;
    DCHECK_GE(remaining_ops_, 0);
    cv_.notify_one();
    VLOG(2) << "Finished executing operator #" << idx;
  }
}

}  // namespace caffe2
<commit_msg>[minor] net.cc: in parallelnet, if the user forgot to set a num_workers, warn instead of quitting.<commit_after>#include "caffe2/core/net.h"
#include "caffe2/core/operator.h"
#include "caffe2/proto/caffe2.pb.h"

namespace caffe2 {

NetBase* CreateNet(const NetDef& net_def, Workspace* ws) {
  if (!net_def.has_net_type() || net_def.net_type() == "simple") {
    VLOG(1) << "Creating simple net.";
    return new SimpleNet(net_def, ws);
  } else if (net_def.net_type() == "parallel") {
    VLOG(1) << "Creating parallel net.";
    return new ParallelNet(net_def, ws);
  } else {
    LOG(ERROR) << "Unknown net type: " << net_def.net_type();
    return nullptr;
  }
  // Just to suppress compiler warning
  return nullptr;
}

SimpleNet::SimpleNet(const NetDef& net_def, Workspace* ws)
    : NetBase(net_def, ws) {
  bool net_def_has_device_option = net_def.has_device_option();
  // Initialize the operators
  for (const OperatorDef& operator_def : net_def.operators()) {
    VLOG(1) << "Creating operator " << operator_def.name()
            << ":" << operator_def.type();
    if (!operator_def.has_device_option() && net_def_has_device_option) {
      // In the case that the operator def does not specify a device option but
      // the net def has a default option, we copy the device option over to the
      // operator def.
      OperatorDef temp_def(operator_def);
      temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
      operators_.emplace_back(CreateOperator(temp_def, ws));
    } else {
      operators_.emplace_back(CreateOperator(operator_def, ws));
    }
  }
}

bool SimpleNet::Verify() {
  for (auto& op : operators_) {
    VLOG(1) << "Verifying operator " << op->def().name()
            << "(" << op->def().type() << ").";
    if (op.get() == nullptr || !op->Verify()) {
      return false;
    }
  }
  return true;
}

bool SimpleNet::Run() {
  VLOG(1) << "Running net.";
  for (const auto& op : operators_) {
    VLOG(1) << "Running operator " << op->def().name()
            << "(" << op->def().type() << ").";
    // TODO(Yangqing): convert this sequential run to event-based.
    if (!op->Run()) return false;
  }
  return true;
}

ParallelNet::ParallelNet(const NetDef& net_def, Workspace* ws)
    : NetBase(net_def, ws), operator_nodes_(net_def.operators_size()) {
  // Blob creator allows us to track which operator created which blob.
  std::map<string, int> blob_creator;
  bool net_def_has_device_option = net_def.has_device_option();
  // Initialize the operators
  for (int idx = 0; idx < net_def.operators_size(); ++idx) {
    const OperatorDef& op_def = net_def.operators(idx);
    VLOG(1) << "Creating operator #" << idx << ": "
            << op_def.name() << ":" << op_def.type();
    if (!op_def.has_device_option() && net_def_has_device_option) {
      OperatorDef temp_def(op_def);
      temp_def.mutable_device_option()->CopyFrom(net_def.device_option());
      operator_nodes_[idx].operator_.reset(CreateOperator(temp_def, ws));
    } else {
      operator_nodes_[idx].operator_.reset(CreateOperator(op_def, ws));
    }
    // Check the inputs, and set up parents if necessary.
    for (const string& input : op_def.inputs()) {
      if (blob_creator.count(input) == 0) {
        VLOG(1) << "Input " << input << " not produced by this net. "
                << "Assuming it is pre-existing.";
      } else {
        int parent = blob_creator[input];
        VLOG(1) << "op dependency: " << parent << "->" << idx;
        operator_nodes_[idx].parents_.push_back(parent);
        operator_nodes_[parent].children_.push_back(idx);
      }
    }
    for (const string& output : op_def.outputs()) {
      if (blob_creator.count(output) != 0) {
        LOG(WARNING) << "Output " << output << " produced again. "
                     << "Such operation is not strictly tested. "
                     << "Use at your own risk.";
      }
      blob_creator[output] = idx;
    }
  }
  // Figure out the initial frontier - this is the one we will feed into the job
  // queue to start a run.
  for (int idx = 0; idx < operator_nodes_.size(); ++idx) {
    if (operator_nodes_[idx].parents_.size() == 0) {
      initial_frontier_.push_back(idx);
    }
  }
  // Finally, start the workers.
  int num_workers = net_def.has_num_workers() ? net_def.num_workers() : 1;
  CHECK_GT(num_workers, 0) << "Must have a nonnegative number of workers";
  if (num_workers == 1) {
    LOG(WARNING) << "Number of workers is 1: this means that all operators "
                 << "will be executed sequentially. Did you forget to set "
                 << "num_workers in the NetDef?";
  }
  for (int i = 0; i < num_workers; ++i) {
    VLOG(1) << "Start worker #" << i;
    workers_.push_back(std::thread(&ParallelNet::WorkerFunction, this));
  }
}

ParallelNet::~ParallelNet() {
  // Safely join all the workers before exiting.
  job_queue_.NoMoreJobs();
  VLOG(1) << "Joining workers.";
  for (auto& worker : workers_) {
    worker.join();
  }
}

bool ParallelNet::Verify() {
  for (auto& op_node : operator_nodes_) {
    auto& op = op_node.operator_;
    VLOG(1) << "Verifying operator " << op->def().name()
            << "(" << op->def().type() << ").";
    if (op.get() == nullptr || !op->Verify()) {
      return false;
    }
  }
  return true;
}

bool ParallelNet::Run() {
  VLOG(1) << "Running parallel net.";
  // First, set up job queue.
  remaining_ops_ = operator_nodes_.size();
  success_ = true;
  // TODO(jiayq): Start all worker threads.
  // Initialize the runtime parent count.
  for (auto& node : operator_nodes_) {
    node.runtime_parent_count_ = node.parents_.size();
  }
  // Kickstart the job queue.
  for (auto& value : initial_frontier_) {
    job_queue_.Push(value);
  }
  std::unique_lock<std::mutex> mutex_lock(remaining_ops_mutex_);
  while (remaining_ops_ > 0) {
    VLOG(2) << "Remaining ops to run: " << remaining_ops_;
    cv_.wait(mutex_lock);
  }
  VLOG(2) << "All ops finished running.";
  // If the above while loop finished, we know that the current run finished.
  return success_;
}

void ParallelNet::WorkerFunction() {
  // WorkerFunctions() is an infinite loop until there are no more jobs to run.
  while (true) {
    int idx;
    // If there is no more jobs - meaning that the ParallelNet is destructing -
    // we will exit safely.
    if (!job_queue_.Pop(&idx)) {
      return;
    }
    VLOG(1) << "Running operator #" << idx << " "
            << operator_nodes_[idx].operator_->def().name()
            << "(" << operator_nodes_[idx].operator_->def().type() << ").";
    bool this_success = operator_nodes_[idx].operator_->Run();
    for (int child : operator_nodes_[idx].children_) {
      int count = --operator_nodes_[child].runtime_parent_count_;
      // The count should never be smaller than zero.
      DCHECK_GE(count, 0)
          << "Found runtime parent count smaller than zero for "
          << "operator node "
          << operator_nodes_[child].operator_->def().name()
          << "(" << operator_nodes_[child].operator_->def().type() << ").";
      if (count == 0) {
        VLOG(2) << "Pushing operator #" << child << " to queue.";
        job_queue_.Push(child);
      }
    }
    // Notify that the processed op is incremented by one.
    std::unique_lock<std::mutex> mutex_lock(remaining_ops_mutex_);
    --remaining_ops_;
    success_ &= this_success;
    DCHECK_GE(remaining_ops_, 0);
    cv_.notify_one();
    VLOG(2) << "Finished executing operator #" << idx;
  }
}

}  // namespace caffe2
<|endoftext|>