# MIF 2.1
# MIF Example File: stdprob3.mif
# Description: Sample problem description for muMAG Standard Problem #3

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

Parameter seed 0
RandomSeed $seed  ;# Initialize seed to {} to get a seed
## value from the system clock.


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

Parameter L  8.47 ;# Cube dimension, in units of exchange length
Parameter N 32    ;# Number of cells along one edge of cube

Parameter initial_state "random" ;# Initial state should be
## one of "uniform", "vortex", "canted", "cantedvortex", "twisted",
## "random" or "file <filename>"; in the last case <filename> is the
## name of a file to use as the initial configuration.

Parameter stop 1e-3

########################################################################
# 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)}]

# Arbitrarily set cube dimension to 100 nm, and compute cellsize and
# exchange length based on parameters L and N.
set cubesize 100e-9 ;# Cube dimension in meters
set cellsize [expr {$cubesize/$N}] ;# In meters
set lex [expr {$cubesize/$L}] ;# exchange length

# 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

########################################################################

Report "A=$A, K1=$K1, Ms=$Ms, lex=$lex, L=$L, seed=$seed"

########################################################################
# Tcl script for CantedVortex proc
#
# Coordinate transform to select initial vortex orientation:
proc CantedVortexInit { vec } {
   proc Mag { v } {
      set v0  [lindex $v 0]
      set v1  [lindex $v 1]
      set v2  [lindex $v 2]
      return [expr {sqrt($v0*$v0+$v1*$v1+$v2*$v2)}]
   }

   proc Scale { a v } {
      set w0  [expr {$a*[lindex $v 0]}]
      set w1  [expr {$a*[lindex $v 1]}]
      set w2  [expr {$a*[lindex $v 2]}]
      return [list $w0 $w1 $w2]
   }

   proc Normalize { v } {
      set mag [Mag $v]
      return [Scale [expr {1.0/$mag}] $v]
   }

   proc Dot { v w } {
      return [expr {[lindex $v 0]*[lindex $w 0]
                    + [lindex $v 1]*[lindex $w 1]
                    + [lindex $v 2]*[lindex $w 2]}]
   }

   proc Cross { v w } {
      set v0  [lindex $v 0]
      set v1  [lindex $v 1]
      set v2  [lindex $v 2]
      set w0  [lindex $w 0]
      set w1  [lindex $w 1]
      set w2  [lindex $w 2]
      set u0 [expr {$v1*$w2-$v2*$w1}]
      set u1 [expr {$v2*$w0-$v0*$w2}]
      set u2 [expr {$v0*$w1-$v1*$w0}]
      return [list $u0 $u1 $u2]
   }

   set v1 [Normalize $vec] ;# Make unit vector
   set v2 [Cross $v1 [list 1 0 0]]      ;# Construct orthogonal vector
   if {[Mag $v2]<0.5} {
      set v2 [Cross $v1 [list 0 1 0]]
      if {[Mag $v2]<0.5} {
         set v2 [Cross $v1 [list 0 0 1]]
      }
   }
   set v2 [Normalize $v2]
   set v3 [Normalize [Cross $v1 $v2]] ;# Normalize just safety

   global a11 a12 a13 a21 a22 a23 a31 a32 a33
   set a11  [lindex $v2 0]
   set a21  [lindex $v2 1]
   set a31  [lindex $v2 2]
   
   set a12  [lindex $v3 0]
   set a22  [lindex $v3 1]
   set a32  [lindex $v3 2]
   
   set a13  [lindex $v1 0]
   set a23  [lindex $v1 1]
   set a33  [lindex $v1 2]

   proc CantedVortex { x y z } {
      global a11 a12 a13 a21 a22 a23 a31 a32 a33
      set x [expr {$x-0.5}]  ;# Shift origin
      set y [expr {$y-0.5}]
      set z [expr {$z-0.5}]
      set nx [expr {$a11*$x+$a21*$y+$a31*$z}] ;# Rotate, frontside
      set ny [expr {$a12*$x+$a22*$y+$a32*$z}]
      set nz [expr {$a13*$x+$a23*$y+$a33*$z}]
      foreach {nvx nvy nvz} [CantedVortexBaseCompute $nx $ny $nz] {}
      set vx [expr {$a11*$nvx+$a12*$nvy+$a13*$nvz}] ;# Rotate, backside
      set vy [expr {$a21*$nvx+$a22*$nvy+$a23*$nvz}]
      set vz [expr {$a31*$nvx+$a32*$nvy+$a33*$nvz}]
      return [list $vx $vy $vz]
   }

   proc CantedVortexBaseCompute { x y z } {
      set normsq [expr {$x*$x+$y*$y}]
      if {$normsq <= 0.0125} {
         return [list [expr {0.125*rand()}] [expr {0.125*rand()}] 1.0]
      }
      return [list [expr {-1*$y}] $x 0]
   }
}

########################################################################

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}]]
}

proc Twisted { x y z } {
   global pi
   set vx 0
   set vy [expr {sin(($pi/2.)*($x-0.5))}]
   set vz [expr {cos(($pi/2.)*($x-0.5))}]
   return [list $vx $vy $vz]
}

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}
   }
   "cantedvortex" {
      CantedVortexInit [list 1. 1. 1.]
      set m0 { Oxs_ScriptVectorField {
         atlas :atlas
         script CantedVortex
         norm  1.0
      }}
   }
   "twisted" {
      set m0 { Oxs_ScriptVectorField {
         atlas :atlas
         script Twisted
         norm  1.0
      }}
   }
   "random" {
      set m0 { Oxs_RandomVectorField {
         min_norm 1.0
         max_norm 1.0
      }}
   }
   "file" {
      if {[llength $initial_state]!=2} {
         error "Invalid setting for parameter initial_state:\
               \"$initial_state\"; this should be a 2 element\
               list, but has instead has [llength $initital_state]\
               elements."
      }
      set m0 [subst { Oxs_FileVectorField {
         atlas :atlas
         file [list [lindex $initial_state 1]]
         norm 1.0
      }}]
   }
   default {
      error "Unrecognized initial_state: \"$initial_state\"; should\
             be one of \"uniform\", \"vortex\", \"canted\",\
             \"cantedvortex\", \"twisted\", \"random\",\
             or \"file <filename>\"."
   }
}


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 {}

# Evolver
Specify Oxs_CGEvolve {}

# Driver
set basename [format {sp3-%s-seed%04d} $initial_state $seed]
Specify Oxs_MinDriver [subst {
   basename [list $basename]
   evolver Oxs_CGEvolve
   stopping_mxHxm $stop
   mesh :mesh
   Ms $Ms
   m0 [list $m0]
}]

Destination archive mmArchive
Schedule DataTable archive Stage 1
