<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2020 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include <cstdio>

#include <boost/format.hpp>

#include "joynr/UdsServer.h"
#include "joynr/Logger.h"

#include "UdsFrameBufferV1.h"
#include "UdsSendQueue.h"

namespace joynr
{

constexpr char UdsServer::_initMessageStart[];
constexpr int UdsServer::_threadsPerServer;

UdsServer::UdsServer(const UdsSettings& settings) noexcept
        : _ioContext(std::make_shared<boost::asio::io_service>(_threadsPerServer)),
          _registry{std::make_shared<Connection::Active>()},
          _openSleepTime{settings.getConnectSleepTimeMs()},
          _endpoint(settings.getSocketPath()),
          _acceptor(*_ioContext),
          _newClientSocket(*_ioContext),
          _started{false}
{
    _remoteConfig._maxSendQueueSize = settings.getSendingQueueSize();
}

UdsServer::~UdsServer()
{
    _started.store(false);
    _ioContext->stop(); // Cancel all pending do-actions
    if (_worker.valid()) {
        _worker.get(); // Assure that no connection interferes with further cleanup of destructor
    }
    _registry->clear(); // Delete all clients not hold by a user
}

void UdsServer::setConnectCallback(const Connected& callback) noexcept
{
    _remoteConfig._connectedCallback = callback;
}

void UdsServer::setDisconnectCallback(const Disconnected& callback) noexcept
{
    _remoteConfig._disconnectedCallback = callback;
}

void UdsServer::setReceiveCallback(const Received& callback) noexcept
{
    _remoteConfig._receivedCallback = callback;
}

void UdsServer::start()
{
    if (_started.exchange(true)) {
        JOYNR_LOG_ERROR(logger(), "UDS server alreay started.");
        return;
    }
    _worker = std::async(&UdsServer::run, this);
}

void UdsServer::run()
{
    bool isRetry = false;
    while (_started.load()) {
        if (isRetry) {
            // Wait before retry to open socket so that worker does not block everything
            std::this_thread::sleep_for(_openSleepTime);
            _ioContext->reset();
        }
        if (remove(_endpoint.path().c_str())) {
            JOYNR_LOG_WARN(logger(),
                           "UDS server path {} already exists. Replacing existing path.",
                           _endpoint.path());
        }
        isRetry = true;
        try {
            _acceptor.open(_endpoint.protocol());
            _acceptor.bind(_endpoint);
            _acceptor.listen();
            JOYNR_LOG_INFO(
                    logger(), "UDS server wating for connections on path {}.", _endpoint.path());
            doAcceptClient();
            _ioContext->run();
        } catch (const boost::system::system_error& error) {
            JOYNR_LOG_ERROR(
                    logger(), "UDS server encountered an error and will restart: {}", error.what());
        }
        boost::system::error_code ignore;
        _acceptor.close(ignore);
    }
}

void UdsServer::doAcceptClient()
{
    _acceptor.async_accept(_newClientSocket, [this](boost::system::error_code acceptFailure) {
        if (acceptFailure) {
            JOYNR_LOG_ERROR(logger(),
                            "UDS server failed to accept new client: {}",
                            acceptFailure.message());
        } else {
            auto newConnection =
                    std::make_shared<Connection>(std::move(_newClientSocket),
                                                 _ioContext,
                                                 std::weak_ptr<Connection::Active>(_registry),
                                                 _remoteConfig);
            _registry->insert(newConnection);
            JOYNR_LOG_INFO(
                    logger(),
                    "Connection request received from new client. {:d} clients are registered.",
                    _registry->size());
            newConnection->doReadInitHeader();
        }
        doAcceptClient();
    });
}

UdsServer::Connection::Connection(uds::socket&& socket,
                                  std::shared_ptr<boost::asio::io_service> ioContext,
                                  std::weak_ptr<Active> registry,
                                  const ConnectionConfig& config) noexcept
        : _socket(std::move(socket)),
          _ioContext(std::move(ioContext)),
          _registry(std::move(registry)),
          _connectedCallback{config._connectedCallback},
          _disconnectedCallback{config._disconnectedCallback},
          _receivedCallback{config._receivedCallback},
          _closedDueToError{false},
          _sendQueue(std::make_unique<UdsSendQueue<UdsFrameBufferV1>>(config._maxSendQueueSize)),
          _readBuffer(std::make_unique<UdsFrameBufferV1>())
{
}

UdsServer::Connection::~Connection()
{
    // Ignore any errors caused by the following socket closure.
    const auto closedDueToError = _closedDueToError.load();

    // Assure that all enqueued actions are removed from the pool which might us the send queue
    boost::system::error_code ignore;
    _socket.close(ignore);
    if (closedDueToError) {
        _sendQueue->emptyQueueAndNotify("Connection lost to " + _address.getId());
    }
}

void UdsServer::Connection::doReadInitHeader()
{
    boost::asio::async_read(_socket,
                            _readBuffer->header(),
                            [this](boost::system::error_code readFailure, std::size_t /*length*/) {
        if (doCheck(readFailure)) {
            doReadInitBody();
        }
    });
}

void UdsServer::Connection::doReadInitBody()
{
    try {
        boost::asio::async_read(_socket,
                                _readBuffer->body(),
                                [this](boost::system::error_code readFailure,
                                       std::size_t /*length*/) {
            if (doCheck(readFailure)) {
                try {
                    _address = _readBuffer->readInit();
                    JOYNR_LOG_INFO(logger(),
                                   "Initialize connection for UDS client id: {}",
                                   _address.getId());
                    _connectedCallback(_address, this->shared_from_this());
                    doReadHeader();
                } catch (const std::exception& e) {
                    std::string id = _address.getId();
                    if (id.empty()) {
                        id = "[unknown ID]";
                    }
                    JOYNR_LOG_FATAL(
                            logger(), "Failed to initialize UDS connection '{}': {}", id, e.what());
                    doClose();
                }
            }
        });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(logger(), "Failed to read init-frame for new UDS connection: {}", e.what());
        doClose();
    }
}

void UdsServer::Connection::doReadHeader()
{
    boost::asio::async_read(_socket,
                            _readBuffer->header(),
                            [this](boost::system::error_code readFailure, std::size_t /*length*/) {
        if (doCheck(readFailure)) {
            doReadBody();
        }
    });
}

void UdsServer::Connection::doReadBody()
{
    try {
        boost::asio::async_read(
                _socket,
                _readBuffer->body(),
                [this](boost::system::error_code readFailure, std::size_t /*length*/) {
                    if (doCheck(readFailure)) {
                        try {
                            _receivedCallback(_address, _readBuffer->readMessage());
                        } catch (const std::exception& e) {
                            JOYNR_LOG_FATAL(logger(),
                                            "Failed to process UDS message from '{}': {}",
                                            _address.getId(),
                                            e.what());
                            doClose();
                        }
                        doReadHeader();
                    }
                });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(logger(),
                        "Failed to read UDS message-frame from '{}': {}",
                        _address.getId(),
                        e.what());
        doClose();
    }
}

void UdsServer::Connection::send(const smrf::ByteArrayView& msg,
                                 const IUdsSender::SendFailed& callback)
{
    try {
        _ioContext->post([ this, frame = UdsFrameBufferV1(msg), callback ]() mutable {
            if (_sendQueue->pushBack(std::move(frame), callback)) {
                doWrite();
            }
        });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(
                logger(), "Failed insert UDS message for '{}': {}", _address.getId(), e.what());
        doClose();
    }
}

void UdsServer::Connection::doWrite()
{
    boost::asio::async_write(_socket,
                             _sendQueue->showFront(),
                             [this](boost::system::error_code writeFailed, std::size_t /*length*/) {
        doCheck(writeFailed);
        if (_sendQueue->popFrontOnSuccess(writeFailed)) {
            doWrite();
        }
    });
}

bool UdsServer::Connection::doCheck(const boost::system::error_code& error)
{
    if (error) {
        JOYNR_LOG_INFO(logger(), "UDS remote client connection disconnected: {}", error.message());
        doClose();
        return false;
    }
    return true;
}

void UdsServer::Connection::doClose()
{
    if (!_closedDueToError.exchange(true)) {
        if (!_address.getId().empty()) {
            _disconnectedCallback(_address);
        }
        boost::system::error_code ignore;
        _socket.close(ignore);
        _ioContext->post([ removeMe = shared_from_this(), registry = _registry ]() {
            auto registryLock = registry.lock();
            if (registryLock) {
                registryLock->erase(removeMe);
            }
        });
    }
}

} // namespace joynr
<commit_msg>[C++] Fix UDS server log statements for socket binding.<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2020 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */

#include <cstdio>

#include <boost/format.hpp>

#include "joynr/UdsServer.h"
#include "joynr/Logger.h"

#include "UdsFrameBufferV1.h"
#include "UdsSendQueue.h"

namespace joynr
{

constexpr char UdsServer::_initMessageStart[];
constexpr int UdsServer::_threadsPerServer;

UdsServer::UdsServer(const UdsSettings& settings) noexcept
        : _ioContext(std::make_shared<boost::asio::io_service>(_threadsPerServer)),
          _registry{std::make_shared<Connection::Active>()},
          _openSleepTime{settings.getConnectSleepTimeMs()},
          _endpoint(settings.getSocketPath()),
          _acceptor(*_ioContext),
          _newClientSocket(*_ioContext),
          _started{false}
{
    _remoteConfig._maxSendQueueSize = settings.getSendingQueueSize();
}

UdsServer::~UdsServer()
{
    _started.store(false);
    _ioContext->stop(); // Cancel all pending do-actions
    if (_worker.valid()) {
        _worker.get(); // Assure that no connection interferes with further cleanup of destructor
    }
    _registry->clear(); // Delete all clients not hold by a user
}

void UdsServer::setConnectCallback(const Connected& callback) noexcept
{
    _remoteConfig._connectedCallback = callback;
}

void UdsServer::setDisconnectCallback(const Disconnected& callback) noexcept
{
    _remoteConfig._disconnectedCallback = callback;
}

void UdsServer::setReceiveCallback(const Received& callback) noexcept
{
    _remoteConfig._receivedCallback = callback;
}

void UdsServer::start()
{
    if (_started.exchange(true)) {
        JOYNR_LOG_ERROR(logger(), "UDS server alreay started.");
        return;
    }
    _worker = std::async(&UdsServer::run, this);
}

void UdsServer::run()
{
    bool isRetry = false;
    while (_started.load()) {
        if (isRetry) {
            // Wait before retry to open socket so that worker does not block everything
            std::this_thread::sleep_for(_openSleepTime);
            _ioContext->reset();
        }
        if (0 == remove(_endpoint.path().c_str())) {
            JOYNR_LOG_WARN(logger(),
                           "UDS server path {} already exists. Replacing existing path.",
                           _endpoint.path());
        }
        isRetry = true;
        try {
            _acceptor.open(_endpoint.protocol());
            _acceptor.bind(_endpoint);
            _acceptor.listen();
            JOYNR_LOG_INFO(logger(), "Waiting for connections on path {}.", _endpoint.path());
            doAcceptClient();
            _ioContext->run();
        } catch (const boost::system::system_error& error) {
            JOYNR_LOG_ERROR(logger(),
                            "UDS server ({}) encountered an error and will restart: {}",
                            _endpoint.path(),
                            error.what());
        }
        boost::system::error_code ignore;
        _acceptor.close(ignore);
    }
}

void UdsServer::doAcceptClient()
{
    _acceptor.async_accept(_newClientSocket, [this](boost::system::error_code acceptFailure) {
        if (acceptFailure) {
            JOYNR_LOG_ERROR(logger(),
                            "UDS server failed to accept new client: {}",
                            acceptFailure.message());
        } else {
            auto newConnection =
                    std::make_shared<Connection>(std::move(_newClientSocket),
                                                 _ioContext,
                                                 std::weak_ptr<Connection::Active>(_registry),
                                                 _remoteConfig);
            _registry->insert(newConnection);
            JOYNR_LOG_INFO(
                    logger(),
                    "Connection request received from new client. {:d} clients are registered.",
                    _registry->size());
            newConnection->doReadInitHeader();
        }
        doAcceptClient();
    });
}

UdsServer::Connection::Connection(uds::socket&& socket,
                                  std::shared_ptr<boost::asio::io_service> ioContext,
                                  std::weak_ptr<Active> registry,
                                  const ConnectionConfig& config) noexcept
        : _socket(std::move(socket)),
          _ioContext(std::move(ioContext)),
          _registry(std::move(registry)),
          _connectedCallback{config._connectedCallback},
          _disconnectedCallback{config._disconnectedCallback},
          _receivedCallback{config._receivedCallback},
          _closedDueToError{false},
          _sendQueue(std::make_unique<UdsSendQueue<UdsFrameBufferV1>>(config._maxSendQueueSize)),
          _readBuffer(std::make_unique<UdsFrameBufferV1>())
{
}

UdsServer::Connection::~Connection()
{
    // Ignore any errors caused by the following socket closure.
    const auto closedDueToError = _closedDueToError.load();

    // Assure that all enqueued actions are removed from the pool which might us the send queue
    boost::system::error_code ignore;
    _socket.close(ignore);
    if (closedDueToError) {
        _sendQueue->emptyQueueAndNotify("Connection lost to " + _address.getId());
    }
}

void UdsServer::Connection::doReadInitHeader()
{
    boost::asio::async_read(_socket,
                            _readBuffer->header(),
                            [this](boost::system::error_code readFailure, std::size_t /*length*/) {
        if (doCheck(readFailure)) {
            doReadInitBody();
        }
    });
}

void UdsServer::Connection::doReadInitBody()
{
    try {
        boost::asio::async_read(_socket,
                                _readBuffer->body(),
                                [this](boost::system::error_code readFailure,
                                       std::size_t /*length*/) {
            if (doCheck(readFailure)) {
                try {
                    _address = _readBuffer->readInit();
                    JOYNR_LOG_INFO(logger(),
                                   "Initialize connection for UDS client id: {}",
                                   _address.getId());
                    _connectedCallback(_address, this->shared_from_this());
                    doReadHeader();
                } catch (const std::exception& e) {
                    std::string id = _address.getId();
                    if (id.empty()) {
                        id = "[unknown ID]";
                    }
                    JOYNR_LOG_FATAL(
                            logger(), "Failed to initialize UDS connection '{}': {}", id, e.what());
                    doClose();
                }
            }
        });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(logger(), "Failed to read init-frame for new UDS connection: {}", e.what());
        doClose();
    }
}

void UdsServer::Connection::doReadHeader()
{
    boost::asio::async_read(_socket,
                            _readBuffer->header(),
                            [this](boost::system::error_code readFailure, std::size_t /*length*/) {
        if (doCheck(readFailure)) {
            doReadBody();
        }
    });
}

void UdsServer::Connection::doReadBody()
{
    try {
        boost::asio::async_read(
                _socket,
                _readBuffer->body(),
                [this](boost::system::error_code readFailure, std::size_t /*length*/) {
                    if (doCheck(readFailure)) {
                        try {
                            _receivedCallback(_address, _readBuffer->readMessage());
                        } catch (const std::exception& e) {
                            JOYNR_LOG_FATAL(logger(),
                                            "Failed to process UDS message from '{}': {}",
                                            _address.getId(),
                                            e.what());
                            doClose();
                        }
                        doReadHeader();
                    }
                });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(logger(),
                        "Failed to read UDS message-frame from '{}': {}",
                        _address.getId(),
                        e.what());
        doClose();
    }
}

void UdsServer::Connection::send(const smrf::ByteArrayView& msg,
                                 const IUdsSender::SendFailed& callback)
{
    try {
        _ioContext->post([ this, frame = UdsFrameBufferV1(msg), callback ]() mutable {
            if (_sendQueue->pushBack(std::move(frame), callback)) {
                doWrite();
            }
        });
    } catch (const std::exception& e) {
        JOYNR_LOG_FATAL(
                logger(), "Failed insert UDS message for '{}': {}", _address.getId(), e.what());
        doClose();
    }
}

void UdsServer::Connection::doWrite()
{
    boost::asio::async_write(_socket,
                             _sendQueue->showFront(),
                             [this](boost::system::error_code writeFailed, std::size_t /*length*/) {
        doCheck(writeFailed);
        if (_sendQueue->popFrontOnSuccess(writeFailed)) {
            doWrite();
        }
    });
}

bool UdsServer::Connection::doCheck(const boost::system::error_code& error)
{
    if (error) {
        JOYNR_LOG_INFO(logger(), "UDS remote client connection disconnected: {}", error.message());
        doClose();
        return false;
    }
    return true;
}

void UdsServer::Connection::doClose()
{
    if (!_closedDueToError.exchange(true)) {
        if (!_address.getId().empty()) {
            _disconnectedCallback(_address);
        }
        boost::system::error_code ignore;
        _socket.close(ignore);
        _ioContext->post([ removeMe = shared_from_this(), registry = _registry ]() {
            auto registryLock = registry.lock();
            if (registryLock) {
                registryLock->erase(removeMe);
            }
        });
    }
}

} // namespace joynr
<|endoftext|>


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

#include <dqtx/QDensityWidget.hpp>
#include <QPainter>
#include <QPen>
#include <QPainterPath>
#include <iostream>
#include <QPaintEvent>
#include <algorithm>
#include <limits>
#include <stdint.h>

namespace dqtx
{
QDensityWidget::QDensityWidget(QWidget *_parent, Qt::WindowFlags _flags)
    : QWidget(_parent, _flags)
    , m_accumulator()
    , m_color(QColor(Qt::black))
    , m_padding(5)
    , m_bandwidth(.5)
    , m_maxObservations(600)
{
    QObject::connect(this, SIGNAL(observationInserted(double)), this,
                     SLOT(onObservationInserted(double)));
    QObject::connect(this, SIGNAL(colorChanged(QColor)), this,
                     SLOT(onColorChanged(QColor)));
    QObject::connect(this, SIGNAL(paddingChanged(int)), this,
                     SLOT(onPaddingChanged(int)));
    QObject::connect(this, SIGNAL(maxObservationsChanged(int)), this,
                     SLOT(onMaxObservationsChanged(int)));
}

void QDensityWidget::insertObservation(const double _data)
{
    emit observationInserted(_data);
}

void QDensityWidget::setColor(const QColor &_color)
{
    emit colorChanged(_color);
}

void QDensityWidget::setPadding(int _padding) { emit paddingChanged(_padding); }

void QDensityWidget::setMaxObservations(int _max)
{
    emit maxObservationsChanged(_max);
}

QSize QDensityWidget::sizeHint() const { return QSize(68, 29); }

void QDensityWidget::paintEvent(QPaintEvent *_event)
{
    QPainter painter(this);

    drawLine(painter, _event->rect(), m_padding, m_padding, m_padding,
             m_padding);
}

double QDensityWidget::density(double _x)
{
    double sum = 0;

    QList< double >::iterator i = m_data.begin();
    QList< double >::iterator iend = m_data.end();

    for (; i != iend; ++i)
    {
        sum += silverman((_x - *i) / m_bandwidth);
    }

    sum *= 1 / (m_data.size() * m_bandwidth);

    return sum;
}

double QDensityWidget::normal(double _x)
{
    return exp(-.5 * _x * _x) / (m_bandwidth * sqrt(2.0 * 3.1415926535898));
}

void QDensityWidget::drawLine(QPainter &_painter,
                              const QRect &_rect,
                              int _leftPadding,
                              int _rightPadding,
                              int _topPadding,
                              int _bottomPadding)
{
    if (m_data.size() > 1)
    {
        int graphHeight = _rect.height() - _topPadding - _bottomPadding;
        int graphWidth = _rect.width() - _leftPadding - _rightPadding;
        QPoint bl = _rect.bottomLeft();

        QPainterPath path;

        double minX = *std::min_element(m_data.begin(), m_data.end());
        double maxX = *std::max_element(m_data.begin(), m_data.end());
        const double extendX = 0 * (maxX - minX);
        minX -= extendX;
        maxX += extendX;

        double minY = std::numeric_limits< double >::max();
        double maxY = std::numeric_limits< double >::min();

        const double xStep = (maxX - minX) / double(graphWidth - 1);

        const double mean = boost::accumulators::mean(m_accumulator);

        double minDiffToMean = std::numeric_limits< double >::max();
        double meanX = 0;

        QList< QPair< double, double > > points;
        for (double x = minX; x < maxX; x += xStep)
        {
            double y = density(x);
            points.push_back(QPair< double, double >(x, y));
            minY = std::min(minY, y);
            maxY = std::max(maxY, y);

            const double diffToMean = fabs(mean - x);
            if (diffToMean < minDiffToMean)
            {
                meanX = x;
                minDiffToMean = diffToMean;
            }
        }

        const double yStep = double(graphHeight - 1) / (maxY);

        bool first = true;
        QList< QPair< double, double > >::iterator i = points.begin();
        QList< QPair< double, double > >::iterator iend = points.end();

        int x = _leftPadding;
        double y = -_bottomPadding;
        for (; i != iend; ++i)
        {
            y = -_bottomPadding - (yStep * i->second);

            if (first)
            {
                path.moveTo(int(bl.x() + x), int(bl.y() + y));
                first = false;
            }
            else
            {
                path.lineTo(int(bl.x() + x), int(bl.y() + y));
            }

            if (i->first == meanX)
            {
                _painter.setRenderHint(QPainter::Antialiasing, false);
                _painter.setPen(QPen(QColor(Qt::lightGray), 1, Qt::SolidLine,
                                     Qt::RoundCap, Qt::RoundJoin));
                _painter.drawLine(bl.x() + x, bl.y() - _bottomPadding, bl.x() + x,
                                  bl.y() - _bottomPadding - graphHeight);
            }

            ++x;
        }

        if (!path.isEmpty())
        {
            _painter.setRenderHint(QPainter::Antialiasing, true);
            _painter.setPen(
                QPen(m_color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
            _painter.drawPath(path);
        }
    }
}

void QDensityWidget::onObservationInserted(double _data)
{
    if (m_data.size() == m_maxObservations)
    {
        QList< double > newList;
        boost::accumulators::accumulator_set<
            double,
            boost::accumulators::stats< boost::accumulators::tag::variance,
                                        boost::accumulators::tag::mean > >
            accumulator;

        int index = 0;

        QList< double >::iterator i = m_data.begin();
        QList< double >::iterator iend = m_data.end();

        for (; i != iend; ++i)
        {
            if (index % 2)
            {
                newList.push_back(*i);
                accumulator(*i);
            }

            ++index;
        }

        m_data = newList;
        m_accumulator = accumulator;
    }

    m_data.push_back(_data);
    m_accumulator(_data);

    updateBandwidth();
    updateToolTip();
    update();
}

void QDensityWidget::onColorChanged(QColor _color)
{
    m_color = _color;
    update();
}

void QDensityWidget::onPaddingChanged(int _padding)
{
    m_padding = _padding;
    update();
}

void QDensityWidget::onMaxObservationsChanged(int _max)
{
    m_maxObservations = _max;

    while (m_data.size() > m_maxObservations)
    {
        QList< double > newList;
        boost::accumulators::accumulator_set<
            double,
            boost::accumulators::stats< boost::accumulators::tag::variance,
                                        boost::accumulators::tag::mean > >
            accumulator;

        int index = 0;

        QList< double >::iterator i = m_data.begin();
        QList< double >::iterator iend = m_data.end();

        for (; i != iend; ++i)
        {
            if (index % 2)
            {
                newList.push_back(*i);
                accumulator(*i);
            }

            ++index;
        }

        m_data = newList;
        m_accumulator = accumulator;
    }

    updateBandwidth();
    updateToolTip();
    update();
}

void QDensityWidget::updateBandwidth()
{
    const double variance = boost::accumulators::variance(m_accumulator);
    const double sigma = sqrt(variance);

    m_bandwidth = .9 * pow(m_data.size(), -.2) *
                  sigma;  //(std::min(sigma, interQuartile / 1.34));
}

void QDensityWidget::updateToolTip()
{
    const double variance = boost::accumulators::variance(m_accumulator);
    const double sigma = sqrt(variance);
    const double min = *std::min_element(m_data.begin(), m_data.end());
    const double max = *std::max_element(m_data.begin(), m_data.end());
    const double mean = boost::accumulators::mean(m_accumulator);

    setToolTip(QString("%1: %2\n%3: %4\nMin: %5\nMax: %6\nbw: %7")
                   .arg(QString(QChar(0x03BC)), QString::number(mean),
                        QString(QChar(0x03C3)), QString::number(sigma),
                        QString::number(min), QString::number(max),
                        QString::number(m_bandwidth)));
}

}  // namespace dqtx
<commit_msg>Fixed stupid bug where I left silverman in there<commit_after>/* Copyright (c) 2015, Daniel C. Dillon
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <dqtx/QDensityWidget.hpp>
#include <QPainter>
#include <QPen>
#include <QPainterPath>
#include <iostream>
#include <QPaintEvent>
#include <algorithm>
#include <limits>
#include <stdint.h>

namespace dqtx
{
QDensityWidget::QDensityWidget(QWidget *_parent, Qt::WindowFlags _flags)
    : QWidget(_parent, _flags)
    , m_accumulator()
    , m_color(QColor(Qt::black))
    , m_padding(5)
    , m_bandwidth(.5)
    , m_maxObservations(600)
{
    QObject::connect(this, SIGNAL(observationInserted(double)), this,
                     SLOT(onObservationInserted(double)));
    QObject::connect(this, SIGNAL(colorChanged(QColor)), this,
                     SLOT(onColorChanged(QColor)));
    QObject::connect(this, SIGNAL(paddingChanged(int)), this,
                     SLOT(onPaddingChanged(int)));
    QObject::connect(this, SIGNAL(maxObservationsChanged(int)), this,
                     SLOT(onMaxObservationsChanged(int)));
}

void QDensityWidget::insertObservation(const double _data)
{
    emit observationInserted(_data);
}

void QDensityWidget::setColor(const QColor &_color)
{
    emit colorChanged(_color);
}

void QDensityWidget::setPadding(int _padding) { emit paddingChanged(_padding); }

void QDensityWidget::setMaxObservations(int _max)
{
    emit maxObservationsChanged(_max);
}

QSize QDensityWidget::sizeHint() const { return QSize(68, 29); }

void QDensityWidget::paintEvent(QPaintEvent *_event)
{
    QPainter painter(this);

    drawLine(painter, _event->rect(), m_padding, m_padding, m_padding,
             m_padding);
}

double QDensityWidget::density(double _x)
{
    double sum = 0;

    QList< double >::iterator i = m_data.begin();
    QList< double >::iterator iend = m_data.end();

    for (; i != iend; ++i)
    {
        sum += normal((_x - *i) / m_bandwidth);
    }

    sum *= 1 / (m_data.size() * m_bandwidth);

    return sum;
}

double QDensityWidget::normal(double _x)
{
    return exp(-.5 * _x * _x) / (m_bandwidth * sqrt(2.0 * 3.1415926535898));
}

void QDensityWidget::drawLine(QPainter &_painter,
                              const QRect &_rect,
                              int _leftPadding,
                              int _rightPadding,
                              int _topPadding,
                              int _bottomPadding)
{
    if (m_data.size() > 1)
    {
        int graphHeight = _rect.height() - _topPadding - _bottomPadding;
        int graphWidth = _rect.width() - _leftPadding - _rightPadding;
        QPoint bl = _rect.bottomLeft();

        QPainterPath path;

        double minX = *std::min_element(m_data.begin(), m_data.end());
        double maxX = *std::max_element(m_data.begin(), m_data.end());
        const double extendX = 0 * (maxX - minX);
        minX -= extendX;
        maxX += extendX;

        double minY = std::numeric_limits< double >::max();
        double maxY = std::numeric_limits< double >::min();

        const double xStep = (maxX - minX) / double(graphWidth - 1);

        const double mean = boost::accumulators::mean(m_accumulator);

        double minDiffToMean = std::numeric_limits< double >::max();
        double meanX = 0;

        QList< QPair< double, double > > points;
        for (double x = minX; x < maxX; x += xStep)
        {
            double y = density(x);
            points.push_back(QPair< double, double >(x, y));
            minY = std::min(minY, y);
            maxY = std::max(maxY, y);

            const double diffToMean = fabs(mean - x);
            if (diffToMean < minDiffToMean)
            {
                meanX = x;
                minDiffToMean = diffToMean;
            }
        }

        const double yStep = double(graphHeight - 1) / (maxY);

        bool first = true;
        QList< QPair< double, double > >::iterator i = points.begin();
        QList< QPair< double, double > >::iterator iend = points.end();

        int x = _leftPadding;
        double y = -_bottomPadding;
        for (; i != iend; ++i)
        {
            y = -_bottomPadding - (yStep * i->second);

            if (first)
            {
                path.moveTo(int(bl.x() + x), int(bl.y() + y));
                first = false;
            }
            else
            {
                path.lineTo(int(bl.x() + x), int(bl.y() + y));
            }

            if (i->first == meanX)
            {
                _painter.setRenderHint(QPainter::Antialiasing, false);
                _painter.setPen(QPen(QColor(Qt::lightGray), 1, Qt::SolidLine,
                                     Qt::RoundCap, Qt::RoundJoin));
                _painter.drawLine(bl.x() + x, bl.y() - _bottomPadding, bl.x() + x,
                                  bl.y() - _bottomPadding - graphHeight);
            }

            ++x;
        }

        if (!path.isEmpty())
        {
            _painter.setRenderHint(QPainter::Antialiasing, true);
            _painter.setPen(
                QPen(m_color, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
            _painter.drawPath(path);
        }
    }
}

void QDensityWidget::onObservationInserted(double _data)
{
    if (m_data.size() == m_maxObservations)
    {
        QList< double > newList;
        boost::accumulators::accumulator_set<
            double,
            boost::accumulators::stats< boost::accumulators::tag::variance,
                                        boost::accumulators::tag::mean > >
            accumulator;

        int index = 0;

        QList< double >::iterator i = m_data.begin();
        QList< double >::iterator iend = m_data.end();

        for (; i != iend; ++i)
        {
            if (index % 2)
            {
                newList.push_back(*i);
                accumulator(*i);
            }

            ++index;
        }

        m_data = newList;
        m_accumulator = accumulator;
    }

    m_data.push_back(_data);
    m_accumulator(_data);

    updateBandwidth();
    updateToolTip();
    update();
}

void QDensityWidget::onColorChanged(QColor _color)
{
    m_color = _color;
    update();
}

void QDensityWidget::onPaddingChanged(int _padding)
{
    m_padding = _padding;
    update();
}

void QDensityWidget::onMaxObservationsChanged(int _max)
{
    m_maxObservations = _max;

    while (m_data.size() > m_maxObservations)
    {
        QList< double > newList;
        boost::accumulators::accumulator_set<
            double,
            boost::accumulators::stats< boost::accumulators::tag::variance,
                                        boost::accumulators::tag::mean > >
            accumulator;

        int index = 0;

        QList< double >::iterator i = m_data.begin();
        QList< double >::iterator iend = m_data.end();

        for (; i != iend; ++i)
        {
            if (index % 2)
            {
                newList.push_back(*i);
                accumulator(*i);
            }

            ++index;
        }

        m_data = newList;
        m_accumulator = accumulator;
    }

    updateBandwidth();
    updateToolTip();
    update();
}

void QDensityWidget::updateBandwidth()
{
    const double variance = boost::accumulators::variance(m_accumulator);
    const double sigma = sqrt(variance);

    m_bandwidth = .9 * pow(m_data.size(), -.2) *
                  sigma;  //(std::min(sigma, interQuartile / 1.34));
}

void QDensityWidget::updateToolTip()
{
    const double variance = boost::accumulators::variance(m_accumulator);
    const double sigma = sqrt(variance);
    const double min = *std::min_element(m_data.begin(), m_data.end());
    const double max = *std::max_element(m_data.begin(), m_data.end());
    const double mean = boost::accumulators::mean(m_accumulator);

    setToolTip(QString("%1: %2\n%3: %4\nMin: %5\nMax: %6\nbw: %7")
                   .arg(QString(QChar(0x03BC)), QString::number(mean),
                        QString(QChar(0x03C3)), QString::number(sigma),
                        QString::number(min), QString::number(max),
                        QString::number(m_bandwidth)));
}

}  // namespace dqtx
<|endoftext|>


<commit_before>#include <Rcpp.h>
#include <iostream>

using namespace std;
using namespace Rcpp;

#include"somoclu.h"

RcppExport SEXP Rtrain(SEXP data_p,
                       SEXP nEpoch_p,
                       SEXP nSomX_p, SEXP nSomY_p,
                       SEXP radius0_p, SEXP radiusN_p,
                       SEXP radiusCooling_p,
                       SEXP scale0_p, SEXP scaleN_p,
                       SEXP scaleCooling_p,
                       SEXP kernelType_p, SEXP mapType_p,
                       SEXP gridType_p, SEXP compactSupport_p,
                       SEXP neighborhood_p,
                       SEXP codebook_p) {
    Rcpp::NumericMatrix dataMatrix(data_p);
    Rcpp::NumericVector codebook_vec(codebook_p);
    int nVectors = dataMatrix.rows();
    int nDimensions = dataMatrix.cols();
    int nEpoch = as<int>(nEpoch_p);
    unsigned int nSomX = (unsigned int) as<int> (nSomX_p);
    unsigned int nSomY = (unsigned int) as<int> (nSomY_p);
    unsigned int radius0 = (unsigned int) as<int> (radius0_p);
    unsigned int radiusN = (unsigned int) as<int> (radiusN_p);
    string radiusCooling = as<string>(radiusCooling_p);
    unsigned int scale0 = (unsigned int) as<int> (scale0_p);
    unsigned int scaleN = (unsigned int) as<int> (scaleN_p);
    string scaleCooling = as<string> (scaleCooling_p);
    unsigned int kernelType = (unsigned int) as<int>(kernelType_p);
    bool compactSupport = as<bool>(compactSupport_p);
    string mapType = as<string>(mapType_p);
    string gridType = as<string>(gridType_p);
    string neighborhood = as<string>(neighborhood_p);
    int data_length = nVectors * nDimensions;
    float* data = new float[data_length];
    int uMatrix_size = nSomX * nSomY;
    // convert matrix to data c float array
    for(int i = 0; i < nVectors; i++) {
        for(int j = 0; j < nDimensions; j++) {
            data[i * nDimensions + j] = (float) dataMatrix(i, j);
        }
    }
    int codebook_size =  nSomY * nSomX * nDimensions;
    float* codebook = new float[codebook_size];
	for(int i = 0; i < uMatrix_size; i++) {
		for(int j = 0; j < nDimensions; j++) {
			codebook[i * nDimensions + j] = (float) codebook_vec(i ,j);
		}
	}

    int globalBmus_size = nVectors * 2;

    int* globalBmus = new int[globalBmus_size];
    float* uMatrix = new float[uMatrix_size];
    train(data, data_length, nEpoch, nSomX, nSomY,
          nDimensions, nVectors, radius0, radiusN,
          radiusCooling, scale0, scaleN, scaleCooling,
          kernelType, mapType,
          gridType, compactSupport, neighborhood == "gaussian",
          codebook, codebook_size, globalBmus, globalBmus_size,
          uMatrix, uMatrix_size);
    Rcpp::NumericVector globalBmus_vec(globalBmus_size);
    Rcpp::NumericVector uMatrix_vec(uMatrix_size);
    if(codebook != NULL) {
    	for(int i = 0; i < uMatrix_size; i++) {
    			for(int j = 0; j < nDimensions; j++) {
    				codebook_vec(i ,j) = (float) codebook[i * nDimensions + j];
    			}
    		}
    }
    if(globalBmus != NULL) {
        for(int i = 0; i < globalBmus_size; i++) {
            globalBmus_vec(i) = globalBmus[i];
        }
    }
    if(uMatrix != NULL) {
        for(int i = 0; i < uMatrix_size; i++) {
            uMatrix_vec(i) = uMatrix[i];
        }
    }
    delete[] codebook;
    delete[] globalBmus;
    delete[] uMatrix;
    return Rcpp::List::create(Rcpp::Named("codebook") = codebook_vec,
                              Rcpp::Named("globalBmus") = globalBmus_vec,
                              Rcpp::Named("uMatrix") = uMatrix_vec);;
}

RCPP_MODULE(Rsomoclu) {
    Rcpp::function("Rtrain", &Rtrain);
}
<commit_msg>return matrix<commit_after>#include <Rcpp.h>
#include <iostream>

using namespace std;
using namespace Rcpp;

#include"somoclu.h"

RcppExport SEXP Rtrain(SEXP data_p,
                       SEXP nEpoch_p,
                       SEXP nSomX_p, SEXP nSomY_p,
                       SEXP radius0_p, SEXP radiusN_p,
                       SEXP radiusCooling_p,
                       SEXP scale0_p, SEXP scaleN_p,
                       SEXP scaleCooling_p,
                       SEXP kernelType_p, SEXP mapType_p,
                       SEXP gridType_p, SEXP compactSupport_p,
                       SEXP neighborhood_p,
                       SEXP codebook_p) {
    Rcpp::NumericMatrix dataMatrix(data_p);
    Rcpp::NumericMatrix codebookMatrix(codebook_p);
    int nVectors = dataMatrix.rows();
    int nDimensions = dataMatrix.cols();
    int nEpoch = as<int>(nEpoch_p);
    unsigned int nSomX = (unsigned int) as<int> (nSomX_p);
    unsigned int nSomY = (unsigned int) as<int> (nSomY_p);
    unsigned int radius0 = (unsigned int) as<int> (radius0_p);
    unsigned int radiusN = (unsigned int) as<int> (radiusN_p);
    string radiusCooling = as<string>(radiusCooling_p);
    unsigned int scale0 = (unsigned int) as<int> (scale0_p);
    unsigned int scaleN = (unsigned int) as<int> (scaleN_p);
    string scaleCooling = as<string> (scaleCooling_p);
    unsigned int kernelType = (unsigned int) as<int>(kernelType_p);
    bool compactSupport = as<bool>(compactSupport_p);
    string mapType = as<string>(mapType_p);
    string gridType = as<string>(gridType_p);
    string neighborhood = as<string>(neighborhood_p);
    int data_length = nVectors * nDimensions;
    float* data = new float[data_length];
    int uMatrix_size = nSomX * nSomY;
    // convert matrix to data c float array
    for(int i = 0; i < nVectors; i++) {
        for(int j = 0; j < nDimensions; j++) {
            data[i * nDimensions + j] = (float) dataMatrix(i, j);
        }
    }
    int codebook_size =  nSomY * nSomX * nDimensions;
    float* codebook = new float[codebook_size];
	for(int i = 0; i < uMatrix_size; i++) {
		for(int j = 0; j < nDimensions; j++) {
			codebook[i * nDimensions + j] = (float) codebookMatrix(i ,j);
		}
	}

    int globalBmus_size = nVectors * 2;

    int* globalBmus = new int[globalBmus_size];
    float* uMatrix = new float[uMatrix_size];
    train(data, data_length, nEpoch, nSomX, nSomY,
          nDimensions, nVectors, radius0, radiusN,
          radiusCooling, scale0, scaleN, scaleCooling,
          kernelType, mapType,
          gridType, compactSupport, neighborhood == "gaussian",
          codebook, codebook_size, globalBmus, globalBmus_size,
          uMatrix, uMatrix_size);
    Rcpp::NumericMatrix globalBmusMatrix(nVectors, 2);
    Rcpp::NumericMatrix uMatrixMatrix(nSomX, nSomY);
    if(codebook != NULL) {
    	for(int i = 0; i < uMatrix_size; i++) {
    			for(int j = 0; j < nDimensions; j++) {
    				codebookMatrix(i ,j) = (float) codebook[i * nDimensions + j];
    			}
    		}
    }
    if(globalBmus != NULL) {
        for(int i = 0; i < nVectors; i++) {
        	for (int j = 0; j < 2; j++) {
        		globalBmusMatrix(i, j) = globalBmus[i * 2 + j];
        	}
        }
    }
    if(uMatrix != NULL) {
        for(int i = 0; i < nSomX; i++) {
        	for (int j = 0; j < nSomY; j++) {
        		uMatrixMatrix(i, j) = uMatrix[i * nSomY + j];
        	}
        }
    }
    delete[] codebook;
    delete[] globalBmus;
    delete[] uMatrix;
    return Rcpp::List::create(Rcpp::Named("codebook") = codebookMatrix,
                              Rcpp::Named("globalBmus") = globalBmusMatrix,
                              Rcpp::Named("uMatrix") = uMatrixMatrix);;
}

RCPP_MODULE(Rsomoclu) {
    Rcpp::function("Rtrain", &Rtrain);
}
<|endoftext|>


<commit_before>/**
 * @file cache.cpp
 *
 * @date Nov 21, 2012
 * @author perämäki
 */

#include "cache.h"
#include "logger_factory.h"
#include "info.h"
#include <time.h>
#include "plugin_factory.h"
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace himan::plugin;

typedef lock_guard<mutex> Lock;

cache::cache()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("cache"));
}

string cache::UniqueName(const shared_ptr<const himan::info> info)
{
	string forecast_time = info->Time().OriginDateTime()->String("%Y-%m-%d_%H:%M:%S");
	string valid_time = info->Time().ValidDateTime()->String("%Y-%m-%d_%H:%M:%S");
	string param = info->Param().Name();
	string projection = boost::lexical_cast<string> (info->Projection());
	string level_value = boost::lexical_cast<string>(info->Level().Value());
	string level = HPLevelTypeToString.at(info->Level().Type());
	return forecast_time + '_' + valid_time + '_' + param + '_' + level + '_' + projection + '_' + level_value;

}

string cache::UniqueNameFromOptions(const search_options& options)
{
	string forecast_time = (options.time.OriginDateTime())->String("%Y-%m-%d_%H:%M:%S");
	string valid_time = (options.time.ValidDateTime())->String("%Y-%m-%d_%H:%M:%S");
	string param = (options.param).Name();
	string projection = (options.configuration)->TargetProjection();
	string level_value = boost::lexical_cast<string>((options.level).Value());
	string level = HPLevelTypeToString.at(options.level.Type());
	return forecast_time + '_' + valid_time + '_' + param + '_' + level + '_' + projection + '_' + level_value;
}

void cache::Insert(shared_ptr<himan::info> anInfo, bool activeOnly)
{

	if (activeOnly)
	{
		SplitToPool(anInfo);
	}
	else
	{
		for (anInfo->ResetTime(); anInfo->NextTime(); )
		{
			for (anInfo->ResetLevel(); anInfo->NextLevel(); )
			{
				for (anInfo->ResetParam(); anInfo->NextParam(); )
				{
					SplitToPool(anInfo);
				}
			}
		}
	}
}

void cache::SplitToPool(const shared_ptr<info> anInfo)
{
	vector<param> params;
	vector<level> levels;
	vector<forecast_time> times;

	params.push_back(anInfo->Param());
	levels.push_back(anInfo->Level());
	times.push_back(anInfo->Time());

	shared_ptr<grid> aGrid = anInfo->Grid();

	shared_ptr<info> newInfo (new info(*anInfo));

	newInfo->Params(params);
	newInfo->Levels(levels);
	newInfo->Times(times);
	newInfo->Create();
	newInfo->First();
	newInfo->Grid(aGrid);

	string uniqueName = UniqueName(newInfo);

	if (!(cache_pool::Instance()->Find(uniqueName)))
	{
		cache_pool::Instance()->Insert(uniqueName, newInfo);
	}
}

void cache::Insert(const vector<shared_ptr<himan::info>>& infos, bool activeOnly)
{
	for (size_t i = 0; i < infos.size(); i++)
	{
		Insert(infos[i], activeOnly);
		//Clean();
	}
}

vector<shared_ptr<himan::info>> cache::GetInfo(const search_options& options)
{
	string uniqueName = UniqueNameFromOptions(options);

	vector<shared_ptr<himan::info>> info;

	if (cache_pool::Instance()->Find(uniqueName))
	{
		info.push_back(cache_pool::Instance()->GetInfo(uniqueName));
		itsLogger->Debug( "Found matching data for " + uniqueName);
	}

	return info;
}

void cache::Clean()
{
	cache_pool::Instance()->Clean();
}

cache_pool* cache_pool::itsInstance = NULL;

cache_pool::cache_pool()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("cache_pool"));
}

cache_pool* cache_pool::Instance()
{
	if (!itsInstance)
	{
		itsInstance = new cache_pool();
	}

	return itsInstance;
}

bool cache_pool::Find(const string& uniqueName)
{
	for (map<string, shared_ptr<himan::info>>::iterator it = itsCache.begin(); it != itsCache.end(); ++it)
	{
		if (it->first == uniqueName)
		{
			return true;
		}
	}

	return false;
}

void cache_pool::Insert(const string& uniqueName, shared_ptr<himan::info> anInfo)
{
	Lock lock(itsInsertMutex);

	itsCache.insert(pair<string, shared_ptr<himan::info>>(uniqueName, anInfo));
	time_t timer;
	time(&timer);
	itsCacheItems.insert(pair<string, time_t>(uniqueName, timer));
	itsLogger->Debug("Data added to cache. UniqueName: " + uniqueName);

}

void cache_pool::Clean()
{
	Lock lock(itsDeleteMutex);

	for (map<string, time_t>::iterator it = itsCacheItems.begin(); it != itsCacheItems.end(); ++it)
	{
		time_t timer;
		time(&timer);
		if (timer - it->second > 10)
		{
			string name = it->first;
			itsCache.erase(name);
			itsCacheItems.erase(name);
			itsLogger->Debug("Data cleared from cache: " + name);
		}
	}
}

shared_ptr<himan::info> cache_pool::GetInfo(const string& uniqueName)
{
	Lock lock(itsGetMutex);

	return itsCache[uniqueName];
}
<commit_msg>Changing log level<commit_after>/**
 * @file cache.cpp
 *
 * @date Nov 21, 2012
 * @author perämäki
 */

#include "cache.h"
#include "logger_factory.h"
#include "info.h"
#include <time.h>
#include "plugin_factory.h"
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace himan::plugin;

typedef lock_guard<mutex> Lock;

cache::cache()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("cache"));
}

string cache::UniqueName(const shared_ptr<const himan::info> info)
{
	string forecast_time = info->Time().OriginDateTime()->String("%Y-%m-%d_%H:%M:%S");
	string valid_time = info->Time().ValidDateTime()->String("%Y-%m-%d_%H:%M:%S");
	string param = info->Param().Name();
	string level_value = boost::lexical_cast<string>(info->Level().Value());
	string level = HPLevelTypeToString.at(info->Level().Type());
	return forecast_time + '_' + valid_time + '_' + param + '_' + level + '_' + level_value;

}

string cache::UniqueNameFromOptions(const search_options& options)
{
	string forecast_time = (options.time.OriginDateTime())->String("%Y-%m-%d_%H:%M:%S");
	string valid_time = (options.time.ValidDateTime())->String("%Y-%m-%d_%H:%M:%S");
	string param = (options.param).Name();
	string level_value = boost::lexical_cast<string>((options.level).Value());
	string level = HPLevelTypeToString.at(options.level.Type());
	return forecast_time + '_' + valid_time + '_' + param + '_' + level + '_' + level_value;
}

void cache::Insert(shared_ptr<himan::info> anInfo, bool activeOnly)
{

	if (activeOnly)
	{
		SplitToPool(anInfo);
	}
	else
	{
		for (anInfo->ResetTime(); anInfo->NextTime(); )
		{
			for (anInfo->ResetLevel(); anInfo->NextLevel(); )
			{
				for (anInfo->ResetParam(); anInfo->NextParam(); )
				{
					SplitToPool(anInfo);
				}
			}
		}
	}
}

void cache::SplitToPool(const shared_ptr<info> anInfo)
{
	vector<param> params;
	vector<level> levels;
	vector<forecast_time> times;

	params.push_back(anInfo->Param());
	levels.push_back(anInfo->Level());
	times.push_back(anInfo->Time());

	shared_ptr<grid> aGrid = anInfo->Grid();

	shared_ptr<info> newInfo (new info(*anInfo));

	newInfo->Params(params);
	newInfo->Levels(levels);
	newInfo->Times(times);
	newInfo->Create();
	newInfo->First();
	newInfo->Grid(aGrid);

	string uniqueName = UniqueName(newInfo);

	if (!(cache_pool::Instance()->Find(uniqueName)))
	{
		cache_pool::Instance()->Insert(uniqueName, newInfo);
	}
}

void cache::Insert(const vector<shared_ptr<himan::info>>& infos, bool activeOnly)
{
	for (size_t i = 0; i < infos.size(); i++)
	{
		Insert(infos[i], activeOnly);
		//Clean();
	}
}

vector<shared_ptr<himan::info>> cache::GetInfo(const search_options& options)
{
	string uniqueName = UniqueNameFromOptions(options);

	vector<shared_ptr<himan::info>> info;

	if (cache_pool::Instance()->Find(uniqueName))
	{
		info.push_back(cache_pool::Instance()->GetInfo(uniqueName));
		itsLogger->Trace( "Found matching data for " + uniqueName);
	}

	return info;
}

void cache::Clean()
{
	cache_pool::Instance()->Clean();
}

cache_pool* cache_pool::itsInstance = NULL;

cache_pool::cache_pool()
{
    itsLogger = std::unique_ptr<logger> (logger_factory::Instance()->GetLog("cache_pool"));
}

cache_pool* cache_pool::Instance()
{
	if (!itsInstance)
	{
		itsInstance = new cache_pool();
	}

	return itsInstance;
}

bool cache_pool::Find(const string& uniqueName)
{
	for (map<string, shared_ptr<himan::info>>::iterator it = itsCache.begin(); it != itsCache.end(); ++it)
	{
		if (it->first == uniqueName)
		{
			return true;
		}
	}

	return false;
}

void cache_pool::Insert(const string& uniqueName, shared_ptr<himan::info> anInfo)
{
	Lock lock(itsInsertMutex);

	itsCache.insert(pair<string, shared_ptr<himan::info>>(uniqueName, anInfo));
	time_t timer;
	time(&timer);
	itsCacheItems.insert(pair<string, time_t>(uniqueName, timer));
	itsLogger->Trace("Data added to cache. UniqueName: " + uniqueName);

}

void cache_pool::Clean()
{
	Lock lock(itsDeleteMutex);

	for (map<string, time_t>::iterator it = itsCacheItems.begin(); it != itsCacheItems.end(); ++it)
	{
		time_t timer;
		time(&timer);
		if (timer - it->second > 10)
		{
			string name = it->first;
			itsCache.erase(name);
			itsCacheItems.erase(name);
			itsLogger->Trace("Data cleared from cache: " + name);
		}
	}
}

shared_ptr<himan::info> cache_pool::GetInfo(const string& uniqueName)
{
	Lock lock(itsGetMutex);

	return itsCache[uniqueName];
}
<|endoftext|>


<commit_before>/**
 * @file radon.cpp
 *
 * @date Oct 28, 2012
 * @author tack
 */

#include "radon.h"
#include "logger_factory.h"
#include "plugin_factory.h"
#include <thread>
#include <sstream>
#include "util.h"
#include "unistd.h" // getuid())
#include "regular_grid.h"

using namespace std;
using namespace himan::plugin;

const int MAX_WORKERS = 16;
static once_flag oflag;

radon::radon() : itsInit(false), itsRadonDB()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog("radon"));

	// no lambda functions for gcc 4.4 :(
	// call_once(oflag, [](){ NFmiNeonsDBPool::MaxWorkers(MAX_WORKERS); });

	call_once(oflag, &himan::plugin::radon::InitPool, this);
}

void radon::InitPool()
{
	NFmiRadonDBPool::Instance()->MaxWorkers(MAX_WORKERS);

	uid_t uid = getuid();

	if (uid == 1459) // weto
	{
		NFmiRadonDBPool::Instance()->Username("wetodb");
		NFmiRadonDBPool::Instance()->Password("3loHRgdio");
	}
}

vector<string> radon::Files(search_options& options)
{

	Init();

	vector<string> files;

	string analtime = options.time.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00");
	string levelvalue = boost::lexical_cast<string> (options.level.Value());

	string ref_prod = options.prod.Name();
	// long no_vers = options.prod.TableVersion();

	string level_name = HPLevelTypeToString.at(options.level.Type());

	vector<vector<string> > gridgeoms;
	vector<string> sourceGeoms = options.configuration->SourceGeomNames();

	if (sourceGeoms.empty())
	{
		// Get all geometries
		gridgeoms = itsRadonDB->GetGridGeoms(ref_prod, analtime);
	}
	else
	{
		for (size_t i = 0; i < sourceGeoms.size(); i++)
		{
			vector<vector<string>> geoms = itsRadonDB->GetGridGeoms(ref_prod, analtime, sourceGeoms[i]);
			gridgeoms.insert(gridgeoms.end(), geoms.begin(), geoms.end());
		}
	}

	if (gridgeoms.empty())
	{
		itsLogger->Warning("No geometries found for producer " + ref_prod +
		", analysistime " + analtime + ", source geom name(s) '" + util::Join(sourceGeoms, ",") +"', param " + options.param.Name());

		return files;
	}

	string forecastTypeValue = (options.ftype.Type() == kEpsPerturbation) ? boost::lexical_cast<string> (options.ftype.Value()) : "-1";

	for (size_t i = 0; i < gridgeoms.size(); i++)
	{
		string tablename = gridgeoms[i][1];
		string geomid = gridgeoms[i][0];

		string parm_name = options.param.Name();

		string query = "SELECT param_id, level_id, level_value, forecast_period, file_location, file_server "
				   "FROM "+tablename+"_v "
				   "WHERE analysis_time = '"+analtime+"' "
				   "AND param_name = '"+parm_name+"' "
				   "AND level_name = upper('"+level_name+"') "
				   "AND level_value = "+levelvalue+" "
				   "AND forecast_period = '"+util::MakeSQLInterval(options.time)+"' "
				   "AND geometry_id = "+geomid+" "
				   "AND forecast_type_id = "+boost::lexical_cast<string> (options.ftype.Type())+" "
				   "AND forecast_type_value = "+forecastTypeValue+" "
				   "ORDER BY forecast_period, level_id, level_value";

		itsRadonDB->Query(query);

		vector<string> values = itsRadonDB->FetchRow();

		if (values.empty())
		{
			continue;
		}

		itsLogger->Trace("Found data for parameter " + parm_name + " from radon geometry " + gridgeoms[i][3]);

		files.push_back(values[4]);

		break; // discontinue loop on first positive match

	}

	return files;

}

bool radon::Save(const info& resultInfo, const string& theFileName)
{

	Init();

	stringstream query;

	if (resultInfo.Grid()->Type() != kRegularGrid)
	{
		itsLogger->Error("Only grid data can be stored to radon for now");
		return false;
	}

	const regular_grid* g = dynamic_cast<regular_grid*> (resultInfo.Grid());

	/*
	 * 1. Get grid information
	 * 2. Get model information
	 * 3. Get data set information (ie model run)
	 * 4. Insert or update
	 */

	himan::point firstGridPoint = g->FirstGridPoint();

	// get grib1 gridType

	int gridType = -1;

	switch (g->Projection()) {
		case 10:
			gridType = 0; // latlon
			break;
		case 11:
			gridType = 10; // rot latlon
			break;
		case 13:
			gridType = 5; // polster
			break;
		default:
			throw runtime_error("Unsupported projection: " + HPProjectionTypeToString.at(g->Projection()));
	}

        auto geominfo = itsRadonDB->GetGeometryDefinition(g->Ni(), g->Nj(), firstGridPoint.Y(), firstGridPoint.X(), g->Di(), g->Dj(), 1, gridType);

	if (geominfo.empty())
	{
		itsLogger->Warning("Grid geometry not found from radon");
		return false;
	}

	string geom_id = geominfo["id"];

	query.str("");

	query	<< "SELECT "
			<< "id, table_name "
			<< "FROM as_grid "
			<< "WHERE geometry_id = '" << geom_id << "'"
			<< " AND analysis_time = '" << resultInfo.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00") << "'"
			<< " AND producer_id = " << resultInfo.Producer().Id();

	itsRadonDB->Query(query.str());

	auto row = itsRadonDB->FetchRow();

	if (row.empty())
	{
		itsLogger->Warning("Data set definition not found from radon");
		return false;
	}

	string table_name = row[1];
	string dset_id = row[0];

	query.str("");

	char host[255];
	gethostname(host, 255);

	auto paraminfo = itsRadonDB->GetParameterFromDatabaseName(resultInfo.Producer().Id(), resultInfo.Param().Name());

	if (paraminfo.empty())
	{
		itsLogger->Error("Parameter information not found from radon for parameter " + resultInfo.Param().Name());
		return false;
	}

	auto levelinfo = itsRadonDB->GetLevelFromGrib(resultInfo.Producer().Id(), resultInfo.Level().Type(), 1);

	if (levelinfo.empty())
	{
		itsLogger->Error("Level information not found from radon for level " + resultInfo.Level().Name());
		return false;
	}

	/*
	 * We have our own error logging for unique key violations
	 */

	// itsRadonDB->Verbose(false);

	double forecastTypeValue = (resultInfo.ForecastType().Type() == kEpsPerturbation) ? resultInfo.ForecastType().Value() : -1.;

	string analysisTime = resultInfo.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00");

	query  << "INSERT INTO data." << table_name
		   << " (producer_id, analysis_time, geometry_id, param_id, level_id, level_value, forecast_period, forecast_type_id, forecast_type_value, file_location, file_server) VALUES ("
		   << resultInfo.Producer().Id() << ", "
		   << "'" << analysisTime << "', "
		   << geom_id << ", "
		   << paraminfo["id"] << ", "
		   << levelinfo["id"] << ", "
		   << resultInfo.Level().Value() << ", "
		   << "'" << util::MakeSQLInterval(resultInfo.Time()) << "', "
		   << resultInfo.ForecastType().Type() << ", "
		   << forecastTypeValue << ","
		   << "'" << theFileName << "', "
		   << "'" << host << "')"
		   ;

	try
	{
		itsRadonDB->Execute(query.str());
		query.str("");

		query << "UPDATE as_grid SET record_count = record_count+1 WHERE producer_id = " << resultInfo.Producer().Id()
				<< " AND geometry_id = " << geom_id
				<< " AND analysis_time = '" << analysisTime << "'";

		itsRadonDB->Execute(query.str());
		itsRadonDB->Commit();
	}
	catch (const pqxx::unique_violation& e)
	{
		itsRadonDB->Rollback();

		query.str("");
		query << "UPDATE data." << table_name << " SET "
				<< "file_location = '" << theFileName << "', "
				<< "file_server = '" << host << "' WHERE "
				<< "producer_id = " << resultInfo.Producer().Id() << " AND "
				<< "analysis_time = '" << analysisTime << "' AND "
				<< "geometry_id = " << geom_id << " AND "
				<< "param_id = " << paraminfo["id"] << " AND "
				<< "level_id = " << levelinfo["id"] << " AND "
				<< "level_value = " << resultInfo.Level().Value() << " AND "
				<< "forecast_period = " << "'" << util::MakeSQLInterval(resultInfo.Time()) << "' AND "
				<< "forecast_type_id = " << resultInfo.ForecastType().Type() << " AND "
				<< "forecast_type_value = " << forecastTypeValue;

		itsRadonDB->Execute(query.str());
		itsRadonDB->Commit();
	}

	itsLogger->Trace("Saved information on file '" + theFileName + "' to radon");

	return true;
}

map<string,string> radon::Grib1ParameterName(long producer, long fmiParameterId, long codeTableVersion, long timeRangeIndicator, long levelId, double level_value)
{
	Init();

	map<string,string> paramName = itsRadonDB->GetParameterFromGrib1(producer, codeTableVersion, fmiParameterId, timeRangeIndicator, levelId, level_value);
	return paramName;
}

map<string,string> radon::Grib2ParameterName(long fmiParameterId, long category, long discipline, long producer, long levelId, double level_value)
{
	Init();

	map<string,string> paramName = itsRadonDB->GetParameterFromGrib2(producer, discipline, category, fmiParameterId, levelId, level_value);
	return paramName;
}

string radon::ProducerMetaData(long producerId, const string& attribute) const
{
	string ret;

	if (attribute == "last hybrid level number")
	{
		switch (producerId)
		{
			case 1:
			case 199:
			case 210:
			case 230:
				ret = "65";
			break;

			case 131:
			case 240:
				ret = "137";
				break;

			default:
				throw runtime_error(ClassName() + ": Producer not supported");
				break;

		}
	}
	else if (attribute == "first hybrid level number")
	{
		switch (producerId)
		{
			case 1:
			case 199:
			case 210:
			case 230:
				ret = "1";
				break;

			case 131:
			case 240:
				ret = "24";
				break;

			default:
				throw runtime_error(ClassName() + ": Producer not supported");
				break;

		}
	}
	else
	{
		throw runtime_error(ClassName() + ": Attribute not recognized");
	}

	return ret;

	// In the future maybe something like this:

	//Init();

	//string query = "SELECT value FROM producers_eav WHERE producer_id = " + boost::lexical_cast<string> (producerId) + " AND attribute = '" + attribute + "'";
}

<commit_msg>read analysis fields for ecmwf<commit_after>/**
 * @file radon.cpp
 *
 * @date Oct 28, 2012
 * @author tack
 */

#include "radon.h"
#include "logger_factory.h"
#include "plugin_factory.h"
#include <thread>
#include <sstream>
#include "util.h"
#include "unistd.h" // getuid())
#include "regular_grid.h"

using namespace std;
using namespace himan::plugin;

const int MAX_WORKERS = 16;
static once_flag oflag;

radon::radon() : itsInit(false), itsRadonDB()
{
	itsLogger = unique_ptr<logger> (logger_factory::Instance()->GetLog("radon"));

	// no lambda functions for gcc 4.4 :(
	// call_once(oflag, [](){ NFmiNeonsDBPool::MaxWorkers(MAX_WORKERS); });

	call_once(oflag, &himan::plugin::radon::InitPool, this);
}

void radon::InitPool()
{
	NFmiRadonDBPool::Instance()->MaxWorkers(MAX_WORKERS);

	uid_t uid = getuid();

	if (uid == 1459) // weto
	{
		NFmiRadonDBPool::Instance()->Username("wetodb");
		NFmiRadonDBPool::Instance()->Password("3loHRgdio");
	}
}

vector<string> radon::Files(search_options& options)
{

	Init();

	vector<string> files;

	string analtime = options.time.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00");
	string levelvalue = boost::lexical_cast<string> (options.level.Value());

	string ref_prod = options.prod.Name();
	// long no_vers = options.prod.TableVersion();

	string level_name = HPLevelTypeToString.at(options.level.Type());

	vector<vector<string> > gridgeoms;
	vector<string> sourceGeoms = options.configuration->SourceGeomNames();

	if (sourceGeoms.empty())
	{
		// Get all geometries
		gridgeoms = itsRadonDB->GetGridGeoms(ref_prod, analtime);
	}
	else
	{
		for (size_t i = 0; i < sourceGeoms.size(); i++)
		{
			vector<vector<string>> geoms = itsRadonDB->GetGridGeoms(ref_prod, analtime, sourceGeoms[i]);
			gridgeoms.insert(gridgeoms.end(), geoms.begin(), geoms.end());
		}
	}

	if (gridgeoms.empty())
	{
		itsLogger->Warning("No geometries found for producer " + ref_prod +
		", analysistime " + analtime + ", source geom name(s) '" + util::Join(sourceGeoms, ",") +"', param " + options.param.Name());

		return files;
	}

	string forecastTypeValue = (options.ftype.Type() == kEpsPerturbation) ? boost::lexical_cast<string> (options.ftype.Value()) : "-1";
	string forecastTypeId = boost::lexical_cast<string> (options.ftype.Type());

	if (options.time.Step() == 0 && options.ftype.Type() == 1)
	{
		// ECMWF (and maybe others) use forecast type id == 2 for analysis hour
		forecastTypeId += ",2";
	}

	for (size_t i = 0; i < gridgeoms.size(); i++)
	{
		string tablename = gridgeoms[i][1];
		string geomid = gridgeoms[i][0];

		string parm_name = options.param.Name();

		string query = "SELECT param_id, level_id, level_value, forecast_period, file_location, file_server "
				   "FROM "+tablename+"_v "
				   "WHERE analysis_time = '"+analtime+"' "
				   "AND param_name = '"+parm_name+"' "
				   "AND level_name = upper('"+level_name+"') "
				   "AND level_value = "+levelvalue+" "
				   "AND forecast_period = '"+util::MakeSQLInterval(options.time)+"' "
				   "AND geometry_id = "+geomid+" "
				   "AND forecast_type_id IN ("+forecastTypeId+") "
				   "AND forecast_type_value = "+forecastTypeValue+" "
				   "ORDER BY forecast_period, level_id, level_value";

		itsRadonDB->Query(query);

		vector<string> values = itsRadonDB->FetchRow();

		if (values.empty())
		{
			continue;
		}

		itsLogger->Trace("Found data for parameter " + parm_name + " from radon geometry " + gridgeoms[i][3]);

		files.push_back(values[4]);

		break; // discontinue loop on first positive match

	}

	return files;

}

bool radon::Save(const info& resultInfo, const string& theFileName)
{

	Init();

	stringstream query;

	if (resultInfo.Grid()->Type() != kRegularGrid)
	{
		itsLogger->Error("Only grid data can be stored to radon for now");
		return false;
	}

	const regular_grid* g = dynamic_cast<regular_grid*> (resultInfo.Grid());

	/*
	 * 1. Get grid information
	 * 2. Get model information
	 * 3. Get data set information (ie model run)
	 * 4. Insert or update
	 */

	himan::point firstGridPoint = g->FirstGridPoint();

	// get grib1 gridType

	int gridType = -1;

	switch (g->Projection()) {
		case 10:
			gridType = 0; // latlon
			break;
		case 11:
			gridType = 10; // rot latlon
			break;
		case 13:
			gridType = 5; // polster
			break;
		default:
			throw runtime_error("Unsupported projection: " + HPProjectionTypeToString.at(g->Projection()));
	}

        auto geominfo = itsRadonDB->GetGeometryDefinition(g->Ni(), g->Nj(), firstGridPoint.Y(), firstGridPoint.X(), g->Di(), g->Dj(), 1, gridType);

	if (geominfo.empty())
	{
		itsLogger->Warning("Grid geometry not found from radon");
		return false;
	}

	string geom_id = geominfo["id"];

	query.str("");

	query	<< "SELECT "
			<< "id, table_name "
			<< "FROM as_grid "
			<< "WHERE geometry_id = '" << geom_id << "'"
			<< " AND analysis_time = '" << resultInfo.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00") << "'"
			<< " AND producer_id = " << resultInfo.Producer().Id();

	itsRadonDB->Query(query.str());

	auto row = itsRadonDB->FetchRow();

	if (row.empty())
	{
		itsLogger->Warning("Data set definition not found from radon");
		return false;
	}

	string table_name = row[1];
	string dset_id = row[0];

	query.str("");

	char host[255];
	gethostname(host, 255);

	auto paraminfo = itsRadonDB->GetParameterFromDatabaseName(resultInfo.Producer().Id(), resultInfo.Param().Name());

	if (paraminfo.empty())
	{
		itsLogger->Error("Parameter information not found from radon for parameter " + resultInfo.Param().Name());
		return false;
	}

	auto levelinfo = itsRadonDB->GetLevelFromGrib(resultInfo.Producer().Id(), resultInfo.Level().Type(), 1);

	if (levelinfo.empty())
	{
		itsLogger->Error("Level information not found from radon for level " + resultInfo.Level().Name());
		return false;
	}

	/*
	 * We have our own error logging for unique key violations
	 */

	// itsRadonDB->Verbose(false);

	double forecastTypeValue = (resultInfo.ForecastType().Type() == kEpsPerturbation) ? resultInfo.ForecastType().Value() : -1.;

	string analysisTime = resultInfo.OriginDateTime().String("%Y-%m-%d %H:%M:%S+00");

	query  << "INSERT INTO data." << table_name
		   << " (producer_id, analysis_time, geometry_id, param_id, level_id, level_value, forecast_period, forecast_type_id, forecast_type_value, file_location, file_server) VALUES ("
		   << resultInfo.Producer().Id() << ", "
		   << "'" << analysisTime << "', "
		   << geom_id << ", "
		   << paraminfo["id"] << ", "
		   << levelinfo["id"] << ", "
		   << resultInfo.Level().Value() << ", "
		   << "'" << util::MakeSQLInterval(resultInfo.Time()) << "', "
		   << resultInfo.ForecastType().Type() << ", "
		   << forecastTypeValue << ","
		   << "'" << theFileName << "', "
		   << "'" << host << "')"
		   ;

	try
	{
		itsRadonDB->Execute(query.str());
		query.str("");

		query << "UPDATE as_grid SET record_count = record_count+1 WHERE producer_id = " << resultInfo.Producer().Id()
				<< " AND geometry_id = " << geom_id
				<< " AND analysis_time = '" << analysisTime << "'";

		itsRadonDB->Execute(query.str());
		itsRadonDB->Commit();
	}
	catch (const pqxx::unique_violation& e)
	{
		itsRadonDB->Rollback();

		query.str("");
		query << "UPDATE data." << table_name << " SET "
				<< "file_location = '" << theFileName << "', "
				<< "file_server = '" << host << "' WHERE "
				<< "producer_id = " << resultInfo.Producer().Id() << " AND "
				<< "analysis_time = '" << analysisTime << "' AND "
				<< "geometry_id = " << geom_id << " AND "
				<< "param_id = " << paraminfo["id"] << " AND "
				<< "level_id = " << levelinfo["id"] << " AND "
				<< "level_value = " << resultInfo.Level().Value() << " AND "
				<< "forecast_period = " << "'" << util::MakeSQLInterval(resultInfo.Time()) << "' AND "
				<< "forecast_type_id = " << resultInfo.ForecastType().Type() << " AND "
				<< "forecast_type_value = " << forecastTypeValue;

		itsRadonDB->Execute(query.str());
		itsRadonDB->Commit();
	}

	itsLogger->Trace("Saved information on file '" + theFileName + "' to radon");

	return true;
}

map<string,string> radon::Grib1ParameterName(long producer, long fmiParameterId, long codeTableVersion, long timeRangeIndicator, long levelId, double level_value)
{
	Init();

	map<string,string> paramName = itsRadonDB->GetParameterFromGrib1(producer, codeTableVersion, fmiParameterId, timeRangeIndicator, levelId, level_value);
	return paramName;
}

map<string,string> radon::Grib2ParameterName(long fmiParameterId, long category, long discipline, long producer, long levelId, double level_value)
{
	Init();

	map<string,string> paramName = itsRadonDB->GetParameterFromGrib2(producer, discipline, category, fmiParameterId, levelId, level_value);
	return paramName;
}

string radon::ProducerMetaData(long producerId, const string& attribute) const
{
	string ret;

	if (attribute == "last hybrid level number")
	{
		switch (producerId)
		{
			case 1:
			case 199:
			case 210:
			case 230:
				ret = "65";
			break;

			case 131:
			case 240:
				ret = "137";
				break;

			default:
				throw runtime_error(ClassName() + ": Producer not supported");
				break;

		}
	}
	else if (attribute == "first hybrid level number")
	{
		switch (producerId)
		{
			case 1:
			case 199:
			case 210:
			case 230:
				ret = "1";
				break;

			case 131:
			case 240:
				ret = "24";
				break;

			default:
				throw runtime_error(ClassName() + ": Producer not supported");
				break;

		}
	}
	else
	{
		throw runtime_error(ClassName() + ": Attribute not recognized");
	}

	return ret;

	// In the future maybe something like this:

	//Init();

	//string query = "SELECT value FROM producers_eav WHERE producer_id = " + boost::lexical_cast<string> (producerId) + " AND attribute = '" + attribute + "'";
}

<|endoftext|>


<commit_before><commit_msg>Aborted setSource if no output formats are available<commit_after><|endoftext|>


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

#pragma once

#include <stdint.h>

namespace px4
{

class WorkQueue; // forward declaration

struct wq_config_t {
	const char *name;
	uint16_t stacksize;
	int8_t relative_priority; // relative to max
};

namespace wq_configurations
{
static constexpr wq_config_t rate_ctrl{"wq:rate_ctrl", 1664, 0}; // PX4 inner loop highest priority

static constexpr wq_config_t SPI0{"wq:SPI0", 2336, -1};
static constexpr wq_config_t SPI1{"wq:SPI1", 2336, -2};
static constexpr wq_config_t SPI2{"wq:SPI2", 2336, -3};
static constexpr wq_config_t SPI3{"wq:SPI3", 2336, -4};
static constexpr wq_config_t SPI4{"wq:SPI4", 2336, -5};
static constexpr wq_config_t SPI5{"wq:SPI5", 2336, -6};
static constexpr wq_config_t SPI6{"wq:SPI6", 2336, -7};

static constexpr wq_config_t I2C0{"wq:I2C0", 1472, -8};
static constexpr wq_config_t I2C1{"wq:I2C1", 1472, -9};
static constexpr wq_config_t I2C2{"wq:I2C2", 1472, -10};
static constexpr wq_config_t I2C3{"wq:I2C3", 1472, -11};
static constexpr wq_config_t I2C4{"wq:I2C4", 1472, -12};

// PX4 att/pos controllers, highest priority after sensors.
static constexpr wq_config_t attitude_ctrl{"wq:attitude_ctrl", 1640, -13};
static constexpr wq_config_t nav_and_controllers{"wq:nav_and_controllers", 7200, -14};

static constexpr wq_config_t hp_default{"wq:hp_default", 1900, -15};

static constexpr wq_config_t uavcan{"wq:uavcan", 3000, -16};

static constexpr wq_config_t UART0{"wq:UART0", 1400, -17};
static constexpr wq_config_t UART1{"wq:UART1", 1400, -18};
static constexpr wq_config_t UART2{"wq:UART2", 1400, -19};
static constexpr wq_config_t UART3{"wq:UART3", 1400, -20};
static constexpr wq_config_t UART4{"wq:UART4", 1400, -21};
static constexpr wq_config_t UART5{"wq:UART5", 1400, -22};
static constexpr wq_config_t UART6{"wq:UART6", 1400, -23};
static constexpr wq_config_t UART7{"wq:UART7", 1400, -24};
static constexpr wq_config_t UART8{"wq:UART8", 1400, -25};
static constexpr wq_config_t UART_UNKNOWN{"wq:UART_UNKNOWN", 1400, -26};

static constexpr wq_config_t lp_default{"wq:lp_default", 1700, -50};

static constexpr wq_config_t test1{"wq:test1", 2000, 0};
static constexpr wq_config_t test2{"wq:test2", 2000, 0};

} // namespace wq_configurations

/**
 * Start the work queue manager task.
 */
int WorkQueueManagerStart();

/**
 * Stop the work queue manager task.
 */
int WorkQueueManagerStop();

/**
 * Work queue manager status.
 */
int WorkQueueManagerStatus();

/**
 * Create (or find) a work queue with a particular configuration.
 *
 * @param new_wq		The work queue configuration (see WorkQueueManager.hpp).
 * @return		A pointer to the WorkQueue, or nullptr on failure.
 */
WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq);

/**
 * Map a PX4 driver device id to a work queue (by sensor bus).
 *
 * @param device_id		The PX4 driver's device id.
 * @return		A work queue configuration.
 */
const wq_config_t &device_bus_to_wq(uint32_t device_id);

/**
 * Map a serial device path (eg /dev/ttyS1) to a work queue.
 *
 * @param device_id		The device path.
 * @return		A work queue configuration.
 */
const wq_config_t &serial_port_to_wq(const char *serial);

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

#pragma once

#include <stdint.h>

namespace px4
{

class WorkQueue; // forward declaration

struct wq_config_t {
	const char *name;
	uint16_t stacksize;
	int8_t relative_priority; // relative to max
};

namespace wq_configurations
{
static constexpr wq_config_t rate_ctrl{"wq:rate_ctrl", 1664, 0}; // PX4 inner loop highest priority

static constexpr wq_config_t SPI0{"wq:SPI0", 2336, -1};
static constexpr wq_config_t SPI1{"wq:SPI1", 2336, -2};
static constexpr wq_config_t SPI2{"wq:SPI2", 2336, -3};
static constexpr wq_config_t SPI3{"wq:SPI3", 2336, -4};
static constexpr wq_config_t SPI4{"wq:SPI4", 2336, -5};
static constexpr wq_config_t SPI5{"wq:SPI5", 2336, -6};
static constexpr wq_config_t SPI6{"wq:SPI6", 2336, -7};

static constexpr wq_config_t I2C0{"wq:I2C0", 1472, -8};
static constexpr wq_config_t I2C1{"wq:I2C1", 1472, -9};
static constexpr wq_config_t I2C2{"wq:I2C2", 1472, -10};
static constexpr wq_config_t I2C3{"wq:I2C3", 1472, -11};
static constexpr wq_config_t I2C4{"wq:I2C4", 1472, -12};

// PX4 att/pos controllers, highest priority after sensors.
static constexpr wq_config_t attitude_ctrl{"wq:attitude_ctrl", 1656, -13};
static constexpr wq_config_t nav_and_controllers{"wq:nav_and_controllers", 7200, -14};

static constexpr wq_config_t hp_default{"wq:hp_default", 1900, -15};

static constexpr wq_config_t uavcan{"wq:uavcan", 3000, -16};

static constexpr wq_config_t UART0{"wq:UART0", 1400, -17};
static constexpr wq_config_t UART1{"wq:UART1", 1400, -18};
static constexpr wq_config_t UART2{"wq:UART2", 1400, -19};
static constexpr wq_config_t UART3{"wq:UART3", 1400, -20};
static constexpr wq_config_t UART4{"wq:UART4", 1400, -21};
static constexpr wq_config_t UART5{"wq:UART5", 1400, -22};
static constexpr wq_config_t UART6{"wq:UART6", 1400, -23};
static constexpr wq_config_t UART7{"wq:UART7", 1400, -24};
static constexpr wq_config_t UART8{"wq:UART8", 1400, -25};
static constexpr wq_config_t UART_UNKNOWN{"wq:UART_UNKNOWN", 1400, -26};

static constexpr wq_config_t lp_default{"wq:lp_default", 1700, -50};

static constexpr wq_config_t test1{"wq:test1", 2000, 0};
static constexpr wq_config_t test2{"wq:test2", 2000, 0};

} // namespace wq_configurations

/**
 * Start the work queue manager task.
 */
int WorkQueueManagerStart();

/**
 * Stop the work queue manager task.
 */
int WorkQueueManagerStop();

/**
 * Work queue manager status.
 */
int WorkQueueManagerStatus();

/**
 * Create (or find) a work queue with a particular configuration.
 *
 * @param new_wq		The work queue configuration (see WorkQueueManager.hpp).
 * @return		A pointer to the WorkQueue, or nullptr on failure.
 */
WorkQueue *WorkQueueFindOrCreate(const wq_config_t &new_wq);

/**
 * Map a PX4 driver device id to a work queue (by sensor bus).
 *
 * @param device_id		The PX4 driver's device id.
 * @return		A work queue configuration.
 */
const wq_config_t &device_bus_to_wq(uint32_t device_id);

/**
 * Map a serial device path (eg /dev/ttyS1) to a work queue.
 *
 * @param device_id		The device path.
 * @return		A work queue configuration.
 */
const wq_config_t &serial_port_to_wq(const char *serial);

} // namespace px4
<|endoftext|>