<commit_before># Copyright (c) 2014, Guillermo López-Anglada. Please see the AUTHORS file for details.
# All rights reserved. Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.)

import logging
import os

import sublime

# If we don't do this, logging will fail sometimes. :-/
logging.basicConfig()

class PluginLogger(object):
    """A logger intented to be used from plugin files inside this package.
    """
    def __init__(self, name):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.ERROR)

    def debug(self, msg, *args, **kwargs):
        self.logger.debug(msg, *args, **kwargs)

    def info(self, msg, *args, **kwargs):
        self.logger.info(msg, *args, **kwargs)

    def warning(self, msg, *args, **kwargs):
        self.logger.warning(msg, *args, **kwargs)

    def error(self, msg, *args, **kwargs):
        self.logger.error(msg, *args, **kwargs)

    def critical(self, msg, *args, **kwargs):
        self.logger.critical(msg, *args, **kwargs)
<commit_msg>subtree: add logging facilities<commit_after># Copyright (c) 2014, Guillermo López-Anglada. Please see the AUTHORS file for details.
# All rights reserved. Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.)

from logging.handlers import RotatingFileHandler
from os import path
import logging
import logging.config
import logging.handlers
import os
import sys

class LogDir(object):
    '''
    Locates the log dir for plugin logs.
    '''

    @staticmethod
    def find():
        return LogDir()._find_log_dir()

    def _test(self, a, b):
        if a == b:
            return 'folder'
        elif a == b + '.sublime-package':
            return 'sublime-package'

    def _find_path(self, start, package):
        while True:
            result = self._test(os.path.basename(start), package)

            if result == 'folder':
                if os.path.exists(path.join(path.dirname(start), 'User')):
                    return path.join(path.dirname(start), '.logs')

            elif result == 'sublime-package':
                parent = path.dirname(start)
                if path.exists(path.join(path.dirname(parent), 'Packages')):
                    return path.join(path.dirname(parent), 'Packages', '.logs')

            if path.dirname(start) == start:
                return

            start = path.dirname(start)

    def _find_log_dir(self):
        package = __name__.split('.')[0]

        if package == '__main__':
            return

        start = path.dirname(__file__)

        logs_path = self._find_path(start, package)

        if not logs_path:
            return

        if not path.exists(logs_path):
            os.mkdir(logs_path)
        return logs_path

class NullPluginLogger(object):
    '''
    Supresses log records.
    '''

    def __init__(self, name):
        pass

    def debug(self, message, *args, **kwargs):
        pass

    def info(self, message, *args, **kwargs):
        pass

    def warn(self, message, *args, **kwargs):
        pass

    def warning(self, message, *args, **kwargs):
        pass

    def error(self, message, *args, **kwargs):
        pass

    def critical(self, message, *args, **kwargs):
        pass

class PluginLogger(object):
    '''
    Logs events.
    '''

    log_dir = LogDir.find()

    def __init__(self, name):
        self.logger = logging.getLogger(name)
        default_level = logging.ERROR
        user_level = self._get_log_level_from_file()
        self.logger.setLevel(user_level if user_level is not None else default_level)

        f = logging.Formatter('%(asctime)s %(levelname)-5s %(name)s %(message)s')

        consoleHandler = logging.StreamHandler()
        consoleHandler.setLevel(logging.WARNING)
        consoleHandler.setFormatter(f)
        self.logger.addHandler(consoleHandler)

        file_name = self._file_name()
        if file_name:
            # FIXME: RotatingFileHandler does not rollover ever.
            if os.path.exists(file_name):
                try:
                    os.uznlink(file_name)
                except:
                    pass
            fileHandler = RotatingFileHandler(file_name, maxBytes=1<<20)
            fileHandler.setFormatter(f)
            self.logger.addHandler(fileHandler)
        else:
            print("cannot find log file path: %s" % file_name)

    def warn_aboug_logging_level(self):
        if self.logger.level <= logging.DEBUG:
            package = __name__.split('.')[0]
            self.warning("debug level set to DEBUG; check or delete %s", self._get_path_to_log())

    def _get_path_to_log(self):
        package = __name__.split('.')[0]
        p = os.path.join(self.log_dir, package)
        return p

    def _get_log_level_from_file(self):
        p = self._get_path_to_log()
        if os.path.exists(p):
            with open(p, 'rt') as f:
                text = f.read().strip().upper()
                return getattr(logging, text, None)

    def _file_name(self):
        p = __name__.split('.')[0]
        return os.path.join(self.log_dir, '{}.log'.format(p))

    def debug(self, message, *args, **kwargs):
        self.logger.debug(message, *args, **kwargs)

    def info(self, message, *args, **kwargs):
        self.logger.info(message, *args, **kwargs)

    def warn(self, message, *args, **kwargs):
        self.logger.warning(message, *args, **kwargs)

    def warning(self, message, *args, **kwargs):
        self.logger.warning(message, *args, **kwargs)

    def error(self, message, *args, **kwargs):
        self.logger.error(message, *args, **kwargs)

    def critical(self, message, *args, **kwargs):
        self.logger.critical(message, *args, **kwargs)
<|endoftext|>


<commit_before>from django.conf import settings
from django.db import models
from meetup.api import MeetupClient
import datetime

STATUSES = [(s, s) for s in ('past','pending','upcoming')]
API_KEY = getattr(settings, 'MEETUP_KEY', None)

class Account(models.Model):
    key = models.CharField(max_length=128)
    description = models.CharField(max_length=128)
    slug = models.SlugField()
    container_id = models.CharField(max_length=16, blank=True)
    sync = models.BooleanField(default=True)

    def __unicode__(self):
        return self.slug

    def past_events(self):
        return self.events.filter(status='past')

    def upcoming_events(self):
        return self.events.filter(status='upcoming')

class EventManager(models.Manager):
    def past(self):
        return Event.objects.filter(status='past')
    def upcoming(self):
        return Event.objects.filter(status='upcoming')

class Event(models.Model):

    objects = EventManager()

    account = models.ForeignKey(Account, related_name="events")

    # Meetup.com fields
    id = models.CharField(max_length=255, primary_key=True)
    meetup_url = models.URLField(verify_exists=False)
    title = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    start_time = models.DateTimeField(blank=True, null=True)
    location = models.CharField(max_length=255, blank=True)
    address = models.CharField(max_length=128, blank=True)
    city = models.CharField(max_length=64, blank=True)
    state = models.CharField(max_length=64, blank=True)
    zipcode = models.CharField(max_length=10, blank=True)
    latitude = models.CharField(max_length=16, blank=True)
    longitude = models.CharField(max_length=16, blank=True)
    url = models.URLField(verify_exists=False, max_length=255, blank=True)
    rsvp_count = models.IntegerField(default=0)
    timestamp = models.DateTimeField()
    status = models.CharField(max_length=16, choices=STATUSES)
    organizer_id = models.CharField(max_length=32, blank=True)
    organizer_name = models.CharField(max_length=128, blank=True)

    # user defined fields
    # none for now, add tags later

    class Meta:
        ordering = ('start_time',)

    def __unicode__(self):
        return self.pk

    def save(self, sync=True, **kwargs):
        super(Event, self).save(**kwargs)
        # if sync:
        #     api_client = MeetupClient(self.account.key)
        #     api_client.update_event(self.pk, udf_category=self.category)

    def city_state(self):
        if self.city:
            if self.state:
                return "%s, %s" % (self.city, self.state)
            else:
                return self.city
        elif self.state:
            return self.state
        else:
            return ''

    def short_description(self, length=64):
        if len(self.description) > length:
            desc = self.description[:length]
            if desc.endswith(' '):
                desc = desc[:-1]
            return desc + '...'
        return self.description<commit_msg>update models to add meetup_url on account<commit_after>from django.conf import settings
from django.db import models
from meetup.api import MeetupClient
import datetime

STATUSES = [(s, s) for s in ('past','pending','upcoming')]
API_KEY = getattr(settings, 'MEETUP_KEY', None)

class Account(models.Model):
    key = models.CharField(max_length=128)
    description = models.CharField(max_length=128)
    slug = models.SlugField()
    container_id = models.CharField(max_length=16, blank=True)
    meetup_url = models.URLField(verify_exists=False, blank=True)
    sync = models.BooleanField(default=True)

    def __unicode__(self):
        return self.slug

    def past_events(self):
        return self.events.filter(status='past')

    def upcoming_events(self):
        return self.events.exclude(status='past')

class EventManager(models.Manager):
    def past(self):
        return Event.objects.filter(status='past')
    def upcoming(self):
        return Event.objects.exclude(status='past')

class Event(models.Model):

    objects = EventManager()

    account = models.ForeignKey(Account, related_name="events")

    # Meetup.com fields
    id = models.CharField(max_length=255, primary_key=True)
    meetup_url = models.URLField(verify_exists=False)
    title = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    start_time = models.DateTimeField(blank=True, null=True)
    location = models.CharField(max_length=255, blank=True)
    address = models.CharField(max_length=128, blank=True)
    city = models.CharField(max_length=64, blank=True)
    state = models.CharField(max_length=64, blank=True)
    zipcode = models.CharField(max_length=10, blank=True)
    latitude = models.CharField(max_length=16, blank=True)
    longitude = models.CharField(max_length=16, blank=True)
    url = models.URLField(verify_exists=False, max_length=255, blank=True)
    rsvp_count = models.IntegerField(default=0)
    timestamp = models.DateTimeField()
    status = models.CharField(max_length=16, choices=STATUSES)
    organizer_id = models.CharField(max_length=32, blank=True)
    organizer_name = models.CharField(max_length=128, blank=True)

    # user defined fields
    # none for now, add tags later

    class Meta:
        ordering = ('start_time',)

    def __unicode__(self):
        return self.pk

    def save(self, sync=True, **kwargs):
        super(Event, self).save(**kwargs)
        # if sync:
        #     api_client = MeetupClient(self.account.key)
        #     api_client.update_event(self.pk, udf_category=self.category)

    def city_state(self):
        if self.city:
            if self.state:
                return "%s, %s" % (self.city, self.state)
            else:
                return self.city
        elif self.state:
            return self.state
        else:
            return ''

    def short_description(self, length=64):
        if len(self.description) > length:
            desc = self.description[:length]
            if desc.endswith(' '):
                desc = desc[:-1]
            return desc + '...'
        return self.description<|endoftext|>


<commit_before>from django.db import models
from pizzaplace.models import PizzaPlace
from django.core.validators import RegexValidator
from meetup.services.meetup_api_lookup_agent import MeetupApiLookupAgent
from django.core.exceptions import ValidationError

def validate_urlname(link):
  validator = RegexValidator(
    regex='meetup\.com\/\w+(-\w+)*\/$',
    message="Does not conform to Meetup Url",
    code='invalid_url')
  return validator(link)

def validate_meetup_exists(link):
  looker = MeetupApiLookupAgent(link)
  is_real = looker.is_real_meetup()

  if not is_real:
    raise ValidationError("That's not a meetup")

class Meetup(models.Model):
  name = models.CharField(max_length=500, null=False, blank=False, default=None, unique=True)
  meetup_link = models.URLField(max_length=500,
                                unique=True,
                                default=None,
                                validators=[validate_urlname, validate_meetup_exists])
  pizza_places = models.ManyToManyField(PizzaPlace)

  def __str__(self):
    return self.name

<commit_msg>Improve meetup's validation error messages<commit_after>from django.db import models
from pizzaplace.models import PizzaPlace
from django.core.validators import RegexValidator
from meetup.services.meetup_api_lookup_agent import MeetupApiLookupAgent
from django.core.exceptions import ValidationError
from model_utils.models import TimeStampedModel

def validate_urlname(link):
  validator = RegexValidator(
    regex='meetup\.com\/\w+(-\w+)*\/$',
    message="Url should be in form 'meetup.com/meetup-name/'",
    code='invalid_url')
  return validator(link)

def validate_meetup_exists(link):
  if not MeetupApiLookupAgent(link).meetup_exists():
    raise ValidationError("Meetup not found on meetup.com")

class Meetup(TimeStampedModel):
  name = models.CharField(max_length=500, null=False, blank=False, default=None, unique=True)
  meetup_link = models.URLField(max_length=500,
                                unique=True,
                                default=None,
                                validators=[validate_urlname, validate_meetup_exists])
  pizza_places = models.ManyToManyField(PizzaPlace)

  def __str__(self):
    return self.name

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# The MIT License (MIT)
#
# Copyright (c) 2015 Iuri Gomes Diniz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from datetime import datetime
from itertools import chain, combinations
from unicodedata import normalize

from google.appengine.ext import ndb

from flask import Flask, make_response, redirect, request
from flask.json import jsonify

# from google.appengine.api import users
app = Flask(__name__)
app.debug = True

# @app.route("/signin")
# def signin():
#     response = make_response()
#     user = users.get_current_user()

#     if user:
#         print "user"
#         response.headers['Content-Type'] = 'text/html; charset=utf-8'
#         response.set_data('Hello, ' + user.nickname())
#     else:
#         redirect(users.create_login_url(request.url))

#     return response

#################################################################
# Utility Functions

def iconv(input_str):
    if type(input_str) == str:
        # assume utf-8 strings
        input_str = input_str.decode('utf-8')
    return normalize("NFKD", input_str).encode('ascii', 'ignore')

def onlynumbers(obj, input_str, *args, **kwargs):
    return ''.join(filter(lambda x: x.isdigit(), str(input_str)))

def powerset(iterable):
    # from https://docs.python.org/2/library/itertools.html#recipes
    xs = list(iterable)
    # note we return an iterator rather than a list
    return chain.from_iterable(combinations(xs, n) for n in range(len(xs) + 1))

def tokenize(phrase, minimum=None, maximum=None, onlystart=True, combine=True):
    GOOD_NUMBER = 4
    if minimum is not None and maximum is None:
        # only minimum defined
        maximum = minimum + GOOD_NUMBER
    elif maximum is not None and minimum is None:
        # only maximum defined
        minimum = maximum - GOOD_NUMBER
    elif maximum is None and minimum is None:
        # both undefined
        minimum = GOOD_NUMBER
        maximum = minimum + GOOD_NUMBER

    if minimum < 1:
        minimum = 1
    if maximum < 1:
        maximum = 1

    tokens = set()
    words = filter(lambda x: len(x) >= minimum, str(phrase).split())
    # add each word and word combination
    if not combine:
        for word in words:
            tokens.add(word)
    else:
        for combination in [" ".join(s) for s in  powerset(words)]:
            if len(combination):
                tokens.add(combination)

    for word in words:
        # add partial words
        length = len(word)

        for i in xrange(1 if onlystart else length):
            first = i + minimum
            last = maximum + i
            if last > length:
                last = length
            if first > length:
                first = length
            for j in xrange(i + minimum, last + 1):
                tokens.add(word[i:j])

    return tokens

# Models
blood_types = ('A+', 'B+', 'AB+', "O+", 'A-', 'B-', 'AB-', "O-")

class Patient(ndb.Model):
    name = ndb.StringProperty(indexed=False, required=True)
    code = ndb.StringProperty(indexed=True, required=True, validator=onlynumbers)
    blood_type = ndb.StringProperty(indexed=False, required=True, choices=blood_types)
    name_tags = ndb.ComputedProperty(lambda self: self._gen_tokens_for_name(self.name), repeated=True)
    code_tags = ndb.ComputedProperty(lambda self: self._gen_tokens_for_code(self.code), repeated=True)

    def _gen_tokens_for_name(self, name):
        return list(tokenize(iconv(name.lower()), minimum=4, maximum=4))
    def _gen_tokens_for_code(self, code):
        return list(tokenize(iconv(code.lower())))

class BloodBag(ndb.Model):
    type_ = ndb.StringProperty(indexed=False, required=True, choices=blood_types)
    content = ndb.StringProperty()

class Transfusion(ndb.Model):
    patient = ndb.StructuredProperty(Patient)
    nhh_code = ndb.StringProperty(indexed=True, required=True, validator=onlynumbers)
    date = ndb.DateProperty(indexed=True, required=True)
    local = ndb.StringProperty(indexed=False, required=True)
    bags = ndb.LocalStructuredProperty(BloodBag, repeated=True)
    tags = ndb.StringProperty(repeated=True, indexed=False,
                              choices=['rt', "ficha_preenchida", "carimbo_plantao", "carimbo_nhh", "anvisa"])
    text = ndb.TextProperty(required=False)

    added_at = ndb.DateTimeProperty(auto_now_add=True, indexed=False)
    updated_at = ndb.DateTimeProperty(auto_now=True, indexed=False)

@app.route("/")
def hello():
    return make_response("MEJC RT", 200, {})

@app.route("/api/create", methods=['POST'])
def create():
    """"
    example:
    {
        "name": "John Heyder Oliveira de Medeiros Galvão",
        "record": "12345/0",
        "blood_type": "O+",
        "date": "2015-05-22",
        "local": "UTINEO",
        "blood_bags" :
        [
            {
                "type": "O-",
                "content": "CHPLI"
            }
        ],
        "text": "",
        "tags": [],
        "nhh_code": "20900"
    }

    """
    if not hasattr(request, 'json'):
        return make_response(jsonify(code="ERROR"), 500, {})

    patient = request.json.get('name', None)
    record_code = request.json.get('record', None)
    blood_type = request.json.get('blood_type', None)
    transfusion_date = request.json.get('date', None)
    transfusion_local = request.json.get('local', None)
    bags = []
    for bag in request.json.get('bags', []):
        bags.put(BloodBag(type_=bag['type'], content=bag['content']))
    text = request.json.get('text', None) or None
    tags = request.json.get('tags', [])

    nhh_code = request.json.get('nhh_code', None)
    tr = Transfusion(patient=Patient(name=patient,
                                     blood_type=blood_type,
                                     code=record_code),
                     nhh_code=nhh_code,
                     date=datetime.strptime(transfusion_date, "%Y-%m-%d"),
                     local=transfusion_local,
                     bags=bags,
                     tags=tags,
                     text=text)
    key = tr.put()

    return make_response(jsonify(code="OK", key=key.urlsafe()), 200, {})
<commit_msg>fix url for create<commit_after># -*- coding: utf-8 -*-
# The MIT License (MIT)
#
# Copyright (c) 2015 Iuri Gomes Diniz
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

from datetime import datetime
from itertools import chain, combinations
from unicodedata import normalize

from google.appengine.ext import ndb

from flask import Flask, make_response, redirect, request
from flask.json import jsonify

# from google.appengine.api import users
app = Flask(__name__)
app.debug = True

# @app.route("/signin")
# def signin():
#     response = make_response()
#     user = users.get_current_user()

#     if user:
#         print "user"
#         response.headers['Content-Type'] = 'text/html; charset=utf-8'
#         response.set_data('Hello, ' + user.nickname())
#     else:
#         redirect(users.create_login_url(request.url))

#     return response

#################################################################
# Utility Functions

def iconv(input_str):
    if type(input_str) == str:
        # assume utf-8 strings
        input_str = input_str.decode('utf-8')
    return normalize("NFKD", input_str).encode('ascii', 'ignore')

def onlynumbers(obj, input_str, *args, **kwargs):
    return ''.join(filter(lambda x: x.isdigit(), str(input_str)))

def powerset(iterable):
    # from https://docs.python.org/2/library/itertools.html#recipes
    xs = list(iterable)
    # note we return an iterator rather than a list
    return chain.from_iterable(combinations(xs, n) for n in range(len(xs) + 1))

def tokenize(phrase, minimum=None, maximum=None, onlystart=True, combine=True):
    GOOD_NUMBER = 4
    if minimum is not None and maximum is None:
        # only minimum defined
        maximum = minimum + GOOD_NUMBER
    elif maximum is not None and minimum is None:
        # only maximum defined
        minimum = maximum - GOOD_NUMBER
    elif maximum is None and minimum is None:
        # both undefined
        minimum = GOOD_NUMBER
        maximum = minimum + GOOD_NUMBER

    if minimum < 1:
        minimum = 1
    if maximum < 1:
        maximum = 1

    tokens = set()
    words = filter(lambda x: len(x) >= minimum, str(phrase).split())
    # add each word and word combination
    if not combine:
        for word in words:
            tokens.add(word)
    else:
        for combination in [" ".join(s) for s in  powerset(words)]:
            if len(combination):
                tokens.add(combination)

    for word in words:
        # add partial words
        length = len(word)

        for i in xrange(1 if onlystart else length):
            first = i + minimum
            last = maximum + i
            if last > length:
                last = length
            if first > length:
                first = length
            for j in xrange(i + minimum, last + 1):
                tokens.add(word[i:j])

    return tokens

# Models
blood_types = ('A+', 'B+', 'AB+', "O+", 'A-', 'B-', 'AB-', "O-")

class Patient(ndb.Model):
    name = ndb.StringProperty(indexed=False, required=True)
    code = ndb.StringProperty(indexed=True, required=True, validator=onlynumbers)
    blood_type = ndb.StringProperty(indexed=False, required=True, choices=blood_types)
    name_tags = ndb.ComputedProperty(lambda self: self._gen_tokens_for_name(self.name), repeated=True)
    code_tags = ndb.ComputedProperty(lambda self: self._gen_tokens_for_code(self.code), repeated=True)

    def _gen_tokens_for_name(self, name):
        return list(tokenize(iconv(name.lower()), minimum=4, maximum=4))
    def _gen_tokens_for_code(self, code):
        return list(tokenize(iconv(code.lower())))

class BloodBag(ndb.Model):
    type_ = ndb.StringProperty(indexed=False, required=True, choices=blood_types)
    content = ndb.StringProperty()

class Transfusion(ndb.Model):
    patient = ndb.StructuredProperty(Patient)
    nhh_code = ndb.StringProperty(indexed=True, required=True, validator=onlynumbers)
    date = ndb.DateProperty(indexed=True, required=True)
    local = ndb.StringProperty(indexed=False, required=True)
    bags = ndb.LocalStructuredProperty(BloodBag, repeated=True)
    tags = ndb.StringProperty(repeated=True, indexed=False,
                              choices=['rt', "ficha_preenchida", "carimbo_plantao", "carimbo_nhh", "anvisa"])
    text = ndb.TextProperty(required=False)

    added_at = ndb.DateTimeProperty(auto_now_add=True, indexed=False)
    updated_at = ndb.DateTimeProperty(auto_now=True, indexed=False)

@app.route("/")
def hello():
    return make_response("MEJC RT", 200, {})

@app.route("/api/transfusion/create", methods=['POST'])
def create():
    """"
    example:
    {
        "name": "John Heyder Oliveira de Medeiros Galvão",
        "record": "12345/0",
        "blood_type": "O+",
        "date": "2015-05-22",
        "local": "UTINEO",
        "blood_bags" :
        [
            {
                "type": "O-",
                "content": "CHPLI"
            }
        ],
        "text": "",
        "tags": [],
        "nhh_code": "20900"
    }

    """
    if not hasattr(request, 'json'):
        return make_response(jsonify(code="ERROR"), 500, {})

    patient = request.json.get('name', None)
    record_code = request.json.get('record', None)
    blood_type = request.json.get('blood_type', None)
    transfusion_date = request.json.get('date', None)
    transfusion_local = request.json.get('local', None)
    bags = []
    for bag in request.json.get('bags', []):
        bags.put(BloodBag(type_=bag['type'], content=bag['content']))
    text = request.json.get('text', None) or None
    tags = request.json.get('tags', [])

    nhh_code = request.json.get('nhh_code', None)
    tr = Transfusion(patient=Patient(name=patient,
                                     blood_type=blood_type,
                                     code=record_code),
                     nhh_code=nhh_code,
                     date=datetime.strptime(transfusion_date, "%Y-%m-%d"),
                     local=transfusion_local,
                     bags=bags,
                     tags=tags,
                     text=text)
    key = tr.put()

    return make_response(jsonify(code="OK", key=key.urlsafe()), 200, {})
<|endoftext|>


<commit_before># Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt).
# Licensed under the BSD 3-clause license (see LICENSE.txt)

import numpy as np
from .. import kern
from ..likelihoods import Gaussian
from ..core.parameterization.variational import NormalPosterior, NormalPrior
from ..inference.latent_function_inference.var_dtc_parallel import VarDTC_minibatch
import logging
from GPy.models.sparse_gp_minibatch import SparseGPMiniBatch
from GPy.core.parameterization.param import Param

class BayesianGPLVMMiniBatch(SparseGPMiniBatch):
    """
    Bayesian Gaussian Process Latent Variable Model

    :param Y: observed data (np.ndarray) or GPy.likelihood
    :type Y: np.ndarray| GPy.likelihood instance
    :param input_dim: latent dimensionality
    :type input_dim: int
    :param init: initialisation method for the latent space
    :type init: 'PCA'|'random'

    """
    def __init__(self, Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
                 Z=None, kernel=None, inference_method=None, likelihood=None,
                 name='bayesian gplvm', normalizer=None,
                 missing_data=False, stochastic=False, batchsize=1):
        self.logger = logging.getLogger(self.__class__.__name__)
        if X is None:
            from ..util.initialization import initialize_latent
            self.logger.info("initializing latent space X with method {}".format(init))
            X, fracs = initialize_latent(init, input_dim, Y)
        else:
            fracs = np.ones(input_dim)

        self.init = init

        if Z is None:
            self.logger.info("initializing inducing inputs")
            Z = np.random.permutation(X.copy())[:num_inducing]
        assert Z.shape[1] == X.shape[1]

        if X_variance == False:
            self.logger.info('no variance on X, activating sparse GPLVM')
            X = Param("latent space", X)
        elif X_variance is None:
            self.logger.info("initializing latent space variance ~ uniform(0,.1)")
            X_variance = np.random.uniform(0,.1,X.shape)
            self.variational_prior = NormalPrior()
            X = NormalPosterior(X, X_variance)

        if kernel is None:
            self.logger.info("initializing kernel RBF")
            kernel = kern.RBF(input_dim, lengthscale=1./fracs, ARD=True) #+ kern.Bias(input_dim) + kern.White(input_dim)

        if likelihood is None:
            likelihood = Gaussian()

        self.kl_factr = 1.

        if inference_method is None:
            from ..inference.latent_function_inference.var_dtc import VarDTC
            self.logger.debug("creating inference_method var_dtc")
            inference_method = VarDTC(limit=1 if not missing_data else Y.shape[1])

        super(BayesianGPLVMMiniBatch,self).__init__(X, Y, Z, kernel, likelihood=likelihood,
                                           name=name, inference_method=inference_method,
                                           normalizer=normalizer,
                                           missing_data=missing_data, stochastic=stochastic,
                                           batchsize=batchsize)
        self.X = X
        self.link_parameter(self.X, 0)

    def set_X_gradients(self, X, X_grad):
        """Set the gradients of the posterior distribution of X in its specific form."""
        X.mean.gradient, X.variance.gradient = X_grad

    def get_X_gradients(self, X):
        """Get the gradients of the posterior distribution of X in its specific form."""
        return X.mean.gradient, X.variance.gradient

    def _inner_parameters_changed(self, kern, X, Z, likelihood, Y, Y_metadata, Lm=None, dL_dKmm=None,psi0=None, psi1=None, psi2=None, **kw):
        posterior, log_marginal_likelihood, grad_dict = super(BayesianGPLVMMiniBatch, self)._inner_parameters_changed(kern, X, Z, likelihood, Y, Y_metadata, Lm=Lm, dL_dKmm=dL_dKmm,
                                                                                psi0=psi0, psi1=psi1, psi2=psi2, **kw)
        kl_fctr = self.kl_factr
        if self.has_uncertain_inputs():
            if self.missing_data:
                d = self.output_dim
                log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(X)/d
            else:
                log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(X)

            X.mean.gradient[:] = 0
            X.variance.gradient[:] = 0

            self.variational_prior.update_gradients_KL(X)
            if self.missing_data:
                grad_dict['meangrad'] = kl_fctr*X.mean.gradient/d
                grad_dict['vargrad'] = kl_fctr*X.variance.gradient/d
            else:
                grad_dict['meangrad'] = kl_fctr*X.mean.gradient
                grad_dict['vargrad'] = kl_fctr*X.variance.gradient

            #if subset_indices is not None:
                #value_indices['meangrad'] = subset_indices['samples']
                #value_indices['vargrad'] = subset_indices['samples']

            #grad_dict['meangrad'] = kl_fctr*self.X.mean.gradient
            #grad_dict['vargrad'] = kl_fctr*self.X.variance.gradient
            #self.X.mean.gradient[:] = 0
            #self.X.variance.gradient[:] = 0
            #import ipdb; ipdb.set_trace()  # XXX BREAKPOINT

        return posterior, log_marginal_likelihood, grad_dict

    def _outer_values_update(self, full_values):
        """
        Here you put the values, which were collected before in the right places.
        E.g. set the gradients of parameters, etc.
        """
        super(BayesianGPLVMMiniBatch, self)._outer_values_update(full_values)
        print full_values['kerngrad']
        import ipdb; ipdb.set_trace()  # XXX BREAKPOINT
        if self.has_uncertain_inputs():
             meangrad_tmp, vargrad_tmp = self.kern.gradients_qX_expectations(
                                                variational_posterior=self.X,
                                                Z=self.Z, dL_dpsi0=full_values['dL_dpsi0'],
                                                dL_dpsi1=full_values['dL_dpsi1'],
                                                dL_dpsi2=full_values['dL_dpsi2'],
                                                psi0=self.psi0, psi1=self.psi1, psi2=self.psi2)
             full_values['meangrad'] += meangrad_tmp
             full_values['vargrad'] += vargrad_tmp
        else:
            full_values['Xgrad'] = self.kern.gradients_X(full_values['dL_dKnm'], self.X, self.Z)
            full_values['Xgrad'] += self.kern.gradients_X_diag(full_values['dL_dKdiag'], self.X)

        #kl_fctr = self.kl_factr
        #if self.has_uncertain_inputs():
            #self._log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(self.X)

            # Subsetting Variational Posterior objects, makes the gradients
            # empty. We need them to be 0 though:
            #self.X.mean.gradient[:] = 0
            #self.X.variance.gradient[:] = 0

            #self.variational_prior.update_gradients_KL(self.X)

        if self.has_uncertain_inputs():
            self.X.mean.gradient = full_values['meangrad']
            self.X.variance.gradient = full_values['vargrad']
        else:
            self.X.gradient = full_values['Xgrad']

    def _outer_init_full_values(self):
        full_values = super(BayesianGPLVMMiniBatch, self)._outer_init_full_values()
        full_values['meangrad'] = np.zeros((self.X.shape[0], self.X.shape[1]))
        full_values['vargrad'] = np.zeros((self.X.shape[0], self.X.shape[1]))
        full_values['dL_dpsi0'] = np.zeros(self.X.shape[0])
        full_values['dL_dpsi1'] = np.zeros((self.X.shape[0], self.Z.shape[0]))
        return full_values

    def parameters_changed(self):
        super(BayesianGPLVMMiniBatch,self).parameters_changed()
        if isinstance(self.inference_method, VarDTC_minibatch):
            return

    def plot_latent(self, labels=None, which_indices=None,
                resolution=50, ax=None, marker='o', s=40,
                fignum=None, plot_inducing=True, legend=True,
                plot_limits=None,
                aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}):
        import sys
        assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
        from ..plotting.matplot_dep import dim_reduction_plots

        return dim_reduction_plots.plot_latent(self, labels, which_indices,
                resolution, ax, marker, s,
                fignum, plot_inducing, legend,
                plot_limits, aspect, updates, predict_kwargs, imshow_kwargs)

    def do_test_latents(self, Y):
        """
        Compute the latent representation for a set of new points Y

        Notes:
        This will only work with a univariate Gaussian likelihood (for now)
        """
        N_test = Y.shape[0]
        input_dim = self.Z.shape[1]

        means = np.zeros((N_test, input_dim))
        covars = np.zeros((N_test, input_dim))

        dpsi0 = -0.5 * self.input_dim / self.likelihood.variance
        dpsi2 = self.grad_dict['dL_dpsi2'][0][None, :, :] # TODO: this may change if we ignore het. likelihoods
        V = Y/self.likelihood.variance

        #compute CPsi1V
        #if self.Cpsi1V is None:
        #    psi1V = np.dot(self.psi1.T, self.likelihood.V)
        #    tmp, _ = linalg.dtrtrs(self._Lm, np.asfortranarray(psi1V), lower=1, trans=0)
        #    tmp, _ = linalg.dpotrs(self.LB, tmp, lower=1)
        #    self.Cpsi1V, _ = linalg.dtrtrs(self._Lm, tmp, lower=1, trans=1)

        dpsi1 = np.dot(self.posterior.woodbury_vector, V.T)

        #start = np.zeros(self.input_dim * 2)

        from scipy.optimize import minimize

        for n, dpsi1_n in enumerate(dpsi1.T[:, :, None]):
            args = (input_dim, self.kern.copy(), self.Z, dpsi0, dpsi1_n.T, dpsi2)
            res = minimize(latent_cost_and_grad, jac=True, x0=np.hstack((means[n], covars[n])), args=args, method='BFGS')
            xopt = res.x
            mu, log_S = xopt.reshape(2, 1, -1)
            means[n] = mu[0].copy()
            covars[n] = np.exp(log_S[0]).copy()

        X = NormalPosterior(means, covars)

        return X

    def dmu_dX(self, Xnew):
        """
        Calculate the gradient of the prediction at Xnew w.r.t Xnew.
        """
        dmu_dX = np.zeros_like(Xnew)
        for i in range(self.Z.shape[0]):
            dmu_dX += self.kern.gradients_X(self.grad_dict['dL_dpsi1'][i:i + 1, :], Xnew, self.Z[i:i + 1, :])
        return dmu_dX

    def dmu_dXnew(self, Xnew):
        """
        Individual gradient of prediction at Xnew w.r.t. each sample in Xnew
        """
        gradients_X = np.zeros((Xnew.shape[0], self.num_inducing))
        ones = np.ones((1, 1))
        for i in range(self.Z.shape[0]):
            gradients_X[:, i] = self.kern.gradients_X(ones, Xnew, self.Z[i:i + 1, :]).sum(-1)
        return np.dot(gradients_X, self.grad_dict['dL_dpsi1'])

    def plot_steepest_gradient_map(self, *args, ** kwargs):
        """
        See GPy.plotting.matplot_dep.dim_reduction_plots.plot_steepest_gradient_map
        """
        import sys
        assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
        from ..plotting.matplot_dep import dim_reduction_plots

        return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs)

def latent_cost_and_grad(mu_S, input_dim, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2):
    """
    objective function for fitting the latent variables for test points
    (negative log-likelihood: should be minimised!)
    """
    mu = mu_S[:input_dim][None]
    log_S = mu_S[input_dim:][None]
    S = np.exp(log_S)

    X = NormalPosterior(mu, S)

    psi0 = kern.psi0(Z, X)
    psi1 = kern.psi1(Z, X)
    psi2 = kern.psi2(Z, X)

    lik = dL_dpsi0 * psi0.sum() + np.einsum('ij,kj->...', dL_dpsi1, psi1) + np.einsum('ijk,lkj->...', dL_dpsi2, psi2) - 0.5 * np.sum(np.square(mu) + S) + 0.5 * np.sum(log_S)

    dLdmu, dLdS = kern.gradients_qX_expectations(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, X)
    dmu = dLdmu - mu
    # dS = S0 + S1 + S2 -0.5 + .5/S
    dlnS = S * (dLdS - 0.5) + .5

    return -lik, -np.hstack((dmu.flatten(), dlnS.flatten()))
<commit_msg>Removed comment<commit_after># Copyright (c) 2012-2014, GPy authors (see AUTHORS.txt).
# Licensed under the BSD 3-clause license (see LICENSE.txt)

import numpy as np
from .. import kern
from ..likelihoods import Gaussian
from ..core.parameterization.variational import NormalPosterior, NormalPrior
from ..inference.latent_function_inference.var_dtc_parallel import VarDTC_minibatch
import logging
from GPy.models.sparse_gp_minibatch import SparseGPMiniBatch
from GPy.core.parameterization.param import Param

class BayesianGPLVMMiniBatch(SparseGPMiniBatch):
    """
    Bayesian Gaussian Process Latent Variable Model

    :param Y: observed data (np.ndarray) or GPy.likelihood
    :type Y: np.ndarray| GPy.likelihood instance
    :param input_dim: latent dimensionality
    :type input_dim: int
    :param init: initialisation method for the latent space
    :type init: 'PCA'|'random'

    """
    def __init__(self, Y, input_dim, X=None, X_variance=None, init='PCA', num_inducing=10,
                 Z=None, kernel=None, inference_method=None, likelihood=None,
                 name='bayesian gplvm', normalizer=None,
                 missing_data=False, stochastic=False, batchsize=1):
        self.logger = logging.getLogger(self.__class__.__name__)
        if X is None:
            from ..util.initialization import initialize_latent
            self.logger.info("initializing latent space X with method {}".format(init))
            X, fracs = initialize_latent(init, input_dim, Y)
        else:
            fracs = np.ones(input_dim)

        self.init = init

        if Z is None:
            self.logger.info("initializing inducing inputs")
            Z = np.random.permutation(X.copy())[:num_inducing]
        assert Z.shape[1] == X.shape[1]

        if X_variance == False:
            self.logger.info('no variance on X, activating sparse GPLVM')
            X = Param("latent space", X)
        elif X_variance is None:
            self.logger.info("initializing latent space variance ~ uniform(0,.1)")
            X_variance = np.random.uniform(0,.1,X.shape)
            self.variational_prior = NormalPrior()
            X = NormalPosterior(X, X_variance)

        if kernel is None:
            self.logger.info("initializing kernel RBF")
            kernel = kern.RBF(input_dim, lengthscale=1./fracs, ARD=True) #+ kern.Bias(input_dim) + kern.White(input_dim)

        if likelihood is None:
            likelihood = Gaussian()

        self.kl_factr = 1.

        if inference_method is None:
            from ..inference.latent_function_inference.var_dtc import VarDTC
            self.logger.debug("creating inference_method var_dtc")
            inference_method = VarDTC(limit=1 if not missing_data else Y.shape[1])

        super(BayesianGPLVMMiniBatch,self).__init__(X, Y, Z, kernel, likelihood=likelihood,
                                           name=name, inference_method=inference_method,
                                           normalizer=normalizer,
                                           missing_data=missing_data, stochastic=stochastic,
                                           batchsize=batchsize)
        self.X = X
        self.link_parameter(self.X, 0)

    def set_X_gradients(self, X, X_grad):
        """Set the gradients of the posterior distribution of X in its specific form."""
        X.mean.gradient, X.variance.gradient = X_grad

    def get_X_gradients(self, X):
        """Get the gradients of the posterior distribution of X in its specific form."""
        return X.mean.gradient, X.variance.gradient

    def _inner_parameters_changed(self, kern, X, Z, likelihood, Y, Y_metadata, Lm=None, dL_dKmm=None,psi0=None, psi1=None, psi2=None, **kw):
        posterior, log_marginal_likelihood, grad_dict = super(BayesianGPLVMMiniBatch, self)._inner_parameters_changed(kern, X, Z, likelihood, Y, Y_metadata, Lm=Lm, dL_dKmm=dL_dKmm,
                                                                                psi0=psi0, psi1=psi1, psi2=psi2, **kw)
        kl_fctr = self.kl_factr
        if self.has_uncertain_inputs():
            if self.missing_data:
                d = self.output_dim
                log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(X)/d
            else:
                log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(X)

            X.mean.gradient[:] = 0
            X.variance.gradient[:] = 0

            self.variational_prior.update_gradients_KL(X)
            if self.missing_data:
                grad_dict['meangrad'] = kl_fctr*X.mean.gradient/d
                grad_dict['vargrad'] = kl_fctr*X.variance.gradient/d
            else:
                grad_dict['meangrad'] = kl_fctr*X.mean.gradient
                grad_dict['vargrad'] = kl_fctr*X.variance.gradient

            #if subset_indices is not None:
                #value_indices['meangrad'] = subset_indices['samples']
                #value_indices['vargrad'] = subset_indices['samples']

            #grad_dict['meangrad'] = kl_fctr*self.X.mean.gradient
            #grad_dict['vargrad'] = kl_fctr*self.X.variance.gradient
            #self.X.mean.gradient[:] = 0
            #self.X.variance.gradient[:] = 0
            #import ipdb; ipdb.set_trace()  # XXX BREAKPOINT

        return posterior, log_marginal_likelihood, grad_dict

    def _outer_values_update(self, full_values):
        """
        Here you put the values, which were collected before in the right places.
        E.g. set the gradients of parameters, etc.
        """
        super(BayesianGPLVMMiniBatch, self)._outer_values_update(full_values)
        if self.has_uncertain_inputs():
             meangrad_tmp, vargrad_tmp = self.kern.gradients_qX_expectations(
                                                variational_posterior=self.X,
                                                Z=self.Z, dL_dpsi0=full_values['dL_dpsi0'],
                                                dL_dpsi1=full_values['dL_dpsi1'],
                                                dL_dpsi2=full_values['dL_dpsi2'],
                                                psi0=self.psi0, psi1=self.psi1, psi2=self.psi2)
             full_values['meangrad'] += meangrad_tmp
             full_values['vargrad'] += vargrad_tmp
        else:
            full_values['Xgrad'] = self.kern.gradients_X(full_values['dL_dKnm'], self.X, self.Z)
            full_values['Xgrad'] += self.kern.gradients_X_diag(full_values['dL_dKdiag'], self.X)

        #kl_fctr = self.kl_factr
        #if self.has_uncertain_inputs():
            #self._log_marginal_likelihood -= kl_fctr*self.variational_prior.KL_divergence(self.X)

            # Subsetting Variational Posterior objects, makes the gradients
            # empty. We need them to be 0 though:
            #self.X.mean.gradient[:] = 0
            #self.X.variance.gradient[:] = 0

            #self.variational_prior.update_gradients_KL(self.X)

        if self.has_uncertain_inputs():
            self.X.mean.gradient = full_values['meangrad']
            self.X.variance.gradient = full_values['vargrad']
        else:
            self.X.gradient = full_values['Xgrad']

    def _outer_init_full_values(self):
        full_values = super(BayesianGPLVMMiniBatch, self)._outer_init_full_values()
        full_values['meangrad'] = np.zeros((self.X.shape[0], self.X.shape[1]))
        full_values['vargrad'] = np.zeros((self.X.shape[0], self.X.shape[1]))
        full_values['dL_dpsi0'] = np.zeros(self.X.shape[0])
        full_values['dL_dpsi1'] = np.zeros((self.X.shape[0], self.Z.shape[0]))
        return full_values

    def parameters_changed(self):
        super(BayesianGPLVMMiniBatch,self).parameters_changed()
        if isinstance(self.inference_method, VarDTC_minibatch):
            return

    def plot_latent(self, labels=None, which_indices=None,
                resolution=50, ax=None, marker='o', s=40,
                fignum=None, plot_inducing=True, legend=True,
                plot_limits=None,
                aspect='auto', updates=False, predict_kwargs={}, imshow_kwargs={}):
        import sys
        assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
        from ..plotting.matplot_dep import dim_reduction_plots

        return dim_reduction_plots.plot_latent(self, labels, which_indices,
                resolution, ax, marker, s,
                fignum, plot_inducing, legend,
                plot_limits, aspect, updates, predict_kwargs, imshow_kwargs)

    def do_test_latents(self, Y):
        """
        Compute the latent representation for a set of new points Y

        Notes:
        This will only work with a univariate Gaussian likelihood (for now)
        """
        N_test = Y.shape[0]
        input_dim = self.Z.shape[1]

        means = np.zeros((N_test, input_dim))
        covars = np.zeros((N_test, input_dim))

        dpsi0 = -0.5 * self.input_dim / self.likelihood.variance
        dpsi2 = self.grad_dict['dL_dpsi2'][0][None, :, :] # TODO: this may change if we ignore het. likelihoods
        V = Y/self.likelihood.variance

        #compute CPsi1V
        #if self.Cpsi1V is None:
        #    psi1V = np.dot(self.psi1.T, self.likelihood.V)
        #    tmp, _ = linalg.dtrtrs(self._Lm, np.asfortranarray(psi1V), lower=1, trans=0)
        #    tmp, _ = linalg.dpotrs(self.LB, tmp, lower=1)
        #    self.Cpsi1V, _ = linalg.dtrtrs(self._Lm, tmp, lower=1, trans=1)

        dpsi1 = np.dot(self.posterior.woodbury_vector, V.T)

        #start = np.zeros(self.input_dim * 2)

        from scipy.optimize import minimize

        for n, dpsi1_n in enumerate(dpsi1.T[:, :, None]):
            args = (input_dim, self.kern.copy(), self.Z, dpsi0, dpsi1_n.T, dpsi2)
            res = minimize(latent_cost_and_grad, jac=True, x0=np.hstack((means[n], covars[n])), args=args, method='BFGS')
            xopt = res.x
            mu, log_S = xopt.reshape(2, 1, -1)
            means[n] = mu[0].copy()
            covars[n] = np.exp(log_S[0]).copy()

        X = NormalPosterior(means, covars)

        return X

    def dmu_dX(self, Xnew):
        """
        Calculate the gradient of the prediction at Xnew w.r.t Xnew.
        """
        dmu_dX = np.zeros_like(Xnew)
        for i in range(self.Z.shape[0]):
            dmu_dX += self.kern.gradients_X(self.grad_dict['dL_dpsi1'][i:i + 1, :], Xnew, self.Z[i:i + 1, :])
        return dmu_dX

    def dmu_dXnew(self, Xnew):
        """
        Individual gradient of prediction at Xnew w.r.t. each sample in Xnew
        """
        gradients_X = np.zeros((Xnew.shape[0], self.num_inducing))
        ones = np.ones((1, 1))
        for i in range(self.Z.shape[0]):
            gradients_X[:, i] = self.kern.gradients_X(ones, Xnew, self.Z[i:i + 1, :]).sum(-1)
        return np.dot(gradients_X, self.grad_dict['dL_dpsi1'])

    def plot_steepest_gradient_map(self, *args, ** kwargs):
        """
        See GPy.plotting.matplot_dep.dim_reduction_plots.plot_steepest_gradient_map
        """
        import sys
        assert "matplotlib" in sys.modules, "matplotlib package has not been imported."
        from ..plotting.matplot_dep import dim_reduction_plots

        return dim_reduction_plots.plot_steepest_gradient_map(self,*args,**kwargs)

def latent_cost_and_grad(mu_S, input_dim, kern, Z, dL_dpsi0, dL_dpsi1, dL_dpsi2):
    """
    objective function for fitting the latent variables for test points
    (negative log-likelihood: should be minimised!)
    """
    mu = mu_S[:input_dim][None]
    log_S = mu_S[input_dim:][None]
    S = np.exp(log_S)

    X = NormalPosterior(mu, S)

    psi0 = kern.psi0(Z, X)
    psi1 = kern.psi1(Z, X)
    psi2 = kern.psi2(Z, X)

    lik = dL_dpsi0 * psi0.sum() + np.einsum('ij,kj->...', dL_dpsi1, psi1) + np.einsum('ijk,lkj->...', dL_dpsi2, psi2) - 0.5 * np.sum(np.square(mu) + S) + 0.5 * np.sum(log_S)

    dLdmu, dLdS = kern.gradients_qX_expectations(dL_dpsi0, dL_dpsi1, dL_dpsi2, Z, X)
    dmu = dLdmu - mu
    # dS = S0 + S1 + S2 -0.5 + .5/S
    dlnS = S * (dLdS - 0.5) + .5

    return -lik, -np.hstack((dmu.flatten(), dlnS.flatten()))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
#
'''
Module for reading unstructured grids (and related data) from various file
formats.

.. moduleauthor:: Nico Schlömer <nico.schloemer@gmail.com>
'''
import h5py
from itertools import islice
import os
import numpy
import re
import vtk

def read(filenames, timestep=None):
    '''Reads an unstructured mesh with added data.

    :param filenames: The files to read from.
    :type filenames: str
    :param timestep: Time step to read from, in case of an Exodus input mesh.
    :type timestep: int, optional
    :returns mesh{2,3}d: The mesh data.
    :returns point_data: Point data read from file.
    :type point_data: dict
    :returns field_data: Field data read from file.
    :type field_data: dict
    '''
    if isinstance(filenames, (list, tuple)) and len(filenames) == 1:
        filenames = filenames[0]

    # http://stackoverflow.com/questions/4843173/how-to-check-if-a-type-of-variable-is-string-in-python
    # if isinstance(filenames, basestring):
    if isinstance(filenames, str):
        filename = filenames
        # serial files
        extension = os.path.splitext(filename)[1]

        # setup the reader
        if extension == '.msh':
            # Gmsh file
            points, cells_nodes = _read_gmsh(filename)
            return points, cells_nodes, None, None, None
        # setup the reader
        elif extension == '.h5m':
            # H5M file
            return _read_h5m(filename)
        else:
            if extension == '.vtu':
                reader = vtk.vtkXMLUnstructuredGridReader()
                vtk_mesh = _read_vtk_mesh(reader, filename)
            elif extension == '.vtk':
                reader = vtk.vtkUnstructuredGridReader()
                vtk_mesh = _read_vtk_mesh(reader, filename)
            elif extension in ['.ex2', '.exo', '.e']:
                reader = vtk.vtkExodusIIReader()
                reader.SetFileName(filename)
                vtk_mesh = _read_exodusii_mesh(reader, timestep=timestep)
            elif re.match('[^\.]*\.e\.\d+\.\d+', filename):
                # Parallel Exodus files.
                # TODO handle with vtkPExodusIIReader
                reader = vtk.vtkExodusIIReader()
                reader.SetFileName(filenames[0])
                vtk_mesh = _read_exodusii_mesh(reader, timestep=timestep)
            else:
                raise RuntimeError('Unknown file type \'%s\'.' % filename)

        # # Parallel files.
        # # Assume Exodus format as we don't know anything else yet.
        # # TODO Guess the file pattern or whatever.
        # reader = vtk.vtkPExodusIIReader()
        # reader.SetFileNames(filenames)
        # vtk_mesh = _read_exodusii_mesh(reader, filename, timestep=timestep)

        # Explicitly extract points, cells, point data, field data
        points = _read_points(vtk_mesh)
        cells_nodes = _read_cells_nodes(vtk_mesh)
        point_data = _read_point_data(vtk_mesh)
        cell_data = _read_cell_data(vtk_mesh)
        field_data = _read_field_data(vtk_mesh)

        return points, cells_nodes, point_data, cell_data, field_data

def _read_gmsh(filename):
    '''Reads a Gmsh msh file.
    '''
    # The format is specified at
    # <http://geuz.org/gmsh/doc/texinfo/gmsh.html#MSH-ASCII-file-format>.
    with open(filename) as f:
        while True:
            try:
                line = islice(f, 1).next()
            except StopIteration:
                break
            assert(line[0] == '$')
            environ = line[1:].strip()
            if environ == 'MeshFormat':
                line = islice(f, 1).next()
                # 2.2 0 8
                line = islice(f, 1).next()
                assert(line.strip() == '$EndMeshFormat')
            elif environ == 'Nodes':
                # The first line is the number of nodes
                line = islice(f, 1).next()
                num_nodes = int(line)
                points = numpy.empty((num_nodes, 3))
                for k, line in enumerate(islice(f, num_nodes)):
                    # Throw away the index immediately
                    points[k, :] = numpy.array(line.split(), dtype=float)[1:]
                line = islice(f, 1).next()
                assert(line.strip() == '$EndNodes')
            elif environ == 'Elements':
                # The first line is the number of elements
                line = islice(f, 1).next()
                num_elems = int(line)
                elems = {
                    'points': [],
                    'lines': [],
                    'triangles': [],
                    'tetrahedra': []
                    }
                for k, line in enumerate(islice(f, num_elems)):
                    # Throw away the index immediately
                    data = numpy.array(line.split(), dtype=int)
                    if data[1] == 15:
                        elems['points'].append(data[-1:])
                    elif data[1] == 1:
                        elems['lines'].append(data[-2:])
                    elif data[1] == 2:
                        elems['triangles'].append(data[-3:])
                    elif data[1] == 4:
                        elems['tetrahedra'].append(data[-4:])
                    else:
                        raise RuntimeError('Unknown element type')
                for key in elems:
                    # Subtract one to account for the fact that python indices
                    # are 0-based.
                    elems[key] = numpy.array(elems[key], dtype=int) - 1
                line = islice(f, 1).next()
                assert(line.strip() == '$EndElements')
            else:
                raise RuntimeError('Unknown environment \'%s\'.' % environ)

    if len(elems['tetrahedra']) > 0:
        cells = elems['tetrahedra']
    elif len(elems['triangles']) > 0:
        cells = elems['triangles']
    else:
        raise RuntimeError('Expected at least triangles.')

    return points, cells

def int_to_bool_list(num):
    # From <http://stackoverflow.com/a/33608387/353337>.
    bin_string = format(num, '04b')
    return [x == '1' for x in bin_string[::-1]]

def _read_h5m(filename):
    '''Reads H5M files, cf.
    https://trac.mcs.anl.gov/projects/ITAPS/wiki/MOAB/h5m.
    '''
    f = h5py.File(filename, 'r')
    dset = f['tstt']

    points = dset['nodes']['coordinates'][()]
    # read point data
    point_data = {}
    if 'tags' in dset['nodes']:
        for name, dataset in dset['nodes']['tags'].items():
            point_data[name] = dataset[()]

    # # Assert that the GLOBAL_IDs are contiguous.
    # point_gids = dset['nodes']['tags']['GLOBAL_ID'][()]
    # point_start_gid = dset['nodes']['coordinates'].attrs['start_id']
    # point_end_gid = point_start_gid + len(point_gids) - 1
    # assert all(point_gids == range(point_start_gid, point_end_gid + 1))

    # Note that the indices are off by 1 in h5m.
    if 'Tri3' in dset['elements']:
        elems = dset['elements']['Tri3']
    elif 'Tet4' in dset['elements']:
        elems = dset['elements']['Tet4']
    else:
        raise RuntimeError('Need Tri3s or Tet4s.')

    conn = elems['connectivity']
    cells = conn[()] - 1

    cell_data = {}
    if 'tags' in elems:
        for name, dataset in elems['tags'].items():
            cell_data[name] = dataset[()]

    field_data = {}
    if 'sets' in dset:
        # read sets
        sets_contents = dset['sets']['contents'][()]
        sets_list = dset['sets']['list'][()]
        sets_tags = dset['sets']['tags']

        cell_start_gid = conn.attrs['start_id']
        cell_gids = cell_start_gid + elems['tags']['GLOBAL_ID'][()]
        cell_end_gid = cell_start_gid + len(cell_gids) - 1
        # assert all(cell_gids == range(cell_start_gid, cell_end_gid + 1))

        # create the sets
        for key, value in sets_tags.items():
            field_data[key] = numpy.empty(len(cells), dtype=int)
            end = 0
            for k, row in enumerate(sets_list):
                bits = int_to_bool_list(row[3])
                # is_owner = bits[3]
                # is_unique = bits[2]
                # is_ordered = bits[1]
                is_range_compressed = bits[0]
                if is_range_compressed:
                    start_gids = sets_contents[end:row[0]+1:2]
                    lengths = sets_contents[end+1:row[0]+1:2]
                    for start_gid, length in zip(start_gids, lengths):
                        end_gid = start_gid + length - 1
                        if start_gid >= cell_start_gid and \
                                end_gid <= cell_end_gid:
                            i0 = start_gid - cell_start_gid
                            i1 = end_gid - cell_start_gid + 1
                            field_data[key][i0:i1] = value[k]
                        else:
                            # TODO deal with point data
                            raise RuntimeError('')
                else:
                    gids = sets_contents[end:row[0]+1]
                    field_data[key][gids - cell_start_gid] = value[k]

                end = row[0] + 1

    return points, cells, point_data, cell_data, field_data

def _read_vtk_mesh(reader, file_name):
    '''Uses a vtkReader to return a vtkUnstructuredGrid.
    '''
    reader.SetFileName(file_name)
    reader.Update()
    return reader.GetOutput()

# def _read_exodus_mesh(reader, file_name):
#     '''Uses a vtkExodusIIReader to return a vtkUnstructuredGrid.
#     '''
#     reader.SetFileName(file_name)
#
#     # Create Exodus metadata that can be used later when writing the file.
#     reader.ExodusModelMetadataOn()
#
#     # Fetch metadata.
#     reader.UpdateInformation()
#
#     # Make sure the point fields are read during Update().
#     for k in range(reader.GetNumberOfPointArrays()):
#         arr_name = reader.GetPointArrayName(k)
#         reader.SetPointArrayStatus(arr_name, 1)
#
#     # Read the file.
#     reader.Update()
#
#     return reader.GetOutput()

def _read_exodusii_mesh(reader, timestep=None):
    '''Uses a vtkExodusIIReader to return a vtkUnstructuredGrid.
    '''
    # Fetch metadata.
    reader.UpdateInformation()

    # Set time step to read.
    if timestep:
        reader.SetTimeStep(timestep)

    # Make sure the point fields are read during Update().
    for k in range(reader.GetNumberOfPointResultArrays()):
        arr_name = reader.GetPointResultArrayName(k)
        reader.SetPointResultArrayStatus(arr_name, 1)

    # Make sure the point fields are read during Update().
    for k in range(reader.GetNumberOfElementResultArrays()):
        arr_name = reader.GetElementResultArrayName(k)
        reader.SetElementResultArrayStatus(arr_name, 1)

    # Make sure all field data is read.
    for k in range(reader.GetNumberOfGlobalResultArrays()):
        arr_name = reader.GetGlobalResultArrayName(k)
        reader.SetGlobalResultArrayStatus(arr_name, 1)

    # Read the file.
    reader.Update()
    out = reader.GetOutput()

    # Loop through the blocks and search for a vtkUnstructuredGrid.
    vtk_mesh = []
    for i in range(out.GetNumberOfBlocks()):
        blk = out.GetBlock(i)
        for j in range(blk.GetNumberOfBlocks()):
            sub_block = blk.GetBlock(j)
            if sub_block.IsA('vtkUnstructuredGrid'):
                vtk_mesh.append(sub_block)

    if len(vtk_mesh) == 0:
        raise IOError('No \'vtkUnstructuredGrid\' found!')
    elif len(vtk_mesh) > 1:
        raise IOError('More than one \'vtkUnstructuredGrid\' found!')

    # Cut off trailing '_' from array names.
    for k in range(vtk_mesh[0].GetPointData().GetNumberOfArrays()):
        array = vtk_mesh[0].GetPointData().GetArray(k)
        array_name = array.GetName()
        if array_name[-1] == '_':
            array.SetName(array_name[0:-1])

    # time_values = reader.GetOutputInformation(0).Get(
    #     vtkStreamingDemandDrivenPipeline.TIME_STEPS()
    #     )

    return vtk_mesh[0]  # , time_values

def _read_points(vtk_mesh):
    num_points = vtk_mesh.GetNumberOfPoints()
    # construct the points list
    points = numpy.empty(num_points, numpy.dtype((float, 3)))
    for k in range(num_points):
        points[k] = numpy.array(vtk_mesh.GetPoint(k))
    return points

def _read_cells_nodes(vtk_mesh):

    num_cells = vtk_mesh.GetNumberOfCells()
    # Assume that all cells have the same number of local nodes.
    max_num_local_nodes = vtk_mesh.GetCell(0).GetNumberOfPoints()
    cells_nodes = numpy.empty(num_cells,
                              dtype=numpy.dtype((int, max_num_local_nodes))
                              )

    for k in range(num_cells):
        cell = vtk_mesh.GetCell(k)
        num_local_nodes = cell.GetNumberOfPoints()
        assert num_local_nodes == max_num_local_nodes, 'Cells not uniform.'
        if num_local_nodes == max_num_local_nodes:
            # Gather up the points.
            for l in range(num_local_nodes):
                cells_nodes[k][l] = cell.GetPointId(l)

    return cells_nodes

def _read_point_data(vtk_data):
    '''Extract point data from a VTK data set.
    '''
    arrays = []
    for k in range(vtk_data.GetPointData().GetNumberOfArrays()):
        arrays.append(vtk_data.GetPointData().GetArray(k))

    # Go through all arrays, fetch psi and A.
    out = {}
    for array in arrays:
        array_name = array.GetName()
        out[array_name] = vtk.util.numpy_support.vtk_to_numpy(array)

    return out

def _read_cell_data(vtk_data):
    '''Extract cell data from a VTK data set.
    '''
    arrays = []
    for k in range(vtk_data.GetCellData().GetNumberOfArrays()):
        arrays.append(vtk_data.GetCellData().GetArray(k))

    out = {}
    for array in arrays:
        array_name = array.GetName()
        out[array_name] = vtk.util.numpy_support.vtk_to_numpy(array)

    return out

def _read_field_data(vtk_data):
    '''Gather field data.
    '''
    vtk_field_data = vtk_data.GetFieldData()
    num_arrays = vtk_field_data.GetNumberOfArrays()

    field_data = {}
    for k in range(num_arrays):
        array = vtk_field_data.GetArray(k)
        name = array.GetName()
        num_values = array.GetDataSize()
        # Data type as specified in vtkSetGet.h.
        data_type = array.GetDataType()
        if data_type == 1:
            dtype = numpy.bool
        elif data_type in [2, 3]:
            dtype = numpy.str
        elif data_type in [4, 5, 6, 7, 8, 9]:
            dtype = numpy.int
        elif data_type in [10, 11]:
            dtype = numpy.float
        else:
            raise TypeError('Unknown VTK data type %d.' % data_type)
        values = numpy.empty(num_values, dtype=dtype)
        for i in range(num_values):
            values[i] = array.GetValue(i)
        field_data[name] = values

    return field_data
<commit_msg>translate h5m sets into cell data<commit_after># -*- coding: utf-8 -*-
#
'''
Module for reading unstructured grids (and related data) from various file
formats.

.. moduleauthor:: Nico Schlömer <nico.schloemer@gmail.com>
'''
import h5py
from itertools import islice
import os
import numpy
import re
import vtk

def read(filenames, timestep=None):
    '''Reads an unstructured mesh with added data.

    :param filenames: The files to read from.
    :type filenames: str
    :param timestep: Time step to read from, in case of an Exodus input mesh.
    :type timestep: int, optional
    :returns mesh{2,3}d: The mesh data.
    :returns point_data: Point data read from file.
    :type point_data: dict
    :returns field_data: Field data read from file.
    :type field_data: dict
    '''
    if isinstance(filenames, (list, tuple)) and len(filenames) == 1:
        filenames = filenames[0]

    # http://stackoverflow.com/questions/4843173/how-to-check-if-a-type-of-variable-is-string-in-python
    # if isinstance(filenames, basestring):
    if isinstance(filenames, str):
        filename = filenames
        # serial files
        extension = os.path.splitext(filename)[1]

        # setup the reader
        if extension == '.msh':
            # Gmsh file
            points, cells_nodes = _read_gmsh(filename)
            return points, cells_nodes, None, None, None
        # setup the reader
        elif extension == '.h5m':
            # H5M file
            return _read_h5m(filename)
        else:
            if extension == '.vtu':
                reader = vtk.vtkXMLUnstructuredGridReader()
                vtk_mesh = _read_vtk_mesh(reader, filename)
            elif extension == '.vtk':
                reader = vtk.vtkUnstructuredGridReader()
                vtk_mesh = _read_vtk_mesh(reader, filename)
            elif extension in ['.ex2', '.exo', '.e']:
                reader = vtk.vtkExodusIIReader()
                reader.SetFileName(filename)
                vtk_mesh = _read_exodusii_mesh(reader, timestep=timestep)
            elif re.match('[^\.]*\.e\.\d+\.\d+', filename):
                # Parallel Exodus files.
                # TODO handle with vtkPExodusIIReader
                reader = vtk.vtkExodusIIReader()
                reader.SetFileName(filenames[0])
                vtk_mesh = _read_exodusii_mesh(reader, timestep=timestep)
            else:
                raise RuntimeError('Unknown file type \'%s\'.' % filename)

        # # Parallel files.
        # # Assume Exodus format as we don't know anything else yet.
        # # TODO Guess the file pattern or whatever.
        # reader = vtk.vtkPExodusIIReader()
        # reader.SetFileNames(filenames)
        # vtk_mesh = _read_exodusii_mesh(reader, filename, timestep=timestep)

        # Explicitly extract points, cells, point data, field data
        points = _read_points(vtk_mesh)
        cells_nodes = _read_cells_nodes(vtk_mesh)
        point_data = _read_point_data(vtk_mesh)
        cell_data = _read_cell_data(vtk_mesh)
        field_data = _read_field_data(vtk_mesh)

        return points, cells_nodes, point_data, cell_data, field_data

def _read_gmsh(filename):
    '''Reads a Gmsh msh file.
    '''
    # The format is specified at
    # <http://geuz.org/gmsh/doc/texinfo/gmsh.html#MSH-ASCII-file-format>.
    with open(filename) as f:
        while True:
            try:
                line = islice(f, 1).next()
            except StopIteration:
                break
            assert(line[0] == '$')
            environ = line[1:].strip()
            if environ == 'MeshFormat':
                line = islice(f, 1).next()
                # 2.2 0 8
                line = islice(f, 1).next()
                assert(line.strip() == '$EndMeshFormat')
            elif environ == 'Nodes':
                # The first line is the number of nodes
                line = islice(f, 1).next()
                num_nodes = int(line)
                points = numpy.empty((num_nodes, 3))
                for k, line in enumerate(islice(f, num_nodes)):
                    # Throw away the index immediately
                    points[k, :] = numpy.array(line.split(), dtype=float)[1:]
                line = islice(f, 1).next()
                assert(line.strip() == '$EndNodes')
            elif environ == 'Elements':
                # The first line is the number of elements
                line = islice(f, 1).next()
                num_elems = int(line)
                elems = {
                    'points': [],
                    'lines': [],
                    'triangles': [],
                    'tetrahedra': []
                    }
                for k, line in enumerate(islice(f, num_elems)):
                    # Throw away the index immediately
                    data = numpy.array(line.split(), dtype=int)
                    if data[1] == 15:
                        elems['points'].append(data[-1:])
                    elif data[1] == 1:
                        elems['lines'].append(data[-2:])
                    elif data[1] == 2:
                        elems['triangles'].append(data[-3:])
                    elif data[1] == 4:
                        elems['tetrahedra'].append(data[-4:])
                    else:
                        raise RuntimeError('Unknown element type')
                for key in elems:
                    # Subtract one to account for the fact that python indices
                    # are 0-based.
                    elems[key] = numpy.array(elems[key], dtype=int) - 1
                line = islice(f, 1).next()
                assert(line.strip() == '$EndElements')
            else:
                raise RuntimeError('Unknown environment \'%s\'.' % environ)

    if len(elems['tetrahedra']) > 0:
        cells = elems['tetrahedra']
    elif len(elems['triangles']) > 0:
        cells = elems['triangles']
    else:
        raise RuntimeError('Expected at least triangles.')

    return points, cells

def int_to_bool_list(num):
    # From <http://stackoverflow.com/a/33608387/353337>.
    bin_string = format(num, '04b')
    return [x == '1' for x in bin_string[::-1]]

def _read_h5m(filename):
    '''Reads H5M files, cf.
    https://trac.mcs.anl.gov/projects/ITAPS/wiki/MOAB/h5m.
    '''
    f = h5py.File(filename, 'r')
    dset = f['tstt']

    points = dset['nodes']['coordinates'][()]
    # read point data
    point_data = {}
    if 'tags' in dset['nodes']:
        for name, dataset in dset['nodes']['tags'].items():
            point_data[name] = dataset[()]

    # # Assert that the GLOBAL_IDs are contiguous.
    # point_gids = dset['nodes']['tags']['GLOBAL_ID'][()]
    # point_start_gid = dset['nodes']['coordinates'].attrs['start_id']
    # point_end_gid = point_start_gid + len(point_gids) - 1
    # assert all(point_gids == range(point_start_gid, point_end_gid + 1))

    # Note that the indices are off by 1 in h5m.
    if 'Tri3' in dset['elements']:
        elems = dset['elements']['Tri3']
    elif 'Tet4' in dset['elements']:
        elems = dset['elements']['Tet4']
    else:
        raise RuntimeError('Need Tri3s or Tet4s.')

    conn = elems['connectivity']
    cells = conn[()] - 1

    cell_data = {}
    if 'tags' in elems:
        for name, dataset in elems['tags'].items():
            cell_data[name] = dataset[()]

    # The `sets` in H5M are special in that they represent a segration of data
    # in the current file, particularly by a load balancer (Metis, Zoltan,
    # etc.). This segregation has no equivalent in other data types, but is
    # certainly worthwhile visualizing.
    # Hence, we will translate the sets into cell data with the prefix "set::"
    # here.
    # TODO deal with point data
    field_data = {}
    if 'sets' in dset:
        # read sets
        sets_contents = dset['sets']['contents'][()]
        sets_list = dset['sets']['list'][()]
        sets_tags = dset['sets']['tags']

        cell_start_gid = conn.attrs['start_id']
        cell_gids = cell_start_gid + elems['tags']['GLOBAL_ID'][()]
        cell_end_gid = cell_start_gid + len(cell_gids) - 1
        assert all(cell_gids == range(cell_start_gid, cell_end_gid + 1))

        # create the sets
        for key, value in sets_tags.items():
            mod_key = 'set::' + key
            cell_data[mod_key] = numpy.empty(len(cells), dtype=int)
            end = 0
            for k, row in enumerate(sets_list):
                bits = int_to_bool_list(row[3])
                # is_owner = bits[0]
                # is_unique = bits[1]
                # is_ordered = bits[2]
                is_range_compressed = bits[3]
                if is_range_compressed:
                    start_gids = sets_contents[end:row[0]+1:2]
                    lengths = sets_contents[end+1:row[0]+1:2]
                    for start_gid, length in zip(start_gids, lengths):
                        end_gid = start_gid + length - 1
                        if start_gid >= cell_start_gid and \
                                end_gid <= cell_end_gid:
                            i0 = start_gid - cell_start_gid
                            i1 = end_gid - cell_start_gid + 1
                            cell_data[mod_key][i0:i1] = value[k]
                        else:
                            # TODO deal with point data
                            raise RuntimeError('')
                else:
                    gids = sets_contents[end:row[0]+1]
                    cell_data[mod_key][gids - cell_start_gid] = value[k]

                end = row[0] + 1

    return points, cells, point_data, cell_data, field_data

def _read_vtk_mesh(reader, file_name):
    '''Uses a vtkReader to return a vtkUnstructuredGrid.
    '''
    reader.SetFileName(file_name)
    reader.Update()
    return reader.GetOutput()

# def _read_exodus_mesh(reader, file_name):
#     '''Uses a vtkExodusIIReader to return a vtkUnstructuredGrid.
#     '''
#     reader.SetFileName(file_name)
#
#     # Create Exodus metadata that can be used later when writing the file.
#     reader.ExodusModelMetadataOn()
#
#     # Fetch metadata.
#     reader.UpdateInformation()
#
#     # Make sure the point fields are read during Update().
#     for k in range(reader.GetNumberOfPointArrays()):
#         arr_name = reader.GetPointArrayName(k)
#         reader.SetPointArrayStatus(arr_name, 1)
#
#     # Read the file.
#     reader.Update()
#
#     return reader.GetOutput()

def _read_exodusii_mesh(reader, timestep=None):
    '''Uses a vtkExodusIIReader to return a vtkUnstructuredGrid.
    '''
    # Fetch metadata.
    reader.UpdateInformation()

    # Set time step to read.
    if timestep:
        reader.SetTimeStep(timestep)

    # Make sure the point fields are read during Update().
    for k in range(reader.GetNumberOfPointResultArrays()):
        arr_name = reader.GetPointResultArrayName(k)
        reader.SetPointResultArrayStatus(arr_name, 1)

    # Make sure the point fields are read during Update().
    for k in range(reader.GetNumberOfElementResultArrays()):
        arr_name = reader.GetElementResultArrayName(k)
        reader.SetElementResultArrayStatus(arr_name, 1)

    # Make sure all field data is read.
    for k in range(reader.GetNumberOfGlobalResultArrays()):
        arr_name = reader.GetGlobalResultArrayName(k)
        reader.SetGlobalResultArrayStatus(arr_name, 1)

    # Read the file.
    reader.Update()
    out = reader.GetOutput()

    # Loop through the blocks and search for a vtkUnstructuredGrid.
    vtk_mesh = []
    for i in range(out.GetNumberOfBlocks()):
        blk = out.GetBlock(i)
        for j in range(blk.GetNumberOfBlocks()):
            sub_block = blk.GetBlock(j)
            if sub_block.IsA('vtkUnstructuredGrid'):
                vtk_mesh.append(sub_block)

    if len(vtk_mesh) == 0:
        raise IOError('No \'vtkUnstructuredGrid\' found!')
    elif len(vtk_mesh) > 1:
        raise IOError('More than one \'vtkUnstructuredGrid\' found!')

    # Cut off trailing '_' from array names.
    for k in range(vtk_mesh[0].GetPointData().GetNumberOfArrays()):
        array = vtk_mesh[0].GetPointData().GetArray(k)
        array_name = array.GetName()
        if array_name[-1] == '_':
            array.SetName(array_name[0:-1])

    # time_values = reader.GetOutputInformation(0).Get(
    #     vtkStreamingDemandDrivenPipeline.TIME_STEPS()
    #     )

    return vtk_mesh[0]  # , time_values

def _read_points(vtk_mesh):
    num_points = vtk_mesh.GetNumberOfPoints()
    # construct the points list
    points = numpy.empty(num_points, numpy.dtype((float, 3)))
    for k in range(num_points):
        points[k] = numpy.array(vtk_mesh.GetPoint(k))
    return points

def _read_cells_nodes(vtk_mesh):

    num_cells = vtk_mesh.GetNumberOfCells()
    # Assume that all cells have the same number of local nodes.
    max_num_local_nodes = vtk_mesh.GetCell(0).GetNumberOfPoints()
    cells_nodes = numpy.empty(num_cells,
                              dtype=numpy.dtype((int, max_num_local_nodes))
                              )

    for k in range(num_cells):
        cell = vtk_mesh.GetCell(k)
        num_local_nodes = cell.GetNumberOfPoints()
        assert num_local_nodes == max_num_local_nodes, 'Cells not uniform.'
        if num_local_nodes == max_num_local_nodes:
            # Gather up the points.
            for l in range(num_local_nodes):
                cells_nodes[k][l] = cell.GetPointId(l)

    return cells_nodes

def _read_point_data(vtk_data):
    '''Extract point data from a VTK data set.
    '''
    arrays = []
    for k in range(vtk_data.GetPointData().GetNumberOfArrays()):
        arrays.append(vtk_data.GetPointData().GetArray(k))

    # Go through all arrays, fetch psi and A.
    out = {}
    for array in arrays:
        array_name = array.GetName()
        out[array_name] = vtk.util.numpy_support.vtk_to_numpy(array)

    return out

def _read_cell_data(vtk_data):
    '''Extract cell data from a VTK data set.
    '''
    arrays = []
    for k in range(vtk_data.GetCellData().GetNumberOfArrays()):
        arrays.append(vtk_data.GetCellData().GetArray(k))

    out = {}
    for array in arrays:
        array_name = array.GetName()
        out[array_name] = vtk.util.numpy_support.vtk_to_numpy(array)

    return out

def _read_field_data(vtk_data):
    '''Gather field data.
    '''
    vtk_field_data = vtk_data.GetFieldData()
    num_arrays = vtk_field_data.GetNumberOfArrays()

    field_data = {}
    for k in range(num_arrays):
        array = vtk_field_data.GetArray(k)
        name = array.GetName()
        num_values = array.GetDataSize()
        # Data type as specified in vtkSetGet.h.
        data_type = array.GetDataType()
        if data_type == 1:
            dtype = numpy.bool
        elif data_type in [2, 3]:
            dtype = numpy.str
        elif data_type in [4, 5, 6, 7, 8, 9]:
            dtype = numpy.int
        elif data_type in [10, 11]:
            dtype = numpy.float
        else:
            raise TypeError('Unknown VTK data type %d.' % data_type)
        values = numpy.empty(num_values, dtype=dtype)
        for i in range(num_values):
            values[i] = array.GetValue(i)
        field_data[name] = values

    return field_data
<|endoftext|>