Program Listing for File muaestimator.cpp

Return to documentation for file (processors/muaestimator/muaestimator.cpp)

// ---------------------------------------------------------------------
// This file is part of falcon-core.
//
// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
//
// Falcon-server is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Falcon-server is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------

#include <limits>

#include "muaestimator.hpp"
#include "utilities/general.hpp"

MUAEstimator::MUAEstimator() : IProcessor() {
  add_option(BIN_SIZE, initial_bin_size_);
}

void MUAEstimator::CreatePorts() {
  data_in_port_ = create_input_port<SpikeType>(
      SPIKEDATA, SpikeType::Capabilities(), PortInPolicy(SlotRange(1, 64)));

  data_out_port_ = create_output_port<MUAType>("mua", MUAType::Capabilities(),
                                               MUAType::Parameters(),
                                               PortOutPolicy(SlotRange(1)));

  bin_size_ = create_static_state(BIN_SIZE, initial_bin_size_(), true,
                                  Permission::WRITE);

  mua_ = create_broadcaster_state("MUA", 0.0, Permission::READ);
}

void MUAEstimator::CompleteStreamInfo() {
  data_out_port_->streaminfo(0).set_parameters(
      MUAType::Parameters(initial_bin_size_()));
  data_out_port_->streaminfo(0).set_stream_rate(1e3 / initial_bin_size_());
}

void MUAEstimator::Prepare(GlobalContext &context) {
  // check that all incoming SpikeData have the same buffer size
  spike_buffer_size_ = data_in_port_->streaminfo(0).parameters().buffer_size;
  if (data_in_port_->number_of_slots() > 1) {
    for (SlotType s = 1; s < data_in_port_->number_of_slots(); ++s) {
      if (spike_buffer_size_ !=
          data_in_port_->streaminfo(s).parameters().buffer_size) {
        throw ProcessingConfigureError(
            "Incoming SpikeData buffer-sizes are different.", name());
      }
    }
  }

  try {
    // work around until check_buffer_sizes has been fixed
    double x = initial_bin_size_();
    check_buffer_sizes_and_log(spike_buffer_size_, x, true, n_spike_buffers_,
                               name());
    initial_bin_size_ = x;
  } catch (std::runtime_error &error) {
    throw ProcessingStreamInfoError(error.what(), name());
  }
  LOG(INFO) << name() << ". MUA will be computed using " << n_spike_buffers_
            << " spike buffers.";

  // TODO if the user doesn't specify a bin_size, use the one from spikedata
  // stream
}

void MUAEstimator::Process(ProcessingContext &context) {
  bool alive = true;
  SpikeType::Data *data_in = nullptr;
  MUAType::Data *data_out = nullptr;
  uint64_t hardware_timestamp = std::numeric_limits<uint64_t>::max();
  std::uint64_t spike_counter;

  while (!context.terminated()) {
    spike_counter = 0;

    current_bin_size_ = bin_size_->get();
    if (current_bin_size_ != previous_bin_size_) {
      try {
        check_buffer_sizes_and_log(spike_buffer_size_, current_bin_size_, true,
                                   n_spike_buffers_, name());
      } catch (std::runtime_error &error) {
        LOG(ERROR) << name() << ". Invalid buffer size (" << error.what()
                   << ").";
        current_bin_size_ = previous_bin_size_;
        // recompute n_spike_buffers
        check_buffer_sizes_and_log(spike_buffer_size_, current_bin_size_, true,
                                   n_spike_buffers_, name());
      }
    }

    if (current_bin_size_ != previous_bin_size_) {
      previous_bin_size_ = current_bin_size_;
      LOG(UPDATE) << ". MUA bin updated to " << current_bin_size_ << " ms.";
    }

    for (decltype(n_spike_buffers_) n = 0; n < n_spike_buffers_; ++n) {
      for (SlotType s = 0; s < data_in_port_->number_of_slots(); ++s) {
        alive = data_in_port_->slot(s)->RetrieveData(data_in);

        if (!alive) {
          break;
        }

        if (s == 0) {
          hardware_timestamp = data_in->hardware_timestamp();
        } else if (data_in->hardware_timestamp() != hardware_timestamp) {
          throw ProcessingError("Synchronization error", name());
        }
        spike_counter += data_in->n_detected_spikes();
        data_in_port_->slot(s)->ReleaseData();
      }
    }
    data_out = data_out_port_->slot(0)->ClaimData(false);
    data_out->set_bin_size(current_bin_size_);
    data_out->set_n_spikes(spike_counter);
    data_out->set_hardware_timestamp(hardware_timestamp);
    mua_->set(data_out->mua());
    data_out_port_->slot(0)->PublishData();
  }
}

REGISTERPROCESSOR(MUAEstimator)