module TSFEMClass use WaveKernelClass use ArrayClass use MPIClass implicit none type :: TSFEM_ type(WaveKernel_) :: WK type(FEMDomainp_) :: femdomain type(MPI_), pointer :: mpid => null() ! >>> boundary condition integer(int32), allocatable :: fix_idx(:) real(real64), allocatable :: f_n(:) ! <<< boundary condition ! >>> solutions >>> real(real64), allocatable :: u(:), v(:) real(real64), allocatable :: u_n(:), v_n(:) ! HPF real(real64), allocatable :: u_2(:), v_2(:) real(real64), allocatable :: u_1(:), v_1(:) real(real64), allocatable :: u_old(:), v_old(:) ! <<< solutions <<< ! >>> material parameters >>> real(real64), allocatable :: YoungModulus(:) real(real64), allocatable :: PoissonRatio(:) real(real64), allocatable :: Density(:) ! <<< material parameters <<< real(real64) :: relative_cutoff_frequency = 1.0d0 real(real64) :: dt = 1.0d0/100.0d0 real(real64) :: t = 0.0d0 integer(int32) :: timestep = 0 integer(int32) :: start_step = 1 integer(int32) :: interval = 0 integer(int32) :: itrmax = 50 integer(int32) :: DOF real(real64) :: tol = dble(1.0e-25) ! for debug !complex(real64),allocatable :: ab_weight_cos(:) !complex(real64),allocatable :: ab_weight_sinc(:) logical :: initialized = .false. contains procedure, public :: init => initTSFEM procedure, public :: DirichletBoundary => DirichletBoundaryTSFEM procedure, pass :: NeumannBoundaryTSFEM procedure, pass :: NeumannBoundary_multiple_ForceTSFEM generic, public :: NeumannBoundary => NeumannBoundary_multiple_ForceTSFEM, & NeumannBoundaryTSFEM procedure, public :: time => timeTSFEM !procedure, public :: update => updateTSFEM procedure, public :: save => saveTSFEM procedure, public :: movie => movieTSFEM ! << UNRECOMMENDED for many bugs>> procedure, public :: AbsorbingBoundary => AbsorbingBoundaryTSFEM end type contains ! ############################################## subroutine initTSFEM(this, femdomain, Density, YoungModulus, PoissonRatio, DOF, mpid) class(TSFEM_), intent(inout) :: this type(FEMDomain_), target, intent(inout) :: femdomain real(real64), intent(in) :: Density, YoungModulus real(real64), optional, intent(in) :: PoissonRatio type(MPI_), target, optional, intent(in) :: mpid integer(int32), intent(in) :: DOF integer(int32) :: nn if (associated(this%mpid)) then nullify (this%mpid) end if if (present(mpid)) then this%mpid => mpid end if this%DOF = DOF this%femdomain%femdomainp => femdomain this%Density = Density*ones(femdomain%ne()) this%YoungModulus = YoungModulus*ones(femdomain%ne()) if (present(PoissonRatio)) then this%PoissonRatio = PoissonRatio*ones(femdomain%ne()) end if this%u = zeros(femdomain%nn()*DOF) this%u_n = zeros(femdomain%nn()*DOF) this%v = zeros(femdomain%nn()*DOF) this%v_n = zeros(femdomain%nn()*DOF) this%v_n = zeros(femdomain%nn()*DOF) this%f_n = zeros(femdomain%nn()*DOF) if (DOF == 1) then call this%WK%init(FEMDomain=femdomain, & YoungModulus=this%YoungModulus, & Density=this%Density, & DOF=DOF) else call this%WK%init(FEMDomain=femdomain, & YoungModulus=this%YoungModulus, & Density=this%Density, & PoissonRatio=this%PoissonRatio, & DOF=DOF) end if nn = this%femdomain%femdomainp%nn() this%initialized = .true. end subroutine initTSFEM ! ############################################## ! ############################################## recursive subroutine DirichletBoundaryTSFEM(this, NodeList, direction) class(TSFEM_), intent(inout) :: this integer(int32), intent(in) :: NodeList(:) integer(int32), allocatable :: LocalNodeList(:), NodeIDx(:) character(*), intent(in) :: direction integer(int32) :: DOF, i integer(int32), allocatable :: idx(:) DOF = this%DOF if (associated(this%mpid)) then if (this%mpid%petot >= 2) then idx = this%femdomain%femdomainp%mpi_global_node_idx.cap.NodeList LocalNodeList = getIdx( & vec=this%femdomain%femdomainp%mpi_global_node_idx, & equal_to=idx) if (size(LocalNodeList) == 0) then return else NodeIDx = LocalNodeList end if else NodeIDx = NodeList end if else NodeIDx = NodeList end if if (.not. allocated(this%fix_idx)) then this%fix_idx = int(zeros(0)) end if if (size(NodeIdx) == 0) then return end if if (index(direction, "x") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 1 end if if (index(direction, "X") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 1 end if if (index(direction, "1") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 1 end if if (index(direction, "y") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 2 end if if (index(direction, "Y") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 2 end if if (index(direction, "2") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 2 end if if (index(direction, "z") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 3 end if if (index(direction, "Z") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 3 end if if (index(direction, "3") /= 0) then this%fix_idx = this%fix_idx//(NodeIdx - 1)*DOF + 3 end if call this%WK%OmegaSqMatrix%fix(idx=this%fix_idx) end subroutine DirichletBoundaryTSFEM ! ############################################## ! ############################################## recursive subroutine NeumannBoundaryTSFEM(this, NodeList, Force, direction, clear) class(TSFEM_), intent(inout) :: this integer(int32), intent(in) :: NodeList(:) character(*), intent(in) :: direction real(real64), intent(in) :: Force integer(int32) :: DOF, nn integer(int32), allocatable :: LocalNodeList(:), idx(:), NodeIdx(:) logical, optional, intent(in) :: clear nn = this%femdomain%femdomainp%nn() DOF = this%DOF if (.not. allocated(this%f_n)) then this%f_n = int(zeros(DOF*nn)) end if if (associated(this%mpid)) then if (this%mpid%petot >= 2) then idx = this%femdomain%femdomainp%mpi_global_node_idx.cap.NodeList LocalNodeList = getIdx( & vec=this%femdomain%femdomainp%mpi_global_node_idx, & equal_to=idx) if (size(LocalNodeList) == 0) then return else NodeIdx = LocalNodeList end if else NodeIdx = NodeList end if else NodeIdx = NodeList end if if (present(clear)) then if (clear) then this%f_n(:) = 0.0d0 return end if end if if (index(direction, "x") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 1) = Force end if if (index(direction, "X") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 1) = Force end if if (index(direction, "1") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 1) = Force end if if (index(direction, "y") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 2) = Force end if if (index(direction, "Y") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 2) = Force end if if (index(direction, "2") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 2) = Force end if if (index(direction, "z") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 3) = Force end if if (index(direction, "Z") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 3) = Force end if if (index(direction, "3") /= 0) then this%f_n((NodeIdx(:) - 1)*DOF + 3) = Force end if end subroutine NeumannBoundaryTSFEM ! ############################################## ! ############################################## recursive subroutine NeumannBoundary_multiple_ForceTSFEM(this, NodeList, Force, direction, clear) class(TSFEM_), intent(inout) :: this integer(int32), intent(in) :: NodeList(:) character(*), intent(in) :: direction real(real64), intent(in) :: Force(:) logical, optional, intent(in) :: clear real(real64) :: force_val integer(int32) :: i do i = 1, size(NodeList) force_val = Force(i) call this%NeumannBoundary(NodeList=NodeList(i:i), & Force=force_val, direction=direction, clear=clear) end do end subroutine NeumannBoundary_multiple_ForceTSFEM ! ############################################## ! ############################################## subroutine AbsorbingBoundaryTSFEM(this, NodeList, direction) class(TSFEM_), intent(inout) :: this integer(int32), intent(in) :: NodeList(:) character(*), intent(in) :: direction !real(real64),intent(in) :: beta integer(int32) :: DOF, nn real(real64) :: force(1:3) !>HPF real(real64) :: a, cutoff_frequency !complex(real64) :: beta_u, beta_v type(Math_) :: math ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. ![[[CAUTION]]] EXPERIMENTAL, MANY CRITICAL BUGS EXIST. nn = this%femdomain%femdomainp%nn() DOF = this%DOF ! HPF ! https://101010.fun/iot/rc-high-pass-filter.html cutoff_frequency = this%relative_cutoff_frequency*(1.0d0/this%dt) cutoff_frequency = cutoff_frequency*10.0d0 a = 1.0d0/(2.0d0*math%pi*this%dt*cutoff_frequency + 1.0d0) if (.not. allocated(this%u_old)) then this%u_old = 0.0d0*this%u_n end if if (.not. allocated(this%v_old)) then this%v_old = 0.0d0*this%v_n end if if (.not. allocated(this%u_1)) then this%u_1 = 0.0d0*this%u_n end if if (.not. allocated(this%v_1)) then this%v_1 = 0.0d0*this%v_n end if if (.not. allocated(this%u_2)) then this%u_2 = 0.0d0*this%u_n end if if (.not. allocated(this%v_2)) then this%v_2 = 0.0d0*this%v_n end if ! caution ! 拡張性なし.1つのAB, 1方向しか対応できない. this%u_2((NodeList(:) - 1)*DOF + 1) = a*this%u_1((NodeList(:) - 1)*DOF + 1) & + a*(this%u_n((NodeList(:) - 1)*DOF + 1) - this%u_old((NodeList(:) - 1)*DOF + 1)) this%u_1((NodeList(:) - 1)*DOF + 1) = this%u_2((NodeList(:) - 1)*DOF + 1) this%u_old((NodeList(:) - 1)*DOF + 1) = this%u_n((NodeList(:) - 1)*DOF + 1) this%u_n((NodeList(:) - 1)*DOF + 1) = this%u_2((NodeList(:) - 1)*DOF + 1) this%u((NodeList(:) - 1)*DOF + 1) = this%u_2((NodeList(:) - 1)*DOF + 1) ! this%v_2((NodeList(:)-1)*DOF + 1) = a*this%v_1((NodeList(:)-1)*DOF + 1) & ! + a*(this%v_n((NodeList(:)-1)*DOF + 1) - this%v_old((NodeList(:)-1)*DOF + 1) ) ! this%v_1 ((NodeList(:)-1)*DOF + 1) = this%v_2((NodeList(:)-1)*DOF + 1) ! this%v_old ((NodeList(:)-1)*DOF + 1) = this%v_n((NodeList(:)-1)*DOF + 1) ! this%v_n ((NodeList(:)-1)*DOF + 1) = this%v_2((NodeList(:)-1)*DOF + 1) ! this%v ((NodeList(:)-1)*DOF + 1) = this%v_2((NodeList(:)-1)*DOF + 1) ! return ! beta_u = sqrt(2.0d0)*cos(math%i*beta*(this%dt) + 0.250d0*math%pi ) ! beta_v = sqrt(2.0d0)*cos(math%i*beta*(this%dt) - 0.250d0*math%pi ) if (index(direction, "x") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 1) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 1) = beta_v !this%v_n((NodeList(:)-1)*DOF + 1) = beta_v*this%v_n((NodeList(:)-1)*DOF + 1) !this%u((NodeList(:)-1)*DOF + 1) = beta_u*this%u((NodeList(:)-1)*DOF + 1) !this%v((NodeList(:)-1)*DOF + 1) = beta_v*this%v((NodeList(:)-1)*DOF + 1) end if if (index(direction, "X") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 1) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 1) = beta_v !this%v_n((NodeList(:)-1)*DOF + 1) = beta_v*this%v_n((NodeList(:)-1)*DOF + 1) !this%u((NodeList(:)-1)*DOF + 1) = beta_u*this%u((NodeList(:)-1)*DOF + 1) !this%v((NodeList(:)-1)*DOF + 1) = beta_v*this%v((NodeList(:)-1)*DOF + 1) end if if (index(direction, "1") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 1) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 1) = beta_v !this%v_n((NodeList(:)-1)*DOF + 1) = beta_v*this%v_n((NodeList(:)-1)*DOF + 1) !this%u((NodeList(:)-1)*DOF + 1) = beta_u*this%u((NodeList(:)-1)*DOF + 1) !this%v((NodeList(:)-1)*DOF + 1) = beta_v*this%v((NodeList(:)-1)*DOF + 1) end if if (index(direction, "y") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 2) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 2) = beta_v !this%v_n((NodeList(:)-1)*DOF + 2) = beta_v*this%v_n((NodeList(:)-1)*DOF + 2) !this%u((NodeList(:)-1)*DOF + 2) = beta_u*this%u((NodeList(:)-1)*DOF + 2) !this%v((NodeList(:)-1)*DOF + 2) = beta_v*this%v((NodeList(:)-1)*DOF + 2) end if if (index(direction, "Y") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 2) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 2) = beta_v !this%v_n((NodeList(:)-1)*DOF + 2) = beta_v*this%v_n((NodeList(:)-1)*DOF + 2) !this%u((NodeList(:)-1)*DOF + 2) = beta_u*this%u((NodeList(:)-1)*DOF + 2) !this%v((NodeList(:)-1)*DOF + 2) = beta_v*this%v((NodeList(:)-1)*DOF + 2) end if if (index(direction, "2") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 2) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 2) = beta_v !this%v_n((NodeList(:)-1)*DOF + 2) = beta_v*this%v_n((NodeList(:)-1)*DOF + 2) !this%u((NodeList(:)-1)*DOF + 2) = beta_u*this%u((NodeList(:)-1)*DOF + 2) !this%v((NodeList(:)-1)*DOF + 2) = beta_v*this%v((NodeList(:)-1)*DOF + 2) end if if (index(direction, "z") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 3) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 3) = beta_v !this%v_n((NodeList(:)-1)*DOF + 3) = beta_v*this%v_n((NodeList(:)-1)*DOF + 3) !this%u((NodeList(:)-1)*DOF + 3) = beta_u*this%u((NodeList(:)-1)*DOF + 3) !this%v((NodeList(:)-1)*DOF + 3) = beta_v*this%v((NodeList(:)-1)*DOF + 3) end if if (index(direction, "Z") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 3) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 3) = beta_v !this%v_n((NodeList(:)-1)*DOF + 3) = beta_v*this%v_n((NodeList(:)-1)*DOF + 3) !this%u((NodeList(:)-1)*DOF + 3) = beta_u*this%u((NodeList(:)-1)*DOF + 3) !this%v((NodeList(:)-1)*DOF + 3) = beta_v*this%v((NodeList(:)-1)*DOF + 3) end if if (index(direction, "3") /= 0) then !this%ab_weight_cos((NodeList(:)-1)*DOF + 3) = beta_u !this%ab_weight_sinc((NodeList(:)-1)*DOF + 3) = beta_v !this%v_n((NodeList(:)-1)*DOF + 3) = beta_v*this%v_n((NodeList(:)-1)*DOF + 3) !this%u((NodeList(:)-1)*DOF + 3) = beta_u*this%u((NodeList(:)-1)*DOF + 3) !this%v((NodeList(:)-1)*DOF + 3) = beta_v*this%v((NodeList(:)-1)*DOF + 3) end if end subroutine AbsorbingBoundaryTSFEM ! ############################################## ! ############################################## subroutine timeTSFEM(this, dt, t, timestep) class(TSFEM_), intent(inout) :: this real(real64), intent(in) :: dt, t integer(int32), intent(in) :: timestep this%dt = dt this%t = t this%timestep = timestep this%start_step = timestep + 1 end subroutine ! ############################################## ! ############################################## subroutine TSFEM(this) class(TSFEM_), intent(inout) :: this real(real64) :: cutoff_frequency real(real64), allocatable :: f_v(:), f_u(:) this%WK%itrmax = this%itrmax this%WK%tol = this%tol cutoff_frequency = this%relative_cutoff_frequency*(1.0d0/this%dt) if (associated(this%mpid)) then if (this%mpid%petot >= 2) then call this%WK%getDisplacement_and_Velocity( & u_n=this%u_n, v_n=this%v_n, dt=this%dt, & fix_idx=this%fix_idx, cutoff_frequency=cutoff_frequency, & u=this%u, v=this%v, RHS=this%f_n, MPID=this%MPID, FEMDomain=this%femdomain%femdomainp) else call this%WK%getDisplacement_and_Velocity( & u_n=this%u_n, v_n=this%v_n, dt=this%dt, & fix_idx=this%fix_idx, cutoff_frequency=cutoff_frequency, & u=this%u, v=this%v, RHS=this%f_n) end if else call this%WK%getDisplacement_and_Velocity( & u_n=this%u_n, v_n=this%v_n, dt=this%dt, & fix_idx=this%fix_idx, cutoff_frequency=cutoff_frequency, & u=this%u, v=this%v, RHS=this%f_n) end if if (allocated(this%fix_idx)) then f_v = this%WK%Mmatrix_diag*this%v_n f_u = this%WK%OmegaSqMatrix%matmul(this%u_n) this%f_n(this%fix_idx) = f_v(this%fix_idx) !+ f_u(this%fix_idx) end if if (associated(this%mpid)) then call this%mpid%barrier() end if this%u_n = this%u this%v_n = this%v this%t = this%t + this%dt this%timestep = this%timestep + 1 ! if(associated(this%mpid) )then ! call this%mpid%barrier() ! endif end subroutine ! ############################################## ! ############################################## subroutine saveTSFEM(this, name) class(TSFEM_), intent(inout) :: this type(IO_) :: f character(*), intent(in) :: name real(real64), allocatable :: u_xyz(:, :), v_xyz(:, :) u_xyz = transpose(reshape(dble(this%u), [this%DOF, this%femdomain%femdomainp%nn()])) call this%femdomain%femdomainp%vtk(name=name + "_ux_"+zfill(this%timestep, 6) + ".vtk", & scalar=u_xyz(:, 1)) call this%femdomain%femdomainp%vtk(name=name + "_uy_"+zfill(this%timestep, 6) + ".vtk", & scalar=u_xyz(:, 2)) call this%femdomain%femdomainp%vtk(name=name + "_uz_"+zfill(this%timestep, 6) + ".vtk", & scalar=u_xyz(:, 3)) deallocate (u_xyz) v_xyz = transpose(reshape(dble(this%u), [this%DOF, this%femdomain%femdomainp%nn()])) call this%femdomain%femdomainp%vtk(name=name + "_vx_"+zfill(this%timestep, 6) + ".vtk", & scalar=v_xyz(:, 1)) call this%femdomain%femdomainp%vtk(name=name + "_vy_"+zfill(this%timestep, 6) + ".vtk", & scalar=v_xyz(:, 2)) call this%femdomain%femdomainp%vtk(name=name + "_vz_"+zfill(this%timestep, 6) + ".vtk", & scalar=v_xyz(:, 3)) deallocate (v_xyz) end subroutine ! ############################################## ! ############################################## subroutine movieTSFEM(this, name) class(TSFEM_), intent(inout) :: this type(IO_) :: f character(*), intent(in) :: name real(real64), allocatable :: u_xyz(:, :) call f%open(name + "_v.gp", "w") call f%write('set term gif enhanced animate optimize size 700, 480') call f%write('set output "'+name + '_v.gif"') call f%write('do for[i='+str(this%start_step) + ':'+str(this%timestep) + ':1]{') call f%write("filename = sprintf('"+name + "_v0%05d.tsv', i)") call f%write("dt="+str(this%dt)) call f%write("plot_title = sprintf('time = %f sec.', i*dt)") call f%write('set title plot_title') call f%write("plot filename u 1:2 w l") call f%write('}') call f%write('set out') call f%write('reset') call f%close() call f%open(name + "_u.gp", "w") call f%write('set term gif enhanced animate optimize size 700, 480') call f%write('set output "'+name + '_u.gif"') call f%write('do for[i='+str(this%start_step) + ':'+str(this%timestep) + ':1]{') call f%write("filename = sprintf('"+name + "_u0%05d.tsv', i)") call f%write("dt="+str(this%dt)) call f%write("plot_title = sprintf('time = %f sec.', i*dt)") call f%write('set title plot_title') call f%write("plot filename u 1:2 w l") call f%write('}') call f%write('set out') call f%write('reset') call f%close() end subroutine ! ############################################## end module TSFEMClass