<commit_before>#include "stdafx.h"
#include "spline.h"

#include <glm/gtx/norm.hpp>

#include "asdf_multiplat/data/gl_vertex_spec.h"

namespace asdf {
    using namespace vertex_attrib;
namespace hexmap {
namespace data
{

    /* --Save Format--
        write the number of nodes (64-bit unsigned integer)
            write the nodes
        write the number of control nodes (64-bit unsigned integer)
            write the control nodes
    */
    void spline_t::save_to_file(SDL_RWops* io) const
    {
        ASSERT(io, "");
        {
            LOG("offset when writing spline node count: %zu", SDL_RWtell(io));
            uint64_t sz = nodes.size();
            SDL_RWwrite(io, reinterpret_cast<const void*>(&sz), sizeof(uint64_t), 1);
            LOG("wrote node count (%zu bytes)", sizeof(uint64_t));
            LOG("offset after writing spline node count: %zu", SDL_RWtell(io));

            size_t n = SDL_RWwrite(io, nodes.data(), sizeof(line_node_t), nodes.size());
            ASSERT(n == nodes.size(), "error writing spline_t::nodes");
            LOG("wrote %zu spline nodes (%zu bytes)", n, n * sizeof(line_node_t));
        }
        {
            uint64_t sz = control_nodes.size();
            SDL_RWwrite(io, reinterpret_cast<const void*>(&sz), sizeof(uint64_t), 1);
            LOG("wrote control_node count (%zu bytes)", sizeof(uint64_t));

            size_t n = SDL_RWwrite(io, control_nodes.data(), sizeof(control_node_t), control_nodes.size());
            ASSERT(n == control_nodes.size(), "error writing spline_t::control_nodes");
            LOG("wrote %zu control_nodes nodes (%zu bytes)", n, n * sizeof(control_node_t));
        }

        size_t sz = SDL_RWwrite(io, reinterpret_cast<const void*>(&spline_type), sizeof(interpolation_e), 1);
        ASSERT(sz == 1, "");
    }

    void spline_t::load_from_file(SDL_RWops* io)
    {
        ASSERT(io, "");
        {
            {
                LOG("offset when loading spline node count: %zu", SDL_RWtell(io));
                uint64_t sz = 0;
                size_t n = SDL_RWread(io, reinterpret_cast<void*>(&sz), sizeof(uint64_t), 1);
                ASSERT(n == 1, "Error writing spline node count");
                LOG("offset after loading spline node count: %zu", SDL_RWtell(io));

                nodes.resize(sz);
                n = SDL_RWread(io, nodes.data(), sizeof(line_node_t), sz);
                ASSERT(n == sz, "Error loading spline nodes");
            }
            {
                uint64_t sz =   0;
                SDL_RWread(io, reinterpret_cast<void*>(&sz), sizeof(uint64_t), 1);

                control_nodes.resize(sz);
                size_t n = SDL_RWread(io, control_nodes.data(), sizeof(line_node_t), sz);
                ASSERT(n == sz, "Error loading spline control nodes");
            }

            size_t n = SDL_RWread(io, reinterpret_cast<void*>(&spline_type), sizeof(interpolation_e), 1);
            ASSERT(n == 1, "Error reading spline interpolation type");
        }
    }

    bool point_intersects_spline(glm::vec2 const& world_pos, spline_t const& spline, float dist_threshold)
    {
        if(spline.nodes.size() == 0)
        {
            return false;
        }
        else if(spline.nodes.size() == 1)
        {
            auto dist = glm::length(spline.nodes[0].position - world_pos);
            return dist <= dist_threshold;
        }
        else
        {
            //get closest point to world_pos
            spline_node_index_t closest = 0;
            auto cv = spline.nodes[0].position - world_pos;
            auto closest_dist_sq = glm::length2(cv);

            for(size_t i = 1; i < spline.nodes.size(); ++i)
            {
                auto v = spline.nodes[i].position - world_pos;
                auto dsq = glm::length2(v);

                if(dsq < closest_dist_sq)
                {
                    closest = i;
                    closest_dist_sq = dsq;
                }
            }

            auto const& p0 = spline.nodes[closest].position;

            // get prev or next node, whichever is closest to world_pos (and exists)
            line_node_t const* prev = nullptr;
            line_node_t const* next = nullptr;

            if(spline.loops)
            {
                prev = (closest == 0) ? &(*spline.nodes.end())  : &(spline.nodes[closest-1]);
                next = (closest+1 == spline.nodes.size()) ?  &(spline.nodes[0])     : &(spline.nodes[closest+1]);
            }
            else
            {
                prev = (closest==0)                       ? nullptr : &(spline.nodes[closest-1]);
                next = (closest+1 == spline.nodes.size()) ? nullptr : &(spline.nodes[closest+1]);
            }

            ASSERT(next || prev, "somehow both next and prev are null");

            //if prev is null, use next, else use prev
            auto* second_closest = (prev != nullptr) ? prev : next;

            //if both are not-null, grab the closest one
            if(prev && next)
            {
                auto d_prev = glm::length2(prev->position - p0);
                auto d_next = glm::length2(next->position - p0);

                second_closest = (d_prev > d_next) ? next : prev;
            }

            auto p1 = second_closest->position;

            switch(spline.spline_type)
            {
                case spline_t::linear:
                    return circle_intersects_line(world_pos, dist_threshold, p0, p1);
                // case spline_t::bezier:
                {
                    //auto c1 = spline.control_nodes[2*inds[0]+0].position;
                    //auto c2 = spline.control_nodes[2*inds[0]+1].position;
                    //return circle_intersects_bezier(world_pos, dist_threshold
                    //                                n1.position, c1, c2, n2.position);
                }
                default: EXPLODE("TODO: implement intersection with %s splines", spline_interpolation_names[spline.spline_type]);
                    return false;
            }
        }
    }

    bool circle_intersects_line(glm::vec2 const& circle_pos, float radius, glm::vec2 const& p0, glm::vec2 const& p1)
    {

        return false;
    }

    bool circle_intersects_bezier(glm::vec2 circle_pos, float radius, glm::vec2 p0, glm::vec2 p1, glm::vec2 p2, glm::vec2 p3)
    {
        EXPLODE("todo");
        return false;
    }

    void spline_selection_t::select_spline(spline_t& spline)
    {
        std::vector<size_t> new_inds;
        new_inds.reserve(spline.size());
        for(size_t i = 0; i < spline.size(); ++i)
        {
            new_inds.push_back(i);
        }

        select_spline_nodes(spline, std::move(new_inds));
    }

    void spline_selection_t::select_spline_nodes(spline_t& spline, std::vector<size_t> node_inds)
    {
        if(is_control_node)
        {
            deselect_all();
            is_control_node = false;
        }

        splines.push_back(&spline);
        node_indices.push_back(std::move(node_inds));
    }

    void spline_selection_t::select_control_node(spline_t& spline, size_t control_node_index)
    {
        deselect_all();
        is_control_node = true;

        splines.push_back(&spline);

        node_indices.resize(1);
        node_indices[0].push_back(control_node_index);
    }

    void spline_selection_t::deselect_all()
    {
        splines.clear();
        node_indices.clear();
    }
}
}
}
<commit_msg>implemented circle_intersects_line()  (thank you wikipedia)<commit_after>#include "stdafx.h"
#include "spline.h"

#include <glm/gtx/norm.hpp>

#include "asdf_multiplat/data/gl_vertex_spec.h"

namespace asdf {
    using namespace vertex_attrib;
namespace hexmap {
namespace data
{

    /* --Save Format--
        write the number of nodes (64-bit unsigned integer)
            write the nodes
        write the number of control nodes (64-bit unsigned integer)
            write the control nodes
    */
    void spline_t::save_to_file(SDL_RWops* io) const
    {
        ASSERT(io, "");
        {
            LOG("offset when writing spline node count: %zu", SDL_RWtell(io));
            uint64_t sz = nodes.size();
            SDL_RWwrite(io, reinterpret_cast<const void*>(&sz), sizeof(uint64_t), 1);
            LOG("wrote node count (%zu bytes)", sizeof(uint64_t));
            LOG("offset after writing spline node count: %zu", SDL_RWtell(io));

            size_t n = SDL_RWwrite(io, nodes.data(), sizeof(line_node_t), nodes.size());
            ASSERT(n == nodes.size(), "error writing spline_t::nodes");
            LOG("wrote %zu spline nodes (%zu bytes)", n, n * sizeof(line_node_t));
        }
        {
            uint64_t sz = control_nodes.size();
            SDL_RWwrite(io, reinterpret_cast<const void*>(&sz), sizeof(uint64_t), 1);
            LOG("wrote control_node count (%zu bytes)", sizeof(uint64_t));

            size_t n = SDL_RWwrite(io, control_nodes.data(), sizeof(control_node_t), control_nodes.size());
            ASSERT(n == control_nodes.size(), "error writing spline_t::control_nodes");
            LOG("wrote %zu control_nodes nodes (%zu bytes)", n, n * sizeof(control_node_t));
        }

        size_t sz = SDL_RWwrite(io, reinterpret_cast<const void*>(&spline_type), sizeof(interpolation_e), 1);
        ASSERT(sz == 1, "");
    }

    void spline_t::load_from_file(SDL_RWops* io)
    {
        ASSERT(io, "");
        {
            {
                LOG("offset when loading spline node count: %zu", SDL_RWtell(io));
                uint64_t sz = 0;
                size_t n = SDL_RWread(io, reinterpret_cast<void*>(&sz), sizeof(uint64_t), 1);
                ASSERT(n == 1, "Error writing spline node count");
                LOG("offset after loading spline node count: %zu", SDL_RWtell(io));

                nodes.resize(sz);
                n = SDL_RWread(io, nodes.data(), sizeof(line_node_t), sz);
                ASSERT(n == sz, "Error loading spline nodes");
            }
            {
                uint64_t sz =   0;
                SDL_RWread(io, reinterpret_cast<void*>(&sz), sizeof(uint64_t), 1);

                control_nodes.resize(sz);
                size_t n = SDL_RWread(io, control_nodes.data(), sizeof(line_node_t), sz);
                ASSERT(n == sz, "Error loading spline control nodes");
            }

            size_t n = SDL_RWread(io, reinterpret_cast<void*>(&spline_type), sizeof(interpolation_e), 1);
            ASSERT(n == 1, "Error reading spline interpolation type");
        }
    }

    bool point_intersects_spline(glm::vec2 const& world_pos, spline_t const& spline, float dist_threshold)
    {
        if(spline.nodes.size() == 0)
        {
            return false;
        }
        else if(spline.nodes.size() == 1)
        {
            auto dist = glm::length(spline.nodes[0].position - world_pos);
            return dist <= dist_threshold;
        }
        else
        {
            //get closest point to world_pos
            spline_node_index_t closest = 0;
            auto cv = spline.nodes[0].position - world_pos;
            auto closest_dist_sq = glm::length2(cv);

            for(size_t i = 1; i < spline.nodes.size(); ++i)
            {
                auto v = spline.nodes[i].position - world_pos;
                auto dsq = glm::length2(v);

                if(dsq < closest_dist_sq)
                {
                    closest = i;
                    closest_dist_sq = dsq;
                }
            }

            auto const& p0 = spline.nodes[closest].position;

            // get prev or next node, whichever is closest to world_pos (and exists)
            line_node_t const* prev = nullptr;
            line_node_t const* next = nullptr;

            if(spline.loops)
            {
                prev = (closest == 0) ? &(*spline.nodes.end())  : &(spline.nodes[closest-1]);
                next = (closest+1 == spline.nodes.size()) ?  &(spline.nodes[0])     : &(spline.nodes[closest+1]);
            }
            else
            {
                prev = (closest==0)                       ? nullptr : &(spline.nodes[closest-1]);
                next = (closest+1 == spline.nodes.size()) ? nullptr : &(spline.nodes[closest+1]);
            }

            ASSERT(next || prev, "somehow both next and prev are null");

            //if prev is null, use next, else use prev
            auto* second_closest = (prev != nullptr) ? prev : next;

            //if both are not-null, grab the closest one
            if(prev && next)
            {
                auto d_prev = glm::length2(prev->position - world_pos);
                auto d_next = glm::length2(next->position - world_pos);

                second_closest = (d_prev > d_next) ? next : prev;
            }

            auto p1 = second_closest->position;

            switch(spline.spline_type)
            {
                case spline_t::linear:
                    return circle_intersects_line(world_pos, dist_threshold, p0, p1);
                // case spline_t::bezier:
                {
                    //auto c1 = spline.control_nodes[2*inds[0]+0].position;
                    //auto c2 = spline.control_nodes[2*inds[0]+1].position;
                    //return circle_intersects_bezier(world_pos, dist_threshold
                    //                                n1.position, c1, c2, n2.position);
                }
                default: EXPLODE("TODO: implement intersection with %s splines", spline_interpolation_names[spline.spline_type]);
                    return false;
            }
        }
    }

    bool circle_intersects_line(glm::vec2 const& circle_pos, float radius, glm::vec2 const& p0, glm::vec2 const& p1)
    {
        using namespace glm;

        auto a = circle_pos - p0;
        auto b = p1-p0;

        float cos_theta = dot(a, b) / (length(a) * length(b));
        float proj_length = length(a) * cos_theta;

        //if beyond the line segment, check dist to p0 and p1
        //otherwise corners won't be handled
        auto t = proj_length / length(b); //I feel like there's proably a more optimal way to calculate this value
        if(t < 0 || t > 1)
        {
            auto d0 = circle_pos - p0;
            auto d1 = circle_pos - p1;
            return (length(d0) <= radius) || (length(d1) <= radius);
        }

        vec2 proj_vect = proj_length * normalize(b);
        vec2 dist_vect = a - proj_vect;
        float dist = length(dist_vect);

        return dist <= radius;
    }

    bool circle_intersects_bezier(glm::vec2 circle_pos, float radius, glm::vec2 p0, glm::vec2 p1, glm::vec2 p2, glm::vec2 p3)
    {
        EXPLODE("todo");
        return false;
    }

    void spline_selection_t::select_spline(spline_t& spline)
    {
        std::vector<size_t> new_inds;
        new_inds.reserve(spline.size());
        for(size_t i = 0; i < spline.size(); ++i)
        {
            new_inds.push_back(i);
        }

        select_spline_nodes(spline, std::move(new_inds));
    }

    void spline_selection_t::select_spline_nodes(spline_t& spline, std::vector<size_t> node_inds)
    {
        if(is_control_node)
        {
            deselect_all();
            is_control_node = false;
        }

        splines.push_back(&spline);
        node_indices.push_back(std::move(node_inds));
    }

    void spline_selection_t::select_control_node(spline_t& spline, size_t control_node_index)
    {
        deselect_all();
        is_control_node = true;

        splines.push_back(&spline);

        node_indices.resize(1);
        node_indices[0].push_back(control_node_index);
    }

    void spline_selection_t::deselect_all()
    {
        splines.clear();
        node_indices.clear();
    }
}
}
}
<|endoftext|>


<commit_before>#include <catch.hpp>
#include <iostream>
#include "../cauldron/integers.h"
#include "predicates.h"
#include "operators.h"

template<typename T>
static void check_strategy() {
  static std::random_device random_device;

  auto distribution = std::uniform_int_distribution<T>();
  std::vector<T> borders{distribution(random_device),
                         distribution(random_device)};
  T min_value = *std::min_element(borders.begin(),
                                  borders.end());
  T max_value = *std::max_element(borders.begin(),
                                  borders.end());
  strategies::Integers<T> integers(min_value,
                                   max_value);

  SECTION("stays in range") {
    T integer = integers();
    auto stays_in_range = in_range_checker<T>(min_value,
                                              max_value);

    REQUIRE(stays_in_range(integer));
  }

  SECTION("filtration") {
    SECTION("parity") {
      auto even_integers = integers.filter(even<T>);
      auto odd_integers = integers.filter(odd<T>);

      auto even_integer = (*even_integers)();
      auto odd_integer = (*odd_integers)();

      REQUIRE(even(even_integer));
      REQUIRE(odd(odd_integer));
    }

    SECTION("impossible") {
      auto invalid_integers = integers.filter(even<T>)->filter(odd<T>);

      REQUIRE_THROWS_AS((*invalid_integers)(),
                        strategies::OutOfCycles);
    }
  }

  SECTION("mapping") {
    SECTION("parity") {
      auto even_integers = integers.map(to_even<T>);
      auto odd_integers = integers.map(to_odd<T>);

      auto even_integer = (*even_integers)();
      auto odd_integer = (*odd_integers)();

      REQUIRE(even(even_integer));
      REQUIRE(odd(odd_integer));
    }

    SECTION("impossible") {
      auto invalid_even_integers = integers.map(to_odd<T>)->filter(even<T>);
      auto invalid_odd_integers = integers.map(to_even<T>)->filter(odd<T>);

      REQUIRE_THROWS_AS((*invalid_odd_integers)(),
                        strategies::OutOfCycles);
      REQUIRE_THROWS_AS((*invalid_even_integers)(),
                        strategies::OutOfCycles);
    }
  }
}

TEST_CASE("\"integers\" strategy", "[integers]") {
  SECTION("unsigned char") {
    check_strategy<unsigned char>();
  }

  SECTION("signed char") {
    check_strategy<signed char>();
  }

  SECTION("short int") {
    check_strategy<short>();
  }

  SECTION("unsigned short int") {
    check_strategy<unsigned short>();
  }

  SECTION("int") {
    check_strategy<int>();
  }

  SECTION("unsigned int") {
    check_strategy<unsigned>();
  }

  SECTION("long int") {
    check_strategy<long>();
  }

  SECTION("unsigned long int") {
    check_strategy<unsigned long>();
  }

  SECTION("long long int") {
    check_strategy<long long>();
  }

  SECTION("unsigned long long int") {
    check_strategy<unsigned long long>();
  }
}
<commit_msg>Renaming: 'integer(s)' -> 'number(s)'<commit_after>#include <catch.hpp>
#include <iostream>
#include "../cauldron/integers.h"
#include "predicates.h"
#include "operators.h"

template<typename T>
static void check_strategy() {
  static std::random_device random_device;

  auto distribution = std::uniform_int_distribution<T>();
  std::vector<T> borders{distribution(random_device),
                         distribution(random_device)};
  T min_value = *std::min_element(borders.begin(),
                                  borders.end());
  T max_value = *std::max_element(borders.begin(),
                                  borders.end());
  strategies::Integers<T> numbers(min_value,
                                  max_value);

  SECTION("stays in range") {
    T number = numbers();
    auto stays_in_range = in_range_checker<T>(min_value,
                                              max_value);

    REQUIRE(stays_in_range(number));
  }

  SECTION("filtration") {
    SECTION("parity") {
      auto even_numbers = numbers.filter(even<T>);
      auto odd_numbers = numbers.filter(odd<T>);

      auto even_number = (*even_numbers)();
      auto odd_number = (*odd_numbers)();

      REQUIRE(even(even_number));
      REQUIRE(odd(odd_number));
    }

    SECTION("impossible") {
      auto invalid_numbers = numbers.filter(even<T>)->filter(odd<T>);

      REQUIRE_THROWS_AS((*invalid_numbers)(),
                        strategies::OutOfCycles);
    }
  }

  SECTION("mapping") {
    SECTION("parity") {
      auto even_numbers = numbers.map(to_even<T>);
      auto odd_numbers = numbers.map(to_odd<T>);

      auto even_number = (*even_numbers)();
      auto odd_number = (*odd_numbers)();

      REQUIRE(even(even_number));
      REQUIRE(odd(odd_number));
    }

    SECTION("impossible") {
      auto invalid_even_numbers = numbers.map(to_odd<T>)->filter(even<T>);
      auto invalid_odd_numbers = numbers.map(to_even<T>)->filter(odd<T>);

      REQUIRE_THROWS_AS((*invalid_odd_numbers)(),
                        strategies::OutOfCycles);
      REQUIRE_THROWS_AS((*invalid_even_numbers)(),
                        strategies::OutOfCycles);
    }
  }
}

TEST_CASE("\"Integers\" strategy", "[Integers]") {
  SECTION("unsigned char") {
    check_strategy<unsigned char>();
  }

  SECTION("signed char") {
    check_strategy<signed char>();
  }

  SECTION("short int") {
    check_strategy<short>();
  }

  SECTION("unsigned short int") {
    check_strategy<unsigned short>();
  }

  SECTION("int") {
    check_strategy<int>();
  }

  SECTION("unsigned int") {
    check_strategy<unsigned>();
  }

  SECTION("long int") {
    check_strategy<long>();
  }

  SECTION("unsigned long int") {
    check_strategy<unsigned long>();
  }

  SECTION("long long int") {
    check_strategy<long long>();
  }

  SECTION("unsigned long long int") {
    check_strategy<unsigned long long>();
  }
}
<|endoftext|>


<commit_before>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

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

/* rbOOmit is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

//
Reduced Basis: Example 6 - Heat transfer on a curved domain in 3D

// In this example we consider heat transfer modeled by a Poisson equation with
// Robin boundary condition:
//  -kappa \Laplacian u = 1, on \Omega
//  -kappa du\dn = kappa Bi u, on \partial\Omega_Biot,
//  u = 0 on \partial\Omega_Dirichlet,
//
// We consider a reference domain \Omega_hat = [0,0.4]x[0,0.4]x[0,3], and the
// physical domain is then obtain via the parametrized mapping:
//  x = -1/mu + (1/mu+x_hat)*cos(mu*z_hat)
//  y = y_hat
//  z = (1/mu+x_hat)*sin(mu*z_hat)
// for (x_hat,y_hat,z_hat) \in \Omega_hat. (Here "hats" denotes reference domain.)
// Also, the "reference Dirichlet boundaries" are [0,0.4]x[0,0.4]x{0} and
// [0,0.4]x[0,0.4]x{3}, and the remaining boundaries are the "Biot" boundaries.

// Then, after putting the PDE into weak form and mapping it to the reference domain,
// we obtain:
//  \kappa \int_\Omega_hat [ (1+mu*x_hat) v_x w_x + v_y w_y + 1/(1+mu*x_hat) v_z w_z ]
//    + \kappa Bi \int_\partial\Omega_hat_Biot1 u v
//    + \kappa Bi \int_\partial\Omega_hat_Biot2 (1+mu x_hat) u v
//    + \kappa Bi \int_\partial\Omega_hat_Biot3 (1+0.4mu) u v
//    = \int_\Omega_hat (1+mu x_hat) v
// where
//  \partial\Omega_hat_Biot1 = [0] x [0,0.4] x [0,3]
//  \partial\Omega_hat_Biot2 = [0,0.4] x {0} x [0,3] \UNION [0,0.4] x {0.4} x [0,3]
//  \partial\Omega_hat_Biot3 = [0.4] x [0,0.4] x [0,3]

// The term
//  \kappa \int_\Omega_hat 1/(1+mu*x_hat) v_z w_z
// is "non-affine" (in the Reduced Basis sense), since we can't express it
// in the form \sum theta_q(kappa,mu) a(v,w). As a result, (as in
// reduced_basis_ex4) we must employ the Empirical Interpolation Method (EIM)
// in order to apply the Reduced Basis method here.

// The approach we use is to construct an EIM approximation, G_EIM, to the vector-valued function
//  G(x_hat,y_hat;mu) = (1 + mu*x_hat, 1, 1/(1+mu*x_hat))
// and then we express the "volumetric integral part" of the left-hand side operator as
//  a(v,w;mu) = \int_\hat\Omega G_EIM(x_hat,y_hat;mu) \dot (v_x w_x, v_y w_y, v_z w_z).
// (We actually only need EIM for the third component of G_EIM, but it's helpful to
// demonstrate "vector-valued" EIM here.)

// C++ include files that we need
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>

// Basic include file needed for the mesh functionality.
#include "libmesh.h"
#include "mesh.h"
#include "mesh_generation.h"
#include "exodusII_io.h"
#include "equation_systems.h"
#include "dof_map.h"
#include "getpot.h"
#include "elem.h"

// local includes
#include "rb_classes.h"
#include "eim_classes.h"
#include "assembly.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// Define a function to scale the mesh according to the parameter.
void transform_mesh_and_plot(EquationSystems& es, Real curvature, const std::string& filename);

// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_assert(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_assert(false, "--disable-singleprecision");
#endif
  // FIXME: This example currently segfaults with Trilinos?
  libmesh_example_assert(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc");

  // This is a 3D example
  libmesh_example_assert(3 == LIBMESH_DIM, "3D support");

  // Parse the input file using GetPot
  std::string eim_parameters = "eim.in";
  std::string rb_parameters  = "rb.in";
  std::string main_parameters = "reduced_basis_ex6.in";
  GetPot infile(main_parameters);

  unsigned int n_elem_xy = infile("n_elem_xy", 1);
  unsigned int n_elem_z  = infile("n_elem_z", 1);

  // Do we write the RB basis functions to disk?
  bool store_basis_functions = infile("store_basis_functions", true);

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Build a mesh.
  Mesh mesh;
  MeshTools::Generation::build_cube (mesh,
                                     n_elem_xy, n_elem_xy, n_elem_z,
                                     0., 0.4,
                                     0., 0.4,
                                     0., 3.,
                                     HEX8);

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);

  SimpleEIMConstruction & eim_construction =
    equation_systems.add_system<SimpleEIMConstruction> ("EIM");
  SimpleRBConstruction & rb_construction =
    equation_systems.add_system<SimpleRBConstruction> ("RB");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  equation_systems.print_info();
  mesh.print_info();

  // Initialize the standard RBEvaluation object
  SimpleRBEvaluation rb_eval;

  // Initialize the EIM RBEvaluation object
  SimpleEIMEvaluation eim_rb_eval;

  // Set the rb_eval objects for the RBConstructions
  eim_construction.set_rb_evaluation(eim_rb_eval);
  rb_construction.set_rb_evaluation(rb_eval);

  if(!online_mode) // Perform the Offline stage of the RB method
  {
    // Read data from input file and print state
    eim_construction.process_parameters_file(eim_parameters);
    eim_construction.print_info();

    // Perform the EIM Greedy and write out the data
    eim_construction.initialize_rb_construction();

    eim_construction.train_reduced_basis();
    eim_construction.get_rb_evaluation().write_offline_data_to_files("eim_data");

    // Read data from input file and print state
    rb_construction.process_parameters_file(rb_parameters);

    // attach the EIM theta objects to the RBConstruction and RBEvaluation objects
    eim_rb_eval.initialize_eim_theta_objects();
    rb_eval.get_rb_theta_expansion().attach_multiple_A_theta(eim_rb_eval.get_eim_theta_objects());

    // attach the EIM assembly objects to the RBConstruction object
    eim_construction.initialize_eim_assembly_objects();
    rb_construction.get_rb_assembly_expansion().attach_multiple_A_assembly(eim_construction.get_eim_assembly_objects());

    // Print out the state of rb_construction now that the EIM objects have been attached
    rb_construction.print_info();

    // Need to initialize _after_ EIM greedy so that
    // the system knows how many affine terms there are
    rb_construction.initialize_rb_construction();
    rb_construction.train_reduced_basis();
    rb_construction.get_rb_evaluation().write_offline_data_to_files("rb_data");

    // Write out the basis functions, if requested
    if(store_basis_functions)
    {
      // Write out the basis functions
      eim_construction.get_rb_evaluation().write_out_basis_functions(eim_construction,"eim_data");
      rb_construction.get_rb_evaluation().write_out_basis_functions(rb_construction,"rb_data");
    }
  }
  else // Perform the Online stage of the RB method
  {
    eim_rb_eval.read_offline_data_from_files("eim_data");

    // attach the EIM theta objects to rb_eval objects
    eim_rb_eval.initialize_eim_theta_objects();
    rb_eval.get_rb_theta_expansion().attach_multiple_A_theta(eim_rb_eval.get_eim_theta_objects());

    // Read in the offline data for rb_eval
    rb_eval.read_offline_data_from_files("rb_data");

    // Get the parameters at which we will do a reduced basis solve
    Real online_curvature = infile("online_curvature", 0.);
    Real online_Bi        = infile("online_Bi", 0.);
    Real online_kappa     = infile("online_kappa", 0.);
    RBParameters online_mu;
    online_mu.set_value("curvature", online_curvature);
    online_mu.set_value("Bi", online_Bi);
    online_mu.set_value("kappa", online_kappa);
    rb_eval.set_parameters(online_mu);
    rb_eval.print_parameters();
    rb_eval.rb_solve( rb_eval.get_n_basis_functions() );

    // plot the solution, if requested
    if(store_basis_functions)
    {
      // read in the data from files
      eim_rb_eval.read_in_basis_functions(eim_construction,"eim_data");
      rb_eval.read_in_basis_functions(rb_construction,"rb_data");

      eim_construction.load_rb_solution();
      rb_construction.load_rb_solution();

      transform_mesh_and_plot(equation_systems,online_curvature,"RB_sol.e");
    }
  }

  return 0;
}

void transform_mesh_and_plot(EquationSystems& es, Real curvature, const std::string& filename)
{
  // Loop over the mesh nodes and move them!
  MeshBase& mesh = es.get_mesh();

  MeshBase::node_iterator       node_it  = mesh.nodes_begin();
  const MeshBase::node_iterator node_end = mesh.nodes_end();

  for( ; node_it != node_end; node_it++)
  {
    Node* node = *node_it;

    Real x = (*node)(0);
    Real z = (*node)(2);

    (*node)(0) = -1./curvature + (1./curvature + x)*cos(curvature*z);
    (*node)(2) = (1./curvature + x)*sin(curvature*z);
  }

#ifdef LIBMESH_HAVE_EXODUS_API
  ExodusII_IO(mesh).write_equation_systems(filename, es);
#endif
}

<commit_msg>fixed comments in reduced_basis_ex6<commit_after>/* rbOOmit: An implementation of the Certified Reduced Basis method. */
/* Copyright (C) 2009, 2010 David J. Knezevic */
/*     This file is part of rbOOmit. */

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

/* rbOOmit is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

//
Reduced Basis: Example 6 - Heat transfer on a curved domain in 3D

// In this example we consider heat transfer modeled by a Poisson equation with
// Robin boundary condition:
//  -kappa \Laplacian u = 1, on \Omega
//  -kappa du\dn = kappa Bi u, on \partial\Omega_Biot,
//  u = 0 on \partial\Omega_Dirichlet,
//
// We consider a reference domain \Omega_hat = [0,0.4]x[0,0.4]x[0,3], and the
// physical domain is then obtain via the parametrized mapping:
//  x = -1/mu + (1/mu+x_hat)*cos(mu*z_hat)
//  y = y_hat
//  z = (1/mu+x_hat)*sin(mu*z_hat)
// for (x_hat,y_hat,z_hat) \in \Omega_hat. (Here "hats" denotes reference domain.)
// Also, the "reference Dirichlet boundaries" are [0,0.4]x[0,0.4]x{0} and
// [0,0.4]x[0,0.4]x{3}, and the remaining boundaries are the "Biot" boundaries.

// Then, after putting the PDE into weak form and mapping it to the reference domain,
// we obtain:
//  \kappa \int_\Omega_hat [ (1+mu*x_hat) v_x w_x + v_y w_y + 1/(1+mu*x_hat) v_z w_z ]
//    + \kappa Bi \int_\partial\Omega_hat_Biot1 u v
//    + \kappa Bi \int_\partial\Omega_hat_Biot2 (1+mu x_hat) u v
//    + \kappa Bi \int_\partial\Omega_hat_Biot3 (1+0.4mu) u v
//    = \int_\Omega_hat (1+mu x_hat) v
// where
//  \partial\Omega_hat_Biot1 = [0] x [0,0.4] x [0,3]
//  \partial\Omega_hat_Biot2 = [0,0.4] x {0} x [0,3] \UNION [0,0.4] x {0.4} x [0,3]
//  \partial\Omega_hat_Biot3 = [0.4] x [0,0.4] x [0,3]

// The term
//  \kappa \int_\Omega_hat 1/(1+mu*x_hat) v_z w_z
// is "non-affine" (in the Reduced Basis sense), since we can't express it
// in the form \sum theta_q(kappa,mu) a(v,w). As a result, (as in
// reduced_basis_ex4) we must employ the Empirical Interpolation Method (EIM)
// in order to apply the Reduced Basis method here.

// The approach we use is to construct an EIM approximation, G_EIM, to the vector-valued function
//  G(x_hat,y_hat;mu) = (1 + mu*x_hat, 1, 1/(1+mu*x_hat))
// and then we express the "volumetric integral part" of the left-hand side operator as
//  a(v,w;mu) = \int_\hat\Omega G_EIM(x_hat,y_hat;mu) \dot (v_x w_x, v_y w_y, v_z w_z).
// (We actually only need EIM for the third component of G_EIM, but it's helpful to
// demonstrate "vector-valued" EIM here.)

// C++ include files that we need
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>

// Basic include file needed for the mesh functionality.
#include "libmesh.h"
#include "mesh.h"
#include "mesh_generation.h"
#include "exodusII_io.h"
#include "equation_systems.h"
#include "dof_map.h"
#include "getpot.h"
#include "elem.h"

// local includes
#include "rb_classes.h"
#include "eim_classes.h"
#include "assembly.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

// Define a function to scale the mesh according to the parameter.
void transform_mesh_and_plot(EquationSystems& es, Real curvature, const std::string& filename);

// The main program.
int main (int argc, char** argv)
{
  // Initialize libMesh.
  LibMeshInit init (argc, argv);

#if !defined(LIBMESH_HAVE_XDR)
  // We need XDR support to write out reduced bases
  libmesh_example_assert(false, "--enable-xdr");
#elif defined(LIBMESH_DEFAULT_SINGLE_PRECISION)
  // XDR binary support requires double precision
  libmesh_example_assert(false, "--disable-singleprecision");
#endif
  // FIXME: This example currently segfaults with Trilinos?
  libmesh_example_assert(libMesh::default_solver_package() == PETSC_SOLVERS, "--enable-petsc");

  // This is a 3D example
  libmesh_example_assert(3 == LIBMESH_DIM, "3D support");

  // Parse the input file using GetPot
  std::string eim_parameters = "eim.in";
  std::string rb_parameters  = "rb.in";
  std::string main_parameters = "reduced_basis_ex6.in";
  GetPot infile(main_parameters);

  unsigned int n_elem_xy = infile("n_elem_xy", 1);
  unsigned int n_elem_z  = infile("n_elem_z", 1);

  // Do we write the RB basis functions to disk?
  bool store_basis_functions = infile("store_basis_functions", true);

  // Read the "online_mode" flag from the command line
  GetPot command_line (argc, argv);
  int online_mode = 0;
  if ( command_line.search(1, "-online_mode") )
    online_mode = command_line.next(online_mode);

  // Build a mesh.
  Mesh mesh;
  MeshTools::Generation::build_cube (mesh,
                                     n_elem_xy, n_elem_xy, n_elem_z,
                                     0., 0.4,
                                     0., 0.4,
                                     0., 3.,
                                     HEX8);

  // Create an equation systems object.
  EquationSystems equation_systems (mesh);

  SimpleEIMConstruction & eim_construction =
    equation_systems.add_system<SimpleEIMConstruction> ("EIM");
  SimpleRBConstruction & rb_construction =
    equation_systems.add_system<SimpleRBConstruction> ("RB");

  // Initialize the data structures for the equation system.
  equation_systems.init ();

  // Print out some information about the "truth" discretization
  equation_systems.print_info();
  mesh.print_info();

  // Initialize the standard RBEvaluation object
  SimpleRBEvaluation rb_eval;

  // Initialize the EIM RBEvaluation object
  SimpleEIMEvaluation eim_rb_eval;

  // Set the rb_eval objects for the RBConstructions
  eim_construction.set_rb_evaluation(eim_rb_eval);
  rb_construction.set_rb_evaluation(rb_eval);

  if(!online_mode) // Perform the Offline stage of the RB method
  {
    // Read data from input file and print state
    eim_construction.process_parameters_file(eim_parameters);
    eim_construction.print_info();

    // Perform the EIM Greedy and write out the data
    eim_construction.initialize_rb_construction();

    eim_construction.train_reduced_basis();
    eim_construction.get_rb_evaluation().write_offline_data_to_files("eim_data");

    // Read data from input file and print state
    rb_construction.process_parameters_file(rb_parameters);

    // attach the EIM theta objects to the RBEvaluation
    eim_rb_eval.initialize_eim_theta_objects();
    rb_eval.get_rb_theta_expansion().attach_multiple_A_theta(eim_rb_eval.get_eim_theta_objects());

    // attach the EIM assembly objects to the RBConstruction
    eim_construction.initialize_eim_assembly_objects();
    rb_construction.get_rb_assembly_expansion().attach_multiple_A_assembly(eim_construction.get_eim_assembly_objects());

    // Print out the state of rb_construction now that the EIM objects have been attached
    rb_construction.print_info();

    // Need to initialize _after_ EIM greedy so that
    // the system knows how many affine terms there are
    rb_construction.initialize_rb_construction();
    rb_construction.train_reduced_basis();
    rb_construction.get_rb_evaluation().write_offline_data_to_files("rb_data");

    // Write out the basis functions, if requested
    if(store_basis_functions)
    {
      // Write out the basis functions
      eim_construction.get_rb_evaluation().write_out_basis_functions(eim_construction,"eim_data");
      rb_construction.get_rb_evaluation().write_out_basis_functions(rb_construction,"rb_data");
    }
  }
  else // Perform the Online stage of the RB method
  {
    eim_rb_eval.read_offline_data_from_files("eim_data");

    // attach the EIM theta objects to rb_eval objects
    eim_rb_eval.initialize_eim_theta_objects();
    rb_eval.get_rb_theta_expansion().attach_multiple_A_theta(eim_rb_eval.get_eim_theta_objects());

    // Read in the offline data for rb_eval
    rb_eval.read_offline_data_from_files("rb_data");

    // Get the parameters at which we will do a reduced basis solve
    Real online_curvature = infile("online_curvature", 0.);
    Real online_Bi        = infile("online_Bi", 0.);
    Real online_kappa     = infile("online_kappa", 0.);
    RBParameters online_mu;
    online_mu.set_value("curvature", online_curvature);
    online_mu.set_value("Bi", online_Bi);
    online_mu.set_value("kappa", online_kappa);
    rb_eval.set_parameters(online_mu);
    rb_eval.print_parameters();
    rb_eval.rb_solve( rb_eval.get_n_basis_functions() );

    // plot the solution, if requested
    if(store_basis_functions)
    {
      // read in the data from files
      eim_rb_eval.read_in_basis_functions(eim_construction,"eim_data");
      rb_eval.read_in_basis_functions(rb_construction,"rb_data");

      eim_construction.load_rb_solution();
      rb_construction.load_rb_solution();

      transform_mesh_and_plot(equation_systems,online_curvature,"RB_sol.e");
    }
  }

  return 0;
}

void transform_mesh_and_plot(EquationSystems& es, Real curvature, const std::string& filename)
{
  // Loop over the mesh nodes and move them!
  MeshBase& mesh = es.get_mesh();

  MeshBase::node_iterator       node_it  = mesh.nodes_begin();
  const MeshBase::node_iterator node_end = mesh.nodes_end();

  for( ; node_it != node_end; node_it++)
  {
    Node* node = *node_it;

    Real x = (*node)(0);
    Real z = (*node)(2);

    (*node)(0) = -1./curvature + (1./curvature + x)*cos(curvature*z);
    (*node)(2) = (1./curvature + x)*sin(curvature*z);
  }

#ifdef LIBMESH_HAVE_EXODUS_API
  ExodusII_IO(mesh).write_equation_systems(filename, es);
#endif
}

<|endoftext|>


<commit_before>// Copyright 2011 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "web_wav_sound_resource.h"
#include "web_resource_loader_inl.h"

#include <ppapi/cpp/instance.h>
#include <ppapi/cpp/url_response_info.h>
#include <ppapi/cpp/var.h>

#include <algorithm>
#include <string.h>

namespace {
// Wav record descriptor per
// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
#pragma pack(push, 1)
struct WavRecord {
  // Header.
  char header_id[4];  // Should be "RIFF"
  int32_t record_size;  // Should be size of data minus 8
  char format[4];  // Should be "WAVE"
  // Subchunk 1, i.e. format descriptor.
  char format_chunk_id[4];  // Should be "fmt ".
  int32_t format_chunk_size;  // Should be 16.
  int16_t audio_format;  // Should be 1 for uncompressed audio.
  int16_t num_channels;  // 1 for mono, 2 for stereo.
  int32_t sample_rate;
  int32_t byte_rate;
  int16_t block_align;
  int16_t bits_per_sample;
  // Data chunk.
  char data_id[4];  // Should be "data"
  int32_t audio_chunk_size;  // Size of sample data that follows.
  char audio_data;  // The first byte of actual sound data;
};
#pragma pack(pop)

// Parse the headers in the url response and return the length of the
// resource content ion bytes. Returns 0 in case of error.
// TODO(gwink): Define a wrapper class around URLResponseInfo and parse
// the headers into a map that can be conveniently queried.
int GetContentLength(const pp::URLResponseInfo response) {
  pp::Var header_var = response.GetHeaders();
  if (!header_var.is_string()) {
    return 0;
  }

  static const std::string kContentLengthKey("Content-Length: ");
  std::string headers = header_var.AsString();
  size_t i = headers.find(kContentLengthKey);
  if (i == headers.npos) {
    return 0;
  }

  return atoi(headers.substr(i + kContentLengthKey.length()).c_str());
}

// Verify that the wav data in the buffer is valid and playable with
// the pepper audio interface.
bool VerifyWavData(const char* data, size_t data_size) {
  // Do we have enough data.
  printf("Wav data size: %i\n", (int)data_size);
  if (data_size < sizeof(WavRecord)) {
    return false;
  }

  const WavRecord* wav = reinterpret_cast<const WavRecord*>(data);
  // Check various chunk formats.
  printf("Wav header id: |%4.4s|\n", wav->header_id);
  printf("Wav audio format id: |%4.4s|\n", wav->format);
  printf("Wav format header id: |%4.4s|\n", wav->format_chunk_id);
  printf("Wav data header id: |%4.4s|\n", wav->data_id);
  if (::strncmp(wav->header_id, "RIFF", 4) != 0 ||
      ::strncmp(wav->format, "WAVE", 4) != 0 ||
      ::strncmp(wav->format_chunk_id, "fmt ", 4) != 0 ||
      ::strncmp(wav->data_id, "data", 4) != 0) {
    printf("   ** bad format id.\n");
    return false;
  }
  // Check that we support the audio format.
  printf("Wav sample rate: %i\n", (int)wav->sample_rate);
  if (wav->sample_rate != 44100 && wav->sample_rate != 48000) {
    printf("   ** bad sample rate.\n");
    return false;
  }
  printf("Wav num channels: %i\n", wav->num_channels);
  printf("Wav bits per sample: %i\n", wav->bits_per_sample);
  if (wav->num_channels != 2 || wav->bits_per_sample != 16) {
    printf("   ** not stereo or not 16-bit.\n");
    return false;
  }
  // Finally, check that the actual data size and wav sample data size match.
  printf("Wav audio size: actual = %i, expected = %i\n",
         (int)wav->audio_chunk_size,
         static_cast<int>(data_size - sizeof(WavRecord) + 1));
  return (wav->audio_chunk_size ==
          static_cast<int32_t>(data_size - sizeof(WavRecord) + 1));
}

}  // anonymous namespace

namespace life {

WebWavSoundResource::WebWavSoundResource()
  : is_ready_(false),
    wav_data_size_(0),
    received_data_size_(0),
    loader_(NULL) {
}

WebWavSoundResource::~WebWavSoundResource() {
  Clear();
}

void WebWavSoundResource::Init(const std::string& url, pp::Instance* instance) {
  assert(wav_data_.empty());  // Can only init once.
  if (wav_data_.empty()) {
    loader_ = new Loader(instance, this);
    loader_->LoadURL(url);
  }
}

int32_t WebWavSoundResource::GetSampleRate() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return wav->sample_rate;
}

const char* WebWavSoundResource::GetAudioData() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return &(wav->audio_data);
}

size_t WebWavSoundResource::GetAudioDataSize() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return wav->audio_chunk_size;
}

bool WebWavSoundResource::OnWebResourceLoaderCallback(
    Loader::DispatchOpCode op_code, Loader* loader) {
  switch(op_code) {
    case Loader::kUrlResponseInfoReady: {
      int content_length = GetContentLength(loader->GetResponseInfo());
      if (content_length <= 0) {
        // Either the download failed, or the sound data is bad. Abort.
        Clear();
        return false;
      } else {
        // Create a local buffer big enough to receive the sound data.
        wav_data_.reserve(content_length);
        wav_data_size_ = content_length;
        received_data_size_ = 0;
        return true;
      }
      break;
    }
    case Loader::kDataReceived: {
      if (received_data_size_ + loader->data_size() > wav_data_size_) {
        // Size of sound data exceeds expected size. Abort.
        return false;
      } else {
        // Append chunk of data to local sound buffer.
        ::memcpy(&wav_data_[0] + received_data_size_,
                 loader->buffer(), loader->data_size());
        received_data_size_ += loader->data_size();
        return true;
      }
      break;
    }
    case Loader::kDownloadComplete: {
      is_ready_ = VerifyWavData(&wav_data_[0], wav_data_size_);
      if (!is_ready_) {
        Clear();
      }
      return true;
      break;
    }
  }
  return false;
}

void WebWavSoundResource::OnWebResourceLoaderError(int32_t error,
                                                   Loader* loader) {
}

void WebWavSoundResource::OnWebResourceLoaderDone(Loader* loader) {
  loader_->CloseAndDeleteSelf();
  loader_ = NULL;
}

void WebWavSoundResource::Clear() {
  is_ready_ = false;
  wav_data_.clear();
  wav_data_size_ = 0;
  received_data_size_ = 0;
  loader_->CloseAndDeleteSelf();
  loader_ = NULL;
}

}  // namespace life
<commit_msg>Adding class WebWavSoundResource, downloads and decode wav audio data from a URL. Implements the  WebResourceLoader::Delegate methods to plug into that class.  Review URL: http://codereview.chromium.org/6801054<commit_after>// Copyright 2011 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "web_wav_sound_resource.h"
#include "web_resource_loader_inl.h"

#include <ppapi/cpp/instance.h>
#include <ppapi/cpp/url_response_info.h>
#include <ppapi/cpp/var.h>

#include <algorithm>
#include <string.h>

namespace {
// Wav record descriptor per
// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/
#pragma pack(push, 1)
struct WavRecord {
  // Header.
  char header_id[4];  // Should be "RIFF"
  int32_t record_size;  // Should be size of data minus 8
  char format[4];  // Should be "WAVE"
  // Subchunk 1, i.e. format descriptor.
  char format_chunk_id[4];  // Should be "fmt ".
  int32_t format_chunk_size;  // Should be 16.
  int16_t audio_format;  // Should be 1 for uncompressed audio.
  int16_t num_channels;  // 1 for mono, 2 for stereo.
  int32_t sample_rate;
  int32_t byte_rate;
  int16_t block_align;
  int16_t bits_per_sample;
  // Data chunk.
  char data_id[4];  // Should be "data"
  int32_t audio_chunk_size;  // Size of sample data that follows.
  char audio_data;  // The first byte of actual sound data;
};
#pragma pack(pop)

// Parse the headers in the url response and return the length of the
// resource content ion bytes. Returns 0 in case of error.
// TODO(gwink): Define a wrapper class around URLResponseInfo and parse
// the headers into a map that can be conveniently queried.
int GetContentLength(const pp::URLResponseInfo response) {
  pp::Var header_var = response.GetHeaders();
  if (!header_var.is_string()) {
    return 0;
  }

  static const std::string kContentLengthKey("Content-Length: ");
  std::string headers = header_var.AsString();
  size_t i = headers.find(kContentLengthKey);
  if (i == headers.npos) {
    return 0;
  }

  return atoi(headers.substr(i + kContentLengthKey.length()).c_str());
}

// Verify that the wav data in the buffer is valid and playable with
// the pepper audio interface.
bool VerifyWavData(const char* data, size_t data_size) {
  // Do we have enough data.
  printf("Wav data size: %i\n", (int)data_size);
  if (data_size < sizeof(WavRecord)) {
    return false;
  }

  const WavRecord* wav = reinterpret_cast<const WavRecord*>(data);
  // Check various chunk formats.
  printf("Wav header id: |%4.4s|\n", wav->header_id);
  printf("Wav audio format id: |%4.4s|\n", wav->format);
  printf("Wav format header id: |%4.4s|\n", wav->format_chunk_id);
  printf("Wav data header id: |%4.4s|\n", wav->data_id);
  if (::strncmp(wav->header_id, "RIFF", 4) != 0 ||
      ::strncmp(wav->format, "WAVE", 4) != 0 ||
      ::strncmp(wav->format_chunk_id, "fmt ", 4) != 0 ||
      ::strncmp(wav->data_id, "data", 4) != 0) {
    printf("   ** bad format id.\n");
    return false;
  }
  // Check that we support the audio format.
  printf("Wav sample rate: %i\n", (int)wav->sample_rate);
  if (wav->sample_rate != 44100 && wav->sample_rate != 48000) {
    printf("   ** bad sample rate.\n");
    return false;
  }
  printf("Wav num channels: %i\n", wav->num_channels);
  printf("Wav bits per sample: %i\n", wav->bits_per_sample);
  if (wav->num_channels != 2 || wav->bits_per_sample != 16) {
    printf("   ** not stereo or not 16-bit.\n");
    return false;
  }
  // Finally, check that the actual data size and wav sample data size match.
  printf("Wav audio size: actual = %i, expected = %i\n",
         (int)wav->audio_chunk_size,
         static_cast<int>(data_size - sizeof(WavRecord) + 1));
  return (wav->audio_chunk_size ==
          static_cast<int32_t>(data_size - sizeof(WavRecord) + 1));
}

}  // anonymous namespace

namespace life {

WebWavSoundResource::WebWavSoundResource()
  : is_ready_(false),
    wav_data_size_(0),
    received_data_size_(0),
    loader_(NULL) {
}

WebWavSoundResource::~WebWavSoundResource() {
  Clear();
}

void WebWavSoundResource::Init(const std::string& url, pp::Instance* instance) {
  assert(wav_data_.empty());  // Can only init once.
  if (wav_data_.empty()) {
    loader_ = new Loader(instance, this);
    loader_->LoadURL(url);
  }
}

int32_t WebWavSoundResource::GetSampleRate() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return wav->sample_rate;
}

const char* WebWavSoundResource::GetAudioData() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return &(wav->audio_data);
}

size_t WebWavSoundResource::GetAudioDataSize() const {
  assert(IsReady());
  const WavRecord* wav = reinterpret_cast<const WavRecord*>(&wav_data_[0]);
  return wav->audio_chunk_size;
}

bool WebWavSoundResource::OnWebResourceLoaderCallback(
    Loader::DispatchOpCode op_code, Loader* loader) {
  switch(op_code) {
    case Loader::kUrlResponseInfoReady: {
      int content_length = GetContentLength(loader->GetResponseInfo());
      if (content_length <= 0) {
        // Either the download failed, or the sound data is bad. Abort.
        Clear();
        return false;
      } else {
        // Create a local buffer big enough to receive the sound data.
        wav_data_.reserve(content_length);
        wav_data_size_ = content_length;
        received_data_size_ = 0;
        return true;
      }
      break;
    }
    case Loader::kDataReceived: {
      if (received_data_size_ + loader->data_size() > wav_data_size_) {
        // Size of sound data exceeds expected size. Abort.
        return false;
      } else {
        // Append chunk of data to local sound buffer.
        ::memcpy(&wav_data_[0] + received_data_size_,
                 loader->buffer(), loader->data_size());
        received_data_size_ += loader->data_size();
        return true;
      }
      break;
    }
    case Loader::kDownloadComplete: {
      is_ready_ = VerifyWavData(&wav_data_[0], wav_data_size_);
      if (!is_ready_) {
        Clear();
      }
      return true;
      break;
    }
  }
  return false;
}

void WebWavSoundResource::OnWebResourceLoaderError(int32_t error,
                                                   Loader* loader) {
}

void WebWavSoundResource::OnWebResourceLoaderDone(Loader* loader) {
  loader_->CloseAndDeleteSelf();
  loader_ = NULL;
}

void WebWavSoundResource::Clear() {
  is_ready_ = false;
  wav_data_.clear();
  wav_data_size_ = 0;
  received_data_size_ = 0;
  if (loader_) {
    loader_->CloseAndDeleteSelf();
    loader_ = NULL;
  }
}

}  // namespace life
<|endoftext|>


<commit_before>#include "CMT.h"

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

namespace cmt {

void CMT::initialize(const Mat im_gray, const Rect rect)
{
    FILE_LOG(logDEBUG) << "CMT::initialize() call";

    //Remember initial size
    size_initial = rect.size();

    //Remember initial image
    im_prev = im_gray;

    //Compute center of rect
    Point2f center = Point2f(rect.x + rect.width/2.0, rect.y + rect.height/2.0);

    //Initialize detector and descriptor
    detector = FeatureDetector::create(str_detector);
    descriptor = DescriptorExtractor::create(str_descriptor);

    //Get initial keypoints in whole image and compute their descriptors
    vector<KeyPoint> keypoints;
    detector->detect(im_gray, keypoints);

    //Divide keypoints into foreground and background keypoints according to selection
    vector<KeyPoint> keypoints_fg;
    vector<KeyPoint> keypoints_bg;

    for (size_t i = 0; i < keypoints.size(); i++)
    {
        KeyPoint k = keypoints[i];
        Point2f pt = k.pt;

        if (pt.x > rect.x && pt.y > rect.y && pt.x < rect.br().x && pt.y < rect.br().y)
        {
            keypoints_fg.push_back(k);
        }

        else
        {
            keypoints_bg.push_back(k);
        }

    }

    //Create foreground classes
    vector<int> classes_fg;
    classes_fg.reserve(keypoints_fg.size());
    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        classes_fg.push_back(i);
    }

    //Compute foreground/background features
    Mat descs_fg;
    Mat descs_bg;
    descriptor->compute(im_gray, keypoints_fg, descs_fg);
    descriptor->compute(im_gray, keypoints_bg, descs_bg);

    //Only now is the right time to convert keypoints to points, as compute() might remove some keypoints
    vector<Point2f> points_fg;
    vector<Point2f> points_bg;

    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        points_fg.push_back(keypoints_fg[i].pt);
    }

    for (size_t i = 0; i < keypoints_bg.size(); i++)
    {
        points_bg.push_back(keypoints_bg[i].pt);
    }

    //Create normalized points
    vector<Point2f> points_normalized;
    for (size_t i = 0; i < points_fg.size(); i++)
    {
        points_normalized.push_back(points_fg[i] - center);
    }

    //Initialize matcher
    matcher.initialize(points_normalized, descs_fg, classes_fg, descs_bg, center);

    //Initialize consensus
    consensus.initialize(points_normalized);

    //Create initial set of active keypoints
    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        points_active.push_back(keypoints_fg[i].pt);
        classes_active = classes_fg;
    }

    FILE_LOG(logDEBUG) << "CMT::initialize() return";
}

void CMT::processFrame(Mat im_gray) {

    FILE_LOG(logDEBUG) << "CMT::processFrame() call";

    //Track keypoints
    vector<Point2f> points_tracked;
    vector<unsigned char> status;
    tracker.track(im_prev, im_gray, points_active, points_tracked, status);

    FILE_LOG(logDEBUG) << points_tracked.size() << " tracked points.";

    //keep only successful classes
    vector<int> classes_tracked;
    for (size_t i = 0; i < classes_active.size(); i++)
    {
        if (status[i])
        {
            classes_tracked.push_back(classes_active[i]);
        }

    }

    //Detect keypoints, compute descriptors
    vector<KeyPoint> keypoints;
    detector->detect(im_gray, keypoints);

    FILE_LOG(logDEBUG) << keypoints.size() << " keypoints found.";

    Mat descriptors;
    descriptor->compute(im_gray, keypoints, descriptors);

    //Match keypoints globally
    vector<Point2f> points_matched_global;
    vector<int> classes_matched_global;
    matcher.matchGlobal(keypoints, descriptors, points_matched_global, classes_matched_global);

    FILE_LOG(logDEBUG) << points_matched_global.size() << " points matched globally.";

    //Fuse tracked and globally matched points
    vector<Point2f> points_fused;
    vector<int> classes_fused;
    fusion.preferFirst(points_tracked, classes_tracked, points_matched_global, classes_matched_global,
            points_fused, classes_fused);

    FILE_LOG(logDEBUG) << points_fused.size() << " points fused.";

    //Estimate scale and rotation from the fused points
    float scale;
    float rotation;
    consensus.estimateScaleRotation(points_fused, classes_fused, scale, rotation);

    FILE_LOG(logDEBUG) << "scale " << scale << ", " << "rotation " << rotation;

    //Find inliers and the center of their votes
    Point2f center;
    vector<Point2f> points_inlier;
    vector<int> classes_inlier;
    consensus.findConsensus(points_fused, classes_fused, scale, rotation,
            center, points_inlier, classes_inlier);

    FILE_LOG(logDEBUG) << points_inlier.size() << " inlier points.";

    //Match keypoints locally
    vector<Point2f> points_matched_local;
    vector<int> classes_matched_local;
    matcher.matchLocal(keypoints, descriptors, center, scale, rotation, points_matched_local, classes_matched_local);

    FILE_LOG(logDEBUG) << points_matched_local.size() << " points matched locally.";

    //Clear active points
    points_active.clear();
    classes_active.clear();

    //Fuse locally matched points and inliers
    fusion.preferFirst(points_matched_local, classes_matched_local, points_inlier, classes_inlier, points_active, classes_active);
//    points_active = points_fused;
//    classes_active = classes_fused;

    FILE_LOG(logDEBUG) << points_active.size() << " final fused points.";

    //TODO: Use theta to suppress result
    bb_rot = RotatedRect(center,  size_initial * scale, rotation/CV_PI * 180);

    //Remember current image
    im_prev = im_gray;

    FILE_LOG(logDEBUG) << "CMT::processFrame() return";
}

} /* namespace CMT */
<commit_msg>Added some debug logging<commit_after>#include "CMT.h"

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

namespace cmt {

void CMT::initialize(const Mat im_gray, const Rect rect)
{
    FILE_LOG(logDEBUG) << "CMT::initialize() call";

    //Remember initial size
    size_initial = rect.size();

    //Remember initial image
    im_prev = im_gray;

    //Compute center of rect
    Point2f center = Point2f(rect.x + rect.width/2.0, rect.y + rect.height/2.0);

    //Initialize detector and descriptor
    detector = FeatureDetector::create(str_detector);
    descriptor = DescriptorExtractor::create(str_descriptor);

    //Get initial keypoints in whole image and compute their descriptors
    vector<KeyPoint> keypoints;
    detector->detect(im_gray, keypoints);

    //Divide keypoints into foreground and background keypoints according to selection
    vector<KeyPoint> keypoints_fg;
    vector<KeyPoint> keypoints_bg;

    for (size_t i = 0; i < keypoints.size(); i++)
    {
        KeyPoint k = keypoints[i];
        Point2f pt = k.pt;

        if (pt.x > rect.x && pt.y > rect.y && pt.x < rect.br().x && pt.y < rect.br().y)
        {
            keypoints_fg.push_back(k);
        }

        else
        {
            keypoints_bg.push_back(k);
        }

    }

    //Create foreground classes
    vector<int> classes_fg;
    classes_fg.reserve(keypoints_fg.size());
    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        classes_fg.push_back(i);
    }

    //Compute foreground/background features
    Mat descs_fg;
    Mat descs_bg;
    descriptor->compute(im_gray, keypoints_fg, descs_fg);
    descriptor->compute(im_gray, keypoints_bg, descs_bg);

    //Only now is the right time to convert keypoints to points, as compute() might remove some keypoints
    vector<Point2f> points_fg;
    vector<Point2f> points_bg;

    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        points_fg.push_back(keypoints_fg[i].pt);
    }

    FILE_LOG(logDEBUG) << points_fg.size() << " foreground points.";

    for (size_t i = 0; i < keypoints_bg.size(); i++)
    {
        points_bg.push_back(keypoints_bg[i].pt);
    }

    //Create normalized points
    vector<Point2f> points_normalized;
    for (size_t i = 0; i < points_fg.size(); i++)
    {
        points_normalized.push_back(points_fg[i] - center);
    }

    //Initialize matcher
    matcher.initialize(points_normalized, descs_fg, classes_fg, descs_bg, center);

    //Initialize consensus
    consensus.initialize(points_normalized);

    //Create initial set of active keypoints
    for (size_t i = 0; i < keypoints_fg.size(); i++)
    {
        points_active.push_back(keypoints_fg[i].pt);
        classes_active = classes_fg;
    }

    FILE_LOG(logDEBUG) << "CMT::initialize() return";
}

void CMT::processFrame(Mat im_gray) {

    FILE_LOG(logDEBUG) << "CMT::processFrame() call";

    //Track keypoints
    vector<Point2f> points_tracked;
    vector<unsigned char> status;
    tracker.track(im_prev, im_gray, points_active, points_tracked, status);

    FILE_LOG(logDEBUG) << points_tracked.size() << " tracked points.";

    //keep only successful classes
    vector<int> classes_tracked;
    for (size_t i = 0; i < classes_active.size(); i++)
    {
        if (status[i])
        {
            classes_tracked.push_back(classes_active[i]);
        }

    }

    //Detect keypoints, compute descriptors
    vector<KeyPoint> keypoints;
    detector->detect(im_gray, keypoints);

    FILE_LOG(logDEBUG) << keypoints.size() << " keypoints found.";

    Mat descriptors;
    descriptor->compute(im_gray, keypoints, descriptors);

    //Match keypoints globally
    vector<Point2f> points_matched_global;
    vector<int> classes_matched_global;
    matcher.matchGlobal(keypoints, descriptors, points_matched_global, classes_matched_global);

    FILE_LOG(logDEBUG) << points_matched_global.size() << " points matched globally.";

    //Fuse tracked and globally matched points
    vector<Point2f> points_fused;
    vector<int> classes_fused;
    fusion.preferFirst(points_tracked, classes_tracked, points_matched_global, classes_matched_global,
            points_fused, classes_fused);

    FILE_LOG(logDEBUG) << points_fused.size() << " points fused.";

    //Estimate scale and rotation from the fused points
    float scale;
    float rotation;
    consensus.estimateScaleRotation(points_fused, classes_fused, scale, rotation);

    FILE_LOG(logDEBUG) << "scale " << scale << ", " << "rotation " << rotation;

    //Find inliers and the center of their votes
    Point2f center;
    vector<Point2f> points_inlier;
    vector<int> classes_inlier;
    consensus.findConsensus(points_fused, classes_fused, scale, rotation,
            center, points_inlier, classes_inlier);

    FILE_LOG(logDEBUG) << points_inlier.size() << " inlier points.";
    FILE_LOG(logDEBUG) << "center " << center;

    //Match keypoints locally
    vector<Point2f> points_matched_local;
    vector<int> classes_matched_local;
    matcher.matchLocal(keypoints, descriptors, center, scale, rotation, points_matched_local, classes_matched_local);

    FILE_LOG(logDEBUG) << points_matched_local.size() << " points matched locally.";

    //Clear active points
    points_active.clear();
    classes_active.clear();

    //Fuse locally matched points and inliers
    fusion.preferFirst(points_matched_local, classes_matched_local, points_inlier, classes_inlier, points_active, classes_active);
//    points_active = points_fused;
//    classes_active = classes_fused;

    FILE_LOG(logDEBUG) << points_active.size() << " final fused points.";

    //TODO: Use theta to suppress result
    bb_rot = RotatedRect(center,  size_initial * scale, rotation/CV_PI * 180);

    //Remember current image
    im_prev = im_gray;

    FILE_LOG(logDEBUG) << "CMT::processFrame() return";
}

} /* namespace CMT */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 */

#ifndef PLIBSYS_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE puthread_test

#include "plibsys.h"

#ifdef PLIBSYS_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

static pint thread_wakes_1 = 0;
static pint thread_wakes_2 = 0;
static pint thread_to_wakes = 100;
static volatile pboolean is_threads_working = TRUE;

static P_HANDLE thread1_id = (P_HANDLE) NULL;
static P_HANDLE thread2_id = (P_HANDLE) NULL;

static PUThreadKey *tls_key = NULL;
static volatile pint free_counter = 0;

extern "C" ppointer pmem_alloc (psize nbytes)
{
	P_UNUSED (nbytes);
	return (ppointer) NULL;
}

extern "C" ppointer pmem_realloc (ppointer block, psize nbytes)
{
	P_UNUSED (block);
	P_UNUSED (nbytes);
	return (ppointer) NULL;
}

extern "C" void pmem_free (ppointer block)
{
	P_UNUSED (block);
}

static void free_with_check (ppointer mem)
{
	p_free (mem);
	p_atomic_int_inc (&free_counter);
}

static void * test_thread_func (void *data)
{
	pint *counter =  static_cast < pint * > (data);

	if ((*counter) == 1)
		thread1_id = p_uthread_current_id ();
	else
		thread2_id = p_uthread_current_id ();

	p_uthread_set_local (tls_key, (ppointer) p_uthread_current_id ());

	*counter = 0;

	while (is_threads_working == TRUE) {
		p_uthread_sleep (10);
		++(*counter);
		p_uthread_yield ();

		if (p_uthread_get_local (tls_key) != (ppointer) p_uthread_current_id ())
			p_uthread_exit (-1);
	}

	p_uthread_exit (*counter);
}

static void * test_thread_nonjoinable_func (void *data)
{
	pint *counter =  static_cast < pint * > (data);

	is_threads_working = TRUE;

	for (int i = thread_to_wakes; i > 0; --i) {
		p_uthread_sleep (10);
		++(*counter);
		p_uthread_yield ();
	}

	is_threads_working = FALSE;

	p_uthread_exit (0);
}

static void * test_thread_tls_func (void *data)
{
	pint self_thread_free = *((pint *) data);

	pint *tls_value = (pint *) p_malloc0 (sizeof (pint));
	*tls_value = 0;
	p_uthread_set_local (tls_key, (ppointer) tls_value);

	pint prev_tls = 0;
	pint counter  = 0;

	while (is_threads_working == TRUE) {
		p_uthread_sleep (10);

		pint *last_tls = (pint *) p_uthread_get_local (tls_key);

		if ((*last_tls) != prev_tls)
			p_uthread_exit (-1);

		pint *tls_new_value = (pint *) p_malloc0 (sizeof (pint));

		*tls_new_value = (*last_tls) + 1;
		prev_tls       = (*last_tls) + 1;

		p_uthread_replace_local (tls_key, (ppointer) tls_new_value);

		if (self_thread_free)
			p_free (last_tls);

		++counter;

		p_uthread_yield ();
	}

	p_uthread_exit (counter);
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (puthread_nomem_test)
{
	p_libsys_init ();

	PUThreadKey *thread_key = p_uthread_local_new (p_free);
	BOOST_CHECK (thread_key != NULL);

	PMemVTable vtable;

	vtable.free	= pmem_free;
	vtable.malloc	= pmem_alloc;
	vtable.realloc	= pmem_realloc;

	BOOST_CHECK (p_mem_set_vtable (&vtable) == TRUE);

	BOOST_CHECK (p_uthread_create ((PUThreadFunc) test_thread_func,
				       (ppointer) &thread_wakes_1,
				       TRUE) == NULL);

	BOOST_CHECK (p_uthread_create_full ((PUThreadFunc) test_thread_func,
					    (ppointer) &thread_wakes_2,
					    TRUE,
					    P_UTHREAD_PRIORITY_NORMAL) == NULL);

	BOOST_CHECK (p_uthread_local_new (NULL) == NULL);

	p_uthread_set_local (thread_key, PINT_TO_POINTER (10));
	BOOST_CHECK (p_uthread_get_local (thread_key) == NULL);

	vtable.malloc	= (ppointer (*)(psize)) malloc;
	vtable.realloc	= (ppointer (*)(ppointer, psize)) realloc;
	vtable.free	= (void (*)(ppointer)) free;

	BOOST_CHECK (p_mem_set_vtable (&vtable) == TRUE);

	p_uthread_local_free (thread_key);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_bad_input_test)
{
	p_libsys_init ();

	BOOST_CHECK (p_uthread_create (NULL, NULL, false) == NULL);
	BOOST_CHECK (p_uthread_create_full (NULL, NULL, false, P_UTHREAD_PRIORITY_NORMAL) == NULL);
	BOOST_CHECK (p_uthread_join (NULL) == -1);
	BOOST_CHECK (p_uthread_set_priority (NULL, P_UTHREAD_PRIORITY_NORMAL));
	BOOST_CHECK (p_uthread_get_local (NULL) == NULL);
	p_uthread_set_local (NULL, NULL);
	p_uthread_replace_local (NULL, NULL);
	p_uthread_free (NULL);
	p_uthread_local_free (NULL);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_general_test)
{
	p_libsys_init ();

	thread_wakes_1 = 1;
	thread_wakes_2 = 2;

	tls_key = p_uthread_local_new (NULL);
	BOOST_CHECK (tls_key != NULL);

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_func,
					   (ppointer) &thread_wakes_1,
					   TRUE);

	PUThread *thr2 = p_uthread_create_full ((PUThreadFunc) test_thread_func,
						(ppointer) &thread_wakes_2,
						TRUE,
						P_UTHREAD_PRIORITY_NORMAL);

	BOOST_CHECK (p_uthread_set_priority (thr1, P_UTHREAD_PRIORITY_NORMAL) == 0);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	BOOST_CHECK (p_uthread_join (thr1) == thread_wakes_1);
	BOOST_CHECK (p_uthread_join (thr2) == thread_wakes_2);

	BOOST_REQUIRE (thread1_id != thread2_id);
	BOOST_CHECK (thread1_id != p_uthread_current_id () &&
		     thread2_id != p_uthread_current_id ());

	p_uthread_local_free (tls_key);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_nonjoinable_test)
{
	p_libsys_init ();

	thread_wakes_1 = 0;

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_nonjoinable_func,
					   (ppointer) &thread_wakes_1,
					   FALSE);

	BOOST_REQUIRE (thr1 != NULL);

	p_uthread_sleep (3000);

	BOOST_CHECK (p_uthread_join (thr1) == -1);

	while (is_threads_working == TRUE)
		p_uthread_sleep (10);

	BOOST_CHECK (thread_wakes_1 == thread_to_wakes);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_tls_test)
{
	p_libsys_init ();

	/* With destroy notification */
	tls_key = p_uthread_local_new (free_with_check);

	is_threads_working = TRUE;

	pint self_thread_free = 0;

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
					   (ppointer) &self_thread_free,
					   TRUE);

	PUThread *thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
					   (ppointer) &self_thread_free,
					   TRUE);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	pint total_counter = 0;

	total_counter += (p_uthread_join (thr1) + 1);
	total_counter += (p_uthread_join (thr2) + 1);

	BOOST_CHECK (total_counter == free_counter);

	p_uthread_local_free (tls_key);

	/* Without destroy notification */
	tls_key = p_uthread_local_new (NULL);

	free_counter       = 0;
	is_threads_working = TRUE;
	self_thread_free   = 1;

	thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
				 (ppointer) &self_thread_free,
				 TRUE);

	thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
				 (ppointer) &self_thread_free,
				 TRUE);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	total_counter = 0;

	total_counter += (p_uthread_join (thr1) + 1);
	total_counter += (p_uthread_join (thr2) + 1);

	BOOST_CHECK (total_counter > 0);
	BOOST_CHECK (free_counter == 0);

	p_uthread_local_free (tls_key);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>tests: Fix memory leaks in threading tests<commit_after>/*
 * Copyright (C) 2013-2016 Alexander Saprykin <xelfium@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 */

#ifndef PLIBSYS_TESTS_STATIC
#  define BOOST_TEST_DYN_LINK
#endif

#define BOOST_TEST_MODULE puthread_test

#include "plibsys.h"

#ifdef PLIBSYS_TESTS_STATIC
#  include <boost/test/included/unit_test.hpp>
#else
#  include <boost/test/unit_test.hpp>
#endif

static pint thread_wakes_1 = 0;
static pint thread_wakes_2 = 0;
static pint thread_to_wakes = 100;
static volatile pboolean is_threads_working = TRUE;

static P_HANDLE thread1_id = (P_HANDLE) NULL;
static P_HANDLE thread2_id = (P_HANDLE) NULL;

static PUThreadKey *tls_key = NULL;
static volatile pint free_counter = 0;

extern "C" ppointer pmem_alloc (psize nbytes)
{
	P_UNUSED (nbytes);
	return (ppointer) NULL;
}

extern "C" ppointer pmem_realloc (ppointer block, psize nbytes)
{
	P_UNUSED (block);
	P_UNUSED (nbytes);
	return (ppointer) NULL;
}

extern "C" void pmem_free (ppointer block)
{
	P_UNUSED (block);
}

static void free_with_check (ppointer mem)
{
	p_free (mem);
	p_atomic_int_inc (&free_counter);
}

static void * test_thread_func (void *data)
{
	pint *counter =  static_cast < pint * > (data);

	if ((*counter) == 1)
		thread1_id = p_uthread_current_id ();
	else
		thread2_id = p_uthread_current_id ();

	p_uthread_set_local (tls_key, (ppointer) p_uthread_current_id ());

	*counter = 0;

	while (is_threads_working == TRUE) {
		p_uthread_sleep (10);
		++(*counter);
		p_uthread_yield ();

		if (p_uthread_get_local (tls_key) != (ppointer) p_uthread_current_id ())
			p_uthread_exit (-1);
	}

	p_uthread_exit (*counter);
}

static void * test_thread_nonjoinable_func (void *data)
{
	pint *counter =  static_cast < pint * > (data);

	is_threads_working = TRUE;

	for (int i = thread_to_wakes; i > 0; --i) {
		p_uthread_sleep (10);
		++(*counter);
		p_uthread_yield ();
	}

	is_threads_working = FALSE;

	p_uthread_exit (0);
}

static void * test_thread_tls_func (void *data)
{
	pint self_thread_free = *((pint *) data);

	pint *tls_value = (pint *) p_malloc0 (sizeof (pint));
	*tls_value = 0;
	p_uthread_set_local (tls_key, (ppointer) tls_value);

	pint prev_tls = 0;
	pint counter  = 0;

	while (is_threads_working == TRUE) {
		p_uthread_sleep (10);

		pint *last_tls = (pint *) p_uthread_get_local (tls_key);

		if ((*last_tls) != prev_tls)
			p_uthread_exit (-1);

		pint *tls_new_value = (pint *) p_malloc0 (sizeof (pint));

		*tls_new_value = (*last_tls) + 1;
		prev_tls       = (*last_tls) + 1;

		p_uthread_replace_local (tls_key, (ppointer) tls_new_value);

		if (self_thread_free)
			p_free (last_tls);

		++counter;

		p_uthread_yield ();
	}

	if (self_thread_free) {
		pint *last_tls = (pint *) p_uthread_get_local (tls_key);

		if ((*last_tls) != prev_tls)
			p_uthread_exit (-1);

		p_free (last_tls);

		p_uthread_replace_local (tls_key, (ppointer) NULL);
	}

	p_uthread_exit (counter);
}

BOOST_AUTO_TEST_SUITE (BOOST_TEST_MODULE)

BOOST_AUTO_TEST_CASE (puthread_nomem_test)
{
	p_libsys_init ();

	PUThreadKey *thread_key = p_uthread_local_new (p_free);
	BOOST_CHECK (thread_key != NULL);

	PMemVTable vtable;

	vtable.free	= pmem_free;
	vtable.malloc	= pmem_alloc;
	vtable.realloc	= pmem_realloc;

	BOOST_CHECK (p_mem_set_vtable (&vtable) == TRUE);

	BOOST_CHECK (p_uthread_create ((PUThreadFunc) test_thread_func,
				       (ppointer) &thread_wakes_1,
				       TRUE) == NULL);

	BOOST_CHECK (p_uthread_create_full ((PUThreadFunc) test_thread_func,
					    (ppointer) &thread_wakes_2,
					    TRUE,
					    P_UTHREAD_PRIORITY_NORMAL) == NULL);

	BOOST_CHECK (p_uthread_local_new (NULL) == NULL);

	p_uthread_set_local (thread_key, PINT_TO_POINTER (10));
	BOOST_CHECK (p_uthread_get_local (thread_key) == NULL);

	vtable.malloc	= (ppointer (*)(psize)) malloc;
	vtable.realloc	= (ppointer (*)(ppointer, psize)) realloc;
	vtable.free	= (void (*)(ppointer)) free;

	BOOST_CHECK (p_mem_set_vtable (&vtable) == TRUE);

	p_uthread_local_free (thread_key);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_bad_input_test)
{
	p_libsys_init ();

	BOOST_CHECK (p_uthread_create (NULL, NULL, false) == NULL);
	BOOST_CHECK (p_uthread_create_full (NULL, NULL, false, P_UTHREAD_PRIORITY_NORMAL) == NULL);
	BOOST_CHECK (p_uthread_join (NULL) == -1);
	BOOST_CHECK (p_uthread_set_priority (NULL, P_UTHREAD_PRIORITY_NORMAL));
	BOOST_CHECK (p_uthread_get_local (NULL) == NULL);
	p_uthread_set_local (NULL, NULL);
	p_uthread_replace_local (NULL, NULL);
	p_uthread_free (NULL);
	p_uthread_local_free (NULL);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_general_test)
{
	p_libsys_init ();

	thread_wakes_1 = 1;
	thread_wakes_2 = 2;

	tls_key = p_uthread_local_new (NULL);
	BOOST_CHECK (tls_key != NULL);

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_func,
					   (ppointer) &thread_wakes_1,
					   TRUE);

	PUThread *thr2 = p_uthread_create_full ((PUThreadFunc) test_thread_func,
						(ppointer) &thread_wakes_2,
						TRUE,
						P_UTHREAD_PRIORITY_NORMAL);

	BOOST_CHECK (p_uthread_set_priority (thr1, P_UTHREAD_PRIORITY_NORMAL) == 0);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	BOOST_CHECK (p_uthread_join (thr1) == thread_wakes_1);
	BOOST_CHECK (p_uthread_join (thr2) == thread_wakes_2);

	BOOST_REQUIRE (thread1_id != thread2_id);
	BOOST_CHECK (thread1_id != p_uthread_current_id () &&
		     thread2_id != p_uthread_current_id ());

	p_uthread_local_free (tls_key);
	p_uthread_free (thr1);
	p_uthread_free (thr2);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_nonjoinable_test)
{
	p_libsys_init ();

	thread_wakes_1 = 0;

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_nonjoinable_func,
					   (ppointer) &thread_wakes_1,
					   FALSE);

	BOOST_REQUIRE (thr1 != NULL);

	p_uthread_sleep (3000);

	BOOST_CHECK (p_uthread_join (thr1) == -1);

	while (is_threads_working == TRUE)
		p_uthread_sleep (10);

	BOOST_CHECK (thread_wakes_1 == thread_to_wakes);

	p_uthread_free (thr1);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_CASE (puthread_tls_test)
{
	p_libsys_init ();

	/* With destroy notification */
	tls_key = p_uthread_local_new (free_with_check);

	is_threads_working = TRUE;

	pint self_thread_free = 0;

	PUThread *thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
					   (ppointer) &self_thread_free,
					   TRUE);

	PUThread *thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
					   (ppointer) &self_thread_free,
					   TRUE);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	pint total_counter = 0;

	total_counter += (p_uthread_join (thr1) + 1);
	total_counter += (p_uthread_join (thr2) + 1);

	BOOST_CHECK (total_counter == free_counter);

	p_uthread_local_free (tls_key);
	p_uthread_free (thr1);
	p_uthread_free (thr2);

	/* Without destroy notification */
	tls_key = p_uthread_local_new (NULL);

	free_counter       = 0;
	is_threads_working = TRUE;
	self_thread_free   = 1;

	thr1 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
				 (ppointer) &self_thread_free,
				 TRUE);

	thr2 = p_uthread_create ((PUThreadFunc) test_thread_tls_func,
				 (ppointer) &self_thread_free,
				 TRUE);

	BOOST_REQUIRE (thr1 != NULL);
	BOOST_REQUIRE (thr2 != NULL);

	p_uthread_sleep (5000);

	is_threads_working = FALSE;

	total_counter = 0;

	total_counter += (p_uthread_join (thr1) + 1);
	total_counter += (p_uthread_join (thr2) + 1);

	BOOST_CHECK (total_counter > 0);
	BOOST_CHECK (free_counter == 0);

	p_uthread_local_free (tls_key);
	p_uthread_free (thr1);
	p_uthread_free (thr2);

	p_libsys_shutdown ();
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before><commit_msg>Fix access to ANCF node direction vector in unit test<commit_after><|endoftext|>


<commit_before>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include <iostream>
#include <string>

#include "jubatus/util/lang/bind.h"

#include "jubatus/core/common/exception.hpp"
#include "../third_party/cmdline/cmdline.h"
#include "../common/logger/logger.hpp"
#include "../common/signals.hpp"
#include "../common/filesystem.hpp"

#include "jubavisor.hpp"

namespace {
const std::string PROGNAME = "jubavisor";
}  // namespace

using jubatus::server::common::set_action_on_term;
using jubatus::server::jubavisor::jubavisor;
using jubatus::server::jubavisor::jubavisor_server;
using jubatus::util::lang::_1;
using jubatus::util::lang::_2;
using jubatus::util::lang::_3;
using jubatus::util::lang::bind;
using jubatus::util::lang::ref;

namespace {

bool logger_configured_ = false;

void stop_on_term(jubavisor_server& serv) {
  LOG(INFO) << "stopping RPC server";
  serv.rpc_end();
}

void configure_logger(const std::string& log_config) {
  if (log_config.empty()) {
    jubatus::server::common::logger::configure();
  } else {
    if (logger_configured_) {
      LOG(INFO) << "reloading log configuration: " << log_config;
    }
    jubatus::server::common::logger::configure(log_config);
  }

  if (!jubatus::server::common::logger::is_configured()) {
    std::cerr << "failed to configure logger" << std::endl;
    ::exit(1);
  }

  logger_configured_ = true;
  jubatus::server::common::set_action_on_hup(jubatus::util::lang::bind(
      configure_logger, jubatus::util::lang::ref(log_config)));
}

}  // namespace

int main(int argc, char* argv[]) try {
  cmdline::parser p;
  p.add<int>("rpc-port", 'p', "port number", false, 9198,
             cmdline::range(1, 65535));
  p.add<std::string>("zookeeper", 'z', "zookeeper location", true);
  p.add<std::string>("logdir", 'l', "log to output all child process' log",
                     false, "/tmp");
  p.add<std::string>("log_config", 'g',
                     "log4cxx XML configuration file", false, "");
  p.add<int>("timeout", 't', "rpc timeout", false, 10);
  p.add("daemon", 'd', "daemonize the process");
  p.parse_check(argc, argv);
  int port = p.get<int>("rpc-port");
  std::string logfile = "";
  std::string log_config = p.get<std::string>("log_config");

  // Configure the logger.
  if (!log_config.empty()) {
    log_config = jubatus::server::common::real_path(log_config);
  }
  jubatus::server::common::logger::setup_parameters(
      jubatus::server::common::get_program_name().c_str(), "", port);
  configure_logger(log_config);

  if (p.exist("daemon")) {
    jubatus::server::common::append_server_path(argv[0]);
    logfile = p.get<std::string>("logdir") + "/" + PROGNAME + ".";

    int r = jubatus::server::common::daemonize();

    if (r == -1) {
      LOG(ERROR) << "failed at daemon(3): errno=" << errno;
      return -1;
    }
    logfile += "zklog";
    LOG(INFO) << "starting with daemon mode on port " << port;
    LOG(INFO) << "writing ZooKeeper logs to " << logfile;
  } else {
    LOG(INFO) << " starting with interactive mode on port " << port;
  }

  jubavisor j(p.get<std::string>("zookeeper"), port, 16, logfile);
  jubavisor_server serv(10 * 1024);
  {
    serv.set_start(bind(&jubavisor::start, &j, _1, _2, _3));
    serv.set_stop(bind(&jubavisor::stop, &j, _1, _2));

    try {
      serv.rpc_listen(port);
      serv.rpc_start(2, true);
      set_action_on_term(bind(&stop_on_term, ref(serv)));
      serv.rpc_join();
    } catch (const mp::system_error& e) {
      if (e.code == EADDRINUSE) {
        LOG(ERROR) << "server failed to start: " << e.what()
                   << " (any process using port " << port << "?)";
      } else {
        LOG(FATAL) << "server failed to start: " << e.what();
      }
      return -1;
    } catch (const std::exception& e) {
      LOG(FATAL) << "error when starting RPC server: " << e.what();
    }
  }
  return 0;
} catch (const jubatus::core::common::exception::jubatus_exception& e) {
  std::cout << e.diagnostic_information(true) << std::endl;
}
<commit_msg>do not reconfigure default logger (fix #962, refs #1084)<commit_after>// Jubatus: Online machine learning framework for distributed environment
// Copyright (C) 2011 Preferred Networks and Nippon Telegraph and Telephone Corporation.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License version 2.1 as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

#include <iostream>
#include <string>

#include "jubatus/util/lang/bind.h"

#include "jubatus/core/common/exception.hpp"
#include "../third_party/cmdline/cmdline.h"
#include "../common/logger/logger.hpp"
#include "../common/signals.hpp"
#include "../common/filesystem.hpp"

#include "jubavisor.hpp"

namespace {
const std::string PROGNAME = "jubavisor";
}  // namespace

using jubatus::server::common::set_action_on_term;
using jubatus::server::jubavisor::jubavisor;
using jubatus::server::jubavisor::jubavisor_server;
using jubatus::util::lang::_1;
using jubatus::util::lang::_2;
using jubatus::util::lang::_3;
using jubatus::util::lang::bind;
using jubatus::util::lang::ref;

namespace {

bool logger_configured_ = false;

void stop_on_term(jubavisor_server& serv) {
  LOG(INFO) << "stopping RPC server";
  serv.rpc_end();
}

void configure_logger(const std::string& log_config) {
  if (log_config.empty()) {
    if (!logger_configured_) {
      jubatus::server::common::logger::configure();
    }
  } else {
    if (logger_configured_) {
      LOG(INFO) << "reloading log configuration: " << log_config;
    }
    jubatus::server::common::logger::configure(log_config);
  }

  if (!jubatus::server::common::logger::is_configured()) {
    std::cerr << "failed to configure logger" << std::endl;
    ::exit(1);
  }

  logger_configured_ = true;
  jubatus::server::common::set_action_on_hup(jubatus::util::lang::bind(
      configure_logger, jubatus::util::lang::ref(log_config)));
}

}  // namespace

int main(int argc, char* argv[]) try {
  cmdline::parser p;
  p.add<int>("rpc-port", 'p', "port number", false, 9198,
             cmdline::range(1, 65535));
  p.add<std::string>("zookeeper", 'z', "zookeeper location", true);
  p.add<std::string>("logdir", 'l', "log to output all child process' log",
                     false, "/tmp");
  p.add<std::string>("log_config", 'g',
                     "log4cxx XML configuration file", false, "");
  p.add<int>("timeout", 't', "rpc timeout", false, 10);
  p.add("daemon", 'd', "daemonize the process");
  p.parse_check(argc, argv);
  int port = p.get<int>("rpc-port");
  std::string logfile = "";
  std::string log_config = p.get<std::string>("log_config");

  // Configure the logger.
  if (!log_config.empty()) {
    log_config = jubatus::server::common::real_path(log_config);
  }
  jubatus::server::common::logger::setup_parameters(
      jubatus::server::common::get_program_name().c_str(), "", port);
  configure_logger(log_config);

  if (p.exist("daemon")) {
    jubatus::server::common::append_server_path(argv[0]);
    logfile = p.get<std::string>("logdir") + "/" + PROGNAME + ".";

    int r = jubatus::server::common::daemonize();

    if (r == -1) {
      LOG(ERROR) << "failed at daemon(3): errno=" << errno;
      return -1;
    }
    logfile += "zklog";
    LOG(INFO) << "starting with daemon mode on port " << port;
    LOG(INFO) << "writing ZooKeeper logs to " << logfile;
  } else {
    LOG(INFO) << " starting with interactive mode on port " << port;
  }

  jubavisor j(p.get<std::string>("zookeeper"), port, 16, logfile);
  jubavisor_server serv(10 * 1024);
  {
    serv.set_start(bind(&jubavisor::start, &j, _1, _2, _3));
    serv.set_stop(bind(&jubavisor::stop, &j, _1, _2));

    try {
      serv.rpc_listen(port);
      serv.rpc_start(2, true);
      set_action_on_term(bind(&stop_on_term, ref(serv)));
      serv.rpc_join();
    } catch (const mp::system_error& e) {
      if (e.code == EADDRINUSE) {
        LOG(ERROR) << "server failed to start: " << e.what()
                   << " (any process using port " << port << "?)";
      } else {
        LOG(FATAL) << "server failed to start: " << e.what();
      }
      return -1;
    } catch (const std::exception& e) {
      LOG(FATAL) << "error when starting RPC server: " << e.what();
    }
  }
  return 0;
} catch (const jubatus::core::common::exception::jubatus_exception& e) {
  std::cout << e.diagnostic_information(true) << std::endl;
}
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2016 ScyllaDB.
 */
#include <vector>

#include "core/do_with.hh"
#include "test-utils.hh"
#include "core/sstring.hh"
#include "core/reactor.hh"
#include "core/do_with.hh"
#include "core/future-util.hh"
#include "core/sharded.hh"
#include "core/gate.hh"
#include "core/scollectd.hh"
#include "core/scollectd_api.hh"

using namespace seastar;
using namespace scollectd;

static const plugin_id  plugin = "the_piglet";
static const plugin_instance_id my_id = "wulf";

template<typename... _Args>
static void test_bind_counters(_Args&& ... args) {
    std::vector<type_instance_id> bound;

    {
        plugin_instance_metrics pm(plugin, my_id, std::forward<_Args>(args)...);

        bound = pm.bound_ids();
        BOOST_CHECK_EQUAL(bound.size(), sizeof...(args));

        for (auto& id : bound) {
            auto vals = get_collectd_value(id);
            BOOST_CHECK_GE(vals.size(), 1);
        }
    }

    // check unregistration
    for (auto& id : bound) {
        auto vals = get_collectd_value(id);
        BOOST_CHECK_EQUAL(vals.size(), 0);
    }
}

SEASTAR_TEST_CASE(test_simple_plugin_instance_metrics) {
    uint64_t counter = 12;
    test_bind_counters(total_bytes("test_bytes", counter));

    double cow;
    test_bind_counters(total_bytes("test_bytes", counter), typed_value_impl<known_type::uptime>("sleeping", cow));

    int64_t rx, tx;
    test_bind_counters(typed_value_impl<known_type::io_packets>("christmas_presents", rx, tx));

    // comment/description
    int64_t woff;
    test_bind_counters(typed_value_impl<known_type::connections>("woffs", description("this is how many woffs where barked"), woff));

    return make_ready_future();
}

SEASTAR_TEST_CASE(test_simple_description) {
    uint64_t counter = 12;
    sstring desc = "I am hungry like the wolf";

    plugin_instance_metrics pm(plugin, my_id, total_bytes("test_bytes", description(desc), counter));

    auto s = get_collectd_description_str(pm.bound_ids().front());
    BOOST_CHECK_EQUAL(s, desc);

    return make_ready_future();
}

<commit_msg>scollectd_test: Add cases for explicit data type + binding callables<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */

/*
 * Copyright (C) 2016 ScyllaDB.
 */
#include <vector>

#include "core/do_with.hh"
#include "test-utils.hh"
#include "core/sstring.hh"
#include "core/reactor.hh"
#include "core/do_with.hh"
#include "core/future-util.hh"
#include "core/sharded.hh"
#include "core/gate.hh"
#include "core/scollectd.hh"
#include "core/scollectd_api.hh"

using namespace seastar;
using namespace scollectd;

static const plugin_id  plugin = "the_piglet";
static const plugin_instance_id my_id = "wulf";

template<typename... _Args>
static void test_bind_counters(_Args&& ... args) {
    std::vector<type_instance_id> bound;

    {
        plugin_instance_metrics pm(plugin, my_id, std::forward<_Args>(args)...);

        bound = pm.bound_ids();
        BOOST_CHECK_EQUAL(bound.size(), sizeof...(args));

        for (auto& id : bound) {
            auto vals = get_collectd_value(id);
            BOOST_CHECK_GE(vals.size(), 1);
        }
    }

    // check unregistration
    for (auto& id : bound) {
        auto vals = get_collectd_value(id);
        BOOST_CHECK_EQUAL(vals.size(), 0);
    }
}

SEASTAR_TEST_CASE(test_simple_plugin_instance_metrics) {
    uint64_t counter = 12;
    test_bind_counters(total_bytes("test_bytes", counter));

    double cow;
    test_bind_counters(total_bytes("test_bytes", counter), typed_value_impl<known_type::uptime>("sleeping", cow));

    int64_t rx, tx;
    test_bind_counters(typed_value_impl<known_type::io_packets>("christmas_presents", rx, tx));

    // comment/description
    int64_t woff;
    test_bind_counters(typed_value_impl<known_type::connections>("woffs", description("this is how many woffs where barked"), woff));

    // typed
    test_bind_counters(typed_value_impl<known_type::connections>("waffs", make_typed(data_type::ABSOLUTE, woff)));

    return make_ready_future();
}

SEASTAR_TEST_CASE(test_simple_description) {
    uint64_t counter = 12;
    sstring desc = "I am hungry like the wolf";

    plugin_instance_metrics pm(plugin, my_id, total_bytes("test_bytes", description(desc), counter));

    auto s = get_collectd_description_str(pm.bound_ids().front());
    BOOST_CHECK_EQUAL(s, desc);

    return make_ready_future();
}

SEASTAR_TEST_CASE(test_bind_callable) {
    uint64_t val;

    auto callable = [&val] { return val; };

    plugin_instance_metrics pm(plugin, my_id, total_bytes("test_bytes", callable));

    auto bound = pm.bound_ids();

    for (auto& id : bound) {
        for (uint64_t i : { 1, 4, 45542, 2323, 12, 0 }) {
            val = i;
            auto vals = get_collectd_value(id);
            for (auto v : vals) {
                BOOST_CHECK_EQUAL(v.u._ui, i);
            }
        }
    }

    return make_ready_future();
}

SEASTAR_TEST_CASE(test_bind_callable_raw) {
    uint64_t val;

    auto callable = [&val] { return val; };

    scollectd::type_instance_id id("apa", per_cpu_plugin_instance, "total_bytes", "ko");
    scollectd::registration r = add_polled_metric(id, make_typed(data_type::DERIVE, callable));

    for (uint64_t i : { 1, 4, 45542, 2323, 12, 0 }) {
        val = i;
        auto vals = get_collectd_value(id);
        for (auto v : vals) {
            BOOST_CHECK_EQUAL(v.u._ui, i);
        }
    }

    return make_ready_future();
}

<|endoftext|>