# MIF 2.1
# MIF Example File: sample2.mif
# Description: Runge-Kutta evolver and a rotating applied field.
#     Same geometry as sample.mif, but illustrating several more
#     complex features of the MIF 2.x problem description format.

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

RandomSeed 1

Parameter cellsize 5e-9

# Select initial magnetization configuration.  m0script should
# be the name of an m0 initialization proc including default
# parameters, if any.  Valid settings include:
#   FourDomain
#   SineSpin 5
#   UpDownSpin
Parameter m0script FourDomain
set m0scriptargs relpt
if {[string compare FourDomain $m0script]==0} {
   set m0scriptargs {relpt span}
}

Specify Oxs_BoxAtlas:atlas {
  xrange {1e-9 201e-9}
  yrange {0 100e-9}
  zrange {-1e-9 19e-9}
}

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

Specify Oxs_PlaneRandomVectorField:axis1 [subst {
   min_norm 1.0
   max_norm 1.0
   plane_normal {0 0 1}
   cache_grid :mesh
}]

Specify Oxs_CubicAnisotropy {
  K1  -4.5e3
  axis1 :axis1
  axis2 { Oxs_PlaneRandomVectorField {
     min_norm 1.0
     max_norm 1.0
     plane_normal :axis1
     cache_grid :mesh
  }}
}

Specify Oxs_UniformExchange {
  A  9e-12
}

Specify Oxs_TransformZeeman  [subst {
  multiplier [expr {0.001/$mu0}]
  type general
  script {Rotate 1e9}
  field {0 10 0}
}]

Specify Oxs_Demag {}

Specify Oxs_RungeKuttaEvolve:evolve {}

Specify Oxs_TimeDriver [subst {
 basename sample2
 evolver :evolve
 stopping_time 1e-9
 stage_count 10
 mesh :mesh
 Ms 490e3
 m0 { Oxs_ScriptVectorField {
    atlas :atlas
    script  [list $m0script]
    script_args [list $m0scriptargs]
    norm  1
 } }
}]

proc UpDownSpin { x y z } {
    if { $x < 0.45 } {
        return "0 1 0"
    } elseif { $x > 0.55 } {
        return "0 -1 0"
    } else {
        return "0 0 1"
    }
}

proc SineSpin { freq x y z } {
    global pi
    set ang [expr {2*$x*$pi*$freq}]
    set vx [expr {sin($ang)}]
    set vy [expr {cos($ang)}]
    set vz 0
    return "$vx $vy $vz"
}

proc FourDomain { x y z xrange yrange zrange } {
    set x [expr {$x*$xrange}]
    set y [expr {$y*$yrange}]
    set halfang 0.70710678
    if {$xrange>=$yrange} {
	# Part width larger than height
	set matcherror [expr {$xrange/65536.0}]
	if {$x<0.5*($yrange-$matcherror)} {
	    if {abs($y-$x)<$matcherror} {
		return "$halfang -$halfang 0"
	    } elseif {abs($x+$y-$yrange)<$matcherror} {
		return "-$halfang -$halfang 0"
	    } elseif {$y<$x} {
		return "1 0 0"
	    } elseif {$y>$yrange-$x} {
		return "-1 0 0"
	    } else {
		return "0 -1 0"
	    }
	} elseif {$xrange-0.5*($yrange-$matcherror)<$x} {
	    if {abs($y+$x-$xrange)<$matcherror} {
		return "$halfang $halfang 0"
	    } elseif {abs($y-$yrange+$xrange-$x)<$matcherror} {
		return "-$halfang $halfang 0"
	    } elseif {$y<$xrange-$x} {
		return "1 0 0"
	    } elseif {$y>$x-$xrange+$yrange} {
		return "-1 0 0"
	    } else {
		return "0 1 0"
	    }
	} else {
	    if {abs($y-0.5*$yrange)<$matcherror} {
		return "0 0 1"   ;# Arbitrarily pick +z
	    } elseif {$y<0.5*$yrange} {
		return "1 0 0"
	    } else {
		return "-1 0 0"
	    }
	}
    } else {
	# Part height larger than width
	set matcherror [expr {$yrange/65536.0}]
	if {$y<0.5*($xrange-$matcherror)} {
	    if {abs($x-$y)<$matcherror} {
		return "$halfang -$halfang 0"
	    } elseif {abs($y+$x-$xrange)<$matcherror} {
		return "$halfang $halfang 0"
	    } elseif {$x<$y} {
		return "0 -1 0"
	    } elseif {$x>$xrange-$y} {
		return "0 1 0"
	    } else {
		return "1 0 0"
	    }
	} elseif {$yrange-0.5*($xrange-$matcherror)<$y} {
	    if {abs($x+$y-$yrange)<$matcherror} {
		return "-$halfang -$halfang 0"
	    } elseif {abs($x-$xrange+$yrange-$y)<$matcherror} {
		return "-$halfang $halfang 0"
	    } elseif {$x<$yrange-$y} {
		return "0 -1 0"
	    } elseif {$x>$y-$yrange+$xrange} {
		return "0 1 0"
	    } else {
		return "-1 0 0"
	    }
	} else {
	    if {abs($x-0.5*$xrange)<$matcherror} {
		return "0 0 1"   ;# Arbitrarily pick +z
	    } elseif {$x<0.5*$xrange} {
		return "0 -1 0"
	    } else {
		return "0 1 0"
	    }
	}
    }
}

set TWOPI [expr {8*atan(1.)}]

proc Rotate { freq stage stagetime totaltime } {
   global TWOPI
   set w [expr {$freq*$TWOPI}]
   set ct [expr {cos($w*$totaltime)}]
   set mct [expr {-1*$ct}]
   set st [expr {sin($w*$totaltime)}]
   set mst [expr {-1*$st}]
   return [list  $ct $mst  0 \
                 $st $ct   0 \
                        0                0         1 \
                 [expr {$w*$mst}] [expr {$w*$mct}] 0 \
                 [expr {$w*$ct}]  [expr {$w*$mst}] 0 \
                        0                0         0]
}
