fpakc/src/modules/mesh/1DCart/moduleMesh1DCart.f90
Jorge Gonzalez - Galactica 8d5cb6a516 Wrong surface in edges
Some edges were calculating the area surface incorrectly, which was leading to wrong densities.
2026-02-02 14:31:58 +01:00

593 lines
15 KiB
Fortran

!moduleMesh1D: 1D cartesian module
! x == x
! y == unused
! z == unused
MODULE moduleMesh1DCart
USE moduleMesh
USE moduleMeshBoundary
IMPLICIT NONE
REAL(8), PARAMETER:: corSeg(1:3) = (/ -DSQRT(3.D0/5.D0), 0.D0, DSQRT(3.D0/5.D0) /)
REAL(8), PARAMETER:: wSeg(1:3) = (/ 5.D0/9.D0 , 8.D0/9.D0, 5.D0/9.D0 /)
TYPE, PUBLIC, EXTENDS(meshNode):: meshNode1DCart
!Element coordinates
REAL(8):: x = 0.D0
CONTAINS
!meshNode DEFERRED PROCEDURES
PROCEDURE, PASS:: init => initNode1DCart
PROCEDURE, PASS:: getCoordinates => getCoord1DCart
END TYPE meshNode1DCart
TYPE, PUBLIC, EXTENDS(meshEdge):: meshEdge1DCart
!Element coordinates
REAL(8):: x = 0.D0
!Connectivity to nodes
CLASS(meshNode), POINTER:: n1 => NULL()
CONTAINS
!meshEdge DEFERRED PROCEDURES
PROCEDURE, PASS:: init => initEdge1DCart
PROCEDURE, PASS:: getNodes => getNodes1DCart
PROCEDURE, PASS:: intersection => intersection1DCart
PROCEDURE, PASS:: randPos => randPosEdge
END TYPE meshEdge1DCart
TYPE, PUBLIC, EXTENDS(meshCell):: meshCell1DCartSegm
!Element coordinates
REAL(8):: x(1:2)
!Connectivity to nodes
CLASS(meshNode), POINTER:: n1 => NULL(), n2 => NULL()
!Connectivity to adjacent elements
CLASS(meshElement), POINTER:: e1 => NULL(), e2 => NULL()
CONTAINS
!meshCell DEFERRED PROCEDURES
PROCEDURE, PASS:: init => initCell1DCartSegm
PROCEDURE, PASS:: getNodes => getNodesSegm
PROCEDURE, PASS:: randPos => randPos1DCartSegm
PROCEDURE, NOPASS:: fPsi => fPsiSegm
PROCEDURE, NOPASS:: dPsi => dPsiSegm
PROCEDURE, PASS:: partialDer => partialDerSegm
PROCEDURE, NOPASS:: detJac => detJ1DCart
PROCEDURE, NOPASS:: invJac => invJ1DCart
PROCEDURE, PASS:: gatherElectricField => gatherEFSegm
PROCEDURE, PASS:: gatherMagneticField => gatherMFSegm
PROCEDURE, PASS:: elemK => elemKSegm
PROCEDURE, PASS:: elemF => elemFSegm
PROCEDURE, NOPASS:: inside => insideSegm
PROCEDURE, PASS:: phy2log => phy2logSegm
PROCEDURE, PASS:: neighbourElement => neighbourElementSegm
!PARTICLUAR PROCEDURES
PROCEDURE, PASS, PRIVATE:: calculateVolume => volumeSegm
END TYPE meshCell1DCartSegm
CONTAINS
!NODE FUNCTIONS
!Init node element
SUBROUTINE initNode1DCart(self, n, r)
USE moduleSpecies
USE moduleRefParam
USE OMP_LIB
IMPLICIT NONE
CLASS(meshNode1DCart), INTENT(out):: self
INTEGER, INTENT(in):: n
REAL(8), INTENT(in):: r(1:3)
self%n = n
self%x = r(1)/L_ref
!Node volume, to be determined in mesh
self%v = 0.D0
!Allocates output
ALLOCATE(self%output(1:nSpecies))
CALL OMP_INIT_LOCK(self%lock)
END SUBROUTINE initNode1DCart
PURE FUNCTION getCoord1DCart(self) RESULT(r)
IMPLICIT NONE
CLASS(meshNode1DCart), INTENT(in):: self
REAL(8):: r(1:3)
r = (/ self%x, 0.D0, 0.D0 /)
END FUNCTION getCoord1DCart
!EDGE FUNCTIONS
!Init edge element
SUBROUTINE initEdge1DCart(self, n, p, bt, physicalSurface)
USE moduleSpecies
USE moduleBoundary
USE moduleErrors
IMPLICIT NONE
CLASS(meshEdge1DCart), INTENT(out):: self
INTEGER, INTENT(in):: n
INTEGER, INTENT(in):: p(:)
INTEGER, INTENT(in):: bt
INTEGER, INTENT(in):: physicalSurface
REAL(8), DIMENSION(1:3):: r1
INTEGER:: s
self%n = n
self%nNodes = SIZE(p)
self%n1 => mesh%nodes(p(1))%obj
!Get element coordinates
r1 = self%n1%getCoordinates()
self%x = r1(1)
self%surface = 1.D0
self%normal = (/ 1.D0, 0.D0, 0.D0 /)
!Boundary index
self%boundary => boundary(bt)
ALLOCATE(self%fboundary(1:nSpecies))
!Assign functions to boundary
DO s = 1, nSpecies
CALL pointBoundaryFunction(self, s)
END DO
!Physical Surface
self%physicalSurface = physicalSurface
END SUBROUTINE initEdge1DCart
!Get nodes from edge
PURE FUNCTION getNodes1DCart(self, nNodes) RESULT(n)
IMPLICIT NONE
CLASS(meshEdge1DCart), INTENT(in):: self
INTEGER, INTENT(in):: nNodes
INTEGER:: n(1:nNodes)
n = (/ self%n1%n /)
END FUNCTION getNodes1DCart
PURE FUNCTION intersection1DCart(self, r0) RESULT(r)
IMPLICIT NONE
CLASS(meshEdge1DCart), INTENT(in):: self
REAL(8), DIMENSION(1:3), INTENT(in):: r0
REAL(8), DIMENSION(1:3):: r
r = (/ self%x, 0.D0, 0.D0 /)
END FUNCTION intersection1DCart
!Calculate a 'random' position in edge
FUNCTION randPosEdge(self) RESULT(r)
CLASS(meshEdge1DCart), INTENT(in):: self
REAL(8):: r(1:3)
r = (/ self%x, 0.D0, 0.D0 /)
END FUNCTION randPosEdge
!VOLUME FUNCTIONS
!SEGMENT FUNCTIONS
!Init element
SUBROUTINE initCell1DCartSegm(self, n, p, nodes)
USE moduleRefParam
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(out):: self
INTEGER, INTENT(in):: n
INTEGER, INTENT(in):: p(:)
TYPE(meshNodeCont), INTENT(in), TARGET:: nodes(:)
REAL(8), DIMENSION(1:3):: r1, r2
self%n = n
self%nNodes = SIZE(p)
self%n1 => nodes(p(1))%obj
self%n2 => nodes(p(2))%obj
!Get element coordinates
r1 = self%n1%getCoordinates()
r2 = self%n2%getCoordinates()
self%x = (/ r1(1), r2(1) /)
!Assign node volume
CALL self%calculateVolume()
CALL OMP_INIT_LOCK(self%lock)
ALLOCATE(self%listPart_in(1:nSpecies))
ALLOCATE(self%totalWeight(1:nSpecies))
END SUBROUTINE initCell1DCartSegm
!Get nodes from 1D volume
PURE FUNCTION getNodesSegm(self, nNodes) RESULT(n)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
INTEGER, INTENT(in):: nNodes
INTEGER:: n(1:nNodes)
n = (/ self%n1%n, self%n2%n /)
END FUNCTION getNodesSegm
!Random position in 1D volume
FUNCTION randPos1DCartSegm(self) RESULT(r)
USE moduleRandom
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
REAL(8):: r(1:3)
REAL(8):: Xi(1:3)
REAL(8):: fPsi(1:2)
Xi = 0.D0
Xi(1) = random(-1.D0, 1.D0)
fPsi = self%fPsi(Xi, 2)
r = 0.D0
r(1) = DOT_PRODUCT(fPsi, self%x)
END FUNCTION randPos1DCartSegm
!Compute element functions at point Xi
PURE FUNCTION fPsiSegm(Xi, nNodes) RESULT(fPsi)
IMPLICIT NONE
REAL(8), INTENT(in):: Xi(1:3)
INTEGER, INTENT(in):: nNodes
REAL(8):: fPsi(1:nNodes)
fPsi = (/ 1.D0 - Xi(1), &
1.D0 + Xi(1) /)
fPsi = fPsi * 0.50D0
END FUNCTION fPsiSegm
!Derivative element function at coordinates Xi
PURE FUNCTION dPsiSegm(Xi, nNodes) RESULT(dPsi)
IMPLICIT NONE
REAL(8), INTENT(in):: Xi(1:3)
INTEGER, INTENT(in):: nNodes
REAL(8):: dPsi(1:3,1:nNodes)
dPsi = 0.D0
dPsi(1, 1:2) = (/ -5.D-1, 5.D-1 /)
END FUNCTION dPsiSegm
!Partial derivative in global coordinates
PURE FUNCTION partialDerSegm(self, nNodes, dPsi) RESULT(pDer)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
INTEGER, INTENT(in):: nNodes
REAL(8), INTENT(in):: dPsi(1:3,1:nNodes)
REAL(8):: pDer(1:3, 1:3)
pDer = 0.D0
pDer(1,1) = DOT_PRODUCT(dPsi(1,1:2), self%x(1:2))
pDer(2,2) = 1.D0
pDer(3,3) = 1.D0
END FUNCTION partialDerSegm
PURE FUNCTION gatherEFSegm(self, Xi) RESULT(array)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
REAL(8), INTENT(in):: Xi(1:3)
REAL(8):: array(1:3)
REAL(8):: phi(1:2)
phi = (/ self%n1%emData%phi, &
self%n2%emData%phi /)
array = -self%gatherDF(Xi, 2, phi)
END FUNCTION gatherEFSegm
PURE FUNCTION gatherMFSegm(self, Xi) RESULT(array)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
REAL(8), INTENT(in):: Xi(1:3)
REAL(8):: array(1:3)
REAL(8):: B(1:2,1:3)
B(:,1) = (/ self%n1%emData%B(1), &
self%n2%emData%B(1) /)
B(:,2) = (/ self%n1%emData%B(2), &
self%n2%emData%B(2) /)
B(:,3) = (/ self%n1%emData%B(3), &
self%n2%emData%B(3) /)
array = self%gatherF(Xi, 2, B)
END FUNCTION gatherMFSegm
!Compute element local stiffness matrix
PURE FUNCTION elemKSegm(self, nNodes) RESULT(localK)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
INTEGER, INTENT(in):: nNodes
REAL(8):: localK(1:nNodes,1:nNodes)
REAL(8):: Xi(1:3)
REAL(8):: dPsi(1:3, 1:2)
REAL(8):: pDer(1:3, 1:3)
REAL(8):: invJ(1:3, 1:3), detJ
INTEGER:: l
localK = 0.D0
Xi = 0.D0
!Start 1D Gauss Quad Integral
DO l = 1, 3
Xi(1) = corSeg(l)
dPsi = self%dPsi(Xi, 2)
pDer = self%partialDer(2, dPsi)
detJ = self%detJac(pDer)
invJ = self%invJac(pDer)
localK = localK + MATMUL(TRANSPOSE(MATMUL(invJ,dPsi)), &
MATMUL(invJ,dPsi))* &
wSeg(l)/detJ
END DO
END FUNCTION elemKSegm
!Compute the local source vector for a force f
PURE FUNCTION elemFSegm(self, nNodes, source) RESULT(localF)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
INTEGER, INTENT(in):: nNodes
REAL(8), INTENT(in):: source(1:nNodes)
REAL(8):: localF(1:nNodes)
REAL(8):: fPsi(1:2)
REAL(8):: dPsi(1:3, 1:2), pDer(1:3, 1:3)
REAL(8):: Xi(1:3)
REAL(8):: detJ, f
INTEGER:: l
localF = 0.D0
Xi = 0.D0
!Start 1D Gauss Quad Integral
DO l = 1, 3
Xi(1) = corSeg(l)
dPsi = self%dPsi(Xi, 2)
pDer = self%partialDer(2, dPsi)
detJ = self%detJac(pDer)
fPsi = self%fPsi(Xi, 2)
f = DOT_PRODUCT(fPsi, source)
localF = localF + f*fPsi*wSeg(l)*detJ
END DO
END FUNCTION elemFSegm
PURE FUNCTION insideSegm(Xi) RESULT(ins)
IMPLICIT NONE
REAL(8), INTENT(in):: Xi(1:3)
LOGICAL:: ins
ins = Xi(1) >=-1.D0 .AND. &
Xi(1) <= 1.D0
END FUNCTION insideSegm
PURE FUNCTION phy2logSegm(self, r) RESULT(Xi)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
REAL(8), INTENT(in):: r(1:3)
REAL(8):: Xi(1:3)
Xi = 0.D0
Xi(1) = 2.D0*(r(1) - self%x(1))/(self%x(2) - self%x(1)) - 1.D0
END FUNCTION phy2logSegm
!Get the next element for a logical position Xi
SUBROUTINE neighbourElementSegm(self, Xi, neighbourElement)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(in):: self
REAL(8), INTENT(in):: Xi(1:3)
CLASS(meshElement), POINTER, INTENT(out):: neighbourElement
NULLIFY(neighbourElement)
IF (Xi(1) < -1.D0) THEN
neighbourElement => self%e2
ELSEIF (Xi(1) > 1.D0) THEN
neighbourElement => self%e1
END IF
END SUBROUTINE neighbourElementSegm
!Compute element volume
PURE SUBROUTINE volumeSegm(self)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(inout):: self
REAL(8):: Xi(1:3)
REAL(8):: dPsi(1:3, 1:2), pDer(1:3, 1:3)
REAL(8):: detJ
REAL(8):: fPsi(1:2)
self%volume = 0.D0
!1D 1 point Gauss Quad Integral
Xi = 0.D0
dPsi = self%dPsi(Xi, 2)
pDer = self%partialDer(2, dPsi)
detJ = self%detJac(pDer)
fPsi = self%fPsi(Xi, 2)
!Compute total volume of the cell
self%volume = detJ*2.D0
!Compute volume per node
self%n1%v = self%n1%v + fPsi(1)*self%volume
self%n2%v = self%n2%v + fPsi(2)*self%volume
END SUBROUTINE volumeSegm
!COMMON FUNCTIONS FOR 1D VOLUME ELEMENTS
!Compute element Jacobian determinant
PURE FUNCTION detJ1DCart(pDer) RESULT(dJ)
IMPLICIT NONE
REAL(8), INTENT(in):: pDer(1:3, 1:3)
REAL(8):: dJ
dJ = pDer(1, 1)
END FUNCTION detJ1DCart
!Compute element Jacobian inverse matrix (without determinant)
PURE FUNCTION invJ1DCart(pDer) RESULT(invJ)
IMPLICIT NONE
REAL(8), INTENT(in):: pDer(1:3, 1:3)
REAL(8):: invJ(1:3,1:3)
invJ = 0.D0
invJ(1, 1) = 1.D0/pDer(1, 1)
invJ(2, 2) = 1.D0
invJ(3, 3) = 1.D0
END FUNCTION invJ1DCart
SUBROUTINE connectMesh1DCart(self)
IMPLICIT NONE
CLASS(meshGeneric), INTENT(inout):: self
INTEGER:: e, et
DO e = 1, self%numCells
!Connect Cell-Cell
DO et = 1, self%numCells
IF (e /= et) THEN
CALL connectCellCell(self%cells(e)%obj, self%cells(et)%obj)
END IF
END DO
SELECT TYPE(self)
TYPE IS(meshParticles)
!Connect Cell-Edge
DO et = 1, self%numEdges
CALL connectCellEdge(self%cells(e)%obj, self%edges(et)%obj)
END DO
END SELECT
END DO
END SUBROUTINE connectMesh1DCart
SUBROUTINE connectCellCell(elemA, elemB)
IMPLICIT NONE
CLASS(meshCell), INTENT(inout):: elemA
CLASS(meshCell), INTENT(inout):: elemB
SELECT TYPE(elemA)
TYPE IS(meshCell1DCartSegm)
SELECT TYPE(elemB)
TYPE IS(meshCell1DCartSegm)
CALL connectSegmSegm(elemA, elemB)
END SELECT
END SELECT
END SUBROUTINE connectCellCell
SUBROUTINE connectSegmSegm(elemA, elemB)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(inout), TARGET:: elemA
CLASS(meshCell1DCartSegm), INTENT(inout), TARGET:: elemB
IF (.NOT. ASSOCIATED(elemA%e1) .AND. &
elemA%n2%n == elemB%n1%n) THEN
elemA%e1 => elemB
elemB%e2 => elemA
END IF
IF (.NOT. ASSOCIATED(elemA%e2) .AND. &
elemA%n1%n == elemB%n2%n) THEN
elemA%e2 => elemB
elemB%e1 => elemA
END IF
END SUBROUTINE connectSegmSegm
SUBROUTINE connectCellEdge(elemA, elemB)
IMPLICIT NONE
CLASS(meshCell), INTENT(inout):: elemA
CLASS(meshEdge), INTENT(inout):: elemB
SELECT TYPE(elemA)
TYPE IS (meshCell1DCartSegm)
SELECT TYPE(elemB)
CLASS IS(meshEdge1DCart)
CALL connectSegmEdge(elemA, elemB)
END SELECT
END SELECT
END SUBROUTINE connectCellEdge
SUBROUTINE connectSegmEdge(elemA, elemB)
IMPLICIT NONE
CLASS(meshCell1DCartSegm), INTENT(inout), TARGET:: elemA
CLASS(meshEdge1DCart), INTENT(inout), TARGET:: elemB
IF (.NOT. ASSOCIATED(elemA%e1) .AND. &
elemA%n2%n == elemB%n1%n) THEN
elemA%e1 => elemB
elemB%e2 => elemA
!Rever the normal to point inside the domain
elemB%normal = - elemB%normal
END IF
IF (.NOT. ASSOCIATED(elemA%e2) .AND. &
elemA%n1%n == elemB%n1%n) THEN
elemA%e2 => elemB
elemB%e1 => elemA
END IF
END SUBROUTINE connectSegmEdge
END MODULE moduleMesh1DCart