Compare the incoming discrete vector against a set of prevailing vectors and return the found closest prevailing integer vector
A set of real numbered unit vectors (compareVector) must be given. The integer numbered vector is compared against those and the closest integer vector overwrites the original vector.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
integer, | intent(inout) | :: | vector(:) |
The given vector, will be set to the vector in compareVector that is best aligned to it. |
||
real(kind=rk), | intent(in) | :: | compareVector(:,:) |
Set of unit vectors to select from against. size is (3, nVectors) |
||
real(kind=rk), | intent(out), | optional | :: | angle |
angle between vectors |
subroutine tem_determine_discreteVector( vector, compareVector, angle )
! -------------------------------------------------------------------- !
!> The given vector, will be set to the vector in compareVector
!! that is best aligned to it.
integer, intent(inout) :: vector(:)
!> Set of unit vectors to select from against.
!! size is (3, nVectors)
real( kind=rk ), intent(in) :: compareVector(:,:)
!> angle between vectors
real( kind=rk ), intent(out), optional :: angle
! -------------------------------------------------------------------- !
integer :: iDir, bestIndex
real(kind=rk) :: length, rv(3)
real(kind=rk) :: rVectIn(3), angleLoc, dotProduct, maxplen, min_nz_comp
! -------------------------------------------------------------------- !
angleLoc = 0.0_rk
! Only need to do anything for non-zero vectors.
if ( maxval(abs(vector)) > 0 ) then
rv = real(vector, kind=rk)
length = sqrt(rv(1)**2 + rv(2)**2 + rv(3)**2)
! Normalize vector
rVectIn = rv / length
! Keep track of the best fitting index.
bestIndex = 0
! Keep track of the maximal projected length.
! As we are looking at two unit vectors, the smallest
! projected length should be -1 (opposing directions).
! Thus, starting with -2 here as a save comparison that is
! smaller than all possible outcomes from compareVectors.
maxplen = -2.0_rk
! Go over all vectors in the compareVector
do iDir = 1, size(compareVector, 2)
! Go through all prevailing directions and check the minimum
dotProduct = rVectIn(1)*compareVector( 1, iDir ) &
& + rVectIn(2)*compareVector( 2, iDir ) &
& + rVectIn(3)*compareVector( 3, iDir )
dotProduct = min( max(dotProduct, -1.0_rk), 1.0_rk )
if ( dotProduct > maxplen ) then
maxplen = dotProduct
bestIndex = iDir
if ( maxplen .feq. 1._rk ) EXIT
end if
end do
! Align the vector to the closest matching prevailing direction from
! the set of compareVector:
! Use the smallest nonzero component to scale the unit vector to
! components close to integer numbers.
min_nz_comp = abs( minval( pack(compareVector(:, bestIndex), &
& abs(compareVector(:, bestIndex)) &
& > epsilon(0.0_rk)) &
& ) )
! Use the nearest integers to represent the projected vector.
vector = nint(compareVector(:, bestIndex)/min_nz_comp)
! Angle between the original vector and the projected direction.
angleLoc = acos(maxplen)
end if ! not zero-vector
if (present(angle)) angle = angleLoc
end subroutine tem_determine_discreteVector