deparkes/OOMMFTools

View on GitHub
oommftools/user_interfaces/gui/oommfdecode.py

Summary

Maintainability
F
3 days
Test Coverage

"""
OOMMFDecode
Copyright (C) 2010  Mark Mascaro

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

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

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

"""
from __future__ import print_function
from __future__ import absolute_import

from future import standard_library
standard_library.install_aliases()
from builtins import hex
from builtins import zip
from builtins import range
import time
from collections import defaultdict
import pickle as pickle
from wx import adv
import os
import wx
import struct
import numpy as np
import scipy.io as spio
from fnameutil import filterOnExtensions
import _about as about
from core import oommfdecode

#########
# About #
#########

VERSION = about.__version__
NAME = "OOMMFDecode"
LICENSE = about.__license__
COPYRIGHT = about.__copyright__
WEBSITE = about.__uri__
DESCRIPTION = """OOMMFDecode is an OOMMF postprocessing tool for
converting OVF files or batches of same into numpy
arrays or MATLAB data files. Just drag and drop.
\nOOMMFDecode is part of OOMMFTools."""


########
# DECS #
########

LASTPATH = os.getcwd()
if __name__ == "__main__":
    #app = wx.App(None)
    #app = wx.App(None)
    #app = wx.App(redirect=True)
    app = wx.App(redirect=True, filename="oommfdecode.log")

#######
# GUI #
#######

class MainFrame(wx.Frame):
    """Main oommfdecode frame
    """
    def __init__(self, manager=None):
        
        wx.Frame.__init__(self, None, -1, " ".join([NAME, VERSION]), size=(340, 400))

        BigFont = wx.Font(16, wx.FONTFAMILY_DEFAULT, style=wx.NORMAL, weight=wx.FONTWEIGHT_BOLD)
        TinyFont = wx.Font(8, wx.FONTFAMILY_DEFAULT, style=wx.NORMAL, weight=wx.FONTWEIGHT_NORMAL)

        self.dt = OOMMFSelectiveTarget(self)
        self.SetDropTarget(self.dt)
        self.manager = manager

        self.Bind(wx.EVT_CLOSE, self.onClose)

        #A very simple menubar
        menubar = wx.MenuBar()
        about = wx.Menu()
        about.Append(999, 'About', 'Program information and license')
        menubar.Append(about, "About")
        self.SetMenuBar(menubar)

        self.Bind(wx.EVT_MENU, self.showAbout, id=999)

        #NOW we can deal with actual GUI stuff - store a reference for forced resize, if it comes up
        panel = wx.Panel(self, -1)
        self.panel = panel

        sizer = wx.BoxSizer(wx.VERTICAL)

        titleText = wx.StaticText(panel, -1, "OMF File Decoding")
        titleText.SetFont(BigFont)
        sizer.Add(titleText, 0, wx.ALIGN_CENTER | wx.TOP, 24)

        sizer.Add(wx.StaticLine(panel, -1), 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 18)

        self.doNumpy = wx.CheckBox(panel, -1, "Create pickled numpy")
        sizer.Add(self.doNumpy, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)

        self.doMATLAB = wx.CheckBox(panel, -1, "Create MATLAB data")
        sizer.Add(self.doMATLAB, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL)

        sizer.Add(wx.StaticLine(panel, -1), 0, wx.EXPAND | wx.TOP, 18)

        ins = wx.StaticText(panel, -1, "Drop OOMMF Files Here!")
        ins.SetFont(BigFont)
        sizer.Add(ins, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP, 80)

        panel.SetSizer(sizer)
        if self.manager:
            self.CenterOnParent()
        panel.Fit()
        self.Show()

    def gatherData(self, data, headers, extraData):
        """
        """
        global LASTPATH
        #Outputs are array, headers, filenam
        if self.doNumpy.GetValue():
            with wx.FileDialog(self, 'Export Pickled numpy Data',
                               LASTPATH, "", "Pickled Data (*.pnp)|*.pnp",
                               wx.FD_SAVE) as dlg:
                if dlg.ShowModal() == wx.ID_OK and dlg.GetFilename():
                    filename = dlg.GetPath()
                    LASTPATH = os.path.dirname(filename)
                    oommfdecode.pickleArray(data, headers, extraData, filename)
                elif dlg.ShowModal() == wx.ID_CANCEL:
                    return # the user changed their mind

        if self.doMATLAB.GetValue():
            with wx.FileDialog(self, 'Export MATLAB Data', LASTPATH, "",
                               "MATLAB Data (*.mat)|*.mat",
                               wx.FD_SAVE) as dlg:
                if dlg.ShowModal() == wx.ID_OK and dlg.GetFilename():
                    filename = dlg.GetPath()
                    LASTPATH = os.path.dirname(filename)
                    oommfdecode.matlabifyArray(data, headers, extraData, filename)
                elif dlg.ShowModal() == wx.ID_CANCEL:
                    return # the user changed their mind

    def showAbout(self, evt):
        """
        """
        info = wx.adv.AboutDialogInfo()
        mydesc = DESCRIPTION
        mylicense = LICENSE
        info.SetName(NAME)
        info.SetVersion(VERSION)
        info.SetDescription(''.join(mydesc))
        info.SetLicense(''.join(mylicense))
        info.SetCopyright(COPYRIGHT)
        info.SetWebSite(WEBSITE)
        wx.adv.AboutBox(info)

    def onClose(self, evt):
        """
        """
        if self.manager:
            self.manager.droppedWindow(self)
        self.Destroy()

class SupportDialog(wx.ProgressDialog):
    """
    """
    def __init__(self, title, message, **kwargs):
        wx.ProgressDialog.__init__(self, title, message, **kwargs)
        self._workDone = 0
        self.workmax = kwargs["maximum"]

    def workDone(self, delta, newmsg):
        """
        """
        self._workDone += delta
        self.Update(self._workDone, newmsg)

    def finish(self):
        """
        """
        self.Update(self.workmax, "Done!")

####################
# BACKEND DECODING #
####################

class OOMMFSelectiveTarget(wx.FileDropTarget):
    """
    """
    def __init__(self, parent):
        wx.FileDropTarget.__init__(self)
        self.parent = parent

    def OnDropFiles(self, x, y, filenames):
        """
        """
        oommf = filterOnExtensions(["omf", "ovf", "oef", "ohf"], filenames)
        if not oommf or not (self.parent.doNumpy.GetValue() or self.parent.doMATLAB.GetValue()):
            return 0 #You got dropped some bad files!
        global LASTPATH
        LASTPATH = os.path.dirname(oommf[0])
        arrays, headers, extra = self.groupUnpack(oommf,
                                             SupportDialog("Decode in Progress",
                                                           "Decoding...",
                                                           maximum=len(oommf)))

        #One final step before we're done - let's try to sort based on the sim time
        #using a standard decorate-sort-undecorate, with a twist for the variable number of keys

        #Let's start by finding the original indices - making a copy is key

        arrays, extra = oommfdecode.sortBySimTime(extra, arrays)

        self.parent.gatherData(arrays, headers, extra)
        return 1


    def groupUnpack(self, targetlist, progdialog=None):
        """
        """
        try:
            (decodedArrays, headers, extraData) = oommfdecode.groupUnpack(targetlist)
            if progdialog:
                progdialog.workDone(1, "Decoding...")
                time.sleep(0.01) #Should facilitate redraw thread coming to life
        except Exception as e:
            if progdialog: progdialog.finish()
            wx.MessageBox('Unpacking error: ' + repr(e), "Error")
            print(e)
        else:
            if progdialog: progdialog.finish()
        return (decodedArrays, headers, extraData)

########
# MAIN #
########
if __name__ == "__main__":
    BigBoss = MainFrame()
    app.MainLoop()