# MIF 2.1
# MIF Example File: bench3.mif
# Description: Used for benchmarking OOMMF performance.
#              Based on muMAG Problem 3.

set pi [expr {4*atan(1.0)}]
set mu0 [expr {4*$pi*1e-7}]

Parameter sil 10   ;# Stage iteration limit
# After a 3 step warm-up, two stages of length $sil are run
# and reported as DataTable output to mmArchive.

Parameter number_of_stages 2 ;# Number of stages after the
# first, initialization stage.

Parameter evolver cg
switch -exact $evolver {
   cg -
   rk -
   euler {}
   default {
      error "Invalid evolver request: \"$evolver\".\
             Should be one of cg, rk, or euler."
   }
}

Parameter cellsize 32 ;# Cell size in nm

Parameter basename {}

Parameter archive_nickname {}
if {![string match {} $archive_nickname] \
       && ![string match {:*} $archive_nickname]} {
   set archive_nickname ":$archive_nickname"
}

if {[string match {} $basename]} {
   if {[regexp {^[0-9]$} $cellsize]} {
      # Integer value
      set basename [format "bench3-cs%02d" $cellsize]
   } else {
      # Float?
      set basename [format "bench3-cs%g" $cellsize]
   }
}

# ***********************************************************************

########################################################################
# Simulation parameters

set cubesize 512  ;# Cube edge length, in nm; = DIMX = DIMY = DIMZ
set N [expr {$cubesize/$cellsize}]

set L  8.47 ;# Cube dimension, in units of exchange length
set lex [expr {$cubesize/$L}] ;# exchange length

RandomSeed 1
set initial_state "canted" ;# Initial state should be
## one of "uniform", "vortex", "canted", or "random".

########################################################################
# Auxiliary variables:

# Work out Ms so magnetostatic energy density, Km=0.5*mu0*Ms^2,
# is 1e6 J/m^3
set Km 1e6
set Ms [expr {sqrt(2*$Km/$mu0)}]

# Set K1 to 0.1*Km
set K1 [expr {$Km/10.}]

# Compute A so that cubesize is requested number of exchange lengths
set A [expr {0.5*$mu0*$Ms*$Ms*$lex*$lex}] ;# Exchange coefficient, J/m


proc Vortex { x y z } {
   set yrad [expr {2.*$y-1.}]
   set zrad [expr {2.*$z-1.}]
   set normsq [expr {$yrad*$yrad+$zrad*$zrad}]
   if {$normsq <= 0.05} {return "1 0 0"}
   return [list 0.0 $zrad [expr {-1*$yrad}]]
}

switch [string tolower [lindex $initial_state 0]] {
   "uniform" {
      set m0 {0 0 1}
   }
   "vortex" {
      set m0 { Oxs_ScriptVectorField {
         atlas :atlas
         script Vortex
         norm  1.0
      }}
   }
   "canted" {
      set m0 {1 1 1}
   }
   "random" {
      set m0 { Oxs_RandomVectorField {
         min_norm 1.0
         max_norm 1.0
      }}
   }
   default {
      error "Unrecognized initial_state: \"$initial_state\"; should\
             be one of \"uniform\", \"vortex\",  \"canted\",,\
             or \"random\"."
   }
}

Specify Oxs_BoxAtlas:atlas [subst {
  xrange {0 $cubesize}
  yrange {0 $cubesize}
  zrange {0 $cubesize}
}]

Specify Oxs_RectangularMesh:mesh [subst {
  cellsize {$cellsize $cellsize $cellsize}
  atlas :atlas
}]

# Uniaxial anistropy.  K1 should be 0.1*Km, where
# Km = 0.5*mu0*Ms^2.
Specify Oxs_UniaxialAnisotropy [subst {
   K1 $K1
   axis {0 0 1}
}]

# Exchange
Specify Oxs_UniformExchange [subst {
  A  $A
}]

# Demag
Specify Oxs_Demag {}

if {[string match cg $evolver]} {
   set driver Oxs_MinDriver
   Specify Oxs_CGEvolve:evolve {}
} else {
   set driver Oxs_TimeDriver
   if {[string match euler $evolver]} {
      Specify Oxs_EulerEvolve:evolve {}
   } else {
      Specify Oxs_RungeKuttaEvolve:evolve {}
   }
}

Specify $driver [subst {
   basename [list $basename]
   evolver :evolve
   stage_iteration_limit {3 {$sil $number_of_stages} :expand:}
   stage_count [expr {$number_of_stages+1}]
   mesh :mesh
   Ms $Ms
   m0 [list $m0]
   report_wall_time 1
   checkpoint_interval -1
}]

Destination archive mmArchive${archive_nickname}
Schedule DataTable archive Stage 1
