@@ -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 =
0 commit comments