Skip to content

Commit 22b53e8

Browse files
committed
Merge branch 'feat/adaptive-steps' of github.com:LemurPwned/cmtj into feat/adaptive-steps
2 parents 3556f6c + f655307 commit 22b53e8

File tree

5 files changed

+332
-54
lines changed

5 files changed

+332
-54
lines changed

core/junction.hpp

Lines changed: 118 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ template <typename T = double> class Layer {
143143
// CMTJ Torque & Field drivers
144144
ScalarDriver<T> currentDriver;
145145
ScalarDriver<T> anisotropyDriver, secondOrderAnisotropyDriver;
146-
ScalarDriver<T> fieldLikeTorqueDriver;
147-
ScalarDriver<T> dampingLikeTorqueDriver;
146+
ScalarDriver<T> fieldLikeTorqueDriver, fieldLikeTorqueDriver2;
147+
ScalarDriver<T> dampingLikeTorqueDriver, dampingLikeTorqueDriver2;
148148
AxialDriver<T> externalFieldDriver;
149149
AxialDriver<T> HoeDriver, HdmiDriver;
150150

@@ -207,7 +207,8 @@ template <typename T = double> class Layer {
207207
T thickness = 0.0;
208208
T cellVolume = 0.0, cellSurface = 0.0;
209209

210-
CVector<T> H_log, Hoe_log, Hconst, mag, anis, referenceLayer;
210+
CVector<T> H_log, Hoe_log, Hconst, mag, anis, referenceLayer,
211+
secondaryReferenceLayer;
211212
CVector<T> Hext, Hdipole, Hdemag, Hoe, HAnis, Hthermal, Hfluctuation, Hdmi,
212213
Hidmi;
213214

@@ -413,28 +414,51 @@ template <typename T = double> class Layer {
413414
this->currentDriver = driver;
414415
}
415416

416-
void setFieldLikeTorqueDriver(const ScalarDriver<T> &driver) {
417+
void setTorqueParameters() {
417418
this->includeSOT = true;
418419
if (this->includeSTT)
419420
throw std::runtime_error(
420421
"includeSTT was on and now setting SOT interaction!");
421422
if (!this->dynamicSOT)
422423
throw std::runtime_error(
423424
"used a static SOT definition, now trying to set it dynamically!");
425+
}
426+
427+
void setFieldLikeTorqueDriver(const ScalarDriver<T> &driver) {
428+
setTorqueParameters();
424429
this->fieldLikeTorqueDriver = driver;
425430
}
426431

427432
void setDampingLikeTorqueDriver(const ScalarDriver<T> &driver) {
428-
this->includeSOT = true;
429-
if (this->includeSTT)
430-
throw std::runtime_error(
431-
"includeSTT was on and now setting SOT interaction!");
432-
if (!this->dynamicSOT)
433-
throw std::runtime_error(
434-
"used a static SOT definition, now trying to set it dynamically!");
433+
setTorqueParameters();
435434
this->dampingLikeTorqueDriver = driver;
436435
}
437436

437+
void setSecondaryFieldLikeTorqueDriver(const ScalarDriver<T> &driver) {
438+
setTorqueParameters();
439+
this->fieldLikeTorqueDriver2 = driver;
440+
}
441+
442+
void setSecondaryDampingLikeTorqueDriver(const ScalarDriver<T> &driver) {
443+
setTorqueParameters();
444+
this->dampingLikeTorqueDriver2 = driver;
445+
}
446+
447+
void setPrimaryTorqueDrivers(const ScalarDriver<T> &fieldLikeTorqueDriver,
448+
const ScalarDriver<T> &dampingLikeTorqueDriver) {
449+
setTorqueParameters();
450+
this->fieldLikeTorqueDriver = fieldLikeTorqueDriver;
451+
this->dampingLikeTorqueDriver = dampingLikeTorqueDriver;
452+
}
453+
454+
void
455+
setSecondaryTorqueDrivers(const ScalarDriver<T> &fieldLikeTorqueDriver,
456+
const ScalarDriver<T> &dampingLikeTorqueDriver) {
457+
setTorqueParameters();
458+
this->fieldLikeTorqueDriver2 = fieldLikeTorqueDriver;
459+
this->dampingLikeTorqueDriver2 = dampingLikeTorqueDriver;
460+
}
461+
438462
void setAnisotropyDriver(const ScalarDriver<T> &driver) {
439463
this->anisotropyDriver = driver;
440464
}
@@ -450,12 +474,12 @@ template <typename T = double> class Layer {
450474
this->HoeDriver = driver;
451475
}
452476

453-
void setMagnetisation(CVector<T> &mag) {
454-
if (mag.length() == 0) {
477+
void setMagnetisation(const CVector<T> &newMag) {
478+
if (newMag.length() == 0) {
455479
throw std::runtime_error(
456480
"Initial magnetisation was set to a zero vector!");
457481
}
458-
this->mag = mag;
482+
this->mag = newMag;
459483
this->mag.normalize();
460484
}
461485

@@ -502,6 +526,11 @@ template <typename T = double> class Layer {
502526
this->referenceType = FIXED;
503527
}
504528

529+
void setSecondaryReferenceLayer(const CVector<T> &reference) {
530+
this->secondaryReferenceLayer = reference;
531+
this->referenceType = FIXED;
532+
}
533+
505534
/**
506535
* @brief Set reference layer with enum
507536
* Can be used to refer to other layers in stack as reference
@@ -524,6 +553,10 @@ template <typename T = double> class Layer {
524553
return this->referenceLayer;
525554
}
526555

556+
CVector<T> getSecondaryReferenceLayer() {
557+
return this->secondaryReferenceLayer;
558+
}
559+
527560
/**
528561
* @brief Get the Reference Layer Type object (enum type is returned)
529562
*/
@@ -721,26 +754,49 @@ template <typename T = double> class Layer {
721754
fieldLike * sttTerm * this->beta) *
722755
convTerm;
723756
} else if (this->includeSOT) {
724-
T Hdl, Hfl;
725-
// I log current density
726-
// use SOT formulation with effective DL and FL fields
757+
T Hdl = 0, Hfl = 0, Hdl2 = 0, Hfl2 = 0;
758+
759+
// Get SOT field values - either from drivers or using current
727760
if (this->dynamicSOT) {
728-
// dynamic SOT is set when the driver is present
729761
Hdl = this->dampingLikeTorqueDriver.getCurrentScalarValue(time);
730762
Hfl = this->fieldLikeTorqueDriver.getCurrentScalarValue(time);
763+
Hdl2 = this->dampingLikeTorqueDriver2.getCurrentScalarValue(time);
764+
Hfl2 = this->fieldLikeTorqueDriver2.getCurrentScalarValue(time);
731765
} else {
732766
this->I_log = this->currentDriver.getCurrentScalarValue(time);
733767
Hdl = this->dampingLikeTorque * this->I_log;
734768
Hfl = this->fieldLikeTorque * this->I_log;
735769
}
770+
771+
// Calculate field vectors
736772
this->Hfl_v = reference * (Hfl - this->damping * Hdl);
737773
this->Hdl_v = reference * (Hdl + this->damping * Hfl);
738-
const CVector<T> cm = c_cross<T>(m, reference);
739-
const CVector<T> ccm = c_cross<T>(m, cm);
740-
const CVector<T> flTorque = cm * (Hfl - this->damping * Hdl);
741-
const CVector<T> dlTorque = ccm * (Hdl + this->damping * Hfl);
742-
return (dmdt + flTorque + dlTorque) * -GYRO * convTerm;
774+
const CVector<T> Hfl2_v =
775+
secondaryReferenceLayer * (Hfl2 - this->damping * Hdl2);
776+
const CVector<T> Hdl2_v =
777+
secondaryReferenceLayer * (Hdl2 + this->damping * Hfl2);
778+
779+
// Calculate torques
780+
const CVector<T> cm_primary = c_cross<T>(m, reference);
781+
const CVector<T> ccm_primary = c_cross<T>(m, cm_primary);
782+
const CVector<T> cm_secondary = c_cross<T>(m, secondaryReferenceLayer);
783+
const CVector<T> ccm_secondary = c_cross<T>(m, cm_secondary);
784+
785+
// Primary and secondary torque components
786+
const CVector<T> flTorque_primary =
787+
cm_primary * (Hfl - this->damping * Hdl);
788+
const CVector<T> dlTorque_primary =
789+
ccm_primary * (Hdl + this->damping * Hfl);
790+
const CVector<T> flTorque_secondary =
791+
cm_secondary * (Hfl2 - this->damping * Hdl2);
792+
const CVector<T> dlTorque_secondary =
793+
ccm_secondary * (Hdl2 + this->damping * Hfl2);
794+
795+
return (dmdt + flTorque_primary + dlTorque_primary + flTorque_secondary +
796+
dlTorque_secondary) *
797+
-GYRO * convTerm;
743798
}
799+
744800
return dmdt * -GYRO * convTerm;
745801
}
746802

@@ -1075,7 +1131,7 @@ template <typename T> class Junction {
10751131

10761132
MRmode MR_mode;
10771133
std::vector<Layer<T>> layers;
1078-
T Rp, Rap = 0.0;
1134+
T Rp = 0.0, Rap = 0.0;
10791135

10801136
std::vector<T> Rx0, Ry0, AMR_X, AMR_Y, SMR_X, SMR_Y, AHE;
10811137
std::unordered_map<std::string, std::vector<T>> log;
@@ -1338,6 +1394,38 @@ template <typename T> class Junction {
13381394
const ScalarDriver<T> &driver) {
13391395
scalarlayerSetter(layerID, &Layer<T>::setFieldLikeTorqueDriver, driver);
13401396
}
1397+
1398+
void setLayerSecondaryFieldLikeTorqueDriver(const std::string &layerID,
1399+
const ScalarDriver<T> &driver) {
1400+
scalarlayerSetter(layerID, &Layer<T>::setSecondaryFieldLikeTorqueDriver,
1401+
driver);
1402+
}
1403+
1404+
void setLayerSecondaryDampingLikeTorqueDriver(const std::string &layerID,
1405+
const ScalarDriver<T> &driver) {
1406+
scalarlayerSetter(layerID, &Layer<T>::setSecondaryDampingLikeTorqueDriver,
1407+
driver);
1408+
}
1409+
1410+
void
1411+
setLayerPrimaryTorqueDrivers(const std::string &layerID,
1412+
const ScalarDriver<T> &fieldLikeTorqueDriver,
1413+
const ScalarDriver<T> &dampingLikeTorqueDriver) {
1414+
scalarlayerSetter(layerID, &Layer<T>::setFieldLikeTorqueDriver,
1415+
fieldLikeTorqueDriver);
1416+
scalarlayerSetter(layerID, &Layer<T>::setDampingLikeTorqueDriver,
1417+
dampingLikeTorqueDriver);
1418+
}
1419+
1420+
void setLayerSecondaryTorqueDrivers(
1421+
const std::string &layerID, const ScalarDriver<T> &fieldLikeTorqueDriver,
1422+
const ScalarDriver<T> &dampingLikeTorqueDriver) {
1423+
scalarlayerSetter(layerID, &Layer<T>::setSecondaryFieldLikeTorqueDriver,
1424+
fieldLikeTorqueDriver);
1425+
scalarlayerSetter(layerID, &Layer<T>::setSecondaryDampingLikeTorqueDriver,
1426+
dampingLikeTorqueDriver);
1427+
}
1428+
13411429
void setLayerReservedInteractionField(const std::string &layerID,
13421430
const AxialDriver<T> &driver) {
13431431
axiallayerSetter(layerID, &Layer<T>::setReservedInteractionField, driver);
@@ -1585,14 +1673,14 @@ template <typename T> class Junction {
15851673
bool &step_accepted) {
15861674
// Run solver for each layer and check if all steps were accepted
15871675
step_accepted = true;
1588-
for (unsigned int i = 0; i < layerNo; i++) {
1589-
const CVector<T> bottom =
1590-
(i > 0) ? layers[i - 1].mag : CVector<T>(0, 0, 0);
1591-
const CVector<T> top =
1592-
(i < layerNo - 1) ? layers[i + 1].mag : CVector<T>(0, 0, 0);
1676+
std::vector<CVector<T>> magCopies(this->layerNo + 2, CVector<T>());
1677+
// the first and the last layer get 0 vector coupled
1678+
for (unsigned int i = 0; i < this->layerNo; i++)
1679+
magCopies[i + 1] = this->layers[i].mag;
15931680

1681+
for (unsigned int i = 0; i < layerNo; i++) {
15941682
// If any layer rejects the step, the whole step is rejected
1595-
if (!(layers[i].*functor)(t, timeStep, bottom, top)) {
1683+
if (!(layers[i].*functor)(t, timeStep, magCopies[i], magCopies[i + 2])) {
15961684
step_accepted = false;
15971685
}
15981686
}
@@ -1865,7 +1953,6 @@ template <typename T> class Junction {
18651953
auto [runner, solver, solver_mode] = getSolver(mode, totalIterations);
18661954
T t = 0.0;
18671955
T next_write_time = 0.0;
1868-
T current_timestep = timeStep;
18691956
if (solver_mode != DORMAND_PRINCE) {
18701957
// assign parameters
18711958
const unsigned int totalIterations =

docs/autogen/02_fieldscan_utilities_.md

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -146,26 +146,6 @@ class FieldScan:
146146

147147
---
148148

149-
## 6. Visualizing the Scan
150-
151-
```mermaid
152-
%% A polar slice at φ=30° showing 3 sample H vectors
153-
graph LR
154-
Origin((0,0,0))
155-
subgraph Sphere[ ]
156-
direction1([θ=45°, H=0])
157-
direction2([θ=45°, H=0.5Hmax])
158-
direction3([θ=45°, H=Hmax])
159-
end
160-
Origin --> direction1
161-
Origin --> direction2
162-
Origin --> direction3
163-
```
164-
165-
Each arrow from the origin is one of your `(Hx,Hy,Hz)` waypoints—lined up along the 45° tilt and spaced in strength.
166-
167-
---
168-
169149
## 7. Conclusion & Next Steps
170150

171151
You’ve learned how **FieldScan Utilities** take simple numeric ranges and angles, and produce full Cartesian field sequences—your “waypoints” for any simulation drive. Next, we’ll see how to turn those static fields into time‑dependent pulses or sine drives with [Time‑Dependent Drivers (ScalarDriver & AxialDriver)](03_time_dependent_drivers__scalardriver___axialdriver__.md).

docs/experimental-methods/MemoryCell.ipynb

Lines changed: 196 additions & 0 deletions
Large diffs are not rendered by default.

python/cmtj.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,16 @@ PYBIND11_MODULE(cmtj, m) {
254254
py::overload_cast<const DVector&>(&DLayer::setReferenceLayer))
255255
.def("setReferenceLayer",
256256
py::overload_cast<Reference>(&DLayer::setReferenceLayer))
257-
257+
.def("setSecondaryReferenceLayer",
258+
&DLayer::setSecondaryReferenceLayer)
259+
// drivers
258260
.def("setFieldLikeTorqueDriver", &DLayer::setFieldLikeTorqueDriver)
259261
.def("setDampingLikeTorqueDriver", &DLayer::setDampingLikeTorqueDriver)
262+
.def("setSecondaryFieldLikeTorqueDriver", &DLayer::setSecondaryFieldLikeTorqueDriver)
263+
.def("setSecondaryDampingLikeTorqueDriver", &DLayer::setSecondaryDampingLikeTorqueDriver)
264+
.def("setPrimaryTorqueDrivers", &DLayer::setPrimaryTorqueDrivers, "fieldLikeTorque"_a, "dampingLikeTorque"_a)
265+
.def("setSecondaryTorqueDrivers", &DLayer::setSecondaryTorqueDrivers, "fieldLikeTorque"_a, "dampingLikeTorque"_a)
266+
260267
.def("setTemperatureDriver", &DLayer::setTemperatureDriver)
261268
.def("setTopDipoleTensor", &DLayer::setTopDipoleTensor)
262269
.def("setBottomDipoleTensor", &DLayer::setBottomDipoleTensor)
@@ -273,6 +280,8 @@ PYBIND11_MODULE(cmtj, m) {
273280
.def("setAlphaNoise", &DLayer::setAlphaNoise, "alpha"_a, "std"_a, "scale"_a, "axis"_a = Axis::all)
274281
.def("setOneFNoise", &DLayer::setOneFNoise)
275282
// getters
283+
.def("getReferenceLayer", &DLayer::getReferenceLayer, py::return_value_policy::reference)
284+
.def("getSecondaryReferenceLayer", &DLayer::getSecondaryReferenceLayer, py::return_value_policy::reference)
276285
.def("getId", &DLayer::getId)
277286
.def("getOneFVector", &DLayer::getOneFVector)
278287
.def("setAdaptiveParams", &DLayer::setAdaptiveParams, "params"_a)
@@ -321,6 +330,14 @@ PYBIND11_MODULE(cmtj, m) {
321330
&DJunction::setLayerFieldLikeTorqueDriver)
322331
.def("setLayerDampingLikeTorqueDriver",
323332
&DJunction::setLayerDampingLikeTorqueDriver)
333+
.def("setLayerSecondaryFieldLikeTorqueDriver",
334+
&DJunction::setLayerSecondaryFieldLikeTorqueDriver)
335+
.def("setLayerSecondaryDampingLikeTorqueDriver",
336+
&DJunction::setLayerSecondaryDampingLikeTorqueDriver)
337+
.def("setLayerPrimaryTorqueDrivers",
338+
&DJunction::setLayerPrimaryTorqueDrivers, "layerId"_a, "fieldLikeTorque"_a, "dampingLikeTorque"_a)
339+
.def("setLayerSecondaryTorqueDrivers",
340+
&DJunction::setLayerSecondaryTorqueDrivers, "layerId"_a, "fieldLikeTorque"_a, "dampingLikeTorque"_a)
324341
// Reference setters
325342
.def("setLayerReferenceType", &DJunction::setLayerReferenceType)
326343
.def("setLayerReferenceLayer", &DJunction::setLayerReferenceLayer)

tests/test_basic.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Tuple
2-
31
import pytest
42
import numpy as np
53
from cmtj import Junction, AxialDriver, CVector, Layer, ScalarDriver

0 commit comments

Comments
 (0)