#include "Includes.h" Module FWHPreSurface ! use SMConstants use Headers use HexMeshClass use FTValueDictionaryClass use SurfaceClass Implicit None private public extractSurface interface Function elementInGeo(r, ratio, centerPosition, x, y, N, lengthAspect, filter) result(isIn) use SMConstants implicit none real(kind=RP) , intent(in) :: r, ratio, lengthAspect real(kind=RP), dimension(N) , intent(in) :: x, y real(kind=RP), dimension(2) , intent(in) :: centerPosition integer , intent(in) :: N logical, optional , intent(in) :: filter logical :: isIn End Function elementInGeo Function distaceToGeo(r, ratio, centerPosition, x, y) result(rdiff) use SMConstants implicit none real(kind=RP), intent(in) :: r, ratio, x, y real(kind=RP), dimension(2), intent(in) :: centerPosition real(kind=RP) :: rdiff End Function distaceToGeo end interface !============== contains !============== ! !//////////////////////////////////////////////////////////////////////// ! Subroutine extractSurface(mesh, controlVariables) use mainKeywordsModule use FileReadingUtilities, only: getFileName, getRealArrayFromString, RemovePath, getCharArrayFromString, getIntArrayFromString use Utilities, only: toLower implicit none type(HexMesh) :: mesh type(FTValueDictionary) :: controlVariables !local variables type(Surface_t), allocatable :: surface real(kind=RP) :: radii, ratio, lengthAspect real(kind=RP), dimension(:), allocatable :: centerPosition integer, dimension(:), allocatable :: eIDs, globaleIDs, numberOfFacesperElement, firstFIDs integer :: numberOfElements, numberOfFaces, numberOfSecondFaces, numberOfVerifiedFaces character(len=LINE_LENGTH) :: geometry, fileName, meshName, center, boundaryNames, newElems, discElems character(len=LINE_LENGTH), allocatable :: boundaryNamesArr(:) procedure(elementInGeo), pointer :: isInGeometry => null() procedure(distaceToGeo), pointer :: rToGeometry => null() type(SurfaceFace_t), dimension(:), allocatable :: firstFaces, allCreatedFaces type(SurfaceFace_t), dimension(:), allocatable :: secondFaces, oldFaces, oldTemp type(SurfaceFace_t), allocatable :: tempSecFaces type(SurfaceElement_t), dimension(:), allocatable :: elementsOfFaces integer :: fID, eID, eIndex integer :: i, k, numberOfBCZones, j, numberOfNewFaces logical :: connectedAtBoundary, discardElems, includeElems, useFilter, saveForMPI integer, dimension(:), allocatable :: zoneMarkers integer, dimension(:), allocatable :: allE, allgE, allF integer, dimension(:), allocatable :: nE, newElemID, allNewElemID, allExcludedElemID, discElemID, secIdsNot integer, dimension(:,:), allocatable :: oldIds, secIds, realSecIds, oldIdsTemp, secIdsTemp, bcFaces integer :: nNe, NelemDir, numberOfBCElemNew, numberOfBCElemDisc, numberOfBCFaces ! Get the solution and mesh file names ! ------------------------------------ fileName = controlVariables % stringValueForKey( solutionFileNameKey, requestedLength = LINE_LENGTH ) fileName = "./MESH/" // trim(removePath(getFileName(fileName))) // ".surfaceZone" meshName = trim(controlVariables % stringValueForKey( meshFileNameKey, requestedLength = LINE_LENGTH )) ! Get the geometry info ! --------------------- geometry = controlVariables % stringValueForKey("geometry", LINE_LENGTH) call toLower(geometry) radii = controlVariables % doublePrecisionValueForKey("radii") ratio = controlVariables % getValueOrDefault("ratio", 1.0_RP) connectedAtBoundary = controlVariables % getValueOrDefault("include boundaries", .false.) center = trim(controlVariables % stringValueForKey("center position",LINE_LENGTH)) centerPosition = getRealArrayFromString(center) lengthAspect = controlVariables % getValueOrDefault("surface tolerance", 0.7_RP) ! Get the BC info ! ---------------- if (controlVariables%containsKey("boundary names")) then boundaryNames = trim(controlVariables % stringValueForKey("boundary names",LINE_LENGTH)) else boundaryNames = "" end if call toLower(boundaryNames) call getCharArrayFromString(boundaryNames, LINE_LENGTH, boundaryNamesArr) numberOfBCZones = size(boundaryNamesArr) allocate(zoneMarkers(numberOfBCZones)) zoneMarkers = 0 bc_loop: do k = 1, numberOfBCZones do i = 1, size(mesh % zones) if (trim(mesh % zones(i) % Name) .eq. trim(boundaryNamesArr(k))) then zoneMarkers(k) = mesh % zones(i) % marker cycle bc_loop end if end do end do bc_loop ! Get the misc info ! ----------------- NelemDir = controlVariables % getValueOrDefault("elements in direction", 0) useFilter = controlVariables % getValueOrDefault("use filtering", .false.) saveForMPI = controlVariables % getValueOrDefault("save for mpi", .false.) includeElems = controlVariables % containsKey("elements to include") newElems = trim(controlVariables % stringValueForKey("elements to include",LINE_LENGTH)) if (newElems .eq. "") newElems = "[0]" newElemID = getIntArrayFromString(newElems) numberOfBCElemNew = size(newElemID) discardElems = controlVariables % containsKey("elements to exclude") discElems = trim(controlVariables % stringValueForKey("elements to exclude",LINE_LENGTH)) if (discElems .eq. "") discElems = "[0]" discElemID = getIntArrayFromString(discElems) numberOfBCElemDisc = size(discElemID) ! get the apropiated functions ! ---------------------------- select case (trim(geometry)) case ("circle") isInGeometry => isInCircle rToGeometry => distaceToCircle case ("ellipse") isInGeometry => isInEllipse rToGeometry => distanceToEllipse case default print *, "Warning, no geometry defined, using circle as default" isInGeometry => isInCircle rToGeometry => distaceToCircle end select ! get the forced elements to include ! ---------------------------- allocate(allNewElemID(numberOfBCElemNew*NelemDir)) allNewElemID = 0 if (includeElems) then k = 1 do i = 1, numberOfBCElemNew call getAdditionalElements(mesh, newElemID(i), NelemDir, zoneMarkers, numberOfBCZones, nE, nNe) allNewElemID(k:k+nNe-1) = nE k = k + nNe safedeallocate(nE) end do end if ! get the forced elements to exclude ! ---------------------------- allocate(allExcludedElemID(numberOfBCElemDisc*NelemDir)) allExcludedElemID = 0 if (discardElems) then k = 1 do i = 1, numberOfBCElemDisc call getAdditionalElements(mesh, discElemID(i), NelemDir, zoneMarkers, numberOfBCZones, nE, nNe) allExcludedElemID(k:k+nNe-1) = nE k = k + nNe safedeallocate(nE) end do end if ! get the elements ids ! -------------------- call getElements(mesh, isInGeometry, radii, ratio, lengthAspect, centerPosition, allNewElemID, allExcludedElemID, eIDs, & globaleIDs, useFilter) numberOfElements = size(eIDs) ! get the first faces ids and construct the faces ! ---------------------------------------------- allocate(firstFIDs(numberOfElements)) allocate(firstFaces(numberOfElements)) do i = 1, numberOfElements call getFirstFace(mesh, rToGeometry, eIDs(i), radii, ratio, centerPosition, firstFIDs(i)) call firstFaces(i) % construct(mesh, eIDs(i), globaleIDs(i), firstFIDs(i)) end do ! construct elements ! ------------------ allocate(elementsOfFaces(numberOfElements)) do i = 1, numberOfElements call elementsOfFaces(i) % construct(mesh, eIDs(i), globaleIDs(i), firstFIDs(i), zoneMarkers, numberOfBCZones, .false.) call elementsOfFaces(i) % reconstructPeriod() end do ! update faces connections ! ------------------------ ! if (.not. connectedAtBoundary) then do i = 1, numberOfElements call firstFaces(i)%updateEdgesPeriod(elementsOfFaces, numberOfElements) if (.not. elementsOfFaces(i) % isInBCZone) cycle call firstFaces(i) % setNoConnections(mode=1) end do ! end if ! get the elements that need second faces ! --------------------------------------- allocate(numberOfFacesperElement(numberOfElements)) numberOfFacesperElement = 2 do i = 1, numberOfElements if ( firstFaces(i) % isFullConnected(firstFaces, numberOfElements) ) then numberOfFacesperElement(i) = 1 else call elementsOfFaces(i) % setNeedSecond(numberOfFacesperElement(i) - 1) end if end do ! get first total numbers ! ----------------------- numberOfFaces = sum(numberOfFacesperElement) numberOfSecondFaces = numberOfFaces - numberOfElements numberOfVerifiedFaces = numberOfElements allocate(oldIds(numberOfElements,3)) oldIds(:,1) = eIDs oldIds(:,2) = globaleIDs oldIds(:,3) = firstFIDs allocate(oldFaces(numberOfElements)) oldFaces = firstFaces ! start loop to obtain extra faces ! -------------------------------- do j = 1, 4 ! print *, "j: ", j ! get the second faces ids ! ------------------------ allocate(secIds(numberOfSecondFaces,3)) k = 1 do i = 1, numberOfElements if ( (.not. elementsOfFaces(i) % needSecondFace) .or. (elementsOfFaces(i) % extrafIDs(1) /= 0) ) cycle call elementsOfFaces(i) % getNotConnectedN(mesh, elementsOfFaces, numberOfElements, secIds(k,3)) secIds(k,1) = eIDs(i) secIds(k,2) = globaleIDs(i) if ( k .ge. numberOfSecondFaces ) exit k = k + 1 end do if (k .le. 1) exit numberOfNewFaces = k ! create connected secondFaces and discard the non well positioned ! ---------------------------------------------------------------- if (j .le. 1) then allocate( allCreatedFaces(numberOfElements+1) ) allCreatedFaces(1:numberOfElements) = oldFaces allocate( secIdsNot(numberOfNewFaces) ) k = 0 do i = 1, numberOfNewFaces if (secIds(i,3) .eq. 0) then ! eIndex = findloc(globaleIDs, secIds(i,1), dim=1) eIndex = maxloc(merge(1.0, 0.0, globaleIDs == secIds(i,1)), dim=1) call elementsOfFaces(eIndex) % setNeedNotSecond() if (any(secIdsNot .eq. secIds(i,2))) cycle k = k + 1 secIdsNot(k) = secIds(i,2) cycle end if if (any(secIdsNot .eq. secIds(i,2))) cycle allocate(tempSecFaces) call tempSecFaces % construct(mesh, secIds(i,1), secIds(i,2), secIds(i,3)) allCreatedFaces(numberOfVerifiedFaces+1) = tempSecFaces if (tempSecFaces % isTwiceEdConnected(allCreatedFaces, numberOfElements+1)) then ! if (tempSecFaces % fee(allCreatedFaces, numberOfElements+1)) then if (any(secIdsNot .eq. secIds(i,2))) cycle k = k + 1 secIdsNot(k) = secIds(i,2) ! eIndex = findloc(globaleIDs, secIds(i,1), dim=1) eIndex = maxloc(merge(1.0, 0.0, globaleIDs == secIds(i,1)), dim=1) call elementsOfFaces(eIndex) % setNeedNotSecond() else do eID = 1, numberOfElements if (.not. elementsOfFaces(eID) % needSecondFace) cycle if (elementsOfFaces(eID) % globaleID .eq. secIds(i,2)) cycle if (any(secIdsNot .eq. elementsOfFaces(eID) % globaleID)) cycle if (.not. any(secIds(:,2) .eq. elementsOfFaces(eID) % globaleID)) cycle ! see if with the new face the original face of the element if connected, to remove second connection if (allCreatedFaces(eID) % isFullConnected(allCreatedFaces, numberOfElements+1)) then k = k + 1 call elementsOfFaces(eID) % setNeedNotSecond() secIdsNot(k) = elementsOfFaces(eID) % globaleID exit end if end do end if call tempSecFaces % destruct deallocate(tempSecFaces) end do deallocate(allCreatedFaces) if (k .gt. 0) then numberOfNewFaces = numberOfNewFaces - k numberOfFaces = numberOfElements + numberOfNewFaces numberOfSecondFaces = numberOfFaces - numberOfElements allocate(secIdsTemp(numberOfNewFaces,3)) k = 1 do i = 1, size(secIds, dim=1) if (k .gt. numberOfNewFaces) exit if (any(secIds(i,2) .eq. secIdsNot)) cycle secIdsTemp(k,:) = secIds(i,:) k = k+1 end do deallocate(secIds) allocate(secIds(numberOfNewFaces,3)) secIds = secIdsTemp(1:numberOfNewFaces,:) deallocate(secIdsTemp) end if deallocate(secIdsNot) end if ! create all secondFaces ! ---------------------- allocate( secondFaces(numberOfNewFaces) ) do i = 1, numberOfNewFaces call secondFaces(i) % construct(mesh, secIds(i,1), secIds(i,2), secIds(i,3)) call secondFaces(i)%updateEdgesPeriod(elementsOfFaces, numberOfElements) end do deallocate(secIds) ! update faces connections ! ------------------------ ! if (.not. connectedAtBoundary) then do i = 1, numberOfSecondFaces eID = secondFaces(i) % globaleID ! eIndex = findloc(globaleIDs, eID, dim=1) eIndex = maxloc(merge(1.0, 0.0, globaleIDs == eID), dim=1) if (.not. elementsOfFaces(eIndex) % isInBCZone) cycle if (.not. elementsOfFaces(eIndex) % needSecondFace) cycle call secondFaces(i) % setNoConnections(mode=1) end do ! end if ! set num of con for sec faces at bc allocate( allCreatedFaces(numberOfFaces) ) allCreatedFaces(1:numberOfVerifiedFaces) = oldFaces allCreatedFaces(numberOfVerifiedFaces+1:numberOfFaces) = secondFaces ! get all possible secondFaces not full connected ! ----------------------------------------------- allocate( realSecIds(numberOfFaces,3) ) k = 0 do i = numberOfVerifiedFaces + 1, numberOfFaces if (allCreatedFaces(i) % isFullConnected(allCreatedFaces, numberOfFaces)) then k = k + 1 realSecIds(k,1) = allCreatedFaces(i) % eID realSecIds(k,2) = allCreatedFaces(i) % globaleID realSecIds(k,3) = allCreatedFaces(i) % fID else eID = allCreatedFaces(i) % globaleID ! eIndex = findloc(globaleIDs, eID, dim=1) eIndex = maxloc(merge(1.0, 0.0, globaleIDs == eID), dim=1) if (.not. elementsOfFaces(eIndex) % needSecondFace) cycle elementsOfFaces(eIndex) % extrafIDs(1) = 0 end if end do ! destroy previous faces ! ---------------------- do i = 1, numberOfSecondFaces call secondFaces(i) % destruct() end do deallocate(secondFaces) deallocate(allCreatedFaces) numberOfSecondFaces = k ! exit loop if not new faces are created ! -------------------------------------- if (numberOfSecondFaces .eq. 0) exit ! create real secondFaces ! ----------------------- allocate( secondFaces(numberOfSecondFaces) ) do i = 1, numberOfSecondFaces call secondFaces(i) % construct(mesh, realSecIds(i,1), realSecIds(i,2), realSecIds(i,3)) call secondFaces(i) % updateEdgesPeriod(elementsOfFaces, numberOfElements) end do k = numberOfVerifiedFaces - numberOfElements ! update old ids with the real new ones ! ------------------------------------- allocate( oldIdsTemp(numberOfVerifiedFaces,3) ) oldIdsTemp = oldIds deallocate(oldIds) allocate( oldIds(numberOfVerifiedFaces+numberOfSecondFaces,3) ) oldIds(1:numberOfVerifiedFaces,:) = oldIdsTemp oldIds(numberOfVerifiedFaces+1 : numberOfVerifiedFaces+numberOfSecondFaces,:) = realSecIds deallocate(oldIdsTemp) deallocate(realSecIds) ! update old Faces with the real new ones ! --------------------------------------- allocate( oldTemp(numberOfVerifiedFaces) ) oldTemp = oldFaces deallocate(oldFaces) allocate( oldFaces( numberOfVerifiedFaces+numberOfSecondFaces ) ) oldFaces(1:numberOfVerifiedFaces) = oldTemp oldFaces(numberOfVerifiedFaces+1 : numberOfVerifiedFaces+numberOfSecondFaces) = secondFaces deallocate(oldTemp) deallocate(secondFaces) numberOfVerifiedFaces = numberOfVerifiedFaces + numberOfSecondFaces ! update elements that need secondFaces based on all real secondFaces ! ------------------------------------------------------------------- do i = 1, numberOfVerifiedFaces eID = oldFaces(i) % globaleID ! eIndex = findloc(globaleIDs, eID, dim=1) eIndex = maxloc(merge(1.0, 0.0, globaleIDs == eID), dim=1) if ( (.not. elementsOfFaces(eIndex) % needSecondFace) .or. (elementsOfFaces(eIndex) % extrafIDs(1) .ne. 0) ) cycle if (oldFaces(i) % isFullConnected(oldFaces, numberOfVerifiedFaces)) then call elementsOfFaces(eIndex) % setNeedNotSecond() numberOfFaces = numberOfFaces - 1 end if end do numberOfSecondFaces = numberOfFaces - numberOfVerifiedFaces ! exit loop if no more faces are needed if (numberOfFaces .eq. numberOfVerifiedFaces) exit end do if (numberOfFaces .ne. numberOfVerifiedFaces) print *, "Warning, not all possible faces have been created. Check results first" ! get boundary faces if needed ! ---------------------------- if (connectedAtBoundary) then call getBCFaces(mesh, isInGeometry, radii, ratio, centerPosition, lengthAspect, allExcludedElemID, allNewElemID, zoneMarkers, numberOfBCZones, bcFaces, numberOfBCFaces) allocate(oldIdsTemp(numberOfVerifiedFaces+numberOfBCFaces,3)) oldIdsTemp(1:numberOfVerifiedFaces,:) = oldIds oldIdsTemp(numberOfVerifiedFaces+1:,:) = bcFaces call move_alloc(oldIdsTemp,oldIds) numberOfVerifiedFaces = numberOfVerifiedFaces + numberOfBCFaces end if ! create final surface and create output files ! -------------------------------------------- allocate(surface) call surface % construct(mesh, fileName, oldIds(:,1), oldIds(:,2), oldIds(:,3), numberOfVerifiedFaces) call surface % writeToTecplot(mesh, meshName) call surface % saveToFile(mesh, saveForMPI) call surface % destruct() End Subroutine extractSurface ! !//////////////////////////////////////////////////////////////////////// ! Subroutine getElements(mesh, isInGeometry, radii, ratio, lengthAspect, centerPosition, toInclude, toExclude, eIDArray, geIDArray, useFilter) use ElementConnectivityDefinitions, only: NODES_PER_ELEMENT, FACES_PER_ELEMENT, normalAxis use MeshTypes, only: emptyBCName implicit none type(HexMesh) , intent(in) :: mesh procedure(elementInGeo) :: isInGeometry real(kind=RP) , intent(in) :: radii, ratio, lengthAspect real(kind=RP), dimension(2) , intent(in) :: centerPosition integer, dimension(:), intent(in) :: toInclude, toExclude integer, dimension(:), allocatable, intent(out) :: geIDArray,eIDArray logical, intent(in) :: useFilter !local variables integer :: eID, i, j, k integer, dimension(:,:), allocatable :: allElements, elementsTemp integer :: nElements, extrudedDirectionIndex, numberOfNeighbours, totalNeighbours integer, dimension(:), allocatable :: neighboursIndex call getAllInteriorElements(mesh, isInGeometry, radii, ratio, centerPosition, lengthAspect, useFilter, toExclude, toInclude, allElements, nElements) if (.not. useFilter) then allocate(elementsTemp(nElements,2)) elementsTemp = allElements(1:nElements,:) deallocate(allElements) allocate(allElements(nElements,2)) k = 0 do eID = 1, nElements ! works if there's only one element neighbour for each face totalNeighbours = FACES_PER_ELEMENT numberOfNeighbours = 0 associate ( e => mesh % elements(elementsTemp(eID,1)) ) do j = 1, FACES_PER_ELEMENT if ( any(elementsTemp(:,2) .eq. e % Connection(j) % globID) ) then numberOfNeighbours = numberOfNeighbours + 1 end if ! remove one constrain for each boundary of the element if (trim(e % boundaryName(j)) .ne. emptyBCName) then totalNeighbours = totalNeighbours - 1 end if end do end associate ! is at the surface boundary if there isn't an element inside the surface in the "wall" outgoing surface direction if (numberOfNeighbours .lt. totalNeighbours) then k = k + 1 allElements(k,:) = elementsTemp(eID,:) end if end do nElements = k deallocate(elementsTemp) end if allocate(geIDArray(nElements), eIDArray(nElements)) eIDArray = allElements(1:nElements,1) geIDArray = allElements(1:nElements,2) deallocate(allElements) End Subroutine getElements ! !//////////////////////////////////////////////////////////////////////// ! Subroutine getAllInteriorElements(mesh, isInGeometry, radii, ratio, centerPosition, lengthAspect, useFilter, toExclude, toInclude, allElements, nElements) use ElementConnectivityDefinitions, only: NODES_PER_ELEMENT implicit none type(HexMesh) , intent(in) :: mesh procedure(elementInGeo) :: isInGeometry real(kind=RP) , intent(in) :: radii, ratio, lengthAspect real(kind=RP), dimension(2) , intent(in) :: centerPosition logical, intent(in) :: useFilter integer, dimension(:), intent(in) :: toInclude, toExclude integer, dimension(:,:), allocatable, intent(out) :: allElements integer, intent(out) :: nElements !local variables real(kind=RP), dimension(:), pointer :: x, y, z real(kind=RP), dimension(3,NODES_PER_ELEMENT), target :: xx integer :: eID, k integer :: Nx, Ny, Nz allocate(allElements(mesh % no_of_elements,2)) k = 1 do eID = 1, mesh % no_of_elements associate ( e => mesh % elements(eID) ) find_or_not: if (any(toExclude .eq. e % globID)) then cycle elseif (any(toInclude .eq. e % globID)) then allElements(k,1) = e % eID allElements(k,2) = e % globID k = k + 1 else find_or_not Nx = e % Nxyz(1) Ny = e % Nxyz(2) Nz = e % Nxyz(3) ! conrners position xx(:,1) = e % geom % x(:,0,0,0) xx(:,2) = e % geom % x(:,Nx,0,0) xx(:,3) = e % geom % x(:,0,Ny,0) xx(:,4) = e % geom % x(:,Nx,Ny,0) xx(:,5) = e % geom % x(:,0,0,Nz) xx(:,6) = e % geom % x(:,Nx,0,Nz) xx(:,7) = e % geom % x(:,0,Ny,Nz) xx(:,8) = e % geom % x(:,Nx,Ny,Nz) x => xx(1,:) y => xx(2,:) z => xx(3,:) ! todo: configure to call x,z or y,z too if (isInGeometry(radii, ratio, centerPosition, x, y, NODES_PER_ELEMENT, lengthAspect, filter=useFilter)) then allElements(k,1) = e % eID allElements(k,2) = e % globID k = k + 1 end if nullify(x,y,z) end if find_or_not end associate end do nElements = k - 1 End Subroutine getAllInteriorElements ! !//////////////////////////////////////////////////////////////////////// ! Subroutine getBCFaces(mesh, isInGeometry, radii, ratio, centerPosition, lengthAspect, toExclude, toInclude, zoneMarkers, nBC, BCFaces, nBCFaces) use ElementConnectivityDefinitions, only: FACES_PER_ELEMENT implicit none type(HexMesh) , intent(in) :: mesh procedure(elementInGeo) :: isInGeometry real(kind=RP) , intent(in) :: radii, ratio, lengthAspect real(kind=RP), dimension(2) , intent(in) :: centerPosition integer, dimension(:), intent(in) :: toInclude, toExclude integer, dimension(nBC), intent(in) :: zoneMarkers integer, intent(in) :: nBC integer, dimension(:,:), allocatable, intent(out) :: BCFaces integer, intent(out) :: nBCFaces !local variables integer :: eID, i, k, fID integer, dimension(:,:), allocatable :: allElements, elementsTemp integer :: nElements character(len=LINE_LENGTH), dimension(nBC) :: boundaryNames do i = 1, nBC boundaryNames(i) = trim(mesh % zones(zoneMarkers(i)) % Name) end do !get all BC elements IDs call getAllInteriorElements(mesh, isInGeometry, radii, ratio, centerPosition, lengthAspect, .false., toExclude, toInclude, allElements, nElements) allocate(elementsTemp(nElements,2)) elementsTemp = allElements(1:nElements,:) deallocate(allElements) allocate(allElements(nElements,2)) k = 0 elems_loop:do eID = 1, nElements associate ( e => mesh % elements(elementsTemp(eID,1)) ) do i = 1, FACES_PER_ELEMENT if (any(boundaryNames .eq. e % boundaryName(i))) then k = k + 1 allElements(k,:) = elementsTemp(eID,:) cycle elems_loop end if end do end associate end do elems_loop nBCFaces = k deallocate(elementsTemp) allocate(elementsTemp(nBCFaces,2)) elementsTemp = allElements(1:nBCFaces,:) call move_alloc(elementsTemp, allElements) ! get ID of the face that is on the corresponded BC allocate(BCFaces(nBCFaces,3)) elem_loop:do eID = 1, nBCFaces do i = 1, FACES_PER_ELEMENT fID = mesh % elements(allElements(eID,1)) % faceIDs(i) if (any(zoneMarkers .eq. mesh % faces(fID) % zone)) then BCFaces(eID,1:2) = allElements(eID,:) BCFaces(eID,3) = fID cycle elem_loop end if end do print *, "Warning, the element ", allElements(eID,1), "didn't found a BC face" end do elem_loop End Subroutine getBCFaces ! !//////////////////////////////////////////////////////////////////////// ! Subroutine getFirstFace(mesh, distanceToGeometry, eID, radii, ratio, centerPosition, fID) type(HexMesh), intent(in) :: mesh procedure(distaceToGeo) :: distanceToGeometry integer, intent(in) :: eID real(kind=RP), intent(in) :: radii, ratio real(kind=RP), dimension(2), intent(in) :: centerPosition integer, intent(out) :: fID ! local variables integer :: i, faceIndex integer :: Nx,Ny integer, dimension(6) :: fIDs real(kind=RP), dimension(2) :: faceCenter real(kind=RP), dimension(6) :: faceDistance fIDs = mesh % elements(eID) % faceIDs do i = 1, 6 associate ( f => mesh % faces(fIDs(i)) ) Nx = f % Nf(1) Ny = f % Nf(2) associate (x => f % geom % x) if (x(3,0,0) .eq. x(3,Nx,Ny)) then faceDistance(i) = huge(x(1,0,0)) cycle end if faceCenter(1) = (x(1,0,0) + x(1,Nx,Ny)) / 2.0_RP faceCenter(2) = (x(2,0,0) + x(2,Nx,Ny)) / 2.0_RP end associate end associate faceDistance(i) = abs(distanceToGeometry(radii, ratio, centerposition, faceCenter(1), faceCenter(2))) end do faceIndex = minloc(faceDistance, dim=1) fID = fIDs(faceIndex) End Subroutine getFirstFace ! !//////////////////////////////////////////////////////////////////////// ! Subroutine getAdditionalElements(mesh, BCeID, numberOfElements, zoneMarkers, zN, newEIDs, realNumberOfElements) use ElementConnectivityDefinitions, only: normalAxis, FACES_PER_ELEMENT use ElementClass implicit none type(HexMesh), target, intent(in) :: mesh integer, intent(in) :: BCeID, numberOfElements, zN integer, dimension(zN), intent(in) :: zoneMarkers integer, dimension(:), allocatable, intent(out) :: newEIDs integer, intent(out) :: realNumberOfElements ! local variables integer :: i, j, neID, zoneID class(Element), pointer :: e, BCe integer :: thisMarker, fBCindex, conIndex, conNormal integer, dimension(:), allocatable :: nEs realNumberOfElements = 0 BCe => mesh%elements(BCeID) zone_loop: do i = 1, zN zoneID = zoneMarkers(i) face_loop: do j = 1, FACES_PER_ELEMENT if ( trim(mesh % zones(zoneID) % Name) /= trim(BCe % boundaryName(j)) ) cycle face_loop thisMarker = i fBCindex = j ! thisMarker = zoneID exit zone_loop end do face_loop end do zone_loop e => BCe allocate( nEs(numberOfElements) ) i=1 do i = 1, numberOfElements nEs(i) = e%eID realNumberOfElements = realNumberOfElements + 1 conNormal = normalAxis(fBCindex) * (-1) ! conIndex = findloc(normalAxis, conNormal, dim=1) conIndex = maxloc(merge(1.0, 0.0, normalAxis == conNormal), dim=1) neID = e % Connection(conIndex) % globID if (neID .eq. 0) exit e => mesh % elements(neID) end do !todo check that new bc have been reached allocate(newEIDs(realNumberOfElements)) newEIDs = nEs(1:realNumberOfElements) deallocate(nEs) End Subroutine getAdditionalElements ! !//////////////////////////////////////////////////////////////////////// ! isInGeometry functions !//////////////////////////////////////////////////////////////////////// ! Function isInEllipse(mayorAxis, ratio, centerPosition, x, y, N, lengthAspect, filter) result(isIn) real(kind=RP) , intent(in) :: mayorAxis, ratio, lengthAspect real(kind=RP), dimension(N) , intent(in) :: x, y real(kind=RP), dimension(2) , intent(in) :: centerPosition integer , intent(in) :: N logical, optional , intent(in) :: filter logical :: isIn ! local variables integer :: i, j, k real(kind=RP) :: rEllipse, rdiff, eSize real(kind=RP) :: r, xx, yy, xs(2), rs(2), xEllipse, yEllipse real(kind=RP) :: xo, yo real(kind=RP), dimension(:,:), allocatable :: rCalcsqr logical :: onlyExternal if (present(filter)) then onlyExternal = filter else onlyExternal = .false. end if isIn = .false. xo = centerPosition(1) yo = centerPosition(2) allocate(rCalcsqr(N,3)) k = 1 do i = 1, N rEllipse = POW2(x(i) - xo) + POW2( (y(i) - yo) / ratio ) if ( POW2(mayorAxis) .lt. rEllipse ) return rCalcsqr(k,1) = x(i) rCalcsqr(k,2) = y(i) rCalcsqr(k,3) = POW2(x(i) - xo) + POW2(y(i) - yo) k = k + 1 end do if (onlyExternal) then k = maxloc(rCalcsqr(:,3),dim=1) xx = rCalcsqr(k,1) yy = rCalcsqr(k,2) rdiff = distanceToEllipse(mayoraxis, ratio, centerposition, xx, yy) eSize = getElementSize(x, y, centerPosition, N) if ( abs(rdiff) .gt. eSize*lengthAspect ) return end if isIn = .true. End Function isInEllipse ! !//////////////////////////////////////////////////////////////////////// ! Function isInCircle(r, ratio, centerPosition, x, y, N, lengthAspect, filter) result(isIn) real(kind=RP) , intent(in) :: r, ratio, lengthAspect real(kind=RP), dimension(N) , intent(in) :: x, y real(kind=RP), dimension(2) , intent(in) :: centerPosition integer , intent(in) :: N logical, optional , intent(in) :: filter logical :: isIn ! local variables integer :: i, j, k real(kind=RP) :: rdiff, eSize real(kind=RP) :: xo, yo real(kind=RP), dimension(:), allocatable :: rCalcsqr logical :: onlyExternal if (present(filter)) then onlyExternal = filter else onlyExternal = .false. end if isIn = .false. xo = centerPosition(1) yo = centerPosition(2) allocate(rCalcsqr(N)) k = 1 do i = 1, N rCalcsqr(k) = POW2(x(i) - xo) + POW2(y(i) - yo) if ( POW2(r) .lt. rCalcsqr(k) ) return k = k + 1 end do if (onlyExternal) then rdiff = r - sqrt(maxval(rCalcsqr)) eSize = sqrt(POW2(x(N) - x(1)) + POW2(y(N) - y(1))) if ( abs(rdiff) .gt. eSize*lengthAspect ) return end if isIn = .true. End Function isInCircle ! !//////////////////////////////////////////////////////////////////////// ! distance to geometry functions !//////////////////////////////////////////////////////////////////////// ! Function distanceToEllipse(mayorAxis, ratio, centerPosition, x, y) result(rdiff) use Utilities, only: AlmostEqual implicit none real(kind=RP), intent(in) :: mayorAxis, ratio, x, y real(kind=RP), dimension(2), intent(in) :: centerPosition real(kind=RP) :: rdiff ! local variables integer :: k real(kind=RP) :: a, b, c, m, yint ! line equation and quadratic coefficients real(kind=RP) :: xo, yo real(kind=RP) :: r, xs(2), rs(2), xEllipse, yEllipse, rPoint xo = centerPosition(1) yo = centerPosition(2) vertical_case: if (AlmostEqual(x, xo)) then a = 1 b = -2*yo c = POW2(yo) - POW2(mayorAxis * ratio) xs(1) = (-b + sqrt(POW2(b) - 4*a*c))/(2.0_RP*a) xs(2) = (-b - sqrt(POW2(b) - 4*a*c))/(2.0_RP*a) rs(1) = abs(y - xs(1)) rs(2) = abs(y - xs(2)) k = minloc(rs,dim=1) yEllipse = xs(k) r = abs(yEllipse - yo) rPoint = abs(y - yo) else vertical_case ! get line equation from center to corner of element m = (y - yo) / (x - xo) yint = yo - m*xo ! solve quadratic equation of intersection between ellipse and line a = 1 + POW2(m/ratio) b = -2*xo + 2*m*(yint-yo)/POW2(ratio) c = POW2((yint-yo)/ratio) + POW2(xo) - POW2(mayorAxis) xs(1) = (-b + sqrt(POW2(b) - 4*a*c))/(2.0_RP*a) xs(2) = (-b - sqrt(POW2(b) - 4*a*c))/(2.0_RP*a) rs(1) = abs(x - xs(1)) rs(2) = abs(x - xs(2)) k = minloc(rs,dim=1) xEllipse = xs(k) yEllipse = m*xEllipse + yint ! get the distance from center to intersection r= sqrt(POW2(xEllipse - xo) + POW2(yEllipse - yo)) rPoint = sqrt(POW2(x - xo) + POW2(y - yo)) end if vertical_case rdiff = rPoint - r End Function distanceToEllipse ! !//////////////////////////////////////////////////////////////////////// ! Function distaceToCircle(r, ratio, centerPosition, x, y) result(rdiff) use Utilities, only: AlmostEqual implicit none real(kind=RP), intent(in) :: r, ratio, x, y real(kind=RP), dimension(2), intent(in) :: centerPosition real(kind=RP) :: rdiff ! local variables real(kind=RP) :: xo, yo, rPoint xo = centerPosition(1) yo = centerPosition(2) rPoint = sqrt(POW2(x - xo) + POW2(y - yo)) rdiff = rPoint - r End Function distaceToCircle ! !//////////////////////////////////////////////////////////////////////// ! extra helper functions !//////////////////////////////////////////////////////////////////////// ! Function getElementSize(x, y, centerPosition, N) result(eS) real(kind=RP), dimension(N), intent(in) :: x, y real(kind=RP), dimension(2), intent(in) :: centerPosition integer , intent(in) :: N real(kind=RP) :: eS ! local variables integer :: i, j, k real(kind=RP) :: r, dx, dy, eps real(kind=RP) :: xo, yo ! eps = 0.15_RP ! eps = 0.25_RP eps = 0.3_RP xo = centerPosition(1) yo = centerPosition(2) r = POW2(x(1) - xo) + POW2(y(1) - yo) dx = (abs(x(1) - xo)) / r dy = (abs(y(1) - yo)) / r if (dy .le. eps) then eS = maxval(x) - minval(x) elseif (dx .le. eps) then eS = maxval(y) - minval(y) else eS = sqrt( POW2(maxval(x) - minval(x)) + POW2(maxval(y) - minval(y)) ) end if End Function getElementSize ! !//////////////////////////////////////////////////////////////////////// ! End Module FWHPreSurface