Octopus
curv_modine.F90
Go to the documentation of this file.
1!! Copyright (C) 2002-2006 M. Marques, A. Castro, A. Rubio, G. Bertsch
2!! Copyright (C) 2025 S. Ohlmann
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
28
31 use debug_oct_m
32 use global_oct_m
33 use, intrinsic :: iso_fortran_env
37 use parser_oct_m
40 use unit_oct_m
42
43 implicit none
44
45 private
46 public :: &
49
50 type, extends(coordinate_system_t) :: curv_modine_t
51 private
52 real(real64), allocatable :: lsize(:)
53 real(real64) :: xbar
54 real(real64) :: Jbar
55
56 real(real64), allocatable :: Jlocal(:)
57 real(real64), allocatable :: Jrange(:)
58
59 real(real64), allocatable :: xi(:,:)
60 real(real64), allocatable :: Q(:,:,:)
61
62 integer :: npos
63 type(root_solver_t) :: rs, rs_init
64 contains
65 procedure :: to_cartesian => curv_modine_to_cartesian
66 procedure :: from_cartesian => curv_modine_from_cartesian
67 procedure :: jacobian => curv_modine_jacobian
68 procedure :: jacobian_inverse => curv_modine_jacobian_inverse
69 procedure :: write_info => curv_modine_write_info
70 procedure :: surface_element => curv_modine_surface_element
72 end type curv_modine_t
73
74 interface curv_modine_t
75 procedure curv_modine_constructor
76 end interface curv_modine_t
77
78 ! Auxiliary variables for the root solver.
79 class(curv_modine_t), pointer :: modine_p
80 real(real64), allocatable :: x_p(:)
81
82contains
83
84 ! ---------------------------------------------------------
85 function curv_modine_constructor(namespace, dim, npos, pos, lsize, spacing) result(modine)
86 type(namespace_t), intent(in) :: namespace
87 integer, intent(in) :: dim
88 integer, intent(in) :: npos
89 real(real64), intent(in) :: pos(1:dim,1:npos)
90 real(real64), intent(in) :: lsize(1:dim)
91 real(real64), intent(in) :: spacing(1:dim)
92 class(curv_modine_t), pointer :: modine
93
94 integer :: iatom, n
95 real(real64) :: kappa(1:npos)
96 type(block_t) :: blk
97
99
100 safe_allocate(modine)
101
102 modine%dim = dim
103 modine%local_basis = .true.
104 modine%orthogonal = .true. ! This needs to be checked.
105
106 modine%npos = npos
107
108 safe_allocate(modine%lsize(1:dim))
109 modine%lsize = lsize
110
111 !%Variable CurvModineXBar
112 !%Type float
113 !%Default 1/3
114 !%Section Mesh::Curvilinear::Modine
115 !%Description
116 !% Size of central flat region (in units of <tt>2*Lsize</tt>). Must be between 0 and 1.
117 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
118 !%End
119 call parse_variable(namespace, 'CurvModineXBar', m_one/m_four, modine%xbar)
120
121 !%Variable CurvModineJBar
122 !%Type float
123 !%Default 3/4
124 !%Section Mesh::Curvilinear::Modine
125 !%Description
126 !% Increase in density of points is inverse of this parameter.
127 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
128 !%End
129 call parse_variable(namespace, 'CurvModineJBar', m_half, modine%Jbar)
130
131 if (modine%xbar < m_zero .or. modine%xbar > m_one) then
132 message(1) = 'The parameter "CurvModineXBar" must lie between 0 and 1.'
133 call messages_fatal(1, namespace=namespace)
134 end if
135 if (modine%Jbar <= modine%xbar) then
136 message(1) = 'The parameter "CurvModineJBar" must be larger than the parameter "CurvModineXBar".'
137 call messages_fatal(1, namespace=namespace)
138 end if
139
140 safe_allocate(modine%Jlocal(1:npos))
141 safe_allocate(modine%Jrange(1:npos))
142
143 !%Variable CurvModineJlocal
144 !%Type block
145 !%Default 0.125
146 !%Section Mesh::Curvilinear::Modine
147 !%Description
148 !% Local refinement around the atoms for each atom. If only one line is specified, the value is taken
149 !% for all atoms. Must be between 0 and 1.
150 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
151 !%End
152 if (parse_block(namespace, "CurvModineJlocal", blk) == 0) then
153 n = parse_block_n(blk)
154 if (n == 1) then
155 call parse_block_float(blk, 0, 0, modine%Jlocal(1))
156 modine%Jlocal(:) = modine%Jlocal(1)
157 else if (n == npos) then
158 do iatom = 1, npos
159 call parse_block_float(blk, iatom - 1, 0, modine%Jlocal(iatom))
160 end do
161 else
162 write(message(1), '(3a,i2)') 'Error in block CurvModineJlocal: number of lines must be 1 or ', npos
163 call messages_fatal(1, namespace=namespace)
164 end if
165 else
166 ! for default value, see page 55, second paragraph
167 modine%Jlocal(:) = 0.125_real64
168 end if
169
170 do iatom = 1, npos
171 if (modine%Jlocal(iatom)<m_zero.or.modine%Jlocal(iatom)>m_one) then
172 message(1) = 'The parameter "CurvModineJlocal" must lie between 0 and 1.'
173 call messages_fatal(1, namespace=namespace)
174 end if
175 end do
176
177 !%Variable CurvModineJrange
178 !%Type block
179 !%Default 1.2 b
180 !%Section Mesh::Curvilinear::Modine
181 !%Description
182 !% Local refinement range (a length) for each atom. If only one line is specified, the value is
183 !% taken for all atoms.
184 !% See N. A. Modine, G. Zumbach, and E. Kaxiras, <i>Phys. Rev. B</i> <b>55</b>, 10289-10301 (1997).
185 !%End
186 if (parse_block(namespace, "CurvModineJrange", blk) == 0) then
187 n = parse_block_n(blk)
188 if (n == 1) then
189 call parse_block_float(blk, 0, 0, kappa(1), units_inp%length)
190 kappa(:) = kappa(1)
191 else if (n == npos) then
192 do iatom = 1, npos
193 call parse_block_float(blk, iatom - 1, 0, kappa(iatom), units_inp%length)
194 end do
195 else
196 write(message(1), '(3a,i2)') 'Error in block CurvModineJrange: number of lines must be 1 or ', npos
197 call messages_fatal(1, namespace=namespace)
198 end if
199 else
200 ! for default value, see page 55, second paragraph
201 kappa(:) = 1.2_real64
202 end if
203
204 ! solve eq. 18
205 do iatom = 1, npos
206 if (modine%Jlocal(iatom) > m_one-1e-5_real64) then
207 modine%Jrange(iatom) = kappa(iatom)
208 else
209 modine%Jrange(iatom) = kappa(iatom) / &
210 sqrt(m_one - product_log(-m_half*(((m_one+modine%Jlocal(1))/m_two)**m_third/(m_one-modine%Jlocal(iatom)**m_third)-m_one)&
211 *sqrt(m_e)))
212 end if
213 end do
214
215 ! initialize root solver for the inversion of the coordinates
216 call root_solver_init(modine%rs, namespace, dim, &
217 solver_type = root_newton, maxiter = 500, abs_tolerance = 1.0e-13_real64)
218
219 safe_allocate(modine%xi(1:modine%dim, 1:modine%npos))
220 safe_allocate(modine%Q(1:modine%dim, 1:modine%dim, 1:modine%npos))
221 call optimize()
222
223 modine%min_mesh_scaling_product = modine%Jbar**modine%dim
224
226 contains
227
228 ! product log function, i.e., the inverse of x exp(x)
229 real(real64) pure function product_log(x)
230 real(real64), intent(in) :: x
231
232 ! no push_sub/pop_sub, pure function
233
234 ! Third-order Taylor expansion around 0
235 product_log = x * (m_one + x * (-m_one + m_three*m_half*x))
236 end function product_log
237
238 subroutine optimize()
239 integer :: iatom, idim
240 real(real64), allocatable :: xi_tmp(:, :), q_tmp(:, :, :)
241 real(real64) :: residue, rr2, dd
242 integer :: iter, nu, mu, idim1, idim2
243 integer, parameter :: maxiter = 1000
244 real(real64), parameter :: tolerance = 1.0e-10_real64
245
247
248 safe_allocate(xi_tmp(1:modine%dim, 1:modine%npos))
249 safe_allocate(q_tmp(1:modine%dim, 1:modine%dim, 1:modine%npos))
250
251 ! initial guess: xi = R, Q = delta (1-J**1/3)
252 modine%Q(:, :, :) = m_zero
253 do iatom = 1, modine%npos
254 modine%xi(:, iatom) = pos(:, iatom)
255 do idim = 1, modine%dim
256 modine%Q(idim, idim, iatom) = m_one-modine%Jlocal(iatom)**(m_one/real(modine%dim, real64))
257 end do
258 end do
259
260 ! relaxation method to solve eq. 16 and 17
261 do iter = 1, maxiter
262 ! copy current values to temporary arrays
263 xi_tmp(:, :) = modine%xi(:, :)
264 q_tmp(:, :, :) = modine%Q(:, :, :)
265
266 modine%Q(:, :, :) = m_zero
267 do mu = 1, modine%npos
268 ! right-hand side
269 modine%xi(:, mu) = pos(:, mu)
270 do idim = 1, modine%dim
271 ! right-hand side and diagonal part
272 modine%Q(idim, idim, mu) = m_one-modine%Jlocal(mu)**(m_one/real(modine%dim, real64))
273 end do
274 do nu = 1, modine%npos
275 if (mu == nu) cycle
276 rr2 = sum((xi_tmp(:, mu) - xi_tmp(:, nu))**2)
277 dd = exp(-rr2/(m_two*modine%Jrange(nu)**2))
278
279 modine%xi(:, mu) = modine%xi(:, mu) + &
280 matmul(modine%Q(:, :, mu), xi_tmp(:, mu) - xi_tmp(:, nu)) * dd
281
282 do idim1 = 1, modine%dim
283 do idim2 = 1, modine%dim
284 modine%Q(idim1, idim2, mu) = modine%Q(idim1, idim2, mu) - q_tmp(idim1, idim2, nu) * dd
285 modine%Q(idim1, idim2, mu) = modine%Q(idim1, idim2, mu) + &
286 sum(q_tmp(idim1, :, nu)*(xi_tmp(:, mu) - xi_tmp(:, nu)))*(xi_tmp(idim2, mu) - xi_tmp(idim2, nu)) * &
287 m_one/modine%Jrange(nu) * dd
288 end do
289 end do
290 end do
291 end do
292
293 ! compute residue
294 residue = norm2(xi_tmp(:, :) - modine%xi(:, :)) / real(modine%dim*modine%npos, real64)
295 residue = residue + norm2(q_tmp(:, :, :) - modine%Q(:, :, :)) / real(modine%dim*modine%dim*modine%npos, real64)
296 if (residue <= tolerance) exit
297 end do
298
299 ! check for convergence
300 if (residue > tolerance) then
301 message(1) = "During the construction of the adaptive grid, the relaxation"
302 message(2) = "method did not converge."
303 message(3) = "This might be due to values of CurvModineJrange that are too large"
304 message(4) = "or CurvModineJlocal that are too small."
305 call messages_fatal(4, namespace=namespace)
306 end if
307
308
309 safe_deallocate_a(xi_tmp)
310 safe_deallocate_a(q_tmp)
311
313 end subroutine optimize
314
315 end function curv_modine_constructor
316
317 ! ---------------------------------------------------------
318 subroutine curv_modine_copy(this_out, this_in)
319 type(curv_modine_t), intent(inout) :: this_out
320 type(curv_modine_t), intent(in) :: this_in
321
322 push_sub(curv_modine_copy)
323
324 this_out%dim = this_in%dim
325 this_out%local_basis = this_in%local_basis
326 safe_allocate_source_a(this_out%lsize, this_in%lsize)
327 this_out%xbar = this_in%xbar
328 this_out%Jbar = this_in%Jbar
329 safe_allocate_source_a(this_out%Jlocal, this_in%Jlocal)
330 safe_allocate_source_a(this_out%Jrange, this_in%Jrange)
331 safe_allocate_source_a(this_out%xi, this_in%xi)
332 safe_allocate_source_a(this_out%Q, this_in%Q)
333 this_out%npos = this_in%npos
334
335 pop_sub(curv_modine_copy)
336 end subroutine curv_modine_copy
337
338 ! ---------------------------------------------------------
339 subroutine curv_modine_finalize(this)
340 type(curv_modine_t), intent(inout) :: this
341
342 push_sub(curv_modine_finalize)
343
344 safe_deallocate_a(this%lsize)
345 safe_deallocate_a(this%Jlocal)
346 safe_deallocate_a(this%Jrange)
347 safe_deallocate_a(this%xi)
348 safe_deallocate_a(this%Q)
349
350 pop_sub(curv_modine_finalize)
351 end subroutine curv_modine_finalize
352
353 ! ---------------------------------------------------------
354 function curv_modine_to_cartesian(this, chi) result(xx)
355 class(curv_modine_t), target, intent(in) :: this
356 real(real64), intent(in) :: chi(:)
357 real(real64) :: xx(1:this%dim)
358
359 real(real64) :: chi2(this%dim), rr2, dd
360 integer :: iatom
361
362 ! no PUSH_SUB, called too often
363
364 ! eq. 14
365 call curv_modine_chi2chi2(this, chi, chi2)
366
367 ! eq. 15
368 xx(:) = chi2(:)
369 do iatom = 1, this%npos
370 rr2 = sum((chi2(:) - this%xi(:, iatom))**2)
371 dd = exp(-rr2/(m_two*this%Jrange(iatom)**2))
372
373 xx(:) = xx(:) - matmul(this%Q(:, :, iatom), chi2(:) - this%xi(:, iatom)) * dd
374 end do
375
376 end function curv_modine_to_cartesian
377
378 ! ---------------------------------------------------------
379 function curv_modine_from_cartesian(this, xx) result(chi)
380 class(curv_modine_t), target, intent(in) :: this
381 real(real64), intent(in) :: xx(:)
382 real(real64) :: chi(1:this%dim)
383
384 logical :: conv
385 real(real64) :: start(1:this%dim)
386 integer :: i
387
388 ! no PUSH_SUB, called too often
389
390 modine_p => this
391 safe_allocate(x_p(1:this%dim))
392 x_p(:) = xx(:)
393
394 ! get a better starting point for the global backdrop
395 do i = 1, this%dim
396 if (abs(xx(i)) > this%lsize(i)) then
397 start(i) = xx(i)
398 else if (abs(xx(i)) > this%xbar*this%lsize(i)) then
399 ! linear interpolation between the two cases
400 start(i) = sign(m_one, xx(i)) * (abs(xx(i))/this%Jbar + abs(xx(i)) *(m_one - m_one/this%Jbar) * &
401 (abs(xx(i)) - this%xbar*this%lsize(i)) / (this%lsize(i) - this%xbar*this%lsize(i)))
402 ! ensure that we stay in the bounds
403 if (abs(start(i)) >= this%lsize(i)) then
404 start(i) = sign(this%lsize(i), xx(i))
405 end if
406 else
407 start(i) = xx(i)/this%Jbar
408 end if
409 end do
410
411 call droot_solver_run(this%rs, getf, chi, conv, startval=start)
412
413 safe_deallocate_a(x_p)
414 nullify(modine_p)
415
416 if (.not. conv) then
417 message(1) = "During the construction of the adaptive grid, the Newton-Raphson"
418 message(2) = "method did not converge for point:"
419 write(message(3),'(3f14.6)') xx(1:this%dim)
420 call messages_fatal(3)
421 end if
422
423 end function curv_modine_from_cartesian
424
425 ! ---------------------------------------------------------
426 subroutine curv_modine_write_info(this, iunit, namespace)
427 class(curv_modine_t), intent(in) :: this
428 integer, optional, intent(in) :: iunit
429 type(namespace_t), optional, intent(in) :: namespace
430
431 push_sub(curv_modine_write_info)
432
433 write(message(1), '(a)') ' Curvilinear Method = modine'
434 call messages_info(1, iunit=iunit, namespace=namespace)
435
437 end subroutine curv_modine_write_info
438
439 ! ---------------------------------------------------------
440 real(real64) function curv_modine_surface_element(this, idir) result(ds)
441 class(curv_modine_t), intent(in) :: this
442 integer, intent(in) :: idir
443
444 ds = m_zero
445 message(1) = 'Surface element with modine curvilinear coordinates not implemented'
446 call messages_fatal(1)
447
448 end function curv_modine_surface_element
450 ! ---------------------------------------------------------
451 pure subroutine curv_modine_chi2chi2(this, chi_, chi2, Jac)
452 class(curv_modine_t), intent(in) :: this
453 real(real64), intent(in) :: chi_(:)
454 real(real64), intent(out) :: chi2(:)
455 real(real64), optional, intent(out) :: jac(:)
456
457 integer, parameter :: qq = 3
458 real(real64) :: chibar(this%dim), rr, chi
459 logical :: neg
460 integer :: i
461
462 ! no PUSH_SUB, called too often
463
464 chibar = this%xbar*this%lsize/this%Jbar
465
466 do i = 1, this%dim
467 neg = (chi_(i) < 0)
468 chi = abs(chi_(i))
469
470 chi2(i) = this%Jbar * chi
471 if (present(jac)) jac(i) = this%Jbar
472
473 if (chi > this%lsize(i)) then
474 ! needed for boundary points
475 chi2(i) = chi
476 if (present(jac)) jac(i) = m_one
477 else if (chi > chibar(i)) then
478 rr = (chi - chibar(i))/(this%lsize(i) - chibar(i))
479
480 chi2(i) = chi2(i) + this%lsize(i)/m_two*(1 - this%Jbar) * rr**qq * &
481 (qq + m_one - (qq - m_one)*rr)
482
483 if (present(jac)) then
484 jac(i) = jac(i) + this%lsize(i)/m_two*(m_one - this%Jbar) * rr**(qq - 1)/(this%lsize(i) - chibar(i)) * &
485 (qq*(qq + m_one) - (qq**2 - m_one)*rr)
486 end if
487 end if
488
489 if (neg) chi2(i) = -chi2(i)
490 ! CHECK if Jacobian does not have to be negated!
491 end do
492
493 end subroutine curv_modine_chi2chi2
494
495 ! ---------------------------------------------------------
496 ! Jacobian for the coordinate transformation, i.e. for eqs. 14 and 15
497 pure subroutine curv_modine_jacobian_inv(this, chi, xx, Jac)
498 type(curv_modine_t), intent(in) :: this
499 real(real64), intent(in) :: chi(:)
500 real(real64), intent(out) :: xx(:)
501 real(real64), intent(out) :: jac(:, :)
502
503 real(real64) :: chi2(this%dim), rr2, dd, j2(this%dim)
504 integer :: iatom, idim, idim2
505
506 ! no PUSH_SUB, called too often
507
508 call curv_modine_chi2chi2(this, chi, chi2, j2)
509
510 ! initialize both xx and the Jacobian
511 xx(:) = chi2(:)
512 jac(:,:) = m_zero
513 do idim = 1, this%dim
514 jac(idim, idim) = m_one
515 end do
516
517 do iatom = 1, this%npos
518 rr2 = sum((chi2(:) - this%xi(:, iatom))**2)
519 dd = exp(-rr2/(m_two*this%Jrange(iatom)**2))
520
521 xx(:) = xx(:) - matmul(this%Q(:, :, iatom), chi2(:) - this%xi(:, iatom)) * dd
522
523 do idim = 1, this%dim
524 do idim2 = 1, this%dim
525 jac(idim, idim2) = jac(idim, idim2) - this%Q(idim, idim2, iatom) * dd
526 jac(idim, idim2) = jac(idim, idim2) + &
527 sum(this%Q(idim, :, iatom)*(chi2(:) - this%xi(:, iatom)))*(chi2(idim2) - this%xi(idim2, iatom)) * &
528 m_one/this%Jrange(iatom) * dd
529 end do
530 end do
531 end do
532
533 do idim = 1, this%dim
534 jac(idim, :) = jac(idim, :) * j2(:)
535 end do
536
537 end subroutine curv_modine_jacobian_inv
538
539 ! ---------------------------------------------------------
540 pure subroutine getf(yy, ff, jf)
541 real(real64), intent(in) :: yy(:)
542 real(real64), intent(out) :: ff(:), jf(:, :)
543
544 ! no PUSH_SUB, called too often
545
547 ff(:) = ff(:) - x_p(:)
548
549 end subroutine getf
550
551 ! ---------------------------------------------------------
552 function curv_modine_jacobian(this, chi) result(jacobian)
553 class(curv_modine_t), intent(in) :: this
554 real(real64), intent(in) :: chi(:)
555 real(real64) :: jacobian(1:this%dim, 1:this%dim)
556
557 real(real64) :: dummy(this%dim)
558
559 call curv_modine_jacobian_inv(this, chi, dummy, jacobian)
560
561 end function curv_modine_jacobian
562
563 ! ---------------------------------------------------------
564 function curv_modine_jacobian_inverse(this, chi) result(jacobian_inverse)
565 class(curv_modine_t), intent(in) :: this
566 real(real64), intent(in) :: chi(:)
567 real(real64) :: jacobian_inverse(1:this%dim, 1:this%dim)
568
569 real(real64) :: dummy(this%dim)
570
571 call curv_modine_jacobian_inv(this, chi, dummy, jacobian_inverse)
572 call lalg_inverse(this%dim, jacobian_inverse, "dir")
573
575
576end module curv_modine_oct_m
577
578!! Local Variables:
579!! mode: f90
580!! coding: utf-8
581!! End:
subroutine optimize()
real(real64) pure function product_log(x)
double exp(double __x) __attribute__((__nothrow__
This module implements the curvilinear coordinates given in N. A. Modine, G. Zumbach,...
class(curv_modine_t), pointer modine_p
real(real64) function, dimension(1:this%dim) curv_modine_from_cartesian(this, xx)
real(real64) function curv_modine_surface_element(this, idir)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_modine_jacobian_inverse(this, chi)
pure subroutine curv_modine_jacobian_inv(this, chi, xx, Jac)
real(real64) function, dimension(1:this%dim, 1:this%dim) curv_modine_jacobian(this, chi)
class(curv_modine_t) function, pointer curv_modine_constructor(namespace, dim, npos, pos, lsize, spacing)
pure subroutine getf(yy, ff, jf)
subroutine curv_modine_finalize(this)
real(real64), dimension(:), allocatable x_p
pure subroutine curv_modine_chi2chi2(this, chi_, chi2, Jac)
subroutine, public curv_modine_copy(this_out, this_in)
subroutine curv_modine_write_info(this, iunit, namespace)
real(real64) function, dimension(1:this%dim) curv_modine_to_cartesian(this, chi)
real(real64), parameter, public m_two
Definition: global.F90:192
real(real64), parameter, public m_zero
Definition: global.F90:190
real(real64), parameter, public m_four
Definition: global.F90:194
real(real64), parameter, public m_third
Definition: global.F90:197
real(real64), parameter, public m_half
Definition: global.F90:196
real(real64), parameter, public m_one
Definition: global.F90:191
real(real64), parameter, public m_three
Definition: global.F90:193
real(real64), parameter, public m_e
Definition: global.F90:189
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
Definition: messages.F90:162
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
Definition: messages.F90:416
integer function, public parse_block(namespace, name, blk, check_varinfo_)
Definition: parser.F90:621
integer, parameter, public root_newton
subroutine, public root_solver_init(rs, namespace, dimensionality, solver_type, maxiter, rel_tolerance, abs_tolerance)
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
Definition: unit.F90:134
This module defines the unit system, used for input and output.
type(unit_system_t), public units_inp
the units systems for reading and writing
abstract class to describe coordinate systems
int true(void)