module MathClass !! This module defines numerious basic mathematical operations, mainly for scalar and vector computation. !! It also contains some converter among string, characters and othe datatypes. use, intrinsic :: iso_fortran_env !use OouraFFT use StringClass implicit none integer(int32) :: i_i = 0 integer(int32) :: j_j = 0 integer(int32) :: k_k = 0 logical :: true = .True. logical :: False = .False. !integer(int32) :: i_i = 0 type :: Math_ real(real64) :: PI = 3.14159265358979323846d0 !! For saving the computation time, this uses a fixed value for PI. real(real64) :: E = 2.718281828459045d0 !! For saving the computation time, this uses a fixed value for e. complex(kind(0d0)) :: i = (0.0d0, 1.0d0) complex(kind(0d0)) :: j = (0.0d0, 1.0d0) !! It is a unit imaginary value. end type !> A real64-type pointer. type :: Real64Ptr_ real(real64), pointer :: ptr end type Real64Ptr_ integer(int32), parameter :: complex64 = real64 !> It computes nCr (combination number) interface nchoosek module procedure comb end interface !> It computes nCr (combination number) interface choose module procedure comb end interface !> It computes factorial. interface fact module procedure factorialInt32, factorialReal64 end interface !> It takes a imaginary part of a complex number. interface imag module procedure imaginary_partComplex64, imaginary_partComplex32 end interface !> It takes a arg() of a complex number. interface arg module procedure arg_complex64, arg_complex64_vector, arg_complex64_tensor end interface !> It computes L^2 norm of a tensor. interface norm module procedure norm_mat, norm_vec, norm_vec_real32, norm_vec_complex64 end interface !> It computes determinant of a regular matrix. interface det_mat module procedure det_mat_real64, det_mat_complex64 end interface !> It converts an array of character into a integer interface int module procedure fint end interface int !> It converts an array of character into a float (real32) interface float module procedure freal end interface float !> It returns the trace of a matrix. interface trace module procedure trace_complex64, trace_real64 end interface !> It returns factorial. interface factorial module procedure factorialInt32, factorialReal64 end interface factorial !> It returns Bessel function of 0th kind by complex number. interface Bessel_J0 module procedure Bessel_J0_complex end interface !> It returns Bessel function of 1st kind by complex number. interface Bessel_J1 module procedure Bessel_J1_complex end interface !> It sorts integer vector interface sort module procedure :: sort_int32 end interface sort !> It sorts integer vector by heap sort. interface heapsort module procedure :: heapsortInt32, heapsortInt32Int32,heapsortReal64Int32,& heapsortReal64, heapsortReal32,& heapsort_int32_array,heapsort_real64_array end interface !> It sorts integer vector and removes duplication. interface sort_and_remove_duplication module procedure :: sort_and_remove_duplication_int32, sort_and_remove_duplication_real64 end interface !> It converts valiables into a string. interface str module procedure fstring_Int, fstring_Int64, fstring_Real, fstring_Real32, & fstring_complex, fstring_Int_len, fstring_Real_len, fstring_logical, fstring_String, stringFromChar end interface str !> It converts valiables into a string. interface fstring module procedure fstring_Int, fstring_Int64, fstring_Real, fstring_Int_len, fstring_Real_len, fstring_logical end interface fstring !> It converts logical array into int. interface int module procedure int_from_logical, int_from_logical_vector end interface int !> It returns a value from defalut value when no optional value is given, and returns the optional value only if it is given. interface input module procedure input_Int, input_Real, input_Real32, input_Complex, input_IntVec, & input_RealVec, input_IntArray, input_RealArray, input_String, input_logical end interface input !> It returns zero if some value is positive/negative. interface zeroif module procedure zeroif_Int, zeroif_Real end interface zeroif !> It removes a character from string. interface removeWord module procedure removeWord_String end interface !> It computes tensor product. interface tensor_product module procedure :: tensor_product_complex, tensor_product_real64 end interface !> It converts deg. to rad. interface radian module procedure radianreal32, radianreal64, radianreal64Vec, radianint end interface !> It allocates array. interface array module procedure arrayDim1Real64, arrayDim2Real64, arrayDim3Real64 end interface !> It returns the Ricker's function. interface RickerFunction module procedure RickerFunctionReal64, RickerFunctionReal64Vector end interface !> It gives a numerical derivative. interface derivative module procedure derivative_scalar, derivative_vector end interface !> It gives a numerical derivative. interface der module procedure derivative_scalar, derivative_vector end interface !> It gives a numerical derivative. interface d_dx module procedure derivative_scalar, derivative_vector end interface !> It computes the fact Fourier transformation. interface FFT module procedure FFT1D, FFT2D_real, FFT2D_comp, FFT_file_to_file end interface !> It computes the power spectral density function from datafile. interface PSD module procedure PSD_file_to_file end interface !> It performs spectral whitening. interface SpectralWhitening module procedure SpectralWhitening_real64 end interface !> It computes matrix exponential by the Taylor expansion. interface exp module procedure matrix_exponential_real64 end interface public :: assignment(=) interface assignment(=) module procedure assign_real64, assign_int32 end interface !interface matmul_complex ! module procedure matmul_complex_real64 !end interface matmul_complex contains function SpectralWhitening_real64(x, auto) result(ret) real(real64), intent(in) :: x(:) complex(complex64), allocatable :: x_c(:) complex(complex64), allocatable :: f_c(:) real(real64), allocatable :: ret(:) real(real64) :: r, r_max, total_power, average_power integer(int32) :: i, n logical, optional, intent(in) :: auto ! FFT n = int(log10(dble(size(x)))/log10(2.0d0) + 0.00010d0) x_c = x(1:2**n) f_c = FFT(x_c) ! for each frequencies, if (present(auto)) then if (auto) then total_power = sum(abs(f_c(:))*abs(f_c(:))) average_power = total_power/size(f_c) r_max = sqrt(average_power) else r_max = 1.0d0 end if else r_max = 1.0d0 end if do i = 1, size(f_c) r = abs(f_c(i)) f_c(i) = f_c(i)/r*r_max end do ret = dble(IFFT(f_c)) end function ! function FFT_file_to_file(infile, outfile, window_size, dt, column, as_abs) result(FourierSpectrum) character(*), intent(in) :: infile, outfile integer(int32), intent(in) :: window_size, column real(real64), intent(in) :: dt real(real64) :: max_freq, min_freq logical, optional, intent(in) :: as_abs logical :: export_as_abs complex(real64), allocatable :: FourierSpectrum(:, :), x(:), FFT_X(:) integer(int32) :: ifile, ofile, i real(real64), allocatable :: line(:) allocate (line(column)) open (newunit=ifile, file=infile, status='old') allocate (x(window_size)) do i = 1, window_size read (ifile, *) line(1:column) x(i) = line(column) end do close (ifile) allocate (FourierSpectrum(window_size/2, 2)) ! frequency axis max_freq = (1.0d0/dt)/2.0d0 min_freq = 1.0d0/(window_size/(1.0d0/dt)) do i = 1, window_size/2 FourierSpectrum(i, 1) = min_freq + (i - 1)*(max_freq - min_freq)/(window_size/2) end do FFT_X = FFT(X) FourierSpectrum(:, 2) = FFT_X(1:window_size/2) export_as_abs = input(default=.false., option=as_abs) if (export_as_abs) then open (newunit=ofile, file=outfile, status='replace') do i = 1, window_size/2 write (ofile, *) dble(FourierSpectrum(i, 1)), abs(FourierSpectrum(i, 2)) end do close (ofile) else open (newunit=ofile, file=outfile, status='replace') do i = 1, window_size/2 write (ofile, *) dble(FourierSpectrum(i, 1)), dble(FourierSpectrum(i, 2)), imag(FourierSpectrum(i, 2)) end do close (ofile) end if end function ! ############################################### function PSD_file_to_file(infile, outfile, window_size, dt, column) result(FourierSpectrum) character(*), intent(in) :: infile, outfile integer(int32), intent(in) :: window_size, column real(real64) :: dt, max_freq, min_freq complex(real64), allocatable :: FourierSpectrum(:, :), x(:), FFT_X(:) integer(int32) :: ifile, ofile, i real(real64), allocatable :: line(:) allocate (line(column)) open (newunit=ifile, file=infile, status='old') allocate (x(window_size)) do i = 1, window_size read (ifile, *) line(1:column) x(i) = line(column) end do close (ifile) allocate (FourierSpectrum(window_size/2, 2)) ! frequency axis max_freq = (1.0d0/dt)/2.0d0 min_freq = 1.0d0/(window_size/(1.0d0/dt)) do i = 1, window_size/2 FourierSpectrum(i, 1) = min_freq + (i - 1)*(max_freq - min_freq)/(window_size/2) end do FFT_X = FFT(X) FourierSpectrum(:, 2) = FFT_X(1:window_size/2) open (newunit=ofile, file=outfile, status='replace') do i = 1, window_size/2 write (ofile, *) dble(FourierSpectrum(i, 1)), abs(FourierSpectrum(i, 2)*conjg(FourierSpectrum(i, 2))) end do close (ofile) end function ! ############################################### function FFT2D_real(xy) result(hatx) real(real64), intent(in) :: xy(:, :) complex(real64), allocatable :: hatx(:, :), buf(:) integer(int32) :: row, i ! type(Math_) :: Math ! character(*),optional,intent(in) :: window ! real(real64),optional,intent(in) :: T(2) ! range ! real(real64) :: Trange(1:2),dt_x,dt_y ! integer(int32) :: Nx, Ny hatx = xy do row = 1, size(xy, 1) hatx(row, :) = FFT_core(hatx(row, :)) end do do row = 1, size(xy, 1) buf = hatx(row, :) hatx(row, size(xy, 1)/2 + 1:size(xy, 1)) = buf(1:size(xy, 1)/2) do i = 1, size(xy, 1)/2 hatx(row, i) = buf(size(xy, 1)/2 - i + 1) end do end do hatx = transpose(hatx) do row = 1, size(xy, 2) hatx(row, :) = FFT_core(hatx(row, :)) end do do row = 1, size(xy, 2) buf = hatx(row, :) hatx(row, size(xy, 2)/2 + 1:size(xy, 2)) = buf(1:size(xy, 2)/2) do i = 1, size(xy, 2)/2 hatx(row, i) = buf(size(xy, 2)/2 - i + 1) end do end do hatx = transpose(hatx) end function ! ############################################### ! ############################################### function FFT2D_comp(xy) result(hatx) complex(real64), intent(in) :: xy(:, :) complex(real64), allocatable :: hatx(:, :) integer(int32) :: row ! type(Math_) :: Math ! character(*),optional,intent(in) :: window ! real(real64),optional,intent(in) :: T(2) ! range ! real(real64) :: Trange(1:2),dt_x,dt_y ! integer(int32) :: Nx, Ny allocate (hatx(size(xy, 1), size(xy, 2))) do row = 1, size(xy, 1) hatx(row, :) = FFT_core(xy(row, :)) end do hatx = transpose(hatx) do row = 1, size(xy, 2) hatx(row, :) = FFT_core(hatx(row, :)) end do hatx = transpose(hatx) end function ! ############################################### ! ############################################### function FFT1D(x, T, window) result(hatx) complex(kind(0d0)), intent(in) :: x(:) complex(kind(0d0)), allocatable :: hatx(:) type(Math_) :: Math character(*), optional, intent(in) :: window real(real64), optional, intent(in) :: T(2) ! range real(real64) :: Trange(1:2), dt integer(int32) :: N N = size(x) if (present(T)) then dt = abs(T(2) - T(1))/dble(N) else dt = 1.0d0 end if hatx = FFT_core(x) hatx = dt*hatx end function ! ############################################### ! Hanning window function hann(L) result(hann_window) integeR(int32), intent(in) :: L real(real64) :: hann_window(1:L) integer(int32) :: i, N type(Math_) :: math N = L - 1 do i = 0, L - 1 hann_window(i + 1) = 0.50d0*(1.0d0 - cos(math%PI*2.0d0*i/N)) end do end function ! ############################################### recursive function FFT_core(x) result(hatx) complex(real64), intent(in) :: x(:) complex(real64), allocatable :: hatx(:), W(:), L(:), R(:) real(real64), allocatable :: a(:), wo(:) integer(int32), allocatable :: ip(:) integer(int32) :: N, i, itr, isgn integer(int32), allocatable :: k(:) type(Math_) :: Math ! This FFT is ! Fw(m dw) = T/N \sum_{n=0}^{N-1} f(n dt) e^{-i 2 \pi k/N m n} N = size(x) allocate (hatx(N)) hatx(:) = 0.0d0 allocate (k(N/2)) allocate (W(N/2)) allocate (L(N/2)) allocate (R(N/2)) do i = 1, size(k) k(i) = i - 1 !print *, exp(-1*Math%i * 2.0d0* Math%PI * k(i)/dble(N)) W(i) = exp(-1.0d0*Math%i*2.0d0*Math%PI*k(i)/dble(N)) end do if (N == 2) then ! butterfly operation hatx(1) = x(1) + x(2) hatx(2) = x(1) - x(2) return end if if (N >= 4) then itr = 0 do i = 1, N, 2 itr = itr + 1 if (itr > size(L)) then exit end if L(itr) = x(i) end do itr = 0 do i = 2, N, 2 itr = itr + 1 if (itr > size(R)) then exit end if R(itr) = x(i) end do L = FFT_core(L) R = FFT_core(R) do i = 1, N/2 hatx(i) = L(i) + W(i)*R(i) end do do i = N/2 + 1, N if (i - N/2 > size(L)) then exit end if hatx(i) = L(i - N/2) - W(i - N/2)*R(i - N/2) end do return end if end function ! ############################################### function IFFT(x, T) result(hatx) complex(kind(0d0)), intent(in) :: x(:) complex(kind(0d0)), allocatable :: hatx(:) type(Math_) :: Math real(real64), optional, intent(in) :: T(2) ! range real(real64) :: Trange(2), TT integer(int32) :: N ! This IFFT is ! ft(n dt) = 1/T \sum_{n=0}^{N-1} Fw(m dw) e^{i 2 \pi k/N m n} N = size(x) if (present(T)) then TT = abs(T(2) - T(1)) else TT = dble(N) end if hatx = IFFT_core(x) hatx = 1.0d0/TT*hatx end function ! ############################################### recursive function IFFT_core(x) result(hatx) complex(kind(0d0)), intent(in) :: x(:) complex(kind(0d0)), allocatable :: hatx(:), W(:), L(:), R(:) real(real64), allocatable :: a(:), wo(:) integer(int32), allocatable :: ip(:) integer(int32) :: N, i, itr, isgn integer(int32), allocatable :: k(:) type(Math_) :: Math !!! call Ooura-FFT !n = size(x)/2 !allocate(a(0:2*n-1) ) !allocate(wo(0:2*n-1) ) !a(0:2*n-1) = x(1:2*n) !isgn = n !call cdft(2*n,isgn,a(0:2*n-1),ip,wo(0:n/2-1) ) !hatx = a ! !return !!! N = size(x) allocate (hatx(N)) hatx(:) = 0.0d0 allocate (k(N/2)) allocate (W(N/2)) allocate (L(N/2)) allocate (R(N/2)) do i = 1, size(k) k(i) = i - 1 !print *, exp(-1*Math%i * 2.0d0* Math%PI * k(i)/dble(N)) W(i) = exp(Math%i*2.0d0*Math%PI*k(i)/dble(N)) end do if (N == 2) then ! butterfly operation hatx(1) = x(1) + x(2) hatx(2) = x(1) - x(2) return end if if (N >= 4) then itr = 0 do i = 1, N, 2 itr = itr + 1 if (itr > size(L)) then exit end if L(itr) = x(i) end do itr = 0 do i = 2, N, 2 itr = itr + 1 if (itr > size(R)) then exit end if R(itr) = x(i) end do L = IFFT_core(L) R = IFFT_core(R) do i = 1, N/2 hatx(i) = L(i) + W(i)*R(i) end do do i = N/2 + 1, N if (i - N/2 > size(L)) then exit end if hatx(i) = L(i - N/2) - W(i - N/2)*R(i - N/2) end do return end if end function ! ############################################### ! ############################################### function arrayDim1Real64(size1) result(ret) integer(int32), intent(in) :: size1 real(real64), allocatable :: ret(:) allocate (ret(size1)) ret(:) = 0.0d0 end function ! ############################################### ! ############################################### function arrayDim2Real64(size1, size2) result(ret) integer(int32), intent(in) :: size1, size2 real(real64), allocatable :: ret(:, :) allocate (ret(size1, size2)) ret(:, :) = 0.0d0 end function ! ############################################### ! ############################################### function arrayDim3Real64(size1, size2, size3) result(ret) integer(int32), intent(in) :: size1, size2, size3 real(real64), allocatable :: ret(:, :, :) allocate (ret(size1, size2, size3)) ret(:, :, :) = 0.0d0 end function ! ############################################### ! ############################################### function radianreal32(deg) result(ret) real(real32), intent(in) :: deg real(real64) :: ret ret = deg/180.0d0*3.14159265358979323846d0 end function ! ############################################### ! ############################################### function radianreal64(deg) result(ret) real(real64), intent(in) :: deg real(real64) :: ret ret = deg/180.0d0*3.14159265358979323846d0 end function ! ############################################### ! ############################################### function radianreal64Vec(degs) result(ret) real(real64), intent(in) :: degs(:) integer(int32) :: i real(real64), allocatable :: ret(:) ret = degs do i = 1, size(degs) ret(i) = degs(i)/180.0d0*3.14159265358979323846d0 end do end function ! ############################################### ! ############################################### function radianint(deg) result(ret) integer(int32), intent(in) :: deg real(real64) :: ret ret = dble(deg)/180.0d0*3.14159265358979323846d0 end function ! ############################################### ! ############################################### function degrees(rad) result(ret) real(real64), intent(in) :: rad real(real64) :: ret ret = rad/3.14159265358979323846d0*180.0d0 end function ! ############################################### !######################################## function norm_vec(vec) result(a) real(real64), intent(in)::vec(:) integer(int32) :: n real(real64) :: a n = size(vec) a = dsqrt(dot_product(vec, vec)) end function !######################################## !######################################## function norm_vec_real32(vec) result(a) real(real32), intent(in)::vec(:) integer(int32) :: n real(real32) :: a n = size(vec) a = sqrt(dot_product(vec, vec)) end function !######################################## !######################################## function norm_vec_complex64(vec) result(a) complex(real64), intent(in)::vec(:) integer(int32) :: n real(real64) :: a n = size(vec) a = sqrt(dble(dot_product(vec, vec))) end function !######################################## !######################################## function norm_mat(vec) result(a) real(real64), intent(in)::vec(:, :) integer(int32) :: n real(real64) :: a a = dsqrt(sum(vec*vec)) end function !######################################## !######################################## pure function SearchNearestValueID(Vector, x) result(id) real(real64), intent(in) :: Vector(:) real(real64), intent(in) :: x integer(int32) :: id, i id = 1 do i = 1, size(vector) if (abs(vector(id) - x) > abs(vector(i) - x)) then id = i cycle end if end do end function !######################################## !######################################## function SearchNearestValueIDs(Vector, x, num) result(id) real(real64), intent(in) :: Vector(:) real(real64), intent(in) :: x integer(int32), intent(in) :: num integer(int32) :: id(num), i, j id(:) = 1 do j = 1, num do i = 1, size(vector) if (j >= 2) then if (abs(minval(id(1:j - 1) - i)) == 0) cycle end if if (abs(vector(id(j)) - x) > abs(vector(i) - x)) then id(j) = i cycle end if end do end do end function !######################################## !######################################## function SearchNearestValue(Vector, x) result(val) real(real64), intent(in) :: Vector(:) real(real64), intent(in) :: x integer(int32) :: id, i real(real64) :: val id = 1 do i = 1, size(vector) if (abs(vector(id) - x) > abs(vector(i) - x)) then id = i cycle end if end do val = vector(id) end function !######################################## !######################################## function SearchNearestCoord(Array, x) result(id) real(real64), intent(in) :: Array(:, :) real(real64), intent(in) :: x(:) integer(int32), allocatable::xr(:) integer(int32) :: i, id, n, m, norm, tr_norm n = size(Array, 1) m = size(Array, 2) if (m /= size(x)) then stop "ERROR :: SearchNearestCoord >> size(Array,2) should be =size(x)" end if allocate (xr(m)) do i = 1, n xr(:) = Array(i, :) tr_norm = dot_product(xr - x, xr - x) if (i == 1) then norm = tr_norm id = i else if (norm > tr_norm) then norm = tr_norm id = i else cycle end if end if end do end function !######################################## !################################################## function SearchIDIntVec(Vec, val) result(id_) integer(int32), intent(in) :: Vec(:) integer(int32), intent(in) :: val integer(int32) :: i, id_ do i = 1, size(Vec) if (Vec(i) == val) then id_ = i return end if end do end function !################################################## !################################################## subroutine heapsortReal64(n, array, val) integer(int32), intent(in) :: n real(real64), intent(inout) :: array(1:n)! rearrange order by this array real(real64), optional, intent(inout) :: val(1:n) ! linked data real(real64) :: t_real integer(int32) ::i, k, j, l real(real64) :: t if (n .le. 0) then write (6, *) "Error, at heapsort"; stop end if if (n .eq. 1) return l = n/2 + 1 k = n do while (k .ne. 1) if (l .gt. 1) then l = l - 1 t = array(L) if (present(val)) then t_real = val(L) end if else t = array(k) if (present(val)) then t_real = val(k) end if array(k) = array(1) if (present(val)) then val(k) = val(1) end if k = k - 1 if (k .eq. 1) then array(1) = t if (present(val)) then val(1) = t_real end if exit end if end if i = l j = l + l do while (j .le. k) if (j .lt. k) then if (array(j) .lt. array(j + 1)) j = j + 1 end if if (t .lt. array(j)) then array(i) = array(j) if (present(val)) then val(i) = val(j) end if i = j j = j + j else j = k + 1 end if end do array(i) = t if (present(val)) then val(i) = t_real end if end do end subroutine heapsortReal64 !################################################## subroutine heapsortReal32(n, array, val) integer(int32), intent(in) :: n real(real32), intent(inout) :: array(1:n)! rearrange order by this array real(real32), optional, intent(inout) :: val(1:n) ! linked data real(real32) :: t_real integer(int32) ::i, k, j, l real(real32) :: t if (n .le. 0) then write (6, *) "Error, at heapsort"; stop end if if (n .eq. 1) return l = n/2 + 1 k = n do while (k .ne. 1) if (l .gt. 1) then l = l - 1 t = array(L) if (present(val)) then t_real = val(L) end if else t = array(k) if (present(val)) then t_real = val(k) end if array(k) = array(1) if (present(val)) then val(k) = val(1) end if k = k - 1 if (k .eq. 1) then array(1) = t if (present(val)) then val(1) = t_real end if exit end if end if i = l j = l + l do while (j .le. k) if (j .lt. k) then if (array(j) .lt. array(j + 1)) j = j + 1 end if if (t .lt. array(j)) then array(i) = array(j) if (present(val)) then val(i) = val(j) end if i = j j = j + j else j = k + 1 end if end do array(i) = t if (present(val)) then val(i) = t_real end if end do end subroutine heapsortReal32 !################################################## !################################################## function sort_int32(vec) result(ret) integer(int32), intent(in) :: vec(:) integer(int32), allocatable :: ret(:) ret = vec call heapsortInt32(size(ret), ret) end function !################################################## pure subroutine heapsortInt32(n, array, val) integer(int32), intent(in) :: n integer(int32), intent(inout) :: array(1:n)! rearrange order by this array real(real64), optional, intent(inout) :: val(1:n) ! linked data real(real64) :: t_real integer(int32) ::i, k, j, l integer(int32) :: t if (n .le. 0) then return !write (6, *) "Error, at heapsort"; stop end if if (n .eq. 1) return l = n/2 + 1 k = n do while (k .ne. 1) if (l .gt. 1) then l = l - 1 t = array(L) if (present(val)) then t_real = val(L) end if else t = array(k) if (present(val)) then t_real = val(k) end if array(k) = array(1) if (present(val)) then val(k) = val(1) end if k = k - 1 if (k .eq. 1) then array(1) = t if (present(val)) then val(1) = t_real end if exit end if end if i = l j = l + l do while (j .le. k) if (j .lt. k) then if (array(j) .lt. array(j + 1)) j = j + 1 end if if (t .lt. array(j)) then array(i) = array(j) if (present(val)) then val(i) = val(j) end if i = j j = j + j else j = k + 1 end if end do array(i) = t if (present(val)) then val(i) = t_real end if end do end subroutine heapsortInt32 !################################################## pure subroutine heapsortInt32Int32(n, array, val) integer(int32), intent(in) :: n integer(int32), intent(inout) :: array(1:n)! rearrange order by this array integer(int32), intent(inout) :: val(1:n) ! linked data integer(int32) :: t_real integer(int32) ::i, k, j, l integer(int32) :: t if (n .le. 0) then !write (6, *) "Error, at heapsort"; stop !print *, "Error, at heapsort" return end if if (n .eq. 1) return l = n/2 + 1 k = n do while (k .ne. 1) if (l .gt. 1) then l = l - 1 t = array(L) t_real = val(L) else t = array(k) t_real = val(k) array(k) = array(1) val(k) = val(1) k = k - 1 if (k .eq. 1) then array(1) = t val(1) = t_real exit end if end if i = l j = l + l do while (j .le. k) if (j .lt. k) then if (array(j) .lt. array(j + 1)) j = j + 1 end if if (t .lt. array(j)) then array(i) = array(j) val(i) = val(j) i = j j = j + j else j = k + 1 end if end do array(i) = t val(i) = t_real end do end subroutine heapsortInt32Int32 !################################################## pure subroutine heapsortReal64Int32(n, array, val) integer(int32), intent(in) :: n real(real64), intent(inout) :: array(1:n)! rearrange order by this array integer(int32), intent(inout) :: val(1:n) ! linked data real(real64) :: t_real integer(int32) ::i, k, j, l real(real64) :: t if (n .le. 0) then !write (6, *) "Error, at heapsort"; stop !print *, "Error, at heapsort" return end if if (n .eq. 1) return l = n/2 + 1 k = n do while (k .ne. 1) if (l .gt. 1) then l = l - 1 t = array(L) t_real = val(L) else t = array(k) t_real = val(k) array(k) = array(1) val(k) = val(1) k = k - 1 if (k .eq. 1) then array(1) = t val(1) = t_real exit end if end if i = l j = l + l do while (j .le. k) if (j .lt. k) then if (array(j) .lt. array(j + 1)) j = j + 1 end if if (t .lt. array(j)) then array(i) = array(j) val(i) = val(j) i = j j = j + j else j = k + 1 end if end do array(i) = t val(i) = t_real end do end subroutine heapsortReal64Int32 !========================================================== !calculate cross product !--------------------------- pure function cross_product(a, b) result(c) real(real64), intent(in) :: a(:), b(:) real(real64), allocatable :: c(:) if (size(a) /= 3 .or. size(b) /= 3) then !stop "wrong number on size a, b" return end if allocate (c(size(a, 1))) if (size(c, 1) == 3) then c(1) = a(2)*b(3) - a(3)*b(2) c(2) = a(3)*b(1) - a(1)*b(3) c(3) = a(1)*b(2) - a(2)*b(1) else !stop "wrong number at cross_product" return end if end function cross_product !========================================================= !calculate diadic !---------------------- function diadic(a, b) result(c) real(real64), intent(in) :: a(:), b(:) real(real64), allocatable :: c(:, :) integer(int32) n, i, j allocate (c(size(a), size(b))) do i = 1, size(a) do j = 1, size(b) c(i, j) = a(i)*b(j) end do end do end function diadic !========================================================== !========================================================= !calculate diadic !---------------------- function tensor_product_real64(a, b) result(c) real(real64), intent(in) :: a(:), b(:) real(real64), allocatable :: c(:, :) integer(int32) n, i, j allocate (c(size(a), size(b))) do i = 1, size(a) do j = 1, size(b) c(i, j) = a(i)*b(j) end do end do end function !========================================================== !========================================================= !calculate diadic !---------------------- function tensor_product_complex(a, b) result(c) complex(real64), intent(in) :: a(:), b(:) complex(real64), allocatable :: c(:, :) integer(int32) n, i, j allocate (c(size(a), size(b))) do i = 1, size(a) do j = 1, size(b) c(i, j) = a(i)*b(j) end do end do end function !========================================================== !calculate gz !-------------- subroutine calcgz(x2, x11, x12, nod_coord, gzi) real(real64), intent(in) :: nod_coord(:, :) real(real64), intent(out) :: gzi integer(int32), intent(in):: x2, x11, x12 real(real64) l real(real64), allocatable::avec(:) allocate (avec(2)) l = dot_product(nod_coord(x12, 1:2) - nod_coord(x11, 1:2), & nod_coord(x12, 1:2) - nod_coord(x11, 1:2)) l = l**(1.0d0/2.0d0) avec(1:2) = (nod_coord(x12, 1:2) - nod_coord(x11, 1:2))/l if (l == 0.0d0) then print *, "calcgz l=0" gzi = 0.0d0 else gzi = 1.0d0/l*dot_product(nod_coord(x2, 1:2) - nod_coord(x11, 1:2), avec(1:2)) end if deallocate (avec) end subroutine calcgz !========================================================== function arg_complex64(comp) result(theta) complex(real64), intent(in) :: comp real(real64) :: theta, re, im real(real64) ::pi = 3.14159265358979323846d0 re = dble(real(comp)) im = dble(aimag(comp)) if (re > 0.0d0) then theta = atan(im/re) elseif (re < 0.0d0 .and. im >= 0.0d0) then theta = atan(im/re + pi) elseif (re < 0.0d0 .and. im < 0.0d0) then theta = atan(im/re - pi) elseif (re == 0.0d0 .and. im > 0.0d0) then theta = pi/2.0d0 elseif (re == 0.0d0 .and. im < 0.0d0) then theta = -pi/2.0d0 else theta = 0.0d0 end if end function !========================================================== !========================================================== function arg_complex64_vector(comp) result(theta) complex(real64), intent(in) :: comp(:) real(real64), allocatable :: theta(:) integer(int32) :: i allocate (theta(size(comp))) do i = 1, size(comp) theta(i) = arg_complex64(comp(i)) end do end function !========================================================== !========================================================== function arg_complex64_tensor(comp) result(theta) complex(real64), intent(in) :: comp(:, :) real(real64), allocatable :: theta(:, :) integer(int32) :: i, j allocate (theta(size(comp, 1), size(comp, 2))) do i = 1, size(comp, 2) do j = 1, size(comp, 1) theta(j, i) = arg_complex64(comp(j, i)) end do end do end function !========================================================== function cubic_equation(a, b, c, d) result(x) real(real64), intent(in) :: a, b, c, d real(real64) :: x(3), theta real(real64) ::Deq, A_, B_, C_, p, q real(real64) ::pi = 3.14159265358979323846d0 complex(real64) :: comp !https://qiita.com/yotapoon/items/42b1749b69c264d6f486 A_ = b/a B_ = c/a C_ = d/a p = B_ - A_*A_/3.0d0 q = 2.0d0*A_*A_*A_/27.0d0 - A_*B_/3.0d0 + C_ Deq = q*q/4.0d0 + p*p*p/27.0d0 if (Deq > 0.0d0) then print *, "D > 0 :: not implemented now." elseif (Deq == 0) then print *, "D == 0 " x(1) = -2.0d0*(p/2.0d0)**(3) x(2) = (p/2.0d0)**(3) x(3) = (p/2.0d0)**(3) return else print *, "D < 0 " comp = cmplx(-q/2.0d0, sqrt(-Deq)) theta = arg(comp) x(1) = 2.0d0*sqrt(-p/3.0d0)*cos(theta) x(2) = 2.0d0*sqrt(-p/3.0d0)*cos((theta + 2.0d0*pi)/3.0d0) x(3) = 2.0d0*sqrt(-p/3.0d0)*cos((theta + 4.0d0*pi)/3.0d0) end if end function !========================================================== subroutine eigen_2d(Amat, eigenvector) real(real64), intent(in)::Amat(:, :) real(real64), allocatable, intent(inout)::eigenvector(:, :) real(real64)::b, c, phy, eigenvalue(2) integer(int32) i, j eigenvalue = array(size(Amat, 1)) eigenvector = array(size(Amat, 1), size(Amat, 1)) b = -1.0d0*(Amat(1, 1) + Amat(2, 2)) c = Amat(1, 1)*Amat(2, 2) - Amat(1, 2)*Amat(1, 2) if (Amat(1, 2) /= Amat(2, 1)) then stop "input matrice is not symmetric" end if do i = 1, 2 eigenvalue(i) = (-1.0d0*b + ((-1.0d0)**dble(i))*(b*b - 4.0d0*c)**(1.0d0/2.0d0))*(0.50d0) end do do i = 1, 2 if (Amat(1, 2) == 0) then cycle elseif (Amat(1, 2) /= 0) then phy = atan((eigenvalue(i) - Amat(1, 1))/Amat(1, 2)) do j = 1, 2 eigenvector(i, 1:2) = (/cos(phy), sin(phy)/) end do end if end do do i = 1, 2 eigenvector(i, :) = eigenvalue(i)*eigenvector(i, :) end do end subroutine eigen_2d !========================================================== function signmm(a) result(b) real(real64), intent(in)::a real(real64) b if (a > 0) then b = 1.0d0 elseif (a < 0) then b = -1.0d0 elseif (a == 0) then b = 0.0d0 else stop "ERROR: Invalid real(real64) in function_signm" end if end function signmm !========================================================== ! ################################################################ ! From 数値計算のためのFortran90/95プログラミング入門 単行本(ソフトカバー) – ! This function is not presented with GPL or any licenses. ! this function will be replaced by LAPACK. recursive function det_mat_real64(a, n) result(ret) integer(int32), intent(in) :: n real(real64), intent(in) :: a(n, n) real(real64) ret, b(n - 1, n - 1) integer(int32) i if (n > 1) then ret = 0.0d0 do i = 1, n b(1:i - 1, 1:n - 1) = a(1:i - 1, 2:n) b(i:n - 1, 1:n - 1) = a(i + 1:n, 2:n) ret = ret + (-1.0d0)**(i + 1) & *a(i, 1)*det_mat_real64(b, n - 1) end do else ret = a(1, 1) end if end function det_mat_real64 !===================================================================================== recursive function det_mat_complex64(a, n) result(ret) integer(int32), intent(in) :: n complex(real64), intent(in) :: a(n, n) complex(real64) ret, b(n - 1, n - 1) integer(int32) i if (n > 1) then ret = 0.0d0 do i = 1, n b(1:i - 1, 1:n - 1) = a(1:i - 1, 2:n) b(i:n - 1, 1:n - 1) = a(i + 1:n, 2:n) ret = ret + (-1.0d0)**(i + 1) & *a(i, 1)*det_mat_complex64(b, n - 1) end do else ret = a(1, 1) end if end function det_mat_complex64 !===================================================================================== !========================================================== recursive function det(a, n) result(det_v) integer(int32), intent(in) :: n real(real64), intent(in) :: a(n, n) real(real64) det_v, b(n - 1, n - 1) integer(int32) i if (n > 1) then det_v = 0.0d0 do i = 1, n b(1:i - 1, 1:n - 1) = a(1:i - 1, 2:n) b(i:n - 1, 1:n - 1) = a(i + 1:n, 2:n) det_v = det_v + (-1.0d0)**(i + 1) & *a(i, 1)*det(b, n - 1) end do else det_v = a(1, 1) end if end function det !===================================================================================== subroutine trans_rank_2(A, A_T) real(real64), intent(in)::A(:, :) real(real64), allocatable, intent(out)::A_T(:, :) integer(int32) n, m, i, j n = size(A, 1) m = size(A, 2) if (.not. allocated(A_T)) allocate (A_T(m, n)) do i = 1, n do j = 1, m A_T(j, i) = A(i, j) end do end do end subroutine trans_rank_2 !================================================================================== function trans1(A) result(A_T) real(real64), intent(in)::A(:) real(real64), allocatable::A_T(:, :) integer(int32) n, m, i, j n = size(A) if (.not. allocated(A_T)) allocate (A_T(1, n)) do i = 1, n A_T(1, i) = A(i) end do end function trans1 !================================================================================== function trans2(A) result(A_T) real(real64), intent(in)::A(:, :) real(real64), allocatable::A_T(:, :) integer(int32) n, m, i, j n = size(A, 1) m = size(A, 2) if (.not. allocated(A_T)) allocate (A_T(m, n)) do i = 1, n do j = 1, m A_T(j, i) = A(i, j) end do end do end function trans2 !================================================================================== subroutine inverse_rank_2(A, A_inv) real(real64), intent(in)::A(:, :) real(real64), allocatable::A_inv(:, :) real(real64) detA, detA_1 integer(int32) m, n m = size(A, 1) n = size(A, 2) if (.not. allocated(A_inv)) allocate (A_inv(m, n)) detA = det_mat(A, n) if (detA == 0.0d0) stop "ERROR: inverse, detA=0" detA_1 = 1.0d0/detA if (n == 2) then A_inv(1, 1) = detA_1*A(2, 2) A_inv(1, 2) = -detA_1*A(1, 2) A_inv(2, 1) = -detA_1*A(2, 1) A_inv(2, 2) = detA_1*A(1, 1) elseif (n == 3) then A_inv(1, 1) = detA_1*(A(2, 2)*A(3, 3) - A(2, 3)*A(3, 2)) A_inv(1, 2) = detA_1*(A(1, 3)*A(3, 2) - A(1, 2)*A(3, 3)) A_inv(1, 3) = detA_1*(A(1, 2)*A(2, 3) - A(1, 3)*A(2, 2)) A_inv(2, 1) = detA_1*(A(2, 3)*A(3, 1) - A(2, 1)*A(3, 3)) A_inv(2, 2) = detA_1*(A(1, 1)*A(3, 3) - A(1, 3)*A(3, 1)) A_inv(2, 3) = detA_1*(A(1, 3)*A(2, 1) - A(1, 1)*A(2, 3)) A_inv(3, 1) = detA_1*(A(2, 1)*A(3, 2) - A(2, 2)*A(3, 1)) A_inv(3, 2) = detA_1*(A(1, 2)*A(3, 1) - A(1, 1)*A(3, 2)) A_inv(3, 3) = detA_1*(A(1, 1)*A(2, 2) - A(1, 2)*A(2, 1)) else print *, "ERROR: Aij with i=j=", n, "/=2or3" end if end subroutine inverse_rank_2 !================================================================================== !================================================================================== function inverse(A) result(A_inv) real(real64), intent(in)::A(:, :) real(real64), allocatable::A_inv(:, :) real(real64) detA, detA_1 integer(int32) m, n m = size(A, 1) n = size(A, 2) if (.not. allocated(A_inv)) allocate (A_inv(m, n)) detA = det_mat(A, n) if (detA == 0.0d0) stop "ERROR: inverse, detA=0" detA_1 = 1.0d0/detA if (n == 2) then A_inv(1, 1) = detA_1*A(2, 2) A_inv(1, 2) = -detA_1*A(1, 2) A_inv(2, 1) = -detA_1*A(2, 1) A_inv(2, 2) = detA_1*A(1, 1) elseif (n == 3) then A_inv(1, 1) = detA_1*(A(2, 2)*A(3, 3) - A(2, 3)*A(3, 2)) A_inv(1, 2) = detA_1*(A(1, 3)*A(3, 2) - A(1, 2)*A(3, 3)) A_inv(1, 3) = detA_1*(A(1, 2)*A(2, 3) - A(1, 3)*A(2, 2)) A_inv(2, 1) = detA_1*(A(2, 3)*A(3, 1) - A(2, 1)*A(3, 3)) A_inv(2, 2) = detA_1*(A(1, 1)*A(3, 3) - A(1, 3)*A(3, 1)) A_inv(2, 3) = detA_1*(A(1, 3)*A(2, 1) - A(1, 1)*A(2, 3)) A_inv(3, 1) = detA_1*(A(2, 1)*A(3, 2) - A(2, 2)*A(3, 1)) A_inv(3, 2) = detA_1*(A(1, 2)*A(3, 1) - A(1, 1)*A(3, 2)) A_inv(3, 3) = detA_1*(A(1, 1)*A(2, 2) - A(1, 2)*A(2, 1)) else print *, "ERROR: Aij with i=j=", n, "/=2or3" end if end function inverse !================================================================================== subroutine tensor_exponential(A, expA, TOL, itr_tol) real(real64), intent(in)::A(:, :), TOL real(real64), allocatable, intent(inout)::expA(:, :) integer(int32), intent(in)::itr_tol real(real64), allocatable::increA(:, :) real(real64) increment, NN integer(int32) i, j, n if (.not. allocated(expA)) allocate (expA(size(A, 1), size(A, 2))) allocate (increA(size(A, 1), size(A, 2))) if (size(A, 1) /= size(A, 2)) stop "ERROR:tensor exp is not a square matrix" expA(:, :) = 0.0d0 do n = 1, size(expA, 1) expA(n, n) = 1.0d0 end do NN = 1.0d0 increA(:, :) = expA(:, :) do n = 1, itr_tol if (n > 1) then NN = NN*(NN + 1.0d0) end if increA(:, :) = matmul(increA, A) expA(:, :) = expA(:, :) + 1.0d0/NN*increA(:, :) increment = 0.0d0 do i = 1, size(A, 1) do j = 1, size(A, 2) increment = increment + 1.0d0/NN*increA(i, j)*increA(i, j) end do end do if (increment <= TOL) then exit else if (n >= itr_tol) then stop "tensor exponential is not converged" end if cycle end if end do deallocate (increA) end subroutine tensor_exponential !================================================================================== function identity_matrix(n) result(mat) integer(int32), intent(in) :: n ! rank real(real64) :: mat(n, n) integer(int32) :: i mat(:, :) = 0.0d0 do i = 1, n mat(i, i) = 1.0d0 end do end function !================================================================================== !================================================================================== function zero_matrix(n) result(mat) integer(int32), intent(in) :: n ! rank real(real64) :: mat(n, n) mat(:, :) = 0.0d0 end function !================================================================================== subroutine tensor_expo_der(A, expA_A, TOL, itr_tol) real(real64), intent(in)::A(:, :), TOL real(real64), allocatable, intent(inout)::expA_A(:, :, :, :) integer(int32), intent(in)::itr_tol real(real64), allocatable::increA_1(:, :), increA_2(:, :), increA_3(:, :, :, :), I_ij(:, :), A_inv(:, :) real(real64) increment, NN integer(int32) i, j, k, l, n, m, o if (.not. allocated(expA_A)) allocate (expA_A(size(A, 1), size(A, 1), size(A, 1), size(A, 1))) allocate (I_ij(size(A, 1), size(A, 1))) allocate (increA_1(size(A, 1), size(A, 1))) allocate (increA_2(size(A, 1), size(A, 1))) allocate (increA_3(size(A, 1), size(A, 1), size(A, 1), size(A, 1))) if (size(A, 1) /= size(A, 2)) stop "ERROR:tensor exp is not a square matrix" call inverse_rank_2(A, A_inv) I_ij(:, :) = 0.0d0 do n = 1, size(expA_A, 1) I_ij(n, n) = 1.0d0 end do NN = 1.0d0 do i = 1, size(A, 1) do j = 1, size(A, 1) do k = 1, size(A, 1) do l = 1, size(A, 1) expA_A(i, j, k, l) = I_ij(i, k)*I_ij(l, j) end do end do end do end do increA_1(:, :) = I_ij(:, :) increA_2(:, :) = I_ij(:, :) do n = 1, itr_tol if (n > 2) then NN = NN*(NN + 1.0d0) end if increA_1(:, :) = A_inv(:, :) increA_2(:, :) = matmul(increA_2, A) increA_3(:, :, :, :) = 0.0d0 do m = 1, n increA_1(:, :) = matmul(increA_1, A) increA_2(:, :) = matmul(increA_2, A_inv) do i = 1, size(A, 1) do j = 1, size(A, 1) do k = 1, size(A, 1) do l = 1, size(A, 1) increA_3(i, j, k, l) = increA_3(i, j, k, l) + increA_1(i, k)*increA_2(l, j) expA_A(i, j, k, l) = expA_A(i, j, k, l) + 1.0d0/NN*increA_3(i, j, k, l) end do end do end do end do end do do i = 1, size(A, 1) do j = 1, size(A, 1) do k = 1, size(A, 1) do l = 1, size(A, 1) increment = increment + 1.0d0/NN*increA_3(i, j, k, l) & *increA_3(i, j, k, l) & *increA_3(i, j, k, l) & *increA_3(i, j, k, l) end do end do end do end do if (increment <= TOL) then exit else if (n >= itr_tol) then stop "tensor exponential is not converged" end if cycle end if end do deallocate (increA_1, increA_2, increA_3, I_ij, A_inv) end subroutine tensor_expo_der !================================================================================== function GetNormRe(a) result(b) real(real64), intent(in)::a(:) real(real64) :: b b = dot_product(a, a) end function !================================================================================== function GetNormMatRe(a) result(b) real(real64), intent(in)::a(:, :) real(real64) :: b integer(int32) :: i, j b = 0 do i = 1, size(a, 1) do j = 1, size(a, 2) b = b + a(i, j)*a(i, j) end do end do end function !================================================================================== function trace_real64(a) result(b) real(real64), intent(in)::a(:, :) real(real64) :: b integer(int32) :: i, j b = 0 do i = 1, size(a, 1) b = b + a(i, i) end do end function !================================================================================== function trace_complex64(a) result(b) complex(real64), intent(in)::a(:, :) complex(real64) :: b integer(int32) :: i, j b = 0 do i = 1, size(a, 1) b = b + a(i, i) end do end function !================================================================================== !================================================================================== function sym(a, n) result(ret) real(real64), intent(in) :: a(:, :) real(real64) :: ret(n, n) integer(int32) :: i, n ret = 0.50d0*(a) + 0.50d0*transpose(a) end function !================================================================================== !================================================================================== function asym(a, n) result(ret) real(real64), intent(in) :: a(:, :) real(real64) :: ret(n, n) integer(int32) :: i, n ret = 0.50d0*(a) - 0.50d0*transpose(a) end function !================================================================================== function pi_value(n) result(res) integer(int32), intent(in)::n real(real64) :: ptr real(real64) :: an, bn, tn, pn real(real64) :: atr, btr, ttr real(real64) :: res integer(int32) :: i an = 1.0d0 bn = 1.0d0/sqrt(2.0d0) tn = 0.250d0 pn = 1.00d0 do i = 1, n atr = 0.50d0*(an + bn) btr = dsqrt(an*bn) ttr = tn - pn*(atr - an)*(atr - an) ptr = 2.0d0*pn an = atr bn = btr tn = ttr pn = ptr res = (atr + btr)*(atr + btr)/4.0d0/ttr end do end function !================================================================================== !================================================================================== pure function fstring_int(x) result(a) integer(int32), intent(in) :: x character(len=20):: b character(len=:), allocatable :: a write (b, *) x a = trim(adjustl(b)) end function !================================================================================== !================================================================================== pure function fstring_int64(x) result(a) integer(int64), intent(in) :: x character(len=40):: b character(len=:), allocatable :: a write (b, *) x a = trim(adjustl(b)) end function !================================================================================== !================================================================================== pure function fstring_logical(x) result(a) logical, intent(in) :: x character(len=5) :: a write (a, *) x end function !================================================================================== !================================================================================== pure function fstring_String(x) result(a) type(String_), intent(in) :: x character(len=:), allocatable :: a a = trim(x%all) end function !================================================================================== !================================================================================== pure function fstring_int_len(x, length) result(a) integer(int32), intent(in) :: x integer(int32), intent(in) :: length character(len=length) :: a if (x /= x .or. abs(x) >= HUGE(int32)) then a = "" return end if write (a, *) x a = adjustl(a) end function !================================================================================== !================================================================================== pure function fstring_real(x) result(a) real(real64), intent(in) :: x character(len=31):: b character(len=:), allocatable :: a if (x /= x .or. abs(x) >= HUGE(real64)) then a = "" return end if write (b, '(f0.7)') x a = trim(adjustl(b)) end function !================================================================================== !================================================================================== pure function fstring_real32(x) result(a) real(real32), intent(in) :: x character(len=20):: b character(len=:), allocatable :: a if (x /= x .or. abs(x) >= HUGE(real64)) then a = "" return end if write (b, '(f0.8)') x a = trim(adjustl(b)) end function !================================================================================== !================================================================================== pure function fstring_complex(x) result(a) complex(kind(0d0)), intent(in) :: x character(len=30):: b character(len=:), allocatable :: a if (x /= x .or. abs(x) >= HUGE(real64)) then a = "" return end if write (b, fmt='(F0.0,SP,F0.0,"i")') x a = trim(adjustl(b)) end function !================================================================================== !================================================================================== pure function fstring_real_len(x, length) result(a) real(real64), intent(in) :: x integer(int32), intent(in) :: length character(len=60) :: a character*40 :: form if (x /= x .or. abs(x) >= HUGE(real64)) then a = "" return end if write (a, '(f0.10)') x a = adjustl(a) end function !================================================================================== !================================================================================== function fint(ch) result(a) character(*), intent(in) :: ch integer(int32) :: a read (ch, *, err=1000) a return 1000 a = 0 end function !================================================================================== !================================================================================== function fint16(ch) result(a) character(*), intent(in) :: ch integer(int16) :: a read (ch, *, err=1001) a return 1001 a = 0 end function !================================================================================== !================================================================================== function fint32(ch) result(a) character(*), intent(in) :: ch integer(int32) :: a read (ch, *, err=1002) a return 1002 a = 0 end function !================================================================================== !================================================================================== function fint64(ch) result(a) character(*), intent(in) :: ch integer(int64) :: a read (ch, *, err=1003) a return 1003 a = 0 end function !================================================================================== !================================================================================== function freal(ch) result(a) character(*), intent(in) :: ch real(real64) :: a read (ch, *, err=1004) a return 1004 a = 0.0d0 end function !================================================================================== !================================================================================== function freal32(ch) result(a) character(*), intent(in) :: ch real(real32) :: a read (ch, *, err=1005) a return 1005 a = 0 end function !================================================================================== !================================================================================== function freal64(ch) result(a) character(*), intent(in) :: ch real(real64) :: a read (ch, *, err=1006) a return 1006 a = 0 end function !================================================================================== !================================================================================== function freal128(ch) result(a) character(*), intent(in) :: ch real(real64) :: a read (ch, *, err=1007) a return 1007 a = 0 end function !================================================================================== !================================================================================== function input_Int(default, option) result(val) integer(int32), intent(in) :: default integer(int32), optional, intent(in)::option integer(int32) :: val if (present(option)) then val = option else val = default end if end function !================================================================================== !================================================================================== function input_Real(default, option) result(val) real(real64), intent(in) :: default real(real64), optional, intent(in)::option real(real64) :: val if (present(option)) then val = option else val = default end if end function !================================================================================== !================================================================================== function input_Real32(default, option) result(val) real(real32), intent(in) :: default real(real32), optional, intent(in)::option real(real32) :: val if (present(option)) then val = option else val = default end if end function !================================================================================== !================================================================================== function input_Complex(default, option) result(val) complex(real64), intent(in) :: default complex(real64), optional, intent(in)::option complex(real64) :: val if (present(option)) then val = option else val = default end if end function !================================================================================== !================================================================================== function input_IntVec(default, option) result(val) integer(int32), intent(in) :: default(:) integer(int32), optional, intent(in)::option(:) integer(int32), allocatable :: val(:) integer(int32) :: n, m if (present(option)) then n = size(option, 1) allocate (val(n)) val(:) = option(:) else n = size(default, 1) allocate (val(n)) val(:) = default(:) end if end function !================================================================================== !================================================================================== function input_Realvec(default, option) result(val) real(real64), intent(in) :: default(:) real(real64), optional, intent(in)::option(:) real(real64), allocatable :: val(:) integer(int32) :: n, m if (present(option)) then n = size(option, 1) allocate (val(n)) val(:) = option(:) else n = size(default, 1) allocate (val(n)) val(:) = default(:) end if end function !================================================================================== !================================================================================== function input_IntArray(default, option) result(val) integer(int32), intent(in) :: default(:, :) integer(int32), optional, intent(in)::option(:, :) integer(int32), allocatable :: val(:, :) integer(int32) :: n, m if (present(option)) then n = size(option, 1) m = size(option, 2) allocate (val(n, m)) val(:, :) = option(:, :) else n = size(default, 1) m = size(default, 2) allocate (val(n, m)) val(:, :) = default(:, :) end if end function !================================================================================== !================================================================================== function input_RealArray(default, option) result(val) real(real64), intent(in) :: default(:, :) real(real64), optional, intent(in)::option(:, :) real(real64), allocatable :: val(:, :) integer(int32) :: n, m if (present(option)) then n = size(option, 1) m = size(option, 2) allocate (val(n, m)) val(:, :) = option(:, :) else n = size(default, 1) m = size(default, 2) allocate (val(n, m)) val(:, :) = default(:, :) end if end function !================================================================================== !================================================================================== function input_String(default, option) result(val) character(*), intent(in) :: default character(*), optional, intent(in)::option character(200) :: val if (present(option)) then val = option else val = default end if end function !================================================================================== !================================================================================== function input_logical(default, option) result(val) logical, intent(in) :: default logical, optional, intent(in)::option logical :: val if (present(option)) then val = option else val = default end if end function !================================================================================== function zeroif_Int(val, negative, positive) result(retval) integer(int32), intent(in)::val integer(int32) :: retval logical, optional, intent(in) :: negative, positive if (val /= val) then print *, "ERROR :: MAthClass >> zeroif_Int is invalid" end if retval = val if (present(negative)) then if (negative .eqv. .true.) then if (val < 0) then retval = 0 end if end if end if if (present(positive)) then if (positive .eqv. .true.) then if (val > 0) then retval = 0 end if end if end if end function function zeroif_Real(val, negative, positive) result(retval) real(real64), intent(in)::val real(real64) :: retval logical, optional, intent(in) :: negative, positive if (val /= val) then print *, "ERROR :: MAthClass >> zeroif_Int is invalid" end if retval = val if (present(negative)) then if (negative .eqv. .true.) then if (val < 0.0d0) then retval = 0.0d0 end if end if end if if (present(positive)) then if (positive .eqv. .true.) then if (val > 0.0d0) then retval = 0.0d0 end if end if end if end function ! ######################################################## subroutine removeWord_String(str, keyword, itr, Compare) character(*), intent(inout)::str character(*), intent(in)::keyword integer(int32) :: len_total, len_kw, i, j, n, itr_max integer(int32), optional, intent(in)::itr logical, optional, intent(in)::Compare logical :: bk if (present(Compare)) then if (Compare .eqv. .true.) then print *, "Before :: ", str end if end if itr_max = input(default=1, option=itr) bk = .false. len_total = len(str) len_kw = len(keyword) do i = 1, itr_max n = index(str, keyword) do j = n, n + len_kw str(j:j) = " " end do if (n == 0) then exit end if end do if (present(Compare)) then if (Compare .eqv. .true.) then print *, "After :: ", str end if end if end subroutine ! ######################################################## ! ######################################################## function Invariant_I1(sigma) result(I1) real(real64), intent(in) :: sigma(:, :) real(real64) :: I1 integer(int32) :: i, j I1 = 0.0d0 do i = 1, size(sigma, 1) I1 = I1 + sigma(i, i) end do end function ! ######################################################## ! ######################################################## function Invariant_J2(sigma) result(J2) real(real64), intent(in) :: sigma(:, :) real(real64) :: I1, J2, delta(3, 3), M_d(3, 3) integer(int32) :: i, j delta(:, :) = 0.0d0 delta(1, 1) = 1.0d0 delta(2, 2) = 1.0d0 delta(3, 3) = 1.0d0 I1 = Invariant_I1(sigma) M_d(:, :) = sigma(:, :) - I1/3.0d0*delta(:, :) J2 = 0.0d0 do i = 1, size(sigma, 1) do j = 1, size(sigma, 1) J2 = J2 + 0.50d0*M_d(i, j)*M_d(i, j) end do end do end function ! ######################################################## ! ######################################################## function Invariant_J3(sigma) result(J3) real(real64), intent(in) :: sigma(:, :) real(real64) :: I1, J3, delta(3, 3), M_d(3, 3) integer(int32) :: i, j, k delta(:, :) = 0.0d0 delta(1, 1) = 1.0d0 delta(2, 2) = 1.0d0 delta(3, 3) = 1.0d0 I1 = Invariant_I1(sigma) M_d(:, :) = sigma(:, :) - I1/3.0d0*delta(:, :) J3 = 0.0d0 do i = 1, size(sigma, 1) do j = 1, size(sigma, 1) do k = 1, size(sigma, 1) J3 = J3 + 1.0d0/3.0d0*M_d(i, j)*M_d(j, k)*M_d(k, i) end do end do end do end function ! ######################################################## ! ######################################################## function Invariant_theta(sigma) result(theta) real(real64), intent(in) :: sigma(:, :) real(real64) :: I1, J2, J3, delta(3, 3), M_d(3, 3), theta integer(int32) :: i, j, k delta(:, :) = 0.0d0 delta(1, 1) = 1.0d0 delta(2, 2) = 1.0d0 delta(3, 3) = 1.0d0 J2 = Invariant_J2(sigma) J3 = Invariant_J3(sigma) theta = 1.0d0/3.0d0*asin(-3.0d0*sqrt(3.0d0)*0.50d0*J3/J2/sqrt(J2)) end function ! ######################################################## ! ######################################################## function inv_mod(a_in, m_in, ItrMax) result(x) integer(int32), intent(in) :: a_in, m_in integer(int32), optional, intent(in) :: ItrMax integer(int32) :: d, q, t, Kmat_n(2, 2), Kmat_npp(2, 2), k, itr_tol, r0, r1, r2, i, x, y, m0 integer(int32) :: a, m a = a_in m = m_in itr_tol = input(default=10000, option=ItrMax) ! inverse modula by Extended Euclidean algorithm ! d = e^-1 (mod (lambda)) ! d*e = 1 (mod (lambda)) ! one integer q ! d*e - q*lambda = 1, e, lambda are known, d, q are unknown. ! get d, q by extended Euclidean algorithm ! gcd(e, lambda) = 1 !Kmat_npp(1,1)=1 !Kmat_npp(1,2)=0 !Kmat_npp(2,1)=0 !Kmat_npp(2,2)=1 !r0=e !r1=lambda !do i=1, itr_tol ! r2=mod(r0,r1) ! if(r2==0)then ! print *, "gcd of ",e," and",lambda,"is", r1 ! exit ! endif ! k=(r0-r2)/r1 ! Kmat_n(1,1)=0 ! Kmat_n(1,2)=1 ! Kmat_n(2,1)=1 ! Kmat_n(2,2)=-k ! a=matmul(Kmat_npp,Kmat_n) ! Kmat_npp=a ! print *, r0,"=",k,"*",r1,"+",r2 ! r0=r1 ! r1=r2 !enddo !d = Kmat_npp(1,2) !print *, "Kmat_npp=",Kmat_npp ! cited by https://www.geeksforgeeks.org/multiplicative-inverse-under-modulo-m/ m0 = m y = 0 x = 1 if (gcd(a, m) /= 1) then a = mod(a, m) do x = 1, m if (mod(a*x, m) == 1) then return end if end do end if if (m == 1) then return end if do i = 1, itr_tol if (a > 1) then q = (a - mod(a, m))/m t = m m = mod(a, m) a = t t = y y = x - q*y x = t else exit end if end do if (x < 0) then x = x + m0 end if end function ! ######################################################## ! ######################################################## function gcd(a, b, ItrMax) result(c) integer(int32), intent(in) :: a, b integer(int32), optional, intent(in) :: ItrMax integer(int32) :: i, r0, r1, r2, k, itr_tol, c c = 1 itr_tol = input(default=10000, option=ItrMax) r0 = a r1 = b do i = 1, itr_tol r2 = mod(r0, r1) if (r2 == 0) then !print *, "gcd of ",a," and",b,"is", r1 exit end if k = (r0 - r2)/r1 !print *, r0,"=",k,"*",r1,"+",r2 r0 = r1 r1 = r2 end do c = r1 end function ! ######################################################## ! ######################################################## function lcm(a, b, ItrMax) result(c) integer(int32), intent(in) :: a, b integer(int32), optional, intent(in) :: ItrMax integer(int32) :: i, r0, r1, r2, k, itr_tol, c itr_tol = input(default=10000, option=ItrMax) r0 = a r1 = b do i = 1, itr_tol r2 = mod(r0, r1) if (r2 == 0) then !print *, "gcd of ",a," and",b,"is", r1 exit end if k = (r0 - r2)/r1 !print *, r0,"=",k,"*",r1,"+",r2 r0 = r1 r1 = r2 end do c = a*b/r1 end function ! ######################################################## ! ######################################################## function convertStringToInteger(message) result(ret) character(*), intent(in):: message character(1) :: x character(2*len(message)) :: ret integer(int32) :: i ret = "" !allocate(ret(len(message)*2 ) ) do i = 1, len(message) x = message(i:i) select case (x) case (" ") cycle case ("a", "A") ret(2*i - 1:2*i) = "01" case ("b", "B") ret(2*i - 1:2*i) = "02" case ("c", "C") ret(2*i - 1:2*i) = "03" case ("d", "D") ret(2*i - 1:2*i) = "04" case ("e", "E") ret(2*i - 1:2*i) = "05" case ("f", "F") ret(2*i - 1:2*i) = "06" case ("g", "G") ret(2*i - 1:2*i) = "07" case ("h", "H") ret(2*i - 1:2*i) = "08" case ("i", "I") ret(2*i - 1:2*i) = "09" case ("j", "J") ret(2*i - 1:2*i) = "10" case ("k", "K") ret(2*i - 1:2*i) = "11" case ("l", "L") ret(2*i - 1:2*i) = "12" case ("m", "M") ret(2*i - 1:2*i) = "13" case ("n", "N") ret(2*i - 1:2*i) = "14" case ("o", "O") ret(2*i - 1:2*i) = "15" case ("p", "P") ret(2*i - 1:2*i) = "16" case ("q", "Q") ret(2*i - 1:2*i) = "17" case ("r", "R") ret(2*i - 1:2*i) = "18" case ("s", "S") ret(2*i - 1:2*i) = "19" case ("t", "T") ret(2*i - 1:2*i) = "20" case ("u", "U") ret(2*i - 1:2*i) = "21" case ("v", "V") ret(2*i - 1:2*i) = "22" case ("w", "W") ret(2*i - 1:2*i) = "23" case ("x", "X") ret(2*i - 1:2*i) = "24" case ("y", "Y") ret(2*i - 1:2*i) = "25" case ("z", "Z") ret(2*i - 1:2*i) = "26" end select end do end function ! ######################################################## ! ######################################################## function convertIntegerToString(message) result(ret) character(*), intent(in):: message character(2) :: x character(len(message)) :: ret integer(int32) :: i ret = "" !allocate(ret(len(message)*2 ) ) do i = 1, len(message) x(1:2) = message(2*i - 1:2*i) select case (x) case ("99") cycle case (" ") cycle case ("01") ret(i:i) = "a" case ("02") ret(i:i) = "b" case ("03") ret(i:i) = "c" case ("04") ret(i:i) = "d" case ("05") ret(i:i) = "e" case ("06") ret(i:i) = "f" case ("07") ret(i:i) = "g" case ("08") ret(i:i) = "h" case ("09") ret(i:i) = "i" case ("10") ret(i:i) = "j" case ("11") ret(i:i) = "k" case ("12") ret(i:i) = "l" case ("13") ret(i:i) = "m" case ("14") ret(i:i) = "n" case ("15") ret(i:i) = "o" case ("16") ret(i:i) = "p" case ("17") ret(i:i) = "q" case ("18") ret(i:i) = "r" case ("19") ret(i:i) = "s" case ("20") ret(i:i) = "t" case ("21") ret(i:i) = "u" case ("22") ret(i:i) = "v" case ("23") ret(i:i) = "w" case ("24") ret(i:i) = "x" case ("25") ret(i:i) = "y" case ("26") ret(i:i) = "z" end select end do end function ! ######################################################## ! ######################################################## subroutine rsa_keygen(prime1, prime2, seed, id_rsa, id_rsa_pub) integer(int32), intent(in) :: prime1, prime2, seed integer(int32), intent(out) :: id_rsa(2), id_rsa_pub(2) integer(int32) :: n, e, lambda, d, p, q p = prime1 q = prime2 n = p*q lambda = (p - 1)*(q - 1)/gcd(p - 1, q - 1) !print *, "lambda=",lambda id_rsa_pub(1) = n id_rsa_pub(2) = seed id_rsa(1) = n id_rsa(2) = inv_mod(seed, lambda) !get d print *, "#######################################################" print *, "Encrypted by RSA algorithm, public keys " print *, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" print *, "Multiplication of two prime numbers is ", id_rsa_pub(1) print *, "Seed value (1 < seed < ", id_rsa_pub(1), ") is", id_rsa_pub(2) print *, "Notice:: message should be (1 < seed < ", id_rsa_pub(1), ")." print *, "#######################################################" end subroutine ! ######################################################## ! ######################################################## function rsa_encrypt(id_rsa_pub, message) result(ciphertext) integer(int32), intent(in) ::id_rsa_pub(2), message integer(int32) :: ciphertext, i ciphertext = 1 do i = 1, id_rsa_pub(2) ciphertext = mod(ciphertext*message, id_rsa_pub(1)) end do end function ! ######################################################## ! ######################################################## function rsa_decrypt(id_rsa, ciphertext) result(message) integer(int32), intent(in) ::id_rsa(2), ciphertext integer(int32) :: d, n, e, message, i message = 1 do i = 1, id_rsa(2) message = mod(message*ciphertext, id_rsa(1)) end do end function ! ######################################################## function IsItNumber(char) result(res) character(*), intent(inout) :: char logical :: res integer :: i character(1) :: firstchar res = .false. ! search all firstchar = trim(adjustl(char(1:1))) if (firstchar == "1") then res = .true. return elseif (firstchar == "2") then res = .true. return elseif (firstchar == "3") then res = .true. return elseif (firstchar == "4") then res = .true. return elseif (firstchar == "5") then res = .true. return elseif (firstchar == "6") then res = .true. return elseif (firstchar == "7") then res = .true. return elseif (firstchar == "8") then res = .true. return elseif (firstchar == "9") then res = .true. return elseif (firstchar == "0") then res = .true. return elseif (firstchar == ".") then res = .true. return else return end if end function IsItNumber ! BitInversion !recursive function BitInversion(i,numBit) result(ret) ! integer(int32),intent(in) :: i ! integer(int32),intent(in) :: numBit ! ! if(numBit==1)then ! ! 1 Bit 0 or 1 ! ! elseif(numBit==2)then ! elseif(numBit==3)then ! if(numBit > 3) then ! endif ! !end function ! Window functions function RectangularWindow(original_data, Width) result(ret) real(real64), intent(in) :: original_data(:) integer(int32), intent(in) :: Width real(real64), allocatable :: ret(:) integer(int32) :: i, j, n allocate (ret(size(original_data))) do i = 1, size(original_data) n = 0 do j = -Width/2, Width/2 if (i + j > size(original_data) .or. i + j < 1) cycle n = n + 1 ret(i) = original_data(i) + original_data(i + j) end do ret(i) = ret(i)/dble(n) end do end function function DigitalWindow(original_data) result(ret) real(real64), intent(in) :: original_data(:) real(real64), allocatable :: ret(:) integer(int32) :: i, j, n allocate (ret(size(original_data))) do i = 2, size(original_data) - 1 ret(i) = 0.250d0*original_data(i - 1) + 0.50d0*original_data(i) + & 0.250d0*original_data(i + 1) end do end function function HanningWindow(Width, DataSize) result(ret) integer(int32), intent(in) :: Width, DataSize real(real64) :: ret(DataSize) type(Math_) :: math integer(int32) :: i print *, "[CAUTION] EXPERIMENTAL!" ret = 0.0d0 do i = 1, width/2 ret(DataSize/2 - i) & = 0.50d0 - 0.50d0*cos(2.0d0*Math%PI*i/(Width/2)) ret(DataSize/2 + i) & = 0.50d0 - 0.50d0*cos(2.0d0*Math%PI*i/(Width/2)) end do end function function HammingWindow(Width, DataSize) result(ret) integer(int32), intent(in) :: Width, DataSize real(real64) :: ret(DataSize) type(Math_) :: math integer(int32) :: i print *, "[CAUTION] EXPERIMENTAL!" ret = 0.0d0 do i = 1, width/2 ret(DataSize/2 - i) & = 0.540d0 - 0.46d0*cos(2.0d0*Math%PI*i/(Width/2)) ret(DataSize/2 + i) & = 0.540d0 - 0.46d0*cos(2.0d0*Math%PI*i/(Width/2)) end do end function ! ####################################################################### function log2(x) result(ret) real(real64), intent(in) :: x real(real64) :: ret ret = log(x)/log(2.0d0) end function ! ####################################################################### ! ####################################################################### pure function day(unit) result(ret) character(*), intent(in):: unit real(real64) :: ret if (unit(1:1) == "S" .or. unit(1:1) == "s") then ! day to second ret = 24.0d0*60.0d0*60.0d0 return end if if (unit(1:1) == "M" .or. unit(1:1) == "m") then ! day to minutes ret = 24.0d0*60.0d0 return end if if (unit(1:1) == "H" .or. unit(1:1) == "h") then ! hour to minutes ret = 24.0d0 return end if if (unit(1:1) == "D" .or. unit(1:1) == "d") then ! day to minutes ret = 1.0d0 return end if if (unit(1:1) == "Y" .or. unit(1:1) == "y") then ! day to year ret = 1.0d0/365.0d0 return end if end function ! ####################################################################### ! ####################################################################### pure recursive function factorialInt32(n) result(ret) integer(int32), intent(in) :: n integer(int64) :: i, ret ret = 1 do i = 1, n ret = ret*i end do end function ! ####################################################################### ! ####################################################################### pure recursive function factorialReal64(n) result(ret) real(real64), intent(in) :: n real(real64) :: ret integeR(int32) :: i ret = 1.0d0 do i = 1, int(n) ret = ret*dble(i) end do end function ! ####################################################################### pure function comb(n, r) result(ret) integer(int32), intent(in) :: n, r real(real64) :: ret integer(int32) :: i real(real64), allocatable :: buf1(:), buf2(:), buf3(:) if (n - r < 0) then ret = 0.0d0 return end if if (n <= 10) then ret = factorial(n)/(factorial(r)*factorial(n - r)) else allocate (buf1(n), buf2(n), buf3(n)) do concurrent(i=1:n) buf1(i) = i end do do concurrent(i=1:r) buf2(i) = i end do do concurrent(i=1:n - r) buf3(i) = i end do do concurrent(i=1:r) buf1(i) = buf1(i)/buf2(i) end do do concurrent(i=1:n - r) buf1(i) = buf1(i)/buf3(i) end do ret = 1.0d0 do i = 1, n ret = ret*buf1(i) end do ret = dble(nint(ret)) !by array end if end function function stringFromChar(charval) result(ret) character(*), intent(in):: charval type(String_) :: ret ret = charval end function ! ####################################################################### pure function zfill(intval, n) result(ret) integer(int32), intent(in) :: intval, n character(n) :: ret !character(:),allocatable :: fmt character(len=20) :: zfill_fmt character(len=20):: b write (b, *) n zfill_fmt = '(I'//trim(adjustl(b))//'.'//trim(adjustl(b))//')' write (ret(1:n), trim(adjustl(zfill_fmt))) intval end function ! ######################################################################## pure function imaginary_partComplex64(complexValue) result(imgpart) complex(real64), intent(in) :: complexValue real(real64) :: imgpart type(Math_) :: math imgpart = real(complexvalue*math%i) end function ! ######################################################################## ! ######################################################################## pure function imaginary_partComplex32(complexValue) result(imgpart) complex(real32), intent(in) :: complexValue real(real32) :: imgpart type(Math_) :: math imgpart = -real(complexvalue*math%i) end function ! ######################################################################## function hilbert(wave) result(h_top_wave) complex(real64), intent(in) :: wave(:) complex(real64), allocatable :: h_top_wave(:), spectre(:) spectre = fft(wave) spectre(1:size(spectre)/2) = 2.0d0*spectre(1:size(spectre)/2) spectre(size(spectre)/2 + 1:) = 0.0d0 h_top_wave = ifft(spectre) end function ! ######################################################################## function short_time_FFT(wave, frame) result(spectre) complex(real64), intent(in) :: wave(:) complex(real64), allocatable :: spectre(:, :) integer(int32), intent(in) :: frame integer(int32) :: i, from, to ! short-time FFT for n=frame length allocate (spectre(size(wave), 2*frame)) !$OMP parallel do private(from,to) do i = 1, size(wave) from = i - frame to = i + frame - 1 if (from < frame .or. to > size(wave) - frame) then cycle end if spectre(i, :) = fft(wave(i - frame:i + frame - 1)) end do !$OMP end parallel do end function ! ######################################################################## ! ######################################################################## pure function RickerFunctionReal64(t, sigma, center) result(ft) real(real64), intent(in) :: t, sigma real(real64), optional, intent(in) :: center type(Math_) :: math real(real64) ::ft128 real(real64) :: ft, b if (present(center)) then b = center else b = 0.0d0 end if ft128 = 2.0d0/(sqrt(3.0d0*sigma)*math%pi**(0.25))* & (1.0d0 - ((t - b)/sigma)*((t - b)/sigma))*exp(-(t - b)*(t - b)/2.0d0/sigma/sigma) ft = dble(ft128) end function ! ######################################################################## ! ######################################################################## pure function RickerFunctionReal64Vector(t, sigma, center) result(ft) real(real64), intent(in) :: t(:), sigma real(real64), optional, intent(in) :: center type(Math_) :: math real(real64) ::ft128 integer(int32) :: i real(real64), allocatable :: ft(:) allocate (ft(size(t))) do i = 1, size(t) ft(i) = RickerFunction(t=t(i), sigma=sigma, center=center) end do end function ! ######################################################################## ! ######################################################## real(real64) function derivative_scalar(func, x, eps) ! >>> Define func() interface real(real64) function func(x) use iso_fortran_env real(real64), intent(in) :: x end function end interface ! <<< ! >>> arg real(real64), intent(in) :: x real(real64), optional, intent(in) :: eps ! <<< real(real64) :: eps_val = dble(1.0e-4) if (present(eps)) then eps_val = eps end if ! >>> operation ! numerical derivative derivative_scalar = (func(x + eps_val) - func(x - eps_val))/(2.0d0*eps_val) ! <<< end function ! ######################################################## function derivative_vector(func, x, dim_num, eps) result(ret) integer(int32), intent(in) :: dim_num ! >>> Define func() interface function func(x) result(ret) use iso_fortran_env real(real64), intent(in) :: x(:) real(real64), allocatable :: ret(:) end function end interface ! <<< ! >>> arg real(real64), intent(in) :: x(1:dim_num) real(real64), optional, intent(in) :: eps ! <<< ! >>> output real(real64), allocatable :: ret(:) ! <<< real(real64) :: x_f(1:dim_num) real(real64) :: x_b(1:dim_num) real(real64) :: eps_val = dble(1.0e-4) if (present(eps)) then eps_val = eps end if ret = x x_f = x x_f(:) = x_f(:) + eps_val x_b = x x_b(:) = x_b(:) - eps_val ! >>> operation ! numerical derivative ret = (func(x_f) - func(x_b))/(2.0d0*eps_val) ! <<< end function ! ######################################################## real(real64) function polynomial(x, params) real(real64), intent(in) :: x real(real64), intent(in) :: params(:) integer(int32) :: i, n, order_ n = size(params) ! (n-1)-order polynomial polynomial = 0.0d0 order_ = 0 do i = n - 1, 0, -1 order_ = order_ + 1 polynomial = polynomial + params(order_)*(x**i) end do end function ! ########################################################### real(real64) function sigmoid(x, params) real(real64), intent(in) :: x, params(:) if (size(params) == 0) then sigmoid = 1.0d0/(1.0d0 + exp(-(x))) elseif (size(params) == 1) then sigmoid = 1.0d0/(1.0d0 + exp(-params(1)*(x))) elseif (size(params) == 2) then sigmoid = 1.0d0/(1.0d0 + exp(-params(1)*(x - params(2)))) else sigmoid = 1.0d0/(1.0d0 + exp(-params(1)*(x - params(2))))*params(3) end if end function ! ########################################################### ! ########################################################### real(real64) function logit(x, params) real(real64), intent(in) :: x, params(:) logit = log(x/(1 - x)) end function ! ########################################################### function int_from_logical(logical_value) result(ret) logical, intent(in) :: logical_value integer(int32) :: ret if (logical_value) then ret = 0 else ret = 1 end if end function function int_from_logical_vector(logical_value) result(ret) logical, intent(in) :: logical_value(:) integer(int32), allocatable :: ret(:) integer(int32) :: i allocate (ret(size(logical_value))) do i = 1, size(ret) if (logical_value(i)) then ret(i) = 0 else ret(i) = 1 end if end do end function ! ########################################################### !function arg_complex64(z) result(theta) ! complex(real64),intent(in) :: z ! real(real64) :: theta, x, y ! type(Math_) :: math ! ! x = dble(z) ! y = imag(z) ! ! if(x>0.0d0)then ! theta = atan(y/x) ! elseif(x<0.0d0 .and. y>=0.0d0)then ! theta = atan(y/x) + math%pi ! elseif(x<0.0d0 .and. y<0.0d0)then ! theta = atan(y/x) - math%pi ! elseif(x==0.0d0 .and. y>0.0d0)then ! theta = math%pi/2.0d0 ! elseif(x==0.0d0 .and. y<0.0d0)then ! theta = - math%pi/2.0d0 ! else ! theta = 0.0d0 ! endif !end function ! ########################################################### function matrix_exponential_real64(mat, order) result(ret) real(real64), intent(in) :: mat(:, :) integer(int32), intent(in) :: order real(real64), allocatable :: ret(:, :), d_ret(:, :) integer(int32) :: i, k ret = 0.0d0*mat d_ret = 0.0d0*mat do i = 1, size(ret, 1) d_ret(i, i) = 1.0d0 end do ! k = 0 ret = d_ret k = 0 do k = k + 1 d_ret = 1.0d0/dble(k)*matmul(d_ret, mat) ret = ret + d_ret if (k + 1 > order) exit end do end function ! ########################################################### function Bessel_J0_complex(z) result(ret) complex(real64), intent(in) :: z complex(real64) :: ret, dret integer(int32) :: k !ret = 1.0d0-z*z/4+(z**4)/64.0d0 ! + O(x^6) ret = 0.0d0 dret = 1.0d0 do k = 1, 30 ret = ret + dret dret = dret/dble(k)/dble(k)*(-1.0d0/4.0d0)*z*z if (abs(dret) < 1.0e-16) exit end do end function ! ########################################################### ! ########################################################### function Bessel_J1_complex(z) result(ret) complex(real64), intent(in) :: z complex(real64) :: ret, dret integer(int32) :: k !ret = z/2.0d0+(z**3)/16.0d0+(z**5)/384.0d0 ! + O(x^6) ret = 0.0d0 dret = 1.0d0/2.0d0*z do k = 1, 30 ret = ret + dret dret = dret/dble(k)/dble(k + 1)*(-1.0d0)*(1.0d0/4.0d0)*z*z if (abs(dret) < 1.0e-16) exit end do end function ! ########################################################### ! ########################################################### recursive subroutine heapsort_int32_array(array,order,exec_row_sort) integer(int32),intent(inout) :: array(:,:) integer(int32),allocatable,optional,intent(inout) :: order(:) logical,optional,intent(in) :: exec_row_sort integer(int32),allocatable :: buf(:),colbuf(:),arraybuf(:,:),new_order(:),orderbuf(:) integer(int32),allocatable :: from_to(:,:) integer(int32) :: i, j, from, to, k, n_from_to logical :: row_sort !if(present(order) )then ! if(.not.allocated(order))then ! order = [(i,i=1,size(array,1))] ! endif !endif row_sort = .true. if(present(exec_row_sort) )then row_sort = exec_row_sort endif ! 各行をソート allocate(buf(size(array,2)) ) if(size(array,2)>2 .and. row_sort)then !$OMP parallel do private(buf) shared(array) !do concurrent(i=1:size(array,1)) do i=1,size(array,1) buf(:) = array(i,:) ! 行内入れ替えではorderは変えず call heapsortInt32(n=size(buf),array=buf) array(i,:) = buf(:) end do !$OMP end parallel do end if ! 1回1列目でソート colbuf = array(:,1) new_order = [(i,i=1,size(colbuf))] call heapsortInt32Int32(n=size(colbuf),array=colbuf,val=new_order) ! new_orderによってorderを並び替え arraybuf = array array(:,:) = arraybuf(new_order(:),:) if(present(order) )then order(:) = order(new_order(:)) endif ! debug !return if(size(array,2)==1 )then return endif ! もしcolumが2以上あれば,再帰 n_from_to = 0 j=1 do if(j>=size(array,1) )exit from = j do to=j+1,size(array,1) if(array(from,1)==array(to,1))then cycle else exit endif end do if(to-from>1)then if(size(array,2)>1 )then !arraybuf = array(from:to-1,2:) !orderbuf = order(from:to-1) ! !call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! !array(from:to-1,2:) = arraybuf(:,:) !order(from:to-1) = orderbuf(:) n_from_to = n_from_to + 1 j = to cycle endif endif j = j + 1 end do allocate(from_to(n_from_to,2)) n_from_to = 0 j=1 do if(j>=size(array,1) )exit from = j do to=j+1,size(array,1) if(array(from,1)==array(to,1))then cycle else exit endif end do if(to-from>1)then if(size(array,2)>1 )then !arraybuf = array(from:to-1,2:) !orderbuf = order(from:to-1) ! !call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! !array(from:to-1,2:) = arraybuf(:,:) !order(from:to-1) = orderbuf(:) n_from_to = n_from_to + 1 from_to(n_from_to,1) = from from_to(n_from_to,2) = to j = to cycle endif endif j = j + 1 end do !$OMP parallel do private(from,to,arraybuf,orderbuf) shared(array,order) do n_from_to=1,size(from_to,1) from = from_to(n_from_to,1) to = from_to(n_from_to,2) arraybuf = array(from:to-1,2:) if(present(order) )then orderbuf = order(from:to-1) endif call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) array(from:to-1,2:) = arraybuf(:,:) if(present(order) )then order(from:to-1) = orderbuf(:) endif enddo !$OMP end parallel do ! >> non-parallelization !j=1 !do ! if(j>=size(array,1) )exit ! from = j ! do to=j+1,size(array,1) ! if(array(from,1)==array(to,1))then ! cycle ! else ! exit ! endif ! end do ! ! ! if(to-from>1)then ! if(size(array,2)>1 )then ! ! arraybuf = array(from:to-1,2:) ! orderbuf = order(from:to-1) ! ! call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! ! array(from:to-1,2:) = arraybuf(:,:) ! order(from:to-1) = orderbuf(:) ! j = to ! cycle ! endif ! endif ! j = j + 1 !end do end subroutine ! ########################################################### ! ########################################################### recursive subroutine heapsort_real64_array(array,order,exec_row_sort) real(real64),intent(inout) :: array(:,:) integer(int32),allocatable,optional,intent(inout) :: order(:) logical,optional,intent(in) :: exec_row_sort real(real64),allocatable :: buf(:),colbuf(:),arraybuf(:,:) integer(int32),allocatable :: new_order(:),orderbuf(:) integer(int32),allocatable :: from_to(:,:) integer(int32) :: i, j, from, to, k, n_from_to logical :: row_sort !if(present(order) )then ! if(.not.allocated(order))then ! order = [(i,i=1,size(array,1))] ! endif !endif row_sort = .true. if(present(exec_row_sort) )then row_sort = exec_row_sort endif ! 各行をソート allocate(buf(size(array,2)) ) if(size(array,2)>2 .and. row_sort)then !$OMP parallel do private(buf) shared(array) !do concurrent(i=1:size(array,1)) do i=1,size(array,1) buf(:) = array(i,:) ! 行内入れ替えではorderは変えず call heapsortReal64(n=size(buf),array=buf) array(i,:) = buf(:) end do !$OMP end parallel do end if ! 1回1列目でソート colbuf = array(:,1) new_order = [(i,i=1,size(colbuf))] call heapsortReal64Int32(n=size(colbuf),array=colbuf,val=new_order) ! new_orderによってorderを並び替え arraybuf = array array(:,:) = arraybuf(new_order(:),:) if(present(order) )then order(:) = order(new_order(:)) endif ! debug !return if(size(array,2)==1 )then return endif ! もしcolumが2以上あれば,再帰 n_from_to = 0 j=1 do if(j>=size(array,1) )exit from = j do to=j+1,size(array,1) if(array(from,1)==array(to,1))then cycle else exit endif end do if(to-from>1)then if(size(array,2)>1 )then !arraybuf = array(from:to-1,2:) !orderbuf = order(from:to-1) ! !call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! !array(from:to-1,2:) = arraybuf(:,:) !order(from:to-1) = orderbuf(:) n_from_to = n_from_to + 1 j = to cycle endif endif j = j + 1 end do allocate(from_to(n_from_to,2)) n_from_to = 0 j=1 do if(j>=size(array,1) )exit from = j do to=j+1,size(array,1) if(array(from,1)==array(to,1))then cycle else exit endif end do if(to-from>1)then if(size(array,2)>1 )then !arraybuf = array(from:to-1,2:) !orderbuf = order(from:to-1) ! !call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! !array(from:to-1,2:) = arraybuf(:,:) !order(from:to-1) = orderbuf(:) n_from_to = n_from_to + 1 from_to(n_from_to,1) = from from_to(n_from_to,2) = to j = to cycle endif endif j = j + 1 end do !$OMP parallel do private(from,to,arraybuf,orderbuf) shared(array,order) do n_from_to=1,size(from_to,1) from = from_to(n_from_to,1) to = from_to(n_from_to,2) arraybuf = array(from:to-1,2:) if(present(order) )then orderbuf = order(from:to-1) endif call heapsort_real64_array(arraybuf,orderbuf,exec_row_sort=.false.) array(from:to-1,2:) = arraybuf(:,:) if(present(order) )then order(from:to-1) = orderbuf(:) endif enddo !$OMP end parallel do ! >> non-parallelization !j=1 !do ! if(j>=size(array,1) )exit ! from = j ! do to=j+1,size(array,1) ! if(array(from,1)==array(to,1))then ! cycle ! else ! exit ! endif ! end do ! ! ! if(to-from>1)then ! if(size(array,2)>1 )then ! ! arraybuf = array(from:to-1,2:) ! orderbuf = order(from:to-1) ! ! call heapsort_int32_array(arraybuf,orderbuf,exec_row_sort=.false.) ! ! array(from:to-1,2:) = arraybuf(:,:) ! order(from:to-1) = orderbuf(:) ! j = to ! cycle ! endif ! endif ! j = j + 1 !end do end subroutine ! ########################################################### ! ########################################################### subroutine sort_and_remove_duplication_int32(array,order) integer(int32),allocatable,intent(inout) :: array(:,:) integer(int32),allocatable,optional,intent(inout) :: order(:) integer(int32),allocatable :: buf(:),arraybuf(:,:),orderbuf(:) integer(int32) :: i,j,offset,count_minus_one,itr offset = minval(array) array = array - offset + 1 call heapsort(array,order) do i=1,size(array,1) buf = array(i,:) do j=i+1,size(array,1)-1 if( maxval(abs(buf(:)-array(j,:)))==0)then array(i,:) = -1 array(j,:) = -1 else exit endif enddo end do count_minus_one = 0 do i=1,size(array,1) if(array(i,1)==-1 )then count_minus_one = count_minus_one + 1 endif enddo arraybuf = array deallocate(array) allocate(array(size(arraybuf,1)-count_minus_one,size(arraybuf,2))) if(present(order) )then orderbuf = order order = 0*orderbuf(1:size(arraybuf,1)-count_minus_one) endif itr = 0 do i=1,size(arraybuf,1) if(arraybuf(i,1)==-1 )then cycle else itr = itr + 1 array(itr,:) = arraybuf(i,:) if(present(order) )then order(itr) = orderbuf(i) endif endif enddo array = array + offset - 1 end subroutine ! ########################################################### ! ########################################################### subroutine sort_and_remove_duplication_real64(array,order) real(real64),allocatable,intent(inout) :: array(:,:) integer(int32),allocatable,optional,intent(inout) :: order(:) integer(int32),allocatable :: buf(:),arraybuf(:,:) integer(int32),allocatable :: orderbuf(:) integer(int32) :: i,j,count_minus_one,itr real(real64) :: offset offset = minval(array) array = array - offset + 1.0d0 call heapsort(array,order) do i=1,size(array,1) buf = array(i,:) do j=i+1,size(array,1)-1 if( maxval(abs(buf(:)-array(j,:)))==0.0d0)then array(i,:) = -1.0d0 array(j,:) = -1.0d0 else exit endif enddo end do count_minus_one = 0 do i=1,size(array,1) if(array(i,1)==-1 )then count_minus_one = count_minus_one + 1 endif enddo arraybuf = array deallocate(array) allocate(array(size(arraybuf,1)-count_minus_one,size(arraybuf,2))) if(present(order) )then orderbuf = order order = 0*orderbuf(1:size(arraybuf,1)-count_minus_one) endif itr = 0 do i=1,size(arraybuf,1) if(arraybuf(i,1)==-1 )then cycle else itr = itr + 1 array(itr,:) = arraybuf(i,:) if(present(order) )then order(itr) = orderbuf(i) endif endif enddo array = array + offset - 1.0d0 end subroutine ! ########################################################### ! ########################################################### subroutine assign_real64(x,y) character(*),intent(in) :: y real(real64),intent(inout) :: x x = freal(y) end subroutine ! ########################################################### ! ########################################################### subroutine assign_int32(x,y) character(*),intent(in) :: y integer(int32),intent(inout) :: x x = fint(y) end subroutine ! ########################################################### !function matmul_complex_real64(a,b) result(ret) ! complex(real64),intent(in) :: a(:,:),b(:,:) ! complex(real64),allocatable :: ret(:,:) ! integer(int32) :: i,j,k ! ! allocate(ret(size(a,1),size(b,2))) ! ret(:,:) = 0.0d0 ! do i=1,size(a,1) ! do j=1,size(b,2) ! do k=1,size(a,2) ! ret(i,j) = ret(i,j) + a(i,k)*b(k,j) ! enddo ! enddo ! enddo ! ! !end function end module MathClass