<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 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 <cassert>
#include "runtimes/libjoynr-runtime/websocket/LibJoynrWebSocketRuntime.h"

#include "joynr/SingleThreadedIOService.h"
#include "joynr/Util.h"
#include "joynr/WebSocketMulticastAddressCalculator.h"
#include "joynr/exceptions/JoynrException.h"
#include "joynr/serializer/Serializer.h"
#include "joynr/system/RoutingTypes/WebSocketClientAddress.h"
#include "joynr/IKeychain.h"
#include "libjoynr/websocket/WebSocketLibJoynrMessagingSkeleton.h"
#include "libjoynr/websocket/WebSocketMessagingStubFactory.h"
#include "libjoynr/websocket/WebSocketPpClientNonTLS.h"
#include "libjoynr/websocket/WebSocketPpClientTLS.h"

namespace joynr
{

INIT_LOGGER(LibJoynrWebSocketRuntime);

LibJoynrWebSocketRuntime::LibJoynrWebSocketRuntime(std::unique_ptr<Settings> settings,
                                                   std::shared_ptr<IKeychain> keyChain)
        : LibJoynrRuntime(std::move(settings)),
          wsSettings(*this->settings),
          websocket(nullptr),
          initializationMsg()
{
    createWebsocketClient(keyChain);
}

LibJoynrWebSocketRuntime::~LibJoynrWebSocketRuntime()
{
    assert(websocket);
    websocket->close();

    // synchronously stop the underlying boost::asio::io_service
    // this ensures all asynchronous operations are stopped now
    // which allows a safe shutdown
    assert(singleThreadIOService);
    singleThreadIOService->stop();
}

void LibJoynrWebSocketRuntime::connect(
        std::function<void()> onSuccess,
        std::function<void(const joynr::exceptions::JoynrRuntimeException&)> onError)
{
    std::string uuid = util::createUuid();
    // remove dashes
    uuid.erase(std::remove(uuid.begin(), uuid.end(), '-'), uuid.end());
    std::string libjoynrMessagingId = "libjoynr.messaging.participantid_" + uuid;
    auto libjoynrMessagingAddress =
            std::make_shared<const joynr::system::RoutingTypes::WebSocketClientAddress>(
                    libjoynrMessagingId);

    // send initialization message containing libjoynr messaging address
    initializationMsg = joynr::serializer::serializeToJson(*libjoynrMessagingAddress);
    JOYNR_LOG_TRACE(logger,
                    "OUTGOING sending websocket intialization message\nmessage: {}\nto: {}",
                    initializationMsg,
                    libjoynrMessagingAddress->toString());

    // create connection to parent routing service
    auto ccMessagingAddress = std::make_shared<const joynr::system::RoutingTypes::WebSocketAddress>(
            wsSettings.createClusterControllerMessagingAddress());

    auto factory = std::make_shared<WebSocketMessagingStubFactory>();
    factory->addServer(*ccMessagingAddress, websocket->getSender());

    std::weak_ptr<WebSocketMessagingStubFactory> weakFactoryRef(factory);
    websocket->registerDisconnectCallback([weakFactoryRef, ccMessagingAddress]() {
        if (auto factory = weakFactoryRef.lock()) {
            factory->onMessagingStubClosed(*ccMessagingAddress);
        }
    });

    auto connectCallback = [
        this,
        onSuccess = std::move(onSuccess),
        onError = std::move(onError),
        factory,
        libjoynrMessagingAddress,
        ccMessagingAddress
    ]()
    {
        sendInitializationMsg();

        std::unique_ptr<IMulticastAddressCalculator> addressCalculator =
                std::make_unique<joynr::WebSocketMulticastAddressCalculator>(ccMessagingAddress);
        init(factory,
             libjoynrMessagingAddress,
             ccMessagingAddress,
             std::move(addressCalculator),
             std::move(onSuccess),
             std::move(onError));
    };

    auto reconnectCallback = [this]() { sendInitializationMsg(); };

    websocket->registerConnectCallback(connectCallback);
    websocket->registerReconnectCallback(reconnectCallback);
    websocket->connect(*ccMessagingAddress);
}

void LibJoynrWebSocketRuntime::sendInitializationMsg()
{
    auto onFailure = [this](const exceptions::JoynrRuntimeException& e) {
        // initialization message will be sent after reconnect
        JOYNR_LOG_ERROR(logger,
                        "Sending websocket initialization message failed. Error: {}",
                        e.getMessage());
    };
    smrf::ByteVector rawMessage(initializationMsg.begin(), initializationMsg.end());
    websocket->send(smrf::ByteArrayView(rawMessage), onFailure);
}

void LibJoynrWebSocketRuntime::createWebsocketClient(std::shared_ptr<IKeychain> keyChain)
{
    system::RoutingTypes::WebSocketAddress webSocketAddress =
            wsSettings.createClusterControllerMessagingAddress();

    std::string certificateAuthorityPemFilename = wsSettings.getCertificateAuthorityPemFilename();
    std::string certificatePemFilename = wsSettings.getCertificatePemFilename();
    std::string privateKeyPemFilename = wsSettings.getPrivateKeyPemFilename();

    if (webSocketAddress.getProtocol() == system::RoutingTypes::WebSocketProtocol::WSS) {
        if (keyChain == nullptr) {
            const std::string message(
                    "TLS websocket connection was configured for but no keychain was provided");
            JOYNR_LOG_FATAL(logger, message);
            throw exceptions::JoynrRuntimeException(message);
        }

        JOYNR_LOG_INFO(logger, "Using TLS connection");
        websocket = std::make_shared<WebSocketPpClientTLS>(
                wsSettings, singleThreadIOService->getIOService(), keyChain);
    } else if (webSocketAddress.getProtocol() == system::RoutingTypes::WebSocketProtocol::WS) {
        JOYNR_LOG_INFO(logger, "Using non-TLS connection");
        websocket = std::make_shared<WebSocketPpClientNonTLS>(
                wsSettings, singleThreadIOService->getIOService());
    } else {
        throw exceptions::JoynrRuntimeException(
                "Unknown protocol used for settings property 'cluster-controller-messaging-url'");
    }
}

void LibJoynrWebSocketRuntime::startLibJoynrMessagingSkeleton(
        std::shared_ptr<IMessageRouter> messageRouter)
{
    auto wsLibJoynrMessagingSkeleton =
            std::make_shared<WebSocketLibJoynrMessagingSkeleton>(util::as_weak_ptr(messageRouter));
    websocket->registerReceiveCallback([wsLibJoynrMessagingSkeleton](smrf::ByteVector&& msg) {
        wsLibJoynrMessagingSkeleton->onMessageReceived(std::move(msg));
    });
}

} // namespace joynr
<commit_msg>[C++] Remove dead code from LibJoynrWebSocketRuntime<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 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 <cassert>
#include "runtimes/libjoynr-runtime/websocket/LibJoynrWebSocketRuntime.h"

#include "joynr/SingleThreadedIOService.h"
#include "joynr/Util.h"
#include "joynr/WebSocketMulticastAddressCalculator.h"
#include "joynr/exceptions/JoynrException.h"
#include "joynr/serializer/Serializer.h"
#include "joynr/system/RoutingTypes/WebSocketClientAddress.h"
#include "joynr/IKeychain.h"
#include "libjoynr/websocket/WebSocketLibJoynrMessagingSkeleton.h"
#include "libjoynr/websocket/WebSocketMessagingStubFactory.h"
#include "libjoynr/websocket/WebSocketPpClientNonTLS.h"
#include "libjoynr/websocket/WebSocketPpClientTLS.h"

namespace joynr
{

INIT_LOGGER(LibJoynrWebSocketRuntime);

LibJoynrWebSocketRuntime::LibJoynrWebSocketRuntime(std::unique_ptr<Settings> settings,
                                                   std::shared_ptr<IKeychain> keyChain)
        : LibJoynrRuntime(std::move(settings)),
          wsSettings(*this->settings),
          websocket(nullptr),
          initializationMsg()
{
    createWebsocketClient(keyChain);
}

LibJoynrWebSocketRuntime::~LibJoynrWebSocketRuntime()
{
    assert(websocket);
    websocket->close();

    // synchronously stop the underlying boost::asio::io_service
    // this ensures all asynchronous operations are stopped now
    // which allows a safe shutdown
    assert(singleThreadIOService);
    singleThreadIOService->stop();
}

void LibJoynrWebSocketRuntime::connect(
        std::function<void()> onSuccess,
        std::function<void(const joynr::exceptions::JoynrRuntimeException&)> onError)
{
    std::string uuid = util::createUuid();
    // remove dashes
    uuid.erase(std::remove(uuid.begin(), uuid.end(), '-'), uuid.end());
    std::string libjoynrMessagingId = "libjoynr.messaging.participantid_" + uuid;
    auto libjoynrMessagingAddress =
            std::make_shared<const joynr::system::RoutingTypes::WebSocketClientAddress>(
                    libjoynrMessagingId);

    // send initialization message containing libjoynr messaging address
    initializationMsg = joynr::serializer::serializeToJson(*libjoynrMessagingAddress);
    JOYNR_LOG_TRACE(logger,
                    "OUTGOING sending websocket intialization message\nmessage: {}\nto: {}",
                    initializationMsg,
                    libjoynrMessagingAddress->toString());

    // create connection to parent routing service
    auto ccMessagingAddress = std::make_shared<const joynr::system::RoutingTypes::WebSocketAddress>(
            wsSettings.createClusterControllerMessagingAddress());

    auto factory = std::make_shared<WebSocketMessagingStubFactory>();
    factory->addServer(*ccMessagingAddress, websocket->getSender());

    std::weak_ptr<WebSocketMessagingStubFactory> weakFactoryRef(factory);
    websocket->registerDisconnectCallback([weakFactoryRef, ccMessagingAddress]() {
        if (auto factory = weakFactoryRef.lock()) {
            factory->onMessagingStubClosed(*ccMessagingAddress);
        }
    });

    auto connectCallback = [
        this,
        onSuccess = std::move(onSuccess),
        onError = std::move(onError),
        factory,
        libjoynrMessagingAddress,
        ccMessagingAddress
    ]()
    {
        sendInitializationMsg();

        std::unique_ptr<IMulticastAddressCalculator> addressCalculator =
                std::make_unique<joynr::WebSocketMulticastAddressCalculator>(ccMessagingAddress);
        init(factory,
             libjoynrMessagingAddress,
             ccMessagingAddress,
             std::move(addressCalculator),
             std::move(onSuccess),
             std::move(onError));
    };

    auto reconnectCallback = [this]() { sendInitializationMsg(); };

    websocket->registerConnectCallback(connectCallback);
    websocket->registerReconnectCallback(reconnectCallback);
    websocket->connect(*ccMessagingAddress);
}

void LibJoynrWebSocketRuntime::sendInitializationMsg()
{
    auto onFailure = [this](const exceptions::JoynrRuntimeException& e) {
        // initialization message will be sent after reconnect
        JOYNR_LOG_ERROR(logger,
                        "Sending websocket initialization message failed. Error: {}",
                        e.getMessage());
    };
    smrf::ByteVector rawMessage(initializationMsg.begin(), initializationMsg.end());
    websocket->send(smrf::ByteArrayView(rawMessage), onFailure);
}

void LibJoynrWebSocketRuntime::createWebsocketClient(std::shared_ptr<IKeychain> keyChain)
{
    system::RoutingTypes::WebSocketAddress webSocketAddress =
            wsSettings.createClusterControllerMessagingAddress();

    if (webSocketAddress.getProtocol() == system::RoutingTypes::WebSocketProtocol::WSS) {
        if (keyChain == nullptr) {
            const std::string message(
                    "TLS websocket connection was configured for but no keychain was provided");
            JOYNR_LOG_FATAL(logger, message);
            throw exceptions::JoynrRuntimeException(message);
        }

        JOYNR_LOG_INFO(logger, "Using TLS connection");
        websocket = std::make_shared<WebSocketPpClientTLS>(
                wsSettings, singleThreadIOService->getIOService(), keyChain);
    } else if (webSocketAddress.getProtocol() == system::RoutingTypes::WebSocketProtocol::WS) {
        JOYNR_LOG_INFO(logger, "Using non-TLS connection");
        websocket = std::make_shared<WebSocketPpClientNonTLS>(
                wsSettings, singleThreadIOService->getIOService());
    } else {
        throw exceptions::JoynrRuntimeException(
                "Unknown protocol used for settings property 'cluster-controller-messaging-url'");
    }
}

void LibJoynrWebSocketRuntime::startLibJoynrMessagingSkeleton(
        std::shared_ptr<IMessageRouter> messageRouter)
{
    auto wsLibJoynrMessagingSkeleton =
            std::make_shared<WebSocketLibJoynrMessagingSkeleton>(util::as_weak_ptr(messageRouter));
    websocket->registerReceiveCallback([wsLibJoynrMessagingSkeleton](smrf::ByteVector&& msg) {
        wsLibJoynrMessagingSkeleton->onMessageReceived(std::move(msg));
    });
}

} // namespace joynr
<|endoftext|>


<commit_before>/* world plugin

# Authors:  Mohammad Hossein Gohari Nejad <mhgoharinejad@gmail.com>
# License:  BSD 3 clause

*/
#include <gazebo/common/Plugin.hh>
#include <ignition/math/Pose3.hh>
#include <ignition/math/Vector3.hh>
#include "gazebo/physics/physics.hh"
#include "gazebo/common/common.hh"
#include "gazebo/gazebo.hh"
#include "gazebo_information_plugins/distance_serivce.h"
#include <ros/ros.h>
#include <string>
#include <vector>
#include <iostream>
#include <math.h>
#include <nav_msgs/OccupancyGrid.h>
#include <std_msgs/String.h>

namespace gazebo {
    class WorldPluginTutorial : public WorldPlugin {
    public:
        physics::WorldPtr _world;
        ros::NodeHandle n;
        ros::Subscriber map_subscriber;
        ros::ServiceServer service1,service2,service3,service4;
        std::vector<std::string> vec;
        std::string object_name;
        int check;

        WorldPluginTutorial() : WorldPlugin() {}

    //  double get_Temperature(){return _world->Atmosphere ().Temperature(0.0);}
    //  double get_Pressure(){return _world->Atmosphere ().Pressure(0.0);}
    //TODO    ignition::math::Vector3d get_Magnetic_Field(){return _world->MagneticField(); }

        int get_walls(std::string robot_name1, std::string robot_name2) {

            physics::ModelPtr model1, model2;
            model1 = _world->GetModel(robot_name1);
            model2 = _world->GetModel(robot_name2);
            if (model1 == 0 || model2 == 0) {
                ROS_WARN("invalid model name!");
                return -1;
            }

            float start_x, start_y, slope;
            int iterations;
            if (model1->GetWorldPose().pos.x > model2->GetWorldPose().pos.x) {
                start_x = model2->GetWorldPose().pos.x;
                start_y = model2->GetWorldPose().pos.y;
                slope = (model1->GetWorldPose().pos.y - start_y) / (model1->GetWorldPose().pos.x - start_x);
                iterations = (model1->GetWorldPose().pos.x - start_x) * 50;
            } else {
                start_x = model1->GetWorldPose().pos.x;
                start_y = model1->GetWorldPose().pos.y;
                slope = (model2->GetWorldPose().pos.y - start_y) / (model2->GetWorldPose().pos.x - start_x);
                iterations = (model2->GetWorldPose().pos.x - start_x) * 50;
            }
            ROS_WARN("iterations %d \n", iterations);
            std::string test_object = "unique_sphere";
            vec.clear();
            vec.push_back(robot_name1);
            vec.push_back(robot_name2);
            check = 1;
            _world->GetModel(test_object)->SetStatic(true);
            for (int i = 0; i < iterations; i++) {

                math::Pose new_test_pose(start_x + i * 0.02, start_y + i * 0.02 * slope, 0.05, 0, 0, 0);
                _world->GetModel(test_object)->SetWorldPose(new_test_pose);
                this->object_name = "";
                _world->GetModel(test_object)->SetWorldPose(new_test_pose);
                ROS_WARN("pose x: %f y: %f  \n", start_x + i * 0.02, start_y + i * 0.02 * slope);
                for (int j = 0; j < vec.size(); j++) {
                    if (vec[j] == this->object_name) { break; }
                    else if (j + 1 == vec.size() && this->object_name != "") {
                        vec.push_back(this->object_name);
                        ROS_INFO("these are the objects %s  \n", this->object_name.c_str());
                    }
                }
            }
            int number_of_walls = vec.size() - 2;
            check = 0;
            vec.clear();
            math::Pose new_test_pose(200.0, 200.0, 10.0, 0, 0, 0);
            _world->GetModel(test_object)->SetWorldPose(new_test_pose);
            return number_of_walls;

        }

        float get_distance(std::string robot_name1, std::string robot_name2) {
            physics::ModelPtr model1, model2;
            model1 = _world->GetModel(robot_name1);
            model2 = _world->GetModel(robot_name2);
            if (model1 == 0 || model2 == 0) {

                ROS_WARN("invalid model name!");
                return -1;
            } else {
                float x_diff = model1->GetWorldPose().pos.x - model2->GetWorldPose().pos.x;
                float y_diff = model1->GetWorldPose().pos.y - model2->GetWorldPose().pos.y;

                return sqrt((x_diff * x_diff) + (y_diff * y_diff));
            }

        }

        void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf) {

            check = 0;
            // Make sure the ROS node for Gazebo has already been initialized
            if (!ros::isInitialized()) {
                ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
                                         << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
                return;
            }
            _world = _parent;
            ROS_INFO("Hello World!");
            ROS_INFO("Hello World!");

            ROS_INFO("Hello World!");

            sdf::SDF sphereSDF;
            sphereSDF.SetFromString(
                    "<sdf version ='1.4'>\
        <model name ='test_sphere'>\
        <pose>-100 -120 0.2 0 0 0</pose>\
        <link name ='link'>\
        <sensor name='my_contact' type='contact'>\
        <plugin name='my_plugin' filename='libgazebo_plugin_contact.so'/>\
        <contact>\
        <collision>test_collision</collision>\
        </contact>\
        </sensor>\
        <pose>0 0 0 0 0 0</pose>\
        <collision name ='test_collision'>\
        <geometry>\
        <sphere><radius>0.01</radius></sphere>\
        </geometry>\
        </collision>\
        <visual name ='test_visual'>\
        <geometry>\
        <sphere><radius>0.01</radius></sphere>\
        </geometry>\
        </visual>\
        </link>\
        </model>\
        </sdf>");
            // Demonstrate using a custom model name.
            sdf::ElementPtr model = sphereSDF.Root()->GetElement("model");
            model->GetAttribute("name")->SetFromString("unique_sphere");
            _world->InsertModelSDF(sphereSDF);
            ROS_INFO("Hello World!");

            //ros::WallDuration(15.0).sleep();

            //std::string asfj="asphalt_plane";
            //std::string hi=_world->GetModel(asfj)->GetName();
            //ROS_INFO("%s",hi.c_str());
            //ROS_INFO("%f",_world->GetModel(1)->GetWorldPose().pos.x );
            //ROS_INFO("%f",get_distance("asphalt_plane","asphalt_plane_1"));
            //math::Pose asdfjk(20,20,0,0,0,0);
            //_world->GetModel(asfj)->SetWorldPose(asdfjk);
            //boost::bind(&MoveBase::goalCB, this, _1)
            int argc = 0;
            char **argv = NULL;
            ros::init(argc, argv, "gazebo_client", ros::init_options::NoSigintHandler);
            service1 = n.advertiseService("GzInfo_service1", &WorldPluginTutorial::service_handler1, this);
            service2 = n.advertiseService("GzInfo_service2", &WorldPluginTutorial::service_handler2, this);
            service3 = n.advertiseService("GzInfo_service3", &WorldPluginTutorial::service_handler3, this);
            service4 = n.advertiseService("GzInfo_service4", &WorldPluginTutorial::service_handler4, this);

            std::string subscribing_topic = "collision_topic";//move_base/local_costmap/costmap";
            map_subscriber = n.subscribe(subscribing_topic, 10, &WorldPluginTutorial::collision_callback, this);

        }

        void collision_callback(const std_msgs::String object_name) {
            this->object_name = object_name.data;
            if (vec.size() > 0 && check == 1) {
                for (int j = 0; j < vec.size(); j++) {
                    if (vec[j] == object_name.data) {
                        break;
                    } else if (j + 1 == vec.size() && object_name.data != "") {
                        vec.push_back(object_name.data);
                        ROS_INFO("these are the objects %s  \n", object_name.data.c_str());
                    }
                }

            }
            //ROS_INFO("%s",object_name.data.c_str());
        }

        bool service_handler1(gazebo_information_plugins::distance_serivce::Request &req,
                             gazebo_information_plugins::distance_serivce::Response &res) {

            std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
            if (command == "distance") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = 0;
            } else if (command == "walls") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            }
            else if (command == "temp") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
            else if (command == "pressure") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
        /*TODO   else if (command == "magnet") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            } */
            return true;
        }

        bool service_handler2(gazebo_information_plugins::distance_serivce::Request &req,
                             gazebo_information_plugins::distance_serivce::Response &res) {

            std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
            if (command == "distance") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = 0;
            } else if (command == "walls") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            }
            else if (command == "temp") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
            else if (command == "pressure") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
        /*TODO   else if (command == "magnet") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            } */
            return true;
        }
        bool service_handler3(gazebo_information_plugins::distance_serivce::Request &req,
                             gazebo_information_plugins::distance_serivce::Response &res) {

            std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
            if (command == "distance") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = 0;
            } else if (command == "walls") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            }
            else if (command == "temp") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
            else if (command == "pressure") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
        /*TODO   else if (command == "magnet") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            } */
            return true;
        }
        bool service_handler4(gazebo_information_plugins::distance_serivce::Request &req,
                             gazebo_information_plugins::distance_serivce::Response &res) {

            std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
            if (command == "distance") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = 0;
            } else if (command == "walls") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            }
            else if (command == "temp") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
            else if (command == "pressure") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
        /*TODO   else if (command == "magnet") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            } */
            return true;
        }

    };

    GZ_REGISTER_WORLD_PLUGIN(WorldPluginTutorial)
}
<commit_msg>adding class for generic message handling<commit_after>/* world plugin

# Authors:  Mohammad Hossein Gohari Nejad <mhgoharinejad@gmail.com>
# License:  BSD 3 clause

*/
#include <gazebo/common/Plugin.hh>
#include <ignition/math/Pose3.hh>
#include <ignition/math/Vector3.hh>
#include "gazebo/physics/physics.hh"
#include "gazebo/common/common.hh"
#include "gazebo/gazebo.hh"
#include "gazebo_information_plugins/distance_serivce.h"
#include <ros/ros.h>
#include <string>
#include <vector>
#include <iostream>
#include <math.h>
#include <nav_msgs/OccupancyGrid.h>
#include <std_msgs/String.h>
#define NUM_SRV 4

namespace gazebo {
    class service_handle;
    class WorldPluginTutorial : public WorldPlugin {
    public:
        physics::WorldPtr _world;
        ros::NodeHandle n;
        ros::Subscriber map_subscriber;
        ros::ServiceServer service1,service2,service3,service4;
        std::vector<std::string> vec;
        std::vector<service_handle*> vec_srv;
        std::string object_name;
        int check;

        WorldPluginTutorial() : WorldPlugin() {}

    //  double get_Temperature(){return _world->Atmosphere ().Temperature(0.0);}
    //  double get_Pressure(){return _world->Atmosphere ().Pressure(0.0);}
    //TODO    ignition::math::Vector3d get_Magnetic_Field(){return _world->MagneticField(); }

        int get_walls(std::string robot_name1, std::string robot_name2) {

            physics::ModelPtr model1, model2;
            model1 = _world->GetModel(robot_name1);
            model2 = _world->GetModel(robot_name2);
            if (model1 == 0 || model2 == 0) {
                ROS_WARN("invalid model name!");
                return -1;
            }

            float start_x, start_y, slope;
            int iterations;
            if (model1->GetWorldPose().pos.x > model2->GetWorldPose().pos.x) {
                start_x = model2->GetWorldPose().pos.x;
                start_y = model2->GetWorldPose().pos.y;
                slope = (model1->GetWorldPose().pos.y - start_y) / (model1->GetWorldPose().pos.x - start_x);
                iterations = (model1->GetWorldPose().pos.x - start_x) * 50;
            } else {
                start_x = model1->GetWorldPose().pos.x;
                start_y = model1->GetWorldPose().pos.y;
                slope = (model2->GetWorldPose().pos.y - start_y) / (model2->GetWorldPose().pos.x - start_x);
                iterations = (model2->GetWorldPose().pos.x - start_x) * 50;
            }
            ROS_WARN("iterations %d \n", iterations);
            std::string test_object = "unique_sphere";
            vec.clear();
            vec.push_back(robot_name1);
            vec.push_back(robot_name2);
            check = 1;
            _world->GetModel(test_object)->SetStatic(true);
            for (int i = 0; i < iterations; i++) {

                math::Pose new_test_pose(start_x + i * 0.02, start_y + i * 0.02 * slope, 0.05, 0, 0, 0);
                _world->GetModel(test_object)->SetWorldPose(new_test_pose);
                this->object_name = "";
                _world->GetModel(test_object)->SetWorldPose(new_test_pose);
                ROS_WARN("pose x: %f y: %f  \n", start_x + i * 0.02, start_y + i * 0.02 * slope);
                for (int j = 0; j < vec.size(); j++) {
                    if (vec[j] == this->object_name) { break; }
                    else if (j + 1 == vec.size() && this->object_name != "") {
                        vec.push_back(this->object_name);
                        ROS_INFO("these are the objects %s  \n", this->object_name.c_str());
                    }
                }
            }
            int number_of_walls = vec.size() - 2;
            check = 0;
            vec.clear();
            math::Pose new_test_pose(200.0, 200.0, 10.0, 0, 0, 0);
            _world->GetModel(test_object)->SetWorldPose(new_test_pose);
            return number_of_walls;

        }

        float get_distance(std::string robot_name1, std::string robot_name2) {
            physics::ModelPtr model1, model2;
            model1 = _world->GetModel(robot_name1);
            model2 = _world->GetModel(robot_name2);
            if (model1 == 0 || model2 == 0) {

                ROS_WARN("invalid model name!");
                return -1;
            } else {
                float x_diff = model1->GetWorldPose().pos.x - model2->GetWorldPose().pos.x;
                float y_diff = model1->GetWorldPose().pos.y - model2->GetWorldPose().pos.y;

                return sqrt((x_diff * x_diff) + (y_diff * y_diff));
            }

        }

        void Load(physics::WorldPtr _parent, sdf::ElementPtr _sdf) {

            check = 0;
            // Make sure the ROS node for Gazebo has already been initialized
            if (!ros::isInitialized()) {
                ROS_FATAL_STREAM("A ROS node for Gazebo has not been initialized, unable to load plugin. "
                                         << "Load the Gazebo system plugin 'libgazebo_ros_api_plugin.so' in the gazebo_ros package)");
                return;
            }
            _world = _parent;
            ROS_INFO("Hello World!");
            ROS_INFO("Hello World!");

            ROS_INFO("Hello World!");

            sdf::SDF sphereSDF;
            sphereSDF.SetFromString(
                    "<sdf version ='1.4'>\
        <model name ='test_sphere'>\
        <pose>-100 -120 0.2 0 0 0</pose>\
        <link name ='link'>\
        <sensor name='my_contact' type='contact'>\
        <plugin name='my_plugin' filename='libgazebo_plugin_contact.so'/>\
        <contact>\
        <collision>test_collision</collision>\
        </contact>\
        </sensor>\
        <pose>0 0 0 0 0 0</pose>\
        <collision name ='test_collision'>\
        <geometry>\
        <sphere><radius>0.01</radius></sphere>\
        </geometry>\
        </collision>\
        <visual name ='test_visual'>\
        <geometry>\
        <sphere><radius>0.01</radius></sphere>\
        </geometry>\
        </visual>\
        </link>\
        </model>\
        </sdf>");
            // Demonstrate using a custom model name.
            sdf::ElementPtr model = sphereSDF.Root()->GetElement("model");
            model->GetAttribute("name")->SetFromString("unique_sphere");
            _world->InsertModelSDF(sphereSDF);
            ROS_INFO("Hello World!");

            //ros::WallDuration(15.0).sleep();

            //std::string asfj="asphalt_plane";
            //std::string hi=_world->GetModel(asfj)->GetName();
            //ROS_INFO("%s",hi.c_str());
            //ROS_INFO("%f",_world->GetModel(1)->GetWorldPose().pos.x );
            //ROS_INFO("%f",get_distance("asphalt_plane","asphalt_plane_1"));
            //math::Pose asdfjk(20,20,0,0,0,0);
            //_world->GetModel(asfj)->SetWorldPose(asdfjk);
            //boost::bind(&MoveBase::goalCB, this, _1)
            int argc = 0;
            char **argv = NULL;
            ros::init(argc, argv, "gazebo_client", ros::init_options::NoSigintHandler);
            for (int i=0;i<NUM_SRV;i++){
              vec_srv.push_back(new service_handle("GzInfo_service"+(std::to_string(i)),this))
            };
            // service1 = n.advertiseService("GzInfo_service1", &WorldPluginTutorial::service_handler1, this);
            // service2 = n.advertiseService("GzInfo_service2", &WorldPluginTutorial::service_handler2, this);
            // service3 = n.advertiseService("GzInfo_service3", &WorldPluginTutorial::service_handler3, this);
            // service4 = n.advertiseService("GzInfo_service4", &WorldPluginTutorial::service_handler4, this);

            std::string subscribing_topic = "collision_topic";//move_base/local_costmap/costmap";
            map_subscriber = n.subscribe(subscribing_topic, 10, &WorldPluginTutorial::collision_callback, this);

        }

        void collision_callback(const std_msgs::String object_name) {
            this->object_name = object_name.data;
            if (vec.size() > 0 && check == 1) {
                for (int j = 0; j < vec.size(); j++) {
                    if (vec[j] == object_name.data) {
                        break;
                    } else if (j + 1 == vec.size() && object_name.data != "") {
                        vec.push_back(object_name.data);
                        ROS_INFO("these are the objects %s  \n", object_name.data.c_str());
                    }
                }

            }
            //ROS_INFO("%s",object_name.data.c_str());
        }

        bool service_handler1(gazebo_information_plugins::distance_serivce::Request &req,
                             gazebo_information_plugins::distance_serivce::Response &res) {

            std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
            if (command == "distance") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = 0;
            } else if (command == "walls") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            }
            else if (command == "temp") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
            else if (command == "pressure") {
                res.distance = 0;
                res.number_of_objects = 0;
            }
        /*TODO   else if (command == "magnet") {
                res.distance = get_distance(robot1, robot2);
                res.number_of_objects = get_walls(robot1, robot2);
            } */
            return true;
        }

    };

    class service_handle {
  public:
    WorldPluginTutorial* WPT;
    std::string sn;
    ros::ServiceServer service1;
    service_handle(std::string service_name,WorldPluginTutorial* world_plugin){
               sn=service_name;
               WPT=world_plugin;
                 service1 = (WPT->n).advertiseService(sn, &service_handle::service_handler1, this);
    };
    bool service_handler1(gazebo_information_plugins::distance_serivce::Request &req,
                         gazebo_information_plugins::distance_serivce::Response &res) {

        std::string command = req.command, robot1 = req.robot1, robot2 = req.robot2;
        if (command == "distance") {
            res.distance = WPT->get_distance(robot1, robot2);
            res.number_of_objects = 0;
        } else if (command == "walls") {
            res.distance = WPT->get_distance(robot1, robot2);
            res.number_of_objects = WPT->get_walls(robot1, robot2);
        }
        else if (command == "temp") {
            res.distance = 0;
            res.number_of_objects = 0;
        }
        else if (command == "pressure") {
            res.distance = 0;
            res.number_of_objects = 0;
        }
    /*TODO   else if (command == "magnet") {
            res.distance = get_distance(robot1, robot2);
            res.number_of_objects = get_walls(robot1, robot2);
        } */
        return true;
    }

  };

    GZ_REGISTER_WORLD_PLUGIN(WorldPluginTutorial)
}
<|endoftext|>


<commit_before>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2018, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "mttilesetpropertymanager.h"
#include "mttilesetaccessors.h"
#include "mttilesetresourceitem.h"
#include "gui-qt/accessor/gridundohelper.h"
#include "gui-qt/accessor/resourceitemundohelper.h"
#include "gui-qt/common/helpers.h"
#include "gui-qt/resources/palette/paletteresourcelist.h"

using namespace UnTech::GuiQt::MetaTiles;

using TilesetUndoHelper = UnTech::GuiQt::Accessor::ResourceItemUndoHelper<MtTilesetResourceItem>;

MtTilesetPropertyManager::MtTilesetPropertyManager(QObject* parent)
    : AbstractPropertyManager(parent)
    , _tileset(nullptr)
{
    using Type = UnTech::GuiQt::PropertyType;

    addProperty(tr("Name"), NAME, Type::IDSTRING);
    addProperty(tr("Scratchpad Size"), SCRATCHPAD_SIZE, Type::SIZE, QSize(0, 0), QSize(255, 255));
    addProperty(tr("Palettes"), PALETTES, Type::IDSTRING_LIST);
    addPropertyGroup(tr("Animation Frames:"));
    addProperty(tr("Frame Images"), FRAME_IMAGES, Type::FILENAME_LIST,
                QStringLiteral("PNG Image (*.png)"));
    addProperty(tr("Animation Delay"), ANIMATION_DELAY, Type::UNSIGNED, 0, 0x10000);
    addProperty(tr("Bit Depth"), BIT_DEPTH, Type::COMBO, QStringList{ "2 bpp", "4 bpp", "8 bpp" }, QVariantList{ 2, 4, 8 });
    addProperty(tr("Add Transparent Tile"), ADD_TRANSPARENT_TILE, Type::BOOLEAN);
}

void MtTilesetPropertyManager::setResourceItem(AbstractResourceItem* abstractItem)
{
    MtTilesetResourceItem* item = qobject_cast<MtTilesetResourceItem*>(abstractItem);

    if (_tileset == item) {
        return;
    }
    if (_tileset) {
        _tileset->disconnect(this);
    }
    _tileset = item;

    setEnabled(_tileset != nullptr);

    if (_tileset) {
        setEnabled(_tileset->tilesetInput() != nullptr);

        connect(_tileset, &MtTilesetResourceItem::dataChanged,
                this, &MtTilesetPropertyManager::dataChanged);
    }

    emit dataChanged();
}

void MtTilesetPropertyManager::updateParameters(int id, QVariant& param1, QVariant&) const
{
    if (_tileset == nullptr) {
        return;
    }

    if (id == PALETTES) {
        param1 = _tileset->project()->paletteResourceList()->itemNames();
    }
}

QVariant MtTilesetPropertyManager::data(int id) const
{
    if (_tileset == nullptr) {
        return QVariant();
    }

    const MT::MetaTileTilesetInput* ti = _tileset->tilesetInput();
    if (ti == nullptr) {
        return QVariant();
    }

    switch ((PropertyId)id) {
    case NAME:
        return QString::fromStdString(ti->name);

    case SCRATCHPAD_SIZE:
        return fromUsize(ti->scratchpad.size());

    case PALETTES:
        return convertStringList(ti->palettes);

    case FRAME_IMAGES:
        return convertStringList(ti->animationFrames.frameImageFilenames);

    case ANIMATION_DELAY:
        return ti->animationFrames.animationDelay;

    case BIT_DEPTH:
        return ti->animationFrames.bitDepth;

    case ADD_TRANSPARENT_TILE:
        return ti->animationFrames.addTransparentTile;
    }

    return QVariant();
}

bool MtTilesetPropertyManager::setData(int id, const QVariant& value)
{
    Q_ASSERT(_tileset);
    Q_ASSERT(_tileset->data());

    TilesetUndoHelper undoHelper(_tileset);

    switch ((PropertyId)id) {
    case NAME:
        return undoHelper.editName(value.toString().toStdString());

    case SCRATCHPAD_SIZE:
        return MtTilesetScratchpadGridUndoHelper(_tileset->scratchpadGrid())
            .resizeSelectedGrid(toUsize(value.toSize()), 0,
                                tr("Resize scratchpad"));

    case PALETTES:
        return undoHelper.editField(toIdstringVector(value.toStringList()),
                                    tr("Edit Palette List"),
                                    [](MT::MetaTileTilesetInput& ti) -> std::vector<idstring>& { return ti.palettes; },
                                    [](MtTilesetResourceItem& item) { emit item.palettesChanged();
                                                                      item.updateDependencies(); });

    case FRAME_IMAGES:
        return undoHelper.editField(toStringVector(value.toStringList()),
                                    tr("Edit Frame Image List"),
                                    [](MT::MetaTileTilesetInput& ti) -> std::vector<std::string>& { return ti.animationFrames.frameImageFilenames; },
                                    [](MtTilesetResourceItem& item) { item.updateExternalFiles(); });

    case ANIMATION_DELAY:
        return undoHelper.editField(value.toUInt(),
                                    tr("Edit Animation Delay"),
                                    [](MT::MetaTileTilesetInput& ti) -> unsigned& { return ti.animationFrames.animationDelay; },
                                    [](MtTilesetResourceItem& item) { emit item.animationDelayChanged(); });

    case BIT_DEPTH:
        return undoHelper.editField(value.toUInt(),
                                    tr("Edit Bit Depth"),
                                    [](MT::MetaTileTilesetInput& ti) -> unsigned& { return ti.animationFrames.bitDepth; });

    case ADD_TRANSPARENT_TILE:
        return undoHelper.editField(value.toBool(),
                                    tr("Edit Add Transparent Tile"),
                                    [](MT::MetaTileTilesetInput& ti) -> bool& { return ti.animationFrames.addTransparentTile; });
    }
}
<commit_msg>Fix compiler warning when compiling with g++<commit_after>/*
 * This file is part of the UnTech Editor Suite.
 * Copyright (c) 2016 - 2018, Marcus Rowe <undisbeliever@gmail.com>.
 * Distributed under The MIT License: https://opensource.org/licenses/MIT
 */

#include "mttilesetpropertymanager.h"
#include "mttilesetaccessors.h"
#include "mttilesetresourceitem.h"
#include "gui-qt/accessor/gridundohelper.h"
#include "gui-qt/accessor/resourceitemundohelper.h"
#include "gui-qt/common/helpers.h"
#include "gui-qt/resources/palette/paletteresourcelist.h"

using namespace UnTech::GuiQt::MetaTiles;

using TilesetUndoHelper = UnTech::GuiQt::Accessor::ResourceItemUndoHelper<MtTilesetResourceItem>;

MtTilesetPropertyManager::MtTilesetPropertyManager(QObject* parent)
    : AbstractPropertyManager(parent)
    , _tileset(nullptr)
{
    using Type = UnTech::GuiQt::PropertyType;

    addProperty(tr("Name"), NAME, Type::IDSTRING);
    addProperty(tr("Scratchpad Size"), SCRATCHPAD_SIZE, Type::SIZE, QSize(0, 0), QSize(255, 255));
    addProperty(tr("Palettes"), PALETTES, Type::IDSTRING_LIST);
    addPropertyGroup(tr("Animation Frames:"));
    addProperty(tr("Frame Images"), FRAME_IMAGES, Type::FILENAME_LIST,
                QStringLiteral("PNG Image (*.png)"));
    addProperty(tr("Animation Delay"), ANIMATION_DELAY, Type::UNSIGNED, 0, 0x10000);
    addProperty(tr("Bit Depth"), BIT_DEPTH, Type::COMBO, QStringList{ "2 bpp", "4 bpp", "8 bpp" }, QVariantList{ 2, 4, 8 });
    addProperty(tr("Add Transparent Tile"), ADD_TRANSPARENT_TILE, Type::BOOLEAN);
}

void MtTilesetPropertyManager::setResourceItem(AbstractResourceItem* abstractItem)
{
    MtTilesetResourceItem* item = qobject_cast<MtTilesetResourceItem*>(abstractItem);

    if (_tileset == item) {
        return;
    }
    if (_tileset) {
        _tileset->disconnect(this);
    }
    _tileset = item;

    setEnabled(_tileset != nullptr);

    if (_tileset) {
        setEnabled(_tileset->tilesetInput() != nullptr);

        connect(_tileset, &MtTilesetResourceItem::dataChanged,
                this, &MtTilesetPropertyManager::dataChanged);
    }

    emit dataChanged();
}

void MtTilesetPropertyManager::updateParameters(int id, QVariant& param1, QVariant&) const
{
    if (_tileset == nullptr) {
        return;
    }

    if (id == PALETTES) {
        param1 = _tileset->project()->paletteResourceList()->itemNames();
    }
}

QVariant MtTilesetPropertyManager::data(int id) const
{
    if (_tileset == nullptr) {
        return QVariant();
    }

    const MT::MetaTileTilesetInput* ti = _tileset->tilesetInput();
    if (ti == nullptr) {
        return QVariant();
    }

    switch ((PropertyId)id) {
    case NAME:
        return QString::fromStdString(ti->name);

    case SCRATCHPAD_SIZE:
        return fromUsize(ti->scratchpad.size());

    case PALETTES:
        return convertStringList(ti->palettes);

    case FRAME_IMAGES:
        return convertStringList(ti->animationFrames.frameImageFilenames);

    case ANIMATION_DELAY:
        return ti->animationFrames.animationDelay;

    case BIT_DEPTH:
        return ti->animationFrames.bitDepth;

    case ADD_TRANSPARENT_TILE:
        return ti->animationFrames.addTransparentTile;
    }

    return QVariant();
}

bool MtTilesetPropertyManager::setData(int id, const QVariant& value)
{
    Q_ASSERT(_tileset);
    Q_ASSERT(_tileset->data());

    TilesetUndoHelper undoHelper(_tileset);

    switch ((PropertyId)id) {
    case NAME:
        return undoHelper.editName(value.toString().toStdString());

    case SCRATCHPAD_SIZE:
        return MtTilesetScratchpadGridUndoHelper(_tileset->scratchpadGrid())
            .resizeSelectedGrid(toUsize(value.toSize()), 0,
                                tr("Resize scratchpad"));

    case PALETTES:
        return undoHelper.editField(toIdstringVector(value.toStringList()),
                                    tr("Edit Palette List"),
                                    [](MT::MetaTileTilesetInput& ti) -> std::vector<idstring>& { return ti.palettes; },
                                    [](MtTilesetResourceItem& item) { emit item.palettesChanged();
                                                                      item.updateDependencies(); });

    case FRAME_IMAGES:
        return undoHelper.editField(toStringVector(value.toStringList()),
                                    tr("Edit Frame Image List"),
                                    [](MT::MetaTileTilesetInput& ti) -> std::vector<std::string>& { return ti.animationFrames.frameImageFilenames; },
                                    [](MtTilesetResourceItem& item) { item.updateExternalFiles(); });

    case ANIMATION_DELAY:
        return undoHelper.editField(value.toUInt(),
                                    tr("Edit Animation Delay"),
                                    [](MT::MetaTileTilesetInput& ti) -> unsigned& { return ti.animationFrames.animationDelay; },
                                    [](MtTilesetResourceItem& item) { emit item.animationDelayChanged(); });

    case BIT_DEPTH:
        return undoHelper.editField(value.toUInt(),
                                    tr("Edit Bit Depth"),
                                    [](MT::MetaTileTilesetInput& ti) -> unsigned& { return ti.animationFrames.bitDepth; });

    case ADD_TRANSPARENT_TILE:
        return undoHelper.editField(value.toBool(),
                                    tr("Edit Add Transparent Tile"),
                                    [](MT::MetaTileTilesetInput& ti) -> bool& { return ti.animationFrames.addTransparentTile; });
    }

    return false;
}
<|endoftext|>


<commit_before>// Copyright 2017 SAS Project Authors. All Rights Reserved.
//
// 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 <Python.h>
#include <iostream>

#include "its/itm.h"

static PyObject* itm_point_to_point(PyObject* self, PyObject* args) {
  PyObject* elev_obj = NULL;
  double tht_m, rht_m;
  double eps_dielect, sgm_conductivity, eno_ns_surfref;
  double frq_mhz;
  int radio_climate, pol;
  double conf, rel;
  int mdvar = 12;  // Default arguments
  int eno_final = 0;
  if (!PyArg_ParseTuple(args, "Oddddddiidd|ii:point_to_point",
                        &elev_obj, &tht_m, &rht_m, &eps_dielect, &sgm_conductivity,
                        &eno_ns_surfref,
                        &frq_mhz, &radio_climate, &pol, &conf, &rel, &mdvar, &eno_final)) {
    return NULL;
  }

  if (!PyList_Check(elev_obj)) {
    return NULL;
  }

  Py_ssize_t size = PyList_Size(elev_obj);
  if (size < 4) {
    PyErr_SetString(PyExc_ValueError, "Invalid profile size. Should be >= 4.");
    return NULL;
  }

  double* elev = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* i_obj = PyList_GetItem(elev_obj, i);
    double elev_val = PyFloat_AsDouble(i_obj);
    elev[i] = elev_val;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Profile should only contain numerical values.");
    return NULL;
  }
  if (elev[0] > size-3) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Invalid Profile. Size in slot 0 bigger than actual list size.");
    return NULL;
  }

  double dbloss;
  char strmode[100];
  int errnum;
  double ver0, ver1;
  point_to_point(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
                 eno_ns_surfref, frq_mhz, radio_climate, pol, conf, rel,
                 mdvar, !!eno_final,
                 dbloss, strmode, errnum, ver0, ver1);
  delete[] elev;
  return Py_BuildValue("dddsi", dbloss, ver0, ver1, strmode, errnum);
}

static PyObject* itm_point_to_point_rels(PyObject* self, PyObject* args) {
  PyObject* elev_obj = NULL;
  double tht_m, rht_m;
  double eps_dielect, sgm_conductivity, eno_ns_surfref;
  double frq_mhz;
  int radio_climate, pol;
  double conf;
  PyObject* rels_obj = NULL;
  int mdvar = 12;  // Default arguments
  int eno_final = 0;
  if (!PyArg_ParseTuple(args, "OddddddiidO|ii:point_to_point_rels",
                        &elev_obj, &tht_m, &rht_m, &eps_dielect, &sgm_conductivity,
                        &eno_ns_surfref,
                        &frq_mhz, &radio_climate, &pol, &conf, &rels_obj,
                        &mdvar, &eno_final)) {
    return NULL;
  }

  if (!PyList_Check(elev_obj)) {
    return NULL;
  }

  if (!PyList_Check(rels_obj)) {
    return NULL;
  }
  // Get the profile
  Py_ssize_t size = PyList_Size(elev_obj);
  if (size < 4) {
    PyErr_SetString(PyExc_ValueError, "Invalid profile size. Should be >= 4.");
    return NULL;
  }

  double* elev = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* i_obj = PyList_GetItem(elev_obj, i);
    double elev_val = PyFloat_AsDouble(i_obj);
    elev[i] = elev_val;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Profile should only contain numerical values.");
    return NULL;
  }
  if (elev[0] > size-3) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Invalid Profile. Size in slot 0 bigger than actual list size.");
    return NULL;
  }
  // Get the reliability list
  size = PyList_Size(rels_obj);
  if (size <= 0) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Reliabilities list empty.");
    return NULL;
  }
  double* rels = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* rel_obj = PyList_GetItem(rels_obj, i);
    double rel = PyFloat_AsDouble(rel_obj);
    rels[i] = rel;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    delete[] rels;
    PyErr_SetString(PyExc_ValueError, "Reliabilities list should only contain numerical values.");
    return NULL;
  }
  int num_rels = size;
  double* db_losses = new double[num_rels];
  double ver0, ver1;
  char strmode[100];
  int errnum;
  point_to_point_rels(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
                      eno_ns_surfref, frq_mhz, radio_climate, pol, conf,
                      rels, num_rels,
                      mdvar, !!eno_final,
                      db_losses, strmode, errnum, ver0, ver1);
  delete[] elev;
  delete[] rels;

  PyObject* loss_obj = PyList_New(num_rels);
  for (int k = 0; k < size; k++ ) {
    PyList_SET_ITEM(loss_obj, k, Py_BuildValue("d", db_losses[k]));
  }
  delete[] db_losses;

  return Py_BuildValue("Oddsi", loss_obj, ver0, ver1, strmode, errnum);
}

static PyMethodDef ITMMethods[] = {
  {"point_to_point", itm_point_to_point, METH_VARARGS, "Point-to-point model"},
  {"point_to_point_rels", itm_point_to_point_rels, METH_VARARGS, "Point-to-point-Rels model"},
  {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC inititm_its(void) {
  Py_InitModule3("itm_its", ITMMethods, "Longley-Rice ITM Propagation Module");
}
<commit_msg>Fix mem leak on ITM Python-C++ interface. (#847)<commit_after>// Copyright 2017 SAS Project Authors. All Rights Reserved.
//
// 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 <Python.h>
#include <iostream>

#include "its/itm.h"

static PyObject* itm_point_to_point(PyObject* self, PyObject* args) {
  PyObject* elev_obj = NULL;
  double tht_m, rht_m;
  double eps_dielect, sgm_conductivity, eno_ns_surfref;
  double frq_mhz;
  int radio_climate, pol;
  double conf, rel;
  int mdvar = 12;  // Default arguments
  int eno_final = 0;
  if (!PyArg_ParseTuple(args, "Oddddddiidd|ii:point_to_point",
                        &elev_obj, &tht_m, &rht_m, &eps_dielect, &sgm_conductivity,
                        &eno_ns_surfref,
                        &frq_mhz, &radio_climate, &pol, &conf, &rel, &mdvar, &eno_final)) {
    return NULL;
  }

  if (!PyList_Check(elev_obj)) {
    return NULL;
  }

  Py_ssize_t size = PyList_Size(elev_obj);
  if (size < 4) {
    PyErr_SetString(PyExc_ValueError, "Invalid profile size. Should be >= 4.");
    return NULL;
  }

  double* elev = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* i_obj = PyList_GetItem(elev_obj, i);
    double elev_val = PyFloat_AsDouble(i_obj);
    elev[i] = elev_val;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Profile should only contain numerical values.");
    return NULL;
  }
  if (elev[0] > size-3) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Invalid Profile. Size in slot 0 bigger than actual list size.");
    return NULL;
  }

  double dbloss;
  char strmode[100];
  int errnum;
  double ver0, ver1;
  point_to_point(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
                 eno_ns_surfref, frq_mhz, radio_climate, pol, conf, rel,
                 mdvar, !!eno_final,
                 dbloss, strmode, errnum, ver0, ver1);
  delete[] elev;
  return Py_BuildValue("dddsi", dbloss, ver0, ver1, strmode, errnum);
}

static PyObject* itm_point_to_point_rels(PyObject* self, PyObject* args) {
  PyObject* elev_obj = NULL;
  double tht_m, rht_m;
  double eps_dielect, sgm_conductivity, eno_ns_surfref;
  double frq_mhz;
  int radio_climate, pol;
  double conf;
  PyObject* rels_obj = NULL;
  int mdvar = 12;  // Default arguments
  int eno_final = 0;
  if (!PyArg_ParseTuple(args, "OddddddiidO|ii:point_to_point_rels",
                        &elev_obj, &tht_m, &rht_m, &eps_dielect, &sgm_conductivity,
                        &eno_ns_surfref,
                        &frq_mhz, &radio_climate, &pol, &conf, &rels_obj,
                        &mdvar, &eno_final)) {
    return NULL;
  }

  if (!PyList_Check(elev_obj)) {
    return NULL;
  }

  if (!PyList_Check(rels_obj)) {
    return NULL;
  }
  // Get the profile
  Py_ssize_t size = PyList_Size(elev_obj);
  if (size < 4) {
    PyErr_SetString(PyExc_ValueError, "Invalid profile size. Should be >= 4.");
    return NULL;
  }

  double* elev = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* i_obj = PyList_GetItem(elev_obj, i);
    double elev_val = PyFloat_AsDouble(i_obj);
    elev[i] = elev_val;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Profile should only contain numerical values.");
    return NULL;
  }
  if (elev[0] > size-3) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Invalid Profile. Size in slot 0 bigger than actual list size.");
    return NULL;
  }
  // Get the reliability list
  size = PyList_Size(rels_obj);
  if (size <= 0) {
    delete[] elev;
    PyErr_SetString(PyExc_ValueError, "Reliabilities list empty.");
    return NULL;
  }
  double* rels = new double[size];
  for (Py_ssize_t i = 0; i < size; i++) {
    PyObject* rel_obj = PyList_GetItem(rels_obj, i);
    double rel = PyFloat_AsDouble(rel_obj);
    rels[i] = rel;
  }
  if (PyErr_Occurred()) {
    delete[] elev;
    delete[] rels;
    PyErr_SetString(PyExc_ValueError, "Reliabilities list should only contain numerical values.");
    return NULL;
  }
  int num_rels = size;
  double* db_losses = new double[num_rels];
  double ver0, ver1;
  char strmode[100];
  int errnum;
  point_to_point_rels(elev, tht_m, rht_m, eps_dielect, sgm_conductivity,
                      eno_ns_surfref, frq_mhz, radio_climate, pol, conf,
                      rels, num_rels,
                      mdvar, !!eno_final,
                      db_losses, strmode, errnum, ver0, ver1);
  delete[] elev;
  delete[] rels;

  PyObject* loss_obj = PyList_New(num_rels);
  for (int k = 0; k < size; k++ ) {
    PyList_SET_ITEM(loss_obj, k, Py_BuildValue("d", db_losses[k]));
  }
  delete[] db_losses;
  // Note: use N instead of O here to avoid increment of ref count of loss_obj.
  // Otherwise would have a mem leak, since it would never be released.
  return Py_BuildValue("Nddsi", loss_obj, ver0, ver1, strmode, errnum);
}

static PyMethodDef ITMMethods[] = {
  {"point_to_point", itm_point_to_point, METH_VARARGS, "Point-to-point model"},
  {"point_to_point_rels", itm_point_to_point_rels, METH_VARARGS, "Point-to-point-Rels model"},
  {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC inititm_its(void) {
  Py_InitModule3("itm_its", ITMMethods, "Longley-Rice ITM Propagation Module");
}
<|endoftext|>


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

Redistribution and use of HOOMD, in source and binary forms, with or
without modification, are permitted, provided that the following
conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names HOOMD's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
*/

// $Id$
// $URL$

/*! \file LJForceComputeGPU.cc
	\brief Defines the LJForceComputeGPU class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include "LJForceComputeGPU.h"
#include "cuda_runtime.h"

#include <stdexcept>

#include <boost/python.hpp>
using namespace boost::python;

#include <boost/bind.hpp>

using namespace boost;
using namespace std;

/*! \param sysdef System to compute forces on
 	\param nlist Neighborlist to use for computing the forces
	\param r_cut Cuttoff radius beyond which the force is 0
	\param slj	 Determines if Diameter Shifted LJ potential is being used
	\post memory is allocated and all parameters lj1 and lj2 are set to 0.0
	\note The LJForceComputeGPU does not own the Neighborlist, the caller should
		delete the neighborlist when done.
*/
LJForceComputeGPU::LJForceComputeGPU(boost::shared_ptr<SystemDefinition> sysdef, boost::shared_ptr<NeighborList> nlist, Scalar r_cut)
	: LJForceCompute(sysdef, nlist, r_cut)
	{
	// can't run on the GPU if there aren't any GPUs in the execution configuration
	if (exec_conf.gpu.size() == 0)
		{
		cerr << endl << "***Error! Creating a LJForceComputeGPU with no GPU in the execution configuration" << endl << endl;
		throw std::runtime_error("Error initializing LJForceComputeGPU");
		}

	if (m_ntypes > 44)
		{
		cerr << endl << "***Error! LJForceComputeGPU cannot handle " << m_ntypes << " types" << endl << endl;
		throw runtime_error("Error initializing LJForceComputeGPU");
		}

	// default block size is the highest performance in testing on different hardware
	// choose based on compute capability of the device
	cudaDeviceProp deviceProp;
	int dev;
	exec_conf.gpu[0]->call(bind(cudaGetDevice, &dev));
	exec_conf.gpu[0]->call(bind(cudaGetDeviceProperties, &deviceProp, dev));
	if (deviceProp.major == 1 && deviceProp.minor == 0)
		m_block_size = 320;
	else if (deviceProp.major == 1 && deviceProp.minor == 1)
		m_block_size = 256;
	else if (deviceProp.major == 1 && deviceProp.minor < 4)
		m_block_size = 384;
	else
		{
		cout << "***Warning! Unknown compute " << deviceProp.major << "." << deviceProp.minor << " when tuning block size for LJForceComputeGPU" << endl;
		m_block_size = 64;
		}

	// ulf workaround setup
	#ifndef DISABLE_ULF_WORKAROUND
	// the ULF workaround is needed on GTX280 and older GPUS
	// it is not needed on C1060, S1070, GTX285, GTX295, and (hopefully) newer ones
	m_ulf_workaround = true;

	if (deviceProp.major == 1 && deviceProp.minor >= 3)
		m_ulf_workaround = false;
	if (string(deviceProp.name) == "GTX 280")
		m_ulf_workaround = true;

	if (m_ulf_workaround)
		cout << "Notice: ULF bug workaround enabled for LJForceComputeGPU" << endl;
	#else
	m_ulf_workaround = false;
	#endif

	// allocate the coeff data on the GPU
	int nbytes = sizeof(float2)*m_pdata->getNTypes()*m_pdata->getNTypes();

	d_coeffs.resize(exec_conf.gpu.size());
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		{
		exec_conf.gpu[cur_gpu]->setTag(__FILE__, __LINE__);
		exec_conf.gpu[cur_gpu]->call(bind(cudaMalloc, (void **)((void *)&d_coeffs[cur_gpu]), nbytes));
		assert(d_coeffs[cur_gpu]);
		exec_conf.gpu[cur_gpu]->call(bind(cudaMemset, (void *)d_coeffs[cur_gpu], 0, nbytes));
		}
	// allocate the coeff data on the CPU
	h_coeffs = new float2[m_pdata->getNTypes()*m_pdata->getNTypes()];
	}

LJForceComputeGPU::~LJForceComputeGPU()
	{
	// free the coefficients on the GPU
	exec_conf.tagAll(__FILE__, __LINE__);
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		{
		assert(d_coeffs[cur_gpu]);
		exec_conf.gpu[cur_gpu]->call(bind(cudaFree, (void *)d_coeffs[cur_gpu]));
		}
	delete[] h_coeffs;
	}

/*! \param block_size Size of the block to run on the device
	Performance of the code may be dependant on the block size run
	on the GPU. \a block_size should be set to be a multiple of 32.
*/
void LJForceComputeGPU::setBlockSize(int block_size)
	{
	m_block_size = block_size;
	}

/*! \post The parameters \a lj1 and \a lj2 are set for the pairs \a typ1, \a typ2 and \a typ2, \a typ1.
	\note \a lj? are low level parameters used in the calculation. In order to specify
	these for a normal lennard jones formula (with alpha), they should be set to the following.
	- \a lj1 = 4.0 * epsilon * pow(sigma,12.0)
	- \a lj2 = alpha * 4.0 * epsilon * pow(sigma,6.0);

	Setting the parameters for typ1,typ2 automatically sets the same parameters for typ2,typ1: there
	is no need to call this funciton for symmetric pairs. Any pairs that this function is not called
	for will have lj1 and lj2 set to 0.0.

	\param typ1 Specifies one type of the pair
	\param typ2 Specifies the second type of the pair
	\param lj1 First parameter used to calcluate forces
	\param lj2 Second parameter used to calculate forces
*/
void LJForceComputeGPU::setParams(unsigned int typ1, unsigned int typ2, Scalar lj1, Scalar lj2)
	{
	assert(h_coeffs);
	if (typ1 >= m_ntypes || typ2 >= m_ntypes)
		{
		cerr << endl << "***Error! Trying to set LJ params for a non existant type! " << typ1 << "," << typ2 << endl << endl;
		throw runtime_error("LJForceComputeGpu::setParams argument error");
		}

	// set coeffs in both symmetric positions in the matrix
	h_coeffs[typ1*m_pdata->getNTypes() + typ2] = make_float2(lj1, lj2);
	h_coeffs[typ2*m_pdata->getNTypes() + typ1] = make_float2(lj1, lj2);

	int nbytes = sizeof(float2)*m_pdata->getNTypes()*m_pdata->getNTypes();
	exec_conf.tagAll(__FILE__, __LINE__);
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		exec_conf.gpu[cur_gpu]->call(bind(cudaMemcpy, d_coeffs[cur_gpu], h_coeffs, nbytes, cudaMemcpyHostToDevice));
	}

/*! \post The lennard jones forces are computed for the given timestep on the GPU.
	The neighborlist's compute method is called to ensure that it is up to date
	before forces are computed.
 	\param timestep Current time step of the simulation

 	Calls gpu_compute_lj_forces to do the dirty work.
*/
void LJForceComputeGPU::computeForces(unsigned int timestep)
	{
	// start by updating the neighborlist
	m_nlist->compute(timestep);

	// start the profile
	if (m_prof) m_prof->push(exec_conf, "LJ pair");

	// The GPU implementation CANNOT handle a half neighborlist, error out now
	bool third_law = m_nlist->getStorageMode() == NeighborList::half;
	if (third_law)
		{
		cerr << endl << "***Error! LJForceComputeGPU cannot handle a half neighborlist" << endl << endl;
		throw runtime_error("Error computing forces in LJForceComputeGPU");
		}

	// access the neighbor list, which just selects the neighborlist into the device's memory, copying
	// it there if needed
	vector<gpu_nlist_array>& nlist = m_nlist->getListGPU();

	// access the particle data
	vector<gpu_pdata_arrays>& pdata = m_pdata->acquireReadOnlyGPU();
	gpu_boxsize box = m_pdata->getBoxGPU();

	// run the kernel on all GPUs in parallel
	exec_conf.tagAll(__FILE__, __LINE__);
	lj_options opt;
	opt.r_cutsq = m_r_cut * m_r_cut;
	opt.block_size = m_block_size;
	opt.xplor_fraction = m_xplor_fraction;
	opt.ulf_workaround = m_ulf_workaround;
	opt.shift_mode = m_shift_mode;
	opt.slj = m_slj;

	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		exec_conf.gpu[cur_gpu]->callAsync(bind(gpu_compute_lj_forces, m_gpu_forces[cur_gpu].d_data, pdata[cur_gpu], box, nlist[cur_gpu], d_coeffs[cur_gpu], m_pdata->getNTypes(), opt));
	exec_conf.syncAll();

	m_pdata->release();

	// the force data is now only up to date on the gpu
	m_data_location = gpu;

	Scalar avg_neigh = m_nlist->estimateNNeigh();
	int64_t n_calc = int64_t(avg_neigh * m_pdata->getN());
	int64_t mem_transfer = m_pdata->getN() * (4 + 16 + 20) + n_calc * (4 + 16);
	int64_t flops = n_calc * (3+12+5+2+2+6+3+2+7);
	if (m_prof) m_prof->pop(exec_conf, flops, mem_transfer);
	}

void export_LJForceComputeGPU()
	{
	class_<LJForceComputeGPU, boost::shared_ptr<LJForceComputeGPU>, bases<LJForceCompute>, boost::noncopyable >
		("LJForceComputeGPU", init< boost::shared_ptr<SystemDefinition>, boost::shared_ptr<NeighborList>, Scalar >(), bool >())
		.def("setBlockSize", &LJForceComputeGPU::setBlockSize)
		;
	}

#ifdef WIN32
#pragma warning( pop )
#endif

<commit_msg>fixed a little oopsie in the LJ GPU code.<commit_after>/*
Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
Source Software License
Copyright (c) 2008 Ames Laboratory Iowa State University
All rights reserved.

Redistribution and use of HOOMD, in source and binary forms, with or
without modification, are permitted, provided that the following
conditions are met:

* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

* Neither the name of the copyright holder nor the names HOOMD's
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.

Disclaimer

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.

IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
*/

// $Id$
// $URL$

/*! \file LJForceComputeGPU.cc
	\brief Defines the LJForceComputeGPU class
*/

#ifdef WIN32
#pragma warning( push )
#pragma warning( disable : 4103 4244 )
#endif

#include "LJForceComputeGPU.h"
#include "cuda_runtime.h"

#include <stdexcept>

#include <boost/python.hpp>
using namespace boost::python;

#include <boost/bind.hpp>

using namespace boost;
using namespace std;

/*! \param sysdef System to compute forces on
 	\param nlist Neighborlist to use for computing the forces
	\param r_cut Cuttoff radius beyond which the force is 0
	\param slj	 Determines if Diameter Shifted LJ potential is being used
	\post memory is allocated and all parameters lj1 and lj2 are set to 0.0
	\note The LJForceComputeGPU does not own the Neighborlist, the caller should
		delete the neighborlist when done.
*/
LJForceComputeGPU::LJForceComputeGPU(boost::shared_ptr<SystemDefinition> sysdef, boost::shared_ptr<NeighborList> nlist, Scalar r_cut)
	: LJForceCompute(sysdef, nlist, r_cut)
	{
	// can't run on the GPU if there aren't any GPUs in the execution configuration
	if (exec_conf.gpu.size() == 0)
		{
		cerr << endl << "***Error! Creating a LJForceComputeGPU with no GPU in the execution configuration" << endl << endl;
		throw std::runtime_error("Error initializing LJForceComputeGPU");
		}

	if (m_ntypes > 44)
		{
		cerr << endl << "***Error! LJForceComputeGPU cannot handle " << m_ntypes << " types" << endl << endl;
		throw runtime_error("Error initializing LJForceComputeGPU");
		}

	// default block size is the highest performance in testing on different hardware
	// choose based on compute capability of the device
	cudaDeviceProp deviceProp;
	int dev;
	exec_conf.gpu[0]->call(bind(cudaGetDevice, &dev));
	exec_conf.gpu[0]->call(bind(cudaGetDeviceProperties, &deviceProp, dev));
	if (deviceProp.major == 1 && deviceProp.minor == 0)
		m_block_size = 320;
	else if (deviceProp.major == 1 && deviceProp.minor == 1)
		m_block_size = 256;
	else if (deviceProp.major == 1 && deviceProp.minor < 4)
		m_block_size = 384;
	else
		{
		cout << "***Warning! Unknown compute " << deviceProp.major << "." << deviceProp.minor << " when tuning block size for LJForceComputeGPU" << endl;
		m_block_size = 64;
		}

	// ulf workaround setup
	#ifndef DISABLE_ULF_WORKAROUND
	// the ULF workaround is needed on GTX280 and older GPUS
	// it is not needed on C1060, S1070, GTX285, GTX295, and (hopefully) newer ones
	m_ulf_workaround = true;

	if (deviceProp.major == 1 && deviceProp.minor >= 3)
		m_ulf_workaround = false;
	if (string(deviceProp.name) == "GTX 280")
		m_ulf_workaround = true;

	if (m_ulf_workaround)
		cout << "Notice: ULF bug workaround enabled for LJForceComputeGPU" << endl;
	#else
	m_ulf_workaround = false;
	#endif

	// allocate the coeff data on the GPU
	int nbytes = sizeof(float2)*m_pdata->getNTypes()*m_pdata->getNTypes();

	d_coeffs.resize(exec_conf.gpu.size());
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		{
		exec_conf.gpu[cur_gpu]->setTag(__FILE__, __LINE__);
		exec_conf.gpu[cur_gpu]->call(bind(cudaMalloc, (void **)((void *)&d_coeffs[cur_gpu]), nbytes));
		assert(d_coeffs[cur_gpu]);
		exec_conf.gpu[cur_gpu]->call(bind(cudaMemset, (void *)d_coeffs[cur_gpu], 0, nbytes));
		}
	// allocate the coeff data on the CPU
	h_coeffs = new float2[m_pdata->getNTypes()*m_pdata->getNTypes()];
	}

LJForceComputeGPU::~LJForceComputeGPU()
	{
	// free the coefficients on the GPU
	exec_conf.tagAll(__FILE__, __LINE__);
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		{
		assert(d_coeffs[cur_gpu]);
		exec_conf.gpu[cur_gpu]->call(bind(cudaFree, (void *)d_coeffs[cur_gpu]));
		}
	delete[] h_coeffs;
	}

/*! \param block_size Size of the block to run on the device
	Performance of the code may be dependant on the block size run
	on the GPU. \a block_size should be set to be a multiple of 32.
*/
void LJForceComputeGPU::setBlockSize(int block_size)
	{
	m_block_size = block_size;
	}

/*! \post The parameters \a lj1 and \a lj2 are set for the pairs \a typ1, \a typ2 and \a typ2, \a typ1.
	\note \a lj? are low level parameters used in the calculation. In order to specify
	these for a normal lennard jones formula (with alpha), they should be set to the following.
	- \a lj1 = 4.0 * epsilon * pow(sigma,12.0)
	- \a lj2 = alpha * 4.0 * epsilon * pow(sigma,6.0);

	Setting the parameters for typ1,typ2 automatically sets the same parameters for typ2,typ1: there
	is no need to call this funciton for symmetric pairs. Any pairs that this function is not called
	for will have lj1 and lj2 set to 0.0.

	\param typ1 Specifies one type of the pair
	\param typ2 Specifies the second type of the pair
	\param lj1 First parameter used to calcluate forces
	\param lj2 Second parameter used to calculate forces
*/
void LJForceComputeGPU::setParams(unsigned int typ1, unsigned int typ2, Scalar lj1, Scalar lj2)
	{
	assert(h_coeffs);
	if (typ1 >= m_ntypes || typ2 >= m_ntypes)
		{
		cerr << endl << "***Error! Trying to set LJ params for a non existant type! " << typ1 << "," << typ2 << endl << endl;
		throw runtime_error("LJForceComputeGpu::setParams argument error");
		}

	// set coeffs in both symmetric positions in the matrix
	h_coeffs[typ1*m_pdata->getNTypes() + typ2] = make_float2(lj1, lj2);
	h_coeffs[typ2*m_pdata->getNTypes() + typ1] = make_float2(lj1, lj2);

	int nbytes = sizeof(float2)*m_pdata->getNTypes()*m_pdata->getNTypes();
	exec_conf.tagAll(__FILE__, __LINE__);
	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		exec_conf.gpu[cur_gpu]->call(bind(cudaMemcpy, d_coeffs[cur_gpu], h_coeffs, nbytes, cudaMemcpyHostToDevice));
	}

/*! \post The lennard jones forces are computed for the given timestep on the GPU.
	The neighborlist's compute method is called to ensure that it is up to date
	before forces are computed.
 	\param timestep Current time step of the simulation

 	Calls gpu_compute_lj_forces to do the dirty work.
*/
void LJForceComputeGPU::computeForces(unsigned int timestep)
	{
	// start by updating the neighborlist
	m_nlist->compute(timestep);

	// start the profile
	if (m_prof) m_prof->push(exec_conf, "LJ pair");

	// The GPU implementation CANNOT handle a half neighborlist, error out now
	bool third_law = m_nlist->getStorageMode() == NeighborList::half;
	if (third_law)
		{
		cerr << endl << "***Error! LJForceComputeGPU cannot handle a half neighborlist" << endl << endl;
		throw runtime_error("Error computing forces in LJForceComputeGPU");
		}

	// access the neighbor list, which just selects the neighborlist into the device's memory, copying
	// it there if needed
	vector<gpu_nlist_array>& nlist = m_nlist->getListGPU();

	// access the particle data
	vector<gpu_pdata_arrays>& pdata = m_pdata->acquireReadOnlyGPU();
	gpu_boxsize box = m_pdata->getBoxGPU();

	// run the kernel on all GPUs in parallel
	exec_conf.tagAll(__FILE__, __LINE__);
	lj_options opt;
	opt.r_cutsq = m_r_cut * m_r_cut;
	opt.block_size = m_block_size;
	opt.xplor_fraction = m_xplor_fraction;
	opt.ulf_workaround = m_ulf_workaround;
	opt.shift_mode = m_shift_mode;
	opt.slj = m_slj;

	for (unsigned int cur_gpu = 0; cur_gpu < exec_conf.gpu.size(); cur_gpu++)
		exec_conf.gpu[cur_gpu]->callAsync(bind(gpu_compute_lj_forces, m_gpu_forces[cur_gpu].d_data, pdata[cur_gpu], box, nlist[cur_gpu], d_coeffs[cur_gpu], m_pdata->getNTypes(), opt));
	exec_conf.syncAll();

	m_pdata->release();

	// the force data is now only up to date on the gpu
	m_data_location = gpu;

	Scalar avg_neigh = m_nlist->estimateNNeigh();
	int64_t n_calc = int64_t(avg_neigh * m_pdata->getN());
	int64_t mem_transfer = m_pdata->getN() * (4 + 16 + 20) + n_calc * (4 + 16);
	int64_t flops = n_calc * (3+12+5+2+2+6+3+2+7);
	if (m_prof) m_prof->pop(exec_conf, flops, mem_transfer);
	}

void export_LJForceComputeGPU()
	{
	class_<LJForceComputeGPU, boost::shared_ptr<LJForceComputeGPU>, bases<LJForceCompute>, boost::noncopyable >
		("LJForceComputeGPU", init< boost::shared_ptr<SystemDefinition>, boost::shared_ptr<NeighborList>, Scalar >())
		.def("setBlockSize", &LJForceComputeGPU::setBlockSize)
		;
	}

#ifdef WIN32
#pragma warning( pop )
#endif

<|endoftext|>


<commit_before>#include "Makefile.hpp"

#include <configure/BuildGraph.hpp>
#include <configure/Build.hpp>
#include <configure/Command.hpp>
#include <configure/Filesystem.hpp>
#include <configure/Graph.hpp>
#include <configure/quote.hpp>
#include <configure/utils/path.hpp>
#include <configure/PropertyMap.hpp>
#include <configure/log.hpp>
#include <configure/Rule.hpp>
#include <configure/ShellCommand.hpp>
#include <configure/error.hpp>

#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem.hpp>

#include <fstream>
#include <unordered_set>

namespace configure { namespace generators {

	Makefile::Makefile(Build& build,
	                   path_t project_directory,
	                   path_t configure_exe,
	                   char const* name)
		: Generator(
			build,
			std::move(project_directory),
			std::move(configure_exe),
			(name == nullptr ? Makefile::name() : name)
		)
	{}

	static std::string relative_node_path(Build& b, Node& n)
	{ return n.relative_path(b.directory()).string(); }

	static std::string absolute_node_path(Build&, Node& n)
	{ return n.path().string(); }

	void Makefile::prepare()
	{
		BuildGraph const& bg = _build.build_graph();
		Graph const& g = bg.graph();

		for (auto vertex_range = boost::vertices(g);
		     vertex_range.first != vertex_range.second;
		     ++vertex_range.first)
		{
			auto vertex = *vertex_range.first;
			auto& node = bg.node(vertex);

			if (node->is_virtual())
			{
				if (!node->name().empty())
					_virtual_nodes.push_back(node);
			}
			else
			{
				// Check for nodes that are not generated by us (no inputs).
				// (this does not apply to virtual nodes, that always
				// considered as targets).
				auto in_edge_range = boost::in_edges(vertex, g);
				if (in_edge_range.first == in_edge_range.second)
				{
					_sources.push_back(node);
					continue;
				}
			}

			// At this point we know that the node is a target.
			_targets.push_back(node);

			auto out_edge_range = boost::out_edges(vertex, g);
			if (out_edge_range.first == out_edge_range.second)
			{
				// Nothing depends on this node, this target is final.
				_final_targets.push_back(node);
			}
			else
			{
				// Something depends on this Node, it is a also a source.
				if (!node->is_virtual())
					_sources.push_back(node);

				// The node is still considered final if the root node depends
				// on it.
				if (bg.has_link(*_build.root_node(), *node))
					_final_targets.push_back(node);
			}
		}

		for (auto& node: _sources)
		{
			if (!node->is_file() || !node->has_property("language"))
				continue;

			auto& lang = node->property<std::string>("language");
			if (lang == "c" || lang == "c++")
			{
				auto include_directories = node->property<std::vector<boost::filesystem::path>>("include_directories");
				NodePtr first_target;
				for (auto out_edge_range = boost::out_edges(node->index, g);
					 out_edge_range.first != out_edge_range.second;
					 ++out_edge_range.first)
				{
					first_target = bg.node(boost::target(*out_edge_range.first, g));
					break;
				}
				if (first_target == nullptr)
				{
					log::warning("Ignore implicit dependencies for",
					             node->string(), ", no target node found...");
					continue;
				}

				auto& target = _build.target_node(
					first_target->relative_path(_build.directory()).string() + ".mk"
				);
				_dependencies.push_back(target);
				ShellCommand cmd;
				cmd.append(
					_configure_exe, "-E" , "c-header-dependencies",
					target, node
				);
				for (auto out_edge_range = boost::out_edges(node->index, g);
					 out_edge_range.first != out_edge_range.second;
					 ++out_edge_range.first)
					cmd.append(bg.node(boost::target(*out_edge_range.first, g)));
				cmd.append("--");
				for (auto& dir: include_directories)
					cmd.append(_build.directory_node(dir));
				_build.add_rule(
					Rule()
						.add_source(node)
						.add_target(target)
						.add_shell_command(std::move(cmd))
				);
			}
		}

		// We still need to add dependencies to the final targets
		for (auto& node: _dependencies)
			_targets.push_back(node);
	}

	namespace {

		struct RelativePathShellFormatter
			: public ShellFormatter
		{
			boost::filesystem::path const& _build_dir;
			boost::filesystem::path const& _project_dir;

			RelativePathShellFormatter(Build& build,
			                           boost::filesystem::path const& project_dir)
				: _build_dir(build.directory())
				, _project_dir(project_dir)
			{}

			std::string
			operator ()(boost::filesystem::path const& value) const override
			{
				if (utils::starts_with(value, _project_dir))
					return utils::relative_path(value, _build_dir).string();
				return value.string();
			}

		};

	}

	void Makefile::generate() const
	{
		bool use_relpath = _build.option<bool>(
		    "GENERATOR_" + std::string(this->name()) + "_USE_RELATIVE_PATH",
		    std::string(this->name()) + " generator uses relative path",
		    this->use_relative_path()
		);
		std::unique_ptr<ShellFormatter> formatter;
		if (use_relpath)
			formatter = std::unique_ptr<ShellFormatter>(
				new RelativePathShellFormatter(_build, _project_directory)
			);
		else
			formatter = std::unique_ptr<ShellFormatter>(new ShellFormatter);

		std::string (*node_path)(Build&, Node&);
		if (use_relpath)
			node_path = &relative_node_path;
		else
			node_path = &absolute_node_path;

		std::ofstream out((_build.directory() / "Makefile").string());
		out << "# Generated makefile" << std::endl;
		if (_name == "Makefile")
		{
			// This speed up the makefile
			out << "MAKEFLAGS += --no-builtin-rules" << std::endl;
			out << ".SUFFIXES:" << std::endl;
		}
		BuildGraph const& bg = _build.build_graph();
		Graph const& g = bg.graph();

		// Fill the "all" and ".PHONY" rules
		out << ".PHONY:" << std::endl;
		out << ".PHONY: all";
		for (auto node: _virtual_nodes)
			out << ' ' << node->name();
		out << "\n\n";

		if (!_final_targets.empty())
		{
			out << "all:";
			for (auto& node: _final_targets)
			{
				if (node->is_file())
					out << ' ' << node_path(_build, *node);
				else if (node->is_virtual() && !node->name().empty())
					out << ' ' << node->name();
			}
			out << "\n\n";

			out << "clean:\n";
			for (auto& node: _targets)
				if (node->is_file())
					out << '\t' << "rm -f " << node_path(_build, *node) << '\n';
			out << "\n";
		}

		std::unordered_set<Node const*> to_delete;
		for (auto& node: _targets)
		{
			if (node->is_virtual())
				out << node->name() << ':';
			else
				out << node_path(_build, *node) << ':';

			auto in_edge_range = boost::in_edges(node->index, g);
			for (GraphTraits::in_edge_iterator i = in_edge_range.first;
			     i != in_edge_range.second; ++i)
			{
				auto node = bg.node(boost::source(*i, g)).get();
				if (node->is_file())
					out << ' ' << node_path(_build, *node);
				else if (node->is_virtual())
					out << ' ' << node->name();
			}
			out << std::endl;

			std::vector<std::string> command_strings;
			std::unordered_set<Command const*> seen_commands;
			for (; in_edge_range.first != in_edge_range.second;
			     ++in_edge_range.first)
			{
				auto& link = bg.link(*in_edge_range.first);
				Command const* cmd_ptr = &link.command();
				if (seen_commands.insert(cmd_ptr).second == false)
					continue;
				for (auto const& shell_command: cmd_ptr->shell_commands())
				{
					command_strings.push_back(
						this->dump_command(
							shell_command.string(_build, link, *formatter)
						)
					);
					out << '\t' << command_strings.back() << std::endl;
				}
			}
			out << std::endl;
			if (node->is_file())
			{
				node->set_property<std::string>(
					std::string(this->name()) + "_GENERATED_COMMANDS",
					boost::join(command_strings, "\n")
				);
				if (node->properties().dirty())
					to_delete.insert(node.get());
			}
		}

		for (auto node: to_delete)
		{
			log::verbose("Deleting node", node->string(), "(command line changed)");
			try {
				boost::filesystem::remove(node->path());
			} catch (...) {
				log::warning("Couldn't remove", node->string(), ":", error_string());
			}
		}

		for (auto& node: _dependencies)
			out << "-include " << node_path(_build, *node) << std::endl;

	}

	std::string Makefile::dump_command(std::vector<std::string> const& cmd) const
	{
#ifdef _WIN32
		if (cmd.size() == 1)
		{
			// Workaroung a bug in GNU Make, when commands contain a double quote
			// they are spawned through CreateProcess() as 'sh -c \"COMMAND HERE\"'
			// when the argument does have any special character other than slash
			// and there is only one argument, quotes are left ...
			auto res = quote<CommandParser::make>(cmd);
			if (res[0] == '"' && res.back() == '"' )
			{
				res = res.substr(1, res.size() - 2);
			}
			return res;
		}
#endif
		return quote<CommandParser::make>(cmd);
	}

	bool Makefile::is_available(Build& build)
	{ return build.fs().which("make") != boost::none; }

	std::vector<std::string>
	Makefile::build_command(std::string const& target) const
	{
		return {
			"make", "-C", _build.directory().string(),
			target.empty() ? "all" : target
		};
	}

	bool Makefile::use_relative_path() const { return true; }
}}

<commit_msg>Discard empty virtual nodes.<commit_after>#include "Makefile.hpp"

#include <configure/BuildGraph.hpp>
#include <configure/Build.hpp>
#include <configure/Command.hpp>
#include <configure/Filesystem.hpp>
#include <configure/Graph.hpp>
#include <configure/quote.hpp>
#include <configure/utils/path.hpp>
#include <configure/PropertyMap.hpp>
#include <configure/log.hpp>
#include <configure/Rule.hpp>
#include <configure/ShellCommand.hpp>
#include <configure/error.hpp>

#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem.hpp>

#include <fstream>
#include <unordered_set>

namespace configure { namespace generators {

	Makefile::Makefile(Build& build,
	                   path_t project_directory,
	                   path_t configure_exe,
	                   char const* name)
		: Generator(
			build,
			std::move(project_directory),
			std::move(configure_exe),
			(name == nullptr ? Makefile::name() : name)
		)
	{}

	static std::string relative_node_path(Build& b, Node& n)
	{ return n.relative_path(b.directory()).string(); }

	static std::string absolute_node_path(Build&, Node& n)
	{ return n.path().string(); }

	void Makefile::prepare()
	{
		BuildGraph const& bg = _build.build_graph();
		Graph const& g = bg.graph();

		for (auto vertex_range = boost::vertices(g);
		     vertex_range.first != vertex_range.second;
		     ++vertex_range.first)
		{
			auto vertex = *vertex_range.first;
			auto& node = bg.node(vertex);

			if (node->is_virtual())
			{
				if (node->name().empty())
					continue;
				_virtual_nodes.push_back(node);
			}
			else
			{
				// Check for nodes that are not generated by us (no inputs).
				// (this does not apply to virtual nodes, that always
				// considered as targets).
				auto in_edge_range = boost::in_edges(vertex, g);
				if (in_edge_range.first == in_edge_range.second)
				{
					_sources.push_back(node);
					continue;
				}
			}

			// At this point we know that the node is a target.
			_targets.push_back(node);

			auto out_edge_range = boost::out_edges(vertex, g);
			if (out_edge_range.first == out_edge_range.second)
			{
				// Nothing depends on this node, this target is final.
				_final_targets.push_back(node);
			}
			else
			{
				// Something depends on this Node, it is a also a source.
				if (!node->is_virtual())
					_sources.push_back(node);

				// The node is still considered final if the root node depends
				// on it.
				if (bg.has_link(*_build.root_node(), *node))
					_final_targets.push_back(node);
			}
		}

		for (auto& node: _sources)
		{
			if (!node->is_file() || !node->has_property("language"))
				continue;

			auto& lang = node->property<std::string>("language");
			if (lang == "c" || lang == "c++")
			{
				auto include_directories = node->property<std::vector<boost::filesystem::path>>("include_directories");
				NodePtr first_target;
				for (auto out_edge_range = boost::out_edges(node->index, g);
					 out_edge_range.first != out_edge_range.second;
					 ++out_edge_range.first)
				{
					first_target = bg.node(boost::target(*out_edge_range.first, g));
					break;
				}
				if (first_target == nullptr)
				{
					log::warning("Ignore implicit dependencies for",
					             node->string(), ", no target node found...");
					continue;
				}

				auto& target = _build.target_node(
					first_target->relative_path(_build.directory()).string() + ".mk"
				);
				_dependencies.push_back(target);
				ShellCommand cmd;
				cmd.append(
					_configure_exe, "-E" , "c-header-dependencies",
					target, node
				);
				for (auto out_edge_range = boost::out_edges(node->index, g);
					 out_edge_range.first != out_edge_range.second;
					 ++out_edge_range.first)
					cmd.append(bg.node(boost::target(*out_edge_range.first, g)));
				cmd.append("--");
				for (auto& dir: include_directories)
					cmd.append(_build.directory_node(dir));
				_build.add_rule(
					Rule()
						.add_source(node)
						.add_target(target)
						.add_shell_command(std::move(cmd))
				);
			}
		}

		// We still need to add dependencies to the final targets
		for (auto& node: _dependencies)
			_targets.push_back(node);
	}

	namespace {

		struct RelativePathShellFormatter
			: public ShellFormatter
		{
			boost::filesystem::path const& _build_dir;
			boost::filesystem::path const& _project_dir;

			RelativePathShellFormatter(Build& build,
			                           boost::filesystem::path const& project_dir)
				: _build_dir(build.directory())
				, _project_dir(project_dir)
			{}

			std::string
			operator ()(boost::filesystem::path const& value) const override
			{
				if (utils::starts_with(value, _project_dir))
					return utils::relative_path(value, _build_dir).string();
				return value.string();
			}

		};

	}

	void Makefile::generate() const
	{
		bool use_relpath = _build.option<bool>(
		    "GENERATOR_" + std::string(this->name()) + "_USE_RELATIVE_PATH",
		    std::string(this->name()) + " generator uses relative path",
		    this->use_relative_path()
		);
		std::unique_ptr<ShellFormatter> formatter;
		if (use_relpath)
			formatter = std::unique_ptr<ShellFormatter>(
				new RelativePathShellFormatter(_build, _project_directory)
			);
		else
			formatter = std::unique_ptr<ShellFormatter>(new ShellFormatter);

		std::string (*node_path)(Build&, Node&);
		if (use_relpath)
			node_path = &relative_node_path;
		else
			node_path = &absolute_node_path;

		std::ofstream out((_build.directory() / "Makefile").string());
		out << "# Generated makefile" << std::endl;
		if (_name == "Makefile")
		{
			// This speed up the makefile
			out << "MAKEFLAGS += --no-builtin-rules" << std::endl;
			out << ".SUFFIXES:" << std::endl;
		}
		BuildGraph const& bg = _build.build_graph();
		Graph const& g = bg.graph();

		// Fill the "all" and ".PHONY" rules
		out << ".PHONY:" << std::endl;
		out << ".PHONY: all";
		for (auto node: _virtual_nodes)
			out << ' ' << node->name();
		out << "\n\n";

		if (!_final_targets.empty())
		{
			out << "all:";
			for (auto& node: _final_targets)
			{
				if (node->is_file())
					out << ' ' << node_path(_build, *node);
				else if (node->is_virtual() && !node->name().empty())
					out << ' ' << node->name();
			}
			out << "\n\n";

			out << "clean:\n";
			for (auto& node: _targets)
				if (node->is_file())
					out << '\t' << "rm -f " << node_path(_build, *node) << '\n';
			out << "\n";
		}

		std::unordered_set<Node const*> to_delete;
		for (auto& node: _targets)
		{
			if (node->is_virtual())
				out << node->name() << ':';
			else
				out << node_path(_build, *node) << ':';

			auto in_edge_range = boost::in_edges(node->index, g);
			for (GraphTraits::in_edge_iterator i = in_edge_range.first;
			     i != in_edge_range.second; ++i)
			{
				auto node = bg.node(boost::source(*i, g)).get();
				if (node->is_file())
					out << ' ' << node_path(_build, *node);
				else if (node->is_virtual())
					out << ' ' << node->name();
			}
			out << std::endl;

			std::vector<std::string> command_strings;
			std::unordered_set<Command const*> seen_commands;
			for (; in_edge_range.first != in_edge_range.second;
			     ++in_edge_range.first)
			{
				auto& link = bg.link(*in_edge_range.first);
				Command const* cmd_ptr = &link.command();
				if (seen_commands.insert(cmd_ptr).second == false)
					continue;
				for (auto const& shell_command: cmd_ptr->shell_commands())
				{
					command_strings.push_back(
						this->dump_command(
							shell_command.string(_build, link, *formatter)
						)
					);
					out << '\t' << command_strings.back() << std::endl;
				}
			}
			out << std::endl;
			if (node->is_file())
			{
				node->set_property<std::string>(
					std::string(this->name()) + "_GENERATED_COMMANDS",
					boost::join(command_strings, "\n")
				);
				if (node->properties().dirty())
					to_delete.insert(node.get());
			}
		}

		for (auto node: to_delete)
		{
			log::verbose("Deleting node", node->string(), "(command line changed)");
			try {
				boost::filesystem::remove(node->path());
			} catch (...) {
				log::warning("Couldn't remove", node->string(), ":", error_string());
			}
		}

		for (auto& node: _dependencies)
			out << "-include " << node_path(_build, *node) << std::endl;

	}

	std::string Makefile::dump_command(std::vector<std::string> const& cmd) const
	{
#ifdef _WIN32
		if (cmd.size() == 1)
		{
			// Workaroung a bug in GNU Make, when commands contain a double quote
			// they are spawned through CreateProcess() as 'sh -c \"COMMAND HERE\"'
			// when the argument does have any special character other than slash
			// and there is only one argument, quotes are left ...
			auto res = quote<CommandParser::make>(cmd);
			if (res[0] == '"' && res.back() == '"' )
			{
				res = res.substr(1, res.size() - 2);
			}
			return res;
		}
#endif
		return quote<CommandParser::make>(cmd);
	}

	bool Makefile::is_available(Build& build)
	{ return build.fs().which("make") != boost::none; }

	std::vector<std::string>
	Makefile::build_command(std::string const& target) const
	{
		return {
			"make", "-C", _build.directory().string(),
			target.empty() ? "all" : target
		};
	}

	bool Makefile::use_relative_path() const { return true; }
}}

<|endoftext|>