<commit_before>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"

#define CCONTROL_TARGET 100

namespace libtorrent
{

	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

   0       4       8               16              24              32
   +-------+-------+---------------+---------------+---------------+
   | ver   | type  | extension     | connection_id                 |
   +-------+-------+---------------+---------------+---------------+
   | timestamp_microseconds                                        |
   +---------------+---------------+---------------+---------------+
   | timestamp_difference_microseconds                             |
   +---------------+---------------+---------------+---------------+
   | wnd_size                                                      |
   +---------------+---------------+---------------+---------------+
   | seq_nr                        | ack_nr                        |
   +---------------+---------------+---------------+---------------+

*/

enum { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN } type;

struct utp_header
{
	unsigned char ver:4;
	unsigned char type:4;
	unsigned char extension;
	be_uint16 connection_id;
	be_uint32 timestamp_microseconds;
	be_uint32 timestamp_difference_microseconds;
	be_uint32 wnd_size;
	be_uint16 seq_nr;
	be_uint16 ack_nr;
};

class utp_stream : public proxy_base
{
public:

	explicit utp_stream(io_service& ios, utp_socket_manager& sm, boost::uint16_t id)
		: proxy_base(ios)
		, m_sm(sm)
		, m_send_id(id + 1)
		, m_recv_id(id)
		, m_state(UTP_STATE_NONE)
	{}

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		TORRENT_ASSERT(m_state == UTP_STATE_NONE);
		// store handler
		async_connect_impl();
	}

	void bind(endpoint_type const& ep, error_code& ec);
	void bind(udp::endpoint const& ep, error_code& ec);
	bool incoming_packet(char const* buf, int size);

	void tick();

	~utp_stream();

private:

	void async_connect_impl();

	utp_socket_manager& m_sm;
	boost::uint16_t m_send_id;
	boost::uint16_t m_recv_id;
	boost::uint16_t m_ack_nr;
	boost::uint16_t m_seq_nr;
	enum state_t {
		UTP_STATE_NONE,
		UTP_STATE_SYN_SENT,
		UTP_STATE_CONNECTED,
		UTP_STATE_FIN_SENT
	};
	unsigned char m_state;
};

}

#endif
<commit_msg>Added const to var in big_endian_int::operator T().<commit_after>/*

Copyright (c) 2009, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_UTP_STREAM_HPP_INCLUDED
#define TORRENT_UTP_STREAM_HPP_INCLUDED

#include "libtorrent/connection_queue.hpp"
#include "libtorrent/proxy_base.hpp"
#include "libtorrent/utp_socket_manager.hpp"
#include "libtorrent/udp_socket.hpp"
#include "libtorrent/io.hpp"

#define CCONTROL_TARGET 100

namespace libtorrent
{

	template <class T> struct big_endian_int
	{
		big_endian_int& operator=(T v)
		{
			char* p = m_storage;
			detail::write_impl(v, p);
			return *this;
		}
		operator T() const
		{
			const char* p = m_storage;
			return detail::read_impl(p, detail::type<T>());
		}
	private:
		char m_storage[sizeof(T)];
	};

	typedef big_endian_int<boost::uint64_t> be_uint64;
	typedef big_endian_int<boost::uint32_t> be_uint32;
	typedef big_endian_int<boost::uint16_t> be_uint16;
	typedef big_endian_int<boost::int64_t> be_int64;
	typedef big_endian_int<boost::int32_t> be_int32;
	typedef big_endian_int<boost::int16_t> be_int16;

/*
	uTP header from BEP 29

   0       4       8               16              24              32
   +-------+-------+---------------+---------------+---------------+
   | ver   | type  | extension     | connection_id                 |
   +-------+-------+---------------+---------------+---------------+
   | timestamp_microseconds                                        |
   +---------------+---------------+---------------+---------------+
   | timestamp_difference_microseconds                             |
   +---------------+---------------+---------------+---------------+
   | wnd_size                                                      |
   +---------------+---------------+---------------+---------------+
   | seq_nr                        | ack_nr                        |
   +---------------+---------------+---------------+---------------+

*/

enum { ST_DATA = 0, ST_FIN, ST_STATE, ST_RESET, ST_SYN } type;

struct utp_header
{
	unsigned char ver:4;
	unsigned char type:4;
	unsigned char extension;
	be_uint16 connection_id;
	be_uint32 timestamp_microseconds;
	be_uint32 timestamp_difference_microseconds;
	be_uint32 wnd_size;
	be_uint16 seq_nr;
	be_uint16 ack_nr;
};

class utp_stream : public proxy_base
{
public:

	explicit utp_stream(io_service& ios, utp_socket_manager& sm, boost::uint16_t id)
		: proxy_base(ios)
		, m_sm(sm)
		, m_send_id(id + 1)
		, m_recv_id(id)
		, m_state(UTP_STATE_NONE)
	{}

	typedef boost::function<void(error_code const&)> handler_type;

	template <class Handler>
	void async_connect(endpoint_type const& endpoint, Handler const& handler)
	{
		TORRENT_ASSERT(m_state == UTP_STATE_NONE);
		// store handler
		async_connect_impl();
	}

	void bind(endpoint_type const& ep, error_code& ec);
	void bind(udp::endpoint const& ep, error_code& ec);
	bool incoming_packet(char const* buf, int size);

	void tick();

	~utp_stream();

private:

	void async_connect_impl();

	utp_socket_manager& m_sm;
	boost::uint16_t m_send_id;
	boost::uint16_t m_recv_id;
	boost::uint16_t m_ack_nr;
	boost::uint16_t m_seq_nr;
	enum state_t {
		UTP_STATE_NONE,
		UTP_STATE_SYN_SENT,
		UTP_STATE_CONNECTED,
		UTP_STATE_FIN_SENT
	};
	unsigned char m_state;
};

}

#endif
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/color.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geometry_impl.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/expression_node.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>

// agg
#include "agg_trans_affine.h"

// boost
#include <boost/optional.hpp>
// stl
#include <memory>
#include <type_traits> // remove_reference
#include <cmath>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl & feature,
                            attributes const& vars)
        : src_(src),
          marker_trans_(marker_trans),
          sym_(sym),
          detector_(detector),
          feature_(feature),
          vars_(vars),
          scale_factor_(scale_factor)
    {}

    virtual ~vector_markers_dispatch() {}

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
        value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
        value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
        value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
        value_double opacity = get<value_double,keys::opacity>(sym_, feature_, vars_);
        value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
        value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
        coord2d center = src_->bounding_box().center();
        agg::trans_affine_translation recenter(-center.x, -center.y);
        agg::trans_affine tr = recenter * marker_trans_;
        direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
        markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
        markers_placement_finder<T, Detector> placement_finder(
            placement_method, path, detector_, params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, ignore_placement))
        {
            agg::trans_affine matrix = tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            render_marker(matrix, opacity);
        }
    }

    virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;

protected:
    svg_path_ptr const& src_;
    agg::trans_affine const& marker_trans_;
    symbolizer_base const& sym_;
    Detector & detector_;
    feature_impl & feature_;
    attributes const& vars_;
    double scale_factor_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl & feature,
                            attributes const& vars)
    : src_(src),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        feature_(feature),
        vars_(vars),
        scale_factor_(scale_factor)
    {}

    virtual ~raster_markers_dispatch() {}

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
        value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
        value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
        value_double opacity = get<value_double, keys::opacity>(sym_, feature_, vars_);
        value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
        value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
        value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
        box2d<double> bbox(0,0, src_.width(),src_.height());
        direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
        markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
        markers_placement_finder<T, label_collision_detector4> placement_finder(
            placement_method, path, detector_, params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, ignore_placement))
        {
            agg::trans_affine matrix = marker_trans_;
            matrix.rotate(angle);
            matrix.translate(x, y);
            render_marker(matrix, opacity);
        }
    }

    virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;

protected:
    image_rgba8 const& src_;
    agg::trans_affine const& marker_trans_;
    symbolizer_base const& sym_;
    Detector & detector_;
    feature_impl & feature_;
    attributes const& vars_;
    double scale_factor_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries
template <typename Converter>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, symbolizer_base const& sym)
{
    using vertex_converter_type = Converter;
    using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type>;
    using vertex_processor_type = new_geometry::vertex_processor<apply_vertex_converter_type>;

    auto const& geom = feature.get_geometry();
    new_geometry::geometry_types type = new_geometry::geometry_type(geom);

    if (type == new_geometry::geometry_types::Point
        || type == new_geometry::geometry_types::LineString
        || type == new_geometry::geometry_types::Polygon)
    {
        apply_vertex_converter_type apply(converter);
        mapnik::util::apply_visitor(vertex_processor_type(apply), geom);
    }
    else if (type != new_geometry::geometry_types::GeometryCollection) // multi geometries
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            new_geometry::point pt;
            if (new_geometry::centroid(geom, pt))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                new_geometry::point_vertex_adapter va(pt);
                converter.apply(va);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == new_geometry::geometry_types::MultiPolygon)
            {
                new_geometry::multi_polygon const& multi_poly = mapnik::util::get<new_geometry::multi_polygon>(geom);
                double maxarea = 0;
                new_geometry::polygon const* largest = 0;
                for (new_geometry::polygon const& poly : multi_poly)
                {
                    box2d<double> bbox = new_geometry::envelope(poly);
                    new_geometry::polygon_vertex_adapter va(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    new_geometry::polygon_vertex_adapter va(*largest);
                    converter.apply(va);
                }
            }
        }
        else if (type == new_geometry::geometry_types::MultiPolygon)
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            new_geometry::multi_polygon const& multi_poly = mapnik::util::get<new_geometry::multi_polygon>(geom);
            for (auto const& poly : multi_poly)
            {
                new_geometry::polygon_vertex_adapter va(poly);
                converter.apply(va);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<commit_msg>handle collections<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_MARKER_HELPERS_HPP
#define MAPNIK_MARKER_HELPERS_HPP

#include <mapnik/color.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/geometry_impl.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/geometry_centroid.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/expression_node.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/marker.hpp> // for svg_storage_type
#include <mapnik/markers_placement.hpp>
#include <mapnik/attribute.hpp>
#include <mapnik/box2d.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/vertex_processor.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/renderer_common/apply_vertex_converter.hpp>

// agg
#include "agg_trans_affine.h"

// boost
#include <boost/optional.hpp>
// stl
#include <memory>
#include <type_traits> // remove_reference
#include <cmath>

namespace mapnik {

struct clip_poly_tag;

using svg_attribute_type = agg::pod_bvector<svg::path_attributes>;

template <typename Detector>
struct vector_markers_dispatch : util::noncopyable
{
    vector_markers_dispatch(svg_path_ptr const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl & feature,
                            attributes const& vars)
        : src_(src),
          marker_trans_(marker_trans),
          sym_(sym),
          detector_(detector),
          feature_(feature),
          vars_(vars),
          scale_factor_(scale_factor)
    {}

    virtual ~vector_markers_dispatch() {}

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
        value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
        value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
        value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
        value_double opacity = get<value_double,keys::opacity>(sym_, feature_, vars_);
        value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
        value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
        coord2d center = src_->bounding_box().center();
        agg::trans_affine_translation recenter(-center.x, -center.y);
        agg::trans_affine tr = recenter * marker_trans_;
        direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
        markers_placement_params params { src_->bounding_box(), tr, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
        markers_placement_finder<T, Detector> placement_finder(
            placement_method, path, detector_, params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, ignore_placement))
        {
            agg::trans_affine matrix = tr;
            matrix.rotate(angle);
            matrix.translate(x, y);
            render_marker(matrix, opacity);
        }
    }

    virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;

protected:
    svg_path_ptr const& src_;
    agg::trans_affine const& marker_trans_;
    symbolizer_base const& sym_;
    Detector & detector_;
    feature_impl & feature_;
    attributes const& vars_;
    double scale_factor_;
};

template <typename Detector>
struct raster_markers_dispatch : util::noncopyable
{
    raster_markers_dispatch(image_rgba8 const& src,
                            agg::trans_affine const& marker_trans,
                            symbolizer_base const& sym,
                            Detector & detector,
                            double scale_factor,
                            feature_impl & feature,
                            attributes const& vars)
    : src_(src),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        feature_(feature),
        vars_(vars),
        scale_factor_(scale_factor)
    {}

    virtual ~raster_markers_dispatch() {}

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_enum placement_method = get<marker_placement_enum, keys::markers_placement_type>(sym_, feature_, vars_);
        value_bool allow_overlap = get<value_bool, keys::allow_overlap>(sym_, feature_, vars_);
        value_bool avoid_edges = get<value_bool, keys::avoid_edges>(sym_, feature_, vars_);
        value_double opacity = get<value_double, keys::opacity>(sym_, feature_, vars_);
        value_bool ignore_placement = get<value_bool, keys::ignore_placement>(sym_, feature_, vars_);
        value_double spacing = get<value_double, keys::spacing>(sym_, feature_, vars_);
        value_double max_error = get<value_double, keys::max_error>(sym_, feature_, vars_);
        box2d<double> bbox(0,0, src_.width(),src_.height());
        direction_enum direction = get<direction_enum, keys::direction>(sym_, feature_, vars_);
        markers_placement_params params { bbox, marker_trans_, spacing * scale_factor_, max_error, allow_overlap, avoid_edges, direction };
        markers_placement_finder<T, label_collision_detector4> placement_finder(
            placement_method, path, detector_, params);
        double x, y, angle = .0;
        while (placement_finder.get_point(x, y, angle, ignore_placement))
        {
            agg::trans_affine matrix = marker_trans_;
            matrix.rotate(angle);
            matrix.translate(x, y);
            render_marker(matrix, opacity);
        }
    }

    virtual void render_marker(agg::trans_affine const& marker_tr, double opacity) = 0;

protected:
    image_rgba8 const& src_;
    agg::trans_affine const& marker_trans_;
    symbolizer_base const& sym_;
    Detector & detector_;
    feature_impl & feature_;
    attributes const& vars_;
    double scale_factor_;
};

void build_ellipse(symbolizer_base const& sym, mapnik::feature_impl & feature, attributes const& vars, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path);

bool push_explicit_style(svg_attribute_type const& src,
                         svg_attribute_type & dst,
                         symbolizer_base const& sym,
                         feature_impl & feature,
                         attributes const& vars);

void setup_transform_scaling(agg::trans_affine & tr,
                             double svg_width,
                             double svg_height,
                             mapnik::feature_impl & feature,
                             attributes const& vars,
                             symbolizer_base const& sym);

// Apply markers to a feature with multiple geometries
template <typename Converter>
void apply_markers_multi(feature_impl const& feature, attributes const& vars, Converter & converter, symbolizer_base const& sym)
{
    using vertex_converter_type = Converter;
    using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type>;
    using vertex_processor_type = new_geometry::vertex_processor<apply_vertex_converter_type>;

    auto const& geom = feature.get_geometry();
    new_geometry::geometry_types type = new_geometry::geometry_type(geom);

    if (type == new_geometry::geometry_types::Point
        || type == new_geometry::geometry_types::LineString
        || type == new_geometry::geometry_types::Polygon)
    {
        apply_vertex_converter_type apply(converter);
        mapnik::util::apply_visitor(vertex_processor_type(apply), geom);
    }
    else //if (type != new_geometry::geometry_types::GeometryCollection) // multi geometries/collection
    {

        marker_multi_policy_enum multi_policy = get<marker_multi_policy_enum, keys::markers_multipolicy>(sym, feature, vars);
        marker_placement_enum placement = get<marker_placement_enum, keys::markers_placement_type>(sym, feature, vars);

        if (placement == MARKER_POINT_PLACEMENT &&
            multi_policy == MARKER_WHOLE_MULTI)
        {
            new_geometry::point pt;
            if (new_geometry::centroid(geom, pt))
            {
                // unset any clipping since we're now dealing with a point
                converter.template unset<clip_poly_tag>();
                new_geometry::point_vertex_adapter va(pt);
                converter.apply(va);
            }
        }
        else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
                 multi_policy == MARKER_LARGEST_MULTI)
        {
            // Only apply to path with largest envelope area
            // TODO: consider using true area for polygon types
            if (type == new_geometry::geometry_types::MultiPolygon)
            {
                new_geometry::multi_polygon const& multi_poly = mapnik::util::get<new_geometry::multi_polygon>(geom);
                double maxarea = 0;
                new_geometry::polygon const* largest = 0;
                for (new_geometry::polygon const& poly : multi_poly)
                {
                    box2d<double> bbox = new_geometry::envelope(poly);
                    new_geometry::polygon_vertex_adapter va(poly);
                    double area = bbox.width() * bbox.height();
                    if (area > maxarea)
                    {
                        maxarea = area;
                        largest = &poly;
                    }
                }
                if (largest)
                {
                    new_geometry::polygon_vertex_adapter va(*largest);
                    converter.apply(va);
                }
            }
        }
        else if (type == new_geometry::geometry_types::MultiPolygon)
        {
            if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
            {
                MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
            }
            new_geometry::multi_polygon const& multi_poly = mapnik::util::get<new_geometry::multi_polygon>(geom);
            for (auto const& poly : multi_poly)
            {
                new_geometry::polygon_vertex_adapter va(poly);
                converter.apply(va);
            }
        }
    }
}

}

#endif //MAPNIK_MARKER_HELPERS_HPP
<|endoftext|>


<commit_before>//
// Created by jan on 7/30/15.
//

#ifndef NIX_ATTRIBUTE_HPP
#define NIX_ATTRIBUTE_HPP

#include <yaml-cpp/yaml.h>
#include <boost/filesystem.hpp>
#include <iostream>
#include <fstream>

#include <nix/Platform.hpp>

namespace nix {
namespace file {

class AttributesFS {

private:
    YAML::Node node;
    boost::filesystem::path loc;

    void open_or_create();

    void write_file();

public:
    AttributesFS();

    AttributesFS(const std::string &file_path);
    // AttributesFS(const nix::file::AttributesFS &other);

    boost::filesystem::path location() const;

    bool hasField(const std::string &name);

    void remove(const std::string &name);

    template <typename T> void read(const std::string &name, T &value);

    template <typename T> void write(const std::string &name, const T &value);

    ndsize_t attributeCount();
};

template <typename T> void AttributesFS::read(const std::string &name, T &value) {
    T result;
    this->open_or_create();
    if (hasField(name)) {
        return this->node[name].as<T>();
    }
    return 0;
}

template <typename T> void AttributesFS::write(const std::string &name, const T &value) {
    this->open_or_create();
    this->node[name] = value;
    this->write_file();
    std::cerr << this->node << std::endl;
}

} // namespace file
} // namespace nix

#endif //NIX_ATTRIBUTE_HPP
<commit_msg>[file backend/Attributes] add removal of field to write method<commit_after>//
// Created by jan on 7/30/15.
//

#ifndef NIX_ATTRIBUTE_HPP
#define NIX_ATTRIBUTE_HPP

#include <yaml-cpp/yaml.h>
#include <boost/filesystem.hpp>
#include <iostream>
#include <fstream>

#include <nix/Platform.hpp>

namespace nix {
namespace file {

class AttributesFS {

private:
    YAML::Node node;
    boost::filesystem::path loc;

    void open_or_create();

    void write_file();

public:
    AttributesFS();

    AttributesFS(const std::string &file_path);
    // AttributesFS(const nix::file::AttributesFS &other);

    boost::filesystem::path location() const;

    bool hasField(const std::string &name);

    void remove(const std::string &name);

    template <typename T> void read(const std::string &name, T &value);

    template <typename T> void write(const std::string &name, const T &value);

    ndsize_t attributeCount();
};

template <typename T> void AttributesFS::read(const std::string &name, T &value) {
    T result;
    this->open_or_create();
    if (hasField(name)) {
        return this->node[name].as<T>();
    }
    return 0;
}

template <typename T> void AttributesFS::write(const std::string &name, const T &value) {
    this->open_or_create();
    if (this->node[name]) {
        this->node.remove(name);
    }
    this->node[name] = value;
    this->write_file();
}

} // namespace file
} // namespace nix

#endif //NIX_ATTRIBUTE_HPP
<|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) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <memory>
#include <seastar/core/task.hh>
#include <seastar/core/future.hh>

namespace seastar {

template <typename Func>
class lambda_task final : public task {
    Func _func;
    using futurator = futurize<std::result_of_t<Func()>>;
    typename futurator::promise_type _result;
public:
    lambda_task(scheduling_group sg, const Func& func) : task(sg), _func(func) {}
    lambda_task(scheduling_group sg, Func&& func) : task(sg), _func(std::move(func)) {}
    typename futurator::type get_future() { return _result.get_future(); }
    virtual void run_and_dispose() noexcept override {
        futurator::invoke(_func).forward_to(std::move(_result));
        delete this;
    }
    virtual task* waiting_task() noexcept override { return nullptr; }
};

template <typename Func>
inline
lambda_task<Func>*
make_task(Func&& func) noexcept {
    return new lambda_task<Func>(current_scheduling_group(), std::forward<Func>(func));
}

template <typename Func>
inline
lambda_task<Func>*
make_task(scheduling_group sg, Func&& func) noexcept {
    return new lambda_task<Func>(sg, std::forward<Func>(func));
}

}
<commit_msg>core/make_task: Implement lambda_task::waiting_task()<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) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include <memory>
#include <seastar/core/task.hh>
#include <seastar/core/future.hh>

namespace seastar {

template <typename Func>
class lambda_task final : public task {
    Func _func;
    using futurator = futurize<std::result_of_t<Func()>>;
    typename futurator::promise_type _result;
public:
    lambda_task(scheduling_group sg, const Func& func) : task(sg), _func(func) {}
    lambda_task(scheduling_group sg, Func&& func) : task(sg), _func(std::move(func)) {}
    typename futurator::type get_future() { return _result.get_future(); }
    virtual void run_and_dispose() noexcept override {
        futurator::invoke(_func).forward_to(std::move(_result));
        delete this;
    }
    virtual task* waiting_task() noexcept override {
        return _result.waiting_task();
    }
};

template <typename Func>
inline
lambda_task<Func>*
make_task(Func&& func) noexcept {
    return new lambda_task<Func>(current_scheduling_group(), std::forward<Func>(func));
}

template <typename Func>
inline
lambda_task<Func>*
make_task(scheduling_group sg, Func&& func) noexcept {
    return new lambda_task<Func>(sg, std::forward<Func>(func));
}

}
<|endoftext|>


<commit_before>#include <sirius.h>
#include <json.hpp>

using namespace sirius;
using json = nlohmann::json;

const std::string aiida_output_file = "output_aiida.json";

enum class task_t : int
{
    ground_state_new     = 0,
    ground_state_restart = 1,
    k_point_path         = 2
};

const double au2angs = 0.5291772108;

void json_output_common(json& dict__)
{
    dict__["git_hash"] = git_hash;
    dict__["build_date"] = build_date;
    dict__["comm_world_size"] = mpi_comm_world().size();
    dict__["threads_per_rank"] = omp_get_max_threads();
}

std::unique_ptr<Simulation_context> create_sim_ctx(std::string     fname__,
                                                   cmd_args const& args__)
{
    auto ctx_ptr = std::unique_ptr<Simulation_context>(new Simulation_context(fname__, mpi_comm_world()));
    Simulation_context& ctx = *ctx_ptr;

    auto& inp = ctx.parameters_input();
    if (inp.gamma_point_ && !(inp.ngridk_[0] * inp.ngridk_[1] * inp.ngridk_[2] == 1)) {
        TERMINATE("this is not a Gamma-point calculation")
    }

    auto mpi_grid_dims = args__.value<std::vector<int>>("mpi_grid", ctx.mpi_grid_dims());
    ctx.set_mpi_grid_dims(mpi_grid_dims);

    auto std_evp_solver_name = args__.value<std::string>("std_evp_solver_name", ctx.control().std_evp_solver_name_);
    ctx.set_std_evp_solver_name(std_evp_solver_name);

    auto gen_evp_solver_name = args__.value<std::string>("gen_evp_solver_name", ctx.control().gen_evp_solver_name_);
    ctx.set_gen_evp_solver_name(gen_evp_solver_name);

    auto pu = args__.value<std::string>("processing_unit", ctx.control().processing_unit_);
    if (pu == "") {
        #ifdef __GPU
        pu = "gpu";
        #else
        pu = "cpu";
        #endif
    }
    ctx.set_processing_unit(pu);

    return std::move(ctx_ptr);
}

double ground_state(Simulation_context& ctx,
                    task_t              task,
                    cmd_args const&     args,
                    int                 write_output)
{
    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    Potential potential(ctx);
    potential.allocate();

    Density density(ctx);
    density.allocate();

    Hamiltonian H(ctx, potential);

    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    auto& inp = ctx.parameters_input();

    K_point_set ks(ctx, inp.ngridk_, inp.shiftk_, ctx.use_symmetry());
    ks.initialize();

    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    std::string ref_file = args.value<std::string>("test_against", "");
    /* don't write output if we compare against the reference calculation */
    bool write_state = (ref_file.size() == 0);

    DFT_ground_state dft(ctx, H, density, ks);

    if (task == task_t::ground_state_restart) {
        if (!Utils::file_exists(storage_file_name)) {
            TERMINATE("storage file is not found");
        }
        density.load();
        potential.load();
    } else {
        density.initial_density();
        potential.generate(density);
        if (!ctx.full_potential()) {
            dft.band().initialize_subspace(ks, H);
        }
    }

    /* launch the calculation */
    int result = dft.find(inp.potential_tol_, inp.energy_tol_, inp.num_dft_iter_, write_state);

    dft.print_magnetic_moment();

    if (ref_file.size() != 0) {
        auto dict = dft.serialize();
        json dict_ref;
        std::ifstream(ref_file) >> dict_ref;

        double e1 = dict["energy"]["total"];
        double e2 = dict_ref["ground_state"]["energy"]["total"];

        if (std::abs(e1 - e2) > 1e-6) {
            printf("total energy is different: %18.7f computed vs. %18.7f reference\n", e1, e2);
            sirius::terminate(1);
        }
    }

    if (!ctx.full_potential()) {
        if (ctx.control().print_stress_) {
            Stress s(ctx, ks, density, potential);
            s.print_info();
        }
        if (ctx.control().print_forces_) {
            Force f(ctx, density, potential, ks);
            f.print_info();
        }
    }

    if (write_state && write_output) {
        json dict;
        json_output_common(dict);

        dict["task"] = static_cast<int>(task);
        dict["ground_state"] = dft.serialize();
        dict["timers"] = sddk::timer::serialize_timers();
        if (ctx.comm().rank() == 0) {
            std::ofstream ofs(std::string("output_") + ctx.start_time_tag() + std::string(".json"),
                              std::ofstream::out | std::ofstream::trunc);
            ofs << dict.dump(4);
        }

        if (args.exist("aiida_output")) {
            json dict;
            json_output_common(dict);
            dict["task"] = static_cast<int>(task);
            if (result >= 0) {
                dict["task_status"] = "converged";
                dict["num_scf_iterations"] =  result;
            } else {
                dict["task_status"] = "unconverged";
            }
            dict["volume"] = ctx.unit_cell().omega() * std::pow(au2angs, 3);
            dict["volume_units"] = "angstrom^3";
            dict["energy"] = dft.total_energy() * ha2ev;
            dict["energy_units"] = "eV";
            if (ctx.comm().rank() == 0) {
                std::ofstream ofs(aiida_output_file, std::ofstream::out | std::ofstream::trunc);
                ofs << dict.dump(4);
            }
        }
    }

    /* wait for all */
    ctx.comm().barrier();

    if (ctx.control().print_timers_ && ctx.comm().rank() == 0)  {
        sddk::timer::print();
    }

    return dft.total_energy();
}

/// Run a task based on a command line input.
void run_tasks(cmd_args const& args)
{
    /* get the task id */
    task_t task = static_cast<task_t>(args.value<int>("task", 0));
    /* get the input file name */
    std::string fname = args.value<std::string>("input", "sirius.json");
    if (!Utils::file_exists(fname)) {
        if (mpi_comm_world().rank() == 0) {
            printf("input file does not exist\n");
        }
        return;
    }

    if (task == task_t::ground_state_new || task == task_t::ground_state_restart) {
        auto ctx = create_sim_ctx(fname, args);
        ctx->initialize();
        ground_state(*ctx, task, args, 1);
    }

    if (task == task_t::k_point_path) {
        auto ctx = create_sim_ctx(fname, args);
        ctx->set_iterative_solver_tolerance(1e-12);
        ctx->set_gamma_point(false);
        ctx->initialize();

        Potential potential(*ctx);
        potential.allocate();

        Hamiltonian H(*ctx, potential);

        Density density(*ctx);
        density.allocate();

        K_point_set ks(*ctx);

        json inp;
        std::ifstream(fname) >> inp;

        /* list of pairs (label, k-point vector) */
        std::vector<std::pair<std::string, std::vector<double>>> vertex;

        auto labels = inp["kpoints_path"].get<std::vector<std::string>>();
        for (auto e: labels) {
            auto v = inp["kpoints_rel"][e].get<std::vector<double>>();
            vertex.push_back({e, v});
        }

        std::vector<double> x_axis;
        std::vector<std::pair<double, std::string>> x_ticks;

        /* first point */
        x_axis.push_back(0);
        x_ticks.push_back({0, vertex[0].first});
        ks.add_kpoint(&vertex[0].second[0], 1.0);

        double t{0};
        for (size_t i = 0; i < vertex.size() - 1; i++) {
            vector3d<double> v0 = vector3d<double>(vertex[i].second);
            vector3d<double> v1 = vector3d<double>(vertex[i + 1].second);
            vector3d<double> dv = v1 - v0;
            vector3d<double> dv_cart = ctx->unit_cell().reciprocal_lattice_vectors() * dv;
            int np = std::max(10, static_cast<int>(30 * dv_cart.length()));
            for (int j = 1; j <= np; j++) {
                vector3d<double> v = v0 + dv * static_cast<double>(j) / np;
                ks.add_kpoint(&v[0], 1.0);
                t += dv_cart.length() / np;
                x_axis.push_back(t);
            }
            x_ticks.push_back({t, vertex[i + 1].first});
        }

        ks.initialize();

        //density.initial_density();
        density.load();
        potential.generate(density);
        Band band(*ctx);
        if (!ctx->full_potential()) {
            band.initialize_subspace(ks, H);
            if (ctx->hubbard_correction()) {
                H.U().hubbard_compute_occupation_numbers(ks); // TODO: this is wrong; U matrix should come form the saved file
                H.U().calculate_hubbard_potential_and_energy();
            }
        }
        band.solve_for_kset(ks, H, true);

        ks.sync_band_energies();
        if (mpi_comm_world().rank() == 0) {
            json dict;
            dict["header"] = {};
            dict["header"]["x_axis"] = x_axis;
            dict["header"]["x_ticks"] = std::vector<json>();
            dict["header"]["num_bands"] = ctx->num_bands();
            for (auto& e: x_ticks) {
                json j;
                j["x"] = e.first;
                j["label"] = e.second;
                dict["header"]["x_ticks"].push_back(j);
            }
            dict["bands"] = std::vector<json>();

            std::vector<double> bnd_e(ctx->num_bands());

            for (int ik = 0; ik < ks.num_kpoints(); ik++) {
                json bnd_k;
                bnd_k["kpoint"] = std::vector<double>(3, 0);
                for (int x = 0; x < 3; x++) {
                    bnd_k["kpoint"][x] = ks[ik]->vk()[x];
                }
                ks.get_band_energies(ik, bnd_e.data());
                bnd_k["values"] = bnd_e;
                dict["bands"].push_back(bnd_k);
            }
            std::ofstream ofs("bands.json", std::ofstream::out | std::ofstream::trunc);
            ofs << dict.dump(4);
        }
    }
}

int main(int argn, char** argv)
{
    cmd_args args;
    args.register_key("--input=", "{string} input file name");
    args.register_key("--task=", "{int} task id");
    args.register_key("--mpi_grid=", "{vector int} MPI grid dimensions");
    args.register_key("--aiida_output", "write output for AiiDA");
    args.register_key("--test_against=", "{string} json file with reference values");
    args.register_key("--std_evp_solver_name=", "{string} standard eigen-value solver");
    args.register_key("--gen_evp_solver_name=", "{string} generalized eigen-value solver");
    args.register_key("--processing_unit=", "{string} type of the processing unit");

    args.parse_args(argn, argv);

    if (args.exist("help")) {
        printf("Usage: %s [options] \n", argv[0]);
        args.print_help();
        return 0;
    }

    sirius::initialize(1);

    run_tasks(args);

    sirius::finalize(1);
    return 0;
}
<commit_msg>some tests failing<commit_after>#include <sirius.h>
#include <json.hpp>

using namespace sirius;
using json = nlohmann::json;

const std::string aiida_output_file = "output_aiida.json";

enum class task_t : int
{
    ground_state_new     = 0,
    ground_state_restart = 1,
    k_point_path         = 2
};

const double au2angs = 0.5291772108;

void json_output_common(json& dict__)
{
    dict__["git_hash"] = git_hash;
    dict__["build_date"] = build_date;
    dict__["comm_world_size"] = mpi_comm_world().size();
    dict__["threads_per_rank"] = omp_get_max_threads();
}

std::unique_ptr<Simulation_context> create_sim_ctx(std::string     fname__,
                                                   cmd_args const& args__)
{
    auto ctx_ptr = std::unique_ptr<Simulation_context>(new Simulation_context(fname__, mpi_comm_world()));
    Simulation_context& ctx = *ctx_ptr;

    auto& inp = ctx.parameters_input();
    if (inp.gamma_point_ && !(inp.ngridk_[0] * inp.ngridk_[1] * inp.ngridk_[2] == 1)) {
        TERMINATE("this is not a Gamma-point calculation")
    }

    auto mpi_grid_dims = args__.value<std::vector<int>>("mpi_grid", ctx.mpi_grid_dims());
    ctx.set_mpi_grid_dims(mpi_grid_dims);

    auto std_evp_solver_name = args__.value<std::string>("std_evp_solver_name", ctx.control().std_evp_solver_name_);
    ctx.set_std_evp_solver_name(std_evp_solver_name);

    auto gen_evp_solver_name = args__.value<std::string>("gen_evp_solver_name", ctx.control().gen_evp_solver_name_);
    ctx.set_gen_evp_solver_name(gen_evp_solver_name);

    auto pu = args__.value<std::string>("processing_unit", ctx.control().processing_unit_);
    if (pu == "") {
        #ifdef __GPU
        pu = "gpu";
        #else
        pu = "cpu";
        #endif
    }
    ctx.set_processing_unit(pu);

    return std::move(ctx_ptr);
}

double ground_state(Simulation_context& ctx,
                    task_t              task,
                    cmd_args const&     args,
                    int                 write_output)
{
    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    Potential potential(ctx);
    potential.allocate();

    Density density(ctx);
    density.allocate();

    Hamiltonian H(ctx, potential);

    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    auto& inp = ctx.parameters_input();

    K_point_set ks(ctx, inp.ngridk_, inp.shiftk_, ctx.use_symmetry());
    ks.initialize();

    if (ctx.comm().rank() == 0 && ctx.control().print_memory_usage_) {
        MEMORY_USAGE_INFO();
    }

    std::string ref_file = args.value<std::string>("test_against", "");
    /* don't write output if we compare against the reference calculation */
    bool write_state = (ref_file.size() == 0);

    DFT_ground_state dft(ctx, H, density, ks);

    if (task == task_t::ground_state_restart) {
        if (!Utils::file_exists(storage_file_name)) {
            TERMINATE("storage file is not found");
        }
        density.load();
        potential.load();
    } else {
        density.initial_density();
        potential.generate(density);
        if (!ctx.full_potential()) {
            dft.band().initialize_subspace(ks, H);
        }
    }

    /* launch the calculation */
    int result = dft.find(inp.potential_tol_, inp.energy_tol_, inp.num_dft_iter_, write_state);

    dft.print_magnetic_moment();

    if (ref_file.size() != 0) {
        auto dict = dft.serialize();
        json dict_ref;
        std::ifstream(ref_file) >> dict_ref;

        double e1 = dict["energy"]["total"];
        double e2 = dict_ref["ground_state"]["energy"]["total"];

        if (std::abs(e1 - e2) > 1e-6) {
            printf("total energy is different: %18.7f computed vs. %18.7f reference\n", e1, e2);
            sirius::terminate(1);
        }
    }

    if (!ctx.full_potential()) {
        if (ctx.control().print_stress_) {
            Stress s(ctx, ks, density, potential);
            s.print_info();
        }
        if (ctx.control().print_forces_) {
            Force f(ctx, density, potential, ks);
            f.print_info();
        }
    }

    if (write_state && write_output) {
        json dict;
        json_output_common(dict);

        dict["task"] = static_cast<int>(task);
        dict["ground_state"] = dft.serialize();
        dict["timers"] = sddk::timer::serialize_timers();
        if (ctx.comm().rank() == 0) {
            std::ofstream ofs(std::string("output_") + ctx.start_time_tag() + std::string(".json"),
                              std::ofstream::out | std::ofstream::trunc);
            ofs << dict.dump(4);
        }

        if (args.exist("aiida_output")) {
            json dict;
            json_output_common(dict);
            dict["task"] = static_cast<int>(task);
            if (result >= 0) {
                dict["task_status"] = "converged";
                dict["num_scf_iterations"] =  result;
            } else {
                dict["task_status"] = "unconverged";
            }
            dict["volume"] = ctx.unit_cell().omega() * std::pow(au2angs, 3);
            dict["volume_units"] = "angstrom^3";
            dict["energy"] = dft.total_energy() * ha2ev;
            dict["energy_units"] = "eV";
            if (ctx.comm().rank() == 0) {
                std::ofstream ofs(aiida_output_file, std::ofstream::out | std::ofstream::trunc);
                ofs << dict.dump(4);
            }
        }
    }

    /* wait for all */
    ctx.comm().barrier();

    if (ctx.control().print_timers_ && ctx.comm().rank() == 0)  {
        sddk::timer::print();
    }

    return dft.total_energy();
}

/// Run a task based on a command line input.
void run_tasks(cmd_args const& args)
{
    /* get the task id */
    task_t task = static_cast<task_t>(args.value<int>("task", 0));
    /* get the input file name */
    std::string fname = args.value<std::string>("input", "sirius.json");
    if (!Utils::file_exists(fname)) {
        if (mpi_comm_world().rank() == 0) {
            printf("input file does not exist\n");
        }
        return;
    }

    if (task == task_t::ground_state_new || task == task_t::ground_state_restart) {
        auto ctx = create_sim_ctx(fname, args);
        ctx->initialize();
        ground_state(*ctx, task, args, 1);
    }

    if (task == task_t::k_point_path) {
        auto ctx = create_sim_ctx(fname, args);
        ctx->set_iterative_solver_tolerance(1e-12);
        ctx->set_gamma_point(false);
        ctx->initialize();

        Potential potential(*ctx);
        potential.allocate();

        Hamiltonian H(*ctx, potential);

        Density density(*ctx);
        density.allocate();

        K_point_set ks(*ctx);

        json inp;
        std::ifstream(fname) >> inp;

        /* list of pairs (label, k-point vector) */
        std::vector<std::pair<std::string, std::vector<double>>> vertex;

        auto labels = inp["kpoints_path"].get<std::vector<std::string>>();
        for (auto e: labels) {
            auto v = inp["kpoints_rel"][e].get<std::vector<double>>();
            vertex.push_back({e, v});
        }

        std::vector<double> x_axis;
        std::vector<std::pair<double, std::string>> x_ticks;

        /* first point */
        x_axis.push_back(0);
        x_ticks.push_back({0, vertex[0].first});
        ks.add_kpoint(&vertex[0].second[0], 1.0);

        double t{0};
        for (size_t i = 0; i < vertex.size() - 1; i++) {
            vector3d<double> v0 = vector3d<double>(vertex[i].second);
            vector3d<double> v1 = vector3d<double>(vertex[i + 1].second);
            vector3d<double> dv = v1 - v0;
            vector3d<double> dv_cart = ctx->unit_cell().reciprocal_lattice_vectors() * dv;
            int np = std::max(10, static_cast<int>(30 * dv_cart.length()));
            for (int j = 1; j <= np; j++) {
                vector3d<double> v = v0 + dv * static_cast<double>(j) / np;
                ks.add_kpoint(&v[0], 1.0);
                t += dv_cart.length() / np;
                x_axis.push_back(t);
            }
            x_ticks.push_back({t, vertex[i + 1].first});
        }

        ks.initialize();

        //density.initial_density();
        density.load();
        potential.generate(density);
        Band band(*ctx);
        if (!ctx->full_potential()) {
            band.initialize_subspace(ks, H);
            if (ctx->hubbard_correction()) {
                H.U().hubbard_compute_occupation_numbers(ks); // TODO: this is wrong; U matrix should come form the saved file
                H.U().calculate_hubbard_potential_and_energy();
            }
        }
        band.solve_for_kset(ks, H, true);

        ks.sync_band_energies();
        if (mpi_comm_world().rank() == 0) {
            json dict;
            dict["header"] = {};
            dict["header"]["x_axis"] = x_axis;
            dict["header"]["x_ticks"] = std::vector<json>();
            dict["header"]["num_bands"] = ctx->num_bands();
            for (auto& e: x_ticks) {
                json j;
                j["x"] = e.first;
                j["label"] = e.second;
                dict["header"]["x_ticks"].push_back(j);
            }
            dict["bands"] = std::vector<json>();

            std::vector<double> bnd_e(ctx->num_bands());

            for (int ik = 0; ik < ks.num_kpoints(); ik++) {
                json bnd_k;
                bnd_k["kpoint"] = std::vector<double>(3, 0);
                for (int x = 0; x < 3; x++) {
                    bnd_k["kpoint"][x] = ks[ik]->vk()[x];
                }
                //ks.get_band_energies(ik, bnd_e.data());
                //bnd_k["values"] = bnd_e;
                dict["bands"].push_back(bnd_k);
            }
            std::ofstream ofs("bands.json", std::ofstream::out | std::ofstream::trunc);
            ofs << dict.dump(4);
        }
    }
}

int main(int argn, char** argv)
{
    cmd_args args;
    args.register_key("--input=", "{string} input file name");
    args.register_key("--task=", "{int} task id");
    args.register_key("--mpi_grid=", "{vector int} MPI grid dimensions");
    args.register_key("--aiida_output", "write output for AiiDA");
    args.register_key("--test_against=", "{string} json file with reference values");
    args.register_key("--std_evp_solver_name=", "{string} standard eigen-value solver");
    args.register_key("--gen_evp_solver_name=", "{string} generalized eigen-value solver");
    args.register_key("--processing_unit=", "{string} type of the processing unit");

    args.parse_args(argn, argv);

    if (args.exist("help")) {
        printf("Usage: %s [options] \n", argv[0]);
        args.print_help();
        return 0;
    }

    sirius::initialize(1);

    run_tasks(args);

    sirius::finalize(1);
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#ifndef VCF2MULTIALIGN_VARIANT_HH
#define VCF2MULTIALIGN_VARIANT_HH

#include <experimental/string_view>
#include <vcf2multialign/types.hh>
#include <vcf2multialign/util.hh>
#include <vector>

// XXX Hack.
namespace std {
	using std::experimental::string_view;
}

namespace vcf2multialign {
	template <typename> class variant_tpl;
}

namespace vcf2multialign { namespace detail {

	template <typename t_string, typename t_other_string>
	struct variant_tpl_cmp
	{
		constexpr bool operator()(variant_tpl <t_string> const &, variant_tpl <t_other_string> const &) const { return false; }
	};

	template <typename t_string>
	struct variant_tpl_cmp <t_string, t_string>
	{
		bool operator()(variant_tpl <t_string> const &lhs, variant_tpl <t_string> const &rhs) const { return &lhs == &rhs; }
	};
}}

namespace vcf2multialign {

	class vcf_reader;
	class variant_base;

	struct genotype_field
	{
		std::size_t	alt{0};
		bool		is_phased{false};
	};

	class sample_field
	{
		friend class variant_base;

	public:
		typedef std::vector <genotype_field> genotype_vector;

	protected:
		genotype_vector	m_genotype;
		std::size_t		m_gt_count{0};

	public:

		std::size_t ploidy() const { return m_gt_count; }
		boost::iterator_range <genotype_vector::const_iterator> get_genotype() const;
	};

	class variant_base
	{
		friend class vcf_reader;

	protected:
		std::vector <sample_field>	m_samples;
		std::size_t					m_sample_count{0};
		std::size_t					m_pos{0};
		std::size_t					m_qual{0};
		std::size_t					m_lineno{0};

	public:
		variant_base(std::size_t sample_count):
			m_samples(1 + sample_count)
		{
		}

		variant_base(variant_base const &) = default;
		variant_base(variant_base &&) = default;
		variant_base &operator=(variant_base const &) & = default;
		variant_base &operator=(variant_base &&) & = default;

		virtual ~variant_base() {}

		void set_lineno(std::size_t const lineno) { m_lineno = lineno; }
		void set_pos(std::size_t const pos) { m_pos = pos; }
		void set_qual(std::size_t const qual) { m_qual = qual; }
		void set_gt(std::size_t const alt, std::size_t const sample, std::size_t const idx, bool const is_phased);
		void reset() { m_sample_count = 0; }	// Try to prevent unneeded deallocation.

		size_t lineno() const											{ return m_lineno; }
		size_t pos() const												{ return m_pos; };
		size_t zero_based_pos() const;
		sample_field const &sample(std::size_t const sample_idx) const	{ always_assert(sample_idx <= m_sample_count); return m_samples.at(sample_idx); }
	};

	template <typename t_string>
	class variant_tpl : public variant_base
	{
		friend class vcf_reader;

		template <typename>
		friend class variant_tpl;

	protected:
		std::vector <t_string>			m_alts;
		std::vector <t_string>			m_id;
		t_string						m_chrom_id;
		t_string						m_ref;

	protected:
		template <typename t_other_string>
		void copy_vectors(variant_tpl <t_other_string> const &other);

	public:
		variant_tpl(std::size_t sample_count = 0):
			variant_base(sample_count)
		{
		}

		template <typename t_other_string>
		variant_tpl(variant_tpl <t_other_string> const &other):
			variant_base(other),
			m_chrom_id(other.m_chrom_id),
			m_ref(other.m_ref)
		{
			copy_vectors(other);
		}

		template <typename t_other_string>
		bool operator==(variant_tpl <t_other_string> const &other) const;

		template <typename t_other_string>
		bool operator!=(variant_tpl <t_other_string> const &other) const { return !(*this == other); }

		template <typename t_other_string>
		variant_tpl &operator=(variant_tpl <t_other_string> const &other);

		std::vector <t_string> const &alts() const	{ return m_alts; }
		t_string const &ref() const					{ return m_ref; }

		void reset() { variant_base::reset(); m_alts.clear(); m_id.clear(); };
		void set_chrom_id(std::string_view const &chrom_id) { m_chrom_id = chrom_id; }
		void set_ref(std::string_view const &ref) { m_ref = ref; }
		void set_id(std::string_view const &id, std::size_t const pos);
		void set_alt(std::string_view const &alt, std::size_t const pos, bool const is_complex);
	};

	// Transient in the sense that strings point to the working
	// buffer of the reader.
	class transient_variant : public variant_tpl <std::string_view>
	{
		friend class vcf_reader;

	protected:
		typedef variant_tpl superclass;

	public:
		using variant_tpl::variant_tpl;
		void reset();
	};

	class variant : public variant_tpl <std::string>
	{
		friend class vcf_reader;

	protected:
		typedef variant_tpl superclass;

	public:
		using variant_tpl::variant_tpl;
		void reset();

		variant &operator=(transient_variant const &other) { variant_tpl::operator=(other); return *this; }
	};

	inline auto sample_field::get_genotype() const -> boost::iterator_range <genotype_vector::const_iterator>
	{
		auto const begin(m_genotype.cbegin());
		return boost::make_iterator_range(begin, begin + m_gt_count);
	}

	template <typename t_string>
	template <typename t_other_string>
	void variant_tpl <t_string>::copy_vectors(variant_tpl <t_other_string> const &other)
	{
		m_alts.clear();
		m_id.clear();
		m_alts.reserve(other.m_alts.size());
		m_id.reserve(other.m_id.size());

		for (auto const &alt : other.m_alts)
			m_alts.emplace_back(alt);

		for (auto const &id : other.m_id)
			m_id.emplace_back(id);
	}

	template <typename t_string>
	template <typename t_other_string>
	bool variant_tpl <t_string>::operator==(variant_tpl <t_other_string> const &other) const
	{
		detail::variant_tpl_cmp <t_string, t_other_string> cmp;
		return cmp(*this, other);
	}

	template <typename t_string>
	template <typename t_other_string>
	auto variant_tpl <t_string>::operator=(variant_tpl <t_other_string> const &other) -> variant_tpl &
	{
		if (*this != other)
		{
			variant_base::operator=(other);
			m_chrom_id.assign(other.m_chrom_id.cbegin(), other.m_chrom_id.cend());
			m_ref.assign(other.m_ref.cbegin(), other.m_ref.cend());
			copy_vectors(other);
		}
		return *this;
	}

	template <typename t_string>
	void variant_tpl <t_string>::set_id(std::string_view const &id, std::size_t const pos)
	{
		if (! (pos < m_id.size()))
			m_id.resize(pos + 1);

		m_id[pos] = id;
	}

	template <typename t_string>
	void variant_tpl <t_string>::set_alt(std::string_view const &alt, std::size_t const pos, bool const is_complex)
	{
		always_assert(is_complex, "Only simple ALTs are handled");

		if (! (pos < m_alts.size()))
			m_alts.resize(pos + 1);

		m_alts[pos] = alt;
	}
}

#endif
<commit_msg>Fix an assertion<commit_after>/*
 * Copyright (c) 2017 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#ifndef VCF2MULTIALIGN_VARIANT_HH
#define VCF2MULTIALIGN_VARIANT_HH

#include <experimental/string_view>
#include <vcf2multialign/types.hh>
#include <vcf2multialign/util.hh>
#include <vector>

// XXX Hack.
namespace std {
	using std::experimental::string_view;
}

namespace vcf2multialign {
	template <typename> class variant_tpl;
}

namespace vcf2multialign { namespace detail {

	template <typename t_string, typename t_other_string>
	struct variant_tpl_cmp
	{
		constexpr bool operator()(variant_tpl <t_string> const &, variant_tpl <t_other_string> const &) const { return false; }
	};

	template <typename t_string>
	struct variant_tpl_cmp <t_string, t_string>
	{
		bool operator()(variant_tpl <t_string> const &lhs, variant_tpl <t_string> const &rhs) const { return &lhs == &rhs; }
	};
}}

namespace vcf2multialign {

	class vcf_reader;
	class variant_base;

	struct genotype_field
	{
		std::size_t	alt{0};
		bool		is_phased{false};
	};

	class sample_field
	{
		friend class variant_base;

	public:
		typedef std::vector <genotype_field> genotype_vector;

	protected:
		genotype_vector	m_genotype;
		std::size_t		m_gt_count{0};

	public:

		std::size_t ploidy() const { return m_gt_count; }
		boost::iterator_range <genotype_vector::const_iterator> get_genotype() const;
	};

	class variant_base
	{
		friend class vcf_reader;

	protected:
		std::vector <sample_field>	m_samples;
		std::size_t					m_sample_count{0};
		std::size_t					m_pos{0};
		std::size_t					m_qual{0};
		std::size_t					m_lineno{0};

	public:
		variant_base(std::size_t sample_count):
			m_samples(1 + sample_count)
		{
		}

		variant_base(variant_base const &) = default;
		variant_base(variant_base &&) = default;
		variant_base &operator=(variant_base const &) & = default;
		variant_base &operator=(variant_base &&) & = default;

		virtual ~variant_base() {}

		void set_lineno(std::size_t const lineno) { m_lineno = lineno; }
		void set_pos(std::size_t const pos) { m_pos = pos; }
		void set_qual(std::size_t const qual) { m_qual = qual; }
		void set_gt(std::size_t const alt, std::size_t const sample, std::size_t const idx, bool const is_phased);
		void reset() { m_sample_count = 0; }	// Try to prevent unneeded deallocation.

		size_t lineno() const											{ return m_lineno; }
		size_t pos() const												{ return m_pos; };
		size_t zero_based_pos() const;
		sample_field const &sample(std::size_t const sample_idx) const	{ always_assert(sample_idx <= m_sample_count); return m_samples.at(sample_idx); }
	};

	template <typename t_string>
	class variant_tpl : public variant_base
	{
		friend class vcf_reader;

		template <typename>
		friend class variant_tpl;

	protected:
		std::vector <t_string>			m_alts;
		std::vector <t_string>			m_id;
		t_string						m_chrom_id;
		t_string						m_ref;

	protected:
		template <typename t_other_string>
		void copy_vectors(variant_tpl <t_other_string> const &other);

	public:
		variant_tpl(std::size_t sample_count = 0):
			variant_base(sample_count)
		{
		}

		template <typename t_other_string>
		variant_tpl(variant_tpl <t_other_string> const &other):
			variant_base(other),
			m_chrom_id(other.m_chrom_id),
			m_ref(other.m_ref)
		{
			copy_vectors(other);
		}

		template <typename t_other_string>
		bool operator==(variant_tpl <t_other_string> const &other) const;

		template <typename t_other_string>
		bool operator!=(variant_tpl <t_other_string> const &other) const { return !(*this == other); }

		template <typename t_other_string>
		variant_tpl &operator=(variant_tpl <t_other_string> const &other);

		std::vector <t_string> const &alts() const	{ return m_alts; }
		t_string const &ref() const					{ return m_ref; }

		void reset() { variant_base::reset(); m_alts.clear(); m_id.clear(); };
		void set_chrom_id(std::string_view const &chrom_id) { m_chrom_id = chrom_id; }
		void set_ref(std::string_view const &ref) { m_ref = ref; }
		void set_id(std::string_view const &id, std::size_t const pos);
		void set_alt(std::string_view const &alt, std::size_t const pos, bool const is_complex);
	};

	// Transient in the sense that strings point to the working
	// buffer of the reader.
	class transient_variant : public variant_tpl <std::string_view>
	{
		friend class vcf_reader;

	protected:
		typedef variant_tpl superclass;

	public:
		using variant_tpl::variant_tpl;
		void reset();
	};

	class variant : public variant_tpl <std::string>
	{
		friend class vcf_reader;

	protected:
		typedef variant_tpl superclass;

	public:
		using variant_tpl::variant_tpl;
		void reset();

		variant &operator=(transient_variant const &other) { variant_tpl::operator=(other); return *this; }
	};

	inline auto sample_field::get_genotype() const -> boost::iterator_range <genotype_vector::const_iterator>
	{
		auto const begin(m_genotype.cbegin());
		return boost::make_iterator_range(begin, begin + m_gt_count);
	}

	template <typename t_string>
	template <typename t_other_string>
	void variant_tpl <t_string>::copy_vectors(variant_tpl <t_other_string> const &other)
	{
		m_alts.clear();
		m_id.clear();
		m_alts.reserve(other.m_alts.size());
		m_id.reserve(other.m_id.size());

		for (auto const &alt : other.m_alts)
			m_alts.emplace_back(alt);

		for (auto const &id : other.m_id)
			m_id.emplace_back(id);
	}

	template <typename t_string>
	template <typename t_other_string>
	bool variant_tpl <t_string>::operator==(variant_tpl <t_other_string> const &other) const
	{
		detail::variant_tpl_cmp <t_string, t_other_string> cmp;
		return cmp(*this, other);
	}

	template <typename t_string>
	template <typename t_other_string>
	auto variant_tpl <t_string>::operator=(variant_tpl <t_other_string> const &other) -> variant_tpl &
	{
		if (*this != other)
		{
			variant_base::operator=(other);
			m_chrom_id.assign(other.m_chrom_id.cbegin(), other.m_chrom_id.cend());
			m_ref.assign(other.m_ref.cbegin(), other.m_ref.cend());
			copy_vectors(other);
		}
		return *this;
	}

	template <typename t_string>
	void variant_tpl <t_string>::set_id(std::string_view const &id, std::size_t const pos)
	{
		if (! (pos < m_id.size()))
			m_id.resize(pos + 1);

		m_id[pos] = id;
	}

	template <typename t_string>
	void variant_tpl <t_string>::set_alt(std::string_view const &alt, std::size_t const pos, bool const is_complex)
	{
		always_assert(!is_complex, "Only simple ALTs are handled");

		if (! (pos < m_alts.size()))
			m_alts.resize(pos + 1);

		m_alts[pos] = alt;
	}
}

#endif
<|endoftext|>


<commit_before>#include "extconfig.h"
#include <utility>
#include <Eigen/Cholesky>
#include <cmath>

/*
 * Member function definitions of TSEncoder template class.
 * See tsencoder.h for template class declaration.
 */

template <size_t M, size_t N, size_t O>
TSEncoder<M, N, O>::TSEncoder(const TSEncoderConfig& config) :
    m_events(),
    m_event_index(0),
    m_skip_order_counter(0),
    m_A(decltype(m_A)::Ones()), /* elements in last column of time stamp matrix are always 1 */
    m_P(decltype(m_P)::Zero()),
    m_B(decltype(m_B)::Zero()),
    m_T(decltype(m_T)::Ones()), /* last element of time vector is always 1 */
    m_t0(0),
    m_alpha(0.0),
    m_config(config),
    m_count(0),
    m_tc(0.0),
    m_state(state_t::STOP),
    m_index(index_t::NONE),
    m_position_result(position_result_t::NONE) { }

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::start() {
    chSysLock();
    osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE),
            "invalid state");
    if (extp->state == EXT_STOP) {
        extStartI(extp);
    }
    extChannelEnableSetModeI(extp, m_config.a, EXT_CH_MODE_BOTH_EDGES, ab_callback, this);
    extChannelEnableSetModeI(extp, m_config.b, EXT_CH_MODE_BOTH_EDGES, ab_callback, this);
    if (m_config.z == PAL_NOLINE) {
        m_index = index_t::NONE;
    } else {
        extChannelEnableSetModeI(extp, m_config.z, EXT_CH_MODE_RISING_EDGE, index_callback, this);
        m_index = index_t::NOTFOUND;
    }
    m_state = state_t::READY;
    chVTSetI(&m_event_deadline_timer, m_event_deadline, add_event_callback, reinterpret_cast<void*>(this));
    chSysUnlock();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::stop() {
    chSysLock();
    m_state = state_t::STOP;
    m_index = index_t::NONE;
    m_position_result = position_result_t::NONE;

    extChannelDisableClearModeI(extp, PAL_PAD(m_config.a));
    extChannelDisableClearModeI(extp, PAL_PAD(m_config.b));
    if (m_config.z != PAL_NOLINE) {
        extChannelDisableClearModeI(extp, PAL_PAD(m_config.z));
    }
    extStopIfChannelsDisabledI(extp);
    chVTResetI(&m_event_deadline_timer);
    chSysUnlock();
}

template <size_t M, size_t N, size_t O>
typename TSEncoder<M, N, O>::state_t TSEncoder<M, N, O>::state() const {
    return m_state;
}

template <size_t M, size_t N, size_t O>
typename TSEncoder<M, N, O>::index_t TSEncoder<M, N, O>::index() const volatile {
    return m_index;
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::update_polynomial_fit() {
    /*
     * Redefine oldest event to be at time zero. Scale time so that difference
     * in time from oldest to newest event is equal to 1.
     *
     * If the difference A(N - 1, 1) - A(0, 1) is too large, the value will be
     * nonsensical due to uint rolling back to zero. The difference must also
     * be less than int32_t_max as these values will be cast from uint32_t to
     * int32_t.
     */
    m_t0 = m_events[(m_event_index + 1) % N].first;
    m_alpha = 1.0f / (m_events[m_event_index].first - m_t0);
    for (unsigned int i = 0; i < N; ++i) {
        m_A(i, M - 1) = m_alpha * (m_events[(m_event_index + i + 1) % N].first - m_t0);
        m_B(i) = m_events[(m_event_index + i + 1) % N].second;
    }
    for (unsigned int i = 0; i < M - 1; ++i) {
        m_A.col(M - 2 - i) = m_A.col(M - 1 - i).cwiseProduct(m_A.col(M - 1));
    }
    m_P.noalias() = (m_A.transpose() * m_A).ldlt().solve(
            (m_A.transpose() * m_B.template cast<polycoeff_t>()));
    m_position_result = position_result_t::NONE;
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::update_estimate_time(rtcnt_t tc) {
    m_tc = tc;
    polycoeff_t tcf = m_alpha * static_cast<polycoeff_t>(tc - m_t0);
    m_T(M - 1) = tcf;
    for (unsigned int i = 0; i < M - 1; ++i) {
        m_T(M - 2 - i) = m_T(M - 1 - i) * tcf;
    }
    m_position_result = position_result_t::NONE;
}

template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::position() const {
    polycoeff_t x = m_P.transpose() * m_T;
    polycoeff_t count = static_cast<polycoeff_t>(m_count);
    if (std::abs(x - count) > 1.0f) {
        m_position_result = position_result_t::ADJUSTED;
        return count;
    }
    m_position_result = position_result_t::ESTIMATED;
    return x;
}

// TODO: Validity of velocity and acceleration for large error in estimated
// position (i.e. position is adjusted if a large amount of time passes without
// an encoder event).
template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::velocity() const {
    if (m_position_result == position_result_t::NONE) {
        position();
    }
    if (m_position_result == position_result_t::ADJUSTED) {
        return static_cast<polycoeff_t>(0.0);
    }
    Eigen::Matrix<tsenccnt_t, M, 1> velocity_coefficients;
    for (unsigned int i = 0; i < M; ++i) {
        velocity_coefficients(i) = M - i;
    }
    return velocity_coefficients.template cast<polycoeff_t>().cwiseProduct(
            m_P.template head<M>()).transpose() * m_T.template tail<M>();
}

template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::acceleration() const {
    if (m_position_result == position_result_t::NONE) {
        position();
    }
    if (m_position_result == position_result_t::ADJUSTED) {
        return static_cast<polycoeff_t>(0.0);
    }
    Eigen::Matrix<tsenccnt_t, M - 1 , 1> acceleration_coefficients;
    for (unsigned int i = 0; i < M - 1; ++i) {
        acceleration_coefficients(i) = (M - i) * (M - i - 1);
    }
    return acceleration_coefficients.template cast<polycoeff_t>().cwiseProduct(
            m_P.template head<M - 1>()).transpose() * m_T.template tail<M - 1>();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::ab_callback(EXTDriver* extp, expchannel_t channel) {
    (void)extp;
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(extGetChannelCallbackObject(channel));
    if (((channel == PAL_PAD(enc->m_config.a)) &&
                (palReadLine(enc->m_config.a) != palReadLine(enc->m_config.b))) ||
        ((channel == PAL_PAD(enc->m_config.b)) &&
                (palReadLine(enc->m_config.a) == palReadLine(enc->m_config.b)))) {
        ++enc->m_count;
    } else {
        --enc->m_count;
    }
    enc->add_event(chSysGetRealtimeCounterX(), enc->m_count, true);
    chVTSetI(&enc->m_event_deadline_timer, enc->m_event_deadline, add_event_callback, reinterpret_cast<void*>(enc));
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::index_callback(EXTDriver* extp, expchannel_t channel) {
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(extGetChannelCallbackObject(channel));
    enc->m_count = 0;
    enc->m_index = index_t::FOUND;
    extChannelDisableClearModeI(extp, PAL_PAD(enc->m_config.z));
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_event_callback(void* p) {
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(p);
    enc->add_deadline_event();
    chVTSetI(&enc->m_event_deadline_timer, enc->m_event_deadline, add_event_callback, p);
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_event(rtcnt_t t, tsenccnt_t x, bool use_skip) const {
    chDbgCheckClassI();
    m_events[m_event_index] = std::make_pair(t, x);
    if (use_skip) {
        if (++m_skip_order_counter >= O) {
            m_skip_order_counter = 0;
        }
    } else {
        m_skip_order_counter = 0;
    }
    if (m_skip_order_counter == 0) {
        if (++m_event_index >= N) {
            m_event_index = 0;
        }
    }
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_deadline_event() const {
    add_event(chSysGetRealtimeCounterX(), m_count, false);
}
<commit_msg>Lock access to event buffer during A, B calculations<commit_after>#include "extconfig.h"
#include <utility>
#include <Eigen/Cholesky>
#include <cmath>

/*
 * Member function definitions of TSEncoder template class.
 * See tsencoder.h for template class declaration.
 */

template <size_t M, size_t N, size_t O>
TSEncoder<M, N, O>::TSEncoder(const TSEncoderConfig& config) :
    m_events(),
    m_event_index(0),
    m_skip_order_counter(0),
    m_A(decltype(m_A)::Ones()), /* elements in last column of time stamp matrix are always 1 */
    m_P(decltype(m_P)::Zero()),
    m_B(decltype(m_B)::Zero()),
    m_T(decltype(m_T)::Ones()), /* last element of time vector is always 1 */
    m_t0(0),
    m_alpha(0.0),
    m_config(config),
    m_count(0),
    m_tc(0.0),
    m_state(state_t::STOP),
    m_index(index_t::NONE),
    m_position_result(position_result_t::NONE) { }

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::start() {
    chSysLock();
    osalDbgAssert((extp->state == EXT_STOP) || (extp->state == EXT_ACTIVE),
            "invalid state");
    if (extp->state == EXT_STOP) {
        extStartI(extp);
    }
    extChannelEnableSetModeI(extp, m_config.a, EXT_CH_MODE_BOTH_EDGES, ab_callback, this);
    extChannelEnableSetModeI(extp, m_config.b, EXT_CH_MODE_BOTH_EDGES, ab_callback, this);
    if (m_config.z == PAL_NOLINE) {
        m_index = index_t::NONE;
    } else {
        extChannelEnableSetModeI(extp, m_config.z, EXT_CH_MODE_RISING_EDGE, index_callback, this);
        m_index = index_t::NOTFOUND;
    }
    m_state = state_t::READY;
    chVTSetI(&m_event_deadline_timer, m_event_deadline, add_event_callback, reinterpret_cast<void*>(this));
    chSysUnlock();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::stop() {
    chSysLock();
    m_state = state_t::STOP;
    m_index = index_t::NONE;
    m_position_result = position_result_t::NONE;

    extChannelDisableClearModeI(extp, PAL_PAD(m_config.a));
    extChannelDisableClearModeI(extp, PAL_PAD(m_config.b));
    if (m_config.z != PAL_NOLINE) {
        extChannelDisableClearModeI(extp, PAL_PAD(m_config.z));
    }
    extStopIfChannelsDisabledI(extp);
    chVTResetI(&m_event_deadline_timer);
    chSysUnlock();
}

template <size_t M, size_t N, size_t O>
typename TSEncoder<M, N, O>::state_t TSEncoder<M, N, O>::state() const {
    return m_state;
}

template <size_t M, size_t N, size_t O>
typename TSEncoder<M, N, O>::index_t TSEncoder<M, N, O>::index() const volatile {
    return m_index;
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::update_polynomial_fit() {
    /*
     * Redefine oldest event to be at time zero. Scale time so that difference
     * in time from oldest to newest event is equal to 1.
     *
     * If the difference A(N - 1, 1) - A(0, 1) is too large, the value will be
     * nonsensical due to uint rolling back to zero. The difference must also
     * be less than int32_t_max as these values will be cast from uint32_t to
     * int32_t.
     */
    chSysLock();
    m_t0 = m_events[(m_event_index + 1) % N].first;
    m_alpha = 1.0f / (m_events[m_event_index].first - m_t0);
    for (unsigned int i = 0; i < N; ++i) {
        m_A(i, M - 1) = m_alpha * (m_events[(m_event_index + i + 1) % N].first - m_t0);
        m_B(i) = m_events[(m_event_index + i + 1) % N].second;
    }
    chSysUnlock();
    for (unsigned int i = 0; i < M - 1; ++i) {
        m_A.col(M - 2 - i) = m_A.col(M - 1 - i).cwiseProduct(m_A.col(M - 1));
    }
    m_P.noalias() = (m_A.transpose() * m_A).ldlt().solve(
            (m_A.transpose() * m_B.template cast<polycoeff_t>()));
    m_position_result = position_result_t::NONE;
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::update_estimate_time(rtcnt_t tc) {
    m_tc = tc;
    polycoeff_t tcf = m_alpha * static_cast<polycoeff_t>(tc - m_t0);
    chDbgAssert(tcf > 1.0f, "tcf should always be ahead of last prediction");
    m_T(M - 1) = tcf;
    for (unsigned int i = 0; i < M - 1; ++i) {
        m_T(M - 2 - i) = m_T(M - 1 - i) * tcf;
    }
    m_position_result = position_result_t::NONE;
}

template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::position() const {
    polycoeff_t x = m_P.transpose() * m_T;
    polycoeff_t count = static_cast<polycoeff_t>(m_count);
    if (std::abs(x - count) > 1.0f) {
        m_position_result = position_result_t::ADJUSTED;
        return count;
    }
    m_position_result = position_result_t::ESTIMATED;
    return x;
}

// TODO: Validity of velocity and acceleration for large error in estimated
// position (i.e. position is adjusted if a large amount of time passes without
// an encoder event).
template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::velocity() const {
    if (m_position_result == position_result_t::NONE) {
        position();
    }
    if (m_position_result == position_result_t::ADJUSTED) {
        return static_cast<polycoeff_t>(0.0);
    }
    Eigen::Matrix<tsenccnt_t, M, 1> velocity_coefficients;
    for (unsigned int i = 0; i < M; ++i) {
        velocity_coefficients(i) = M - i;
    }
    return velocity_coefficients.template cast<polycoeff_t>().cwiseProduct(
            m_P.template head<M>()).transpose() * m_T.template tail<M>();
}

template <size_t M, size_t N, size_t O>
polycoeff_t TSEncoder<M, N, O>::acceleration() const {
    if (m_position_result == position_result_t::NONE) {
        position();
    }
    if (m_position_result == position_result_t::ADJUSTED) {
        return static_cast<polycoeff_t>(0.0);
    }
    Eigen::Matrix<tsenccnt_t, M - 1 , 1> acceleration_coefficients;
    for (unsigned int i = 0; i < M - 1; ++i) {
        acceleration_coefficients(i) = (M - i) * (M - i - 1);
    }
    return acceleration_coefficients.template cast<polycoeff_t>().cwiseProduct(
            m_P.template head<M - 1>()).transpose() * m_T.template tail<M - 1>();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::ab_callback(EXTDriver* extp, expchannel_t channel) {
    (void)extp;
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(extGetChannelCallbackObject(channel));
    if (((channel == PAL_PAD(enc->m_config.a)) &&
                (palReadLine(enc->m_config.a) != palReadLine(enc->m_config.b))) ||
        ((channel == PAL_PAD(enc->m_config.b)) &&
                (palReadLine(enc->m_config.a) == palReadLine(enc->m_config.b)))) {
        ++enc->m_count;
    } else {
        --enc->m_count;
    }
    enc->add_event(chSysGetRealtimeCounterX(), enc->m_count, true);
    chVTSetI(&enc->m_event_deadline_timer, enc->m_event_deadline, add_event_callback, reinterpret_cast<void*>(enc));
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::index_callback(EXTDriver* extp, expchannel_t channel) {
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(extGetChannelCallbackObject(channel));
    enc->m_count = 0;
    enc->m_index = index_t::FOUND;
    extChannelDisableClearModeI(extp, PAL_PAD(enc->m_config.z));
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_event_callback(void* p) {
    chSysLockFromISR();
    TSEncoder<M, N, O>* enc = reinterpret_cast<TSEncoder<M, N, O>*>(p);
    enc->add_deadline_event();
    chVTSetI(&enc->m_event_deadline_timer, enc->m_event_deadline, add_event_callback, p);
    chSysUnlockFromISR();
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_event(rtcnt_t t, tsenccnt_t x, bool use_skip) const {
    chDbgCheckClassI();
    m_events[m_event_index] = std::make_pair(t, x);
    if (use_skip) {
        if (++m_skip_order_counter >= O) {
            m_skip_order_counter = 0;
        }
    } else {
        m_skip_order_counter = 0;
    }
    if (m_skip_order_counter == 0) {
        if (++m_event_index >= N) {
            m_event_index = 0;
        }
    }
}

template <size_t M, size_t N, size_t O>
void TSEncoder<M, N, O>::add_deadline_event() const {
    add_event(chSysGetRealtimeCounterX(), m_count, false);
}
<|endoftext|>