# This file is automatically generated by hotspin-apigen. DO NOT EDIT.


import os
import json
import sys
import socket


m_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
initialized = 0
outputdir = ""
M_ADDR = ""
M_HOST, M_PORT = "", 0

# Initializes the communication with mumax2.
# @note Internal use only


def init():
    global outputdir
    global m_sock
    global initialized
    global M_HOST
    global M_PORT

    # get the output directory from environment
    outputdir = os.environ["HOTSPIN_OUTPUTDIR"] + "/"
    M_ADDR = os.environ["HOTSPIN_ADDR"]

    print 'MuMax grants connection on: ' + M_ADDR

    m_name = M_ADDR.split(':')
    M_HOST = m_name[0]
    M_PORT = int(m_name[1])

    m_sock.connect((M_HOST, M_PORT))
    initialized = 1

#	print 'python frontend is initialized'

# Calls a mumax2 command and returns the result as string.
# @note Internal use only.


def call(command, args):
    if (initialized == 0):
        init()
    m_sock.sendall(json.dumps([command, args]) + '\n')
    resp = recvall(m_sock)
    return json.loads(resp)

End = '<<< End of mumax message >>>'

# Retrieving message until the EOM statement
# @note Internal use only.


def recvall(the_socket):
    total_data = []
    data = ''
    while True:
        data = the_socket.recv(8192)
        if data == '':
            sys.exit(1)
        if End in data:
            total_data.append(data[:data.find(End)])
            break
        total_data.append(data)
        if len(total_data) > 1:
            # check if end_of_data was split
            last_pair = total_data[-2] + total_data[-1]
            if End in last_pair:
                total_data[-2] = last_pair[:last_pair.find(End)]
                total_data.pop()
                break
    return ''.join(total_data)
		


##  Add a new quantity to the multi-physics engine, its
#  value is added to the (existing) sumQuantity.
#  E.g.: Add_To("H", "H_1") adds a new external field
#  H_1 that will be added to H.
def add_to(sumQuantity, newQuantity):
    ret = call("add_to", [sumQuantity, newQuantity])
    return 

def add_to_weighted(sumQuantity, newQuantity, weight):
    ret = call("add_to_weighted", [sumQuantity, newQuantity, weight])
    return 

def adddeltaquant(src, ref):
    ret = call("adddeltaquant", [src, ref])
    return 

##  Saves a space-dependent quantity periodically, every period (expressed in seconds).
#  Output appears in the output directory with automatically generated file names.
#  E.g., for a quantity named "m", and format "txt" the generated files will be:
# 	m00000.txt m00001.txt m00002.txt...
#  See FilenameFormat() for setting the number of zeros.
#  Returns an integer handle that can be used to manipulate the auto-save entry.
#  E.g. remove(handle) stops auto-saving it.
#  @see filenumberfomat
def autosave(quantity, format, options, period):
    ret = call("autosave", [quantity, format, options, period])
    return int(ret[0])

##  Saves any number of space-independent quantities periodically,
#  every period (expressed in seconds).
#  The values are appended to the file.
#  Returns an integer handle that can be used to manipulate the auto-save entry.
#  E.g. remove(handle) stops auto-saving it.
def autotabulate(quantities, filename, period):
    ret = call("autotabulate", [quantities, filename, period])
    return int(ret[0])

##  DEBUG: removes the updater of this quantity
def debug_disableupdate(quantity):
    ret = call("debug_disableupdate", [quantity])
    return 

def debug_gc():
    ret = call("debug_gc", [])
    return 

##  FOR DEBUG ONLY.
#  Gets the quantity's array, raw.
def debug_getarray(quant):
    ret = call("debug_getarray", [quant])
    return (ret[0])

##  DEBUG: manually update the quantity state
def debug_invalidate(quantity):
    ret = call("debug_invalidate", [quantity])
    return 

##  DEBUG: manually update the quantity state
def debug_update(quantity):
    ret = call("debug_update", [quantity])
    return 

##  DEBUG: verify all quanties' values
def debug_verifyall():
    ret = call("debug_verifyall", [])
    return 

##  DEBUG: does not update
def debugfield(quantity):
    ret = call("debugfield", [quantity])
    return (ret[0])

##  DEBUG: Does not update.
def debugv(quantity):
    ret = call("debugv", [quantity])
    return (ret[0])

##  DEBUG: echos a string, can be used for synchronous output
def echo(str):
    ret = call("echo", [str])
    return 

##  Sets a global C-style printf format string used to generate file names for automatically saved files.
#  The default "%!d(MISSING)" generates, e.g., "m000001.txt". "%!d(MISSING)" would generate, e.g., "m1.txt".
def filenumberformat(format):
    ret = call("filenumberformat", [format])
    return 

##  Gets a space-dependent quantity. If the quantity uses a mask,
#  the result is equal to GetMask() * GetValue()
def getarray(quantity):
    ret = call("getarray", [quantity])
    return (ret[0])

##  Gets the value of the quantity at cell position x,y,z
def getcell(quant, x, y, z):
    ret = call("getcell", [quant, x, y, z])
    return (ret[0])

##  Get the cell size.
#  WARNING: convert to ZYX, internal units
def getcellsize():
    ret = call("getcellsize", [])
    return float(ret[0]), float(ret[1]), float(ret[2])

##  Get the grid size.
#  WARNING: convert to ZYX
def getgridsize():
    ret = call("getgridsize", [])
    return int(ret[0]), int(ret[1]), int(ret[2])

##  Gets a space-dependent quantity. If the quantity uses a mask,
#  the result is equal to GetMask() * GetValue()
def getmask(quantity):
    ret = call("getmask", [quantity])
    return (ret[0])

##  Get the periodicity
#  WARNING: convert to ZYX, internal units
def getperiodic():
    ret = call("getperiodic", [])
    return int(ret[0]), int(ret[1]), int(ret[2])

##  Get the value of a scalar, space-independent quantity.
#  Similar to GetValue, but returns a single number.
def gets(quantity):
    ret = call("gets", [quantity])
    return float(ret[0])

##  DEBUG: Gets the time, in seconds, recorded by the timer with this tag.
def gettime(tag):
    ret = call("gettime", [tag])
    return float(ret[0])

##  Get the value of a space-independent or masked quantity.
#  Returns an array with vector components or an
#  array with just one element in case of a scalar quantity.
def getv(quantity):
    ret = call("getv", [quantity])
    return (ret[0])

##  Get the toal size, in meters, of the simulated world.
def getworldsize():
    ret = call("getworldsize", [])
    return float(ret[0]), float(ret[1]), float(ret[2])

##  Load a physics module.
def load(name):
    ret = call("load", [name])
    return 

##  Load a physics module with user-defined variables.
def loadargs(name, ins, deps, outs):
    ret = call("loadargs", [name, ins, deps, outs])
    return 

##  Add a new quantity to the multi-physics engine, its
#  value is the maximum of the absolute value of inputQuantity.
#  E.g.: New_MaxAbs("max_torque", "torque") adds a new quantity
#  "max_torque" whose value is max(abs(torque)). For vector
#  quantities, the maximum is taken over all components.
def new_maxabs(newQuantity, inputQuantity):
    ret = call("new_maxabs", [newQuantity, inputQuantity])
    return 

##  Add a new quantity to the multi-physics engine, its
#  value is the maximum norm of inputQuantity (a 3-component vector).
#  E.g.: New_MaxNorm("maxnorm_torque", "torque") adds a new quantity
#  "maxnorm_torque" whose value is max(norm(torque)).
def new_maxnorm(newQuantity, inputQuantity):
    ret = call("new_maxnorm", [newQuantity, inputQuantity])
    return 

def new_peak(newQuantity, inputQuantity):
    ret = call("new_peak", [newQuantity, inputQuantity])
    return 

##  Returns the output directory for the running simulation.
def outputdirectory():
    ret = call("outputdirectory", [])
    return str(ret[0])

##  Returns the output ID corresponding to the current simulation time.
#  All automatic output uses this number to identify the time corresponding
#  to the saved quantity.
def outputid():
    ret = call("outputid", [])
    return int(ret[0])

##  DEBUG
def printstats():
    ret = call("printstats", [])
    return 

##  DEBUG: reads an array from a file.
def readfile(filename):
    ret = call("readfile", [filename])
    return (ret[0])

def recoverstate(dst, src):
    ret = call("recoverstate", [dst, src])
    return 

##  Removes the object with given handle.
#  E.g.:
# 	handle = autosave(...)
# 	remove(handle) # stops auto-saving
def remove(handle):
    ret = call("remove", [handle])
    return 

##  DEBUG: Resets the timer with this tag.
def resettimer(tag):
    ret = call("resettimer", [tag])
    return 

##  Runs for a duration given in seconds.
#  TODO: precise stopping time
def run(duration):
    ret = call("run", [duration])
    return 

##  Runs the simulation until quantity a > quantity b
def run_until_larger(quantity, value):
    ret = call("run_until_larger", [quantity, value])
    return 

##  Runs the simulation until quantity a < value
def run_until_smaller(quantity, value):
    ret = call("run_until_smaller", [quantity, value])
    return 

##  Saves a space-dependent quantity, once. Uses the specified format and gives an automatic file name (like "m000001.png").
#  See also: Save()
def save(quantity, format, options):
    ret = call("save", [quantity, format, options])
    return 

##  Saves a space-dependent quantity, once. Uses the specified format and file name.
def saveas(quantity, format, options, filename):
    ret = call("saveas", [quantity, format, options, filename])
    return 

##  Saves an image file of the physics graph using the given file name.
#  The extension determines the output format. E.g.: .png, .svg, ...
#  A file with a .dot extension will be written as well.
#  Rendering requires the package "graphviz" to be installed.
def savegraph(file):
    ret = call("savegraph", [file])
    return 

def savestate(dst, src):
    ret = call("savestate", [dst, src])
    return 

##  Sets a space-dependent field quantity, like the magnetization.
def setarray(quantity, field):
    ret = call("setarray", [quantity, field])
    return 

##  Like SetArray but reads the array from a file.
def setarray_file(quantity, filename):
    ret = call("setarray_file", [quantity, filename])
    return 

##  Sets the value of the quantity at cell position x,y,z
def setcell(quant, x, y, z, value):
    ret = call("setcell", [quant, x, y, z, value])
    return 

##  Set the cell size.
#  WARNING: convert to ZYX
def setcellsize(x, y, z):
    ret = call("setcellsize", [x, y, z])
    return 

##  Set the grid size.
#  WARNING: convert to ZYX
def setgridsize(x, y, z):
    ret = call("setgridsize", [x, y, z])
    return 

##  Sets a space-dependent multiplier mask for the quantity.
#  The value of the quantity (set by SetValue), will be multiplied
#  by the mask value in each point of space. The mask is dimensionless
#  and typically contains values between 0 and 1.
def setmask(quantity, mask):
    ret = call("setmask", [quantity, mask])
    return 

##  Like SetMask but reads the mask from a file.
def setmask_file(quantity, filename):
    ret = call("setmask_file", [quantity, filename])
    return 

##  Set periodic boundary conditions in each direction.
#  A value of 0 means no periodicity in that direction (the default).
#  A nonzero value means the system is infinitely reproduced in that direction.
#  The magnitude of the nonzero value is a hint of how accurately the
#  infinite character should be approached, if applicable.
#  E.g.: for the ferromagnetic exchange interaction,
#  any nonzero value will give the same result: perfect infinite periodicity.
#  But for the magnetostatic interaction, the magnitude of the nonzero value
#  may be used as a hint where to cut off the magnetic field.
def setperiodic(x, y, z):
    ret = call("setperiodic", [x, y, z])
    return 

##  Set scalar. Convenience method for SetValue() with only one number.
#  REDUNDANT?
def sets(quantity, value):
    ret = call("sets", [quantity, value])
    return 

##  Set value of a quantity. The quantity must be of type VALUE or MASK.
#  If the quantity is a MASK, the value will be multiplied by a space-dependent mask
#  which typically contains dimensionless numbers between 0 and 1.
def setv(quantity, value):
    ret = call("setv", [quantity, value])
    return 

def setvmap(yName, xName, yValue, xValue):
    ret = call("setvmap", [yName, xName, yValue, xValue])
    return 

##  DEBUG: start a timer with a given identifier tag
def starttimer(tag):
    ret = call("starttimer", [tag])
    return 

##  Take one solver step
def step():
    ret = call("step", [])
    return 

##  Takes N solver steps
def steps(N):
    ret = call("steps", [N])
    return 

##  DEBUG: stop a timer with a given identifier tag.
#  It must be started first.
def stoptimer(tag):
    ret = call("stoptimer", [tag])
    return 

##  Should be called at the end of each input file to make
#  sure the input script does not terminate too early.
def sync():
    ret = call("sync", [])
    return 

##  Saves these space-independent quantities, once.
#  Their values are appended to the file, on one line.
def tabulate(quantities, filename):
    ret = call("tabulate", [quantities, filename])
    return 

##  Gets the quantities unit.
def unit(quantity):
    ret = call("unit", [quantity])
    return str(ret[0])


## Permeability of vacuum in J/Am2
mu0    = 1.25663706E-6

## Gyromagnetic ratio in m/As
gamma0 = 2.211E5 

## Boltzmann's constant in J/K
kB     = 1.380650424E-23  

## Bohr magneton in Am^2
muB    = 9.2740091523E-24 

## Electron charge in As
e      = 1.60217646E-19

# Permittivity of vacuum in C/Vm
epsilon0 = 8.854187817620E-12

pi       = 3.14159265358979323846264338327950288

## Makes a 4D array suited for mumax.
# comp: number of components (1:scalar, 3:vector,...). First index ranges over components.
# nx, ny, nz: number of elements in X,Y,Z.
def makearray(comp, Nx, Ny, Nz):
	return [[[[0 for z in range(Nz)] for y in range(Ny)] for x in range(Nx)] for c in range(comp)]
