diff --git a/src/action.hpp b/src/action.hpp index 1066e57835a2050cdc004897e4f90a527f406021..d4b5fcb46453e2e9a36ac7e53ffb3c1b396b8f12 100644 --- a/src/action.hpp +++ b/src/action.hpp @@ -83,7 +83,14 @@ inline Scalar S_2(const array::ArrayView<const Mask, Shape0>& mask, const int N_i[2] = {1, 0}; const int N_j[2] = {0, 1}; - /* Directions cycle (left->right, down->up, right->left, up->down) */ + /* + * Directions cycle (left->right, down->up, right->left, up->down) + * + * U(i,j,k) = U_{(i2,j2),(i,j)} where i2 = i + N_i[k], j2 = j + N_i[k]. + * + * Hence, spatial index of the link matrices U indicate the starting point, + * and the direction index the direction away from the starting point. + */ const size_t invdir[4] = {2, 3, 0, 1}; Scalar S{0.0}; @@ -108,8 +115,8 @@ inline Scalar S_2(const array::ArrayView<const Mask, Shape0>& mask, continue; auto Q2 = Qmat.part(i2,j2).matrix(); - auto U12 = U.part(i,j,k).matrix(); - auto U21 = U.part(i2,j2,invdir[k]).matrix(); + auto U21 = U.part(i,j,k).matrix(); + auto U12 = U.part(i2,j2,invdir[k]).matrix(); auto M = nambu_diag_mul(U12, Q2, U21) - Q1; diff --git a/src/core.cpp b/src/core.cpp index 068c42124dc584a202650c6cc59f8ea75ea7f16d..2ce489a90a9d3a24aa4342a51dee058fba2deea9 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -69,8 +69,8 @@ private: std::unordered_map<std::pair<size_t,size_t>, bool, pair_hash> hes_pattern_map_; - CppAD::ADFun<Complex> J_f_; /**< Derivatives for currents */ - bool J_computed_; + CppAD::ADFun<Complex> A_f_; /**< Derivatives for currents */ + bool A_computed_; CppAD::ADFun<Complex> S_f_; /**< Derivatives for densities */ bool S_computed_; @@ -91,7 +91,7 @@ private: public: Action(double Lx, double Ly, Complex alpha, Complex D, MaskType&& mask, UType&& U, OmegaType&& Omega) : U_(std::move(U)), Omega_(std::move(Omega)), mask_(std::move(mask)), nx_(U_.dim(0)), ny_(U_.dim(1)), Lx_(Lx), Ly_(Ly), alpha_(alpha), D_(D), omega_(0), - hes_pattern_map_(), J_computed_(false), S_computed_(false) + hes_pattern_map_(), A_computed_(false), S_computed_(false) { if (Omega.dim(0) != nx_ || Omega.dim(1) != ny_) throw std::domain_error("U and Omega have incompatible shape"); @@ -310,9 +310,9 @@ public: * Computing currents and densities. * * Current flowing to i is obtained as derivatives vs. xi with - * U_{ij} -> exp(xi J) * U_{ij} =~ U_{ij} + (xi J) U_ij - * where J is the generator matrix. We implement this as derivatives - * vs. the elements of the generator J. + * U_{ij} -> exp(xi A(i)) * U_{ij} exp(xi A(j)) =~ U_{ij} + xi A(i) U_ij + xi U_ij A(j) + * where A is the generator matrix. We implement this as derivatives + * vs. the elements of the generator A. * * Densities are derivatives vs. the 0-component of the gauge * potential, i.e., derivatives vs Omega. We implement this @@ -348,27 +348,28 @@ public: return dynamic; } - CppAD::ADFun<Complex> eval_dS_dJ(const QType& Q) + CppAD::ADFun<Complex> eval_dS_dA(const QType& Q) { if (Q.dim(0) != nx_ || Q.dim(1) != ny_) throw std::out_of_range("Q array wrong size"); Array<ADComplex, Shape<Dynamic,Dynamic,4,4,4> > - J({nx_, ny_, 4, 4, 4}); + A({nx_, ny_, 4, 4, 4}); - J.fill(Complex(0)); + A.fill(Complex(0)); std::vector<ADComplex> dynamic = dynamic_Omega_Q<ADComplex>(Q); ArrayView<ADComplex, Shape<Dynamic,Dynamic,4,4> > Omegadyn(dynamic.data()+1, dynamic.size()-1, Omega_.shape()); ArrayView<ADComplex, Shape<Dynamic,Dynamic,2,2,2> > Qdyn(dynamic.data()+1+Omega_.size(), dynamic.size()-1-Omega_.size(), Q.shape()); - CppAD::Independent(J.storage(), dynamic); + CppAD::Independent(A.storage(), dynamic); Array<ADComplex, Shape<Dynamic,Dynamic,4,4,4> > U({nx_, ny_, 4, 4, 4}); const size_t invdir[4] = {2, 3, 0, 1}; const int neigh[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}}; + const Complex sgn_A[4] = {1, 1, -1, -1}; for (size_t i = 0; i < nx_; ++i) { for (size_t j = 0; j < ny_; ++j) { @@ -381,8 +382,8 @@ public: continue; U.part(i,j,k).matrix() += - J.part(i,j,k).matrix() * U_.part(i,j,k).matrix() - - U_.part(i,j,k).matrix() * J.part(i2,j2,invdir[k]).matrix(); + sgn_A[k] * U_.part(i,j,k).matrix() * A.part(i,j,k).matrix() + + sgn_A[k] * A.part(i2,j2,invdir[k]).matrix() * U_.part(i,j,k).matrix(); } } } @@ -390,7 +391,7 @@ public: Array<ADComplex, Shape<1> > res; res(0u) = S(mask_, Qdyn, dynamic[0], U, Omegadyn, Lx_, Ly_, alpha_, D_); - return {J.storage(), res.storage()}; + return {A.storage(), res.storage()}; } CppAD::ADFun<Complex> eval_dS_dOmega(const QType& Q) @@ -417,11 +418,11 @@ public: return {Omega.storage(), res.storage()}; } - void compute_dS_dJ(const QType& Q) + void compute_dS_dA(const QType& Q) { - J_f_ = eval_dS_dJ(Q); - J_f_.optimize(); - J_computed_ = true; + A_f_ = eval_dS_dA(Q); + A_f_.optimize(); + A_computed_ = true; } void compute_dS_dOmega(const QType& Q) @@ -431,16 +432,16 @@ public: S_computed_ = true; } - auto grad_J(const QType& Q) + auto grad_A(const QType& Q) { Vector<Complex> x(U_.size()); - if (!J_computed_) - compute_dS_dJ(Q); + if (!A_computed_) + compute_dS_dA(Q); else - J_f_.new_dynamic(dynamic_Omega_Q<Complex>(Q)); + A_f_.new_dynamic(dynamic_Omega_Q<Complex>(Q)); - auto jac = J_f_.Jacobian(x); + auto jac = A_f_.Jacobian(x); return Array<Complex, Shape<Dynamic,Dynamic,4,4,4>, Vector<Complex> >(std::move(jac), {nx_, ny_, 4, 4, 4}); } @@ -448,7 +449,7 @@ public: { Vector<Complex> x = ravel(Omega_); - if (!J_computed_) + if (!S_computed_) compute_dS_dOmega(Q); else S_f_.new_dynamic(dynamic_Q<Complex>(Q)); @@ -479,7 +480,7 @@ PYBIND11_MODULE(_core, m) .def("compute", &Action::compute, "Precompute for AD", py::arg("Q")) .def_property("omega", &Action::get_omega, &Action::set_omega) .def_property_readonly("hess_computed", &Action::get_hess_computed) - .def("grad_J", &Action::grad_J, "Evaluate gradient of action vs. current generators", py::arg("Q")) + .def("grad_A", &Action::grad_A, "Evaluate gradient of action vs. current generators", py::arg("Q")) .def("grad_Omega", &Action::grad_Omega, "Evaluate gradient of action vs. Omega", py::arg("Q")) ; diff --git a/tests/test_solver.py b/tests/test_solver.py index ecbb70b1ef6a0852c9c97d5c338e18fe090d3909..212def5a09493ec168318b69725dbe8de4133d20 100644 --- a/tests/test_solver.py +++ b/tests/test_solver.py @@ -312,7 +312,8 @@ def test_soc_analytic(n=10): Jtot = 0 for ww, aa in zip(w, a): res0 = sol0.solve(omega=ww, finite_difference=False) - J = sol._core.grad_J(res0.Phi.copy()).transpose(0, 1, 2, 4, 3) * (-1 / 8) + sol.omega = ww + J = sol._core.grad_A(res0.Phi.copy()).transpose(0, 1, 2, 4, 3) * (-1 / 8) Jtot += aa * J diff --git a/usadelndsoc/core.py b/usadelndsoc/core.py index 7ab47fb2980e2a7972228fb9f96b8cb0d4981621..ff89b460333a21355c004d8c85a52bc910c035a4 100644 --- a/usadelndsoc/core.py +++ b/usadelndsoc/core.py @@ -105,9 +105,9 @@ class Core: self._ensure_action() return self._action.hess_mul(Q, dQ) - def grad_J(self, Q): + def grad_A(self, Q): self._ensure_action() - return self._action.grad_J(Q) + return self._action.grad_A(Q) def grad_Omega(self, Q): self._ensure_action() diff --git a/usadelndsoc/solver.py b/usadelndsoc/solver.py index 780db9edb981cbffb50a65c48431ce52766352fd..22e933713df93e9e5727dab867ea3b86c8659d33 100644 --- a/usadelndsoc/solver.py +++ b/usadelndsoc/solver.py @@ -597,7 +597,7 @@ class Result: @property def J(self): - return self._core.grad_J(self.Phi).transpose(0, 1, 2, 4, 3) * (-1 / 16) + return self._core.grad_A(self.Phi).transpose(0, 1, 2, 4, 3) * (-1 / 16) @property def S(self):