From b5b78976e5cbf9dd18d67b2412f03fb28ef2fb87 Mon Sep 17 00:00:00 2001 From: Pauli Virtanen <pauli.t.virtanen@jyu.fi> Date: Tue, 23 Aug 2022 18:16:49 +0300 Subject: [PATCH] edit --- src/action.hpp | 13 ++++++--- src/core.cpp | 13 +++++---- src/xtest.f95 | 24 ++++++++++++---- usadelndsoc/solver.py | 65 ++++++++++++++++++++++++++++++++----------- 4 files changed, 84 insertions(+), 31 deletions(-) diff --git a/src/action.hpp b/src/action.hpp index c58cb3b..b93cade 100644 --- a/src/action.hpp +++ b/src/action.hpp @@ -60,7 +60,8 @@ inline Scalar S_2(const array::ArrayView<const Mask, Shape0>& mask, const array::ArrayView<ConstScalar, Shape>& Qmat, const array::ArrayView<const Complex, Shape2>& U, const double& Lx, - const double& Ly) + const double& Ly, + const Complex& D) { const int nx = Qmat.dim(0); const int ny = Qmat.dim(1); @@ -74,6 +75,9 @@ inline Scalar S_2(const array::ArrayView<const Mask, Shape0>& mask, const size_t invdir[4] = {2, 3, 1, 0}; Scalar S{0.0}; + if (D == Complex(0)) + return S; + for (int i = 0; i < nx; ++i) { for (int j = 0; j < ny; ++j) { if (mask(i,j) == Mask::VACUUM) @@ -102,7 +106,7 @@ inline Scalar S_2(const array::ArrayView<const Mask, Shape0>& mask, } } - return (dd[0]*dd[1]*2.0/4.0) * S; + return (D*dd[0]*dd[1]*2.0/4.0) * S; } template <typename ConstScalar, typename Shape0, typename Shape, typename Shape2, typename Scalar = typename std::remove_const<ConstScalar>::type> @@ -245,7 +249,8 @@ inline Scalar S(const array::ArrayView<const Mask, Shape0>& mask, const array::ArrayView<const Complex, Shape3>& Omega, const double& Lx, const double& Ly, - const Complex& alpha) + const Complex& alpha, + const Complex& D) { using array::Array; using array::Shape; @@ -283,7 +288,7 @@ inline Scalar S(const array::ArrayView<const Mask, Shape0>& mask, } } - S = S + S_2(mask, Qmat, U, Lx, Ly) + S_Omega(mask, Qmat, omega, Omega, Lx, Ly) + S_H(mask, Qmat, U, Lx, Ly, alpha); + S = S + S_2(mask, Qmat, U, Lx, Ly, D) + S_Omega(mask, Qmat, omega, Omega, Lx, Ly) + S_H(mask, Qmat, U, Lx, Ly, alpha); return S; } diff --git a/src/core.cpp b/src/core.cpp index 022d90f..e98f4ba 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -52,6 +52,7 @@ private: size_t nx_, ny_; double Lx_, Ly_; Complex alpha_; + Complex D_; Complex omega_; typedef Vector<size_t> SizeVector; @@ -87,8 +88,8 @@ private: } public: - Action(double Lx, double Ly, Complex alpha, 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), omega_(0), + 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_() { if (Omega.dim(0) != nx_ || Omega.dim(1) != ny_) @@ -107,7 +108,7 @@ public: { if (Q.dim(0) != nx_ || Q.dim(1) != ny_) throw std::out_of_range("Q array wrong size"); - return S(mask_, Q, omega_, U_, Omega_, Lx_, Ly_, alpha_); + return S(mask_, Q, omega_, U_, Omega_, Lx_, Ly_, alpha_, D_); } CppAD::ADFun<Complex> eval_ad(const QType& Qval) @@ -129,7 +130,7 @@ public: CppAD::Independent(Q.storage(), dynamic); Array<ADComplex, Shape<1> > res; - res(0u) = S(mask_, Q, dynamic[0], U_, Omega_, Lx_, Ly_, alpha_); + res(0u) = S(mask_, Q, dynamic[0], U_, Omega_, Lx_, Ly_, alpha_, D_); return {Q.storage(), res.storage()}; } @@ -294,8 +295,8 @@ PYBIND11_MODULE(_core, m) m.doc() = "usadelndsoc._core"; py::class_<Action>(m, "Action") - .def(py::init<double, double, Complex, Action::MaskType, Action::UType, Action::OmegaType>(), "Action", - py::arg("L_x"), py::arg("L_y"), py::arg("alpha"), py::arg("mask"), py::arg("U"), py::arg("Omega")) + .def(py::init<double, double, Complex, Complex, Action::MaskType, Action::UType, Action::OmegaType>(), "Action", + py::arg("L_x"), py::arg("L_y"), py::arg("alpha"), py::arg("D"), py::arg("mask"), py::arg("U"), py::arg("Omega")) .def("eval", &Action::eval, "Evaluate value of action", py::arg("Q")) .def("grad", &Action::grad, "Evaluate gradient of action", py::arg("Q")) .def("hess", &Action::hess, "Evaluate hessian of action", py::arg("Q")) diff --git a/src/xtest.f95 b/src/xtest.f95 index 930c8a1..d7df1da 100644 --- a/src/xtest.f95 +++ b/src/xtest.f95 @@ -1,7 +1,9 @@ program main use adjac implicit none - + + integer, parameter :: n = 35 + type(adjac_complexan), dimension(:,:,:,:,:), allocatable :: Q double complex, dimension(:,:,:,:,:), allocatable :: U type(adjac_complexan), dimension(1) :: res @@ -9,11 +11,16 @@ program main double complex, dimension(:, :), allocatable ::jac double complex :: v + double complex, dimension(:), allocatable :: hess_v + integer, dimension(:), allocatable :: hess_i + integer, dimension(:), allocatable :: hess_j + integer :: nnz + integer i1, i2, i3, i4, i5, p, p2 - allocate(Q(50,50,2,2,2)) - allocate(U(50,50,4,4,4)) - allocate(jac(1, 50*50*2*2*2)) + allocate(Q(n,n,2,2,2)) + allocate(U(n,n,4,4,4)) + allocate(jac(1, n*n*2*2*2)) call adjac_reset() @@ -44,12 +51,19 @@ program main res(1) = S_2(Q, U, 0.1d0) call adjac_get_dense_jacobian(res, jac) - call adjac_reset(.false.) do i1 = 1, 10 write(*,*) '->', jac(1,i1) end do + call adjac_get_coo_hessian(res(1), nnz, hess_v, hess_i, hess_j) + + do i1 = 1, nnz + write(*,*) hess_i(i1), hess_j(i1), '->>', hess_v(i1) + end do + + call adjac_reset(.false.) + return contains function inverse(M) result(W) diff --git a/usadelndsoc/solver.py b/usadelndsoc/solver.py index fa32924..a7d50af 100644 --- a/usadelndsoc/solver.py +++ b/usadelndsoc/solver.py @@ -75,10 +75,11 @@ def _norm(z): class Core: - def __init__(self, Lx=1, Ly=1, alpha=0, nx=1, ny=1): - self.Lx = 1 - self.Ly = 1 - self.alpha = 0 + def __init__(self, Lx=1, Ly=1, alpha=0, D=1, nx=1, ny=1): + self.Lx = Lx + self.Ly = Ly + self.alpha = alpha + self.D = D self.set_shape(nx, ny) def set_shape(self, nx=1, ny=1): @@ -95,7 +96,9 @@ class Core: def new_action(self): self.init_U() - return Action(self.Lx, self.Ly, self.alpha, self._mask, self._U, self._Omega) + return Action( + self.Lx, self.Ly, self.alpha, self.D, self._mask, self._U, self._Omega + ) @property def x(self): @@ -185,7 +188,7 @@ class Solver: if solver is None: solver = "lgmres" - if A_size > 20000: + if A_size > 40000: _log_solve.debug( f" Problem too large ({A_size}): cannot compute hessian" ) @@ -377,7 +380,18 @@ class Solver: return (abs(Phi + dx) < 1.0).all() def _check_final(self, Phi): - # XXX: check the branch here! + # Check branch + g = Phi[:, :, 0] + gt = Phi[:, :, 1] + I = np.eye(2) + s = np.sign(self._action.omega) + + G = s * np.linalg.solve(I + g @ gt, I + gt @ g) + if G[:, :, 0, 0].real.min() < -0.05 or G[:, :, 1, 1].real.min() < -0.05: + Phi[:, :, 0] *= -0.5 + Phi[:, :, 1] *= 0.5 + _log_solve.info(" Force restart: wrong branch") + return False return True def _eval_rhs(self, Phi): @@ -429,7 +443,7 @@ class Solver: if sz > 1000 and pyamg is not None: preconditioner = "pyamg" elif umfpack is not None: - preconditioner = "umfpack-ilu" + preconditioner = "umfpack" if sz < 100 else "umfpack-ilu" else: preconditioner = "splu" @@ -461,7 +475,7 @@ class Solver: def solve_many(self, omega, **kw): omega = np.asarray(omega) - Phi = np.zeros(self.Phi.shape + omega.shape, dtype=self.Phi.dtype) + Phi = np.zeros(omega.shape + self.Phi.shape, dtype=self.Phi.dtype) self._M = None self._Phi[...] = 0 @@ -474,13 +488,18 @@ class Solver: for v in it: self.solve(omega=v, action=action, **kw) Phi_prev = self._Phi.copy() - Phi[(Ellipsis,) + it.multi_index] = self._Phi + Phi[it.multi_index + (Ellipsis,)] = self._Phi if np.isnan(self._Phi).any(): self._Phi[...] = Phi_prev return Result(self, omega=omega, Phi=Phi) +def _bcast_left(x, shape): + x = np.asarray(x) + return x[(Ellipsis,) + (None,) * (len(shape) - x.ndim)] + + class Result: def __init__(self, parent, omega=None, Phi=None, core=None): self._core = core if core is not None else parent._core @@ -494,26 +513,40 @@ class Result: @property def G(self): - s = np.sign(self.omega) + g = self.Phi[..., 0, :, :] + gt = self.Phi[..., 0, :, :] + I = np.eye(2) + s = _bcast_left(np.sign(self.omega), g.shape) with np.errstate(invalid="ignore"): - return (1 - self.Phi[0] * self.Phi[1]) / (1 + self.Phi[0] * self.Phi[1]) * s + return s * np.linalg.solve(I + g @ gt, I - g @ gt) @property def F(self): - s = np.sign(self.omega) + g = self.Phi[..., 0, :, :] + gt = self.Phi[..., 0, :, :] + I = np.eye(2) + s = _bcast_left(np.sign(self.omega), g.shape) with np.errstate(invalid="ignore"): - return 2 * self.Phi[0] / (1 + self.Phi[0] * self.Phi[1]) * s + return 2 * s * np.linalg.solve(I + g @ gt, g) @property def Fc(self): + g = self.Phi[..., 0, :, :] + gt = self.Phi[..., 0, :, :] + I = np.eye(2) + s = _bcast_left(np.sign(self.omega), g.shape) with np.errstate(invalid="ignore"): - return 2 * self.Phi[1] / (1 + self.Phi[0] * self.Phi[1]) + return 2 * s * np.linalg.solve(I + gt @ g, gt) @property def g(self): + g = self.Phi[..., 0, :, :] + gt = self.Phi[..., 0, :, :] + I = np.eye(2) + s = _bcast_left(np.sign(self.omega), g.shape) with np.errstate(invalid="ignore"): G = self.G - return np.array([[G, self.F], [self.Fc, -G]]) + return s * np.linalg.solve(I + gt @ g, I - gt @ g) @property def J(self): -- GitLab