<commit_before>from sympy.parsing.maxima import parse_maxima
from sympy import Rational, Abs, Symbol, sin, cos, E, oo, log, factorial
from sympy.abc import x

n = Symbol('n', integer=True)

def test_parser():
    assert Abs(parse_maxima('float(1/3)') - 0.333333333) < 10**(-5)
    assert parse_maxima('13^26') == 91733330193268616658399616009
    assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3, 2)
    assert parse_maxima('log(%e)') == 1

def test_injection():
    parse_maxima('c: x+1', globals=globals())
    assert c == x + 1

    parse_maxima('g: sqrt(81)', globals=globals())
    assert g == 9

def test_maxima_functions():
    assert parse_maxima('expand( (x+1)^2)') == x**2 + 2*x + 1
    assert parse_maxima('factor( x**2 + 2*x + 1)') == (x + 1)**2
    assert parse_maxima('trigsimp(2*cos(x)^2 + sin(x)^2)') == 1 + cos(x)**2
    assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == \
        -1 + 2*cos(x)**2 + 2*cos(x)*sin(x)
    assert parse_maxima('solve(x^2-4,x)') == [-2, 2]
    assert parse_maxima('limit((1+1/x)^x,x,inf)') == E
    assert parse_maxima('limit(sqrt(-x)/x,x,0,minus)') == -oo
    assert parse_maxima('diff(x^x, x)') == x**x*(1 + log(x))
    assert parse_maxima('sum(k, k, 1, n)', name_dict=dict(
        n=Symbol('n', integer=True),
        k=Symbol('k', integer=True)
    )) == (n**2 + n)/2
    assert parse_maxima('product(k, k, 1, n)', name_dict=dict(
        n=Symbol('n', integer=True),
        k=Symbol('k', integer=True)
    )) == factorial(n)
    assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x - 1
    assert Abs( parse_maxima(
        'float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5)
<commit_msg>modify maxima test to not depend on trigsimp<commit_after>from sympy.parsing.maxima import parse_maxima
from sympy import Rational, Abs, Symbol, sin, cos, E, oo, log, factorial
from sympy.abc import x

n = Symbol('n', integer=True)

def test_parser():
    assert Abs(parse_maxima('float(1/3)') - 0.333333333) < 10**(-5)
    assert parse_maxima('13^26') == 91733330193268616658399616009
    assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3, 2)
    assert parse_maxima('log(%e)') == 1

def test_injection():
    parse_maxima('c: x+1', globals=globals())
    assert c == x + 1

    parse_maxima('g: sqrt(81)', globals=globals())
    assert g == 9

def test_maxima_functions():
    assert parse_maxima('expand( (x+1)^2)') == x**2 + 2*x + 1
    assert parse_maxima('factor( x**2 + 2*x + 1)') == (x + 1)**2
    assert parse_maxima('2*cos(x)^2 + sin(x)^2') == 2*cos(x)**2 + sin(x)**2
    assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == \
        -1 + 2*cos(x)**2 + 2*cos(x)*sin(x)
    assert parse_maxima('solve(x^2-4,x)') == [-2, 2]
    assert parse_maxima('limit((1+1/x)^x,x,inf)') == E
    assert parse_maxima('limit(sqrt(-x)/x,x,0,minus)') == -oo
    assert parse_maxima('diff(x^x, x)') == x**x*(1 + log(x))
    assert parse_maxima('sum(k, k, 1, n)', name_dict=dict(
        n=Symbol('n', integer=True),
        k=Symbol('k', integer=True)
    )) == (n**2 + n)/2
    assert parse_maxima('product(k, k, 1, n)', name_dict=dict(
        n=Symbol('n', integer=True),
        k=Symbol('k', integer=True)
    )) == factorial(n)
    assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x - 1
    assert Abs( parse_maxima(
        'float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5)
<|endoftext|>


<commit_before>import os
from datetime import datetime, timedelta
from django.test import TestCase
from couchforms.signals import xform_archived, xform_unarchived

from corehq.form_processor.interfaces.processor import FormProcessorInterface
from corehq.form_processor.test_utils import FormProcessorTestUtils, run_with_all_backends
from corehq.util.test_utils import TestFileMixin

class TestFormArchiving(TestCase, TestFileMixin):
    file_path = ('data', 'sample_xforms')
    root = os.path.dirname(__file__)

    def setUp(self):
        self.interface = FormProcessorInterface('test-domain')

    def tearDown(self):
        FormProcessorTestUtils.delete_all_xforms()
        FormProcessorTestUtils.delete_all_cases()

    @run_with_all_backends
    def testArchive(self):
        xml_data = self.get_xml('basic')
        response, xform, cases = self.interface.submit_form_locally(
            xml_data,
            'test-domain',
        )

        self.assertTrue(xform.is_normal)
        self.assertEqual(0, len(xform.history))

        lower_bound = datetime.utcnow() - timedelta(seconds=1)
        xform.archive(user='mr. librarian')
        upper_bound = datetime.utcnow() + timedelta(seconds=1)

        xform = self.interface.xform_model.get(xform.form_id)
        self.assertTrue(xform.is_archived)

        [archival] = xform.history
        self.assertTrue(lower_bound <= archival.date <= upper_bound)
        self.assertEqual('archive', archival.operation)
        self.assertEqual('mr. librarian', archival.user)

        lower_bound = datetime.utcnow() - timedelta(seconds=1)
        xform.unarchive(user='mr. researcher')
        upper_bound = datetime.utcnow() + timedelta(seconds=1)

        xform = self.interface.xform_model.get(xform.form_id)
        self.assertTrue(xform.is_normal)

        [archival, restoration] = xform.history
        self.assertTrue(lower_bound <= restoration.date <= upper_bound)
        self.assertEqual('unarchive', restoration.operation)
        self.assertEqual('mr. researcher', restoration.user)

    def testSignal(self):
        global archive_counter, restore_counter
        archive_counter = 0
        restore_counter = 0

        def count_archive(**kwargs):
            global archive_counter
            archive_counter += 1

        def count_unarchive(**kwargs):
            global restore_counter
            restore_counter += 1

        xform_archived.connect(count_archive)
        xform_unarchived.connect(count_unarchive)

        xml_data = self.get_xml('basic')
        response, xform, cases = self.interface.submit_form_locally(
            xml_data,
            'test-domain',
        )

        self.assertEqual(0, archive_counter)
        self.assertEqual(0, restore_counter)

        xform.archive()
        self.assertEqual(1, archive_counter)
        self.assertEqual(0, restore_counter)

        xform.unarchive()
        self.assertEqual(1, archive_counter)
        self.assertEqual(1, restore_counter)
<commit_msg>update archive tests<commit_after>import os
from datetime import datetime, timedelta
from django.test import TestCase
from couchforms.signals import xform_archived, xform_unarchived

from corehq.form_processor.interfaces.processor import FormProcessorInterface
from corehq.form_processor.test_utils import FormProcessorTestUtils, run_with_all_backends
from corehq.util.test_utils import TestFileMixin

class TestFormArchiving(TestCase, TestFileMixin):
    file_path = ('data', 'sample_xforms')
    root = os.path.dirname(__file__)

    def setUp(self):
        self.interface = FormProcessorInterface('test-domain')

    def tearDown(self):
        FormProcessorTestUtils.delete_all_xforms()
        FormProcessorTestUtils.delete_all_cases()

    @run_with_all_backends
    def testArchive(self):
        case_id = 'ddb8e2b3-7ce0-43e4-ad45-d7a2eebe9169'
        xml_data = self.get_xml('basic')
        response, xform, cases = self.interface.submit_form_locally(
            xml_data,
            'test-domain',
        )

        self.assertTrue(xform.is_normal)
        self.assertEqual(0, len(xform.history))

        lower_bound = datetime.utcnow() - timedelta(seconds=1)
        xform.archive(user='mr. librarian')
        upper_bound = datetime.utcnow() + timedelta(seconds=1)

        xform = self.interface.xform_model.get(xform.form_id)
        self.assertTrue(xform.is_archived)
        case = self.interface.case_model.get(case_id)
        self.assertTrue(case.is_deleted)
        self.assertEqual(case.xform_ids, [])

        [archival] = xform.history
        self.assertTrue(lower_bound <= archival.date <= upper_bound)
        self.assertEqual('archive', archival.operation)
        self.assertEqual('mr. librarian', archival.user)

        lower_bound = datetime.utcnow() - timedelta(seconds=1)
        xform.unarchive(user='mr. researcher')
        upper_bound = datetime.utcnow() + timedelta(seconds=1)

        xform = self.interface.xform_model.get(xform.form_id)
        self.assertTrue(xform.is_normal)
        case = self.interface.case_model.get(case_id)
        self.assertFalse(case.is_deleted)
        self.assertEqual(case.xform_ids, [xform.form_id])

        [archival, restoration] = xform.history
        self.assertTrue(lower_bound <= restoration.date <= upper_bound)
        self.assertEqual('unarchive', restoration.operation)
        self.assertEqual('mr. researcher', restoration.user)

    @run_with_all_backends
    def testSignal(self):
        global archive_counter, restore_counter
        archive_counter = 0
        restore_counter = 0

        def count_archive(**kwargs):
            global archive_counter
            archive_counter += 1

        def count_unarchive(**kwargs):
            global restore_counter
            restore_counter += 1

        xform_archived.connect(count_archive)
        xform_unarchived.connect(count_unarchive)

        xml_data = self.get_xml('basic')
        response, xform, cases = self.interface.submit_form_locally(
            xml_data,
            'test-domain',
        )

        self.assertEqual(0, archive_counter)
        self.assertEqual(0, restore_counter)

        xform.archive()
        self.assertEqual(1, archive_counter)
        self.assertEqual(0, restore_counter)

        xform.unarchive()
        self.assertEqual(1, archive_counter)
        self.assertEqual(1, restore_counter)
<|endoftext|>


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

from __future__ import absolute_import

import datetime
import time
import uuid

import mock
import six

from google import auth
from google.cloud import pubsub_v1

def _resource_name(resource_type):
    """Return a randomly selected name for a resource.

    Args:
        resource_type (str): The resource for which a name is being
            generated. Should be singular (e.g. "topic", "subscription")
    """
    return 'projects/{project}/{resource_type}s/st-n{random}'.format(
        project=auth.default()[1],
        random=str(uuid.uuid4())[0:8],
        resource_type=resource_type,
    )

def test_publish_messages():
    publisher = pubsub_v1.PublisherClient()
    topic_name = _resource_name('topic')
    futures = []

    try:
        publisher.create_topic(topic_name)
        for i in range(0, 500):
            futures.append(
                publisher.publish(
                    topic_name,
                    b'The hail in Wales falls mainly on the snails.',
                    num=str(i),
                ),
            )
        for future in futures:
            result = future.result()
            assert isinstance(result, (six.text_type, six.binary_type))
    finally:
        publisher.delete_topic(topic_name)

def test_subscribe_to_messages():
    publisher = pubsub_v1.PublisherClient()
    subscriber = pubsub_v1.SubscriberClient()
    topic_name = _resource_name('topic')
    sub_name = _resource_name('subscription')

    try:
        # Create a topic.
        publisher.create_topic(topic_name)

        # Subscribe to the topic. This must happen before the messages
        # are published.
        subscriber.create_subscription(sub_name, topic_name)
        subscription = subscriber.subscribe(sub_name)

        # Publish some messages.
        futures = [publisher.publish(
            topic_name,
            b'Wooooo! The claaaaaw!',
            num=str(i),
        ) for i in range(0, 50)]

        # Make sure the publish completes.
        [f.result() for f in futures]

        # The callback should process the message numbers to prove
        # that we got everything at least once.
        callback = mock.Mock(wraps=lambda message: message.ack())

        # Actually open the subscription and hold it open for a few seconds.
        subscription.open(callback)
        for second in range(0, 10):
            time.sleep(1)

            # The callback should have fired at least fifty times, but it
            # may take some time.
            if callback.call_count >= 50:
                return

        # Okay, we took too long; fail out.
        assert callback.call_count >= 50
    finally:
        publisher.delete_topic(topic_name)

def test_subscribe_to_messages_async_callbacks():
    publisher = pubsub_v1.PublisherClient()
    subscriber = pubsub_v1.SubscriberClient()
    topic_name = _resource_name('topic')
    sub_name = _resource_name('subscription')

    try:
        # Create a topic.
        publisher.create_topic(topic_name)

        # Subscribe to the topic. This must happen before the messages
        # are published.
        subscriber.create_subscription(sub_name, topic_name)
        subscription = subscriber.subscribe(sub_name)

        # Publish some messages.
        futures = [publisher.publish(
            topic_name,
            b'Wooooo! The claaaaaw!',
            num=str(i),
        ) for i in range(0, 2)]

        # Make sure the publish completes.
        [f.result() for f in futures]

        # We want to make sure that the callback was called asynchronously. So
        # track when each call happened and make sure below.
        call_times = []

        def process_message(message):
            # list.append() is thread-safe.
            call_times.append(datetime.datetime.now())
            time.sleep(2)
            message.ack()

        callback = mock.Mock(wraps=process_message)
        side_effect = mock.Mock()
        callback.side_effect = side_effect

        # Actually open the subscription and hold it open for a few seconds.
        subscription.open(callback)
        for second in range(0, 5):
            time.sleep(4)

            # The callback should have fired at least two times, but it may
            # take some time.
            if callback.call_count >= 2 and side_effect.call_count >= 2:
                first = min(call_times[:2])
                last = max(call_times[:2])
                diff = last - first
                # "Ensure" the first two callbacks were executed asynchronously
                # (sequentially would have resulted in a difference of 2+
                # seconds).
                assert diff.days == 0
                assert diff.seconds < 2

        # Okay, we took too long; fail out.
        assert callback.call_count >= 2
    finally:
        publisher.delete_topic(topic_name)
<commit_msg>Using `pytest` fixtures in Pub/Sub system tests. (#4440)<commit_after># Copyright 2017, Google LLC All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import

import datetime
import threading
import time

import pytest
import six

import google.auth
from google.cloud import pubsub_v1

from test_utils.system import unique_resource_id

@pytest.fixture(scope=u'module')
def project():
    _, default_project = google.auth.default()
    yield default_project

@pytest.fixture(scope=u'module')
def publisher():
    yield pubsub_v1.PublisherClient()

@pytest.fixture(scope=u'module')
def subscriber():
    yield pubsub_v1.SubscriberClient()

@pytest.fixture
def topic_path(project, publisher):
    topic_name = 't' + unique_resource_id('-')
    yield publisher.topic_path(project, topic_name)

@pytest.fixture
def subscription_path(project, subscriber):
    sub_name = 's' + unique_resource_id('-')
    yield subscriber.subscription_path(project, sub_name)

@pytest.fixture
def cleanup():
    registry = []
    yield registry

    # Perform all clean up.
    for to_call, argument in registry:
        to_call(argument)

def test_publish_messages(publisher, topic_path, cleanup):
    futures = []
    # Make sure the topic gets deleted.
    cleanup.append((publisher.delete_topic, topic_path))

    publisher.create_topic(topic_path)
    for index in six.moves.range(500):
        futures.append(
            publisher.publish(
                topic_path,
                b'The hail in Wales falls mainly on the snails.',
                num=str(index),
            ),
        )

    for future in futures:
        result = future.result()
        assert isinstance(result, six.string_types)

def test_subscribe_to_messages(
        publisher, topic_path, subscriber, subscription_path, cleanup):
    # Make sure the topic and subscription get deleted.
    cleanup.append((publisher.delete_topic, topic_path))
    cleanup.append((subscriber.delete_subscription, subscription_path))

    # Create a topic.
    publisher.create_topic(topic_path)

    # Subscribe to the topic. This must happen before the messages
    # are published.
    subscriber.create_subscription(subscription_path, topic_path)
    subscription = subscriber.subscribe(subscription_path)

    # Publish some messages.
    futures = [
        publisher.publish(
            topic_path,
            b'Wooooo! The claaaaaw!',
            num=str(index),
        )
        for index in six.moves.range(50)
    ]

    # Make sure the publish completes.
    for future in futures:
        future.result()

    # Actually open the subscription and hold it open for a few seconds.
    # The callback should process the message numbers to prove
    # that we got everything at least once.
    callback = AckCallback()
    subscription.open(callback)
    for second in six.moves.range(10):
        time.sleep(1)

        # The callback should have fired at least fifty times, but it
        # may take some time.
        if callback.calls >= 50:
            return

    # Okay, we took too long; fail out.
    assert callback.calls >= 50

def test_subscribe_to_messages_async_callbacks(
        publisher, topic_path, subscriber, subscription_path, cleanup):
    # Make sure the topic and subscription get deleted.
    cleanup.append((publisher.delete_topic, topic_path))
    cleanup.append((subscriber.delete_subscription, subscription_path))

    # Create a topic.
    publisher.create_topic(topic_path)

    # Subscribe to the topic. This must happen before the messages
    # are published.
    subscriber.create_subscription(subscription_path, topic_path)
    subscription = subscriber.subscribe(subscription_path)

    # Publish some messages.
    futures = [
        publisher.publish(
            topic_path,
            b'Wooooo! The claaaaaw!',
            num=str(index),
        )
        for index in six.moves.range(2)
    ]

    # Make sure the publish completes.
    for future in futures:
        future.result()

    # We want to make sure that the callback was called asynchronously. So
    # track when each call happened and make sure below.
    callback = TimesCallback(2)

    # Actually open the subscription and hold it open for a few seconds.
    subscription.open(callback)
    for second in six.moves.range(5):
        time.sleep(4)

        # The callback should have fired at least two times, but it may
        # take some time.
        if callback.calls >= 2:
            first, last = sorted(callback.call_times[:2])
            diff = last - first
            # "Ensure" the first two callbacks were executed asynchronously
            # (sequentially would have resulted in a difference of 2+
            # seconds).
            assert diff.days == 0
            assert diff.seconds < callback.sleep_time

    # Okay, we took too long; fail out.
    assert callback.calls >= 2

class AckCallback(object):

    def __init__(self):
        self.calls = 0

    def __call__(self, message):
        message.ack()
        # Only increment the number of calls **after** finishing.
        with threading.Lock():
            self.calls += 1

class TimesCallback(object):

    def __init__(self, sleep_time):
        self.sleep_time = sleep_time
        self.calls = 0
        self.call_times = []

    def __call__(self, message):
        now = datetime.datetime.now()
        time.sleep(self.sleep_time)
        message.ack()
        # Only increment the number of calls **after** finishing.
        with threading.Lock():
            # list.append() is thread-safe, but we still wait until
            # ``calls`` is incremented to do it.
            self.call_times.append(now)
            self.calls += 1
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""HTML template to embed geotiffs of GMF/Loss Ratio maps."""

HTML_TEMPLATE_LOSSRATIO = """<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<title>Loss Ratio</title>

Color
Percentage

 	0-6

 	7-12

 	13-18

 	19-25

 	26-31

 	32-37

 	38-43

 	44-50

 	51-56

 	57-62

 	63-69

 	70-75

 	76-81

 	82-87

 	88-94

 	95-100

"""

HTML_TEMPLATE_HEADER = """<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<title>PLACEHOLDER_TITLE</title>

"""

HTML_TEMPLATE_IMAGE = """

"""

HTML_TEMPLATE_TABLE_START = """

Color
PLACEHOLDER_IMT

"""

HTML_TEMPLATE_FOOTER = """

"""

HTML_TEMPLATE_TABLE_ROW = """

PLACEHOLDER_IML_VALUE

"""

def generate_html(path, width="", height="", colorscale=None, imt='PGA/g',
                  title="", template=None):
    """This function creates an HTML page with a Geotiff image linked, and a
    colorscale as HTML table. The HTML can be created from an explicitly
    given template, or automatically based on color scale values."""

    if not template:
        curr_html = HTML_TEMPLATE_HEADER
        header_html = curr_html.replace('PLACEHOLDER_TITLE', title)

        curr_html = HTML_TEMPLATE_IMAGE
        curr_html = curr_html.replace('PLACEHOLDER_IMAGE_NAME', path)
        curr_html = curr_html.replace('PLACEHOLDER_WIDTH', width)
        curr_html = curr_html.replace('PLACEHOLDER_HEIGHT', height)
        image_html = curr_html

        curr_html = HTML_TEMPLATE_TABLE_START
        table_start_html = curr_html.replace('PLACEHOLDER_IMT', imt)

        table_body_html = ''
        for curr_color in colorscale:
            curr_row_html = HTML_TEMPLATE_TABLE_ROW
            curr_row_html = curr_row_html.replace('PLACEHOLDER_COLOR_HEX_CODE',
                                                curr_color[0])
            curr_row_html = curr_row_html.replace('PLACEHOLDER_IML_VALUE',
                                                curr_color[1])
            table_body_html += curr_row_html

        return ''.join((header_html, image_html, table_start_html,
                        table_body_html, HTML_TEMPLATE_FOOTER))
    else:
        curr_html = template
        for (token, new_value) in (
            ('PLACEHOLDER_IMAGE_NAME', path), ('PLACEHOLDER_WIDTH', width),
            ('PLACEHOLDER_HEIGHT', height)):
            curr_html = curr_html.replace(token, new_value)
        return curr_html
<commit_msg>fixed trailing whitespace<commit_after># -*- coding: utf-8 -*-
"""HTML template to embed geotiffs of GMF/Loss Ratio maps."""

HTML_TEMPLATE_LOSSRATIO = """<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<title>Loss Ratio</title>

Color
Percentage

 	0-6

 	7-12

 	13-18

 	19-25

 	26-31

 	32-37

 	38-43

 	44-50

 	51-56

 	57-62

 	63-69

 	70-75

 	76-81

 	82-87

 	88-94

 	95-100

"""

HTML_TEMPLATE_HEADER = """<!DOCTYPE html PUBLIC
    "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<title>PLACEHOLDER_TITLE</title>

"""

HTML_TEMPLATE_IMAGE = """

"""

HTML_TEMPLATE_TABLE_START = """

Color
PLACEHOLDER_IMT

"""

HTML_TEMPLATE_FOOTER = """

"""

HTML_TEMPLATE_TABLE_ROW = """

PLACEHOLDER_IML_VALUE

"""

def generate_html(path, width="", height="", colorscale=None, imt='PGA/g',
                  title="", template=None):
    """This function creates an HTML page with a Geotiff image linked, and a
    colorscale as HTML table. The HTML can be created from an explicitly
    given template, or automatically based on color scale values."""

    if not template:
        curr_html = HTML_TEMPLATE_HEADER
        header_html = curr_html.replace('PLACEHOLDER_TITLE', title)

        curr_html = HTML_TEMPLATE_IMAGE
        curr_html = curr_html.replace('PLACEHOLDER_IMAGE_NAME', path)
        curr_html = curr_html.replace('PLACEHOLDER_WIDTH', width)
        curr_html = curr_html.replace('PLACEHOLDER_HEIGHT', height)
        image_html = curr_html

        curr_html = HTML_TEMPLATE_TABLE_START
        table_start_html = curr_html.replace('PLACEHOLDER_IMT', imt)

        table_body_html = ''
        for curr_color in colorscale:
            curr_row_html = HTML_TEMPLATE_TABLE_ROW
            curr_row_html = curr_row_html.replace('PLACEHOLDER_COLOR_HEX_CODE',
                                                curr_color[0])
            curr_row_html = curr_row_html.replace('PLACEHOLDER_IML_VALUE',
                                                curr_color[1])
            table_body_html += curr_row_html

        return ''.join((header_html, image_html, table_start_html,
                        table_body_html, HTML_TEMPLATE_FOOTER))
    else:
        curr_html = template
        for (token, new_value) in (
            ('PLACEHOLDER_IMAGE_NAME', path), ('PLACEHOLDER_WIDTH', width),
            ('PLACEHOLDER_HEIGHT', height)):
            curr_html = curr_html.replace(token, new_value)
        return curr_html
<|endoftext|>


<commit_before>#!/usr/bin/env python
# coding=utf-8

"""
This node tries to generate odometrie by converting wheel encoder ticks from my
robot 'minibot'.
It then publishes odometrie messages into ROS for use in the navigation stack.

Author:  Markus Knapp, 2018
Website: https://direcs.de
"""

import logging
import sys
import time

import rospy
import math

from std_msgs.msg import Header, Float32
from sensor_msgs.msg import Imu

# see also http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom:
# "The nav_msgs/Odometry message stores an estimate of the position
#  and velocity of a robot in free space"

# see also ROS Odometry Python example
# https://gist.github.com/atotto/f2754f75bedb6ea56e3e0264ec405dcf
import nav_msgs.msg
from nav_msgs.msg import Odometry
# for the tf broadcaster
import tf
from geometry_msgs.msg import Point, Pose, Quaternion, Twist, Vector3

# sleep time for this node in seconds
sleepTime = 0.25

# initialise the ROS node
rospy.init_node('odom_node', anonymous=False)

# initialize the odom publisher
odom_pub = rospy.Publisher('odom', Odometry, queue_size=10)

# initial position
x  = 0.0
y  = 0.0
th = 0.0

# velocity
vx  = 0.4
vy  = 0.0
vth = 0.4
current_time = rospy.Time.now()
last_time = rospy.Time.now()
odo_last_time = rospy.Time.now()
tfBroadcaster = tf.TransformBroadcaster()
degree = M_PI/180

""" robot parameters

:@# TODO: move these values to ROS parameter server
i.e.: node.getParam("odom/distancepercount", param_distancepercount)

16 Flankenwechsel pro Umdrehung,
durch Getriebe:
544 Flankenwechsel pro Umdrehung für ein 34:1 Getriebe

double DistancePerCount = 50.0/12.0 * 0.6/17.0 """
distancePerCount       = 0.0  # param_distancepercount   in meters (m)!!
lengthBetweenTwoWheels = 0.0  # param_widthbetweenwheels

# --------------------
# wheel encoder stuff
# --------------------
import atexit

# for signal handling
import signal
import sys

# count the ticks from the wheel encoders "forever"
odomCountForeverFrontLeft  = 0
odomCountForeverRearLeft   = 0
odomCountForeverFrontRight = 0
odomCountForeverRearRight  = 0

odomCountFrontLeft  = 0
odomCountRearLeft   = 0
odomCountFrontRight = 0
odomCountRearRight  = 0

# this is one tick from a wheel encoder
odomStep = 1

# for getting the hostname of the underlying system
import socket
# showing hostname
hostname = socket.gethostname()
rospy.loginfo("Running on host %s.", hostname)
if (hostname != 'minibot') and (hostname != 'minibottest'):
    rospy.logwarn("Test mode only due to other host. Skipping all hardware staff!")
else:
    # we are "live" on robot hardware
    import RPi.GPIO as GPIO

    # GPIO init
    GPIO.setmode(GPIO.BCM) # use the BCM-GPIO names, _not_ the pin numbers on the board

    # Raspberry Pi GPIO configuration:
    frontLeftEncoderGPIO  = 27 # forward
    rearLeftEncoderGPIO   = 22 # forward
    frontRightEncoderGPIO = 23 # forward
    rearRightEncoderGPIO  = 24 # forward

    # setup
    rospy.loginfo("Wheel encoder GPIO setup...")
    GPIO.setup(frontLeftEncoderGPIO,  GPIO.IN)
    GPIO.setup(rearLeftEncoderGPIO,   GPIO.IN)
    GPIO.setup(frontRightEncoderGPIO, GPIO.IN)
    GPIO.setup(rearRightEncoderGPIO,  GPIO.IN)

    # encoder pulse detection by interrupt
    def fronLeftEncoderCallback(answer):
        global odomCountFrontLeft
        global odomCountForeverFrontLeft
        # velocity is always positive, so we always increment
        odomCountFrontLeft        = odomCountFrontLeft        + odomStep
        odomCountForeverFrontLeft = odomCountForeverFrontLeft + odomStep
        rospy.loginfo("Front left encoder.")

    def rearLeftEncoderCallback(answer):
        global odomCountRearLeft
        global odomCountForeverRearLeft
        odomCountRearLeft        = odomCountRearLeft        + odomStep
        odomCountForeverRearLeft = odomCountForeverRearLeft + odomStep
        rospy.loginfo("Rear left encoder.")

    def frontRightEncoderCallback(answer):
        global odomCountFrontRight
        global odomCountForeverFrontRight
        odomCountFrontRight        = odomCountFrontRight        + odomStep
        odomCountForeverFrontRight = odomCountForeverFrontRight + odomStep
        rospy.loginfo("Front right encoder.")

    def rearRightEncoderCallback(answer):
        global odomCountRearRight
        global odomCountForeverRearRight
        odomCountRearRight        = odomCountRearRight        + odomStep
        odomCountForeverRearRight = odomCountForeverRearRight + odomStep
        rospy.loginfo("Rear right encoder.")

    # add GPIO event detectors (interrupt service routines)
    rospy.loginfo("registering event handlers...")

    # enabling event handlers (if needed only)
    def enableEncoderTracking():
        GPIO.add_event_detect(frontLeftEncoderGPIO,  GPIO.FALLING, callback=fronLeftEncoderCallback)
        GPIO.add_event_detect(rearLeftEncoderGPIO, GPIO.FALLING, callback=rearLeftEncoderCallback)
        GPIO.add_event_detect(frontRightEncoderGPIO, GPIO.FALLING, callback=frontRightEncoderCallback)
        GPIO.add_event_detect(rearRightEncoderGPIO, GPIO.FALLING, callback=rearRightEncoderCallback)

    # disabling event handlers
    def disableEncoderTracking():
        GPIO.remove_event_detect(frontLeftEncoderGPIO)
        GPIO.remove_event_detect(rearLeftEncoderGPIO)
        GPIO.remove_event_detect(frontRightEncoderGPIO)
        GPIO.remove_event_detect(rearRightEncoderGPIO)

    """ START wheel encoder tracking """
    enableEncoderTracking()

# define a clean node exit
def my_exit():
  rospy.loginfo("Shutting down odometry service...")
  # run some parts only on the real robot
  if hostname == 'minibot' or hostname == 'minibottest':
        """ STOP wheel encoder tracking """
        disableEncoderTracking()
        GPIO.cleanup()
  rospy.loginfo("...shutting down odometrie service complete.")

# call this method on node exit
rospy.on_shutdown(my_exit)

""" this is where the odometry magic happens """
def calculateOdometry():
    # get current time
    current_time = rospy.Time.now()

	XXX = (0.1 / 50.0)

    # calculate passed time
    dt = (current_time - odo_last_time).toSec()

#	if (dt>=ODOM_PERIOD)
#	{
	# https://answers.ros.org/question/207392/generating-odom-message-from-encoder-ticks-for-robot_pose_ekf/
	# http://www.seattlerobotics.org/encoder/200610/Article3/IMU%20Odometry,%20by%20David%20Anderson.htm

    # extract the wheel velocities from the tick signals count
    deltaFrontLeft  = odomCountFrontLeft
    deltaRearLeft   = odomCountRearLeft
    deltaFrontRight = odomCountFrontRight
    deltaRearRight  = odomCountRearRight

    v_FrontLeft  = (deltaFrontLeft  * distancePerCount) / dt
    v_RearLeft   = (deltaRearLeft   * distancePerCount) / dt
    v_FrontRight = (deltaFrontRight * distancePerCount) / dt
    v_RearRight  = (deltaRearRight  * distancePerCount) / dt

    #motor_md[MOTOR_L].odom_rate = v_left;
    #motor_md[MOTOR_R].odom_rate = v_right;

    # :@TODO what about the rear values?!?
    motor_md[MOTOR_L].odom_rate = (4.0 * motor_md[MOTOR_L].odom_rate + v_FrontLeft) / 5.0
    motor_md[MOTOR_R].odom_rate = (4.0 * motor_md[MOTOR_R].odom_rate + v_FrontRight) / 5.0

    #motor_md[MOTOR_L].odom_rate = (19.0 * motor_md[MOTOR_L].odom_rate + v_left) / 20.0;
    #motor_md[MOTOR_R].odom_rate = (19.0 * motor_md[MOTOR_R].odom_rate + v_right) / 20.0;

    # :@TODO what about the rear values?!?
    vx = ((v_FrontRight + v_FrontLeft) / 2)
    vy = 0
    # :@TODO declare and define lengthBetweenTwoWheels
    # :@TODO what about the rear values?!?
    vth = ((v_FrontRight - v_FrontLeft) / lengthBetweenTwoWheels)

    #double dt = (current_time - last_time).toSec();
    delta_x = (vx * cos(th)) * dt
    delta_y = (vx * sin(th)) * dt
    delta_th = vth * dt

    x += delta_x
    y += delta_y
    th += delta_th

    # org: geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
    # since all odometry is 6DOF we'll need a quaternion created from yaw
    odom_quat = tf::createQuaternionMsgFromYaw(th)
    # oder von imu_bno055:     odom_quat = tf.transformations.quaternion_from_euler(x, y, z) #   z vs. th ?!??

    """ generate tf broacast message and publish """
    # message declarations
    # the tf broadcaster
    # "any odometry source must publish information about the coordinate frame that it manages"
    # org: geometry_msgs::TransformStamped odom_trans;
    odom_trans = tf.TransformBroadcaster()
	odom_trans.header.stamp = current_time
	odom_trans.header.frame_id = "odom"
	odom_trans.child_frame_id = "base_footprint"

	odom_trans.transform.translation.x = x
	odom_trans.transform.translation.y = y
	odom_trans.transform.translation.z = 0.0
	odom_trans.transform.rotation = odom_quat

	# send the transform
	tfBroadcaster.sendTransform(odom_trans)

	""" Odometry message """
	odom = Odometry()
	odom.header.stamp = current_time
	#odom.header.frame_id = "odom";

	# set the position
	odom.pose.pose.position.x = x
	odom.pose.pose.position.y = y
	odom.pose.pose.position.z = 0.0
	odom.pose.pose.orientation = odom_quat
	max = 1000000000000.0
	min = 0.001
	odom.pose.covariance = {
			min,    0.0, 0.0,  0.0,  0.0,  0.0,
			0.0,    min, 0.0,  0.0,  0.0,  0.0,
			0.0,    0.0, max,  0.0,  0.0,  0.0,
			0.0,    0.0, 0.0,  max,  0.0,  0.0,
			0.0,    0.0, 0.0,  0.0,  max,  0.0,
			0.0,    0.0, 0.0,  0.0,  0.0,  max }

	# set the velocity
	#odom.child_frame_id = "base_footprint";
	odom.twist.twist.linear.x = vx
	odom.twist.twist.linear.y = vy
	odom.twist.twist.angular.z = vth
	odom.twist.covariance = {
			min,     0.0,  0.0,  0.0,  0.0,  0.0,
			0.0,     min,  0.0,  0.0,  0.0,  0.0,
			0.0,     0.0,  max,  0.0,  0.0,  0.0,
			0.0,     0.0,  0.0,  max,  0.0,  0.0,
			0.0,     0.0,  0.0,  0.0,  max,  0.0,
			0.0,     0.0,  0.0,  0.0,  0.0,  max }

	ROS_DEBUG("handleODO() dt=%f encoder=%d,%d,%d,%d position=%f,%f twist=%f,%f,%f ",
			dt,
			motor_md[MOTOR_R].odom_cnt,motor_md[MOTOR_R].odom_step,
			motor_md[MOTOR_L].odom_cnt,motor_md[MOTOR_L].odom_step,
			x,
			y,
			vx,
			vy,
			vth);

	# publish the message
	odom_pub.publish(odom)

    # update last odom time to current
	odo_last_time = current_time

	#
	# insert PID mode used/not used stuff here
	#

""" to be ported
	#
	# publish diagnostic data
	#
	Float32 msg

	msg.data = motor_md[MOTOR_L].setpoint
	motor_pub_setpoint[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].setpoint
	motor_pub_setpoint[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].value
	motor_pub_value[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].value
	motor_pub_value[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].odom_rate/XXX
	motor_pub_rate[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].odom_rate/XXX
	motor_pub_rate[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].odom_cnt_forever
	motor_pub_odomcnt[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].odom_cnt_forever
	motor_pub_odomcnt[MOTOR_R].publish(msg)
"""

    # reset odom tick counters
    odomCountFrontLeft  = 0
    odomCountRearLeft   = 0
    odomCountFrontRight = 0
    odomCountRearRight  = 0

""" 'main' """
while not rospy.is_shutdown():
    # measure staff and publish odom
    calculateOdometry()

    # Sleep for a second until the next reading.
    rospy.sleep(sleepTime)
<commit_msg>added my counters to debug message<commit_after>#!/usr/bin/env python
# coding=utf-8

"""
This node tries to generate odometrie by converting wheel encoder ticks from my
robot 'minibot'.
It then publishes odometrie messages into ROS for use in the navigation stack.

Author:  Markus Knapp, 2018
Website: https://direcs.de
"""

import logging
import sys
import time

import rospy
import math

from std_msgs.msg import Header, Float32
from sensor_msgs.msg import Imu

# see also http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom:
# "The nav_msgs/Odometry message stores an estimate of the position
#  and velocity of a robot in free space"

# see also ROS Odometry Python example
# https://gist.github.com/atotto/f2754f75bedb6ea56e3e0264ec405dcf
import nav_msgs.msg
from nav_msgs.msg import Odometry
# for the tf broadcaster
import tf
from geometry_msgs.msg import Point, Pose, Quaternion, Twist, Vector3

# sleep time for this node in seconds
sleepTime = 0.25

# initialise the ROS node
rospy.init_node('odom_node', anonymous=False)

# initialize the odom publisher
odom_pub = rospy.Publisher('odom', Odometry, queue_size=10)

# initial position
x  = 0.0
y  = 0.0
th = 0.0

# velocity
vx  = 0.4
vy  = 0.0
vth = 0.4
current_time = rospy.Time.now()
last_time = rospy.Time.now()
odo_last_time = rospy.Time.now()
tfBroadcaster = tf.TransformBroadcaster()
degree = M_PI/180

""" robot parameters

:@# TODO: move these values to ROS parameter server
i.e.: node.getParam("odom/distancepercount", param_distancepercount)

16 Flankenwechsel pro Umdrehung,
durch Getriebe:
544 Flankenwechsel pro Umdrehung für ein 34:1 Getriebe

double DistancePerCount = 50.0/12.0 * 0.6/17.0 """
distancePerCount       = 0.0  # param_distancepercount   in meters (m)!!
lengthBetweenTwoWheels = 0.0  # param_widthbetweenwheels

# --------------------
# wheel encoder stuff
# --------------------
import atexit

# for signal handling
import signal
import sys

# count the ticks from the wheel encoders "forever"
odomCountForeverFrontLeft  = 0
odomCountForeverRearLeft   = 0
odomCountForeverFrontRight = 0
odomCountForeverRearRight  = 0

odomCountFrontLeft  = 0
odomCountRearLeft   = 0
odomCountFrontRight = 0
odomCountRearRight  = 0

# this is one tick from a wheel encoder
odomStep = 1

# for getting the hostname of the underlying system
import socket
# showing hostname
hostname = socket.gethostname()
rospy.loginfo("Running on host %s.", hostname)
if (hostname != 'minibot') and (hostname != 'minibottest'):
    rospy.logwarn("Test mode only due to other host. Skipping all hardware staff!")
else:
    # we are "live" on robot hardware
    import RPi.GPIO as GPIO

    # GPIO init
    GPIO.setmode(GPIO.BCM) # use the BCM-GPIO names, _not_ the pin numbers on the board

    # Raspberry Pi GPIO configuration:
    frontLeftEncoderGPIO  = 27 # forward
    rearLeftEncoderGPIO   = 22 # forward
    frontRightEncoderGPIO = 23 # forward
    rearRightEncoderGPIO  = 24 # forward

    # setup
    rospy.loginfo("Wheel encoder GPIO setup...")
    GPIO.setup(frontLeftEncoderGPIO,  GPIO.IN)
    GPIO.setup(rearLeftEncoderGPIO,   GPIO.IN)
    GPIO.setup(frontRightEncoderGPIO, GPIO.IN)
    GPIO.setup(rearRightEncoderGPIO,  GPIO.IN)

    # encoder pulse detection by interrupt
    def fronLeftEncoderCallback(answer):
        global odomCountFrontLeft
        global odomCountForeverFrontLeft
        # velocity is always positive, so we always increment
        odomCountFrontLeft        = odomCountFrontLeft        + odomStep
        odomCountForeverFrontLeft = odomCountForeverFrontLeft + odomStep
        rospy.loginfo("Front left encoder.")

    def rearLeftEncoderCallback(answer):
        global odomCountRearLeft
        global odomCountForeverRearLeft
        odomCountRearLeft        = odomCountRearLeft        + odomStep
        odomCountForeverRearLeft = odomCountForeverRearLeft + odomStep
        rospy.loginfo("Rear left encoder.")

    def frontRightEncoderCallback(answer):
        global odomCountFrontRight
        global odomCountForeverFrontRight
        odomCountFrontRight        = odomCountFrontRight        + odomStep
        odomCountForeverFrontRight = odomCountForeverFrontRight + odomStep
        rospy.loginfo("Front right encoder.")

    def rearRightEncoderCallback(answer):
        global odomCountRearRight
        global odomCountForeverRearRight
        odomCountRearRight        = odomCountRearRight        + odomStep
        odomCountForeverRearRight = odomCountForeverRearRight + odomStep
        rospy.loginfo("Rear right encoder.")

    # add GPIO event detectors (interrupt service routines)
    rospy.loginfo("registering event handlers...")

    # enabling event handlers (if needed only)
    def enableEncoderTracking():
        GPIO.add_event_detect(frontLeftEncoderGPIO,  GPIO.FALLING, callback=fronLeftEncoderCallback)
        GPIO.add_event_detect(rearLeftEncoderGPIO, GPIO.FALLING, callback=rearLeftEncoderCallback)
        GPIO.add_event_detect(frontRightEncoderGPIO, GPIO.FALLING, callback=frontRightEncoderCallback)
        GPIO.add_event_detect(rearRightEncoderGPIO, GPIO.FALLING, callback=rearRightEncoderCallback)

    # disabling event handlers
    def disableEncoderTracking():
        GPIO.remove_event_detect(frontLeftEncoderGPIO)
        GPIO.remove_event_detect(rearLeftEncoderGPIO)
        GPIO.remove_event_detect(frontRightEncoderGPIO)
        GPIO.remove_event_detect(rearRightEncoderGPIO)

    """ START wheel encoder tracking """
    enableEncoderTracking()

# define a clean node exit
def my_exit():
  rospy.loginfo("Shutting down odometry service...")
  # run some parts only on the real robot
  if hostname == 'minibot' or hostname == 'minibottest':
        """ STOP wheel encoder tracking """
        disableEncoderTracking()
        GPIO.cleanup()
  rospy.loginfo("...shutting down odometrie service complete.")

# call this method on node exit
rospy.on_shutdown(my_exit)

""" this is where the odometry magic happens """
def calculateOdometry():
    # get current time
    current_time = rospy.Time.now()

	XXX = (0.1 / 50.0)

    # calculate passed time
    dt = (current_time - odo_last_time).toSec()

#	if (dt>=ODOM_PERIOD)
#	{
	# https://answers.ros.org/question/207392/generating-odom-message-from-encoder-ticks-for-robot_pose_ekf/
	# http://www.seattlerobotics.org/encoder/200610/Article3/IMU%20Odometry,%20by%20David%20Anderson.htm

    # extract the wheel velocities from the tick signals count
    deltaFrontLeft  = odomCountFrontLeft
    deltaRearLeft   = odomCountRearLeft
    deltaFrontRight = odomCountFrontRight
    deltaRearRight  = odomCountRearRight

    v_FrontLeft  = (deltaFrontLeft  * distancePerCount) / dt
    v_RearLeft   = (deltaRearLeft   * distancePerCount) / dt
    v_FrontRight = (deltaFrontRight * distancePerCount) / dt
    v_RearRight  = (deltaRearRight  * distancePerCount) / dt

    #motor_md[MOTOR_L].odom_rate = v_left;
    #motor_md[MOTOR_R].odom_rate = v_right;

    # :@TODO what about the rear values?!?
    motor_md[MOTOR_L].odom_rate = (4.0 * motor_md[MOTOR_L].odom_rate + v_FrontLeft) / 5.0
    motor_md[MOTOR_R].odom_rate = (4.0 * motor_md[MOTOR_R].odom_rate + v_FrontRight) / 5.0

    #motor_md[MOTOR_L].odom_rate = (19.0 * motor_md[MOTOR_L].odom_rate + v_left) / 20.0;
    #motor_md[MOTOR_R].odom_rate = (19.0 * motor_md[MOTOR_R].odom_rate + v_right) / 20.0;

    # :@TODO what about the rear values?!?
    vx = ((v_FrontRight + v_FrontLeft) / 2)
    vy = 0
    # :@TODO declare and define lengthBetweenTwoWheels
    # :@TODO what about the rear values?!?
    vth = ((v_FrontRight - v_FrontLeft) / lengthBetweenTwoWheels)

    #double dt = (current_time - last_time).toSec();
    delta_x = (vx * cos(th)) * dt
    delta_y = (vx * sin(th)) * dt
    delta_th = vth * dt

    x += delta_x
    y += delta_y
    th += delta_th

    # org: geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
    # since all odometry is 6DOF we'll need a quaternion created from yaw
    odom_quat = tf::createQuaternionMsgFromYaw(th)
    # oder von imu_bno055:     odom_quat = tf.transformations.quaternion_from_euler(x, y, z) #   z vs. th ?!??

    """ generate tf broacast message and publish """
    # message declarations
    # the tf broadcaster
    # "any odometry source must publish information about the coordinate frame that it manages"
    # org: geometry_msgs::TransformStamped odom_trans;
    odom_trans = tf.TransformBroadcaster()
	odom_trans.header.stamp = current_time
	odom_trans.header.frame_id = "odom"
	odom_trans.child_frame_id = "base_footprint"

	odom_trans.transform.translation.x = x
	odom_trans.transform.translation.y = y
	odom_trans.transform.translation.z = 0.0
	odom_trans.transform.rotation = odom_quat

	# send the transform
	tfBroadcaster.sendTransform(odom_trans)

	""" Odometry message """
	odom = Odometry()
	odom.header.stamp = current_time
	#odom.header.frame_id = "odom";

	# set the position
	odom.pose.pose.position.x = x
	odom.pose.pose.position.y = y
	odom.pose.pose.position.z = 0.0
	odom.pose.pose.orientation = odom_quat
	max = 1000000000000.0
	min = 0.001
	odom.pose.covariance = {
			min,    0.0, 0.0,  0.0,  0.0,  0.0,
			0.0,    min, 0.0,  0.0,  0.0,  0.0,
			0.0,    0.0, max,  0.0,  0.0,  0.0,
			0.0,    0.0, 0.0,  max,  0.0,  0.0,
			0.0,    0.0, 0.0,  0.0,  max,  0.0,
			0.0,    0.0, 0.0,  0.0,  0.0,  max }

	# set the velocity
	#odom.child_frame_id = "base_footprint";
	odom.twist.twist.linear.x = vx
	odom.twist.twist.linear.y = vy
	odom.twist.twist.angular.z = vth
	odom.twist.covariance = {
			min,     0.0,  0.0,  0.0,  0.0,  0.0,
			0.0,     min,  0.0,  0.0,  0.0,  0.0,
			0.0,     0.0,  max,  0.0,  0.0,  0.0,
			0.0,     0.0,  0.0,  max,  0.0,  0.0,
			0.0,     0.0,  0.0,  0.0,  max,  0.0,
			0.0,     0.0,  0.0,  0.0,  0.0,  max }

	ROS_DEBUG("calculateOdometry() dt=%f encoder=%d,%d,%d,%d position=%f,%f twist=%f,%f,%f ",
			dt,
			odomCountFrontLeft,  odomCountRearLeft,
			odomCountFrontRight, odomCountRearRight,
			x,
			y,
			vx,
			vy,
			vth)

	# publish the message
	odom_pub.publish(odom)

    # update last odom time to current
	odo_last_time = current_time

	#
	# insert PID mode used/not used stuff here
	#

""" to be ported
	#
	# publish diagnostic data
	#
	Float32 msg

	msg.data = motor_md[MOTOR_L].setpoint
	motor_pub_setpoint[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].setpoint
	motor_pub_setpoint[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].value
	motor_pub_value[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].value
	motor_pub_value[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].odom_rate/XXX
	motor_pub_rate[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].odom_rate/XXX
	motor_pub_rate[MOTOR_R].publish(msg)

	msg.data = motor_md[MOTOR_L].odom_cnt_forever
	motor_pub_odomcnt[MOTOR_L].publish(msg)
	msg.data = motor_md[MOTOR_R].odom_cnt_forever
	motor_pub_odomcnt[MOTOR_R].publish(msg)
"""

    # reset odom tick counters
    odomCountFrontLeft  = 0
    odomCountRearLeft   = 0
    odomCountFrontRight = 0
    odomCountRearRight  = 0

""" 'main' """
while not rospy.is_shutdown():
    # measure staff and publish odom
    calculateOdometry()

    # Sleep for a second until the next reading.
    rospy.sleep(sleepTime)
<|endoftext|>


<commit_before>#  -*- coding: utf-8 -*-
#  vim: tabstop=4 shiftwidth=4 softtabstop=4

#  Copyright (C) 2016-2017 GEM Foundation

#  OpenQuake is free software: you can redistribute it and/or modify it
#  under the terms of the GNU Affero General Public License as published
#  by the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.

#  OpenQuake 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 Affero General Public License
#  along with OpenQuake.  If not, see <http://www.gnu.org/licenses/>.

import sys
import time
import os.path
import sqlite3
import logging
import threading
import subprocess

from openquake.baselib import config, sap, zeromq as z, workerpool as w
from openquake.baselib.general import socket_ready
from openquake.baselib.parallel import safely_call
from openquake.commonlib import logs
from openquake.server.db import actions
from openquake.server import dbapi
from openquake.server import __file__ as server_path
from openquake.server.settings import DATABASE

db = dbapi.Db(sqlite3.connect, DATABASE['NAME'], isolation_level=None,
              detect_types=sqlite3.PARSE_DECLTYPES, timeout=20)
# NB: I am increasing the timeout from 5 to 20 seconds to see if the random
# OperationalError: "database is locked" disappear in the WebUI tests

ZMQ = os.environ('OQ_DISTRIBUTE', config.distribution.oq_distribute) == 'zmq'

class DbServer(object):
    """
    A server collecting the received commands into a queue
    """
    def __init__(self, db, address, num_workers=5):
        self.db = db
        self.master_host = address[0]
        self.frontend = 'tcp://%s:%s' % address
        self.backend = 'inproc://dbworkers'
        self.num_workers = num_workers
        self.pid = os.getpid()
        self.master = w.WorkerMaster(**config.zworkers)

    def dworker(self, sock):
        # a database worker responding to commands
        for cmd_ in sock:
            cmd, args = cmd_[0], cmd_[1:]
            if cmd == 'getpid':
                sock.send((self.pid, None, None))
                continue
            try:
                func = getattr(actions, cmd)
            except AttributeError:
                sock.send(('Invalid command ' + cmd, ValueError, None))
            else:
                sock.send(safely_call(func, (self.db,) + args))

    def start(self):
        # start database worker threads
        dworkers = []
        for _ in range(self.num_workers):
            sock = z.Socket(self.backend, z.zmq.REP, 'connect')
            threading.Thread(target=self.dworker, args=(sock,)).start()
            dworkers.append(sock)
        logging.warn('DB server started with %s on %s, pid=%d',
                     sys.executable, self.frontend, self.pid)
        if ZMQ:
            # start task_in->task_out streamer thread
            c = config.zworkers
            threading.Thread(
                target=w.streamer,
                args=(self.master_host, c.task_in_port, c.task_out_port)
            ).start()
            logging.warn('Task streamer started from %s -> %s',
                         c.task_in_port, c.task_out_port)

            # start zworkers and wait a bit for them
            msg = self.master.start()
            logging.warn(msg)
            time.sleep(1)

        # start frontend->backend proxy for the database workers
        try:
            z.zmq.proxy(z.bind(self.frontend, z.zmq.ROUTER),
                        z.bind(self.backend, z.zmq.DEALER))
        except (KeyboardInterrupt, z.zmq.ZMQError):
            for sock in dworkers:
                sock.running = False
            logging.warn('DB server stopped')

def different_paths(path1, path2):
    path1 = os.path.realpath(path1)  # expand symlinks
    path2 = os.path.realpath(path2)  # expand symlinks
    # don't care about the extension (it may be .py or .pyc)
    return os.path.splitext(path1)[0] != os.path.splitext(path2)[0]

def get_status(address=None):
    """
    Check if the DbServer is up.

    :param address: pair (hostname, port)
    :returns: 'running' or 'not-running'
    """
    address = address or (config.dbserver.host, config.dbserver.port)
    return 'running' if socket_ready(address) else 'not-running'

def check_foreign():
    """
    Check if we the DbServer is the right one
    """
    if not config.dbserver.multi_user:
        remote_server_path = logs.dbcmd('get_path')
        if different_paths(server_path, remote_server_path):
            return('You are trying to contact a DbServer from another'
                   ' instance (got %s, expected %s)\n'
                   'Check the configuration or stop the foreign'
                   ' DbServer instance') % (remote_server_path, server_path)

def ensure_on():
    """
    Start the DbServer if it is off
    """
    if get_status() == 'not-running':
        if config.dbserver.multi_user:
            sys.exit('Please start the DbServer: '
                     'see the documentation for details')
        # otherwise start the DbServer automatically
        subprocess.Popen([sys.executable, '-m', 'openquake.server.dbserver',
                          '-l', 'INFO'])

        # wait for the dbserver to start
        waiting_seconds = 10
        while get_status() == 'not-running':
            if waiting_seconds == 0:
                sys.exit('The DbServer cannot be started after 10 seconds. '
                         'Please check the configuration')
            time.sleep(1)
            waiting_seconds -= 1

@sap.Script
def run_server(dbhostport=None, dbpath=None, logfile=DATABASE['LOG'],
               loglevel='WARN'):
    """
    Run the DbServer on the given database file and port. If not given,
    use the settings in openquake.cfg.
    """
    if dbhostport:  # assume a string of the form "dbhost:port"
        dbhost, port = dbhostport.split(':')
        addr = (dbhost, int(port))
        DATABASE['PORT'] = int(port)
    else:
        addr = (config.dbserver.host, config.dbserver.port)

    if dbpath:
        DATABASE['NAME'] = dbpath

    # create the db directory if needed
    dirname = os.path.dirname(DATABASE['NAME'])
    if not os.path.exists(dirname):
        os.makedirs(dirname)

    # create and upgrade the db if needed
    db('PRAGMA foreign_keys = ON')  # honor ON DELETE CASCADE
    actions.upgrade_db(db)
    # the line below is needed to work around a very subtle bug of sqlite;
    # we need new connections, see https://github.com/gem/oq-engine/pull/3002
    db.close()

    # configure logging and start the server
    logging.basicConfig(level=getattr(logging, loglevel), filename=logfile)
    try:
        DbServer(db, addr).start()
    finally:
        db.close()

run_server.arg('dbhostport', 'dbhost:port')
run_server.arg('dbpath', 'dbpath')
run_server.arg('logfile', 'log file')
run_server.opt('loglevel', 'WARN or INFO')

if __name__ == '__main__':
    run_server.callfunc()
<commit_msg>Fixed misprint [demos]<commit_after>#  -*- coding: utf-8 -*-
#  vim: tabstop=4 shiftwidth=4 softtabstop=4

#  Copyright (C) 2016-2017 GEM Foundation

#  OpenQuake is free software: you can redistribute it and/or modify it
#  under the terms of the GNU Affero General Public License as published
#  by the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.

#  OpenQuake 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 Affero General Public License
#  along with OpenQuake.  If not, see <http://www.gnu.org/licenses/>.

import sys
import time
import os.path
import sqlite3
import logging
import threading
import subprocess

from openquake.baselib import config, sap, zeromq as z, workerpool as w
from openquake.baselib.general import socket_ready
from openquake.baselib.parallel import safely_call
from openquake.commonlib import logs
from openquake.server.db import actions
from openquake.server import dbapi
from openquake.server import __file__ as server_path
from openquake.server.settings import DATABASE

db = dbapi.Db(sqlite3.connect, DATABASE['NAME'], isolation_level=None,
              detect_types=sqlite3.PARSE_DECLTYPES, timeout=20)
# NB: I am increasing the timeout from 5 to 20 seconds to see if the random
# OperationalError: "database is locked" disappear in the WebUI tests

ZMQ = os.environ.get(
    'OQ_DISTRIBUTE', config.distribution.oq_distribute) == 'zmq'

class DbServer(object):
    """
    A server collecting the received commands into a queue
    """
    def __init__(self, db, address, num_workers=5):
        self.db = db
        self.master_host = address[0]
        self.frontend = 'tcp://%s:%s' % address
        self.backend = 'inproc://dbworkers'
        self.num_workers = num_workers
        self.pid = os.getpid()
        self.master = w.WorkerMaster(**config.zworkers)

    def dworker(self, sock):
        # a database worker responding to commands
        for cmd_ in sock:
            cmd, args = cmd_[0], cmd_[1:]
            if cmd == 'getpid':
                sock.send((self.pid, None, None))
                continue
            try:
                func = getattr(actions, cmd)
            except AttributeError:
                sock.send(('Invalid command ' + cmd, ValueError, None))
            else:
                sock.send(safely_call(func, (self.db,) + args))

    def start(self):
        # start database worker threads
        dworkers = []
        for _ in range(self.num_workers):
            sock = z.Socket(self.backend, z.zmq.REP, 'connect')
            threading.Thread(target=self.dworker, args=(sock,)).start()
            dworkers.append(sock)
        logging.warn('DB server started with %s on %s, pid=%d',
                     sys.executable, self.frontend, self.pid)
        if ZMQ:
            # start task_in->task_out streamer thread
            c = config.zworkers
            threading.Thread(
                target=w.streamer,
                args=(self.master_host, c.task_in_port, c.task_out_port)
            ).start()
            logging.warn('Task streamer started from %s -> %s',
                         c.task_in_port, c.task_out_port)

            # start zworkers and wait a bit for them
            msg = self.master.start()
            logging.warn(msg)
            time.sleep(1)

        # start frontend->backend proxy for the database workers
        try:
            z.zmq.proxy(z.bind(self.frontend, z.zmq.ROUTER),
                        z.bind(self.backend, z.zmq.DEALER))
        except (KeyboardInterrupt, z.zmq.ZMQError):
            for sock in dworkers:
                sock.running = False
            logging.warn('DB server stopped')

def different_paths(path1, path2):
    path1 = os.path.realpath(path1)  # expand symlinks
    path2 = os.path.realpath(path2)  # expand symlinks
    # don't care about the extension (it may be .py or .pyc)
    return os.path.splitext(path1)[0] != os.path.splitext(path2)[0]

def get_status(address=None):
    """
    Check if the DbServer is up.

    :param address: pair (hostname, port)
    :returns: 'running' or 'not-running'
    """
    address = address or (config.dbserver.host, config.dbserver.port)
    return 'running' if socket_ready(address) else 'not-running'

def check_foreign():
    """
    Check if we the DbServer is the right one
    """
    if not config.dbserver.multi_user:
        remote_server_path = logs.dbcmd('get_path')
        if different_paths(server_path, remote_server_path):
            return('You are trying to contact a DbServer from another'
                   ' instance (got %s, expected %s)\n'
                   'Check the configuration or stop the foreign'
                   ' DbServer instance') % (remote_server_path, server_path)

def ensure_on():
    """
    Start the DbServer if it is off
    """
    if get_status() == 'not-running':
        if config.dbserver.multi_user:
            sys.exit('Please start the DbServer: '
                     'see the documentation for details')
        # otherwise start the DbServer automatically
        subprocess.Popen([sys.executable, '-m', 'openquake.server.dbserver',
                          '-l', 'INFO'])

        # wait for the dbserver to start
        waiting_seconds = 10
        while get_status() == 'not-running':
            if waiting_seconds == 0:
                sys.exit('The DbServer cannot be started after 10 seconds. '
                         'Please check the configuration')
            time.sleep(1)
            waiting_seconds -= 1

@sap.Script
def run_server(dbhostport=None, dbpath=None, logfile=DATABASE['LOG'],
               loglevel='WARN'):
    """
    Run the DbServer on the given database file and port. If not given,
    use the settings in openquake.cfg.
    """
    if dbhostport:  # assume a string of the form "dbhost:port"
        dbhost, port = dbhostport.split(':')
        addr = (dbhost, int(port))
        DATABASE['PORT'] = int(port)
    else:
        addr = (config.dbserver.host, config.dbserver.port)

    if dbpath:
        DATABASE['NAME'] = dbpath

    # create the db directory if needed
    dirname = os.path.dirname(DATABASE['NAME'])
    if not os.path.exists(dirname):
        os.makedirs(dirname)

    # create and upgrade the db if needed
    db('PRAGMA foreign_keys = ON')  # honor ON DELETE CASCADE
    actions.upgrade_db(db)
    # the line below is needed to work around a very subtle bug of sqlite;
    # we need new connections, see https://github.com/gem/oq-engine/pull/3002
    db.close()

    # configure logging and start the server
    logging.basicConfig(level=getattr(logging, loglevel), filename=logfile)
    try:
        DbServer(db, addr).start()
    finally:
        db.close()

run_server.arg('dbhostport', 'dbhost:port')
run_server.arg('dbpath', 'dbpath')
run_server.arg('logfile', 'log file')
run_server.opt('loglevel', 'WARN or INFO')

if __name__ == '__main__':
    run_server.callfunc()
<|endoftext|>


<commit_before>#!/usr/bin/env python

import unittest
import numpy as np

from pymatgen.symmetry.settings import *

__author__ = "Matthew Horton"
__copyright__ = "Copyright 2017, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Matthew Horton"
__email__ = "mkhorton@lbl.gov"
__status__ = "Development"
__date__ = "Apr 2017"

class JonesFaithfulTransformationTest(unittest.TestCase):

    def setUp(self):
        self.test_strings = ['a,b,c;0,0,0',  # identity
                             'a-b,a+b,2c;0,0,1/2',
                             'a/4+b/4-c/2,a/4-b/4,-a/2-b/2;0,0,0',
                             'a,b,c;1/4,1/2,3/4']  # pure translation
        self.test_Pps = [([[1, 0, 0], [0, 1, 0], [0, 0, 1]], [0, 0, 0]),
                         ([[1, 1, 0], [-1, 1, 0], [0, 0, 2]], [0, 0, 0.5]),
                         ([[0.25, 0.25, -0.5], [0.25, -0.25, -0.5], [-0.5, 0, 0]], [0, 0, 0]),
                         ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], [0.25, 0.5, 0.75])]

    def test_init(self):
        for test_string, test_Pp in zip(self.test_strings, self.test_Pps):
            jft = JonesFaithfulTransformation.from_transformation_string(test_string)
            jft2 = JonesFaithfulTransformation(test_Pp[0], test_Pp[1])
            self.assertTrue(np.allclose(jft.P, jft2.P))
            self.assertTrue(np.allclose(jft.p, jft2.p))
            self.assertEqual(test_string, jft.transformation_string)
            self.assertEqual(test_string, jft2.transformation_string)

    def test_inverse(self):
        for test_string in self.test_strings:
            jft = JonesFaithfulTransformation.from_transformation_string(test_string)
            self.assertEqual(jft, jft.inverse.inverse)
            self.assertEqual(jft.transformation_string, jft.inverse.inverse.transformation_string)

    def test_transform_lattice(self):
        lattice = Lattice.cubic(5)

        all_ref_lattices = [[[5., 0., 0.], [0., 5., 0.], [0., 0., 5.]],
                            [[5., 5., 0.], [-5., 5., 0.], [0., 0., 10.]],
                            [[1.25, 1.25, -2.5], [1.25, -1.25, -2.5], [-2.5, 0., 0.]],
                            [[5., 0., 0.], [0., 5., 0.], [0., 0., 5.]]]

        for ref_lattice, (P, p) in zip(all_ref_lattices, self.test_Pps):
            jft = JonesFaithfulTransformation(P, p)
            self.assertTrue(np.allclose(jft.transform_lattice(lattice).matrix, ref_lattice))

    def test_transform_coords(self):
        coords = [[0, 0, 0], [0.5, 0.5, 0.5]]

        all_ref_coords = [[[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
                          [[0.0, 0.0, -0.25], [0.0, 0.5, 0.0]],
                          [[0.0, 0.0, 0.0], [-1.0, 0.0, -1.5]],
                          [[-0.25, -0.5, -0.75], [0.25, 0.0, -0.25]]]

        for ref_coords, (P, p) in zip(all_ref_coords, self.test_Pps):
            jft = JonesFaithfulTransformation(P, p)
            transformed_coords = jft.transform_coords(coords)
            for coord, ref_coord in zip(transformed_coords, ref_coords):
                self.assertTrue(np.allclose(coord, ref_coord))

    def test_transform_symmops(self):

        # reference data for this test taken from GENPOS
        # http://cryst.ehu.es/cryst/get_gen.html

        # Fm-3m
        input_symmops = """x,y,z
-x,-y,z
-x,y,-z
x,-y,-z
z,x,y
z,-x,-y
-z,-x,y
-z,x,-y
y,z,x
-y,z,-x
y,-z,-x
-y,-z,x
y,x,-z
-y,-x,-z
y,-x,z
-y,x,z
x,z,-y
-x,z,y
-x,-z,-y
x,-z,y
z,y,-x
z,-y,x
-z,y,x
-z,-y,-x
-x,-y,-z
x,y,-z
x,-y,z
-x,y,z
-z,-x,-y
-z,x,y
z,x,-y
z,-x,y
-y,-z,-x
y,-z,x
-y,z,x
y,z,-x
-y,-x,z
y,x,z
-y,x,-z
y,-x,-z
-x,-z,y
x,-z,-y
x,z,y
-x,z,-y
-z,-y,x
-z,y,-x
z,-y,-x
z,y,x"""

        # Fm-3m transformed by (a-b,a+b,2c;0,0,1/2)
        ref_transformed_symmops = """x,y,z
-x,-y,z
-y,-x,-z-1/2
y,x,-z-1/2
-1/2x-1/2y+z+1/4,1/2x+1/2y+z+1/4,-1/2x+1/2y-1/4
1/2x+1/2y+z+1/4,-1/2x-1/2y+z+1/4,1/2x-1/2y-1/4
1/2x+1/2y-z-1/4,-1/2x-1/2y-z-1/4,-1/2x+1/2y-1/4
-1/2x-1/2y-z-1/4,1/2x+1/2y-z-1/4,1/2x-1/2y-1/4
-1/2x+1/2y-z-1/4,-1/2x+1/2y+z+1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,1/2x-1/2y+z+1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,-1/2x+1/2y-z-1/4,-1/2x-1/2y-1/4
1/2x-1/2y+z+1/4,1/2x-1/2y-z-1/4,1/2x+1/2y-1/4
-x,y,-z-1/2
x,-y,-z-1/2
y,-x,z
-y,x,z
1/2x+1/2y-z-1/4,1/2x+1/2y+z+1/4,1/2x-1/2y-1/4
-1/2x-1/2y-z-1/4,-1/2x-1/2y+z+1/4,-1/2x+1/2y-1/4
-1/2x-1/2y+z+1/4,-1/2x-1/2y-z-1/4,1/2x-1/2y-1/4
1/2x+1/2y+z+1/4,1/2x+1/2y-z-1/4,-1/2x+1/2y-1/4
1/2x-1/2y+z+1/4,-1/2x+1/2y+z+1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,1/2x-1/2y+z+1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,-1/2x+1/2y-z-1/4,1/2x+1/2y-1/4
-1/2x+1/2y-z-1/4,1/2x-1/2y-z-1/4,-1/2x-1/2y-1/4
-x,-y,-z-1/2
x,y,-z-1/2
y,x,z
-y,-x,z
1/2x+1/2y-z-1/4,-1/2x-1/2y-z-1/4,1/2x-1/2y-1/4
-1/2x-1/2y-z-1/4,1/2x+1/2y-z-1/4,-1/2x+1/2y-1/4
-1/2x-1/2y+z+1/4,1/2x+1/2y+z+1/4,1/2x-1/2y-1/4
1/2x+1/2y+z+1/4,-1/2x-1/2y+z+1/4,-1/2x+1/2y-1/4
1/2x-1/2y+z+1/4,1/2x-1/2y-z-1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,-1/2x+1/2y-z-1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,1/2x-1/2y+z+1/4,1/2x+1/2y-1/4
-1/2x+1/2y-z-1/4,-1/2x+1/2y+z+1/4,-1/2x-1/2y-1/4
x,-y,z
-x,y,z
-y,x,-z-1/2
y,-x,-z-1/2
-1/2x-1/2y+z+1/4,-1/2x-1/2y-z-1/4,-1/2x+1/2y-1/4
1/2x+1/2y+z+1/4,1/2x+1/2y-z-1/4,1/2x-1/2y-1/4
1/2x+1/2y-z-1/4,1/2x+1/2y+z+1/4,-1/2x+1/2y-1/4
-1/2x-1/2y-z-1/4,-1/2x-1/2y+z+1/4,1/2x-1/2y-1/4
-1/2x+1/2y-z-1/4,1/2x-1/2y-z-1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,-1/2x+1/2y-z-1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,1/2x-1/2y+z+1/4,-1/2x-1/2y-1/4
1/2x-1/2y+z+1/4,-1/2x+1/2y+z+1/4,1/2x+1/2y-1/4"""

        jft = JonesFaithfulTransformation.from_transformation_string(self.test_strings[1])

        input_symmops = [SymmOp.from_xyz_string(s) for s in input_symmops.split()]
        ref_transformed_symmops = [SymmOp.from_xyz_string(s) for s in ref_transformed_symmops.split()]

        transformed_symmops = [jft.transform_symmop(op) for op in input_symmops]

        for transformed_op, ref_transformed_op in zip(transformed_symmops, ref_transformed_symmops):
            self.assertEqual(transformed_op, ref_transformed_op)

if __name__ == '__main__':
    unittest.main()
<commit_msg>Fixed Jones Faithful test for coordinate wrapping<commit_after>#!/usr/bin/env python

import unittest
import numpy as np

from pymatgen.symmetry.settings import *

__author__ = "Matthew Horton"
__copyright__ = "Copyright 2017, The Materials Project"
__version__ = "0.1"
__maintainer__ = "Matthew Horton"
__email__ = "mkhorton@lbl.gov"
__status__ = "Development"
__date__ = "Apr 2017"

class JonesFaithfulTransformationTest(unittest.TestCase):

    def setUp(self):
        self.test_strings = ['a,b,c;0,0,0',  # identity
                             'a-b,a+b,2c;0,0,1/2',
                             'a/4+b/4-c/2,a/4-b/4,-a/2-b/2;0,0,0',
                             'a,b,c;1/4,1/2,3/4']  # pure translation
        self.test_Pps = [([[1, 0, 0], [0, 1, 0], [0, 0, 1]], [0, 0, 0]),
                         ([[1, 1, 0], [-1, 1, 0], [0, 0, 2]], [0, 0, 0.5]),
                         ([[0.25, 0.25, -0.5], [0.25, -0.25, -0.5], [-0.5, 0, 0]], [0, 0, 0]),
                         ([[1, 0, 0], [0, 1, 0], [0, 0, 1]], [0.25, 0.5, 0.75])]

    def test_init(self):
        for test_string, test_Pp in zip(self.test_strings, self.test_Pps):
            jft = JonesFaithfulTransformation.from_transformation_string(test_string)
            jft2 = JonesFaithfulTransformation(test_Pp[0], test_Pp[1])
            self.assertTrue(np.allclose(jft.P, jft2.P))
            self.assertTrue(np.allclose(jft.p, jft2.p))
            self.assertEqual(test_string, jft.transformation_string)
            self.assertEqual(test_string, jft2.transformation_string)

    def test_inverse(self):
        for test_string in self.test_strings:
            jft = JonesFaithfulTransformation.from_transformation_string(test_string)
            self.assertEqual(jft, jft.inverse.inverse)
            self.assertEqual(jft.transformation_string, jft.inverse.inverse.transformation_string)

    def test_transform_lattice(self):
        lattice = Lattice.cubic(5)

        all_ref_lattices = [[[5., 0., 0.], [0., 5., 0.], [0., 0., 5.]],
                            [[5., 5., 0.], [-5., 5., 0.], [0., 0., 10.]],
                            [[1.25, 1.25, -2.5], [1.25, -1.25, -2.5], [-2.5, 0., 0.]],
                            [[5., 0., 0.], [0., 5., 0.], [0., 0., 5.]]]

        for ref_lattice, (P, p) in zip(all_ref_lattices, self.test_Pps):
            jft = JonesFaithfulTransformation(P, p)
            self.assertTrue(np.allclose(jft.transform_lattice(lattice).matrix, ref_lattice))

    def test_transform_coords(self):
        coords = [[0, 0, 0], [0.5, 0.5, 0.5]]

        all_ref_coords = [[[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]],
                          [[0.0, 0.0, -0.25], [0.0, 0.5, 0.0]],
                          [[0.0, 0.0, 0.0], [-1.0, 0.0, -1.5]],
                          [[-0.25, -0.5, -0.75], [0.25, 0.0, -0.25]]]

        for ref_coords, (P, p) in zip(all_ref_coords, self.test_Pps):
            jft = JonesFaithfulTransformation(P, p)
            transformed_coords = jft.transform_coords(coords)
            for coord, ref_coord in zip(transformed_coords, ref_coords):
                self.assertTrue(np.allclose(coord, ref_coord))

    def test_transform_symmops(self):

        # reference data for this test taken from GENPOS
        # http://cryst.ehu.es/cryst/get_gen.html

        # Fm-3m
        input_symmops = """x,y,z
-x,-y,z
-x,y,-z
x,-y,-z
z,x,y
z,-x,-y
-z,-x,y
-z,x,-y
y,z,x
-y,z,-x
y,-z,-x
-y,-z,x
y,x,-z
-y,-x,-z
y,-x,z
-y,x,z
x,z,-y
-x,z,y
-x,-z,-y
x,-z,y
z,y,-x
z,-y,x
-z,y,x
-z,-y,-x
-x,-y,-z
x,y,-z
x,-y,z
-x,y,z
-z,-x,-y
-z,x,y
z,x,-y
z,-x,y
-y,-z,-x
y,-z,x
-y,z,x
y,z,-x
-y,-x,z
y,x,z
-y,x,-z
y,-x,-z
-x,-z,y
x,-z,-y
x,z,y
-x,z,-y
-z,-y,x
-z,y,-x
z,-y,-x
z,y,x"""

        # Fm-3m transformed by (a-b,a+b,2c;0,0,1/2)
        ref_transformed_symmops = """x,y,z
-x,-y,z
-y,-x,-z+1/2
y,x,-z+1/2
-1/2x-1/2y+z+1/4,1/2x+1/2y+z+1/4,-1/2x+1/2y-1/4
1/2x+1/2y+z+1/4,-1/2x-1/2y+z+1/4,1/2x-1/2y-1/4
1/2x+1/2y-z-1/4,-1/2x-1/2y-z-1/4,-1/2x+1/2y-1/4
-1/2x-1/2y-z-1/4,1/2x+1/2y-z-1/4,1/2x-1/2y-1/4
-1/2x+1/2y-z-1/4,-1/2x+1/2y+z+1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,1/2x-1/2y+z+1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,-1/2x+1/2y-z-1/4,-1/2x-1/2y-1/4
1/2x-1/2y+z+1/4,1/2x-1/2y-z-1/4,1/2x+1/2y-1/4
-x,y,-z+1/2
x,-y,-z+1/2
y,-x,z
-y,x,z
1/2x+1/2y-z-1/4,1/2x+1/2y+z+1/4,1/2x-1/2y-1/4
-1/2x-1/2y-z-1/4,-1/2x-1/2y+z+1/4,-1/2x+1/2y-1/4
-1/2x-1/2y+z+1/4,-1/2x-1/2y-z-1/4,1/2x-1/2y-1/4
1/2x+1/2y+z+1/4,1/2x+1/2y-z-1/4,-1/2x+1/2y-1/4
1/2x-1/2y+z+1/4,-1/2x+1/2y+z+1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,1/2x-1/2y+z+1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,-1/2x+1/2y-z-1/4,1/2x+1/2y-1/4
-1/2x+1/2y-z-1/4,1/2x-1/2y-z-1/4,-1/2x-1/2y-1/4
-x,-y,-z+1/2
x,y,-z+1/2
y,x,z
-y,-x,z
1/2x+1/2y-z-1/4,-1/2x-1/2y-z-1/4,1/2x-1/2y-1/4
-1/2x-1/2y-z-1/4,1/2x+1/2y-z-1/4,-1/2x+1/2y-1/4
-1/2x-1/2y+z+1/4,1/2x+1/2y+z+1/4,1/2x-1/2y-1/4
1/2x+1/2y+z+1/4,-1/2x-1/2y+z+1/4,-1/2x+1/2y-1/4
1/2x-1/2y+z+1/4,1/2x-1/2y-z-1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,-1/2x+1/2y-z-1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,1/2x-1/2y+z+1/4,1/2x+1/2y-1/4
-1/2x+1/2y-z-1/4,-1/2x+1/2y+z+1/4,-1/2x-1/2y-1/4
x,-y,z
-x,y,z
-y,x,-z+1/2
y,-x,-z+1/2
-1/2x-1/2y+z+1/4,-1/2x-1/2y-z-1/4,-1/2x+1/2y-1/4
1/2x+1/2y+z+1/4,1/2x+1/2y-z-1/4,1/2x-1/2y-1/4
1/2x+1/2y-z-1/4,1/2x+1/2y+z+1/4,-1/2x+1/2y-1/4
-1/2x-1/2y-z-1/4,-1/2x-1/2y+z+1/4,1/2x-1/2y-1/4
-1/2x+1/2y-z-1/4,1/2x-1/2y-z-1/4,1/2x+1/2y-1/4
1/2x-1/2y-z-1/4,-1/2x+1/2y-z-1/4,-1/2x-1/2y-1/4
-1/2x+1/2y+z+1/4,1/2x-1/2y+z+1/4,-1/2x-1/2y-1/4
1/2x-1/2y+z+1/4,-1/2x+1/2y+z+1/4,1/2x+1/2y-1/4"""

        jft = JonesFaithfulTransformation.from_transformation_string(self.test_strings[1])

        input_symmops = [SymmOp.from_xyz_string(s) for s in input_symmops.split()]
        ref_transformed_symmops = [SymmOp.from_xyz_string(s) for s in ref_transformed_symmops.split()]

        transformed_symmops = [jft.transform_symmop(op) for op in input_symmops]

        for transformed_op, ref_transformed_op in zip(transformed_symmops, ref_transformed_symmops):
            self.assertEqual(transformed_op, ref_transformed_op)

if __name__ == '__main__':
    unittest.main()
<|endoftext|>


<commit_before>from couchdbkit import ResourceNotFound
from casexml.apps.case.dbaccessors import get_reverse_indices_for_case_id
from casexml.apps.case.util import get_case_xform_ids, post_case_blocks
from casexml.apps.phone.models import SyncLog
from corehq.apps.hqcase.dbaccessors import get_case_ids_in_domain
from corehq.util.test_utils import unit_testing_only

from dimagi.utils.couch.undo import DELETED_SUFFIX
from dimagi.utils.couch.database import iter_docs, safe_delete
from casexml.apps.case.models import CommCareCase
from couchforms.util import process_xform
from couchforms.models import doc_types, XFormInstance, XFormError
from couchforms.exceptions import UnexpectedDeletedXForm

from .exceptions import CaseNotFound, XFormNotFound
from .utils import to_generic

class FormProcessorInterface(object):
    """
    The FormProcessorInterface serves as the base transactions that take place in forms. Different
    backends can implement this class in order to make common interface.
    """

    @staticmethod
    @to_generic
    def create_from_generic(generic_xform, generic_attachment=None):
        xform = XFormInstance.from_generic(generic_xform)
        xform.save()
        if generic_attachment:
            xform.put_attachment(**generic_attachment.to_json())
        return xform

    @staticmethod
    @to_generic
    def create_case_from_generic(generic_case):
        case = CommCareCase.from_generic(generic_case)
        case.save()
        return case

    @staticmethod
    def get_attachment(xform_id, attachment_name):
        return XFormInstance.get_db().fetch_attachment(xform_id, attachment_name)

    @classmethod
    def archive_xform(cls, xform_generic, user=None):
        xform = cls._get_xform(xform_generic.id)
        return xform.archive(user=user)

    @classmethod
    def unarchive_xform(cls, xform_generic, user=None):
        xform = cls._get_xform(xform_generic.id)
        return xform.unarchive(user=user)

    @classmethod
    def get_xml_element(cls, xform_generic):
        xform = cls._get_xform(xform_generic.id)
        return xform.get_xml_element()

    @classmethod
    @to_generic
    def get_xform(cls, xform_id):
        try:
            return cls._get_xform(xform_id)
        except ResourceNotFound:
            raise XFormNotFound

    @staticmethod
    def _get_xform(xform_id):
        db = XFormInstance.get_db()
        doc = db.get(xform_id)
        if doc['doc_type'] in doc_types():
            return doc_types()[doc['doc_type']].wrap(doc)
        if doc['doc_type'] == "%s%s" % (XFormInstance.__name__, DELETED_SUFFIX):
            raise UnexpectedDeletedXForm(xform_id)
        raise ResourceNotFound(xform_id)

    @classmethod
    @to_generic
    def get_case(cls, case_id):
        try:
            return cls._get_case(case_id)
        except ResourceNotFound:
            raise CaseNotFound

    @staticmethod
    def _get_case(case_id):
        return CommCareCase.get(case_id)

    @staticmethod
    @to_generic
    def get_cases(case_ids):
        return [
            CommCareCase.wrap(doc) for doc in iter_docs(
                CommCareCase.get_db(),
                case_ids
            )
        ]

    @staticmethod
    def get_cases_in_domain(domain):
        case_ids = FormProcessorInterface.get_case_ids_in_domain(domain)
        return FormProcessorInterface.get_cases(case_ids)

    @staticmethod
    def get_case_ids_in_domain(domain):
        return get_case_ids_in_domain(domain)

    @staticmethod
    def get_reverse_indices(domain, case_id):
        return get_reverse_indices_for_case_id(domain, case_id)

    @staticmethod
    @to_generic
    def get_by_doc_type(domain, doc_type):
        return XFormError.view(
            'domain/docs',
            startkey=[domain, doc_type],
            endkey=[domain, doc_type, {}],
            reduce=False,
            include_docs=True,
        ).all()

    @classmethod
    @to_generic
    def update_properties(cls, xform_generic, **properties):
        xform = cls._get_xform(xform_generic.id)
        for prop, value in properties.iteritems():
            setattr(xform, prop, value)
        xform.save()
        return xform

    @classmethod
    @to_generic
    def update_case_properties(cls, case_generic, **properties):
        case = cls._get_case(case_generic.id)
        for prop, value in properties.iteritems():
            setattr(case, prop, value)
        case.save()
        return case

    @staticmethod
    def get_case_xform_ids_from_couch(case_id):
        return get_case_xform_ids(case_id)

    @staticmethod
    @to_generic
    @unit_testing_only
    def post_xform(instance_xml, attachments=None, process=None, domain='test-domain'):
        """
        create a new xform and releases the lock

        this is a testing entry point only and is not to be used in real code

        """
        if not process:
            def process(xform):
                xform.domain = domain
        xform_lock = process_xform(instance_xml, attachments=attachments, process=process, domain=domain)
        with xform_lock as xforms:
            for xform in xforms:
                xform.save()
            return xforms[0]

    @staticmethod
    def submit_form_locally(instance, domain='test-domain', **kwargs):
        from corehq.apps.receiverwrapper.util import submit_form_locally
        response, xform, cases = submit_form_locally(instance, domain, **kwargs)
        # response is an iterable to @to_generic doesn't work
        return response, xform.to_generic(), [case.to_generic() for case in cases]

    @staticmethod
    @to_generic
    def post_case_blocks(case_blocks, form_extras=None, domain=None):
        return post_case_blocks(case_blocks, form_extras=form_extras, domain=domain)

    @classmethod
    def soft_delete_case(cls, case_id):
        case = cls._get_case(case_id)
        case.doc_type += DELETED_SUFFIX
        case.save()

    @classmethod
    def hard_delete_case(cls, case_generic):
        from casexml.apps.case.cleanup import safe_hard_delete
        case = cls._get_case(case_generic.id)
        safe_hard_delete(case)

    @classmethod
    @unit_testing_only
    def delete_all_cases(cls):
        cls._delete_all(CommCareCase.get_db(), 'case/get_lite')

    @classmethod
    @unit_testing_only
    def delete_all_xforms(cls):
        cls._delete_all(XFormInstance.get_db(), 'couchforms/all_submissions_by_domain')

    @classmethod
    @unit_testing_only
    def delete_all_sync_logs(cls):
        cls._delete_all(SyncLog.get_db(), 'phone/sync_logs_by_user')

    @staticmethod
    def _delete_all(db, viewname):
        deleted = set()
        for row in db.view(viewname, reduce=False):
            doc_id = row['id']
            if id not in deleted:
                try:
                    safe_delete(db, doc_id)
                    deleted.add(doc_id)
                except ResourceNotFound:
                    pass
<commit_msg>fix spelling [ci skip]<commit_after>from couchdbkit import ResourceNotFound
from casexml.apps.case.dbaccessors import get_reverse_indices_for_case_id
from casexml.apps.case.util import get_case_xform_ids, post_case_blocks
from casexml.apps.phone.models import SyncLog
from corehq.apps.hqcase.dbaccessors import get_case_ids_in_domain
from corehq.util.test_utils import unit_testing_only

from dimagi.utils.couch.undo import DELETED_SUFFIX
from dimagi.utils.couch.database import iter_docs, safe_delete
from casexml.apps.case.models import CommCareCase
from couchforms.util import process_xform
from couchforms.models import doc_types, XFormInstance, XFormError
from couchforms.exceptions import UnexpectedDeletedXForm

from .exceptions import CaseNotFound, XFormNotFound
from .utils import to_generic

class FormProcessorInterface(object):
    """
    The FormProcessorInterface serves as the base transactions that take place in forms. Different
    backends can implement this class in order to make common interface.
    """

    @staticmethod
    @to_generic
    def create_from_generic(generic_xform, generic_attachment=None):
        xform = XFormInstance.from_generic(generic_xform)
        xform.save()
        if generic_attachment:
            xform.put_attachment(**generic_attachment.to_json())
        return xform

    @staticmethod
    @to_generic
    def create_case_from_generic(generic_case):
        case = CommCareCase.from_generic(generic_case)
        case.save()
        return case

    @staticmethod
    def get_attachment(xform_id, attachment_name):
        return XFormInstance.get_db().fetch_attachment(xform_id, attachment_name)

    @classmethod
    def archive_xform(cls, xform_generic, user=None):
        xform = cls._get_xform(xform_generic.id)
        return xform.archive(user=user)

    @classmethod
    def unarchive_xform(cls, xform_generic, user=None):
        xform = cls._get_xform(xform_generic.id)
        return xform.unarchive(user=user)

    @classmethod
    def get_xml_element(cls, xform_generic):
        xform = cls._get_xform(xform_generic.id)
        return xform.get_xml_element()

    @classmethod
    @to_generic
    def get_xform(cls, xform_id):
        try:
            return cls._get_xform(xform_id)
        except ResourceNotFound:
            raise XFormNotFound

    @staticmethod
    def _get_xform(xform_id):
        db = XFormInstance.get_db()
        doc = db.get(xform_id)
        if doc['doc_type'] in doc_types():
            return doc_types()[doc['doc_type']].wrap(doc)
        if doc['doc_type'] == "%s%s" % (XFormInstance.__name__, DELETED_SUFFIX):
            raise UnexpectedDeletedXForm(xform_id)
        raise ResourceNotFound(xform_id)

    @classmethod
    @to_generic
    def get_case(cls, case_id):
        try:
            return cls._get_case(case_id)
        except ResourceNotFound:
            raise CaseNotFound

    @staticmethod
    def _get_case(case_id):
        return CommCareCase.get(case_id)

    @staticmethod
    @to_generic
    def get_cases(case_ids):
        return [
            CommCareCase.wrap(doc) for doc in iter_docs(
                CommCareCase.get_db(),
                case_ids
            )
        ]

    @staticmethod
    def get_cases_in_domain(domain):
        case_ids = FormProcessorInterface.get_case_ids_in_domain(domain)
        return FormProcessorInterface.get_cases(case_ids)

    @staticmethod
    def get_case_ids_in_domain(domain):
        return get_case_ids_in_domain(domain)

    @staticmethod
    def get_reverse_indices(domain, case_id):
        return get_reverse_indices_for_case_id(domain, case_id)

    @staticmethod
    @to_generic
    def get_by_doc_type(domain, doc_type):
        return XFormError.view(
            'domain/docs',
            startkey=[domain, doc_type],
            endkey=[domain, doc_type, {}],
            reduce=False,
            include_docs=True,
        ).all()

    @classmethod
    @to_generic
    def update_properties(cls, xform_generic, **properties):
        xform = cls._get_xform(xform_generic.id)
        for prop, value in properties.iteritems():
            setattr(xform, prop, value)
        xform.save()
        return xform

    @classmethod
    @to_generic
    def update_case_properties(cls, case_generic, **properties):
        case = cls._get_case(case_generic.id)
        for prop, value in properties.iteritems():
            setattr(case, prop, value)
        case.save()
        return case

    @staticmethod
    def get_case_xform_ids_from_couch(case_id):
        return get_case_xform_ids(case_id)

    @staticmethod
    @to_generic
    @unit_testing_only
    def post_xform(instance_xml, attachments=None, process=None, domain='test-domain'):
        """
        create a new xform and releases the lock

        this is a testing entry point only and is not to be used in real code

        """
        if not process:
            def process(xform):
                xform.domain = domain
        xform_lock = process_xform(instance_xml, attachments=attachments, process=process, domain=domain)
        with xform_lock as xforms:
            for xform in xforms:
                xform.save()
            return xforms[0]

    @staticmethod
    def submit_form_locally(instance, domain='test-domain', **kwargs):
        from corehq.apps.receiverwrapper.util import submit_form_locally
        response, xform, cases = submit_form_locally(instance, domain, **kwargs)
        # response is an iterable so @to_generic doesn't work
        return response, xform.to_generic(), [case.to_generic() for case in cases]

    @staticmethod
    @to_generic
    def post_case_blocks(case_blocks, form_extras=None, domain=None):
        return post_case_blocks(case_blocks, form_extras=form_extras, domain=domain)

    @classmethod
    def soft_delete_case(cls, case_id):
        case = cls._get_case(case_id)
        case.doc_type += DELETED_SUFFIX
        case.save()

    @classmethod
    def hard_delete_case(cls, case_generic):
        from casexml.apps.case.cleanup import safe_hard_delete
        case = cls._get_case(case_generic.id)
        safe_hard_delete(case)

    @classmethod
    @unit_testing_only
    def delete_all_cases(cls):
        cls._delete_all(CommCareCase.get_db(), 'case/get_lite')

    @classmethod
    @unit_testing_only
    def delete_all_xforms(cls):
        cls._delete_all(XFormInstance.get_db(), 'couchforms/all_submissions_by_domain')

    @classmethod
    @unit_testing_only
    def delete_all_sync_logs(cls):
        cls._delete_all(SyncLog.get_db(), 'phone/sync_logs_by_user')

    @staticmethod
    def _delete_all(db, viewname):
        deleted = set()
        for row in db.view(viewname, reduce=False):
            doc_id = row['id']
            if id not in deleted:
                try:
                    safe_delete(db, doc_id)
                    deleted.add(doc_id)
                except ResourceNotFound:
                    pass
<|endoftext|>