<commit_before>import datetime

from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse

from django.db.models import Q
from piston.handler import BaseHandler, AnonymousBaseHandler
from piston.utils import rc

from emocracy.issues_content.models import IssueBody
from emocracy.voting.models import Issue
from emocracy.voting.models import Vote
from emocracy.profiles.models import UserProfile
import gamelogic.actions

domain = Site.objects.get_current().domain

class AnonymousVoteHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    #model = Vote

    def read(self, request, id, *args, **kwargs):
        return self.model.objects.filter(issue=id)

    @classmethod
    def issue_uri(cls, vote):
        return "http://%s%s" %(domain, reverse('api_issue' , args=[vote.issue.id]))

    @classmethod
    def user_uri(cls, vote):
        return "http://%s%s" %(domain , reverse('api_user' , args=[vote.owner.id]))

class AnonymousVoteListHandler(AnonymousVoteHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote

    def read(self, request, *args, **kwargs):
        return self.model.objects.filter()

class VoteHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote
    #anonymous = AnonymousVoteHandler

    def read(self, request, id, *args, **kwargs):
        return self.model.objects.filter(issue=id)

    @classmethod
    def issue_uri(cls, vote):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[vote.issue.id]))

    @classmethod
    def user_uri(cls, vote):
        return "http://%s%s" %(domain , reverse('api_user' , args=[vote.owner.id]))

class VoteListHandler(VoteHandler):
    allowed_methods = ('GET', 'POST',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote
    anonymous = AnonymousVoteListHandler

    def read(self, request, *args, **kwargs):
        return self.model.objects.filter()

    def create(self, request):
        attrs = self.flatten_dict(request.POST)
        attrs['is_archived'] = False
        attrs['owner'] = request.user.id

        if self.exists(**attrs):
            return rc.DUPLICATE_ENTRY
        else:
            current = Vote.objects.filter(
                Q(issue=attrs['issue']) &
                Q(owner=request.user) &
                Q(is_archived=False)
            )
            if len(current) == 0:
                pass
            else:
                current = current[0]
                current.is_archived = True
                current.save()
            vote = Vote(vote=attrs['vote'],
                            issue=Issue.objects.get(id=attrs['issue']),
                            keep_private=attrs['keep_private'],
                            owner=request.user,
                            time_stamp = datetime.datetime.now())
            vote.save()

            return vote

class AnonymousUserListHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('user_uri', 'username')
    exclude = ('absolute_uri',)
    model = User

    def read(self, request, *args, **kwargs):
        return self.model.objects.filter()

    @classmethod
    def user_uri(cls, user):
        pass
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class UserListHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('user_uri', 'username')
    anonymous = AnonymousUserListHandler
    model = User

    def read(self, request, *args, **kwargs):
        return self.model.objects.filter()

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class AnonymousUserHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('username', 'score', 'ranking' , 'user_uri')
    model = User

    def read(self, request, id, *args, **kwargs):
        return self.model.objects.filter(id=id)

    @classmethod
    def score(cls, user):
        return user.get_profile().score

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def ranking(cls , user):
        p = user.get_profile()
        return UserProfile.objects.filter( score__gte = p.score ).count()

class UserHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('username', 'score', 'user_uri')
    anonymous = AnonymousUserHandler
    model = User

    def read(self, request, id, *args, **kwargs):
        return self.model.objects.filter(id=id)

    @classmethod
    def score(cls, user):
        return user.get_profile().score

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class AnonymousIssueListHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url', 'votes_for', 'votes_abstain', 'votes_against')
    model = IssueBody

    def read(self, request, *args, **kwargs):
        return self.model.objects.filter()

    @classmethod
    def votes_for(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote=1) & Q(is_archived=False)).count()

    @classmethod
    def votes_abstain(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote__gt=9) & Q(is_archived=False)).count()

    @classmethod
    def votes_against(cls, issue):
        votes_against = Vote.objects.filter(Q(issue=issue) & Q(vote=-1) &Q(is_archived=False)).count()
        return votes_against

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class IssueListHandler(BaseHandler):
    allowed_methods = ('GET',)

    anonymous = AnonymousIssueListHandler
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url', 'votes_for', 'votes_abstain', 'votes_against', 'my_vote')
    model = IssueBody

    def read(self, request, *args, **kwargs):

        issues= self.model.objects.filter()
        issue_list = []
        for issue in issues:
            vote = Vote.objects.filter(Q(issue=issue) & Q(owner=request.user) &Q(is_archived=False))
            issue.my_vote = vote
            issue_list.append(issue)
        return issue_list

    @classmethod
    def my_vote(cls, issue):
        return issue.my_vote

    @classmethod
    def votes_for(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote=1) &Q(is_archived=False)).count()

    @classmethod
    def votes_abstain(cls, issue):
        votes_abstain = Vote.objects.filter(Q(issue=issue) & Q(vote__gt=9) &Q(is_archived=False)).count()
        return votes_abstain

    @classmethod
    def votes_against(cls, issue):
        votes_against = Vote.objects.filter(Q(issue=issue) & Q(vote=-1) &Q(is_archived=False)).count()
        return votes_against

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class AnonymousIssueHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'source_type', 'url')
    #model = IssueBody

    def read(self, request, id, *args, **kwargs):
        return self.model.objects.filter(id=id)

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class IssueHandler(BaseHandler):
    allowed_methods = ('GET', 'POST',)
    anonymous = AnonymousIssueHandler
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url')
    #model = IssueBody

    def create(self, request):
        attrs = self.flatten_dict(request.POST)

        if self.exists(**attrs):
            return rc.DUPLICATE_ENTRY
        else:
            issue = gamelogic.actions.propose(
                request.user,
                attrs['title'],
                attrs['body'],
                attrs['owners_vote'],
                attrs['url'],
                attrs['source_type'],
                attrs['is_draft'],
                None,
            )
            issue.save()
            return issue

    def read(self, request, id):
        if id==None:
            return self.model.objects.filter()
        else:
            return self.model.objects.filter(id=id)

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))
<commit_msg>added pagination<commit_after>import datetime

from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.core.paginator import Paginator
from django.core.paginator import InvalidPage
from django.core.paginator import EmptyPage

from django.db.models import Q
from piston.handler import BaseHandler, AnonymousBaseHandler
from piston.utils import rc

from emocracy.issues_content.models import IssueBody
from emocracy.voting.models import Issue
from emocracy.voting.models import Vote
from emocracy.profiles.models import UserProfile
import gamelogic.actions

domain = Site.objects.get_current().domain

# TODO: add pagination to all views
# TODO: communicate current page number or error to consumer
def paginate(request, qs):
    paginator = Paginator(qs, 25)  # TODO: add to settings.py
    try:
        pageno = int(request.GET.get('page', '1'))
    except ValueError:
        pageno = 1
    try:
        page = paginator.page(pageno)
    except (EmptyPage, InvalidPage):
        page = paginator.page(paginator.num_pages) #last page
    return page

class AnonymousVoteHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    #model = Vote

    def read(self, request, id, *args, **kwargs):
        queryset = self.model.objects.filter(issue=id)
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def issue_uri(cls, vote):
        return "http://%s%s" %(domain, reverse('api_issue' , args=[vote.issue.id]))

    @classmethod
    def user_uri(cls, vote):
        return "http://%s%s" %(domain , reverse('api_user' , args=[vote.owner.id]))

class AnonymousVoteListHandler(AnonymousVoteHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote

    def read(self, request, *args, **kwargs):
        queryset = self.model.objects.filter()
        page = paginate(request, queryset)
        return page.object_list

class VoteHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote
    #anonymous = AnonymousVoteHandler

    def read(self, request, id, *args, **kwargs):
        queryset = self.model.objects.filter(issue=id)
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def issue_uri(cls, vote):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[vote.issue.id]))

    @classmethod
    def user_uri(cls, vote):
        return "http://%s%s" %(domain , reverse('api_user' , args=[vote.owner.id]))

class VoteListHandler(VoteHandler):
    allowed_methods = ('GET', 'POST',)
    fields = ('vote', 'time_stamp', 'issue_uri', 'keep_private', 'user_uri')
    model = Vote
    anonymous = AnonymousVoteListHandler

    def read(self, request, *args, **kwargs):
        queryset = self.model.objects.filter()
        page = paginate(request, queryset)
        return page.object_list

    def create(self, request):
        attrs = self.flatten_dict(request.POST)
        attrs['is_archived'] = False
        attrs['owner'] = request.user.id

        if self.exists(**attrs):
            return rc.DUPLICATE_ENTRY
        else:
            current = Vote.objects.filter(
                Q(issue=attrs['issue']) &
                Q(owner=request.user) &
                Q(is_archived=False)
            )
            if len(current) == 0:
                pass
            else:
                current = current[0]
                current.is_archived = True
                current.save()
            vote = Vote(vote=attrs['vote'],
                            issue=Issue.objects.get(id=attrs['issue']),
                            keep_private=attrs['keep_private'],
                            owner=request.user,
                            time_stamp = datetime.datetime.now())
            vote.save()

            return vote

class AnonymousUserListHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('user_uri', 'username')
    exclude = ('absolute_uri',)
    model = User

    def read(self, request, *args, **kwargs):
        queryset = self.model.objects.filter()
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def user_uri(cls, user):
        pass
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class UserListHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('user_uri', 'username')
    anonymous = AnonymousUserListHandler
    model = User

    def read(self, request, *args, **kwargs):
        queryset = self.model.objects.filter()
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class AnonymousUserHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('username', 'score', 'ranking' , 'user_uri')
    model = User

    def read(self, request, id, *args, **kwargs):
        queryset = self.model.objects.filter(id=id)
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def score(cls, user):
        return user.get_profile().score

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def ranking(cls , user):
        p = user.get_profile()
        return UserProfile.objects.filter( score__gte = p.score ).count()

class UserHandler(BaseHandler):
    allowed_methods = ('GET',)
    fields = ('username', 'score', 'user_uri')
    anonymous = AnonymousUserHandler
    model = User

    def read(self, request, id, *args, **kwargs):
        queryset = self.model.objects.filter(id=id)
        page = paginate(request, queryset)
        return page.object_list

    @classmethod
    def score(cls, user):
        return user.get_profile().score

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

class AnonymousIssueListHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url', 'votes_for', 'votes_abstain', 'votes_against')
    model = IssueBody

    def read(self, request, *args, **kwargs):
        issueset = self.model.objects.filter()
        page = paginate(request, issueset)
        return page.object_list

    @classmethod
    def votes_for(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote=1) & Q(is_archived=False)).count()

    @classmethod
    def votes_abstain(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote__gt=9) & Q(is_archived=False)).count()

    @classmethod
    def votes_against(cls, issue):
        votes_against = Vote.objects.filter(Q(issue=issue) & Q(vote=-1) &Q(is_archived=False)).count()
        return votes_against

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class IssueListHandler(BaseHandler):
    allowed_methods = ('GET',)

    anonymous = AnonymousIssueListHandler
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url', 'votes_for', 'votes_abstain', 'votes_against', 'my_vote')
    model = IssueBody

    def read(self, request, *args, **kwargs):

        issues= self.model.objects.filter()
        page = paginate(request, issues)
        issue_list = []
        for issue in page.object_list:
            vote = Vote.objects.filter(Q(issue=issue) & Q(owner=request.user) &Q(is_archived=False))
            issue.my_vote = vote
            issue_list.append(issue)
        return issue_list

    @classmethod
    def my_vote(cls, issue):
        return issue.my_vote

    @classmethod
    def votes_for(cls, issue):
        return Vote.objects.filter(Q(issue=issue) & Q(vote=1) &Q(is_archived=False)).count()

    @classmethod
    def votes_abstain(cls, issue):
        votes_abstain = Vote.objects.filter(Q(issue=issue) & Q(vote__gt=9) &Q(is_archived=False)).count()
        return votes_abstain

    @classmethod
    def votes_against(cls, issue):
        votes_against = Vote.objects.filter(Q(issue=issue) & Q(vote=-1) &Q(is_archived=False)).count()
        return votes_against

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class AnonymousIssueHandler(AnonymousBaseHandler):
    allowed_methods = ('GET',)
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'source_type', 'url')
    #model = IssueBody

    def read(self, request, id, *args, **kwargs):
        queryset = self.model.objects.filter(id=id)
        page = paginate(request, queryset)
        return page

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))

class IssueHandler(BaseHandler):
    allowed_methods = ('GET', 'POST',)
    anonymous = AnonymousIssueHandler
    fields = ('issue_uri', 'title', 'body', ('owner', ('username', 'user_uri',)), 'time_stamp', 'souce_type', 'url')
    #model = IssueBody

    def create(self, request):
        attrs = self.flatten_dict(request.POST)

        if self.exists(**attrs):
            return rc.DUPLICATE_ENTRY
        else:
            issue = gamelogic.actions.propose(
                request.user,
                attrs['title'],
                attrs['body'],
                attrs['owners_vote'],
                attrs['url'],
                attrs['source_type'],
                attrs['is_draft'],
                None,
            )
            issue.save()
            return issue

    def read(self, request, id):
        if id==None:
            queryset = self.model.objects.filter()
            page = paginate(request, queryset)
            return page.object_list
        else:
            return self.model.objects.filter(id=id)

    @classmethod
    def user_uri(cls, user):
        return "http://%s%s" % (domain , reverse('api_user' , args=[user.id]))

    @classmethod
    def issue_uri(cls, issue):
        return "http://%s%s" % (domain , reverse('api_issue' , args=[issue.id]))
<|endoftext|>


<commit_before><commit_msg>Revert change made for dedup items (#22470)<commit_after><|endoftext|>


<commit_before># -*- encoding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.tools.translate import _
from openerp import netsvc
from openerp.exceptions import except_orm
from openerp import models, api, fields

from openerp.tools import (
    DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT,
    DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT,
)

import time

_STATES = [
    ('draft', _('Draft')),
    ('analysis', _('Analysis')),
    ('pending', _('Pending Approval')),
    ('open', _('In Progress')),
    ('done', _('Closed')),
    ('cancel', _('Cancelled')),
]
_STATES_DICT = dict(_STATES)

class mgmtsystem_nonconformity(models.Model):
    """
    Management System - Nonconformity
    """
    _name = "mgmtsystem.nonconformity"
    _description = "Nonconformity of the management system"
    _rec_name = "description"
    _inherit = ['mail.thread']
    _order = "date desc"

    def _state_name(self):
        res = dict()
        for o in self:
            res[o.id] = _STATES_DICT.get(o.state, o.state)
        return res

    # 1. Description
    ref = fields.Char(
        'Reference',
        size=64,
        required=True,
        readonly=True,
        default="NEW"
    )
    date = fields.Date(
        'Date',
        required=True,
        default=lambda *a: time.strftime(DATE_FORMAT)
    )
    partner_id = fields.Many2one('res.partner', 'Partner', required=True)
    reference = fields.Char('Related to', size=50)
    responsible_user_id = fields.Many2one(
        'res.users',
        'Responsible',
        required=True,
    )
    manager_user_id = fields.Many2one(
        'res.users',
        'Manager',
        required=True,
    )
    author_user_id = fields.Many2one(
        'res.users',
        'Filled in by',
        required=True,
        default=lambda self: self.env.user.id
    )
    origin_ids = fields.Many2many(
        'mgmtsystem.nonconformity.origin',
        'mgmtsystem_nonconformity_origin_rel',
        'nonconformity_id',
        'origin_id',
        'Origin',
        required=True,
    )
    procedure_ids = fields.Many2many(
        'document.page',
        'mgmtsystem_nonconformity_procedure_rel',
        'nonconformity_id',
        'procedure_id',
        'Procedure',
    )
    description = fields.Text('Description', required=True)
    state = fields.Selection(_STATES, 'State', readonly=True, default="draft")
    state_name = fields.Char(
        compute='_state_name',
        string='State Description',
        size=40,
    )
    system_id = fields.Many2one('mgmtsystem.system', 'System')

    # 2. Root Cause Analysis
    cause_ids = fields.Many2many(
        'mgmtsystem.nonconformity.cause',
        'mgmtsystem_nonconformity_cause_rel',
        'nonconformity_id',
        'cause_id',
        'Cause',
    )
    severity_id = fields.Many2one(
        'mgmtsystem.nonconformity.severity',
        'Severity',
    )
    analysis = fields.Text('Analysis')
    immediate_action_id = fields.Many2one(
        'mgmtsystem.action',
        'Immediate action',
        domain="[('nonconformity_id', '=', id)]",
    )
    analysis_date = fields.Datetime('Analysis Date', readonly=True)
    analysis_user_id = fields.Many2one(
        'res.users',
        'Analysis by',
        readonly=True,
    )

    # 3. Action Plan
    action_ids = fields.Many2many(
        'mgmtsystem.action',
        'mgmtsystem_nonconformity_action_rel',
        'nonconformity_id',
        'action_id',
        'Actions',
    )
    actions_date = fields.Datetime('Action Plan Date', readonly=True)
    actions_user_id = fields.Many2one(
        'res.users',
        'Action Plan by',
        readonly=True,
    )
    action_comments = fields.Text(
        'Action Plan Comments',
        help="Comments on the action plan.",
    )

    # 4. Effectiveness Evaluation
    evaluation_date = fields.Datetime('Evaluation Date', readonly=True)
    evaluation_user_id = fields.Many2one(
        'res.users',
        'Evaluation by',
        readonly=True,
    )
    evaluation_comments = fields.Text(
        'Evaluation Comments',
        help="Conclusions from the last effectiveness evaluation.",
    )

    # Multi-company
    company_id = fields.Many2one(
        'res.company',
        'Company',
        default=lambda self: self.env.user.company_id.id)

    @api.model
    def create(self, vals):
        vals.update({
            'ref': self.env['ir.sequence'].get('mgmtsystem.nonconformity')
        })
        return super(mgmtsystem_nonconformity, self).create(vals)

    def message_auto_subscribe(
            self, cr, uid, ids, updated_fields, context=None, values=None):
        """Add the reponsible, manager and OpenChatter follow list."""
        o = self.browse(cr, uid, ids, context=context)[0]
        user_ids = [
            o.responsible_user_id.id,
            o.manager_user_id.id,
            o.author_user_id.id,
        ]
        self.message_subscribe_users(
            cr, uid, ids, user_ids=user_ids, subtype_ids=None, context=context
        )
        return super(mgmtsystem_nonconformity, self).message_auto_subscribe(
            cr, uid, ids, updated_fields=updated_fields, context=context,
            values=values
        )

    def case_send_note(self, cr, uid, ids, text, data=None, context=None):
        for id in ids:
            pre = self.case_get_note_msg_prefix(cr, uid, id, context=context)
            msg = '%s %s' % (pre, text)
            if data:
                o = self.browse(cr, uid, ids, context=context)[0]
                post = _(u'''

 State: %s → %s

\
''') % (o.state, data['state'])
                msg += post
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_get_note_msg_prefix(self, cr, uid, id, context=None):
        return _('Nonconformity')

    def wkf_analysis(self, cr, uid, ids, context=None):
        """Change state from draft to analysis"""
        data = {
            'state': 'analysis',
            'analysis_date': None,
            'analysis_user_id': None}
        self.case_send_note(
            cr, uid, ids, _('Analysis'), data=data, context=context
        )
        return self.write(cr, uid, ids, data, context=context)

    def action_sign_analysis(self, cr, uid, ids, context=None):
        """Sign-off the analysis"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'analysis':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the Analysis state.')
            )
        if o.analysis_date:
            raise except_orm(
                _('Error !'),
                _('Analysis is already approved.')
            )
        if not o.analysis:
            raise except_orm(
                _('Error !'),
                _('Please provide an analysis before approving.')
            )
        vals = {
            'analysis_date': time.strftime(DATETIME_FORMAT),
            'analysis_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Analysis Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_review(self, cr, uid, ids, context=None):
        """Change state from analysis to pending approval"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if not o.analysis_date:
            err = _('Analysis must be performed before submiting to approval.')
            raise except_orm(_('Error !'), err)
        vals = {
            'state': 'pending',
            'actions_date': None,
            'actions_user_id': None}
        self.case_send_note(
            cr, uid, ids, _('Pending Approval'), data=vals, context=context
        )
        return self.write(cr, uid, ids, vals, context=context)

    def action_sign_actions(self, cr, uid, ids, context=None):
        """Sign-off the action plan"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'pending':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the Pending for Approval '
                  'state.')
            )
        if o.actions_date:
            raise except_orm(
                _('Error !'),
                _('Action plan is already approved.')
            )
        if not self.browse(cr, uid, ids, context=context)[0].analysis_date:
            raise except_orm(
                _('Error !'),
                _('Analysis approved before the review confirmation.')
            )
        vals = {
            'actions_date': time.strftime(DATETIME_FORMAT),
            'actions_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Action Plan Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_open(self, cr, uid, ids, context=None):
        """Change state from pending approval to in progress, and Open
        the related actions
        """
        o = self.browse(cr, uid, ids, context=context)[0]
        if not o.actions_date:
            raise except_orm(
                _('Error !'),
                _('Action plan must be approved before opening.')
            )
        self.case_open_send_note(cr, uid, ids, context=context)
        # Open related Actions
        # TODO static variables... hmm update state isn't going to work
        if (o.immediate_action_id
                and o.immediate_action_id.stage_id.name.lower() == 'draft'):
            o.immediate_action_id.case_open()
        for a in o.action_ids:
            if a.stage_id.name.lower() == 'draft':
                a.case_open()
        return self.write(cr, uid, ids, {
            'state': 'open',
            'evaluation_date': None,
            'evaluation_user_id': None,
        }, context=context)

    def action_sign_evaluation(self, cr, uid, ids, context=None):
        """Sign-off the effectiveness evaluation"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'open':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the In Progress state.')
            )
        vals = {
            'evaluation_date': time.strftime(DATETIME_FORMAT),
            'evaluation_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Effectiveness Evaluation Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_cancel(self, cr, uid, ids, context=None):
        """Change state to cancel"""
        self.case_cancel_send_note(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)

    def wkf_close(self, cr, uid, ids, context=None):
        """Change state from in progress to closed"""
        o = self.browse(cr, uid, ids, context=context)[0]
        # TODO make it more friendly
        done_states = ['done', 'cancelled', 'settled', 'rejected']
        if (o.immediate_action_id
                and o.immediate_action_id.stage_id.name.lower()
                not in done_states):
            raise except_orm(
                _('Error !'),
                _('Immediate action from analysis has not been closed.')
            )
        if ([i for i in o.action_ids
                if i.stage_id.name.lower() not in done_states]):
            raise except_orm(
                _('Error !'),
                _('Not all actions have been closed.')
            )
        if not o.evaluation_date:
            raise except_orm(
                _('Error !'),
                _('Effectiveness evaluation must be performed before closing.')
            )
        self.case_close_send_note(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)

    def case_reset(self, cr, uid, ids, context=None, *args):
        """Reset to Draft and restart the workflows"""
        wf_service = netsvc.LocalService("workflow")
        for id in ids:
            wf_service.trg_create(uid, self._name, id, cr)
        self.case_reset_send_note(cr, uid, ids, context=context)
        vals = {
            'state': 'draft',
            'analysis_date': None, 'analysis_user_id': None,
            'actions_date': None, 'actions_user_id': None,
            'evaluation_date': None, 'evaluation_user_id': None,
        }
        return self.write(cr, uid, ids, vals, context=context)

    def case_cancel_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been canceled.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_reset_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been renewed.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_open_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been opened.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_close_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been closed.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True
<commit_msg>Removed size<commit_after># -*- encoding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.tools.translate import _
from openerp import netsvc
from openerp.exceptions import except_orm
from openerp import models, api, fields

from openerp.tools import (
    DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT,
    DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT,
)

import time

_STATES = [
    ('draft', _('Draft')),
    ('analysis', _('Analysis')),
    ('pending', _('Pending Approval')),
    ('open', _('In Progress')),
    ('done', _('Closed')),
    ('cancel', _('Cancelled')),
]
_STATES_DICT = dict(_STATES)

class mgmtsystem_nonconformity(models.Model):
    """
    Management System - Nonconformity
    """
    _name = "mgmtsystem.nonconformity"
    _description = "Nonconformity of the management system"
    _rec_name = "description"
    _inherit = ['mail.thread']
    _order = "date desc"

    def _state_name(self):
        res = dict()
        for o in self:
            res[o.id] = _STATES_DICT.get(o.state, o.state)
        return res

    # 1. Description
    ref = fields.Char(
        'Reference',
        required=True,
        readonly=True,
        default="NEW"
    )
    date = fields.Date(
        'Date',
        required=True,
        default=lambda *a: time.strftime(DATE_FORMAT)
    )
    partner_id = fields.Many2one('res.partner', 'Partner', required=True)
    reference = fields.Char('Related to')
    responsible_user_id = fields.Many2one(
        'res.users',
        'Responsible',
        required=True,
    )
    manager_user_id = fields.Many2one(
        'res.users',
        'Manager',
        required=True,
    )
    author_user_id = fields.Many2one(
        'res.users',
        'Filled in by',
        required=True,
        default=lambda self: self.env.user.id
    )
    origin_ids = fields.Many2many(
        'mgmtsystem.nonconformity.origin',
        'mgmtsystem_nonconformity_origin_rel',
        'nonconformity_id',
        'origin_id',
        'Origin',
        required=True,
    )
    procedure_ids = fields.Many2many(
        'document.page',
        'mgmtsystem_nonconformity_procedure_rel',
        'nonconformity_id',
        'procedure_id',
        'Procedure',
    )
    description = fields.Text('Description', required=True)
    state = fields.Selection(_STATES, 'State', readonly=True, default="draft")
    state_name = fields.Char(
        compute='_state_name',
        string='State Description',
    )
    system_id = fields.Many2one('mgmtsystem.system', 'System')

    # 2. Root Cause Analysis
    cause_ids = fields.Many2many(
        'mgmtsystem.nonconformity.cause',
        'mgmtsystem_nonconformity_cause_rel',
        'nonconformity_id',
        'cause_id',
        'Cause',
    )
    severity_id = fields.Many2one(
        'mgmtsystem.nonconformity.severity',
        'Severity',
    )
    analysis = fields.Text('Analysis')
    immediate_action_id = fields.Many2one(
        'mgmtsystem.action',
        'Immediate action',
        domain="[('nonconformity_id', '=', id)]",
    )
    analysis_date = fields.Datetime('Analysis Date', readonly=True)
    analysis_user_id = fields.Many2one(
        'res.users',
        'Analysis by',
        readonly=True,
    )

    # 3. Action Plan
    action_ids = fields.Many2many(
        'mgmtsystem.action',
        'mgmtsystem_nonconformity_action_rel',
        'nonconformity_id',
        'action_id',
        'Actions',
    )
    actions_date = fields.Datetime('Action Plan Date', readonly=True)
    actions_user_id = fields.Many2one(
        'res.users',
        'Action Plan by',
        readonly=True,
    )
    action_comments = fields.Text(
        'Action Plan Comments',
        help="Comments on the action plan.",
    )

    # 4. Effectiveness Evaluation
    evaluation_date = fields.Datetime('Evaluation Date', readonly=True)
    evaluation_user_id = fields.Many2one(
        'res.users',
        'Evaluation by',
        readonly=True,
    )
    evaluation_comments = fields.Text(
        'Evaluation Comments',
        help="Conclusions from the last effectiveness evaluation.",
    )

    # Multi-company
    company_id = fields.Many2one(
        'res.company',
        'Company',
        default=lambda self: self.env.user.company_id.id)

    @api.model
    def create(self, vals):
        vals.update({
            'ref': self.env['ir.sequence'].get('mgmtsystem.nonconformity')
        })
        return super(mgmtsystem_nonconformity, self).create(vals)

    def message_auto_subscribe(
            self, cr, uid, ids, updated_fields, context=None, values=None):
        """Add the reponsible, manager and OpenChatter follow list."""
        o = self.browse(cr, uid, ids, context=context)[0]
        user_ids = [
            o.responsible_user_id.id,
            o.manager_user_id.id,
            o.author_user_id.id,
        ]
        self.message_subscribe_users(
            cr, uid, ids, user_ids=user_ids, subtype_ids=None, context=context
        )
        return super(mgmtsystem_nonconformity, self).message_auto_subscribe(
            cr, uid, ids, updated_fields=updated_fields, context=context,
            values=values
        )

    def case_send_note(self, cr, uid, ids, text, data=None, context=None):
        for id in ids:
            pre = self.case_get_note_msg_prefix(cr, uid, id, context=context)
            msg = '%s %s' % (pre, text)
            if data:
                o = self.browse(cr, uid, ids, context=context)[0]
                post = _(u'''

 State: %s → %s

\
''') % (o.state, data['state'])
                msg += post
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_get_note_msg_prefix(self, cr, uid, id, context=None):
        return _('Nonconformity')

    def wkf_analysis(self, cr, uid, ids, context=None):
        """Change state from draft to analysis"""
        data = {
            'state': 'analysis',
            'analysis_date': None,
            'analysis_user_id': None}
        self.case_send_note(
            cr, uid, ids, _('Analysis'), data=data, context=context
        )
        return self.write(cr, uid, ids, data, context=context)

    def action_sign_analysis(self, cr, uid, ids, context=None):
        """Sign-off the analysis"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'analysis':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the Analysis state.')
            )
        if o.analysis_date:
            raise except_orm(
                _('Error !'),
                _('Analysis is already approved.')
            )
        if not o.analysis:
            raise except_orm(
                _('Error !'),
                _('Please provide an analysis before approving.')
            )
        vals = {
            'analysis_date': time.strftime(DATETIME_FORMAT),
            'analysis_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Analysis Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_review(self, cr, uid, ids, context=None):
        """Change state from analysis to pending approval"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if not o.analysis_date:
            err = _('Analysis must be performed before submiting to approval.')
            raise except_orm(_('Error !'), err)
        vals = {
            'state': 'pending',
            'actions_date': None,
            'actions_user_id': None}
        self.case_send_note(
            cr, uid, ids, _('Pending Approval'), data=vals, context=context
        )
        return self.write(cr, uid, ids, vals, context=context)

    def action_sign_actions(self, cr, uid, ids, context=None):
        """Sign-off the action plan"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'pending':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the Pending for Approval '
                  'state.')
            )
        if o.actions_date:
            raise except_orm(
                _('Error !'),
                _('Action plan is already approved.')
            )
        if not self.browse(cr, uid, ids, context=context)[0].analysis_date:
            raise except_orm(
                _('Error !'),
                _('Analysis approved before the review confirmation.')
            )
        vals = {
            'actions_date': time.strftime(DATETIME_FORMAT),
            'actions_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Action Plan Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_open(self, cr, uid, ids, context=None):
        """Change state from pending approval to in progress, and Open
        the related actions
        """
        o = self.browse(cr, uid, ids, context=context)[0]
        if not o.actions_date:
            raise except_orm(
                _('Error !'),
                _('Action plan must be approved before opening.')
            )
        self.case_open_send_note(cr, uid, ids, context=context)
        # Open related Actions
        # TODO static variables... hmm update state isn't going to work
        if (o.immediate_action_id
                and o.immediate_action_id.stage_id.name.lower() == 'draft'):
            o.immediate_action_id.case_open()
        for a in o.action_ids:
            if a.stage_id.name.lower() == 'draft':
                a.case_open()
        return self.write(cr, uid, ids, {
            'state': 'open',
            'evaluation_date': None,
            'evaluation_user_id': None,
        }, context=context)

    def action_sign_evaluation(self, cr, uid, ids, context=None):
        """Sign-off the effectiveness evaluation"""
        o = self.browse(cr, uid, ids, context=context)[0]
        if o.state != 'open':
            raise except_orm(
                _('Error !'),
                _('This action can only be done in the In Progress state.')
            )
        vals = {
            'evaluation_date': time.strftime(DATETIME_FORMAT),
            'evaluation_user_id': uid,
        }
        self.write(cr, uid, ids, vals, context=context)
        note = _('Effectiveness Evaluation Approved')
        self.case_send_note(cr, uid, ids, note, context=context)
        return True

    def wkf_cancel(self, cr, uid, ids, context=None):
        """Change state to cancel"""
        self.case_cancel_send_note(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)

    def wkf_close(self, cr, uid, ids, context=None):
        """Change state from in progress to closed"""
        o = self.browse(cr, uid, ids, context=context)[0]
        # TODO make it more friendly
        done_states = ['done', 'cancelled', 'settled', 'rejected']
        if (o.immediate_action_id
                and o.immediate_action_id.stage_id.name.lower()
                not in done_states):
            raise except_orm(
                _('Error !'),
                _('Immediate action from analysis has not been closed.')
            )
        if ([i for i in o.action_ids
                if i.stage_id.name.lower() not in done_states]):
            raise except_orm(
                _('Error !'),
                _('Not all actions have been closed.')
            )
        if not o.evaluation_date:
            raise except_orm(
                _('Error !'),
                _('Effectiveness evaluation must be performed before closing.')
            )
        self.case_close_send_note(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state': 'done'}, context=context)

    def case_reset(self, cr, uid, ids, context=None, *args):
        """Reset to Draft and restart the workflows"""
        wf_service = netsvc.LocalService("workflow")
        for id in ids:
            wf_service.trg_create(uid, self._name, id, cr)
        self.case_reset_send_note(cr, uid, ids, context=context)
        vals = {
            'state': 'draft',
            'analysis_date': None, 'analysis_user_id': None,
            'actions_date': None, 'actions_user_id': None,
            'evaluation_date': None, 'evaluation_user_id': None,
        }
        return self.write(cr, uid, ids, vals, context=context)

    def case_cancel_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been canceled.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_reset_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been renewed.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_open_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been opened.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True

    def case_close_send_note(self, cr, uid, ids, context=None):
        for id in ids:
            msg = _('%s has been closed.') % (
                self.case_get_note_msg_prefix(cr, uid, id, context=context)
            )
            self.message_post(cr, uid, [id], body=msg, context=context)
        return True
<|endoftext|>


<commit_before>"""
TESTS is a dict with all you tests.
Keys for this will be categories' names.
Each test is dict with
    "input" -- input data for user function
    "answer" -- your right answer
    "explanation" -- not necessary key, it's using for additional info in animation.
"""

TESTS = {
    "Basics": [
        {
            "input": [(4, 7, 7, 5), (1, 2, 1, 5), (1, 5, 4, 7), (1, 2, 7, 2)],
            "answer": [(4, 7, 7, 5), (1, 2, 1, 5), (1, 5, 4, 7), (1, 2, 7, 2)],
        },
        {
            "input": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 2)],
            "answer": [],
        },
        {
            "input": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 5),
                      (1, 5, 7, 2)],
            "answer": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 5),
                       (1, 5, 7, 2)],
        },
    ],
    "Edge": [
        {
            "input": [(1, 1, 9, 9)],
            "answer": [(1, 1, 9, 9)],
        },
        {
            "input": [(1, 1, 1, 99), (99, 99, 1, 99), (99, 99, 99, 1), (99, 1, 1, 1)],
            "answer": [(1, 1, 1, 99), (99, 99, 1, 99), (99, 99, 99, 1), (99, 1, 1, 1)],
        },
        {
            "input": [(8, 4, 8, 6), (4, 8, 6, 2), (6, 8, 8, 6), (4, 8, 8, 6), (2, 6, 4, 2), (6, 2, 8, 4), (6, 8, 6, 2),
                      (2, 6, 6, 2), (2, 4, 8, 4), (6, 8, 8, 4), (4, 2, 6, 2), (4, 2, 8, 6), (2, 4, 2, 6), (4, 2, 6, 8),
                      (4, 2, 4, 8), (2, 4, 6, 2), (2, 4, 4, 8), (4, 8, 6, 8), (6, 2, 8, 6), (4, 8, 8, 4), (2, 6, 8, 6),
                      (2, 6, 6, 8), (2, 4, 4, 2), (4, 2, 8, 4), (2, 4, 6, 8), (2, 6, 4, 8), (2, 6, 8, 4), (2, 4, 8, 6)],
            "answer": [],
        },
        {
            "input": [(4, 2, 6, 8), (2, 4, 6, 2), (4, 8, 6, 2), (2, 4, 6, 8), (6, 8, 6, 2), (6, 2, 8, 4), (4, 2, 8, 4),
                      (2, 6, 4, 8), (2, 6, 6, 8), (2, 6, 4, 2), (4, 2, 4, 8), (2, 4, 4, 8), (4, 8, 6, 8), (2, 4, 4, 2),
                      (2, 4, 8, 4), (6, 8, 8, 4), (2, 6, 6, 2), (2, 6, 8, 4), (4, 2, 6, 2), (4, 8, 8, 4), (2, 4, 2, 6)],
            "answer": [(4, 2, 6, 8), (2, 4, 6, 2), (4, 8, 6, 2), (2, 4, 6, 8), (6, 8, 6, 2), (6, 2, 8, 4), (4, 2, 8, 4),
                       (2, 6, 4, 8), (2, 6, 6, 8), (2, 6, 4, 2), (4, 2, 4, 8), (2, 4, 4, 8), (4, 8, 6, 8), (2, 4, 4, 2),
                       (2, 4, 8, 4), (6, 8, 8, 4), (2, 6, 6, 2), (2, 6, 8, 4), (4, 2, 6, 2), (4, 8, 8, 4),
                       (2, 4, 2, 6)],
        },
    ],
    "Extra": [
        {
            "input": [(97, 8, 3, 3), (3, 3, 50, 50), (50, 50, 97, 8)],
            "answer": [(97, 8, 3, 3), (3, 3, 50, 50), (50, 50, 97, 8)],
        },
        {
            "input": [(50, 40, 60, 40), (60, 10, 70, 20), (20, 40, 30, 40), (50, 10, 60, 10), (30, 10, 40, 25),
                      (10, 30, 20, 40), (40, 25, 50, 10), (30, 40, 40, 25), (20, 10, 30, 10), (10, 20, 10, 30),
                      (60, 40, 70, 30), (10, 20, 20, 10), (40, 25, 50, 40), (70, 30, 70, 20)],
            "answer": [(50, 40, 60, 40), (60, 10, 70, 20), (20, 40, 30, 40), (50, 10, 60, 10), (30, 10, 40, 25),
                       (10, 30, 20, 40), (40, 25, 50, 10), (30, 40, 40, 25), (20, 10, 30, 10), (10, 20, 10, 30),
                       (60, 40, 70, 30), (10, 20, 20, 10), (40, 25, 50, 40), (70, 30, 70, 20)],
        },
        {
            "input": [(11, 11, 55, 66), (22, 33, 33, 56), (22, 33, 55, 66), (11, 11, 22, 33), (55, 66, 33, 56)],
            "answer": [(11, 11, 55, 66), (22, 33, 33, 56), (22, 33, 55, 66), (11, 11, 22, 33), (55, 66, 33, 56)],
        },
        {
            "input": [(55, 30, 55, 55), (40, 20, 55, 55), (55, 30, 70, 44), (10, 50, 55, 55), (10, 50, 40, 20),
                      (40, 20, 70, 44), (40, 20, 55, 30), (55, 55, 70, 44), (10, 50, 55, 30), (10, 50, 70, 44)],
            "answer": [(55, 30, 55, 55), (40, 20, 55, 55), (55, 30, 70, 44), (10, 50, 55, 55), (10, 50, 40, 20),
                       (40, 20, 70, 44), (40, 20, 55, 30), (55, 55, 70, 44), (10, 50, 55, 30), (10, 50, 70, 44)],
        },
        {
            "input": [(1, 1, 2, 2), (2, 1, 2, 2), (2, 1, 3, 2), (2, 1, 3, 1), (1, 1, 0, 2), (1, 1, 0, 0), (3, 2, 3, 1),
                      (0, 0, 0, 2)],
            "answer": [(1, 1, 2, 2), (2, 1, 2, 2), (2, 1, 3, 2), (2, 1, 3, 1), (1, 1, 0, 2), (1, 1, 0, 0), (3, 2, 3, 1),
                       (0, 0, 0, 2)],
        }
    ]
}
<commit_msg>add test case where travel-to-adjacent-vertex-with-most-untraveled edges won't work<commit_after>"""
TESTS is a dict with all you tests.
Keys for this will be categories' names.
Each test is dict with
    "input" -- input data for user function
    "answer" -- your right answer
    "explanation" -- not necessary key, it's using for additional info in animation.
"""

TESTS = {
    "Basics": [
        {
            "input": [(4, 7, 7, 5), (1, 2, 1, 5), (1, 5, 4, 7), (1, 2, 7, 2)],
            "answer": [(4, 7, 7, 5), (1, 2, 1, 5), (1, 5, 4, 7), (1, 2, 7, 2)],
        },
        {
            "input": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 2)],
            "answer": [],
        },
        {
            "input": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 5),
                      (1, 5, 7, 2)],
            "answer": [(1, 2, 1, 5), (1, 2, 7, 2), (7, 5, 1, 2), (4, 7, 7, 5), (1, 5, 4, 7), (7, 5, 7, 2), (1, 5, 7, 5),
                       (1, 5, 7, 2)],
        },
    ],
    "Edge": [
        {
            "input": [(1, 1, 9, 9)],
            "answer": [(1, 1, 9, 9)],
        },
        {
            "input": [(1, 1, 1, 99), (99, 99, 1, 99), (99, 99, 99, 1), (99, 1, 1, 1)],
            "answer": [(1, 1, 1, 99), (99, 99, 1, 99), (99, 99, 99, 1), (99, 1, 1, 1)],
        },
        {
            "input": [(8, 4, 8, 6), (4, 8, 6, 2), (6, 8, 8, 6), (4, 8, 8, 6), (2, 6, 4, 2), (6, 2, 8, 4), (6, 8, 6, 2),
                      (2, 6, 6, 2), (2, 4, 8, 4), (6, 8, 8, 4), (4, 2, 6, 2), (4, 2, 8, 6), (2, 4, 2, 6), (4, 2, 6, 8),
                      (4, 2, 4, 8), (2, 4, 6, 2), (2, 4, 4, 8), (4, 8, 6, 8), (6, 2, 8, 6), (4, 8, 8, 4), (2, 6, 8, 6),
                      (2, 6, 6, 8), (2, 4, 4, 2), (4, 2, 8, 4), (2, 4, 6, 8), (2, 6, 4, 8), (2, 6, 8, 4), (2, 4, 8, 6)],
            "answer": [],
        },
        {
            "input": [(4, 2, 6, 8), (2, 4, 6, 2), (4, 8, 6, 2), (2, 4, 6, 8), (6, 8, 6, 2), (6, 2, 8, 4), (4, 2, 8, 4),
                      (2, 6, 4, 8), (2, 6, 6, 8), (2, 6, 4, 2), (4, 2, 4, 8), (2, 4, 4, 8), (4, 8, 6, 8), (2, 4, 4, 2),
                      (2, 4, 8, 4), (6, 8, 8, 4), (2, 6, 6, 2), (2, 6, 8, 4), (4, 2, 6, 2), (4, 8, 8, 4), (2, 4, 2, 6)],
            "answer": [(4, 2, 6, 8), (2, 4, 6, 2), (4, 8, 6, 2), (2, 4, 6, 8), (6, 8, 6, 2), (6, 2, 8, 4), (4, 2, 8, 4),
                       (2, 6, 4, 8), (2, 6, 6, 8), (2, 6, 4, 2), (4, 2, 4, 8), (2, 4, 4, 8), (4, 8, 6, 8), (2, 4, 4, 2),
                       (2, 4, 8, 4), (6, 8, 8, 4), (2, 6, 6, 2), (2, 6, 8, 4), (4, 2, 6, 2), (4, 8, 8, 4),
                       (2, 4, 2, 6)],
        },
    ],
    "Extra": [
        {
            "input": [(97, 8, 3, 3), (3, 3, 50, 50), (50, 50, 97, 8)],
            "answer": [(97, 8, 3, 3), (3, 3, 50, 50), (50, 50, 97, 8)],
        },
        {
            "input": [(50, 40, 60, 40), (60, 10, 70, 20), (20, 40, 30, 40), (50, 10, 60, 10), (30, 10, 40, 25),
                      (10, 30, 20, 40), (40, 25, 50, 10), (30, 40, 40, 25), (20, 10, 30, 10), (10, 20, 10, 30),
                      (60, 40, 70, 30), (10, 20, 20, 10), (40, 25, 50, 40), (70, 30, 70, 20)],
            "answer": [(50, 40, 60, 40), (60, 10, 70, 20), (20, 40, 30, 40), (50, 10, 60, 10), (30, 10, 40, 25),
                       (10, 30, 20, 40), (40, 25, 50, 10), (30, 40, 40, 25), (20, 10, 30, 10), (10, 20, 10, 30),
                       (60, 40, 70, 30), (10, 20, 20, 10), (40, 25, 50, 40), (70, 30, 70, 20)],
        },
        {
            "input": [(11, 11, 55, 66), (22, 33, 33, 56), (22, 33, 55, 66), (11, 11, 22, 33), (55, 66, 33, 56)],
            "answer": [(11, 11, 55, 66), (22, 33, 33, 56), (22, 33, 55, 66), (11, 11, 22, 33), (55, 66, 33, 56)],
        },
        {
            "input": [(55, 30, 55, 55), (40, 20, 55, 55), (55, 30, 70, 44), (10, 50, 55, 55), (10, 50, 40, 20),
                      (40, 20, 70, 44), (40, 20, 55, 30), (55, 55, 70, 44), (10, 50, 55, 30), (10, 50, 70, 44)],
            "answer": [(55, 30, 55, 55), (40, 20, 55, 55), (55, 30, 70, 44), (10, 50, 55, 55), (10, 50, 40, 20),
                       (40, 20, 70, 44), (40, 20, 55, 30), (55, 55, 70, 44), (10, 50, 55, 30), (10, 50, 70, 44)],
        },
        {
            "input": [(1, 1, 2, 2), (2, 1, 2, 2), (2, 1, 3, 2), (2, 1, 3, 1), (1, 1, 0, 2), (1, 1, 0, 0), (3, 2, 3, 1),
                      (0, 0, 0, 2)],
            "answer": [(1, 1, 2, 2), (2, 1, 2, 2), (2, 1, 3, 2), (2, 1, 3, 1), (1, 1, 0, 2), (1, 1, 0, 0), (3, 2, 3, 1),
                       (0, 0, 0, 2)],
        },
        {
            "input": [(0, 0, 0, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 3, 0),
                      (3, 0, 4, 0), (3, 0, 4, 1), (4, 0, 4, 1)],
            "answer": [(0, 0, 0, 1), (1, 0, 0, 0), (1, 0, 0, 1), (1, 0, 3, 0),
                       (3, 0, 4, 0), (3, 0, 4, 1), (4, 0, 4, 1)],
        },
    ],
}
<|endoftext|>


<commit_before>import imp
import logging
import math

from . import Veros, settings

class LowercaseAttributeWrapper(object):
    """
    A simple wrapper class that converts attributes to lower case (needed for Fortran interface)
    """

    def __init__(self, wrapped_object):
        object.__setattr__(self, "_w", wrapped_object)

    def __getattr__(self, key):
        if key == "_w":
            return object.__getattribute__(self, "_w")
        return getattr(object.__getattribute__(self, "_w"), key.lower())

    def __setattr__(self, key, value):
        setattr(self._w, key.lower(), value)

class VerosLegacy(Veros):
    """
    An alternative Veros class that supports the pyOM Fortran interface as backend

    .. warning::

       Do not use this class for new setups!

    """

    def __init__(self, fortran=None, *args, **kwargs):
        """
        To use the pyOM2 legacy interface point the fortran argument to the Veros fortran library:

        > simulation = GlobalOneDegree(fortran = "pyOM_code.so")

        """
        if fortran:
            self.legacy_mode = True
            try:
                self.fortran = LowercaseAttributeWrapper(imp.load_dynamic("pyOM_code", fortran))
                self.use_mpi = False
            except ImportError:
                self.fortran = LowercaseAttributeWrapper(imp.load_dynamic("pyOM_code_MPI", fortran))
                self.use_mpi = True
                from mpi4py import MPI
                self.mpi_comm = MPI.COMM_WORLD
            self.main_module = LowercaseAttributeWrapper(self.fortran.main_module)
            self.isoneutral_module = LowercaseAttributeWrapper(self.fortran.isoneutral_module)
            self.idemix_module = LowercaseAttributeWrapper(self.fortran.idemix_module)
            self.tke_module = LowercaseAttributeWrapper(self.fortran.tke_module)
            self.eke_module = LowercaseAttributeWrapper(self.fortran.eke_module)
        else:
            self.legacy_mode = False
            self.use_mpi = False
            self.fortran = self
            self.main_module = self
            self.isoneutral_module = self
            self.idemix_module = self
            self.tke_module = self
            self.eke_module = self
        self.modules = (self.main_module, self.isoneutral_module, self.idemix_module,
                        self.tke_module, self.eke_module)

        if self.use_mpi and self.mpi_comm.Get_rank() != 0:
            kwargs["loglevel"] = "critical"
        super(VerosLegacy, self).__init__(*args, **kwargs)

    def set_legacy_parameter(self, *args, **kwargs):
        m = self.fortran.main_module
        if self.use_mpi:
            n_sqrt = int(math.sqrt(m.n_pes))
            m.n_pes_i = n_sqrt
            m.n_pes_j = m.n_pes / n_sqrt
        self.if2py = lambda i: i + m.onx - m.is_pe
        self.jf2py = lambda j: j + m.onx - m.js_pe
        self.ip2fy = lambda i: i + m.is_pe - m.onx
        self.jp2fy = lambda j: j + m.js_pe - m.onx
        self.get_tau = lambda: m.tau - 1 if self.legacy_mode else m.tau

        # force settings that are not supported by Veros
        idm = self.fortran.idemix_module
        m.enable_streamfunction = True
        m.enable_hydrostatic = True
        idm.enable_idemix_m2 = False
        idm.enable_idemix_niw = False

    def _set_commandline_settings(self):
        for key, val in self.command_line_settings:
            for m in self.modules:
                if hasattr(m, key):
                    setattr(m, key, settings.SETTINGS[key].type(val))

    def setup(self, *args, **kwargs):
        with self.timers["setup"]:
            if self.legacy_mode:
                if self.use_mpi:
                    self.fortran.my_mpi_init(self.mpi_comm.py2f())
                else:
                    self.fortran.my_mpi_init(0)
                self.set_parameter()
                self.set_legacy_parameter()
                self._set_commandline_settings()
                self.fortran.pe_decomposition()
                self.fortran.allocate_main_module()
                self.fortran.allocate_isoneutral_module()
                self.fortran.allocate_tke_module()
                self.fortran.allocate_eke_module()
                self.fortran.allocate_idemix_module()
                self.set_grid()
                self.fortran.calc_grid()
                self.set_coriolis()
                self.fortran.calc_beta()
                self.set_topography()
                self.fortran.calc_topo()
                self.fortran.calc_spectral_topo()
                self.set_initial_conditions()
                self.fortran.calc_initial_conditions()
                self.set_forcing()
                self.fortran.streamfunction_init()
                self.set_diagnostics()
                self.fortran.check_isoneutral_slope_crit()
            else:
                # self.set_parameter() is called twice, but that shouldn't matter
                self.set_parameter()
                self.set_legacy_parameter()
                super(VerosLegacy, self).setup(*args, **kwargs)

                diag_legacy_settings = (
                    (self.diagnostics["cfl_monitor"], "output_frequency", "ts_monint"),
                    (self.diagnostics["tracer_monitor"], "output_frequency", "trac_cont_int"),
                    (self.diagnostics["snapshot"], "output_frequency", "snapint"),
                    (self.diagnostics["averages"], "output_frequency", "aveint"),
                    (self.diagnostics["averages"], "sampling_frequency", "avefreq"),
                    (self.diagnostics["overturning"], "output_frequency", "overint"),
                    (self.diagnostics["overturning"], "sampling_frequency", "overfreq"),
                    (self.diagnostics["energy"], "output_frequency", "energint"),
                    (self.diagnostics["energy"], "sampling_frequency", "energfreq"),
                )

                for diag, param, attr in diag_legacy_settings:
                    if hasattr(self, attr):
                        setattr(diag, param, getattr(self, attr))

    def run(self, **kwargs):
        if not self.legacy_mode:
            super(VerosLegacy, self).run(**kwargs)
            return

        f = self.fortran
        m = self.main_module
        idm = self.idemix_module
        ekm = self.eke_module
        tkm = self.tke_module

        m.enditt = m.itt + int(m.runlen / m.dt_tracer)
        logging.info("Starting integration for {:.2e}s".format(float(m.runlen)))
        logging.info(" from time step {} to {}".format(m.itt, m.enditt))

        while m.itt < m.enditt:
            with self.timers["main"]:
                self.set_forcing()

                if idm.enable_idemix:
                    f.set_idemix_parameter()

                f.set_eke_diffusivities()
                f.set_tke_diffusivities()

                with self.timers["momentum"]:
                    f.momentum()

                with self.timers["temperature"]:
                    f.thermodynamics()

                if ekm.enable_eke or tkm.enable_tke or idm.enable_idemix:
                    f.calculate_velocity_on_wgrid()

                with self.timers["eke"]:
                    if ekm.enable_eke:
                        f.integrate_eke()

                with self.timers["idemix"]:
                    if idm.enable_idemix:
                        f.integrate_idemix()

                with self.timers["tke"]:
                    if tkm.enable_tke:
                        f.integrate_tke()

                """
                Main boundary exchange
                for density, temp and salt this is done in integrate_tempsalt.f90
                """
                f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                   m.onx, m.je_pe + m.onx, m.u[:, :, :, m.taup1 - 1], m.nz)
                f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                m.je_pe + m.onx, m.u[:, :, :, m.taup1 - 1], m.nz)
                f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                   m.onx, m.je_pe + m.onx, m.v[:, :, :, m.taup1 - 1], m.nz)
                f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                m.je_pe + m.onx, m.v[:, :, :, m.taup1 - 1], m.nz)

                if tkm.enable_tke:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, tkm.tke[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, tkm.tke[:, :, :, m.taup1 - 1], m.nz)
                if ekm.enable_eke:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, ekm.eke[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, ekm.eke[:, :, :, m.taup1 - 1], m.nz)
                if idm.enable_idemix:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, idm.e_iw[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, idm.e_iw[:, :, :, m.taup1 - 1], m.nz)

                # diagnose vertical velocity at taup1
                f.vertical_velocity()

            # shift time
            m.itt += 1
            self.time += m.dt_tracer

            self.after_timestep()

            otaum1 = m.taum1 * 1
            m.taum1 = m.tau
            m.tau = m.taup1
            m.taup1 = otaum1

            logging.info("Current iteration: {}".format(m.itt))
            logging.debug("Time step took {}s".format(self.timers["main"].getLastTime()))

        logging.debug("Timing summary:")
        logging.debug(" setup time summary       = {}s".format(self.timers["setup"].getTime()))
        logging.debug(" main loop time summary   = {}s".format(self.timers["main"].getTime()))
        logging.debug("     momentum             = {}s".format(self.timers["momentum"].getTime()))
        logging.debug("     thermodynamics       = {}s".format(self.timers["temperature"].getTime()))
        logging.debug("     EKE                  = {}s".format(self.timers["eke"].getTime()))
        logging.debug("     IDEMIX               = {}s".format(self.timers["idemix"].getTime()))
        logging.debug("     TKE                  = {}s".format(self.timers["tke"].getTime()))
<commit_msg>[test] improve MPI decomposition algorithm<commit_after>import imp
import logging
import math

from . import Veros, settings

class LowercaseAttributeWrapper(object):
    """
    A simple wrapper class that converts attributes to lower case (needed for Fortran interface)
    """

    def __init__(self, wrapped_object):
        object.__setattr__(self, "_w", wrapped_object)

    def __getattr__(self, key):
        if key == "_w":
            return object.__getattribute__(self, "_w")
        return getattr(object.__getattribute__(self, "_w"), key.lower())

    def __setattr__(self, key, value):
        setattr(self._w, key.lower(), value)

class VerosLegacy(Veros):
    """
    An alternative Veros class that supports the pyOM Fortran interface as backend

    .. warning::

       Do not use this class for new setups!

    """

    def __init__(self, fortran=None, *args, **kwargs):
        """
        To use the pyOM2 legacy interface point the fortran argument to the Veros fortran library:

        > simulation = GlobalOneDegree(fortran = "pyOM_code.so")

        """
        if fortran:
            self.legacy_mode = True
            try:
                self.fortran = LowercaseAttributeWrapper(imp.load_dynamic("pyOM_code", fortran))
                self.use_mpi = False
            except ImportError:
                self.fortran = LowercaseAttributeWrapper(imp.load_dynamic("pyOM_code_MPI", fortran))
                self.use_mpi = True
                from mpi4py import MPI
                self.mpi_comm = MPI.COMM_WORLD
            self.main_module = LowercaseAttributeWrapper(self.fortran.main_module)
            self.isoneutral_module = LowercaseAttributeWrapper(self.fortran.isoneutral_module)
            self.idemix_module = LowercaseAttributeWrapper(self.fortran.idemix_module)
            self.tke_module = LowercaseAttributeWrapper(self.fortran.tke_module)
            self.eke_module = LowercaseAttributeWrapper(self.fortran.eke_module)
        else:
            self.legacy_mode = False
            self.use_mpi = False
            self.fortran = self
            self.main_module = self
            self.isoneutral_module = self
            self.idemix_module = self
            self.tke_module = self
            self.eke_module = self
        self.modules = (self.main_module, self.isoneutral_module, self.idemix_module,
                        self.tke_module, self.eke_module)

        if self.use_mpi and self.mpi_comm.Get_rank() != 0:
            kwargs["loglevel"] = "critical"
        super(VerosLegacy, self).__init__(*args, **kwargs)

    def set_legacy_parameter(self, *args, **kwargs):
        m = self.fortran.main_module
        if self.use_mpi:
            proc_combinations = ((ni, m.n_pes / ni) for ni in xrange(1, int(math.sqrt(m.n_pes)+1) if ni * (m.n_pes / ni) == m.n_pes)
            m.n_pes_i, m.n_pes_j = min(proc_combinations, key=lambda x: abs(x[1] - x[0]))
        self.if2py = lambda i: i + m.onx - m.is_pe
        self.jf2py = lambda j: j + m.onx - m.js_pe
        self.ip2fy = lambda i: i + m.is_pe - m.onx
        self.jp2fy = lambda j: j + m.js_pe - m.onx
        self.get_tau = lambda: m.tau - 1 if self.legacy_mode else m.tau

        # force settings that are not supported by Veros
        idm = self.fortran.idemix_module
        m.enable_streamfunction = True
        m.enable_hydrostatic = True
        idm.enable_idemix_m2 = False
        idm.enable_idemix_niw = False

    def _set_commandline_settings(self):
        for key, val in self.command_line_settings:
            for m in self.modules:
                if hasattr(m, key):
                    setattr(m, key, settings.SETTINGS[key].type(val))

    def setup(self, *args, **kwargs):
        with self.timers["setup"]:
            if self.legacy_mode:
                if self.use_mpi:
                    self.fortran.my_mpi_init(self.mpi_comm.py2f())
                else:
                    self.fortran.my_mpi_init(0)
                self.set_parameter()
                self.set_legacy_parameter()
                self._set_commandline_settings()
                self.fortran.pe_decomposition()
                self.fortran.allocate_main_module()
                self.fortran.allocate_isoneutral_module()
                self.fortran.allocate_tke_module()
                self.fortran.allocate_eke_module()
                self.fortran.allocate_idemix_module()
                self.set_grid()
                self.fortran.calc_grid()
                self.set_coriolis()
                self.fortran.calc_beta()
                self.set_topography()
                self.fortran.calc_topo()
                self.fortran.calc_spectral_topo()
                self.set_initial_conditions()
                self.fortran.calc_initial_conditions()
                self.set_forcing()
                self.fortran.streamfunction_init()
                self.set_diagnostics()
                self.fortran.check_isoneutral_slope_crit()
            else:
                # self.set_parameter() is called twice, but that shouldn't matter
                self.set_parameter()
                self.set_legacy_parameter()
                super(VerosLegacy, self).setup(*args, **kwargs)

                diag_legacy_settings = (
                    (self.diagnostics["cfl_monitor"], "output_frequency", "ts_monint"),
                    (self.diagnostics["tracer_monitor"], "output_frequency", "trac_cont_int"),
                    (self.diagnostics["snapshot"], "output_frequency", "snapint"),
                    (self.diagnostics["averages"], "output_frequency", "aveint"),
                    (self.diagnostics["averages"], "sampling_frequency", "avefreq"),
                    (self.diagnostics["overturning"], "output_frequency", "overint"),
                    (self.diagnostics["overturning"], "sampling_frequency", "overfreq"),
                    (self.diagnostics["energy"], "output_frequency", "energint"),
                    (self.diagnostics["energy"], "sampling_frequency", "energfreq"),
                )

                for diag, param, attr in diag_legacy_settings:
                    if hasattr(self, attr):
                        setattr(diag, param, getattr(self, attr))

    def run(self, **kwargs):
        if not self.legacy_mode:
            super(VerosLegacy, self).run(**kwargs)
            return

        f = self.fortran
        m = self.main_module
        idm = self.idemix_module
        ekm = self.eke_module
        tkm = self.tke_module

        m.enditt = m.itt + int(m.runlen / m.dt_tracer)
        logging.info("Starting integration for {:.2e}s".format(float(m.runlen)))
        logging.info(" from time step {} to {}".format(m.itt, m.enditt))

        while m.itt < m.enditt:
            with self.timers["main"]:
                self.set_forcing()

                if idm.enable_idemix:
                    f.set_idemix_parameter()

                f.set_eke_diffusivities()
                f.set_tke_diffusivities()

                with self.timers["momentum"]:
                    f.momentum()

                with self.timers["temperature"]:
                    f.thermodynamics()

                if ekm.enable_eke or tkm.enable_tke or idm.enable_idemix:
                    f.calculate_velocity_on_wgrid()

                with self.timers["eke"]:
                    if ekm.enable_eke:
                        f.integrate_eke()

                with self.timers["idemix"]:
                    if idm.enable_idemix:
                        f.integrate_idemix()

                with self.timers["tke"]:
                    if tkm.enable_tke:
                        f.integrate_tke()

                """
                Main boundary exchange
                for density, temp and salt this is done in integrate_tempsalt.f90
                """
                f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                   m.onx, m.je_pe + m.onx, m.u[:, :, :, m.taup1 - 1], m.nz)
                f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                m.je_pe + m.onx, m.u[:, :, :, m.taup1 - 1], m.nz)
                f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                   m.onx, m.je_pe + m.onx, m.v[:, :, :, m.taup1 - 1], m.nz)
                f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                m.je_pe + m.onx, m.v[:, :, :, m.taup1 - 1], m.nz)

                if tkm.enable_tke:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, tkm.tke[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, tkm.tke[:, :, :, m.taup1 - 1], m.nz)
                if ekm.enable_eke:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, ekm.eke[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, ekm.eke[:, :, :, m.taup1 - 1], m.nz)
                if idm.enable_idemix:
                    f.border_exchg_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe -
                                       m.onx, m.je_pe + m.onx, idm.e_iw[:, :, :, m.taup1 - 1], m.nz)
                    f.setcyclic_xyz(m.is_pe - m.onx, m.ie_pe + m.onx, m.js_pe - m.onx,
                                    m.je_pe + m.onx, idm.e_iw[:, :, :, m.taup1 - 1], m.nz)

                # diagnose vertical velocity at taup1
                f.vertical_velocity()

            # shift time
            m.itt += 1
            self.time += m.dt_tracer

            self.after_timestep()

            otaum1 = m.taum1 * 1
            m.taum1 = m.tau
            m.tau = m.taup1
            m.taup1 = otaum1

            logging.info("Current iteration: {}".format(m.itt))
            logging.debug("Time step took {}s".format(self.timers["main"].getLastTime()))

        logging.debug("Timing summary:")
        logging.debug(" setup time summary       = {}s".format(self.timers["setup"].getTime()))
        logging.debug(" main loop time summary   = {}s".format(self.timers["main"].getTime()))
        logging.debug("     momentum             = {}s".format(self.timers["momentum"].getTime()))
        logging.debug("     thermodynamics       = {}s".format(self.timers["temperature"].getTime()))
        logging.debug("     EKE                  = {}s".format(self.timers["eke"].getTime()))
        logging.debug("     IDEMIX               = {}s".format(self.timers["idemix"].getTime()))
        logging.debug("     TKE                  = {}s".format(self.timers["tke"].getTime()))
<|endoftext|>