iterate.f90 Source File

This File Depends On

sourcefile~~iterate.f90~~EfferentGraph sourcefile~iterate.f90 iterate.f90 sourcefile~kinds.f90 kinds.f90 sourcefile~kinds.f90->sourcefile~iterate.f90
Help

Files Dependent On This One

sourcefile~~iterate.f90~~AfferentGraph sourcefile~iterate.f90 iterate.f90 sourcefile~testiterate.f90 testIterate.f90 sourcefile~iterate.f90->sourcefile~testiterate.f90
Help

Source Code


Source Code

module iterate_mod
	!! Module for creating and using iteration arrays
	use kinds_mod
	implicit none
	private
	
	type::iterator_t
		integer,dimension(:),allocatable::idx
			!! Current iteration index
		integer,dimension(:),allocatable::N
			!! Iteration limits
		real(wp),dimension(:),allocatable::lB
			!! Lower bounds for real conversion
		real(wp),dimension(:),allocatable::hB
			!! Upper bounds for real conversion
		logical::isDone = .false.
			!! Completion state flag
	contains
		procedure::next
		procedure::getReals
		procedure::getInt
		procedure::setInt
		procedure::getProgress
	end type
	
	public::iterator_t
	public::newIterator
	
contains

	function newIterator(N,lB,hB) result(o)
		!! Create a new iterator_t object
		integer,dimension(:),intent(in)::N
			!! Number of steps in each dimension
		real(wp),dimension(:),intent(in)::lB
			!! Lower bounds in each dimension for real conversion
		real(wp),dimension(:),intent(in)::hB
			!! Upper bounds in each dimension for real conversion
		type(iterator_t)::o
			!! New iterator object
		
		integer::k
		
		o%idx = [( 0 , k=1,size(N) )]
		o%N   = N-1
		o%lB  = lB
		o%hB  = hB
		
		o%isDone = .false.
	end function newIterator

	subroutine next(self)
		!! Increment the iterator's index
		class(iterator_t),intent(inout)::self
			!! Self object
		
		integer::N,k
		
		N = size(self%idx)
		
		self%idx(1) = self%idx(1)+1
		do k=1,N-1
			if( self%idx(k)/=self%N(k) ) cycle
			self%idx(k) = 0
			self%idx(k+1) = self%idx(k+1)+1
		end do
		self%isDone = (self%idx(N)==self%N(N))
	end subroutine next

	function getReals(self) result(r)
		!! Convert the index into the real ranges defined by lB and hB
		class(iterator_t),intent(in)::self
			!! Self object
		real(wp),dimension(:),allocatable::r
			!! Real values in B-space
		
		integer::N,k
		
		N = size(self%idx)
		r = [( 0.0_wp , k=1,N )]
		
		where(self%N/=1) 
			r = real(self%idx,wp)/real(self%N-1,wp)*(self%hB-self%lB)+self%lB
		else where
			r = self%lB
		end where
	end function getReals

	function getInt(self) result(i)
		!! Convert the index array into a single count comparable to product(N)
		class(iterator_t),intent(in)::self
			!! Self object
		integer::i
			!! Single index equivalent
		
		integer::N,k
		
		N = size(self%idx)
		
		i = self%idx(1)
		do k=2,N
			i = i+self%idx(k)*product(self%N(1:k-1))
		end do
	end function getInt

	subroutine setInt(self,i)
		!! Set the index array to the equivalent of a single value comparable to product(N)
		class(iterator_t),intent(inout)::self
			!! Self object
		integer,intent(in)::i
			!! Single index equivalent
		
		integer::N,c,k
		
		N = size(self%idx)
		c = i
		
		self%idx(1) = mod(c,self%N(1))
		c = c-self%idx(1)
		do k=2,N
			self%idx(k) = mod(c,product(self%N(1:k)))/product(self%N(1:k-1))
			c = c-self%idx(k)
		end do
	end subroutine setInt

	function getProgress(self) result(p)
		!! Get the progress of the iterator such that \(p\in[0,1]\)
		class(iterator_t),intent(in)::self
			!! Self object
		real(wp)::p
			!! Progress
		
		p = real(self%getInt(),wp)/real(product(self%N)-1,wp)
	end function getProgress

end module iterate_mod