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:

- Code: Select all
`MaskBoundary = Logical True`

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