<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2004 Max Howell <max.howell@methylblue.com>
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "audiodataoutput.h"
#include "mediaobject.h"

namespace Phonon
{
namespace Xine
{

AudioDataOutputXT::AudioDataOutputXT(AudioDataOutput *output) :
                    SinkNodeXT("AudioDataOutput"),
                    SourceNodeXT("AudioDataOutput"),
                    m_frontend(output),
                    m_audioPort(0)

{
    m_xine = Backend::xine();

    // Dummy audio port, until we get the proper one
    xine_audio_port_t *port = xine_open_audio_driver(m_xine, "none", 0);

    // Allocate a new scope plugin
    m_plugin = (scope_plugin_t*)qMalloc(sizeof(scope_plugin_t));

    // It is also a post plugin
    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;

    //1 audio input, 0 video inputs
    _x_post_init(post_plugin, 1, 0);

    // Intercept the null audio port (until we get the proper one)
    intercept(port);

    /* code is straight from xine_init_post()
       can't use that function as it only dlopens the plugins
       and our plugin is statically linked in */
    post_plugin->running_ticket = (*m_xine).port_ticket;
    post_plugin->xine = m_xine;

    // Store a reference to our own object in the post plugin struct
    m_plugin->audioDataOutput = this;
}

AudioDataOutputXT::~AudioDataOutputXT()
{
    delete m_plugin;
}

/// Rewires this node to the specified sourcenode. I don't think this is ever used (properly).
void AudioDataOutputXT::rewireTo(SourceNodeXT *source)
{
    debug() << Q_FUNC_INFO << "rewiring to " << source;
    if (!source->audioOutputPort()) { // I can't get no satisfaction
        debug() << Q_FUNC_INFO << " no audioport in source";
        return;
    }

    // Make sure the source is sane
    source->assert();

    // Get the audio input port in our post plugin
    xine_post_in_t *target = (xine_post_in_t*)xine_post_input(
                                    &((post_plugin_t*)m_plugin)->xine_post,
                                    const_cast<char*>("audio in"));

    if (!xine_post_wire(source->audioOutputPort(), target)) {
        qWarning() << Q_FUNC_INFO << ": Failed to rewire!";
        return;
    }
    m_postOutput = source->audioOutputPort();

    // Make sure things went okay
    source->assert();
    SinkNodeXT::assert();
}

/// Returns this Source's audio output port. Don't think this is used either.
xine_post_out_t *AudioDataOutputXT::audioOutputPort() const
{
    return m_postOutput;
}

/// Intercepts a given Xine audio port (called from AudioOutput)
void AudioDataOutputXT::intercept(xine_audio_port_t *p)
{
    if (p == m_audioPort) // we're already intercepting this one
        return;
    m_audioPort = p;

    post_in_t  *input;
    post_out_t *output;

    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;

    // Populate the port with dummy functions
    post_audio_port_t *port = _x_post_intercept_audio_port(post_plugin, m_audioPort, &input, &output);
    /* TODO:
     *  Do we leak these ports? Or is the Xine reference counting enough?
     *  Stay tuned for valgrind and interesting questions!
     */

    if (!port) {
        qWarning() << Q_FUNC_INFO << "unable to allocate port! (out of memory?)";
        delete post_plugin;
        return;
    }

    // Put in our own callbacks
    port->new_port.open       = openPort;
    port->new_port.close      = closePort;
    port->new_port.put_buffer = putBufferCallback;

    // Store the audio port for future use
    m_audioPort = &port->new_port;

    // Wire in the port input into our post plugin
    post_plugin->xine_post.audio_input[0] = &port->new_port;
    post_plugin->xine_post.type = PLUGIN_POST;
}

/// Callback function, opens the xine port
int AudioDataOutputXT::openPort(xine_audio_port_t *port_gen,
                                xine_stream_t *stream,
                                uint32_t bits,
                                uint32_t rate,
                                int mode)
{
    // Reference to the relevant object
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;

    post_audio_port_t *port = (post_audio_port_t*)port_gen;

    _x_post_rewire((post_plugin_t*)port->post);
    _x_post_inc_usage(port);

    port->stream = stream;
    port->bits = bits;
    port->rate = rate;
    port->mode = mode;

    // Set the new audio stream parameters
    that->m_channels = _x_ao_mode2channels(mode);
    that->m_frontend->setChannels(that->m_channels);
    that->m_frontend->m_sampleRate = rate;

    return port->original_port->open(port->original_port, stream, bits, rate, mode);
}

/// Callback function, closes the xine port
void AudioDataOutputXT::closePort(xine_audio_port_t *port_gen, xine_stream_t *stream)
{
    debug() << Q_FUNC_INFO << " closing port " << port_gen;
    post_audio_port_t *port = (post_audio_port_t*)port_gen;

    // This is the same as closing the port, according to comments in the Xine source
    port->stream = NULL;
    port->original_port->close(port->original_port, stream);

    // Decrease the reference counter in the port
    _x_post_dec_usage(port);
}

/// Callback function, receives audio data
void AudioDataOutputXT::putBufferCallback(xine_audio_port_t * port_gen, audio_buffer_t *buf, xine_stream_t *stream)
{
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;

    // Get the number of samples (audio frames * audio channels)
    int samples = buf->num_frames * that->m_channels;

    // Present the audio data to our frontend
    that->m_frontend->packetReady(samples, buf->mem);

    /* Send the audio buffer back to the original port.
       This notifies Xine that we have finished processing
       this buffer, so Xine can give us a new one */
    post_audio_port_t *port = (post_audio_port_t*)port_gen;
    port->original_port->put_buffer(port->original_port, buf, stream);
}

/* BACKEND-FRONT OBJECT */
AudioDataOutput::AudioDataOutput(QObject*)
: SinkNode(new AudioDataOutputXT(this))
, SourceNode(static_cast<AudioDataOutputXT *>(SinkNode::m_threadSafeObject.data()))
, m_format(Phonon::AudioDataOutput::IntegerFormat)
{
}

AudioDataOutput::~AudioDataOutput()
{
    K_XT(AudioDataOutput);
    delete xt;
}

inline void AudioDataOutput::packetReady(const int samples, const qint16 *buffer)
{
    //TODO: support floats, we currently only handle ints
    if (m_format == Phonon::AudioDataOutput::FloatFormat)
        return;

    // Tell the QVector how much data we're expecting, speeds things up a bit
    m_pendingData.reserve(m_pendingData.size() + samples);

    // Add the data to our QVector
    for (int i=0; i<samples; ++i)
        m_pendingData.append(buffer[i]);

    // While we have enough audio data for one signal
    while (m_pendingData.size() / m_channels > dataSize())
    {
        QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > map;

        /* If there's only one channel, we duplicate the data
           into both channels in the QMap */
        if (m_channels==1)
        {
            QVector<qint16> intBuffer(dataSize());

            memcpy(intBuffer.data(), m_pendingData.constData(), dataSize() * sizeof(qint16));
            m_pendingData.resize(m_pendingData.size() - m_dataSize);

            map.insert(Phonon::AudioDataOutput::LeftChannel, intBuffer);
            map.insert(Phonon::AudioDataOutput::RightChannel, intBuffer);
            emit dataReady(map);
        }
        else if (m_channels==2)
        {
            QVector<qint16> left, right;

            /* Copy out the interleaved data into the
               appropriate channels.
               This isn't very optimal.
               Especially since most analyzers and
               visualizations just want one channel. */

            for (int i=0; i < dataSize()*2; i+=2)
            {
                left.append(m_pendingData[i]);
                right.append(m_pendingData[i+1]);
            }

            // Remove the data we just copied out
            m_pendingData.resize(m_pendingData.size() - dataSize()*2);

            // Insert into the map, and emit
            map.insert(Phonon::AudioDataOutput::LeftChannel, left);
            map.insert(Phonon::AudioDataOutput::RightChannel, right);
            emit dataReady(map);
        }
    }
}

/// Handle events (basically just pass it on)
void AudioDataOutput::upstreamEvent(Event *e)
{
    Q_ASSERT(e);
    if (e->type() == Event::IsThereAXineEngineForMe) {
        // yes there is
        MediaObject *mediaObject = dynamic_cast<MediaObject*>(m_source);
        if (mediaObject)
            SourceNode::downstreamEvent(new HeresYourXineStreamEvent(mediaObject->stream()));
    } else
        SourceNode::upstreamEvent(e);
}

}} //namespace Phonon::Xine

#include "audiodataoutput.moc"
// vim: sw=4 ts=4
<commit_msg>let xine dispose of our plugin, so we don't get lots of callbacks after we're gone<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2004 Max Howell <max.howell@methylblue.com>
    Copyright (C) 2006 Tim Beaulen <tbscope@gmail.com>
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "audiodataoutput.h"
#include "mediaobject.h"

namespace Phonon
{
namespace Xine
{

AudioDataOutputXT::AudioDataOutputXT(AudioDataOutput *output) :
                    SinkNodeXT("AudioDataOutput"),
                    SourceNodeXT("AudioDataOutput"),
                    m_frontend(output),
                    m_audioPort(0)

{
    m_xine = Backend::xine();

    // Dummy audio port, until we get the proper one
    xine_audio_port_t *port = xine_open_audio_driver(m_xine, "none", 0);

    // Allocate a new scope plugin
    m_plugin = (scope_plugin_t*)qMalloc(sizeof(scope_plugin_t));

    // It is also a post plugin
    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;

    //1 audio input, 0 video inputs
    _x_post_init(post_plugin, 1, 0);

    // Intercept the null audio port (until we get the proper one)
    intercept(port);

    /* code is straight from xine_init_post()
       can't use that function as it only dlopens the plugins
       and our plugin is statically linked in */
    post_plugin->running_ticket = (*m_xine).port_ticket;
    post_plugin->xine = m_xine;

    // Store a reference to our own object in the post plugin struct
    m_plugin->audioDataOutput = this;
}

AudioDataOutputXT::~AudioDataOutputXT()
{
    xine_post_dispose(m_xine, &((post_plugin_t*)m_plugin)->xine_post);
    delete m_plugin;
}

/// Rewires this node to the specified sourcenode. I don't think this is ever used (properly).
void AudioDataOutputXT::rewireTo(SourceNodeXT *source)
{
    debug() << Q_FUNC_INFO << "rewiring to " << source;
    if (!source->audioOutputPort()) { // I can't get no satisfaction
        debug() << Q_FUNC_INFO << " no audioport in source";
        return;
    }

    // Make sure the source is sane
    source->assert();

    // Get the audio input port in our post plugin
    xine_post_in_t *target = (xine_post_in_t*)xine_post_input(
                                    &((post_plugin_t*)m_plugin)->xine_post,
                                    const_cast<char*>("audio in"));

    if (!xine_post_wire(source->audioOutputPort(), target)) {
        qWarning() << Q_FUNC_INFO << ": Failed to rewire!";
        return;
    }
    m_postOutput = source->audioOutputPort();

    // Make sure things went okay
    source->assert();
    SinkNodeXT::assert();
}

/// Returns this Source's audio output port. Don't think this is used either.
xine_post_out_t *AudioDataOutputXT::audioOutputPort() const
{
    return m_postOutput;
}

/// Intercepts a given Xine audio port (called from AudioOutput)
void AudioDataOutputXT::intercept(xine_audio_port_t *p)
{
    if (p == m_audioPort) // we're already intercepting this one
        return;
    m_audioPort = p;

    post_in_t  *input;
    post_out_t *output;

    post_plugin_t *post_plugin  = (post_plugin_t*)m_plugin;

    // Populate the port with dummy functions
    post_audio_port_t *port = _x_post_intercept_audio_port(post_plugin, m_audioPort, &input, &output);
    /* TODO:
     *  Do we leak these ports? Or is the Xine reference counting enough?
     *  Stay tuned for valgrind and interesting questions!
     */

    if (!port) {
        qWarning() << Q_FUNC_INFO << "unable to allocate port! (out of memory?)";
        delete post_plugin;
        return;
    }

    // Put in our own callbacks
    port->new_port.open       = openPort;
    port->new_port.close      = closePort;
    port->new_port.put_buffer = putBufferCallback;

    // Store the audio port for future use
    m_audioPort = &port->new_port;

    // Wire in the port input into our post plugin
    post_plugin->xine_post.audio_input[0] = &port->new_port;
    post_plugin->xine_post.type = PLUGIN_POST;
}

/// Callback function, opens the xine port
int AudioDataOutputXT::openPort(xine_audio_port_t *port_gen,
                                xine_stream_t *stream,
                                uint32_t bits,
                                uint32_t rate,
                                int mode)
{
    // Reference to the relevant object
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;

    post_audio_port_t *port = (post_audio_port_t*)port_gen;

    _x_post_rewire((post_plugin_t*)port->post);
    _x_post_inc_usage(port);

    port->stream = stream;
    port->bits = bits;
    port->rate = rate;
    port->mode = mode;

    // Set the new audio stream parameters
    that->m_channels = _x_ao_mode2channels(mode);
    that->m_frontend->setChannels(that->m_channels);
    that->m_frontend->m_sampleRate = rate;

    return port->original_port->open(port->original_port, stream, bits, rate, mode);
}

/// Callback function, closes the xine port
void AudioDataOutputXT::closePort(xine_audio_port_t *port_gen, xine_stream_t *stream)
{
    debug() << Q_FUNC_INFO << " closing port " << port_gen;
    post_audio_port_t *port = (post_audio_port_t*)port_gen;

    // This is the same as closing the port, according to comments in the Xine source
    port->stream = NULL;
    port->original_port->close(port->original_port, stream);

    // Decrease the reference counter in the port
    _x_post_dec_usage(port);
}

/// Callback function, receives audio data
void AudioDataOutputXT::putBufferCallback(xine_audio_port_t * port_gen, audio_buffer_t *buf, xine_stream_t *stream)
{
    AudioDataOutputXT *that = ((scope_plugin_t*)((post_audio_port_t*)port_gen)->post)->audioDataOutput;

    // Get the number of samples (audio frames * audio channels)
    int samples = buf->num_frames * that->m_channels;

    // Present the audio data to our frontend
    that->m_frontend->packetReady(samples, buf->mem);

    /* Send the audio buffer back to the original port.
       This notifies Xine that we have finished processing
       this buffer, so Xine can give us a new one */
    post_audio_port_t *port = (post_audio_port_t*)port_gen;
    port->original_port->put_buffer(port->original_port, buf, stream);
}

/* BACKEND-FRONT OBJECT */
AudioDataOutput::AudioDataOutput(QObject*)
: SinkNode(new AudioDataOutputXT(this))
, SourceNode(static_cast<AudioDataOutputXT *>(SinkNode::m_threadSafeObject.data()))
, m_format(Phonon::AudioDataOutput::IntegerFormat)
{
}

AudioDataOutput::~AudioDataOutput()
{
    K_XT(AudioDataOutput);
    delete xt;
}

inline void AudioDataOutput::packetReady(const int samples, const qint16 *buffer)
{
    //TODO: support floats, we currently only handle ints
    if (m_format == Phonon::AudioDataOutput::FloatFormat)
        return;

    // Tell the QVector how much data we're expecting, speeds things up a bit
    m_pendingData.reserve(m_pendingData.size() + samples);

    // Add the data to our QVector
    for (int i=0; i<samples; ++i)
        m_pendingData.append(buffer[i]);

    // While we have enough audio data for one signal
    while (m_pendingData.size() / m_channels > dataSize())
    {
        QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > map;

        /* If there's only one channel, we duplicate the data
           into both channels in the QMap */
        if (m_channels==1)
        {
            QVector<qint16> intBuffer(dataSize());

            memcpy(intBuffer.data(), m_pendingData.constData(), dataSize() * sizeof(qint16));
            m_pendingData.resize(m_pendingData.size() - m_dataSize);

            map.insert(Phonon::AudioDataOutput::LeftChannel, intBuffer);
            map.insert(Phonon::AudioDataOutput::RightChannel, intBuffer);
            emit dataReady(map);
        }
        else if (m_channels==2)
        {
            QVector<qint16> left, right;

            /* Copy out the interleaved data into the
               appropriate channels.
               This isn't very optimal.
               Especially since most analyzers and
               visualizations just want one channel. */

            for (int i=0; i < dataSize()*2; i+=2)
            {
                left.append(m_pendingData[i]);
                right.append(m_pendingData[i+1]);
            }

            // Remove the data we just copied out
            m_pendingData.resize(m_pendingData.size() - dataSize()*2);

            // Insert into the map, and emit
            map.insert(Phonon::AudioDataOutput::LeftChannel, left);
            map.insert(Phonon::AudioDataOutput::RightChannel, right);
            emit dataReady(map);
        }
    }
}

/// Handle events (basically just pass it on)
void AudioDataOutput::upstreamEvent(Event *e)
{
    Q_ASSERT(e);
    if (e->type() == Event::IsThereAXineEngineForMe) {
        // yes there is
        MediaObject *mediaObject = dynamic_cast<MediaObject*>(m_source);
        if (mediaObject)
            SourceNode::downstreamEvent(new HeresYourXineStreamEvent(mediaObject->stream()));
    } else
        SourceNode::upstreamEvent(e);
}

}} //namespace Phonon::Xine

#include "audiodataoutput.moc"
// vim: sw=4 ts=4
<|endoftext|>


<commit_before>#include "Epatest.hpp"

#include "core/pll/pllhead.hpp"
#include "core/pll/pll_util.hpp"
#include "core/pll/epa_pll_util.hpp"
#include "io/file_io.hpp"
#include "tree/Tree_Numbers.hpp"
#include "core/raxml/Model.hpp"
#include "seq/MSA.hpp"

#include <string>
#include <tuple>

using namespace std;

TEST(pll_util, utree_query_branches)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());

  // tests
  vector<pll_unode_t *> node_list(nums.branches);
  auto num_traversed = utree_query_branches(tree, &node_list[0]);

  EXPECT_EQ(nums.branches, num_traversed);

  for (auto x : node_list) {
    EXPECT_NE(x, nullptr);
  }

  // check for duplicates
  for (auto x : node_list) {
    int count = 0;
    for (auto y : node_list) {
      if (x == y || x == y->back)
        count++;
    }
    EXPECT_EQ(count, 1);
  }

  // teardown
  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, set_unique_clv_indices)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();

  auto tree = build_tree_from_file(env->tree_file, nums);
  auto part = build_partition_from_file( env->model, nums, msa.num_sites());

  set_unique_clv_indices(get_root(tree), nums.tip_nodes);

  // tests
  vector<pll_unode_t *> tip_nodes(nums.tip_nodes);
  tip_nodes.assign(tree->nodes, tree->nodes + nums.tip_nodes);

  vector<pll_unode_t *> inner_nodes(nums.inner_nodes);
  inner_nodes.assign(tree->nodes + nums.tip_nodes, tree->nodes + nums.nodes);

  // check for duplicate clv indices
  vector<unsigned int> index_list;
  for (auto x : tip_nodes)
    index_list.push_back(x->clv_index);

  for (auto x : inner_nodes) {
    index_list.push_back(x->clv_index);
    index_list.push_back(x->next->clv_index);
    index_list.push_back(x->next->next->clv_index);
  }

  for (auto x : index_list) {
    int count = 0;
    for (auto y : index_list) {
      if (x == y)
        count++;
    }
    EXPECT_EQ(count, 1);
  }

  // teardown
  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

static int cb_set_branchlengths_one(pll_unode_t * node)
{
  node->length = 1;
  if(node->next)
  {
    node->next->length = 1;
    node->next->next->length = 1;
  }
  return 1;
};

TEST(pll_util, get_numbered_newick_string)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;
  raxml::Model model;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());
  // auto valid_map = vector<Range>(nums.tip_nodes);
  link_tree_msa(tree, part, model, msa, nums.tip_nodes);

  // tests
  // valid output as returned by RAxML, with reset branch lengths, as we only want to test format
  string valid(
  "(Seal:1{0},(Whale:1{1},(Mouse:1{2},(Human:1{3},(Chicken:1{4},(Frog:1{5},Loach:1{6}):1{7}):1{8}):1{9}):1{10}):1{11},Cow:1{12});");

  vector<pll_unode_t*> travbuffer(nums.nodes);
  unsigned int traversal_size;
  pll_utree_traverse( get_root(tree),
                      PLL_TREE_TRAVERSE_POSTORDER,
                      cb_set_branchlengths_one,
                      &travbuffer[0],
                      &traversal_size);

  auto ret_string =  get_numbered_newick_string(tree);

  EXPECT_STREQ(valid.c_str(), ret_string.c_str());

  // teardown

  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, sum_branch_lengths)
{
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());
  set_branch_lengths(tree, 1.0);
  auto total_length = sum_branch_lengths(tree);

  EXPECT_DOUBLE_EQ(nums.branches, total_length);

  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, shift_partition_focus_shifty)
{
  // buildup
  pll_partition_t * part;
  part =  pll_partition_create(
    3, // tips
    1, // extra clv's
    4, 10,
    1,
    3, // number of prob. matrices (one per possible unique branch length)
    4,
    1, // number of scale buffers (one per possible inner node)
    // pll_map_nt,
    PLL_ATTRIB_PATTERN_TIP | PLL_ATTRIB_ARCH_CPU);

  // tests

  int clv_size = part->states * part->rate_cats;
  int begin = 2;
  int span = 4;

  for (size_t i = 0; i < part->sites * clv_size; i++) {
    if ((int)i < begin * clv_size or (int)i >= (begin + span) * clv_size)
      part->clv[3][i] = 2.0;
    else
      part->clv[3][i] = 1.0;
  }

  auto seq = new char[part->sites];

  for (size_t i = 0; i < part->sites; i++)
  {
    if ((int)i < begin or (int)i >= (begin + span))
    {
      seq[i] = 'A';
    }
    else
    {
      seq[i] = 'G';
    }
  }

  // printf("Sequence: %s\n", seq);

  pll_set_tip_states(part, 0, pll_map_nt, seq);
  ASSERT_NE(part->tipchars, nullptr);
  ASSERT_NE(part->tipchars[0], nullptr);

  shift_partition_focus(part, begin, span);

  // CLV test
  for (size_t i = 0; i < part->sites * clv_size; i++) {
    EXPECT_DOUBLE_EQ(part->clv[3][i], 1.0);
  }
  EXPECT_DOUBLE_EQ(part->clv[3][-1], 2.0);
  EXPECT_DOUBLE_EQ(part->clv[3][part->sites * clv_size], 2.0);

  // tipchars test
  for (size_t i = 0; i < part->sites; i++) {
    EXPECT_EQ(part->tipchars[0][i], '\x4');
  }
  EXPECT_EQ(part->tipchars[0][-1], '\x1');
  EXPECT_EQ(part->tipchars[0][part->sites], '\x1');

  // teardown
  shift_partition_focus(part, -begin, 10);
  delete[] seq;
  pll_partition_destroy(part);
}

TEST(pll_util, shift_partition_focus_logtest)
{
  // buildup
  pll_partition_t * part;
  part =  pll_partition_create(
    3, // tips
    1, // extra clv's
    4, 10,
    1,
    3, // number of prob. matrices (one per possible unique branch length)
    4,
    1, // number of scale buffers (one per possible inner node)
    // pll_map_nt,
    PLL_ATTRIB_PATTERN_TIP | PLL_ATTRIB_ARCH_CPU);

  double frequencies[4] = { 0.17, 0.19, 0.25, 0.39 };

  /* substitution rates for the GTR model */
  double subst_params[6] = {1,1,1,1,1,1};

  /* discretized category rates from a gamma distribution with alpha shape 1 */
  double rate_cats[4];
  pll_compute_gamma_cats(1.0, 4, rate_cats, PLL_GAMMA_RATES_MEAN);

  /* set frequencies */
  pll_set_frequencies(part, 0, frequencies);

  /* set substitution parameters */
  pll_set_subst_params(part, 0, subst_params);

  /* set rate categories */
  pll_set_category_rates(part, rate_cats);

  /* set the 5 tip CLVs, and use the pll_map_nt map for converting
     the sequences to CLVs */
  pll_set_tip_states(part, 0, pll_map_nt, "--AAAA----");
  pll_set_tip_states(part, 1, pll_map_nt, "--TTTT----");
  pll_set_tip_states(part, 2, pll_map_nt, "--GGGG----");

  double branch_lengths[3] = {0.123, 0.123, 0.123};
  unsigned int matrix_indices[3] = {0, 1, 2};
  unsigned int param_indices[4] = {0};
  pll_update_prob_matrices(part, param_indices, matrix_indices, branch_lengths, 3);

  pll_operation_t op;
  op.parent_clv_index = 3;
  op.child1_clv_index = 1;
  op.child1_scaler_index = PLL_SCALE_BUFFER_NONE;
  op.child2_clv_index = 2;
  op.child2_scaler_index = PLL_SCALE_BUFFER_NONE;
  op.parent_scaler_index = 0;
  op.child1_matrix_index = 1;
  op.child2_matrix_index = 2;

  pll_update_partials(part, &op, 1);

  // tests
  double full_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  shift_partition_focus(part, 2, 4);

  pll_update_partials(part, &op, 1);

  double ranged_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  EXPECT_DOUBLE_EQ(full_logl, ranged_logl);

  shift_partition_focus(part, 0, 3);

  pll_update_partials(part, &op, 1);

  double false_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  EXPECT_TRUE(abs(full_logl - false_logl) > 1.0 );
  // printf("Full:\t %.40f\n", full_logl);
  // printf("Ranged:\t %.40f\n", ranged_logl);
  // printf("False:\t %.40f\n", false_logl);

// extra tests
  shift_partition_focus(part, 3, 1);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("False+missing:\t %.40f\n", false_logl);

  shift_partition_focus(part, 1, 4);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("f+m+right:\t %.40f\n", false_logl);

  shift_partition_focus(part, -6, 2);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("fmr+left:\t %.40f\n", false_logl);

  shift_partition_focus(part, 0, 10);

  // teardown
  pll_partition_destroy(part);
}
<commit_msg>adjusted unit test for precision<commit_after>#include "Epatest.hpp"

#include "core/pll/pllhead.hpp"
#include "core/pll/pll_util.hpp"
#include "core/pll/epa_pll_util.hpp"
#include "io/file_io.hpp"
#include "tree/Tree_Numbers.hpp"
#include "core/raxml/Model.hpp"
#include "seq/MSA.hpp"

#include <string>
#include <tuple>

using namespace std;

TEST(pll_util, utree_query_branches)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());

  // tests
  vector<pll_unode_t *> node_list(nums.branches);
  auto num_traversed = utree_query_branches(tree, &node_list[0]);

  EXPECT_EQ(nums.branches, num_traversed);

  for (auto x : node_list) {
    EXPECT_NE(x, nullptr);
  }

  // check for duplicates
  for (auto x : node_list) {
    int count = 0;
    for (auto y : node_list) {
      if (x == y || x == y->back)
        count++;
    }
    EXPECT_EQ(count, 1);
  }

  // teardown
  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, set_unique_clv_indices)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();

  auto tree = build_tree_from_file(env->tree_file, nums);
  auto part = build_partition_from_file( env->model, nums, msa.num_sites());

  set_unique_clv_indices(get_root(tree), nums.tip_nodes);

  // tests
  vector<pll_unode_t *> tip_nodes(nums.tip_nodes);
  tip_nodes.assign(tree->nodes, tree->nodes + nums.tip_nodes);

  vector<pll_unode_t *> inner_nodes(nums.inner_nodes);
  inner_nodes.assign(tree->nodes + nums.tip_nodes, tree->nodes + nums.nodes);

  // check for duplicate clv indices
  vector<unsigned int> index_list;
  for (auto x : tip_nodes)
    index_list.push_back(x->clv_index);

  for (auto x : inner_nodes) {
    index_list.push_back(x->clv_index);
    index_list.push_back(x->next->clv_index);
    index_list.push_back(x->next->next->clv_index);
  }

  for (auto x : index_list) {
    int count = 0;
    for (auto y : index_list) {
      if (x == y)
        count++;
    }
    EXPECT_EQ(count, 1);
  }

  // teardown
  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

static int cb_set_branchlengths_one(pll_unode_t * node)
{
  node->length = 1;
  if(node->next)
  {
    node->next->length = 1;
    node->next->next->length = 1;
  }
  return 1;
};

TEST(pll_util, get_numbered_newick_string)
{
  // buildup
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;
  raxml::Model model;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());
  // auto valid_map = vector<Range>(nums.tip_nodes);
  link_tree_msa(tree, part, model, msa, nums.tip_nodes);

  // tests
  // valid output as returned by RAxML, with reset branch lengths, as we only want to test format
  string valid(
  "(Seal:1.00{0},(Whale:1.00{1},(Mouse:1.00{2},(Human:1.00{3},(Chicken:1.00{4},(Frog:1.00{5},Loach:1.00{6}):1.00{7}):1.00{8}):1.00{9}):1.00{10}):1.00{11},Cow:1.00{12});");

  vector<pll_unode_t*> travbuffer(nums.nodes);
  unsigned int traversal_size;
  pll_utree_traverse( get_root(tree),
                      PLL_TREE_TRAVERSE_POSTORDER,
                      cb_set_branchlengths_one,
                      &travbuffer[0],
                      &traversal_size);

  auto ret_string =  get_numbered_newick_string(tree, 2);

  EXPECT_STREQ(valid.c_str(), ret_string.c_str());

  // teardown

  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, sum_branch_lengths)
{
  auto msa = build_MSA_from_file(env->reference_file, MSA_Info(env->reference_file), true);
  Tree_Numbers nums = Tree_Numbers();
  pll_partition_t * part;
  pll_utree_t * tree;

  tree = build_tree_from_file(env->tree_file, nums);
  part = build_partition_from_file( env->model, nums, msa.num_sites());
  set_branch_lengths(tree, 1.0);
  auto total_length = sum_branch_lengths(tree);

  EXPECT_DOUBLE_EQ(nums.branches, total_length);

  pll_partition_destroy(part);
  pll_utree_destroy(tree, nullptr);
}

TEST(pll_util, shift_partition_focus_shifty)
{
  // buildup
  pll_partition_t * part;
  part =  pll_partition_create(
    3, // tips
    1, // extra clv's
    4, 10,
    1,
    3, // number of prob. matrices (one per possible unique branch length)
    4,
    1, // number of scale buffers (one per possible inner node)
    // pll_map_nt,
    PLL_ATTRIB_PATTERN_TIP | PLL_ATTRIB_ARCH_CPU);

  // tests

  int clv_size = part->states * part->rate_cats;
  int begin = 2;
  int span = 4;

  for (size_t i = 0; i < part->sites * clv_size; i++) {
    if ((int)i < begin * clv_size or (int)i >= (begin + span) * clv_size)
      part->clv[3][i] = 2.0;
    else
      part->clv[3][i] = 1.0;
  }

  auto seq = new char[part->sites];

  for (size_t i = 0; i < part->sites; i++)
  {
    if ((int)i < begin or (int)i >= (begin + span))
    {
      seq[i] = 'A';
    }
    else
    {
      seq[i] = 'G';
    }
  }

  // printf("Sequence: %s\n", seq);

  pll_set_tip_states(part, 0, pll_map_nt, seq);
  ASSERT_NE(part->tipchars, nullptr);
  ASSERT_NE(part->tipchars[0], nullptr);

  shift_partition_focus(part, begin, span);

  // CLV test
  for (size_t i = 0; i < part->sites * clv_size; i++) {
    EXPECT_DOUBLE_EQ(part->clv[3][i], 1.0);
  }
  EXPECT_DOUBLE_EQ(part->clv[3][-1], 2.0);
  EXPECT_DOUBLE_EQ(part->clv[3][part->sites * clv_size], 2.0);

  // tipchars test
  for (size_t i = 0; i < part->sites; i++) {
    EXPECT_EQ(part->tipchars[0][i], '\x4');
  }
  EXPECT_EQ(part->tipchars[0][-1], '\x1');
  EXPECT_EQ(part->tipchars[0][part->sites], '\x1');

  // teardown
  shift_partition_focus(part, -begin, 10);
  delete[] seq;
  pll_partition_destroy(part);
}

TEST(pll_util, shift_partition_focus_logtest)
{
  // buildup
  pll_partition_t * part;
  part =  pll_partition_create(
    3, // tips
    1, // extra clv's
    4, 10,
    1,
    3, // number of prob. matrices (one per possible unique branch length)
    4,
    1, // number of scale buffers (one per possible inner node)
    // pll_map_nt,
    PLL_ATTRIB_PATTERN_TIP | PLL_ATTRIB_ARCH_CPU);

  double frequencies[4] = { 0.17, 0.19, 0.25, 0.39 };

  /* substitution rates for the GTR model */
  double subst_params[6] = {1,1,1,1,1,1};

  /* discretized category rates from a gamma distribution with alpha shape 1 */
  double rate_cats[4];
  pll_compute_gamma_cats(1.0, 4, rate_cats, PLL_GAMMA_RATES_MEAN);

  /* set frequencies */
  pll_set_frequencies(part, 0, frequencies);

  /* set substitution parameters */
  pll_set_subst_params(part, 0, subst_params);

  /* set rate categories */
  pll_set_category_rates(part, rate_cats);

  /* set the 5 tip CLVs, and use the pll_map_nt map for converting
     the sequences to CLVs */
  pll_set_tip_states(part, 0, pll_map_nt, "--AAAA----");
  pll_set_tip_states(part, 1, pll_map_nt, "--TTTT----");
  pll_set_tip_states(part, 2, pll_map_nt, "--GGGG----");

  double branch_lengths[3] = {0.123, 0.123, 0.123};
  unsigned int matrix_indices[3] = {0, 1, 2};
  unsigned int param_indices[4] = {0};
  pll_update_prob_matrices(part, param_indices, matrix_indices, branch_lengths, 3);

  pll_operation_t op;
  op.parent_clv_index = 3;
  op.child1_clv_index = 1;
  op.child1_scaler_index = PLL_SCALE_BUFFER_NONE;
  op.child2_clv_index = 2;
  op.child2_scaler_index = PLL_SCALE_BUFFER_NONE;
  op.parent_scaler_index = 0;
  op.child1_matrix_index = 1;
  op.child2_matrix_index = 2;

  pll_update_partials(part, &op, 1);

  // tests
  double full_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  shift_partition_focus(part, 2, 4);

  pll_update_partials(part, &op, 1);

  double ranged_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  EXPECT_DOUBLE_EQ(full_logl, ranged_logl);

  shift_partition_focus(part, 0, 3);

  pll_update_partials(part, &op, 1);

  double false_logl = pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);

  EXPECT_TRUE(abs(full_logl - false_logl) > 1.0 );
  // printf("Full:\t %.40f\n", full_logl);
  // printf("Ranged:\t %.40f\n", ranged_logl);
  // printf("False:\t %.40f\n", false_logl);

// extra tests
  shift_partition_focus(part, 3, 1);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("False+missing:\t %.40f\n", false_logl);

  shift_partition_focus(part, 1, 4);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("f+m+right:\t %.40f\n", false_logl);

  shift_partition_focus(part, -6, 2);

  pll_update_partials(part, &op, 1);

  false_logl += pll_compute_edge_loglikelihood(part,
                                        0,
                                        PLL_SCALE_BUFFER_NONE,
                                        3,
                                        0,
                                        0,
                                        param_indices, nullptr);
  // printf("fmr+left:\t %.40f\n", false_logl);

  shift_partition_focus(part, 0, 10);

  // teardown
  pll_partition_destroy(part);
}
<|endoftext|>


<commit_before>/*
Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
Source Software License
Copyright (c) 2008 Ames Laboratory Iowa State University
All rights reserved.

Redistribution and use of HOOMD, 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 the copyright holder nor the names HOOMD's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*/

// $Id$
// $URL$

#ifdef WIN32
#include <windows.h>
#endif

#include <iostream>
#include <iomanip>

#include "NeighborList.h"
#include "BinnedNeighborList.h"

#ifdef USE_CUDA
#include "NeighborListNsqGPU.h"
#include "BinnedNeighborListGPU.h"
#endif

#include "SFCPackUpdater.h"

#include "Initializers.h"
#include <stdlib.h>

#include <boost/program_options.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost::program_options;
using namespace boost;
using namespace std;

/*! \file neighborlist_bmark.cc
	\brief Executable for benchmarking all of the various Neighborlist classes
	\details This is intended as a quick test to check the performance of Neighborlists
		on various machines and after performance tweaks have been made. It allows for a
		number of command line options to change settings, but will most likely just
		be run with the default settings most of the time.
	\ingroup benchmarks
*/

// options from command line
//! quite mode: only display time per compute and nothing else
bool quiet = false;
//! number of threads (for applicable computes)
unsigned int nthreads = 1;
//! cutoff radius for pair forces (for applicable computes)
Scalar r_cut = 3.0;
//! buffer radius for pair forces (for applicable computes)
Scalar r_buff = 0.8;
//! block size for calculation (for applicable computes)
unsigned int block_size = 128;
//! number of particles to benchmark
unsigned int N = 100000;
//! Should the particles be sorted with SFCPACK?
bool sort_particles = true;
//! number of seconds to average over
unsigned int nsec = 10;
//! Activate profiling?
bool profile_compute = true;
//! Use half neighborlist?
bool half_nlist = true;
//! Specify packing fraction of particles for the benchmark (if applicable)
Scalar phi_p = 0.2;

//! Initialize the force compute from a string selecting it
shared_ptr<NeighborList> init_neighboorlist_compute(const string& nl_name, shared_ptr<ParticleData> pdata)
	{
	shared_ptr<NeighborList> result;

	// handle creation of the various lennard=jones computes
	if (nl_name == "BinnedNl")
		result = shared_ptr<NeighborList>(new BinnedNeighborList(pdata, r_cut, r_buff));
	if (nl_name == "Nl")
		result = shared_ptr<NeighborList>(new NeighborList(pdata, r_cut, r_buff));
	#ifdef USE_CUDA
	if (nl_name == "BinnedNL.GPU")
		result = shared_ptr<NeighborList>(new BinnedNeighborListGPU(pdata, r_cut, r_buff));
	if (nl_name == "Nl_NSQ.GPU")
		result = shared_ptr<NeighborList>(new NeighborListNsqGPU(pdata, r_cut, r_buff));
	#endif

	result->setStorageMode(NeighborList::full);

	return result;
	}

//! Initializes the particle data to a random set of particles
shared_ptr<ParticleData> init_pdata()
	{
	RandomInitializer rand_init(N, phi_p, 0.0);
	shared_ptr<ParticleData> pdata(new ParticleData(rand_init));
	if (sort_particles)
		{
		SFCPackUpdater sorter(pdata, Scalar(1.0));
		sorter.update(0);
		}

	return pdata;
	}

//! Actually performs the benchmark on the preconstructed force compute
void benchmark(shared_ptr<NeighborList> nl) {

	// initialize profiling if requested
	shared_ptr<Profiler> prof(new Profiler());
	if (profile_compute && !quiet)
		nl->setProfiler(prof);

	// timer to count how long we spend at each point
	ClockSource clk;
	int count = 2;

	// do a warmup run so memory allocations don't change the benchmark numbers
	nl->compute(count++);

	int64_t tstart = clk.getTime();
	int64_t tend;
	// do at least one test, then repeat until we get at least 5s of data at this point
	int nrepeat = 0;
	do {
		nl->forceUpdate();
		nl->compute(count++);
		nrepeat++;
		tend = clk.getTime();
	} while((tend - tstart) < int64_t(nsec) * int64_t(1000000000) || nrepeat < 50);

	// make sure all kernels have been executed when using CUDA
	#ifdef USE_CUDA
	cudaThreadSynchronize();
	#endif
	tend = clk.getTime();

	if (!quiet)
		cout << *prof << endl;

	double avgTime = double(tend - tstart)/1e9/double(nrepeat);;
	cout << setprecision(7) << avgTime << " s/step" << endl;
}

//! Parses the command line and runs the benchmark
int main(int argc, char **argv)
	{

	// the name of the ForceCompute to benchmark (gotten from user)
	string nl_name;

	options_description desc("Allowed options");
	desc.add_options()
		("help,h", "Produce help message")
		("nparticles,N", value<unsigned int>(&N)->default_value(64000), "Number of particles")
		("phi_p", value<Scalar>(&phi_p)->default_value(0.2), "Volume fraction of particles in test system")
		("r_cut", value<Scalar>(&r_cut)->default_value(3.0), "Cutoff radius for pair force sum")
		("r_buff", value<Scalar>(&r_buff)->default_value(0.8), "Buffer radius for pair force sum")
		("nthreads,t", value<unsigned int>(&nthreads)->default_value(1), "Number of threads to execute (for multithreaded computes)")
		("block_size", value<unsigned int>(&block_size)->default_value(128), "Block size for GPU computes")
		("quiet,q", value<bool>(&quiet)->default_value(false)->zero_tokens(), "Only output time per computation")
		("sort", value<bool>(&sort_particles)->default_value(true), "Sort particles with SFCPACK")
		("profile", value<bool>(&profile_compute)->default_value(true), "Profile GFLOPS and GB/s sustained")
		("half_nlist", value<bool>(&half_nlist)->default_value(true), "Only store 1/2 of the neighbors (optimization for some pair force computes")
		("nsec", value<unsigned int>(&nsec)->default_value(10), "Number of seconds to profile for")
		("nl_name,f", value<string>(&nl_name)->default_value("Nl"), "NeighboorList to benchmark")
		;

	// parse the command line
	variables_map vm;
	try
		{
		store(parse_command_line(argc, argv, desc), vm);
		notify(vm);
		}
	catch (std::logic_error e)
		{
		// print help on error
		cerr << "Error parsing command line: " << e.what() << endl;
		cout << desc;
		cout << "Available ForceComputes are: ";
		cout << "Nl, BinnedNl";
		#ifdef USE_CUDA
		cout << ", BinnedNL.GPU, and Nl_NSQ.GPU";
		#endif
		cout << endl;

		exit(1);
		}

	//if (!quiet)
		//output_version_info(false);

	// if help is specified, print it
	if (vm.count("help"))
		{
		cout << desc;
		exit(1);
		}

	// initialize the particle data
	if (!quiet)
		cout << "Building particle data...";

	shared_ptr<ParticleData> pdata = init_pdata();
	cout << "done." << endl;

	// initialize the neighbor list
	if (!quiet)
		cout << "Building neighbor list data...";
	shared_ptr<NeighborList> nlist = init_neighboorlist_compute(nl_name, pdata);

	cout << "done." << endl;

	nlist->setStorageMode(NeighborList::full);

	if (nl_name == "Nl" || nl_name == "BinnedNl"){
		if (half_nlist)
			nlist->setStorageMode(NeighborList::half);
		else
			nlist->setStorageMode(NeighborList::full);
	}
	nlist->setEvery(1000000000);
	nlist->forceUpdate();
	nlist->compute(1);

	// count the average number of neighbors
	int64_t neigh_count = 0;
	vector< vector< unsigned int> > list = nlist->getList();
	for (unsigned int i = 0; i < N; i++)
		neigh_count += list[i].size();
	double avgNneigh = double(neigh_count) / double(N);

	/* Not needed for only benchmarking neighboor list creation

	// initialize the force compute
	shared_ptr<ForceCompute> fc = init_force_compute(fc_name, pdata, nlist);
	if (fc == NULL)
		{
		cerr << "Unrecognized force compute: " << fc_name << endl;
		exit(1);
		}

	if (!quiet)
		{
		cout << "Starting benchmarking of: " << fc_name << endl;
		cout << "nsec = " << nsec << " / N = " << N << " / phi_p = "<< phi_p << endl;
		cout << "sort_particles = " << sort_particles << " / half_nlist = " << half_nlist << endl;
		cout << "r_cut = " << r_cut << " / r_buff = " << r_buff << " / avg_n_neigh = " << avgNneigh << endl;
		cout << "nthreads = " << nthreads << " / block_size = " << block_size << endl;
		}

	*/

	benchmark(nlist);

	return 0;
	}
<commit_msg>Slight changes to the every and r_buff settings for functionally correct benchmarks. ticket #67<commit_after>/*
Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
Source Software License
Copyright (c) 2008 Ames Laboratory Iowa State University
All rights reserved.

Redistribution and use of HOOMD, 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 the copyright holder nor the names HOOMD's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 HOLDER 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.
*/

// $Id$
// $URL$

#ifdef WIN32
#include <windows.h>
#endif

#include <iostream>
#include <iomanip>

#include "NeighborList.h"
#include "BinnedNeighborList.h"

#ifdef USE_CUDA
#include "NeighborListNsqGPU.h"
#include "BinnedNeighborListGPU.h"
#endif

#include "SFCPackUpdater.h"

#include "Initializers.h"
#include <stdlib.h>

#include <boost/program_options.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>

using namespace boost::program_options;
using namespace boost;
using namespace std;

/*! \file neighborlist_bmark.cc
	\brief Executable for benchmarking all of the various Neighborlist classes
	\details This is intended as a quick test to check the performance of Neighborlists
		on various machines and after performance tweaks have been made. It allows for a
		number of command line options to change settings, but will most likely just
		be run with the default settings most of the time.
	\ingroup benchmarks
*/

// options from command line
//! quite mode: only display time per compute and nothing else
bool quiet = false;
//! number of threads (for applicable computes)
unsigned int nthreads = 1;
//! cutoff radius for pair forces (for applicable computes)
Scalar r_cut = 3.8;
//! buffer radius for pair forces (for applicable computes)
Scalar r_buff = 0.0;
//! block size for calculation (for applicable computes)
unsigned int block_size = 128;
//! number of particles to benchmark
unsigned int N = 100000;
//! Should the particles be sorted with SFCPACK?
bool sort_particles = true;
//! number of seconds to average over
unsigned int nsec = 10;
//! Activate profiling?
bool profile_compute = true;
//! Use half neighborlist?
bool half_nlist = true;
//! Specify packing fraction of particles for the benchmark (if applicable)
Scalar phi_p = 0.2;

//! Initialize the force compute from a string selecting it
shared_ptr<NeighborList> init_neighboorlist_compute(const string& nl_name, shared_ptr<ParticleData> pdata)
	{
	shared_ptr<NeighborList> result;

	// handle creation of the various lennard=jones computes
	if (nl_name == "BinnedNl")
		result = shared_ptr<NeighborList>(new BinnedNeighborList(pdata, r_cut, r_buff));
	if (nl_name == "Nl")
		result = shared_ptr<NeighborList>(new NeighborList(pdata, r_cut, r_buff));
	#ifdef USE_CUDA
	if (nl_name == "BinnedNL.GPU")
		result = shared_ptr<NeighborList>(new BinnedNeighborListGPU(pdata, r_cut, r_buff));
	if (nl_name == "Nl_NSQ.GPU")
		result = shared_ptr<NeighborList>(new NeighborListNsqGPU(pdata, r_cut, r_buff));
	#endif

	return result;
	}

//! Initializes the particle data to a random set of particles
shared_ptr<ParticleData> init_pdata()
	{
	RandomInitializer rand_init(N, phi_p, 0.0);
	shared_ptr<ParticleData> pdata(new ParticleData(rand_init));
	if (sort_particles)
		{
		SFCPackUpdater sorter(pdata, Scalar(1.0));
		sorter.update(0);
		}

	return pdata;
	}

//! Actually performs the benchmark on the preconstructed force compute
void benchmark(shared_ptr<NeighborList> nl) {

	// initialize profiling if requested
	shared_ptr<Profiler> prof(new Profiler());
	if (profile_compute && !quiet)
		nl->setProfiler(prof);

	// timer to count how long we spend at each point
	ClockSource clk;
	int count = 2;

	// do a warmup run so memory allocations don't change the benchmark numbers
	nl->compute(count++);

	int64_t tstart = clk.getTime();
	int64_t tend;
	// do at least one test, then repeat until we get at least 5s of data at this point
	int nrepeat = 0;
	do {
		nl->forceUpdate();
		nl->compute(count++);
		nrepeat++;
		tend = clk.getTime();
	} while((tend - tstart) < int64_t(nsec) * int64_t(1000000000) || nrepeat < 5);

	// make sure all kernels have been executed when using CUDA
	#ifdef USE_CUDA
	cudaThreadSynchronize();
	#endif
	tend = clk.getTime();

	if (!quiet)
		cout << *prof << endl;

	double avgTime = double(tend - tstart)/1e9/double(nrepeat);;
	cout << setprecision(7) << avgTime << " s/step" << endl;
}

//! Parses the command line and runs the benchmark
int main(int argc, char **argv)
	{

	// the name of the ForceCompute to benchmark (gotten from user)
	string nl_name;

	options_description desc("Allowed options");
	desc.add_options()
		("help,h", "Produce help message")
		("nparticles,N", value<unsigned int>(&N)->default_value(64000), "Number of particles")
		("phi_p", value<Scalar>(&phi_p)->default_value(0.2), "Volume fraction of particles in test system")
		("r_cut", value<Scalar>(&r_cut)->default_value(3.8), "Cutoff radius for pair force sum")
		//("r_buff", value<Scalar>(&r_buff)->default_value(0.8), "Buffer radius for pair force sum")
		("nthreads,t", value<unsigned int>(&nthreads)->default_value(1), "Number of threads to execute (for multithreaded computes)")
		("block_size", value<unsigned int>(&block_size)->default_value(128), "Block size for GPU computes")
		("quiet,q", value<bool>(&quiet)->default_value(false)->zero_tokens(), "Only output time per computation")
		("sort", value<bool>(&sort_particles)->default_value(true), "Sort particles with SFCPACK")
		("profile", value<bool>(&profile_compute)->default_value(true), "Profile GFLOPS and GB/s sustained")
		("half_nlist", value<bool>(&half_nlist)->default_value(true), "Only store 1/2 of the neighbors (optimization for some pair force computes")
		("nsec", value<unsigned int>(&nsec)->default_value(10), "Number of seconds to profile for")
		("nl_name,f", value<string>(&nl_name)->default_value("BinnedNl"), "NeighboorList to benchmark")
		;

	// parse the command line
	variables_map vm;
	try
		{
		store(parse_command_line(argc, argv, desc), vm);
		notify(vm);
		}
	catch (std::logic_error e)
		{
		// print help on error
		cerr << "Error parsing command line: " << e.what() << endl;
		cout << desc;
		cout << "Available ForceComputes are: ";
		cout << "Nl, BinnedNl";
		#ifdef USE_CUDA
		cout << ", BinnedNL.GPU, and Nl_NSQ.GPU";
		#endif
		cout << endl;

		exit(1);
		}

	//if (!quiet)
		//output_version_info(false);

	// if help is specified, print it
	if (vm.count("help"))
		{
		cout << desc;
		exit(1);
		}

	// initialize the particle data
	if (!quiet)
		cout << "Building particle data...";

	shared_ptr<ParticleData> pdata = init_pdata();
	cout << "done." << endl;

	// initialize the neighbor list
	if (!quiet)
		cout << "Building neighbor list data...";
	shared_ptr<NeighborList> nlist = init_neighboorlist_compute(nl_name, pdata);

	cout << "done." << endl;

	if (nl_name == "Nl" || nl_name == "BinnedNl"){
		if (half_nlist)
			nlist->setStorageMode(NeighborList::half);
		else
			nlist->setStorageMode(NeighborList::full);
	}
	nlist->setEvery(1);
	nlist->forceUpdate();
	nlist->compute(1);

	// count the average number of neighbors
	int64_t neigh_count = 0;
	vector< vector< unsigned int> > list = nlist->getList();
	for (unsigned int i = 0; i < N; i++)
		neigh_count += list[i].size();
	double avgNneigh = double(neigh_count) / double(N);

	/* Not needed for only benchmarking neighboor list creation

	// initialize the force compute
	shared_ptr<ForceCompute> fc = init_force_compute(fc_name, pdata, nlist);
	if (fc == NULL)
		{
		cerr << "Unrecognized force compute: " << fc_name << endl;
		exit(1);
		}

	if (!quiet)
		{
		cout << "Starting benchmarking of: " << fc_name << endl;
		cout << "nsec = " << nsec << " / N = " << N << " / phi_p = "<< phi_p << endl;
		cout << "sort_particles = " << sort_particles << " / half_nlist = " << half_nlist << endl;
		cout << "r_cut = " << r_cut << " / r_buff = " << r_buff << " / avg_n_neigh = " << avgNneigh << endl;
		cout << "nthreads = " << nthreads << " / block_size = " << block_size << endl;
		}

	*/

	benchmark(nlist);

	return 0;
	}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_COORD_HPP
#define MAPNIK_COORD_HPP

// boost
#include <boost/operators.hpp>

// stl
#include <iomanip>
#include <sstream>

namespace mapnik {
template <typename T,int dim>
struct coord {
    typedef T type;
};

template <typename T>
struct coord<T,2>
    : boost::addable<coord<T,2>,
                     boost::addable2<coord<T,2>,T,
                                     boost::subtractable<coord<T,2>,
                                                         boost::subtractable2<coord<T,2>,T,
                                                                              boost::dividable2<coord<T,2>, T,
                                                                                boost::multipliable2<coord<T,2>, T > > > > > >

{
    typedef T type;
    T x;
    T y;
public:
    coord()
        : x(),y() {}
    coord(T x_,T y_)
        : x(x_),y(y_) {}
    template <typename T2>
    coord (const coord<T2,2>& rhs)
        : x(type(rhs.x)),
          y(type(rhs.y)) {}

    coord<T,2>& operator=(coord<T,2> rhs)
    {
        std::swap(this->x, rhs.x);
        std::swap(this->y, rhs.y);
        return *this;
    }

    template <typename T2>
    coord<T,2>& operator=(const coord<T2,2>& rhs)
    {
        if ((void*)this==(void*)&rhs)
        {
            return *this;
        }
        x=type(rhs.x);
        y=type(rhs.y);
        return *this;
    }
    template <typename T2>
    bool operator==(coord<T2,2> const& rhs)
    {
        return x == rhs.x && y == rhs.y;
    }

    coord<T,2>& operator+=(coord<T,2> const& rhs)
    {
        x+=rhs.x;
        y+=rhs.y;
        return *this;
    }

    coord<T,2>& operator+=(T rhs)
    {
        x+=rhs;
        y+=rhs;
        return *this;
    }

    coord<T,2>& operator-=(coord<T,2> const& rhs)
    {
        x-=rhs.x;
        y-=rhs.y;
        return *this;
    }

    coord<T,2>& operator-=(T rhs)
    {
        x-=rhs;
        y-=rhs;
        return *this;
    }

    coord<T,2>& operator*=(T t)
    {
        x*=t;
        y*=t;
        return *this;
    }
    coord<T,2>& operator/=(T t)
    {
        x/=t;
        y/=t;
        return *this;
    }
};

template <typename T>
struct coord<T,3>
{
    typedef T type;
    T x;
    T y;
    T z;
public:
    coord()
        : x(),y(),z() {}
    coord(T x_,T y_,T z_)
        : x(x_),y(y_),z(z_) {}
    template <typename T2>
    coord (const coord<T2,3>& rhs)
        : x(type(rhs.x)),
          y(type(rhs.y)),
          z(type(rhs.z)) {}

    template <typename T2>
    coord<T,3>& operator=(const coord<T2,3>& rhs)
    {
        if ((void*)this==(void*)&rhs)
        {
            return *this;
        }
        x=type(rhs.x);
        y=type(rhs.y);
        z=type(rhs.z);
        return *this;
    }
};

typedef coord<double,2> coord2d;
typedef coord<int,2> coord2i;

template <typename charT,typename traits,typename T ,int dim>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,dim>& c);

template <typename charT,typename traits,typename T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,2>& c)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s << "coord2(" << std::setprecision(16)
      << c.x << "," << c.y<< ")";
    out << s.str();
    return out;
}

template <typename charT,typename traits,typename T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,3>& c)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s << "coord3(" << std::setprecision(16)
      << c.x << "," << c.y<< "," << c.z<<")";
    out << s.str();
    return out;
}
}

#endif // MAPNIK_COORD_HPP
<commit_msg>unify assignment op's<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_COORD_HPP
#define MAPNIK_COORD_HPP

// boost
#include <boost/operators.hpp>

// stl
#include <iomanip>
#include <sstream>

namespace mapnik {
template <typename T,int dim>
struct coord {
    typedef T type;
};

template <typename T>
struct coord<T,2>
    : boost::addable<coord<T,2>,
                     boost::addable2<coord<T,2>,T,
                                     boost::subtractable<coord<T,2>,
                                                         boost::subtractable2<coord<T,2>,T,
                                                                              boost::dividable2<coord<T,2>, T,
                                                                                boost::multipliable2<coord<T,2>, T > > > > > >

{
    typedef T type;
    T x;
    T y;
public:
    coord()
        : x(),y() {}
    coord(T x_,T y_)
        : x(x_),y(y_) {}
    template <typename T2>
    coord (const coord<T2,2>& rhs)
        : x(type(rhs.x)),
          y(type(rhs.y)) {}

    coord<T,2>& operator=(coord<T,2> rhs)
    {
        swap(rhs);
        return *this;
    }

    template <typename T2>
    coord<T,2>& operator=(const coord<T2,2>& rhs)
    {
        coord<T,2> tmp(rhs);
        swap(rhs);
        return *this;
    }

    template <typename T2>
    bool operator==(coord<T2,2> const& rhs)
    {
        return x == rhs.x && y == rhs.y;
    }

    coord<T,2>& operator+=(coord<T,2> const& rhs)
    {
        x+=rhs.x;
        y+=rhs.y;
        return *this;
    }

    coord<T,2>& operator+=(T rhs)
    {
        x+=rhs;
        y+=rhs;
        return *this;
    }

    coord<T,2>& operator-=(coord<T,2> const& rhs)
    {
        x-=rhs.x;
        y-=rhs.y;
        return *this;
    }

    coord<T,2>& operator-=(T rhs)
    {
        x-=rhs;
        y-=rhs;
        return *this;
    }

    coord<T,2>& operator*=(T t)
    {
        x*=t;
        y*=t;
        return *this;
    }
    coord<T,2>& operator/=(T t)
    {
        x/=t;
        y/=t;
        return *this;
    }
private:
    void swap(coord<T,2> & rhs)
    {
        std::swap(this->x, rhs.x);
        std::swap(this->y, rhs.y);
    }
};

template <typename T>
struct coord<T,3>
{
    typedef T type;
    T x;
    T y;
    T z;
public:
    coord()
        : x(),y(),z() {}
    coord(T x_,T y_,T z_)
        : x(x_),y(y_),z(z_) {}

    template <typename T2>
    coord (coord<T2,3> const& rhs)
        : x(type(rhs.x)),
          y(type(rhs.y)),
          z(type(rhs.z)) {}

    coord<T,3> operator=(coord<T,3> rhs)
    {
        swap(rhs);
        return *this;
    }

    template <typename T2>
    coord<T,3>& operator=(coord<T2,3> const& rhs)
    {
        coord<T,3> tmp(rhs);
        swap(tmp);
        return *this;
    }
private:
    void swap(coord<T,3> & rhs)
    {
        std::swap(this->x, rhs.x);
        std::swap(this->y, rhs.y);
        std::swap(this->z, rhs.z);
    }
};

typedef coord<double,2> coord2d;
typedef coord<int,2> coord2i;

template <typename charT,typename traits,typename T ,int dim>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,dim>& c);

template <typename charT,typename traits,typename T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,2>& c)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s << "coord2(" << std::setprecision(16)
      << c.x << "," << c.y<< ")";
    out << s.str();
    return out;
}

template <typename charT,typename traits,typename T>
inline std::basic_ostream<charT,traits>&
operator << (std::basic_ostream<charT,traits>& out,
             const coord<T,3>& c)
{
    std::basic_ostringstream<charT,traits> s;
    s.copyfmt(out);
    s.width(0);
    s << "coord3(" << std::setprecision(16)
      << c.x << "," << c.y<< "," << c.z<<")";
    out << s.str();
    return out;
}
}

#endif // MAPNIK_COORD_HPP
<|endoftext|>


<commit_before>#include "aikido/rviz/InteractiveMarkerViewer.hpp"

#include <dart/dart.hpp>

#include "aikido/common/memory.hpp"
#include "aikido/rviz/FrameMarker.hpp"
#include "aikido/rviz/SkeletonMarker.hpp"
#include "aikido/rviz/TrajectoryMarker.hpp"

using dart::dynamics::Skeleton;
using dart::dynamics::SkeletonPtr;
using interactive_markers::InteractiveMarkerServer;

namespace aikido {
namespace rviz {

//==============================================================================
InteractiveMarkerViewer::InteractiveMarkerViewer(
    const std::string& topicNamespace,
    const std::string& frameId,
    aikido::planner::WorldPtr env)
  : mMarkerServer(topicNamespace, "", true)
  , mTrajectoryNameManager("Trajectory Name Manager", "Trajectory")
  , mRunning(false)
  , mUpdating(false)
  , mFrameId(frameId)
  , mWorld(std::move(env))
{
  mTrajectoryNameManager.setPattern("Frame[%s(%d)]");
}

//==============================================================================
InteractiveMarkerViewer::~InteractiveMarkerViewer()
{
  mRunning.store(false, std::memory_order_release);
  mThread.join();
}

//==============================================================================
InteractiveMarkerServer& InteractiveMarkerViewer::marker_server()
{
  return mMarkerServer;
}

//==============================================================================
SkeletonMarkerPtr InteractiveMarkerViewer::addSkeletonMarker(
    const SkeletonPtr& skeleton)
{
  std::lock_guard<std::mutex> lock(mMutex);
  const SkeletonMarkerPtr marker = std::make_shared<SkeletonMarker>(
      nullptr, &mMarkerServer, skeleton, mFrameId);
  mSkeletonMarkers.emplace(skeleton, marker);
  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateSkeletonMarkers()
{
  // Update SkeletonMarkers from the world.
  if (mWorld)
  {
    for (std::size_t i = 0; i < mWorld->getNumSkeletons(); ++i)
    {
      const dart::dynamics::SkeletonPtr skeleton = mWorld->getSkeleton(i);
      if (skeleton)
      {
        // Adds skeleton if previously not in the world.
        mSkeletonMarkers.emplace(
            skeleton,
            std::make_shared<SkeletonMarker>(
                nullptr, &mMarkerServer, skeleton, mFrameId));
      }
    }
  }

  // Update existing skeletons, and delete erased skeletons.
  auto it = std::begin(mSkeletonMarkers);
  while (it != std::end(mSkeletonMarkers))
  {
    // If the skeleton is either a nullptr or no longer exists in an associated
    // world, delete.
    if (!it->first || (mWorld && !mWorld->hasSkeleton(it->first)))
    {
      it = mSkeletonMarkers.erase(it);
    }
    else
    {
      // In any other case, since the skeleton exists, update it, increment
      // iterator.
      std::unique_lock<std::mutex> skeleton_lock(
          it->first->getMutex(), std::try_to_lock);
      if (skeleton_lock.owns_lock())
      {
        it->second->update();
      }
      ++it;
    }
  }
}

//==============================================================================
FrameMarkerPtr InteractiveMarkerViewer::addFrameMarker(
    dart::dynamics::Frame* frame, double length, double thickness, double alpha)
{
  std::lock_guard<std::mutex> lock(mMutex);
  const FrameMarkerPtr marker = std::make_shared<FrameMarker>(
      &mMarkerServer, frame, mFrameId, length, thickness, alpha);
  mFrameMarkers.insert(marker);
  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateFrameMarkers()
{
  for (const auto& marker : mFrameMarkers)
    marker->update();
}

//==============================================================================
TSRMarkerPtr InteractiveMarkerViewer::addTSRMarker(
    const constraint::dart::TSR& tsr, int nSamples, const std::string& basename)
{
  using dart::dynamics::Frame;
  using dart::dynamics::SimpleFrame;

  auto sampler = tsr.createSampleGenerator();
  auto state = tsr.getSE3()->createState();

  std::string name;
  if (basename.empty())
  {
    std::ostringstream ost;
    ost << &tsr;
    name = ost.str();
  }
  else
  {
    name = basename;
  }

  std::vector<std::unique_ptr<SimpleFrame>> tsrFrames;
  tsrFrames.reserve(nSamples);

  for (int i = 0; i < nSamples && sampler->canSample(); ++i)
  {
    auto sampled = sampler->sample(state);
    assert(sampled);
    DART_UNUSED(sampled);

    std::stringstream ss;
    ss << "TSRMarker[" << name << "].frame[" << i << "]";

    auto tsrFrame = ::aikido::common::make_unique<SimpleFrame>(
        Frame::World(), ss.str(), state.getIsometry());
    addFrameMarker(tsrFrame.get());
    tsrFrames.emplace_back(std::move(tsrFrame));
  }

  auto tsrMarker = std::make_shared<TSRMarker>(std::move(tsrFrames));
  return tsrMarker;
}

//==============================================================================
TrajectoryMarkerPtr InteractiveMarkerViewer::addTrajectoryMarker(
    trajectory::ConstTrajectoryPtr trajectory,
    dart::dynamics::MetaSkeletonPtr skeleton,
    const dart::dynamics::Frame& frame,
    const Eigen::Vector4d& rgba,
    double thickness,
    std::size_t numLineSegments)
{
  std::lock_guard<std::mutex> lock(mMutex);
  DART_UNUSED(lock);
  auto marker = std::make_shared<TrajectoryMarker>(
      &mMarkerServer,
      mFrameId,
      mTrajectoryNameManager.issueNewNameAndAdd("", trajectory),
      std::move(trajectory),
      std::move(skeleton),
      frame,
      rgba,
      thickness,
      numLineSegments);
  mTrajectoryMarkers.insert(marker);

  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateTrajectoryMarkers()
{
  for (const auto& marker : mTrajectoryMarkers)
    marker->update();
}

//==============================================================================
void InteractiveMarkerViewer::setAutoUpdate(bool flag)
{
  mUpdating.store(flag, std::memory_order_release);

  const bool wasRunning = mRunning.exchange(flag);
  if (flag && !wasRunning)
    mThread = std::thread(&InteractiveMarkerViewer::autoUpdate, this);
  else if (!flag && wasRunning)
    mThread.join();
}

//==============================================================================
void InteractiveMarkerViewer::autoUpdate()
{
  ros::Rate rate(30);

  while (mRunning.load() && ros::ok())
  {
    update();
    rate.sleep();
  }

  mRunning.store(false);
}

//==============================================================================
void InteractiveMarkerViewer::update()
{
  std::lock_guard<std::mutex> lock(mMutex);

  // Update skeleton markers.
  updateSkeletonMarkers();

  // Update frame markers.
  updateFrameMarkers();

  // Update trajectory markers.
  updateTrajectoryMarkers();

  // Apply changes anytime a marker has been modified.
  mMarkerServer.applyChanges();
}

} // namespace rviz
} // namespace aikido
<commit_msg>Set the interactive marker viewer to autoupdate by default. (#589)<commit_after>#include "aikido/rviz/InteractiveMarkerViewer.hpp"

#include <dart/dart.hpp>

#include "aikido/common/memory.hpp"
#include "aikido/rviz/FrameMarker.hpp"
#include "aikido/rviz/SkeletonMarker.hpp"
#include "aikido/rviz/TrajectoryMarker.hpp"

using dart::dynamics::Skeleton;
using dart::dynamics::SkeletonPtr;
using interactive_markers::InteractiveMarkerServer;

namespace aikido {
namespace rviz {

//==============================================================================
InteractiveMarkerViewer::InteractiveMarkerViewer(
    const std::string& topicNamespace,
    const std::string& frameId,
    aikido::planner::WorldPtr env)
  : mMarkerServer(topicNamespace, "", true)
  , mTrajectoryNameManager("Trajectory Name Manager", "Trajectory")
  , mRunning(false)
  , mUpdating(false)
  , mFrameId(frameId)
  , mWorld(std::move(env))
{
  mTrajectoryNameManager.setPattern("Frame[%s(%d)]");
  // Set the viewer to update by default.
  setAutoUpdate(true);
}

//==============================================================================
InteractiveMarkerViewer::~InteractiveMarkerViewer()
{
  mRunning.store(false, std::memory_order_release);
  mThread.join();
}

//==============================================================================
InteractiveMarkerServer& InteractiveMarkerViewer::marker_server()
{
  return mMarkerServer;
}

//==============================================================================
SkeletonMarkerPtr InteractiveMarkerViewer::addSkeletonMarker(
    const SkeletonPtr& skeleton)
{
  std::lock_guard<std::mutex> lock(mMutex);
  const SkeletonMarkerPtr marker = std::make_shared<SkeletonMarker>(
      nullptr, &mMarkerServer, skeleton, mFrameId);
  mSkeletonMarkers.emplace(skeleton, marker);
  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateSkeletonMarkers()
{
  // Update SkeletonMarkers from the world.
  if (mWorld)
  {
    for (std::size_t i = 0; i < mWorld->getNumSkeletons(); ++i)
    {
      const dart::dynamics::SkeletonPtr skeleton = mWorld->getSkeleton(i);
      if (skeleton)
      {
        // Adds skeleton if previously not in the world.
        mSkeletonMarkers.emplace(
            skeleton,
            std::make_shared<SkeletonMarker>(
                nullptr, &mMarkerServer, skeleton, mFrameId));
      }
    }
  }

  // Update existing skeletons, and delete erased skeletons.
  auto it = std::begin(mSkeletonMarkers);
  while (it != std::end(mSkeletonMarkers))
  {
    // If the skeleton is either a nullptr or no longer exists in an associated
    // world, delete.
    if (!it->first || (mWorld && !mWorld->hasSkeleton(it->first)))
    {
      it = mSkeletonMarkers.erase(it);
    }
    else
    {
      // In any other case, since the skeleton exists, update it, increment
      // iterator.
      std::unique_lock<std::mutex> skeleton_lock(
          it->first->getMutex(), std::try_to_lock);
      if (skeleton_lock.owns_lock())
      {
        it->second->update();
      }
      ++it;
    }
  }
}

//==============================================================================
FrameMarkerPtr InteractiveMarkerViewer::addFrameMarker(
    dart::dynamics::Frame* frame, double length, double thickness, double alpha)
{
  std::lock_guard<std::mutex> lock(mMutex);
  const FrameMarkerPtr marker = std::make_shared<FrameMarker>(
      &mMarkerServer, frame, mFrameId, length, thickness, alpha);
  mFrameMarkers.insert(marker);
  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateFrameMarkers()
{
  for (const auto& marker : mFrameMarkers)
    marker->update();
}

//==============================================================================
TSRMarkerPtr InteractiveMarkerViewer::addTSRMarker(
    const constraint::dart::TSR& tsr, int nSamples, const std::string& basename)
{
  using dart::dynamics::Frame;
  using dart::dynamics::SimpleFrame;

  auto sampler = tsr.createSampleGenerator();
  auto state = tsr.getSE3()->createState();

  std::string name;
  if (basename.empty())
  {
    std::ostringstream ost;
    ost << &tsr;
    name = ost.str();
  }
  else
  {
    name = basename;
  }

  std::vector<std::unique_ptr<SimpleFrame>> tsrFrames;
  tsrFrames.reserve(nSamples);

  for (int i = 0; i < nSamples && sampler->canSample(); ++i)
  {
    auto sampled = sampler->sample(state);
    assert(sampled);
    DART_UNUSED(sampled);

    std::stringstream ss;
    ss << "TSRMarker[" << name << "].frame[" << i << "]";

    auto tsrFrame = ::aikido::common::make_unique<SimpleFrame>(
        Frame::World(), ss.str(), state.getIsometry());
    addFrameMarker(tsrFrame.get());
    tsrFrames.emplace_back(std::move(tsrFrame));
  }

  auto tsrMarker = std::make_shared<TSRMarker>(std::move(tsrFrames));
  return tsrMarker;
}

//==============================================================================
TrajectoryMarkerPtr InteractiveMarkerViewer::addTrajectoryMarker(
    trajectory::ConstTrajectoryPtr trajectory,
    dart::dynamics::MetaSkeletonPtr skeleton,
    const dart::dynamics::Frame& frame,
    const Eigen::Vector4d& rgba,
    double thickness,
    std::size_t numLineSegments)
{
  std::lock_guard<std::mutex> lock(mMutex);
  DART_UNUSED(lock);
  auto marker = std::make_shared<TrajectoryMarker>(
      &mMarkerServer,
      mFrameId,
      mTrajectoryNameManager.issueNewNameAndAdd("", trajectory),
      std::move(trajectory),
      std::move(skeleton),
      frame,
      rgba,
      thickness,
      numLineSegments);
  mTrajectoryMarkers.insert(marker);

  return marker;
}

//==============================================================================
void InteractiveMarkerViewer::updateTrajectoryMarkers()
{
  for (const auto& marker : mTrajectoryMarkers)
    marker->update();
}

//==============================================================================
void InteractiveMarkerViewer::setAutoUpdate(bool flag)
{
  mUpdating.store(flag, std::memory_order_release);

  const bool wasRunning = mRunning.exchange(flag);
  if (flag && !wasRunning)
    mThread = std::thread(&InteractiveMarkerViewer::autoUpdate, this);
  else if (!flag && wasRunning)
    mThread.join();
}

//==============================================================================
void InteractiveMarkerViewer::autoUpdate()
{
  ros::Rate rate(30);

  while (mRunning.load() && ros::ok())
  {
    update();
    rate.sleep();
  }

  mRunning.store(false);
}

//==============================================================================
void InteractiveMarkerViewer::update()
{
  std::lock_guard<std::mutex> lock(mMutex);

  // Update skeleton markers.
  updateSkeletonMarkers();

  // Update frame markers.
  updateFrameMarkers();

  // Update trajectory markers.
  updateTrajectoryMarkers();

  // Apply changes anytime a marker has been modified.
  mMarkerServer.applyChanges();
}

} // namespace rviz
} // namespace aikido
<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_loop/message_loop.h"
#include "mojo/public/bindings/allocation_scope.h"
#include "mojo/public/bindings/remote_ptr.h"
#include "mojo/shell/service_connector.h"
#include "mojom/shell.h"
#include "mojom/test.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace shell {
namespace {

class TestApp : public ShellClient {
 public:
  TestApp(ScopedMessagePipeHandle shell_handle)
      : shell_(shell_handle.Pass(), this) {
  }
  virtual ~TestApp() {
  }
  virtual void AcceptConnection(ScopedMessagePipeHandle client_handle)
      MOJO_OVERRIDE {
    service_.reset(new TestServiceImpl(this, client_handle.Pass()));
  }
  std::string GetLastTestString() {
    return service_->last_test_string_;
  }

 private:
  class TestServiceImpl : public TestService {
   public:
    TestServiceImpl(TestApp* service, ScopedMessagePipeHandle client_handle)
        : service_(service),
          client_(client_handle.Pass(), this) {
    }
    virtual ~TestServiceImpl() {
    }
    virtual void Test(const mojo::String& test_string) OVERRIDE {
      last_test_string_ = test_string.To<std::string>();
      client_->AckTest();
    }
    TestApp* service_;
    RemotePtr<TestClient> client_;
    std::string last_test_string_;
  };
  RemotePtr<Shell> shell_;
  scoped_ptr<TestServiceImpl> service_;
};

class TestClientImpl : public TestClient {
 public:
  explicit TestClientImpl(ScopedMessagePipeHandle service_handle)
      : service_(service_handle.Pass(), this),
        quit_after_ack_(false) {
  }
  virtual ~TestClientImpl() {
  }
  virtual void AckTest() OVERRIDE {
    if (quit_after_ack_)
      base::MessageLoop::current()->QuitNow();
  }
  void Test(std::string test_string) {
    AllocationScope scope;
    quit_after_ack_ = true;
    service_->Test(mojo::String(test_string));
  }
  RemotePtr<TestService> service_;
  bool quit_after_ack_;
};

class ServiceConnectorTest : public testing::Test,
                             public ServiceConnector::Loader {
 public:
  ServiceConnectorTest() {
  }

  virtual ~ServiceConnectorTest() {
  }

  virtual void SetUp() OVERRIDE {
    GURL test_url("test:testService");
    service_connector_.reset(new ServiceConnector);
    service_connector_->SetLoaderForURL(this, test_url);
    MessagePipe pipe;
    test_client_.reset(new TestClientImpl(pipe.handle0.Pass()));
    service_connector_->Connect(test_url, pipe.handle1.Pass());
  }

  virtual void TearDown() OVERRIDE {
    test_client_.reset(NULL);
    test_app_.reset(NULL);
    service_connector_.reset(NULL);
  }

  virtual void Load(const GURL& url,
                    ScopedMessagePipeHandle shell_handle) OVERRIDE {
    test_app_.reset(new TestApp(shell_handle.Pass()));
  }

 protected:
  base::MessageLoop loop_;
  scoped_ptr<TestApp> test_app_;
  scoped_ptr<TestClientImpl> test_client_;
  scoped_ptr<ServiceConnector> service_connector_;
  DISALLOW_COPY_AND_ASSIGN(ServiceConnectorTest);
};

TEST_F(ServiceConnectorTest, Basic) {
  test_client_->Test("test");
  loop_.Run();
  EXPECT_EQ(std::string("test"), test_app_->GetLastTestString());
}

}  // namespace
}  // namespace shell
}  // namespace mojo
<commit_msg>Modify service_connector_unitttest to use Service<><commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/message_loop/message_loop.h"
#include "mojo/public/bindings/allocation_scope.h"
#include "mojo/public/bindings/remote_ptr.h"
#include "mojo/public/shell/service.h"
#include "mojo/shell/service_connector.h"
#include "mojom/shell.h"
#include "mojom/test.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace shell {
namespace {

struct Context {
  std::string last_test_string;
};

class TestServiceImpl : public Service<TestService, TestServiceImpl, Context> {
 public:
  virtual void Test(const mojo::String& test_string) OVERRIDE {
    context()->last_test_string = test_string.To<std::string>();
    client()->AckTest();
  }
};

class TestClientImpl : public TestClient {
 public:
  explicit TestClientImpl(ScopedMessagePipeHandle service_handle)
      : service_(service_handle.Pass(), this),
        quit_after_ack_(false) {
  }
  virtual ~TestClientImpl() {
  }
  virtual void AckTest() OVERRIDE {
    if (quit_after_ack_)
      base::MessageLoop::current()->QuitNow();
  }
  void Test(std::string test_string) {
    AllocationScope scope;
    quit_after_ack_ = true;
    service_->Test(mojo::String(test_string));
  }
  RemotePtr<TestService> service_;
  bool quit_after_ack_;
};

class ServiceConnectorTest : public testing::Test,
                             public ServiceConnector::Loader {
 public:
  ServiceConnectorTest() {
  }

  virtual ~ServiceConnectorTest() {
  }

  virtual void SetUp() OVERRIDE {
    GURL test_url("test:testService");
    service_connector_.reset(new ServiceConnector);
    service_connector_->SetLoaderForURL(this, test_url);
    MessagePipe pipe;
    test_client_.reset(new TestClientImpl(pipe.handle0.Pass()));
    service_connector_->Connect(test_url, pipe.handle1.Pass());
  }

  virtual void TearDown() OVERRIDE {
    test_client_.reset(NULL);
    test_app_.reset(NULL);
    service_connector_.reset(NULL);
  }

  virtual void Load(const GURL& url,
                    ScopedMessagePipeHandle shell_handle) OVERRIDE {
    test_app_.reset(new ServiceFactory<TestServiceImpl, Context>(
        shell_handle.Pass(), &context_));
  }

 protected:
  base::MessageLoop loop_;
  Context context_;
  scoped_ptr<ServiceFactory<TestServiceImpl, Context> > test_app_;
  scoped_ptr<TestClientImpl> test_client_;
  scoped_ptr<ServiceConnector> service_connector_;
  DISALLOW_COPY_AND_ASSIGN(ServiceConnectorTest);
};

TEST_F(ServiceConnectorTest, Basic) {
  test_client_->Test("test");
  loop_.Run();
  EXPECT_EQ(std::string("test"), context_.last_test_string);
}

}  // namespace
}  // namespace shell
}  // namespace mojo
<|endoftext|>