import oommfc as oc
import discretisedfield as df
%matplotlib inline

# Define macro spin mesh (i.e. one discretisation cell).
p1 = (0, 0, 0)  # first point of the mesh domain (m)
p2 = (1e-9, 1e-9, 1e-9)  # second point of the mesh domain (m)
cell = (1e-9, 1e-9, 1e-9)  # discretisation cell size (m)
mesh = oc.Mesh(p1=p1, p2=p2, cell=cell)

"""
Explanation: Tutorial 3 - Dynamics
The dynamics of magnetisation field $\mathbf{m}$ is governed by the Landau-Lifshitz-Gilbert (LLG) equation
$$\frac{d\mathbf{m}}{dt} = \underbrace{-\gamma_{0}(\mathbf{m} \times \mathbf{H}\text{eff})}\text{precession} + \underbrace{\alpha\left(\mathbf{m} \times \frac{d\mathbf{m}}{dt}\right)}_\text{damping},$$
where $\gamma_{0}$ is the gyromagnetic ratio, $\alpha$ is the Gilbert damping, and $\mathbf{H}_\text{eff}$ is the effective field. It consists of two terms: precession and damping. In this exercise, we will explore some basic properties of this equation to understand how to define it in simulations.
We will study the simplest "zero-dimensional" case - macrospin. In the first step, after we import necessary modules (oommfc and discretisedfield), we create the mesh which consists of a single finite difference cell.
End of explanation
"""


system = oc.System(name="macrospin")

"""
Explanation: Now, we can create a micromagnetic system object.
End of explanation
"""


H = (0, 0, 2e6)  # external magnetic field (A/m)
system.hamiltonian = oc.Zeeman(H=H)

"""
Explanation: Let us assume we have a simple Hamiltonian which consists of only Zeeman energy term
$$\mathcal{H} = -\mu_{0}M_\text{s}\mathbf{m}\cdot\mathbf{H},$$
where $M_\text{s}$ is the saturation magnetisation, $\mu_{0}$ is the magnetic constant, and $\mathbf{H}$ is the external magnetic field. For more information on defining micromagnetic Hamiltonians, please refer to the Hamiltonian tutorial. We apply the external magnetic field with magnitude $H = 2 \times 10^{6} \,\text{A}\,\text{m}^{-1}$ in the positive $z$ direction.
End of explanation
"""


gamma = 2.211e5  # gyromagnetic ratio (m/As)
alpha = 0.1  # Gilbert damping

system.dynamics = oc.Precession(gamma=gamma) + oc.Damping(alpha=alpha)

"""
Explanation: In the next step we can define the system's dynamics. Let us assume we have $\gamma_{0} = 2.211 \times 10^{5} \,\text{m}\,\text{A}^{-1}\,\text{s}^{-1}$ and $\alpha=0.1$.
End of explanation
"""


system.dynamics

"""
Explanation: To check what is our dynamics equation:
End of explanation
"""


initial_m = (1, 0, 0)  # vector in x direction
Ms = 8e6  # magnetisation saturation (A/m)

system.m = df.Field(mesh, value=initial_m, norm=Ms)

"""
Explanation: Before we start running time evolution simulations, we need to initialise the magnetisation. In this case, our magnetisation is pointing in the positive $x$ direction with $M_\text{s} = 8 \times 10^{6} \,\text{A}\,\text{m}^{-1}$. The magnetisation is defined using Field class from the discretisedfield package we imported earlier.
End of explanation
"""


td = oc.TimeDriver()

td.drive(system, t=0.1e-9, n=200)

"""
Explanation: Now, we can run the time evolution using TimeDriver for $t=0.1 \,\text{ns}$ and save the magnetisation configuration in $n=200$ steps.
End of explanation
"""


system.dt

"""
Explanation: How different system parameters vary with time, we can inspect by showing the system's datatable.
End of explanation
"""


system.dt.plot("t", "mz");

"""
Explanation: However, in our case it is much more informative if we plot the time evolution of magnetisation $z$ component $m_{z}(t)$.
End of explanation
"""


system.dt.plot("t", ["mx", "my", "mz"]);

"""
Explanation: Similarly, we can plot all three magnetisation components
End of explanation
"""


system.dynamics.damping.alpha = 0.2
system.m = df.Field(mesh, value=initial_m, norm=Ms)

td.drive(system, t=0.1e-9, n=200)

system.dt.plot("t", ["mx", "my", "mz"]);

"""
Explanation: We can see that after some time the macrospin aligns parallel to the external magnetic field in the $z$ direction. We can explore the effect of Gilbert damping $\alpha = 0.2$ on the magnetisation dynamics.
End of explanation
"""


# insert missing code here.
system.m = df.Field(mesh, value=initial_m, norm=Ms)

td.drive(system, t=0.1e-9, n=200)

system.dt.plot("t", ["mx", "my", "mz"]);

"""
Explanation: Exercise 1
By looking at the previous example, explore the magnetisation dynamics for $\alpha=0.005$ in the following code cell.
End of explanation
"""


# insert missing code here.
system.m = df.Field(mesh, value=initial_m, norm=Ms)

td.drive(system, t=0.1e-9, n=200)

system.dt.plot("t", ["mx", "my", "mz"]);

"""
Explanation: Exercise 2
Repeat the simulation with $\alpha=0.1$ and H = (0, 0, -2e6).
End of explanation
"""


system.hamiltonian.zeeman.H = (0, -1.41e6, -1.41e6)

td.drive(system, t=0.1e-9, n=200)

system.dt.plot("t", ["mx", "my", "mz"]);

"""
Explanation: Exercise 3
Keep using $\alpha=0.1$. 
Change the field from H = (0, 0, -2e6) to H = (0, -1.41e6, -1.41e6), and plot
$m_x(t)$, $m_y(t)$ and $m_z(t)$ as above. Can you explain the (initially non-intuitive) output?
End of explanation
"""


