In [6]:
import numpy as np
import matplotlib.pyplot as plt
import re
import struct

NUMPAT = '[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?'

In [2]:
def run(x, y, filenames):
    global LASTPATH
    LASTPATH = os.path.dirname(filenames[0])
    arrays, headers, extra = groupUnpack(filenames)

    #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
    originalTimeIndex = list(extra["SimTime"])
    if len(set(extra["MIFSource"])) == 1:
        if not -1 in extra["SimTime"]:
            extra["SimTime"], arrays = zip(*sorted(zip(originalTimeIndex, arrays)))
            #Sadly, the cleverness ends here - the rest must be bruteforced.
            for key in extra:
                if not key == "SimTime": #We did that one.
                    junk, extra[key] = zip(*sorted(zip(originalTimeIndex, extra[key])))
    gatherData(arrays, headers, extra)

def groupUnpack(targetlist):
    progdialog = None
    decodedArrays = []
    headers = {}
    extraData = defaultdict(list)
    firstTime = True
    for target in targetlist:
        collect = unpackFile(target)
        if firstTime:
            firstTime = False
            headers = collect[1]
        decodedArrays.append(collect[0])
        #Unpack extra collected data
        for key, value in collect[2].iteritems():
            extraData[key].append(value)
    return (np.array(decodedArrays), headers, extraData)

def unpackFile(filename):
    with open(filename, 'rb') as f:
        headers = {} #I know valuemultiplier isn't always present. This is checked later.
        extraCaptures = {'SimTime':-1, 'Iteration':-1, 'Stage':-1, "MIFSource":""}
        #Parse headers
        a = ""
        while not "Begin: Data" in a:
            a = f.readline().strip()
            #Determine if it's actually something we need as header data
            for key in ["xbase", "ybase", "zbase", "xstepsize", "ystepsize", "zstepsize", "xnodes", "ynodes", "znodes", "valuemultiplier"]:
                if key in a:
                    headers[key] = float(a.split()[2]) #Known position FTW
            #All right, it may also be time data, which we should capture
            if "Total simulation time" in a:
                #Split on the colon to get the time with units; strip spaces and split on the space to separate time and units
                #Finally, pluck out the time, stripping defensively (which should be unnecessary).
                extraCaptures['SimTime'] = float(a.split(":")[-1].strip().split()[0].strip())
            if "Iteration:" in a:
                #Another tricky split...
                extraCaptures['Iteration'] = float(a.split(":")[2].split(",")[0].strip())
            if "Stage:" in a:
                extraCaptures['Stage'] = float(a.split(":")[2].split(",")[0].strip())
            if "MIF source file" in a:
                extraCaptures['MIFSource'] = a.split(":",2)[2].strip()


        #Initialize array to be populated
        outArray = np.zeros((int(headers["xnodes"]),
                             int(headers["ynodes"]),
                             int(headers["znodes"]),
                             3))

        #Determine decoding mode and use that to populate the array
        decode = a.split()
        if decode[3] == "Text":
            return _textDecode(f, outArray, headers, extraCaptures)
        elif decode[3] == "Binary" and decode[4] == "4":
            #Determine endianness
            endianflag = f.read(4)
            if struct.unpack(">f", endianflag)[0] == 1234567.0:
                dc = struct.Struct(">f")
            elif struct.unpack("<f", endianflag)[0] == 1234567.0:
                dc = struct.Struct("<f")
            else:
                raise Exception("Can't decode 4-byte byte order mark: " + hex(endianflag))
            return _binaryDecode(f, 4, dc, outArray, headers, extraCaptures)
        elif decode[3] == "Binary" and decode[4] == "8":
            #Determine endianness
            endianflag = f.read(8)
            if struct.unpack(">d", endianflag)[0] == 123456789012345.0:
                dc = struct.Struct(">d")
            elif struct.unpack("<d", endianflag)[0] == 123456789012345.0:
                dc = struct.Struct("<d")
            else:
                raise Exception("Can't decode 8-byte byte order mark: " + hex(endianflag))
            return _binaryDecode(f, 8, dc, outArray, headers, extraCaptures)
        else:
            raise Exception("Unknown OOMMF data format:" + decode[3] + " " + decode[4])



def _textDecode(filehandle, targetarray, headers, extraCaptures):
    valm = headers.get("valuemultiplier",1)
    for k in range(int(headers["znodes"])):
        for j in range(int(headers["ynodes"])):
            for i in range(int(headers["xnodes"])):
                #numpy is fantastic - splice in a tuple
                text = filehandle.readline().strip().split()
                targetarray[i,j,k] = (float(text[0])*valm, float(text[1])*valm, float(text[2])*valm)
    return (targetarray, headers, extraCaptures)


def _binaryDecode(filehandle, chunksize, decoder, targetarray, headers, extraCaptures):
    valm = headers.get("valuemultiplier",1)
    for k in range(int(headers["znodes"])):
        for j in range(int(headers["ynodes"])):
            for i in range(int(headers["xnodes"])):
                for coord in range(3): #Slowly populate, coordinate by coordinate
                    targetarray[i,j,k,coord] = decoder.unpack(filehandle.read(chunksize))[0] * valm
    return (targetarray, headers, extraCaptures)

def pickleArray(array, headers, extraCaptures, filename):
    temp = dict(headers)
    temp.update(extraCaptures)
    f = open(filename,'w')
    pickle.dump((array,temp), f)
    f.close()

def matlabifyArray(array, headers, extraCaptures, filename):
    GridSize = np.array([float(headers["xstepsize"]), float(headers["ystepsize"]), float(headers["zstepsize"])])
    OutDict = {"OOMMFData":array, "GridSize":GridSize}
    OutDict.update(extraCaptures)
    spio.savemat(filename, OutDict)

def slowlyPainfullyMaximize(filenames):
    """
    This is a special utility function used by OOMMFConvert to find the single largest-magnitude
    vector in a set of vector files
    """
    #There is no nice way to do this.
    def mag(a, b, c):
        return np.sqrt(a**2 + b**2 + c**2)
    maxmag = 0

    for filename in filenames:
        thisArray, headers, extraCaps = unpackFile(filename)
        for k in range(int(headers["znodes"])):
            for j in range(int(headers["ynodes"])):
                for i in range(int(headers["xnodes"])):
                    maxmag = max(maxmag, mag(*thisArray[i,j,k]))
    return maxmag

In [31]:
def unpackFile(filename):
    with open(filename, 'rb') as f:
        headers = {}
        extraCaptures = {'SimTime':-1, 'Iteration':-1, 'Stage':-1, "MIFSource":""}
        
        #Parse headers
        a = ""
        while not "Begin: Data" in a:
            a = str(f.readline().strip())
            #Determine if it's actually something we need as header data
            for key in ["xbase", "ybase", "zbase", "xstepsize", "ystepsize", "zstepsize", "xnodes", "ynodes", "znodes", "valuemultiplier"]:
                if str(key) in a:
                    headers[key] = float(re.search("({})".format(NUMPAT), a).groups()[0])

        #Initialize array to be populated
        outArray = np.zeros((int(headers["xnodes"]),
                             int(headers["ynodes"]),
                             int(headers["znodes"]),
                             3))

        #Determine decoding mode and use that to populate the array
        decode = a.split()
        if decode[3] == "Text":
            return _textDecode(f, outArray, headers, extraCaptures)
        elif decode[3] == "Binary" and decode[4][0] == "4":
            #Determine endianness
            endianflag = f.read(4)
            if struct.unpack(">f", endianflag)[0] == 1234567.0:
                dc = struct.Struct(">f")
            elif struct.unpack("<f", endianflag)[0] == 1234567.0:
                dc = struct.Struct("<f")
            else:
                raise Exception("Can't decode 4-byte byte order mark: " + hex(endianflag))
            return _binaryDecode(f, 4, dc, outArray, headers, extraCaptures)
        elif decode[3] == "Binary" and decode[4] == "8":
            #Determine endianness
            endianflag = f.read(8)
            if struct.unpack(">d", endianflag)[0] == 123456789012345.0:
                dc = struct.Struct(">d")
            elif struct.unpack("<d", endianflag)[0] == 123456789012345.0:
                dc = struct.Struct("<d")
            else:
                raise Exception("Can't decode 8-byte byte order mark: " + hex(endianflag))
            return _binaryDecode(f, 8, dc, outArray, headers, extraCaptures)
        else:
            raise Exception("Unknown OOMMF data format:" + decode[3] + " " + decode[4])



def _textDecode(filehandle, targetarray, headers, extraCaptures):
    valm = headers.get("valuemultiplier",1)
    for k in range(int(headers["znodes"])):
        for j in range(int(headers["ynodes"])):
            for i in range(int(headers["xnodes"])):
                #numpy is fantastic - splice in a tuple
                text = filehandle.readline().strip().split()
                targetarray[i,j,k] = (float(text[0])*valm, float(text[1])*valm, float(text[2])*valm)
    return (targetarray, headers, extraCaptures)


def _binaryDecode(filehandle, chunksize, decoder, targetarray, headers, extraCaptures):
    valm = headers.get("valuemultiplier",1)
    for k in range(int(headers["znodes"])):
        for j in range(int(headers["ynodes"])):
            for i in range(int(headers["xnodes"])):
                for coord in range(3): #Slowly populate, coordinate by coordinate
                    targetarray[i,j,k,coord] = decoder.unpack(filehandle.read(chunksize))[0] * valm
    return (targetarray, headers, extraCaptures)

In [32]:
filename = rb"G:\box\jjirwin\Box Sync\mumax3_output\julian_irwin\save\Ni_pmn-pt_simulations_171214\13_vary_Ku_seed=283634\Ku=0.0\m000046.ovf"

data = unpackFile(filename)

In [11]:
import matplotlib.pyplot

In [12]:
%matplotlib inline

In [26]:
m = data[0].squeeze()

In [28]:
fig, ax = plt.subplots()
ax.imshow(m[:,:,2])
plt.show()



In [ ]:
f