Octopus
basis_vectors.F90
Go to the documentation of this file.
1!! Copyright (C) 2021 N. Tancogne-Dejean, M. Oliveira
2!!
3!! This program is free software; you can redistribute it and/or modify
4!! it under the terms of the GNU General Public License as published by
5!! the Free Software Foundation; either version 2, or (at your option)
6!! any later version.
7!!
8!! This program is distributed in the hope that it will be useful,
9!! but WITHOUT ANY WARRANTY; without even the implied warranty of
10!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11!! GNU General Public License for more details.
12!!
13!! You should have received a copy of the GNU General Public License
14!! along with this program; if not, write to the Free Software
15!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16!! 02110-1301, USA.
17!!
18
19#include "global.h"
20
22 use debug_oct_m
23 use global_oct_m
26 use math_oct_m
30
31 implicit none
32
33 private
34
35 public :: &
37
57 ! Components are public by default
58 integer, private :: dim
59 real(real64), allocatable :: vectors(:,:)
60 real(real64), allocatable :: change_of_basis_matrix(:,:)
61 logical :: orthogonal
62 contains
63 procedure :: copy => basis_vectors_copy
64 generic :: assignment(=) => copy
65 procedure :: scale => basis_vectors_scale
66 generic :: from_cartesian => from_cartesian1, from_cartesian2
67 generic :: to_cartesian => to_cartesian1, to_cartesian2
68 procedure :: from_cartesian1 => basis_vectors_from_cartesian1
69 procedure :: to_cartesian1 => basis_vectors_to_cartesian1
70 procedure :: from_cartesian2 => basis_vectors_from_cartesian2
71 procedure :: to_cartesian2 => basis_vectors_to_cartesian2
73 end type basis_vectors_t
74
75 interface basis_vectors_t
76 module procedure basis_vectors_constructor
77 end interface basis_vectors_t
78
79contains
80
81 !--------------------------------------------------------------
82 type(basis_vectors_t) function basis_vectors_constructor(namespace, dim, vectors) result(basis)
83 type(namespace_t), intent(in) :: namespace
84 integer, intent(in) :: dim
85 real(real64), intent(in) :: vectors(dim, dim)
86
87 integer :: idir1, idir2
88
89 push_sub(basis_vectors_constructor)
90
91 basis%dim = dim
92
93 safe_allocate(basis%vectors(1:dim, 1:dim))
94 safe_allocate(basis%change_of_basis_matrix(1:dim, 1:dim))
95
96 basis%vectors = vectors
97
98 basis%orthogonal = .true.
99 do idir1 = 1, dim
100 do idir2 = idir1 + 1, dim
101 if (abs(dot_product(basis%vectors(:, idir1), basis%vectors(:, idir2))) > m_epsilon) then
102 basis%orthogonal = .false.
103 exit
104 end if
105 end do
106 end do
107
108 if (abs(lalg_determinant(dim, basis%vectors, preserve_mat = .true.)) < m_epsilon) then
109 message(1) = "Basis vectors are not linearly independent and therefore the change-of-basis matrix cannot be calculated."
110 call messages_fatal(1, namespace=namespace)
111 end if
112 call calculate_change_of_basis_matrix(dim, basis%vectors, basis%change_of_basis_matrix)
113
114 pop_sub(basis_vectors_constructor)
115 end function basis_vectors_constructor
116
117 !--------------------------------------------------------------
118 subroutine basis_vectors_copy(this, source)
119 class(basis_vectors_t), intent(out) :: this
120 class(basis_vectors_t), intent(in) :: source
121
122 push_sub(basis_vectors_copy)
123
124 this%dim = source%dim
125 safe_allocate_source_a(this%vectors, source%vectors)
126 safe_allocate_source_a(this%change_of_basis_matrix, source%change_of_basis_matrix)
127 this%orthogonal = source%orthogonal
128
129 pop_sub(basis_vectors_copy)
130 end subroutine basis_vectors_copy
131
132 !--------------------------------------------------------------
133 subroutine basis_vectors_finalize(this)
134 type(basis_vectors_t), intent(inout) :: this
135
136 push_sub(basis_vectors_finalize)
137
138 safe_deallocate_a(this%vectors)
139 safe_deallocate_a(this%change_of_basis_matrix)
140
142 end subroutine basis_vectors_finalize
143
144 !--------------------------------------------------------------
145 subroutine basis_vectors_scale(this, factor)
146 class(basis_vectors_t), intent(inout) :: this
147 real(real64), intent(in) :: factor(1:this%dim)
148
149 integer :: idir
150
153 ! Scale the basis in real space
154 do idir = 1, this%dim
155 this%vectors(:, idir) = this%vectors(:, idir)*factor(idir)
156 end do
158 ! Calculate the new change-of-basis matrix
159 call calculate_change_of_basis_matrix(this%dim, this%vectors, this%change_of_basis_matrix)
162 end subroutine basis_vectors_scale
164 !--------------------------------------------------------------
165 pure function basis_vectors_from_cartesian1(this, xx_cart) result(xx)
166 class(basis_vectors_t), intent(in) :: this
167 real(real64), intent(in) :: xx_cart(1:this%dim)
168 real(real64) :: xx(1:this%dim)
169
170 ! no PUSH_SUB, called too often
171
172 xx = matmul(this%change_of_basis_matrix, xx_cart)
173
176 !--------------------------------------------------------------
177 pure function basis_vectors_to_cartesian1(this, xx) result(xx_cart)
178 class(basis_vectors_t), intent(in) :: this
179 real(real64), intent(in) :: xx(1:this%dim)
180 real(real64) :: xx_cart(1:this%dim)
181
182 ! no PUSH_SUB, called too often
183
184 xx_cart = matmul(this%vectors, xx)
185
186 end function basis_vectors_to_cartesian1
187
188 !--------------------------------------------------------------
189 function basis_vectors_from_cartesian2(this, np, xx_cart) result(xx)
190 class(basis_vectors_t), intent(in) :: this
191 integer, intent(in) :: np
192 real(real64), contiguous, intent(in) :: xx_cart(:,:)
193 real(real64) :: xx(np, this%dim)
194
195 ! no PUSH_SUB, called too often
196
197 call lalg_gemm_nc(np, this%dim, this%dim, m_one, xx_cart, this%change_of_basis_matrix, m_zero, xx)
198
200
201 !--------------------------------------------------------------
202 function basis_vectors_to_cartesian2(this, np, xx) result(xx_cart)
203 class(basis_vectors_t), intent(in) :: this
204 integer, intent(in) :: np
205 real(real64), contiguous, intent(in) :: xx(:,:)
206 real(real64) :: xx_cart(np, this%dim)
207
208 ! no PUSH_SUB, called too often
209 call lalg_gemm_nc(np, this%dim, this%dim, m_one, xx, this%vectors, m_zero, xx_cart)
210
212
213 !--------------------------------------------------------------
214 subroutine calculate_change_of_basis_matrix(dim, vectors, matrix)
215 integer, intent(in) :: dim
216 real(real64), intent(in) :: vectors(1:dim, 1:dim)
217 real(real64), intent(out) :: matrix(1:dim, 1:dim)
218
219 real(real64) :: volume, cross(1:3)
220
222
223 select case (dim)
224 case (3)
225 cross(1:3) = dcross_product(vectors(1:3, 2), vectors(1:3, 3))
226 volume = dot_product(vectors(1:3, 1), cross(1:3))
227
228 matrix(1, 1:3) = dcross_product(vectors(:, 2), vectors(:, 3))/volume
229 matrix(2, 1:3) = dcross_product(vectors(:, 3), vectors(:, 1))/volume
230 matrix(3, 1:3) = dcross_product(vectors(:, 1), vectors(:, 2))/volume
231 case (2)
232 volume = vectors(1, 1)*vectors(2, 2) - vectors(2, 1)*vectors(1, 2)
233 matrix(1, 1) = vectors(2, 2)/volume
234 matrix(1, 2) = -vectors(1, 2)/volume
235 matrix(2, 1) = -vectors(2, 1)/volume
236 matrix(2, 2) = vectors(1, 1)/volume
237 case (1)
238 volume = vectors(1, 1)
239 matrix(1, 1) = m_one / vectors(1, 1)
240 case default ! dim > 3
241 matrix = vectors
242 call lalg_inverse(dim, matrix, 'dir')
243 end select
244
247
248end module basis_vectors_oct_m
249
250!! Local Variables:
251!! mode: f90
252!! coding: utf-8
253!! End:
Note that lalg_determinant and lalg_inverse are just wrappers over the same routine.
Definition: lalg_adv.F90:187
subroutine basis_vectors_copy(this, source)
real(real64) function, dimension(np, this%dim) basis_vectors_to_cartesian2(this, np, xx)
real(real64) function, dimension(np, this%dim) basis_vectors_from_cartesian2(this, np, xx_cart)
subroutine calculate_change_of_basis_matrix(dim, vectors, matrix)
pure real(real64) function, dimension(1:this%dim) basis_vectors_from_cartesian1(this, xx_cart)
subroutine basis_vectors_scale(this, factor)
subroutine basis_vectors_finalize(this)
pure real(real64) function, dimension(1:this%dim) basis_vectors_to_cartesian1(this, xx)
type(basis_vectors_t) function basis_vectors_constructor(namespace, dim, vectors)
real(real64), parameter, public m_epsilon
Definition: global.F90:203
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:420
Vectors defining a basis in a vector space. This class provides methods to convert vector coordinates...
int true(void)