Octopus
affine_coordinates.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2021 M. Oliveira
3!! Copyright (C) 2025 S. Ohlmann
4!!
5!! This program is free software; you can redistribute it and/or modify
6!! it under the terms of the GNU General Public License as published by
7!! the Free Software Foundation; either version 2, or (at your option)
8!! any later version.
9!!
10!! This program is distributed in the hope that it will be useful,
11!! but WITHOUT ANY WARRANTY; without even the implied warranty of
12!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13!! GNU General Public License for more details.
14!!
15!! You should have received a copy of the GNU General Public License
16!! along with this program; if not, write to the Free Software
17!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18!! 02110-1301, USA.
19!!
20
21#include "global.h"
22
26 use debug_oct_m
27 use global_oct_m
29 use math_oct_m
33 use unit_oct_m
35
36 implicit none
37
38 private
39 public :: &
42
44 private
45 type(basis_vectors_t), public :: basis
46 contains
47 procedure :: to_cartesian => affine_coordinates_to_cartesian
48 procedure :: from_cartesian => affine_coordinates_from_cartesian
49 procedure :: write_info => affine_coordinates_write_info
50 procedure :: surface_element => affine_coordinates_surface_element
51 procedure :: jacobian => affine_coordinates_jacobian
52 procedure :: jacobian_inverse => affine_coordinates_jacobian_inverse
54
55 interface affine_coordinates_t
56 procedure affine_coordinates_constructor
57 end interface affine_coordinates_t
58
59contains
60
61 function affine_coordinates_constructor(namespace, dim, basis_vectors) result(affine)
62 type(namespace_t), intent(in) :: namespace
63 integer, intent(in) :: dim
64 real(real64), intent(in) :: basis_vectors(1:dim, 1:dim)
65 class(affine_coordinates_t), pointer :: affine
66
68
69 safe_allocate(affine)
70
71 affine%dim = dim
72 affine%local_basis = .false.
73 affine%basis = basis_vectors_t(namespace, dim, basis_vectors)
74 affine%orthogonal = affine%basis%orthogonal
75
78
79 ! --------------------------------------------------------------
80 subroutine affine_coordinates_copy(this_out, this_in)
81 type(affine_coordinates_t), intent(inout) :: this_out
82 type(affine_coordinates_t), intent(in) :: this_in
83
85
86 this_out%dim = this_in%dim
87 this_out%local_basis = this_in%local_basis
88 this_out%basis = this_in%basis
89
91 end subroutine affine_coordinates_copy
92
93 ! ---------------------------------------------------------
94 pure function affine_coordinates_to_cartesian(this, chi) result(xx)
95 class(affine_coordinates_t), target, intent(in) :: this
96 real(real64), intent(in) :: chi(:)
97 real(real64) :: xx(1:this%dim)
98
99 ! no PUSH_SUB, called too often
100
101 xx(:) = this%basis%to_cartesian(chi(:))
102
104
105 ! ---------------------------------------------------------
106 pure function affine_coordinates_from_cartesian(this, xx) result(chi)
107 class(affine_coordinates_t), target, intent(in) :: this
108 real(real64), intent(in) :: xx(:)
109 real(real64) :: chi(1:this%dim)
110
111 ! no PUSH_SUB, called too often
112
113 chi(:) = this%basis%from_cartesian(xx(:))
114
117 ! ---------------------------------------------------------
118 subroutine affine_coordinates_write_info(this, iunit, namespace)
119 class(affine_coordinates_t), intent(in) :: this
120 integer, optional, intent(in) :: iunit
121 type(namespace_t), optional, intent(in) :: namespace
122
123 integer :: idir1, idir2
124
126
127 write(message(1), '(a)') ' Using affine coordinates'
128 write(message(2), '(a)') ' Basis vectors [', trim(units_abbrev(units_out%length)), ']:'
129 call messages_info(2, iunit=iunit, namespace=namespace)
130 do idir1 = 1, this%dim
131 write(message(2), '(4x,a,99(f8.3,a))') '(', &
132 (units_from_atomic(units_out%length, this%basis%vectors(idir2, idir1)), idir2 = 1, this%dim - 1), &
133 units_from_atomic(units_out%length, this%basis%vectors(this%dim, idir1)), ')'
134 call messages_info(1, iunit=iunit, namespace=namespace)
135 end do
139
140 ! ---------------------------------------------------------
141 real(real64) function affine_coordinates_surface_element(this, idir) result(ds)
142 class(affine_coordinates_t), intent(in) :: this
143 integer, intent(in) :: idir
146
147 select case (this%dim)
148 case (3)
149 select case (idir)
150 case (1)
151 ds = norm2(dcross_product(this%basis%vectors(1:3, 2), this%basis%vectors(1:3, 3)))
152 case (2)
153 ds = norm2(dcross_product(this%basis%vectors(1:3, 3), this%basis%vectors(1:3, 1)))
154 case (3)
155 ds = norm2(dcross_product(this%basis%vectors(1:3, 1), this%basis%vectors(1:3, 2)))
156 end select
157
158 case (2)
159 select case (idir)
160 case (3)
161 ds = this%basis%vectors(1, 1)*this%basis%vectors(2, 2) - this%basis%vectors(2, 1)*this%basis%vectors(1, 2)
162 case default
163 ! We can only get the surface element along z, as the only existing plane is the xy plane
164 assert(.false.)
165 end select
166
167 case default
168 ! We only know how to do this for 2D and 3D
169 assert(.false.)
170 end select
171
174
175 ! ---------------------------------------------------------
176 function affine_coordinates_jacobian(this, chi) result(jacobian)
177 class(affine_coordinates_t), intent(in) :: this
178 real(real64), intent(in) :: chi(:)
179 real(real64) :: jacobian(1:this%dim, 1:this%dim)
180
181 jacobian(:, :) = this%basis%vectors(:, :)
182 end function affine_coordinates_jacobian
183
184 ! ---------------------------------------------------------
185 function affine_coordinates_jacobian_inverse(this, chi) result(jacobian_inverse)
186 class(affine_coordinates_t), intent(in) :: this
187 real(real64), intent(in) :: chi(:)
188 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
189
190 jacobian_inverse(:, :) = this%basis%change_of_basis_matrix(:, :)
192
194
195!! Local Variables:
196!! mode: f90
197!! coding: utf-8
198!! End:
subroutine affine_coordinates_write_info(this, iunit, namespace)
pure real(real64) function, dimension(1:this%dim) affine_coordinates_to_cartesian(this, chi)
class(affine_coordinates_t) function, pointer affine_coordinates_constructor(namespace, dim, basis_vectors)
subroutine, public affine_coordinates_copy(this_out, this_in)
real(real64) function, dimension(1:this%dim, 1:this%dim) affine_coordinates_jacobian(this, chi)
real(real64) function, dimension(1:this%dim, 1:this%dim) affine_coordinates_jacobian_inverse(this, chi)
pure real(real64) function, dimension(1:this%dim) affine_coordinates_from_cartesian(this, xx)
real(real64) function affine_coordinates_surface_element(this, idir)
This module is intended to contain "only mathematical" functions and procedures.
Definition: math.F90:115
pure real(real64) function, dimension(1:3), public dcross_product(a, b)
Definition: math.F90:1906
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:160
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
Definition: messages.F90:616
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:132
character(len=20) pure function, public units_abbrev(this)
Definition: unit.F90:223
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
Vectors defining a basis in a vector space. This class provides methods to convert vector coordinates...
abstract class to describe coordinate systems