<commit_before>#include "sshtunnelout.h"
#include "sshclient.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <cerrno>
#include <QMutexLocker>

Q_LOGGING_CATEGORY(logsshtunnelout, "ssh.tunnelout", QtWarningMsg)

SshTunnelOut::SshTunnelOut(SshClient *client, QTcpSocket *tcpSocket, const QString &port_identifier, quint16 port, QObject *parent):
    QObject(parent),
    m_port(port),
    m_name(port_identifier),
    m_tcpsocket(tcpSocket),
    m_client(client),
    m_dataSsh(16384, 0),
    m_dataSocket(16384, 0),
    m_retryChannelCreation(20)
{
    QObject::connect(m_tcpsocket, &QTcpSocket::disconnected,   this, &SshTunnelOut::tcpDisconnected);
    QObject::connect(m_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)),   this, SLOT(displayError(QAbstractSocket::SocketError)));

    qCDebug(logsshtunnelout) << "SshTunnelOut::SshTunnelOut() OK " << m_name;
    QTimer::singleShot(0, this, &SshTunnelOut::_init_channel);
}

SshTunnelOut::~SshTunnelOut()
{
    qCDebug(logsshtunnelout) << "~SshTunnelOut() " << m_name << " " << this;
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }

    if (m_sshChannel == nullptr)
        return;

    int ret = qssh2_channel_close(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_close: LIBSSH2_ERROR_SOCKET_SEND";
        return;
    }

    ret = qssh2_channel_wait_closed(m_sshChannel);
    if(ret)
    {
        qDebug(logsshtunnelout) << "Failed to channel_wait_closed";
        return;
    }

    ret = qssh2_channel_free(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_free";
        return;
    }
}

void SshTunnelOut::_init_channel()
{
    if(m_sshChannel == nullptr)
    {
        if ( ! m_client->takeChannelCreationMutex(this) )
        {
            qCDebug(logsshtunnelout) << "Initchannel have to wait for its tunnel creation" << m_port;
            QTimer::singleShot(50, this, &SshTunnelOut::_init_channel);
            return;
        }
        qCDebug(logsshtunnelout) << "Initchannel" << m_name << m_port;
        m_sshChannel = qssh2_channel_direct_tcpip(m_client->session(),  "127.0.0.1", m_port);

        if(m_sshChannel == nullptr)
        {
            int ret = qssh2_session_last_error(m_client->session(), nullptr, nullptr, 0);
            if(ret == LIBSSH2_ERROR_CHANNEL_FAILURE)
            {
                qCCritical(logsshtunnelout) << "Error channel failure " << " for port " << m_port;
            }
            else if (ret == LIBSSH2_ERROR_EAGAIN)
            {
                if ( m_retryChannelCreation )
                {
                    qCDebug(logsshtunnelout) << "Will retry channel creation later";
                    QTimer::singleShot(50, this, &SshTunnelOut::_init_channel);
                    m_retryChannelCreation--;
                }
                else
                {
                    qCCritical(logsshtunnelout) << "Out of retries for channel creation, channel creation failed " <<"for port" << m_port;
                }
            }
            else
            {
                qCCritical(logsshtunnelout) << "Error during channel creation, code:" << ret <<",for port" << m_port;
            }
            return;
        }
        else
        {
            QObject::connect(m_client,    &SshClient::sshDataReceived, this, &SshTunnelOut::sshDataReceived);
            QObject::connect(m_tcpsocket, &QTcpSocket::readyRead,      this, &SshTunnelOut::tcpDataReceived);
            m_client->releaseChannelCreationMutex(this);
            // If there is some data to read try processing them
            if ( m_tcpsocket->bytesAvailable())
            {
                QTimer::singleShot(0, this, &SshTunnelOut::tcpDataReceived);
            }
            QTimer::singleShot(0, this, &SshTunnelOut::sshDataReceived);
        }
    }
}

void SshTunnelOut::disconectFromHost()
{
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }
}

QString SshTunnelOut::name() const
{
    return m_name;
}

void SshTunnelOut::sshDataReceived()
{
    qCDebug(logsshtunnelout) << "SshTunnelOut::sshDataReceived() " << m_name << m_sshChannel;
    ssize_t len = 0,wr = 0;
    qint64 i;

    do
    {
        /* Read data from SSH */
        /*
         * In this case, we must not used qssh2_channel_read
         * beacause we don't need to ProcessEvent to be locked
         * We can return, we will be recall at the next sshDataReceived
         */
        len = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_dataSsh.data(), static_cast<unsigned int>(m_dataSsh.size())));
        //qCDebug(logsshtunnelout) << "SshTunnelOut::sshDataReceived() read" << len;
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            return;
        }
        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " remote failed to read (" << len << " / " << m_dataSsh.size() << ")";
            return;
        }

        /* Write data into output local socket */
        wr = 0;
        if(m_tcpsocket != nullptr)
        {
            while (wr < len)
            {
                i = m_tcpsocket->write( m_dataSsh.mid(static_cast<int>(wr), static_cast<int>(len)));
                if (i <= 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " local failed to write (" << i << ")";
                    return;
                }
                wr += i;
            }
        }
    }
    while(len == m_dataSsh.size());

    if (libssh2_channel_eof(m_sshChannel))
    {
        if(m_tcpsocket)
            m_tcpsocket->disconnectFromHost();
        qCDebug(logsshtunnelout) << "Disconnected from ssh";
        emit disconnectedFromSsh();
    }
}

void SshTunnelOut::tcpDataReceived()
{
    qCDebug(logsshtunnelout) << "SshTunnelOut::tcpDataReceived() In";
    qint64 len = 0;
    ssize_t wr = 0;
    ssize_t i = 0;

    if (m_tcpsocket == nullptr || m_sshChannel == nullptr)
    {
        qCWarning(logsshtunnelout) <<  "ERROR : SshTunnelOut(" << m_name << ") : received TCP data but not seems to be a valid Tcp socket or channel not ready";
        return;
    }

    do
    {
        /* Read data from local socket */
        len = m_tcpsocket->read(m_dataSocket.data(), m_dataSocket.length());
        if (-EAGAIN == len)
        {
            qCDebug(logsshtunnelout) << m_name << "tcpDataReceived() EAGAIN";
            break;
        }

        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " local failed to read (" << len << ")";
            return;
        }

        if(len > 0 )
        {
            do
            {
                i = qssh2_channel_write(m_sshChannel, m_dataSocket.data(), static_cast<size_t>(len));
                if (i < 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " remote failed to write (" << i << ")";
                    return;
                }
                if (i == 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " qssh2_channel_write return 0";
                }
                wr += i;
            } while(i > 0 && wr < len);
        }

    }
    while(len > 0);
}

void SshTunnelOut::tcpDisconnected()
{
    qCDebug(logsshtunnelout) << "Disconnected from socket";
    m_tcpsocket->deleteLater();
    m_tcpsocket = nullptr;
    qssh2_channel_send_eof(m_sshChannel);
    emit disconnectedFromTcp();
}

void SshTunnelOut::displayError(QAbstractSocket::SocketError error)
{
    qCWarning(logsshtunnelout) << "ERROR : SshTunnelOut(" << m_name << ") : redirection socket error=" << error;
}

<commit_msg>Do not manage QAbstractSocket::RemoteHostClosedError has an error because case is handled properly.<commit_after>#include "sshtunnelout.h"
#include "sshclient.h"
#include <QTcpServer>
#include <QTcpSocket>
#include <cerrno>
#include <QMutexLocker>

Q_LOGGING_CATEGORY(logsshtunnelout, "ssh.tunnelout", QtWarningMsg)

SshTunnelOut::SshTunnelOut(SshClient *client, QTcpSocket *tcpSocket, const QString &port_identifier, quint16 port, QObject *parent):
    QObject(parent),
    m_port(port),
    m_name(port_identifier),
    m_tcpsocket(tcpSocket),
    m_client(client),
    m_dataSsh(16384, 0),
    m_dataSocket(16384, 0),
    m_retryChannelCreation(20)
{
    QObject::connect(m_tcpsocket, &QTcpSocket::disconnected,   this, &SshTunnelOut::tcpDisconnected);
    QObject::connect(m_tcpsocket, SIGNAL(error(QAbstractSocket::SocketError)),   this, SLOT(displayError(QAbstractSocket::SocketError)));

    qCDebug(logsshtunnelout) << "SshTunnelOut::SshTunnelOut() OK " << m_name;
    QTimer::singleShot(0, this, &SshTunnelOut::_init_channel);
}

SshTunnelOut::~SshTunnelOut()
{
    qCDebug(logsshtunnelout) << "~SshTunnelOut() " << m_name << " " << this;
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }

    if (m_sshChannel == nullptr)
        return;

    int ret = qssh2_channel_close(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_close: LIBSSH2_ERROR_SOCKET_SEND";
        return;
    }

    ret = qssh2_channel_wait_closed(m_sshChannel);
    if(ret)
    {
        qDebug(logsshtunnelout) << "Failed to channel_wait_closed";
        return;
    }

    ret = qssh2_channel_free(m_sshChannel);
    if(ret)
    {
        qCDebug(logsshtunnelout) << "Failed to channel_free";
        return;
    }
}

void SshTunnelOut::_init_channel()
{
    if(m_sshChannel == nullptr)
    {
        if ( ! m_client->takeChannelCreationMutex(this) )
        {
            qCDebug(logsshtunnelout) << "Initchannel have to wait for its tunnel creation" << m_port;
            QTimer::singleShot(50, this, &SshTunnelOut::_init_channel);
            return;
        }
        qCDebug(logsshtunnelout) << "Initchannel" << m_name << m_port;
        m_sshChannel = qssh2_channel_direct_tcpip(m_client->session(),  "127.0.0.1", m_port);

        if(m_sshChannel == nullptr)
        {
            int ret = qssh2_session_last_error(m_client->session(), nullptr, nullptr, 0);
            if(ret == LIBSSH2_ERROR_CHANNEL_FAILURE)
            {
                qCCritical(logsshtunnelout) << "Error channel failure " << " for port " << m_port;
            }
            else if (ret == LIBSSH2_ERROR_EAGAIN)
            {
                if ( m_retryChannelCreation )
                {
                    qCDebug(logsshtunnelout) << "Will retry channel creation later";
                    QTimer::singleShot(50, this, &SshTunnelOut::_init_channel);
                    m_retryChannelCreation--;
                }
                else
                {
                    qCCritical(logsshtunnelout) << "Out of retries for channel creation, channel creation failed " <<"for port" << m_port;
                }
            }
            else
            {
                qCCritical(logsshtunnelout) << "Error during channel creation, code:" << ret <<",for port" << m_port;
            }
            return;
        }
        else
        {
            QObject::connect(m_client,    &SshClient::sshDataReceived, this, &SshTunnelOut::sshDataReceived);
            QObject::connect(m_tcpsocket, &QTcpSocket::readyRead,      this, &SshTunnelOut::tcpDataReceived);
            m_client->releaseChannelCreationMutex(this);
            // If there is some data to read try processing them
            if ( m_tcpsocket->bytesAvailable())
            {
                QTimer::singleShot(0, this, &SshTunnelOut::tcpDataReceived);
            }
            QTimer::singleShot(0, this, &SshTunnelOut::sshDataReceived);
        }
    }
}

void SshTunnelOut::disconectFromHost()
{
    if(m_tcpsocket && (m_tcpsocket->state() == QAbstractSocket::ConnectedState))
    {
        m_tcpsocket->disconnectFromHost();
    }
}

QString SshTunnelOut::name() const
{
    return m_name;
}

void SshTunnelOut::sshDataReceived()
{
    qCDebug(logsshtunnelout) << "SshTunnelOut::sshDataReceived() " << m_name << m_sshChannel;
    ssize_t len = 0,wr = 0;
    qint64 i;

    do
    {
        /* Read data from SSH */
        /*
         * In this case, we must not used qssh2_channel_read
         * beacause we don't need to ProcessEvent to be locked
         * We can return, we will be recall at the next sshDataReceived
         */
        len = static_cast<ssize_t>(libssh2_channel_read(m_sshChannel, m_dataSsh.data(), static_cast<unsigned int>(m_dataSsh.size())));
        //qCDebug(logsshtunnelout) << "SshTunnelOut::sshDataReceived() read" << len;
        if(len == LIBSSH2_ERROR_EAGAIN)
        {
            return;
        }
        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " remote failed to read (" << len << " / " << m_dataSsh.size() << ")";
            return;
        }

        /* Write data into output local socket */
        wr = 0;
        if(m_tcpsocket != nullptr)
        {
            while (wr < len)
            {
                i = m_tcpsocket->write( m_dataSsh.mid(static_cast<int>(wr), static_cast<int>(len)));
                if (i <= 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " local failed to write (" << i << ")";
                    return;
                }
                wr += i;
            }
        }
    }
    while(len == m_dataSsh.size());

    if (libssh2_channel_eof(m_sshChannel))
    {
        if(m_tcpsocket)
            m_tcpsocket->disconnectFromHost();
        qCDebug(logsshtunnelout) << "Disconnected from ssh";
        emit disconnectedFromSsh();
    }
}

void SshTunnelOut::tcpDataReceived()
{
    qCDebug(logsshtunnelout) << "SshTunnelOut::tcpDataReceived() In";
    qint64 len = 0;
    ssize_t wr = 0;
    ssize_t i = 0;

    if (m_tcpsocket == nullptr || m_sshChannel == nullptr)
    {
        qCWarning(logsshtunnelout) <<  "ERROR : SshTunnelOut(" << m_name << ") : received TCP data but not seems to be a valid Tcp socket or channel not ready";
        return;
    }

    do
    {
        /* Read data from local socket */
        len = m_tcpsocket->read(m_dataSocket.data(), m_dataSocket.length());
        if (-EAGAIN == len)
        {
            qCDebug(logsshtunnelout) << m_name << "tcpDataReceived() EAGAIN";
            break;
        }

        if (len < 0)
        {
            qCWarning(logsshtunnelout) <<  "ERROR : " << m_name << " local failed to read (" << len << ")";
            return;
        }

        if(len > 0 )
        {
            do
            {
                i = qssh2_channel_write(m_sshChannel, m_dataSocket.data(), static_cast<size_t>(len));
                if (i < 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " remote failed to write (" << i << ")";
                    return;
                }
                if (i == 0)
                {
                    qCWarning(logsshtunnelout) << "ERROR : " << m_name << " qssh2_channel_write return 0";
                }
                wr += i;
            } while(i > 0 && wr < len);
        }

    }
    while(len > 0);
}

void SshTunnelOut::tcpDisconnected()
{
    qCDebug(logsshtunnelout) << "Disconnected from socket";
    m_tcpsocket->deleteLater();
    m_tcpsocket = nullptr;
    qssh2_channel_send_eof(m_sshChannel);
    emit disconnectedFromTcp();
}

void SshTunnelOut::displayError(QAbstractSocket::SocketError error)
{
    switch(error)
    {
    case QAbstractSocket::RemoteHostClosedError:
        // Socket will be closed just after this, nothing to care about
        break;
    default:
        qCWarning(logsshtunnelout) << "ERROR : SshTunnelOut(" << m_name << ") : redirection socket error=" << error;
    }
}
<|endoftext|>


<commit_before>#ifdef UART_INTERFACES
#if UART_INTERFACES > 0

#include "unity/src/unity.h"
#include "unity/Helpers.h"
#include "board/Board.h"
#include "common/OpenDeckMIDIformat/OpenDeckMIDIformat.h"
#include "core/src/general/RingBuffer.h"

#define TEST_MIDI_CHANNEL 0
#define BUFFER_SIZE       50

namespace
{
    auto                                   rebootType = Board::rebootType_t::rebootApp;
    core::RingBuffer<uint8_t, BUFFER_SIZE> buffer;
}    // namespace

namespace Board
{
    namespace io
    {
        void ledFlashStartup(bool fwUpdated)
        {
        }

        void writeLEDstate(uint8_t ledID, bool state)
        {
        }
    }    // namespace io

    void reboot(Board::rebootType_t type)
    {
        rebootType = type;
    }

    namespace UART
    {
        bool read(uint8_t channel, uint8_t& data)
        {
            return buffer.remove(data);
        }

        bool write(uint8_t channel, uint8_t data)
        {
            TEST_ASSERT(buffer.insert(data) == true);
            return true;
        }
    }    // namespace UART
}    // namespace Board

TEST_CASE(MIDI)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(MIDI::messageType_t::noteOn);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    TEST_ASSERT(OpenDeckMIDIformat::write(TEST_MIDI_CHANNEL, sending, OpenDeckMIDIformat::packetType_t::midi) == true);
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::midi);

    TEST_ASSERT(receiving.Event == static_cast<uint8_t>(MIDI::messageType_t::noteOn));
    TEST_ASSERT(receiving.Data1 == 0x10);
    TEST_ASSERT(receiving.Data2 == 0x20);
    TEST_ASSERT(receiving.Data3 == 0x30);

    //nothing left in the buffer - read should return false
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
}

TEST_CASE(InternalCMD)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(OpenDeckMIDIformat::command_t::btldrReboot);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    //change the state to app reboot first - after reading this should be switched to rebootBtldr
    rebootType = Board::rebootType_t::rebootApp;

    TEST_ASSERT(OpenDeckMIDIformat::write(TEST_MIDI_CHANNEL, sending, OpenDeckMIDIformat::packetType_t::internalCommand) == true);
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::internalCommand);

    //in case of internal commands, Event, Data1, Data2 and Data3 are fully ignored - only the
    //specific function is called
    TEST_ASSERT(rebootType == Board::rebootType_t::rebootBtldr);

    //nothing left in the buffer - read should return false
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
}

TEST_CASE(ManualPacketBuilding)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(OpenDeckMIDIformat::command_t::btldrReboot);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    uint8_t dataXor = sending.Event ^ sending.Data1 ^ sending.Data2 ^ sending.Data3;

    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, dataXor));

    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    //now send the same packet but with XOR byte being wrong
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, 0x00));

    rebootType = Board::rebootType_t::rebootApp;

    //read should return false and btldr reboot function shouldn't be called
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
    TEST_ASSERT(rebootType == Board::rebootType_t::rebootApp);

    //try building valid packet, and then start another one in the middle without first one being finished properly
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    //now start another one
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, dataXor));

    //there are several reads now which should return failure:
    //5 more failed reads until wrong XOR packet is cleared out of memory
    //2 more failed reads for first two bytes
    for (int i = 0; i < 7; i++)
        TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);

    //next read should return success
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);
    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::internalCommand);
    rebootType = Board::rebootType_t::rebootBtldr;
}

#endif
#endif
<commit_msg>tests: cleanup<commit_after>#ifdef UART_INTERFACES
#if UART_INTERFACES > 0

#include "unity/src/unity.h"
#include "unity/Helpers.h"
#include "board/Board.h"
#include "common/OpenDeckMIDIformat/OpenDeckMIDIformat.h"
#include "core/src/general/RingBuffer.h"

#define TEST_MIDI_CHANNEL 0
#define BUFFER_SIZE       50

namespace
{
    auto                                   rebootType = Board::rebootType_t::rebootApp;
    core::RingBuffer<uint8_t, BUFFER_SIZE> buffer;
}    // namespace

namespace Board
{
    void reboot(Board::rebootType_t type)
    {
        rebootType = type;
    }

    namespace UART
    {
        bool read(uint8_t channel, uint8_t& data)
        {
            return buffer.remove(data);
        }

        bool write(uint8_t channel, uint8_t data)
        {
            TEST_ASSERT(buffer.insert(data) == true);
            return true;
        }
    }    // namespace UART
}    // namespace Board

TEST_CASE(MIDI)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(MIDI::messageType_t::noteOn);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    TEST_ASSERT(OpenDeckMIDIformat::write(TEST_MIDI_CHANNEL, sending, OpenDeckMIDIformat::packetType_t::midi) == true);
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::midi);

    TEST_ASSERT(receiving.Event == static_cast<uint8_t>(MIDI::messageType_t::noteOn));
    TEST_ASSERT(receiving.Data1 == 0x10);
    TEST_ASSERT(receiving.Data2 == 0x20);
    TEST_ASSERT(receiving.Data3 == 0x30);

    //nothing left in the buffer - read should return false
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
}

TEST_CASE(InternalCMD)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(OpenDeckMIDIformat::command_t::btldrReboot);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    //change the state to app reboot first - after reading this should be switched to rebootBtldr
    rebootType = Board::rebootType_t::rebootApp;

    TEST_ASSERT(OpenDeckMIDIformat::write(TEST_MIDI_CHANNEL, sending, OpenDeckMIDIformat::packetType_t::internalCommand) == true);
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::internalCommand);

    //in case of internal commands, Event, Data1, Data2 and Data3 are fully ignored - only the
    //specific function is called
    TEST_ASSERT(rebootType == Board::rebootType_t::rebootBtldr);

    //nothing left in the buffer - read should return false
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
}

TEST_CASE(ManualPacketBuilding)
{
    MIDI::USBMIDIpacket_t            sending;
    MIDI::USBMIDIpacket_t            receiving;
    OpenDeckMIDIformat::packetType_t receivedPacketType;

    sending.Event = static_cast<uint8_t>(OpenDeckMIDIformat::command_t::btldrReboot);
    sending.Data1 = 0x10;
    sending.Data2 = 0x20;
    sending.Data3 = 0x30;

    uint8_t dataXor = sending.Event ^ sending.Data1 ^ sending.Data2 ^ sending.Data3;

    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, dataXor));

    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);

    //now send the same packet but with XOR byte being wrong
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, 0x00));

    rebootType = Board::rebootType_t::rebootApp;

    //read should return false and btldr reboot function shouldn't be called
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);
    TEST_ASSERT(rebootType == Board::rebootType_t::rebootApp);

    //try building valid packet, and then start another one in the middle without first one being finished properly
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    //now start another one
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, static_cast<uint8_t>(OpenDeckMIDIformat::packetType_t::internalCommand)));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Event));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data1));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data2));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, sending.Data3));
    TEST_ASSERT(true == Board::UART::write(TEST_MIDI_CHANNEL, dataXor));

    //there are several reads now which should return failure:
    //5 more failed reads until wrong XOR packet is cleared out of memory
    //2 more failed reads for first two bytes
    for (int i = 0; i < 7; i++)
        TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == false);

    //next read should return success
    TEST_ASSERT(OpenDeckMIDIformat::read(TEST_MIDI_CHANNEL, receiving, receivedPacketType) == true);
    TEST_ASSERT(receivedPacketType == OpenDeckMIDIformat::packetType_t::internalCommand);
    rebootType = Board::rebootType_t::rebootBtldr;
}

#endif
#endif
<|endoftext|>


<commit_before>/*
 * testActorStdOut.cpp
 *
 *  Created on: 22 sep. 2015
 *      Author: Daniel Nordahl
 */

#include "../src/actorStdOut.h"
#include "gtest/gtest.h"
#include "ArduinoJson.h"

class ActorTest : public ::testing::Test {
	protected:
	 virtual void SetUp(){
	 }

	 virtual void TearDown(){
	 }
};

TEST(ActorTest,jsonTest){
	ActorStdOut actorstd;
	EXPECT_EQ(1,actorstd.createJson());
}
/**
 * Testing the actor struct.
 */
TEST(ActorTest,structTest){
	ActorStdOut actorstd;
	actorstd.createJson();
	actor newActor;
	actor globalActor;
	globalActor = actorstd.getGlobalStruct();

	//Test struct
	newActor.type = "Daniel";
	newActor.name = "Hej";
	newActor.id = "1";
	newActor.outport = "7411";
	newActor.inport = "1337";
	EXPECT_EQ("Daniel",newActor.type);
	EXPECT_EQ("Hej",newActor.name);
	EXPECT_EQ("1",newActor.id);
	EXPECT_EQ("7411",newActor.outport);
	EXPECT_EQ("1337",newActor.inport);

	//Test struct with json string
	EXPECT_STREQ("actor",globalActor.type);
	EXPECT_STREQ("actor1",globalActor.name);
	EXPECT_STREQ("89",globalActor.id);
	EXPECT_STREQ("12",globalActor.fifo);
	EXPECT_STREQ("NULL",globalActor.outport);

}

TEST(ActorTest,createActor){
	ActorStdOut actorstd;
	StaticJsonBuffer<2000> jsonBuffer;
	char str[] = "{\"type\":\"actor\",\"name\":\"actor1\",\"id\":\"89\",\"fifo\":\"12\"}";
	JsonObject &root = jsonBuffer.parseObject(str);
	//EXPECT_EQ(1,actorstd.createActor(root));
}

TEST(ActorTest,actorFire){
	ActorStdOut actorstd;
	actor globalActor;
	globalActor = actorstd.getGlobalStruct();
	EXPECT_EQ(2,globalActor.function());
}

TEST(ActorTest,processTest){
	ActorStdOut actorstd;
	EXPECT_EQ(1,actorstd.process("Test1"));
	EXPECT_EQ(1,actorstd.process("Test2"));
	EXPECT_EQ(1,actorstd.process("Test3"));
	EXPECT_STREQ("Test1",fifoPop());
	EXPECT_STREQ("Test2",fifoPop());
	EXPECT_STREQ("Test3",fifoPop());
}

TEST(ActorTest,testKeys){
	/*
	ActorStdOut actorstd;
	int8_t* array;
	array = actorstd.searchForKeys("ett","sex","sju");
	EXPECT_EQ(4,array[0]);
	EXPECT_EQ(0,array[1]);
	EXPECT_EQ(3,array[2]);

	main
	globalActor.value[0].key = "e4tt";
	globalActor.value[1].key = "e22tt";
	globalActor.value[2].key = "etdt";
	globalActor.value[3].key = "esstft";
	globalActor.value[4].key = "ett";
	globalActor.value[4].value[0].key = "sex";
	globalActor.value[4].value[1].key = "se2x";
	globalActor.value[4].value[2].key = "se2x";
	globalActor.value[4].value[3].key = "s2ex";
	globalActor.value[4].value[4].key = "se2x";

	globalActor.value[4].value[0].value[0].key = "sex";
	globalActor.value[4].value[0].value[1].key  = "se2x";
	globalActor.value[4].value[0].value[2].key = "se2x";
	globalActor.value[4].value[0].value[3].key  = "sju";
	globalActor.value[4].value[0].value[4].key  = "se2x";
	*/
}

TEST(ActorTest,TestFifo){

	initFifo();
	EXPECT_EQ(1,fifoAdd("Andre"));
	EXPECT_STREQ("Andre",fifoPop());
	EXPECT_EQ(1,fifoAdd("Daniel"));
	EXPECT_STREQ("Daniel",fifoPop());
	EXPECT_EQ(1,fifoAdd("Hej"));
	EXPECT_EQ(1,fifoAdd("Saker"));
	EXPECT_STREQ("Hej",fifoPop());
	EXPECT_STREQ("Saker",fifoPop());
	/*
	EXPECT_EQ(1,fifoAdd("Andre"));
	EXPECT_EQ(1,fifoAdd("Daniel"));
	EXPECT_EQ(1,fifoAdd("Hej"));
	EXPECT_EQ(1,fifoAdd("Saker"));
	EXPECT_EQ(1,fifoAdd("Som"));
	EXPECT_EQ(-1,fifoAdd("ser"));   //Testign if fifo return 0 when full
	EXPECT_EQ(-1,fifoAdd("ser"));

	EXPECT_STREQ("Andre",fifoPop());
	EXPECT_STREQ("Daniel",fifoPop());
	EXPECT_STREQ("Hej",fifoPop());
	EXPECT_STREQ("Saker",fifoPop());
	EXPECT_STREQ("Som",fifoPop());

	EXPECT_EQ(1,fifoAdd("First"));
	EXPECT_STREQ("First",fifoPop());
	/*
	EXPECT_EQ(1,fifoAdd("Second"));
	EXPECT_STREQ("Second",fifoPop());

	EXPECT_EQ(1,fifoAdd("Second"));
	EXPECT_STREQ("First",fifoPop());
	EXPECT_EQ(1,fifoAdd("Third"));
	*/
}

<commit_msg>test fixes<commit_after>/*
 * testActorStdOut.cpp
 *
 *  Created on: 22 sep. 2015
 *      Author: Daniel Nordahl
 */

#include "../src/actorStdOut.h"
#include "gtest/gtest.h"
#include "ArduinoJson.h"

class ActorTest : public ::testing::Test {
	protected:
	 virtual void SetUp(){
	 }

	 virtual void TearDown(){
	 }
};

TEST(ActorTest,jsonTest){
	ActorStdOut actorstd;
	EXPECT_EQ(1,actorstd.createJson());
}
/**
 * Testing the actor struct.
 */
TEST(ActorTest,structTest){
	ActorStdOut actorstd;
	actorstd.createJson();
	actor newActor;
	actor globalActor;
	globalActor = actorstd.getGlobalStruct();

	//Test struct
	newActor.type = "Daniel";
	newActor.name = "Hej";
	newActor.id = "1";
	newActor.outport = "7411";
	newActor.inport = "1337";
	EXPECT_EQ("Daniel",newActor.type);
	EXPECT_EQ("Hej",newActor.name);
	EXPECT_EQ("1",newActor.id);
	EXPECT_EQ("7411",newActor.outport);
	EXPECT_EQ("1337",newActor.inport);

	//Test struct with json string
	EXPECT_STREQ("actor",globalActor.type);
	EXPECT_STREQ("actor1",globalActor.name);
	EXPECT_STREQ("89",globalActor.id);
	EXPECT_STREQ("12",globalActor.fifo);
	EXPECT_STREQ("NULL",globalActor.outport);

}

TEST(ActorTest,createActor){
	ActorStdOut actorstd;
	StaticJsonBuffer<2000> jsonBuffer;
	char str[] = "{\"type\":\"actor\",\"name\":\"actor1\",\"id\":\"89\",\"fifo\":\"12\"}";
	JsonObject &root = jsonBuffer.parseObject(str);
	//EXPECT_EQ(1,actorstd.createActor(root));
}

TEST(ActorTest,actorFire){
	ActorStdOut actorstd;
	actor globalActor;
	globalActor = actorstd.getGlobalStruct();
	EXPECT_EQ(2,globalActor.function());
}

TEST(ActorTest,processTest){
	ActorStdOut actorstd;
	EXPECT_EQ(1,actorstd.process("Test1"));
	EXPECT_EQ(1,actorstd.process("Test2"));
	EXPECT_EQ(1,actorstd.process("Test3"));
	EXPECT_STREQ("Test1",fifoPop());
	EXPECT_STREQ("Test2",fifoPop());
	EXPECT_STREQ("Test3",fifoPop());
}

/**
 * I need to figure out how to make the actorstruct
 * global before these tests can be runned.
 */
TEST(ActorTest,testKeys){
	/*
	ActorStdOut actorstd;
	int8_t* array;
	array = actorstd.searchForKeys("ett","sex","sju");
	EXPECT_EQ(4,array[0]);
	EXPECT_EQ(0,array[1]);
	EXPECT_EQ(3,array[2]);

	main
	globalActor.value[0].key = "e4tt";
	globalActor.value[1].key = "e22tt";
	globalActor.value[2].key = "etdt";
	globalActor.value[3].key = "esstft";
	globalActor.value[4].key = "ett";
	globalActor.value[4].value[0].key = "sex";
	globalActor.value[4].value[1].key = "se2x";
	globalActor.value[4].value[2].key = "se2x";
	globalActor.value[4].value[3].key = "s2ex";
	globalActor.value[4].value[4].key = "se2x";

	globalActor.value[4].value[0].value[0].key = "sex";
	globalActor.value[4].value[0].value[1].key  = "se2x";
	globalActor.value[4].value[0].value[2].key = "se2x";
	globalActor.value[4].value[0].value[3].key  = "sju";
	globalActor.value[4].value[0].value[4].key  = "se2x";
	*/
}

TEST(ActorTest,TestFifo){

	initFifo();
	EXPECT_EQ(1,fifoAdd("Andre"));
	EXPECT_STREQ("Andre",fifoPop());
	EXPECT_EQ(1,fifoAdd("Daniel"));
	EXPECT_STREQ("Daniel",fifoPop());
	EXPECT_EQ(1,fifoAdd("Hej"));
	EXPECT_EQ(1,fifoAdd("Saker"));
	EXPECT_STREQ("Hej",fifoPop());
	EXPECT_STREQ("Saker",fifoPop());

}

<|endoftext|>


<commit_before>/**
 * @file test_dense_eval.cpp
 *
 * Unit test of evaluation of dense matrices
 *
 * @author Dahua Lin
 */

#include "test_base.h"
#include <light_mat/matrix/matrix_classes.h>

using namespace lmat;
using namespace lmat::test;

void fill_lin(dblock<double>& arr)
{
	for (index_t i = 0; i < arr.nelems(); ++i)
		arr[i] = double(i + 1);
}

MN_CASE( mat_eval, dense_mat )
{
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(m * n);
	fill_lin(s);

	dense_matrix<double, M, N> a(m, n, copy_from(s.ptr_data()));
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

MN_CASE( mat_eval, ref_mat )
{
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(m * n);
	fill_lin(s);

	ref_matrix<double, M, N> a(s.ptr_data(), m, n);
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	// ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

MN_CASE( mat_eval, ref_mat_ex )
{
	const index_t ldim = 7;
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(ldim * n);
	fill_lin(s);

	ref_block<double, M, N> a(s.ptr_data(), m, n, ldim);
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

BEGIN_TPACK( dense_mat_eval )
	ADD_MN_CASE_3X3( mat_eval, dense_mat, 4, 5 );
END_TPACK

BEGIN_TPACK( ref_mat_eval )
	ADD_MN_CASE_3X3( mat_eval, ref_mat, 4, 5 );
END_TPACK

BEGIN_TPACK( ref_mat_ex_eval )
	ADD_MN_CASE_3X3( mat_eval, ref_mat_ex, 4, 5 );
END_TPACK

BEGIN_MAIN_SUITE
	ADD_TPACK( dense_mat_eval )
	ADD_TPACK( ref_mat_eval )
	ADD_TPACK( ref_mat_ex_eval )
END_MAIN_SUITE

<commit_msg>add ref_grid for dense_eval testing<commit_after>/**
 * @file test_dense_eval.cpp
 *
 * Unit test of evaluation of dense matrices
 *
 * @author Dahua Lin
 */

#include "test_base.h"
#include <light_mat/matrix/matrix_classes.h>

using namespace lmat;
using namespace lmat::test;

void fill_lin(dblock<double>& arr)
{
	for (index_t i = 0; i < arr.nelems(); ++i)
		arr[i] = double(i + 1);
}

MN_CASE( mat_eval, dense_mat )
{
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(m * n);
	fill_lin(s);

	dense_matrix<double, M, N> a(m, n, copy_from(s.ptr_data()));
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

MN_CASE( mat_eval, ref_mat )
{
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(m * n);
	fill_lin(s);

	ref_matrix<double, M, N> a(s.ptr_data(), m, n);
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	// ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

MN_CASE( mat_eval, ref_block )
{
	const index_t ldim = 7;
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;

	dblock<double> s(ldim * n);
	fill_lin(s);

	ref_block<double, M, N> a(s.ptr_data(), m, n, ldim);
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

MN_CASE( mat_eval, ref_grid )
{
	const index_t m = M == 0 ? 4 : M;
	const index_t n = N == 0 ? 5 : N;
	const index_t rs = 2;
	const index_t cs = 9;

	dblock<double> s(cs * n);
	fill_lin(s);

	ref_grid<double, M, N> a(s.ptr_data(), m, n, rs, cs);
	dense_matrix<double, M, N> r = eval(a);

	ASSERT_EQ( r.nrows(), m );
	ASSERT_EQ( r.ncolumns(), n );
	ASSERT_NE( r.ptr_data(), a.ptr_data() );

	ASSERT_MAT_EQ(m, n, a, r);
}

BEGIN_TPACK( dense_mat_eval )
	ADD_MN_CASE_3X3( mat_eval, dense_mat, 4, 5 );
END_TPACK

BEGIN_TPACK( ref_mat_eval )
	ADD_MN_CASE_3X3( mat_eval, ref_mat, 4, 5 );
END_TPACK

BEGIN_TPACK( ref_block_eval )
	ADD_MN_CASE_3X3( mat_eval, ref_block, 4, 5 );
END_TPACK

BEGIN_TPACK( ref_grid_eval )
	ADD_MN_CASE_3X3( mat_eval, ref_grid, 4, 5 );
END_TPACK

BEGIN_MAIN_SUITE
	ADD_TPACK( dense_mat_eval )
	ADD_TPACK( ref_mat_eval )
	ADD_TPACK( ref_block_eval )
	ADD_TPACK( ref_grid_eval )
END_MAIN_SUITE

<|endoftext|>


<commit_before>#include <iostream>

#include "Cluster.h"
#include "utils.h"
#include "numerics.h"
#include "View.h"
#include "RandomNumberGenerator.h"

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

typedef boost::numeric::ublas::matrix<double> matrixD;
using namespace std;
typedef vector<Cluster*> vectorCp;
typedef set<Cluster*> setCp;
typedef map<int, Cluster*> mapICp;
typedef setCp::iterator setCp_it;
typedef mapICp::iterator mapICp_it;
typedef vector<int>::iterator vectorI_it;

void print_cluster_memberships(View& v) {
  cout << "Cluster memberships" << endl;
  setCp_it it = v.clusters.begin();
  for(; it!=v.clusters.end(); it++) {
    Cluster &cd = **it;
    cout << cd.get_row_indices() << endl;
  }
  cout << "num clusters: " << v.get_num_clusters() << endl;
}

void insert_and_print(View& v, map<int, vector<double> > data_map,
		      int cluster_idx, int row_idx) {
  vector<double> row = data_map[row_idx];
  Cluster& cluster = v.get_cluster(cluster_idx);
  v.insert_row(row, cluster, row_idx);
  cout << "v.insert_row(" << row << ", " << cluster_idx << ", " \
	    << row_idx << ")" << endl;
  cout << "v.get_score(): " << v.get_score() << endl;
}

void print_with_header(View &v, string header) {
  cout << endl;
  cout << "=================================" << endl;
  cout << header << endl;
  v.print();
  cout << header << endl;
  cout << "=================================" << endl;
  cout << endl;
}

void remove_all_data(View &v, map<int, vector<double> > data_map) {
  vector<int> rows_in_view;
  for(mapICp_it it=v.cluster_lookup.begin(); it!=v.cluster_lookup.end(); it++) {
    rows_in_view.push_back(it->first);
  }
  for(vectorI_it it=rows_in_view.begin(); it!=rows_in_view.end(); it++) {
    int idx_to_remove = *it;
    vector<double> row = data_map[idx_to_remove];
    v.remove_row(row, idx_to_remove);
  }
  cout << "removed all data" << endl;
  v.print();
  //
  for(setCp_it it=v.clusters.begin(); it!=v.clusters.end(); it++) {
    v.remove_if_empty(**it);
  }
  assert(v.get_num_vectors()==0);
  assert(v.get_num_clusters()==0);
  cout << "removed empty clusters" << endl;
  v.print();
}

int main(int argc, char** argv) {
  cout << endl << "Hello World!" << endl;

  // load some data
  matrixD data;
  LoadData("SynData2.csv", data);
  int num_cols = data.size2();
  int num_rows = data.size1();
  //
  map<int, vector<double> > data_map;
  cout << "populating data_map" << endl;
  for(int row_idx=0; row_idx<num_rows; row_idx++) {
    data_map[row_idx] = extract_row(data, row_idx);
  }

  // create the view
  vector<int> global_column_indices;
  for(int col_idx=0; col_idx<data.size2(); col_idx++) {
    global_column_indices.push_back(col_idx);
  }
  View v = View(data, global_column_indices, 31);

  // print the initial view
  print_with_header(v, "empty view print");

  // populate the objects to test
  cout << endl << "populating objects" << endl;
  cout << "=================================" << endl;
  cout << "Insertings row:";
  for(int row_idx=0; row_idx<num_rows; row_idx++) {
    cout << " " << row_idx;
    vector<double> row = extract_row(data, row_idx);
    v.insert_row(row, row_idx);
  }
  print_with_header(v, "view after population");

  cout << "====================" << endl;
  cout << "Sampling" << endl;
  // test transition
  RandomNumberGenerator rng = RandomNumberGenerator();
  for(int iter=0; iter<21; iter++) {
    v.assert_state_consistency();
    v.transition_zs(data_map);
    v.transition_crp_alpha();
    v.transition_hypers();
    // if(iter % 10 == 0) {
    if(iter % 1 == 0) {
      print_cluster_memberships(v);
      for(int col_idx=0; col_idx<num_cols; col_idx++) {
	cout << "Hypers(col_idx=" << col_idx <<"): " << v.get_hypers(col_idx) << endl;
      }
      cout << "score: " << v.get_score() << endl;
      cout << "Done iter: " << iter << endl;
      cout << endl;
    }
  }
  print_cluster_memberships(v);
  cout << "Done transition_zs" << endl;
  cout << endl;

  // empty object and verify empty
  remove_all_data(v, data_map);
  v.print();

  cout << endl << "Goodbye World!" << endl;
}
<commit_msg>try removing a column, failing because dont have mechanism to rearrange data per new view columns<commit_after>#include <iostream>

#include "Cluster.h"
#include "utils.h"
#include "numerics.h"
#include "View.h"
#include "RandomNumberGenerator.h"

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/io.hpp>

typedef boost::numeric::ublas::matrix<double> matrixD;
using namespace std;
typedef vector<Cluster*> vectorCp;
typedef set<Cluster*> setCp;
typedef map<int, Cluster*> mapICp;
typedef setCp::iterator setCp_it;
typedef mapICp::iterator mapICp_it;
typedef vector<int>::iterator vectorI_it;

void print_cluster_memberships(View& v) {
  cout << "Cluster memberships" << endl;
  setCp_it it = v.clusters.begin();
  for(; it!=v.clusters.end(); it++) {
    Cluster &cd = **it;
    cout << cd.get_row_indices() << endl;
  }
  cout << "num clusters: " << v.get_num_clusters() << endl;
}

void insert_and_print(View& v, map<int, vector<double> > data_map,
		      int cluster_idx, int row_idx) {
  vector<double> row = data_map[row_idx];
  Cluster& cluster = v.get_cluster(cluster_idx);
  v.insert_row(row, cluster, row_idx);
  cout << "v.insert_row(" << row << ", " << cluster_idx << ", " \
	    << row_idx << ")" << endl;
  cout << "v.get_score(): " << v.get_score() << endl;
}

void print_with_header(View &v, string header) {
  cout << endl;
  cout << "=================================" << endl;
  cout << header << endl;
  v.print();
  cout << header << endl;
  cout << "=================================" << endl;
  cout << endl;
}

void remove_all_data(View &v, map<int, vector<double> > data_map) {
  vector<int> rows_in_view;
  for(mapICp_it it=v.cluster_lookup.begin(); it!=v.cluster_lookup.end(); it++) {
    rows_in_view.push_back(it->first);
  }
  for(vectorI_it it=rows_in_view.begin(); it!=rows_in_view.end(); it++) {
    int idx_to_remove = *it;
    vector<double> row = data_map[idx_to_remove];
    v.remove_row(row, idx_to_remove);
  }
  cout << "removed all data" << endl;
  v.print();
  //
  for(setCp_it it=v.clusters.begin(); it!=v.clusters.end(); it++) {
    v.remove_if_empty(**it);
  }
  assert(v.get_num_vectors()==0);
  assert(v.get_num_clusters()==0);
  cout << "removed empty clusters" << endl;
  v.print();
}

int main(int argc, char** argv) {
  cout << endl << "Hello World!" << endl;

  // load some data
  matrixD data;
  LoadData("SynData2.csv", data);
  int num_cols = data.size2();
  int num_rows = data.size1();
  //
  map<int, vector<double> > data_map;
  cout << "populating data_map" << endl;
  for(int row_idx=0; row_idx<num_rows; row_idx++) {
    data_map[row_idx] = extract_row(data, row_idx);
  }

  // create the view
  vector<int> global_column_indices;
  for(int col_idx=0; col_idx<data.size2(); col_idx++) {
    global_column_indices.push_back(col_idx);
  }
  View v = View(data, global_column_indices, 31);

  // print the initial view
  print_with_header(v, "empty view print");

  // populate the objects to test
  cout << endl << "populating objects" << endl;
  cout << "=================================" << endl;
  cout << "Insertings row:";
  for(int row_idx=0; row_idx<num_rows; row_idx++) {
    cout << " " << row_idx;
    vector<double> row = extract_row(data, row_idx);
    v.insert_row(row, row_idx);
  }
  print_with_header(v, "view after population");

  cout << "====================" << endl;
  cout << "Sampling" << endl;
  // test transition
  RandomNumberGenerator rng = RandomNumberGenerator();
  for(int iter=0; iter<21; iter++) {
    v.assert_state_consistency();
    v.transition_zs(data_map);
    v.transition_crp_alpha();
    v.transition_hypers();
    // if(iter % 10 == 0) {
    if(iter % 1 == 0) {
      cout << "Done iter: " << iter << endl;
      print_with_header(v, "view after iter");
    }
  }
  cout << "Done transition_zs" << endl;
  cout << endl;

  cout << "=====================" << endl;
  cout << "=====================" << endl;
  cout << "=====================" << endl;
  int remove_col_idx = 2;
  cout << "removing column: " << remove_col_idx;
  v.remove_col(remove_col_idx);
  print_with_header(v, "view after column removal");

  // empty object and verify empty
  remove_all_data(v, data_map);
  v.print();

  cout << endl << "Goodbye World!" << endl;
}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "config.h"
#include "alloc.h"
#include "intrinsics.h"
#if defined(TASKING_TBB)
#  define TBB_IMPLEMENT_CPP0X 0
#  define __TBB_NO_IMPLICIT_LINKAGE 1
#  define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1
#  include "tbb/scalable_allocator.h"
#endif

////////////////////////////////////////////////////////////////////////////////
/// Windows Platform
////////////////////////////////////////////////////////////////////////////////

#ifdef _WIN32

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <malloc.h>

namespace embree
{
  void* os_malloc(size_t bytes, const int additional_flags)
  {
    int flags = MEM_COMMIT | MEM_RESERVE | additional_flags;
    char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
    if (ptr == nullptr) throw std::bad_alloc();
    return ptr;
  }

  void* os_reserve(size_t bytes)
  {
    char* ptr = (char*) VirtualAlloc(nullptr,bytes,MEM_RESERVE,PAGE_READWRITE);
    if (ptr == nullptr) throw std::bad_alloc();
    return ptr;
  }

  void os_commit (void* ptr, size_t bytes) {
    VirtualAlloc(ptr,bytes,MEM_COMMIT,PAGE_READWRITE);
  }

  size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld)
  {
    size_t pageSize = 4096;
    bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
    assert(bytesNew <= bytesOld);
    if (bytesNew < bytesOld)
      VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT);
    return bytesNew;
  }

  void os_free(void* ptr, size_t bytes) {
    if (bytes == 0) return;
    VirtualFree(ptr,0,MEM_RELEASE);
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// Unix Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__UNIX__)

#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

/* hint for transparent huge pages (THP) */
#if defined(__MACOSX__)
#define USE_MADVISE 0
#else
#define USE_MADVISE 1
#endif

#define UPGRADE_TO_2M_PAGE_LIMIT (256*1024)
#define PAGE_SIZE_2M (2*1024*1024)
#define PAGE_SIZE_4K (4*1024)

namespace embree
{
  __forceinline bool isHugePageCandidate(const size_t bytes)
  {
    /* try to use huge pages for large allocations */
    if (bytes >= PAGE_SIZE_2M)
    {
      /* multiple of page size */
      if ((bytes % PAGE_SIZE_2M) == 0)
        return true;
      else if (bytes >= 64 * PAGE_SIZE_2M) /* will only introduce a 3% overhead */
        return true;
    }
    return false;
  }

// ============================================
// ============================================
// ============================================

#if !defined(__MACOSX__)
  static bool tryDirectHugePageAllocation = true;
#endif

#if USE_MADVISE
  void os_madvise(void *ptr, size_t bytes)
  {
#if defined(MADV_HUGEPAGE)
    madvise(ptr,bytes,MADV_HUGEPAGE);
#endif
  }
#endif

  void* os_malloc(size_t bytes, const int additional_flags)
  {
    int flags = MAP_PRIVATE | MAP_ANON | additional_flags;

    if (isHugePageCandidate(bytes))
    {
      bytes = (bytes+PAGE_SIZE_2M-1)&ssize_t(-PAGE_SIZE_2M);

#if !defined(__MACOSX__)
      /* try direct huge page allocation first */
      if (tryDirectHugePageAllocation)
      {
        int huge_flags = flags;
#ifdef MAP_HUGETLB
        huge_flags |= MAP_HUGETLB;
#endif
#ifdef MAP_ALIGNED_SUPER
        huge_flags |= MAP_ALIGNED_SUPER;
#endif
        void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, huge_flags, -1, 0);

        if (ptr == nullptr || ptr == MAP_FAILED)
        {
          /* direct huge page allocation failed, disable it for the future */
          tryDirectHugePageAllocation = false;
        }
        else
          return ptr;
      }
#endif
    }
    else
      bytes = (bytes+PAGE_SIZE_4K-1)&ssize_t(-PAGE_SIZE_4K);

    /* standard mmap call */
    void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, flags, -1, 0);
    assert( ptr != MAP_FAILED );
    if (ptr == nullptr || ptr == MAP_FAILED) throw std::bad_alloc();

#if USE_MADVISE
    /* advise huge page hint for THP */
    os_madvise(ptr,bytes);
#endif

    return ptr;
  }

  void* os_reserve(size_t bytes)
  {

    /* linux always allocates pages on demand, thus just call allocate */
    return os_malloc(bytes);
  }

  void os_commit (void* ptr, size_t bytes) {
  }

  size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld)
  {
    size_t pageSize = PAGE_SIZE_4K;
    if (isHugePageCandidate(bytesOld))
      pageSize = PAGE_SIZE_2M;

    bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);

    assert(bytesNew <= bytesOld);
    if (bytesNew >= bytesOld)
      return bytesOld;

    if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
      throw std::bad_alloc();

    return bytesNew;
  }

  void os_free(void* ptr, size_t bytes)
  {
    if (bytes == 0)
      return;

    size_t pageSize = PAGE_SIZE_4K;
    if (isHugePageCandidate(bytes))
      pageSize = PAGE_SIZE_2M;

    bytes = (bytes+pageSize-1)&ssize_t(-pageSize);
    if (munmap(ptr,bytes) == -1)
      throw std::bad_alloc();
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// All Platforms
////////////////////////////////////////////////////////////////////////////////

namespace embree
{
  void* alignedMalloc(size_t size, size_t align) {
    assert((align & (align-1)) == 0);
    return _mm_malloc(size,align);
  }

  void alignedFree(void* ptr) {
    _mm_free(ptr);
  }
}
<commit_msg>cleanups in sys/alloc.cpp<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "config.h"
#include "alloc.h"
#include "intrinsics.h"

////////////////////////////////////////////////////////////////////////////////
/// Windows Platform
////////////////////////////////////////////////////////////////////////////////

#ifdef _WIN32

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <malloc.h>

namespace embree
{
  void* os_malloc(size_t bytes, const int additional_flags)
  {
    int flags = MEM_COMMIT | MEM_RESERVE | additional_flags;
    char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE);
    if (ptr == nullptr) throw std::bad_alloc();
    return ptr;
  }

  void* os_reserve(size_t bytes)
  {
    char* ptr = (char*) VirtualAlloc(nullptr,bytes,MEM_RESERVE,PAGE_READWRITE);
    if (ptr == nullptr) throw std::bad_alloc();
    return ptr;
  }

  void os_commit (void* ptr, size_t bytes) {
    VirtualAlloc(ptr,bytes,MEM_COMMIT,PAGE_READWRITE);
  }

  size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld)
  {
    size_t pageSize = 4096;
    bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);
    assert(bytesNew <= bytesOld);
    if (bytesNew < bytesOld)
      VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT);
    return bytesNew;
  }

  void os_free(void* ptr, size_t bytes) {
    if (bytes == 0) return;
    VirtualFree(ptr,0,MEM_RELEASE);
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// Unix Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__UNIX__)

#include <sys/mman.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#define UPGRADE_TO_2M_PAGE_LIMIT (256*1024)
#define PAGE_SIZE_2M (2*1024*1024)
#define PAGE_SIZE_4K (4*1024)

namespace embree
{
  __forceinline bool isHugePageCandidate(const size_t bytes)
  {
    /* try to use huge pages for large allocations */
    if (bytes >= PAGE_SIZE_2M)
    {
      /* multiple of page size */
      if ((bytes % PAGE_SIZE_2M) == 0)
        return true;
      else if (bytes >= 64 * PAGE_SIZE_2M) /* will only introduce a 3% overhead */
        return true;
    }
    return false;
  }

#if !defined(__MACOSX__)
  static bool tryDirectHugePageAllocation = true;
#endif

  /* hint for transparent huge pages (THP) */
  void os_madvise(void *ptr, size_t bytes)
  {
#if defined(MADV_HUGEPAGE)
    madvise(ptr,bytes,MADV_HUGEPAGE);
#endif
  }

  void* os_malloc(size_t bytes, const int additional_flags)
  {
    int flags = MAP_PRIVATE | MAP_ANON | additional_flags;

    if (isHugePageCandidate(bytes))
    {
      bytes = (bytes+PAGE_SIZE_2M-1)&ssize_t(-PAGE_SIZE_2M);

#if !defined(__MACOSX__)
      /* try direct huge page allocation first */
      if (tryDirectHugePageAllocation)
      {
        int huge_flags = flags;
#ifdef MAP_HUGETLB
        huge_flags |= MAP_HUGETLB;
#endif
#ifdef MAP_ALIGNED_SUPER
        huge_flags |= MAP_ALIGNED_SUPER;
#endif
        void* ptr = mmap(0, bytes, PROT_READ | PROT_WRITE, huge_flags, -1, 0);

        if (ptr == nullptr || ptr == MAP_FAILED)
        {
          /* direct huge page allocation failed, disable it for the future */
          tryDirectHugePageAllocation = false;
        }
        else
          return ptr;
      }
#endif
    }
    else
      bytes = (bytes+PAGE_SIZE_4K-1)&ssize_t(-PAGE_SIZE_4K);

    /* standard mmap call */
    void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, flags, -1, 0);
    assert( ptr != MAP_FAILED );
    if (ptr == nullptr || ptr == MAP_FAILED) throw std::bad_alloc();

    /* advise huge page hint for THP */
    os_madvise(ptr,bytes);

    return ptr;
  }

  void* os_reserve(size_t bytes)
  {
    /* linux always allocates pages on demand, thus just call allocate */
    return os_malloc(bytes);
  }

  void os_commit (void* ptr, size_t bytes) {
  }

  size_t os_shrink(void* ptr, size_t bytesNew, size_t bytesOld)
  {
    size_t pageSize = PAGE_SIZE_4K;
    if (isHugePageCandidate(bytesOld))
      pageSize = PAGE_SIZE_2M;

    bytesNew = (bytesNew+pageSize-1) & ~(pageSize-1);

    assert(bytesNew <= bytesOld);
    if (bytesNew >= bytesOld)
      return bytesOld;

    if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1)
      throw std::bad_alloc();

    return bytesNew;
  }

  void os_free(void* ptr, size_t bytes)
  {
    if (bytes == 0)
      return;

    size_t pageSize = PAGE_SIZE_4K;
    if (isHugePageCandidate(bytes))
      pageSize = PAGE_SIZE_2M;

    bytes = (bytes+pageSize-1)&ssize_t(-pageSize);
    if (munmap(ptr,bytes) == -1)
      throw std::bad_alloc();
  }
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// All Platforms
////////////////////////////////////////////////////////////////////////////////

namespace embree
{
  void* alignedMalloc(size_t size, size_t align) {
    assert((align & (align-1)) == 0);
    return _mm_malloc(size,align);
  }

  void alignedFree(void* ptr) {
    _mm_free(ptr);
  }
}
<|endoftext|>


<commit_before>/*
    openDCM, dimensional constraint manager
    Copyright (C) 2012  Stefan Troeger <stefantroeger@gmx.net>

    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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef DCM_CORE_H
#define DCM_CORE_H

#ifdef _WIN32
	//warning about to long decoraded names, won't affect the code correctness
	#pragma warning( disable : 4503 )
#endif

#include "core/geometry.hpp"
#include "core/kernel.hpp"
#include "core/system.hpp"

#endif //DCM_CORE_H

<commit_msg>disable conecpt checks for msvc due to alignment problems<commit_after>/*
    openDCM, dimensional constraint manager
    Copyright (C) 2012  Stefan Troeger <stefantroeger@gmx.net>

    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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#ifndef DCM_CORE_H
#define DCM_CORE_H

#ifdef _WIN32
	//warning about to long decoraded names, won't affect the code correctness
	#pragma warning( disable : 4503 )

	//disable boost concept checks, as some of them have alignment problems which bring msvc to an error
	//(for example DFSvisitor check in boost::graph::depht_first_search)
	//this has no runtime effect as these are only compile time checks
	#include <boost/concept/assert.hpp>
	#undef BOOST_CONCEPT_ASSERT
	#define BOOST_CONCEPT_ASSERT(Model)
	#include <boost/concept_check.hpp>

#endif

#include "core/geometry.hpp"
#include "core/kernel.hpp"
#include "core/system.hpp"

#endif //DCM_CORE_H

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <string>

#include <cstdlib>
#include <cassert>

using namespace std;

template <
	typename fn_output,
	typename char_type = char,
	char_type opening = '(',
	char_type closing = ')'
>
class generate_balanced_parenthesis {
	fn_output out;
	string buffer;
	size_t pairs;

	void generate(size_t open, size_t position) {
		if(position == buffer.size()) {
			out(buffer);
			return;
		}

		if(position < buffer.size() - 1) {
			buffer[position] = opening;
			generate(open + 1, position + 1);
		}
		else {
			assert(open == buffer.size() / 2);
		}

		if(open > 0) {
			buffer[position] = closing;
			generate(open - 1, position + 1);
		}
	}

public:
	generate_balanced_parenthesis(fn_output out, size_t pairs):
		out(out),
		buffer(pairs * 2),
		pairs(pairs)
	{
		assert(pairs > 0);
	}

	void operator () {
		generate(0, 0);
	}
};
void generate_balanced_parenthesis() {
	vector<char> buffer(pairs * 2);
}

template <typename fn_output>
void  {
	vector<char> buffer(pairs * 2);
}

int main(int argc, char **argv) {
	auto out = [](string const &s) { cout << s << endl; };

	generate_balanced_parenthesis<decltype(out)>(
		out, argc > 1 ? atoi(argv[1]) : 3
	)();

	return 0;
}
<commit_msg>[30]: - fixing compilation errors - tracking max-depth for each combination<commit_after>#include <iostream>
#include <string>

#include <cstdlib>
#include <cassert>

using namespace std;

template <
	typename fn_output,
	typename char_type = char,
	char_type opening = '(',
	char_type closing = ')'
>
void generate_balanced_parenthesis(fn_output out, size_t pairs) {
	struct generator {
		fn_output out;
		string buffer;
		size_t pairs;
		size_t maxDepth;

		void generate(size_t open = 0, size_t closed = 0, size_t position = 0, size_t depth = 0) {
			if(depth > maxDepth) {
				maxDepth = depth;
			}

			if(position == buffer.size()) {
				out(buffer, maxDepth);
				return;
			}

			if(open < pairs) {
				assert(depth < pairs);
				size_t prev = maxDepth;

				buffer[position] = opening;
				generate(open + 1, closed, position + 1, depth + 1);

				if(prev < maxDepth) {
					maxDepth = prev;
				}
			}
			else {
				assert(open == pairs);
			}

			if(closed < open) {
				assert(depth);

				buffer[position] = closing;
				generate(open, closed + 1, position + 1, depth - 1);
			}
			else {
				assert(closed == open);
			}
		}
	};

	generator g{out, string(pairs * 2, char_type(0)), pairs, 0};
	g.generate();
}

int main(int argc, char **argv) {
	auto out = [](string const &s, size_t maxDepth) {
		cout << s << ", maximum depth = " << maxDepth << endl;
	};

	generate_balanced_parenthesis<decltype(out)>(
		out, argc > 1 ? atoi(argv[1]) : 3
	);

	return 0;
}
<|endoftext|>


<commit_before>//
//  The MIT License (MIT)
//
//  Copyright (c) 2016 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <CSTest.h>
#include <IntegrationTest/TestSystem/TestCase.h>

#include <ChilliSource/Core/Base.h>
#include <ChilliSource/Core/File.h>

namespace CSTest
{
    namespace IntegrationTest
    {
        namespace
        {
            const std::string k_rootDirectory = "IntegrationTest/FileStream/";
            const std::string k_testTextFileName = k_rootDirectory + "TestOutFile.txt";

            const std::string k_testTextFileFirstLine = "This is a test file.\n";
            const std::string k_testTextFileSecondLine = "I am on another line!";
            const std::string k_testTextFileContents = k_testTextFileFirstLine +  k_testTextFileSecondLine;

			constexpr CS::StorageLocation k_storageLocation = CS::StorageLocation::k_saveData;

            /// Opens the test text file for writing
            ///
            /// @return Output Text Stream
            ///
            CS::TextOutputStreamUPtr OpenOutputTestTextFile()
            {
				const auto fileSystem = CS::Application::Get()->GetFileSystem();
				CS_ASSERT(fileSystem->CreateDirectoryPath(k_storageLocation, k_rootDirectory), "Could not create directory!");
                return fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
            }

			/// Opens the test text file for reading
			///
			/// @return Input Text Stream
			///
			CS::ITextInputStreamUPtr OpenInputTestTextFile()
			{
				const auto fileSystem = CS::Application::Get()->GetFileSystem();
				return fileSystem->CreateTextInputStream(k_storageLocation, k_testTextFileName);
			}

            /// Delete the test file
            ///
            bool DeleteTestFile()
            {
                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                return !fileSystem->DoesFileExist(k_storageLocation, k_testTextFileName) || fileSystem->DeleteFile(k_storageLocation, k_testTextFileName);
            }
        }

        /// A series of integration tests to verify the functionality of an TextOutputStream.
        ///
        CSIT_TESTCASE(TextOutputStream)
        {
            /// Validate that a file stream can be opened
            ///
            CSIT_TEST(SuccessTextOutputStreamCreate)
            {
                CSIT_ASSERT(DeleteTestFile(), "Could not delete test file.");

                auto outputFileStream = OpenOutputTestTextFile();
                CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);
                CSIT_PASS();
            }

            /// Validate that single buffer of contents can be written to file
            ///
            CSIT_TEST(SuccessTextOutputStreamWrite)
            {
                CSIT_ASSERT(DeleteTestFile(), "Could not delete test file.");

                auto outputFileStream = OpenOutputTestTextFile();
                CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

                outputFileStream->Write(k_testTextFileContents);
                outputFileStream = nullptr;

				auto inputFileStream = OpenInputTestTextFile();
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileContents, "Written text does not match expectations");
                CSIT_PASS();
            }

			/// Validate that contents can be written to stream multiple times, maintaining correct buffer position
			///
			CSIT_TEST(SuccessTextOutputStreamWriteMultiple)
            {
                CSIT_ASSERT(DeleteTestFile(), "Could not delete test file.");

				auto outputFileStream = OpenOutputTestTextFile();
				CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

				outputFileStream->Write(k_testTextFileFirstLine);
				outputFileStream->Write(k_testTextFileSecondLine);
				outputFileStream = nullptr;

				auto inputFileStream = OpenInputTestTextFile();
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileContents, "Written text does not match expectations");
				CSIT_PASS();
			}

			/// Validate that contents of a larger size can be overwritten with shorter
			/// text without remnants of the first remaining
			///
			CSIT_TEST(SuccessTextOutputStreamOverwrite)
            {
                CSIT_ASSERT(DeleteTestFile(), "Could not delete test file.");

				auto outputFileStream = OpenOutputTestTextFile();
				CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

				outputFileStream->Write(k_testTextFileFirstLine);
				outputFileStream->Write(k_testTextFileSecondLine);
				outputFileStream = nullptr;

				auto overwriteFileStream = OpenOutputTestTextFile();
				overwriteFileStream->Write(k_testTextFileFirstLine);
				overwriteFileStream = nullptr;

				auto inputFileStream = OpenInputTestTextFile();
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileFirstLine, "Written text does not match expectations");
				CSIT_PASS();
			}
        }
    }
}
<commit_msg>Review fixes<commit_after>//
//  The MIT License (MIT)
//
//  Copyright (c) 2016 Tag Games Limited
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//

#include <CSTest.h>
#include <IntegrationTest/TestSystem/TestCase.h>

#include <ChilliSource/Core/Base.h>
#include <ChilliSource/Core/File.h>

namespace CSTest
{
    namespace IntegrationTest
    {
        namespace
        {
            const std::string k_rootDirectory = "IntegrationTest/FileStream/";
            const std::string k_testTextFileName = k_rootDirectory + "TestOutFile.txt";

            const std::string k_testTextFileFirstLine = "This is a test file.\n";
            const std::string k_testTextFileSecondLine = "I am on another line!";
            const std::string k_testTextFileContents = k_testTextFileFirstLine +  k_testTextFileSecondLine;

			constexpr CS::StorageLocation k_storageLocation = CS::StorageLocation::k_saveData;

            /// Clears all written information from the test directory
            ///
            void ClearTestDirectory()
            {
                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                CS_ASSERT(fileSystem->CreateDirectoryPath(k_storageLocation, k_rootDirectory), "Could not create directory!");

                if(fileSystem->DoesFileExist(k_storageLocation, k_testTextFileName))
                {
                    fileSystem->DeleteFile(k_storageLocation, k_testTextFileName);
                }
            }
        }

        /// A series of integration tests to verify the functionality of an TextOutputStream.
        ///
        CSIT_TESTCASE(TextOutputStream)
        {
            /// Validate that a file stream can be opened
            ///
            CSIT_TEST(SuccessTextOutputStreamCreate)
            {
                ClearTestDirectory();

                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                auto outputFileStream = fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

                ClearTestDirectory();

                CSIT_PASS();
            }

            /// Validate that single buffer of contents can be written to file
            ///
            CSIT_TEST(SuccessTextOutputStreamWrite)
            {
                ClearTestDirectory();

                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                auto outputFileStream = fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

                outputFileStream->Write(k_testTextFileContents);
                outputFileStream = nullptr;

                const auto inputFileStream = fileSystem->CreateTextInputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(inputFileStream, "Cannot open input stream to file: " + k_testTextFileName);
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileContents, "Written text does not match expectations");

                ClearTestDirectory();

                CSIT_PASS();
            }

			/// Validate that contents can be written to stream multiple times, maintaining correct buffer position
			///
			CSIT_TEST(SuccessTextOutputStreamWriteMultiple)
            {
                ClearTestDirectory();

                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                auto outputFileStream = fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
				CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

				outputFileStream->Write(k_testTextFileFirstLine);
				outputFileStream->Write(k_testTextFileSecondLine);
				outputFileStream = nullptr;

                const auto inputFileStream = fileSystem->CreateTextInputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(inputFileStream, "Cannot open input stream to file: " + k_testTextFileName);
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileContents, "Written text does not match expectations");

                ClearTestDirectory();

				CSIT_PASS();
			}

			/// Validate that contents of a larger size can be overwritten with shorter
			/// text without remnants of the first remaining
			///
			CSIT_TEST(SuccessTextOutputStreamOverwrite)
            {
                ClearTestDirectory();

                const auto fileSystem = CS::Application::Get()->GetFileSystem();
                auto outputFileStream = fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
				CSIT_ASSERT(outputFileStream, "Cannot open output stream to file: " + k_testTextFileName);

				outputFileStream->Write(k_testTextFileFirstLine);
				outputFileStream->Write(k_testTextFileSecondLine);
				outputFileStream = nullptr;

                auto overwriteFileStream = fileSystem->CreateTextOutputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(overwriteFileStream, "Cannot open output stream to file: " + k_testTextFileName);
				overwriteFileStream->Write(k_testTextFileFirstLine);
				overwriteFileStream = nullptr;

                const auto inputFileStream = fileSystem->CreateTextInputStream(k_storageLocation, k_testTextFileName);
                CSIT_ASSERT(inputFileStream, "Cannot open input stream to file: " + k_testTextFileName);
				auto contents = inputFileStream->ReadAll();

				CSIT_ASSERT(contents == k_testTextFileFirstLine, "Written text does not match expectations");

                ClearTestDirectory();

				CSIT_PASS();
			}
        }
    }
}
<|endoftext|>


<commit_before>/*
C++ implementation of the PCA fitter

L.Storchi, A.Modak, S.R.Chowdhury : 2016
*/
#include "../interface/PCATrackFitter.h"

// to store PCA constants very quick, quite dirty and very ugly (may be a class or ....)
// is there a 2d array class in cmssw ?
#define PCA_RZ_RDIM 2
#define PCA_RZ_CDIM 6
#define PCA_RPHI_RDIM 2
#define PCA_RPHI_CDIM 12
namespace
{
  double c_18_rz_1[PCA_RZ_RDIM][PCA_RZ_CDIM] = {};
  double q_18_rz_1[PCA_RZ_RDIM] = {};
  double c_18_rphi_1_cgt0[PCA_RPHI_RDIM][PCA_RPHI_CDIM] = {};
  double q_18_rphi_1_cgt0[PCA_RPHI_RDIM] = {};

  void get_c_matrix_rz (double eta, int towerid,
      double c[PCA_RZ_RDIM][PCA_RZ_CDIM])
  {
    if (towerid == 18)
    {
      if ((eta >= -0.6) && (eta <= -0.55))
      {
        // TODO read and store
        for (int i=0; i<PCA_RZ_RDIM; ++i)
          for (int j=0; j<PCA_RZ_CDIM; ++j)
            c[i][j] = c_18_rz_1[i][j];
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_c_matrix_rphi (double pt, int charge,
      int towerid, double c[PCA_RPHI_RDIM][PCA_RPHI_CDIM])
  {
    if (charge > 0)
    {
      if (towerid == 18)
      {
        if ((pt >= 3.0) && (pt <= 7))
        {
          // TODO read and store
          for (int i=0; i<PCA_RPHI_RDIM; ++i)
            for (int j=0; j<PCA_RPHI_CDIM; ++j)
              c[i][j] = c_18_rphi_1_cgt0[i][j];
        }
        else
        {
          // TODO
        }
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_q_vector_rz (double eta, int towerid, double q[PCA_RZ_RDIM])
  {
    if (towerid == 18)
    {
      if ((eta >= -0.6) && (eta <= -0.55))
      {
        // TODO read and store
        for (int i=0; i<PCA_RZ_RDIM; ++i)
          q[i] = q_18_rz_1[i];
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_q_vector_rphi (double pt, int charge,
      int towerid, double q[PCA_RPHI_RDIM])
  {
    if (charge > 0)
    {
      if (towerid == 18)
      {
        if ((pt >= 3.0) && (pt <= 7))
        {
          // TODO read and store
          for (int i=0; i<PCA_RPHI_RDIM; ++i)
            q[i] = q_18_rphi_1_cgt0[i];
        }
        else
        {
          // TODO
        }
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }
}

PCATrackFitter::PCATrackFitter():TrackFitter(0)
{
}

PCATrackFitter::PCATrackFitter(int nb):TrackFitter(nb)
{
}

PCATrackFitter::~PCATrackFitter()
{
}

void PCATrackFitter::initialize()
{
}

void PCATrackFitter::mergePatterns()
{
}

// Tentative duplicate removal
// Not used for the moment

void PCATrackFitter::mergeTracks()
{
  unsigned int index = 0;
  vector<Track*>::iterator it = tracks.begin();

  while(it!=tracks.end())
  {
    Track* newTrack = *it;
    bool found = false;
    for(unsigned int i=0;i<index;i++)
    {
      Track* ref = tracks[i];
      float dpt,dphi,dz,deta;
      dpt = fabs(newTrack->getCurve()-ref->getCurve());
      dphi = fabs(newTrack->getPhi0()-ref->getPhi0());
      dz = fabs(newTrack->getZ0()-ref->getZ0());
      deta = fabs(newTrack->getEta0()-ref->getEta0());
      found = (deta<0.02) &&
	(dphi<0.005) &&
	(dpt<0.1) &&
	(dz<0.3);

      if(found)
	break;
    }

    if(found)
      tracks.erase(it);
    else
    {
      index++;
      it++;
    }
  }
}

void PCATrackFitter::setTracks(const std::vector<Track*> & intc,
     const std::map< unsigned int , edm::Ref< edmNew::DetSetVector<
       TTStub< Ref_PixelDigi_ > >, TTStub< Ref_PixelDigi_ > > > & stubmap,
       unsigned int seedsector)
{
  tracks_ = intc;
  stubmap_ = stubmap;
  seedsector_ = seedsector; // TODO: is it the towerid ?
}

void PCATrackFitter::fit(vector<Hit*> hits)
{
  int tow = sector_id; // The tower ID, necessary to get the phi shift

  std::cout << "PCA fit fot tow: " << tow << std::endl;

  double sec_phi = 0;
  switch (tow%8)
  {
    case 0:
      sec_phi = 0.4;
      break;
    case 1:
      sec_phi = 1.2;
      break;
    case 3:
      sec_phi = 2.0;
      break;
    case 4:
      sec_phi = 2.7;
      break;
    case 5:
      sec_phi = -2.0;
      break;
    case 6:
      sec_phi = -1.2;
      break;
    case 7:
      sec_phi = -0.4;
      break;
  }

  double ci = cos(sec_phi);
  double si = sin(sec_phi);

  std::cout << "tracks_.size(): " << tracks_.size() << std::endl;

  for(unsigned int tt=0; tt<tracks_.size(); ++tt)
  {
    vector<int> stubids = tracks_[tt]->getStubs(); // TODO are they the hits idx ?

    /* TODO segfault
    std::vector< edm::Ref< edmNew::DetSetVector< TTStub< Ref_PixelDigi_ > >,
      TTStub< Ref_PixelDigi_ > > > tempvec;

    for(unsigned int sti=0; sti<stubids.size(); ++sti)
      tempvec.push_back( stubmap_[ stubids[sti] ] );

    TTTrack< Ref_PixelDigi_ > temptrack( tempvec );

    double pz = tracks_[tt]->getCurve()/
      (tan(2*atan(exp(-tracks_[tt]->getEta0()))));
    GlobalPoint POCA(0.,0.,tracks[tt]->getZ0());
    GlobalVector mom(tracks_[tt]->getCurve()*cos(tracks_[tt]->getPhi0()),
		     tracks_[tt]->getCurve()*sin(tracks_[tt]->getPhi0()),
		     pz);

    temptrack.setSector( seedsector_ ); // TODO: is it the towerid ?
    temptrack.setWedge( -1 );
    temptrack.setMomentum( mom , 5);
    temptrack.setPOCA( POCA , 5);
    */

    std::cout << "stubids.size(): " << stubids.size() << std::endl;

    if (stubids.size() == 6)
    {
      std::vector<double> zrv, phirv;
      int charge = 1; // TODO estimate the charge as in the TCB ? or store it from the TCB
                      //      we should be able to get charge from Hit part_id

      // TODO segfault
      //temptrack.getRInv() > 0 ? charge = 1 : charge = -1; // TODO is it correct ?

      vector<int>::const_iterator idx = stubids.begin();
      for(; idx != stubids.end(); ++idx)
      {
        // TODO is it ok ? are they the hits id ? looking at the implementation seems so
        //      the stubID is idx in the hit vector, Seb say yes but sgfault
        std::cout << "idx: " << *idx << std::endl;

        double xi = hits[*idx]->getX()*ci+ hits[*idx]->getY()*si;
        double yi = -hits[*idx]->getX()*si+ hits[*idx]->getY()*ci;

        double zi = hits[*idx]->getZ();
        double ri = sqrt(xi*xi+yi*yi);
        double pi = atan2(yi,xi);

        std::cout << xi << " " << yi << " " << zi << " "
          << ri  << " " << pi << std::endl;

        zrv.push_back(zi);
        zrv.push_back(ri);

        phirv.push_back(pi);
        phirv.push_back(ri);
      }

      double pt_est, eta_est;

      pt_est = tracks_[tt]->getCurve();
      eta_est = tracks_[tt]->getEta0();

      double c_rz[PCA_RZ_RDIM][PCA_RZ_CDIM];
      double q_rz[PCA_RZ_RDIM];

      double c_rphi[PCA_RPHI_RDIM][PCA_RPHI_CDIM];
      double q_rphi[PCA_RPHI_RDIM];

      double cottheta = 0.0; // eta
      double z0 = 0.0;
      get_c_matrix_rz (eta_est, tow, c_rz);
      get_q_vector_rz (eta_est, tow, q_rz);

      std::cout << "Here 1" << std::endl;

      // TODO checkit
      cottheta = q_rz[0];
      z0 = q_rz[1];
      for (int i=0; i<PCA_RPHI_CDIM; ++i)
      {
        cottheta += c_rz[0][i]*zrv[i];
        z0 += c_rz[1][i]*zrv[i];
      }

      double coverpt = 0.0; // pt
      double phi = 0.0;
      get_c_matrix_rphi (pt_est, charge, tow, c_rphi);
      get_q_vector_rphi (pt_est, charge, tow, q_rphi);

      std::cout << "Here 2" << std::endl;

      // TODO checkit
      coverpt = q_rphi[0];
      phi = q_rphi[1];
      for (int i=0; i<PCA_RPHI_CDIM; ++i)
      {
        coverpt += c_rphi[0][i]*phirv[i];
        z0 += c_rphi[1][i]*phirv[i];
      }

      std::cout << "Here 3" << std::endl;

      double pt = (double)(charge)/coverpt;

      // TODO: checkit theta to eta
      double eta = 0.0e0;
      double theta = atan(1.0e0 / cottheta);
      double tantheta2 = tan (theta/2.0e0);
      if (tantheta2 < 0.0)
        eta = 1.0e0 * log (-1.0e0 * tantheta2);
      else
        eta = -1.0e0 * log (tantheta2);

      std::cout << "New fit track " << std::endl;

      Track* fit_track = new Track();

      fit_track->setCurve(pt);
      fit_track->setPhi0(phi);
      fit_track->setEta0(eta);
      fit_track->setZ0(z0);

      idx = stubids.begin();
      for(; idx != stubids.end(); ++idx)
        fit_track->addStubIndex(*idx);

      tracks.push_back(fit_track);
    }
    else
    {
      // TODO non 6 layers
    }
  }
}

void PCATrackFitter::fit()
{

  vector<Hit*> activatedHits;

  //////// Get the list of unique stubs from the tracks ///////////

  // TODO not sure will work as it is now need to deal with given
  //      tracks

  set<int> ids;
  int total=0;
  for (unsigned int i=0; i<patterns.size(); ++i)
  {
    vector<Hit*> allHits = patterns[i]->getHits();
    total+=allHits.size();
    for(unsigned int j=0; j<allHits.size(); ++j)
    {
      pair<set<int>::iterator,bool> result = ids.insert(allHits[j]->getID());
      if (result.second == true )
        activatedHits.push_back(allHits[j]);
    }
  }

  fit(activatedHits);
}

TrackFitter* PCATrackFitter::clone()
{
  PCATrackFitter* fit = new PCATrackFitter(nb_layers);

  // TODO

  return fit;
}
<commit_msg>minor<commit_after>/*
C++ implementation of the PCA fitter

L.Storchi, A.Modak, S.R.Chowdhury : 2016
*/
#include "../interface/PCATrackFitter.h"

// to store PCA constants very quick, quite dirty and very ugly (may be a class or ....)
// is there a 2d array class in cmssw ?
#define PCA_RZ_RDIM 2
#define PCA_RZ_CDIM 6
#define PCA_RPHI_RDIM 2
#define PCA_RPHI_CDIM 12
namespace
{
  double c_18_rz_1[PCA_RZ_RDIM][PCA_RZ_CDIM] = {};
  double q_18_rz_1[PCA_RZ_RDIM] = {};
  double c_18_rphi_1_cgt0[PCA_RPHI_RDIM][PCA_RPHI_CDIM] = {};
  double q_18_rphi_1_cgt0[PCA_RPHI_RDIM] = {};

  void get_c_matrix_rz (double eta, int towerid,
      double c[PCA_RZ_RDIM][PCA_RZ_CDIM])
  {
    if (towerid == 18)
    {
      if ((eta >= -0.6) && (eta <= -0.55))
      {
        // TODO read and store
        for (int i=0; i<PCA_RZ_RDIM; ++i)
          for (int j=0; j<PCA_RZ_CDIM; ++j)
            c[i][j] = c_18_rz_1[i][j];
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_c_matrix_rphi (double pt, int charge,
      int towerid, double c[PCA_RPHI_RDIM][PCA_RPHI_CDIM])
  {
    if (charge > 0)
    {
      if (towerid == 18)
      {
        if ((pt >= 3.0) && (pt <= 7))
        {
          // TODO read and store
          for (int i=0; i<PCA_RPHI_RDIM; ++i)
            for (int j=0; j<PCA_RPHI_CDIM; ++j)
              c[i][j] = c_18_rphi_1_cgt0[i][j];
        }
        else
        {
          // TODO
        }
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_q_vector_rz (double eta, int towerid, double q[PCA_RZ_RDIM])
  {
    if (towerid == 18)
    {
      if ((eta >= -0.6) && (eta <= -0.55))
      {
        // TODO read and store
        for (int i=0; i<PCA_RZ_RDIM; ++i)
          q[i] = q_18_rz_1[i];
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }

  void get_q_vector_rphi (double pt, int charge,
      int towerid, double q[PCA_RPHI_RDIM])
  {
    if (charge > 0)
    {
      if (towerid == 18)
      {
        if ((pt >= 3.0) && (pt <= 7))
        {
          // TODO read and store
          for (int i=0; i<PCA_RPHI_RDIM; ++i)
            q[i] = q_18_rphi_1_cgt0[i];
        }
        else
        {
          // TODO
        }
      }
      else
      {
        // TODO
      }
    }
    else
    {
      // TODO
    }
  }
}

PCATrackFitter::PCATrackFitter():TrackFitter(0)
{
}

PCATrackFitter::PCATrackFitter(int nb):TrackFitter(nb)
{
}

PCATrackFitter::~PCATrackFitter()
{
}

void PCATrackFitter::initialize()
{
}

void PCATrackFitter::mergePatterns()
{
}

// Tentative duplicate removal
// Not used for the moment

void PCATrackFitter::mergeTracks()
{
  unsigned int index = 0;
  vector<Track*>::iterator it = tracks.begin();

  while(it!=tracks.end())
  {
    Track* newTrack = *it;
    bool found = false;
    for(unsigned int i=0;i<index;i++)
    {
      Track* ref = tracks[i];
      float dpt,dphi,dz,deta;
      dpt = fabs(newTrack->getCurve()-ref->getCurve());
      dphi = fabs(newTrack->getPhi0()-ref->getPhi0());
      dz = fabs(newTrack->getZ0()-ref->getZ0());
      deta = fabs(newTrack->getEta0()-ref->getEta0());
      found = (deta<0.02) &&
	(dphi<0.005) &&
	(dpt<0.1) &&
	(dz<0.3);

      if(found)
	break;
    }

    if(found)
      tracks.erase(it);
    else
    {
      index++;
      it++;
    }
  }
}

void PCATrackFitter::setTracks(const std::vector<Track*> & intc,
     const std::map< unsigned int , edm::Ref< edmNew::DetSetVector<
       TTStub< Ref_PixelDigi_ > >, TTStub< Ref_PixelDigi_ > > > & stubmap,
       unsigned int seedsector)
{
  tracks_ = intc;
  stubmap_ = stubmap;
  seedsector_ = seedsector; // TODO: is it the towerid ?
}

void PCATrackFitter::fit(vector<Hit*> hits)
{
  int tow = sector_id; // The tower ID, necessary to get the phi shift

  std::cout << "PCA fit for tow: " << tow << std::endl;

  double sec_phi = 0;
  switch (tow%8)
  {
    case 0:
      sec_phi = 0.4;
      break;
    case 1:
      sec_phi = 1.2;
      break;
    case 3:
      sec_phi = 2.0;
      break;
    case 4:
      sec_phi = 2.7;
      break;
    case 5:
      sec_phi = -2.0;
      break;
    case 6:
      sec_phi = -1.2;
      break;
    case 7:
      sec_phi = -0.4;
      break;
  }

  double ci = cos(sec_phi);
  double si = sin(sec_phi);

  std::cout << "tracks_.size(): " << tracks_.size() << std::endl;

  for(unsigned int tt=0; tt<tracks_.size(); ++tt)
  {
    vector<int> stubids = tracks_[tt]->getStubs(); // TODO are they the hits idx ?

    /* TODO segfault
    std::vector< edm::Ref< edmNew::DetSetVector< TTStub< Ref_PixelDigi_ > >,
      TTStub< Ref_PixelDigi_ > > > tempvec;

    for(unsigned int sti=0; sti<stubids.size(); ++sti)
      tempvec.push_back( stubmap_[ stubids[sti] ] );

    TTTrack< Ref_PixelDigi_ > temptrack( tempvec );

    double pz = tracks_[tt]->getCurve()/
      (tan(2*atan(exp(-tracks_[tt]->getEta0()))));
    GlobalPoint POCA(0.,0.,tracks[tt]->getZ0());
    GlobalVector mom(tracks_[tt]->getCurve()*cos(tracks_[tt]->getPhi0()),
		     tracks_[tt]->getCurve()*sin(tracks_[tt]->getPhi0()),
		     pz);

    temptrack.setSector( seedsector_ ); // TODO: is it the towerid ?
    temptrack.setWedge( -1 );
    temptrack.setMomentum( mom , 5);
    temptrack.setPOCA( POCA , 5);
    */

    std::cout << "stubids.size(): " << stubids.size() << std::endl;

    if (stubids.size() == 6)
    {
      std::vector<double> zrv, phirv;
      int charge = 1; // TODO estimate the charge as in the TCB ? or store it from the TCB
                      //      we should be able to get charge from Hit part_id

      // TODO segfault
      //temptrack.getRInv() > 0 ? charge = 1 : charge = -1; // TODO is it correct ?

      vector<int>::const_iterator idx = stubids.begin();
      for(; idx != stubids.end(); ++idx)
      {
        // TODO is it ok ? are they the hits id ? looking at the implementation seems so
        //      the stubID is idx in the hit vector, Seb say yes but sgfault
        std::cout << "idx: " << *idx << std::endl;

        double xi = hits[*idx]->getX()*ci+ hits[*idx]->getY()*si;
        double yi = -hits[*idx]->getX()*si+ hits[*idx]->getY()*ci;

        double zi = hits[*idx]->getZ();
        double ri = sqrt(xi*xi+yi*yi);
        double pi = atan2(yi,xi);

        std::cout << xi << " " << yi << " " << zi << " "
          << ri  << " " << pi << std::endl;

        zrv.push_back(zi);
        zrv.push_back(ri);

        phirv.push_back(pi);
        phirv.push_back(ri);
      }

      double pt_est, eta_est;

      pt_est = tracks_[tt]->getCurve();
      eta_est = tracks_[tt]->getEta0();

      double c_rz[PCA_RZ_RDIM][PCA_RZ_CDIM];
      double q_rz[PCA_RZ_RDIM];

      double c_rphi[PCA_RPHI_RDIM][PCA_RPHI_CDIM];
      double q_rphi[PCA_RPHI_RDIM];

      double cottheta = 0.0; // eta
      double z0 = 0.0;
      get_c_matrix_rz (eta_est, tow, c_rz);
      get_q_vector_rz (eta_est, tow, q_rz);

      std::cout << "Here 1" << std::endl;

      // TODO checkit
      cottheta = q_rz[0];
      z0 = q_rz[1];
      for (int i=0; i<PCA_RPHI_CDIM; ++i)
      {
        cottheta += c_rz[0][i]*zrv[i];
        z0 += c_rz[1][i]*zrv[i];
      }

      double coverpt = 0.0; // pt
      double phi = 0.0;
      get_c_matrix_rphi (pt_est, charge, tow, c_rphi);
      get_q_vector_rphi (pt_est, charge, tow, q_rphi);

      std::cout << "Here 2" << std::endl;

      // TODO checkit
      coverpt = q_rphi[0];
      phi = q_rphi[1];
      for (int i=0; i<PCA_RPHI_CDIM; ++i)
      {
        coverpt += c_rphi[0][i]*phirv[i];
        z0 += c_rphi[1][i]*phirv[i];
      }

      std::cout << "Here 3" << std::endl;

      double pt = (double)(charge)/coverpt;

      // TODO: checkit theta to eta
      double eta = 0.0e0;
      double theta = atan(1.0e0 / cottheta);
      double tantheta2 = tan (theta/2.0e0);
      if (tantheta2 < 0.0)
        eta = 1.0e0 * log (-1.0e0 * tantheta2);
      else
        eta = -1.0e0 * log (tantheta2);

      std::cout << "New fit track " << std::endl;

      Track* fit_track = new Track();

      fit_track->setCurve(pt);
      fit_track->setPhi0(phi);
      fit_track->setEta0(eta);
      fit_track->setZ0(z0);

      idx = stubids.begin();
      for(; idx != stubids.end(); ++idx)
        fit_track->addStubIndex(*idx);

      tracks.push_back(fit_track);
    }
    else
    {
      // TODO non 6 layers
    }
  }
}

void PCATrackFitter::fit()
{

  vector<Hit*> activatedHits;

  //////// Get the list of unique stubs from the tracks ///////////

  // TODO not sure will work as it is now need to deal with given
  //      tracks

  set<int> ids;
  int total=0;
  for (unsigned int i=0; i<patterns.size(); ++i)
  {
    vector<Hit*> allHits = patterns[i]->getHits();
    total+=allHits.size();
    for(unsigned int j=0; j<allHits.size(); ++j)
    {
      pair<set<int>::iterator,bool> result = ids.insert(allHits[j]->getID());
      if (result.second == true )
        activatedHits.push_back(allHits[j]);
    }
  }

  fit(activatedHits);
}

TrackFitter* PCATrackFitter::clone()
{
  PCATrackFitter* fit = new PCATrackFitter(nb_layers);

  // TODO

  return fit;
}
<|endoftext|>