Hi Eelis,
I tried implementing Sue's code as a UDF and it is consuming a lot of time. In fact, for my first iteration, I get the following message:
Operating system error: Not enough space
Out of memory
I am surprise this happens because this is only the first time step and first iteration step.
Let me just describe what I plan to do:
I am solving a Joule Heating problem where I would like to specify the potential on a boundary that depends on the maximum boundary temperature. For instance, if the temperature at any node on the boundaries of the domain is greater than a value, say To, then the potential is given by V=Vo. Otherwise, it would just be V=0.
So I have in my SIF file:
!***************************************************************************************!
Boundary Condition 2
!***************************************************************************************!
Target Boundaries(12) = 5 6 7 8 9 11 12 13 14 15 16 17
Name = "ZeroFlux"
Heat Flux BC = True
Heat Flux = 0.0
! Potential = pot
MaskBoundary = Logical True
Potential = Variable time
Real Procedure "BCPOT" "BCPOT"
!***************************************************************************************!
End
!***************************************************************************************!
This was after intense search on how to use MakePermUsingMask and I finally successfully compiled it without error. Maybe MakePermUsingMask is not the optimal way of doing what I want but I can't seem to find another option.
You mentioned about writing a solver. I have no experience in that area but I guess I can convert the UDF to a solver quite straightforwardly. If I do that, how do I make the potential that I calculate with this solver visible when I prescribe my boundary condition.
My UDF so far, looks like this, although it may not be the optimum code:
Code: Select all
FUNCTION POT_BC(Model, n ,t) RESULT(pot)
!********************************************************************************!
! MODULE THAT INCLUDES WRAPPERS TO THE BASIC TASKS COMMON TO STANDARD SOLVERS
USE DefUtils
IMPLICIT None
!********************************************************************************!
! DECLARED AND DEFINED IN Types.src AND REFERENCED BY DefUtils
! CONTAINS MESH AND ALL MODEL DATA SPECIFIED IN SOLVER INPUT FILE
TYPE(Model_t) :: Model
TYPE(Solver_t) :: Solver
TYPE(Mesh_t), POINTER :: Mesh
TYPE(Variable_t), POINTER :: TempVariable
INTEGER, POINTER :: BoundaryPerm(:), TempPerm(:)
REAL(KIND=dp), POINTER :: TempValues(:)
REAL(KIND=dp) :: pot, t, cont
REAL(KIND=dp), ALLOCATABLE :: localTemp(:)
INTEGER, ALLOCATABLE :: boundIndex(:)
INTEGER :: i, N, BoundaryNodes, ss
CHARACTER(LEN=12) :: BoundaryName
!********************************************************************************!
! ACCESS BOUNDARY ONLY ELEMENTS USING MakePermUsingMask
Mesh => Model % Mesh
!if (.FALSE.) then
N = Mesh % NumberOfNodes
ALLOCATE(BoundaryPerm(N))
BoundaryPerm = 0
BoundaryNodes = 0
BoundaryName = 'MaskBoundary'
CALL MakePermUsingMask(Model,Model%Solver,Model%Mesh,BoundaryName,.FALSE.,BoundaryPerm,BoundaryNodes)
!end if
!********************************************************************************!
! READ IN ALL VALUES OF RELEVANT VARIABLE (TEMPERATURE)
TempVariable => VariableGet( Model % Variables, 'Temperature' )
IF ( ASSOCIATED( TempVariable ) ) THEN
TempPerm => TempVariable % Perm
TempValues => TempVariable % Values
ELSE
CALL FATAL('POT_BC', 'Need Temperature solver')
END IF
!********************************************************************************!
! ALLOCATE SPACE FOR NEW ARRAYS Allocate space for new arrays
IF (allocated(localTemp)) deallocate(localTemp); allocate(localTemp(BoundaryNodes))
IF (allocated(boundIndex)) deallocate(boundIndex); allocate(boundIndex(BoundaryNodes))
! GET NODE MAPPING
DO i = 1,size(BoundaryPerm)
IF (BoundaryPerm(i)/=0) boundIndex(BoundaryPerm(i))=i
END DO
! CREATE NEW ARRAY USING ONLY VALUES ON THE BOUNDARY
DO i = 1,BoundaryNodes
localTemp(i) = TempValues(TempPerm(boundIndex(i)))
END DO
!pause
!write(*,*) localTemp(BoundaryNodes), BoundaryNodes
!pause
!********************************************************************************!
! RUN DO WHILE LOOP
cont = -10; i = 0;
DO WHILE (cont < 0)
i = i + 1
if (localTemp(i) > 373) then
pot = 25
cont = 10
GO TO 10
else
if (i == BoundaryNodes) then
cont = 10
pot = 30
end if
end if
END DO
10 CONTINUE
END FUNCTION POT_BC
Can anyone help?
Thanks.
Best wishes,
EH
Takala wrote:suecook wrote:Hello,
We managed to get what we needed working. For anyone wanting to use it in future here's what we did:
In the relevant boundary condition of the sif file, one line was added:
In the User Function we added:
Code: Select all
BoundaryName = "MaskBoundary"
CALL MakePermUsingMask(Model, Model%Solver,Model%Mesh,BoundaryName,.false.,BoundaryPerm,BoundaryNodes)
This produces BoundaryPerm, which gives a mask of all the nodes on the relevant boundary, and BoundaryNodes which is the total number of nodes on the boundary. To create an array containing values of a variable only on this boundary we then used this:
Code: Select all
! Read in all values of relevant variable, in this case depth
DepthVariable => VariableGet( Model % Variables, 'Depth' )
IF ( ASSOCIATED( DepthVariable ) ) THEN
DepthPerm => DepthVariable % Perm
DepthValues => DepthVariable % Values
ELSE
CALL FATAL('MyUserFunction', 'Need Depth solver')
END IF
! Allocate space for new arrays
IF (allocated(dpt)) deallocate(dpt); allocate(dpt(BoundaryNodes))
IF (allocated(boundIndex)) deallocate(boundIndex); allocate(boundIndex(BoundaryNodes))
! Get node mapping
DO i=1,size(BoundaryPerm)
IF (BoundaryPerm(i)/=0) boundIndex(BoundaryPerm(i))=i
END DO
! Create new array using only values on boundary
DO i=1,BoundaryNodes
dpt(i) = DepthValues(DepthPerm(boundIndex(i)))
END DO
We have tested the method and it seems to work ok, so hope I hope it might be helpful to others too!
Thanks for the other useful advice on the topic
Sue
I'm not really sure what you want to do. What I understand from your post is that you want to have an array that contain values of some boundary and you use that array to calculate something when for example dealing with some nodes that are not in that boundary.
If this is the case, then I think you should use a solver (instead of User Function) which gets the boundary values once, goes through all the points you want and do the calculations there and stores the result in the solver variable. Then you could say in sif:
SomeVariable = Equals SolverVariable
The reason is that now you are fetching, allocating and deallocating stuff every time you access the user function. This should be really slow when you increase the number of nodes.
Maybe I didn't get the point of what you are doing?
Cheers,
Eelis