UPF in PyMAPDL#

The following Python UPF examples are available:

Python UserMat subroutine#

This example simulates a block modeled with 3D elements. The user material in the usermat.py file is equivalent to linear elastic. The block is under uniaxial compression. The final deformation is compared with the theoretical result.

Input data#

/batch,list
/title,upf-py1s, 'test usermat.py with 3D elements'

/prep7
/upf,'usermat.py'
tb,user,1,,2
tbdata,1,1e5, 0.3    ! E, Poisson

et,1,185

block,0,1,0,1,0,1
esize,1
mshape,0,3D
vmesh,all
elist

nsel,s,loc,x,0
d,all,ux

nsel,s,loc,y,0
d,all,uy

nsel,s,loc,z,0
d,all,uz,

allsel,all
finish

/solu

time,1
deltime,0.1
eresx,no
nsel,s,loc,x,1
!d,all,ux,-0.01
sf,all,pres,1000        ! pressure on x-axis
allsel,all

outres,all,all

solve

finish
/POST1
set,last
esel,s,elem,,1
/output
presol,s
presol,epel
/com, expected results: Sx=-1000, epel_x=-1e-2
finish
/exit,nosave

usermat.py file#

import grpc
import sys
import math
import numpy as np
from mapdl import *


class MapdlUserService(MapdlUser_pb2_grpc.MapdlUserServiceServicer):
    #   #################################################################
    def UserMat(self, request, context):
        ncomp = request.ncomp
        nDirect = request.nDirect

        response = MapdlUser_pb2.UserMatResponse()

        response.stress[:] = request.stress[:]
        response.ustatev[:] = request.ustatev[:]
        response.sedEl = request.sedEl
        response.sedPl = request.sedPl
        response.epseq = request.epseq
        response.epsPl[:] = request.epsPl[:]
        response.var0 = request.var0
        response.var3 = request.var3
        response.var4 = request.var4
        response.var5 = request.var5
        response.var6 = request.var6
        response.var7 = request.var7

        if ncomp > 4:  # ***    3d, plane strain and axisymmetric example
            usermat3d(request, context, response)
        elif nDirect == 2 and ncomp == 3:  # ***    plane stress example
            usermatps(request, context, response)
        elif ncomp == 3:  # ***    3d beam example
            usermatbm(request, context, response)
        elif ncomp == 1:  # ***    1d beam example
            usermat1d(request, context, response)

        return response


def usermat3d(request, context, response):
    ZERO = 0.0
    HALF = 0.5
    THIRD = 1.0 / 3.0
    ONE = 1.0
    TWO = 2.0
    SMALL = 1.0e-08
    sqTiny = 1.0e-20
    ONEDM02 = 1.0e-02
    ONEDM05 = 1.0e-05
    ONEHALF = 1.5
    TWOTHIRD = 2.0 / 3.0
    mcomp = 6

    G = [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]

    db.start()  # Connect to the MAPDL DB gRPC Server
    ncomp = request.ncomp

    # *** get Young's modulus and Poisson's ratio
    young = request.prop[0]
    posn = request.prop[1]
    twoG = young / (ONE + posn)
    elast1 = young * posn / ((1.0 + posn) * (1.0 - TWO * posn))
    elast2 = HALF * twoG

    #
    # *** calculate elastic stiffness matrix (3d)
    #
    dsdeEl = np.zeros((6, 6))

    dsdeEl[0, 0] = (elast1 + TWO * elast2) * G[0] * G[0]
    dsdeEl[0, 1] = elast1 * G[0] * G[1] + elast2 * TWO * G[3] * G[3]
    dsdeEl[0, 2] = elast1 * G[0] * G[2] + elast2 * TWO * G[4] * G[4]
    dsdeEl[0, 3] = elast1 * G[0] * G[3] + elast2 * TWO * G[0] * G[3]
    dsdeEl[0, 4] = elast1 * G[0] * G[4] + elast2 * TWO * G[0] * G[4]
    dsdeEl[0, 5] = elast1 * G[0] * G[5] + elast2 * TWO * G[3] * G[4]

    dsdeEl[1, 1] = (elast1 + TWO * elast2) * G[1] * G[1]
    dsdeEl[1, 2] = elast1 * G[1] * G[2] + elast2 * TWO * G[5] * G[5]
    dsdeEl[1, 3] = elast1 * G[1] * G[3] + elast2 * TWO * G[0] * G[3]
    dsdeEl[1, 4] = elast1 * G[1] * G[4] + elast2 * TWO * G[0] * G[4]
    dsdeEl[1, 5] = elast1 * G[1] * G[5] + elast2 * TWO * G[1] * G[5]

    dsdeEl[2, 2] = (elast1 + TWO * elast2) * G[2] * G[2]
    dsdeEl[2, 3] = elast1 * G[2] * G[3] + elast2 * TWO * G[4] * G[5]
    dsdeEl[2, 4] = elast1 * G[2] * G[4] + elast2 * TWO * G[4] * G[2]
    dsdeEl[2, 5] = elast1 * G[2] * G[5] + elast2 * TWO * G[5] * G[2]

    dsdeEl[3, 3] = elast1 * G[3] * G[3] + elast2 * (G[0] * G[1] + G[3] * G[3])
    dsdeEl[3, 4] = elast1 * G[3] * G[4] + elast2 * (G[0] * G[5] + G[4] * G[3])
    dsdeEl[3, 5] = elast1 * G[3] * G[5] + elast2 * (G[3] * G[5] + G[4] * G[1])

    dsdeEl[4, 4] = elast1 * G[4] * G[4] + elast2 * (G[0] * G[2] + G[4] * G[4])
    dsdeEl[4, 5] = elast1 * G[4] * G[5] + elast2 * (G[3] * G[2] + G[4] * G[5])

    dsdeEl[5, 5] = elast1 * G[5] * G[5] + elast2 * (G[1] * G[2] + G[5] * G[5])

    for i in range(0, 5):
        for j in range(i + 1, 6):
            dsdeEl[j, i] = dsdeEl[i, j]

    Strain = np.zeros(ncomp)
    Strain[0:ncomp] = request.Strain[0:ncomp]
    dStrain = np.zeros(ncomp)
    dStrain[0:ncomp] = request.dStrain[0:ncomp]

    #
    # *** calculate the stress and
    #     copy elastic moduli dsdeEl to material Jacobian matrix

    strainEl = np.copy(Strain)  # strainEl = Strain
    strainEl = np.add(strainEl, dStrain)  # strainEl += dStrain

    dsdePl = np.copy(dsdeEl)
    sigElp = np.zeros(ncomp)
    sigElp = dsdeEl.dot(strainEl)

    response.stress[:] = sigElp
    dsdePl.shape = 6 * 6
    response.dsdePl[:] = dsdePl

    return response


if __name__ == "__main__":
    upf.launch(sys.argv[0])

Python UsrShift subroutine#

This example describes a block of Prony viscoplastic material with a user-defined shift function following a Tool-Narayanaswamy shift function. Uniaxial tension is applied on one end and held for 15 seconds with a constant 280 K uniform temperature. The final stress is obtained to verify stress relaxation.

Input data#

/batch,list
/title,upf-py10s, 'test usrshift.py'

/prep7
/upf,'usrshift.py'

n1=60
n2=n1*10
n3=n1
dy = 0.0045
fact=2
t1end=30.0/fact
alpha = 0.5
tau = 2.0
a1 = alpha          ! participating factor for el182, 183
t1 = tau
c1 = a1/a1          ! participating factor for el88

tr = 0
theta = 280
toffst,273
tunif, theta
tref,0
b1 = log(fact)*(273+tr)*(273+theta)/(theta-tr)
b2 = 1
b11=b1/273/273

young = 20e5
poiss = 0.3
G0 = young/2/(1+poiss)
K0 = young/3/(1-2*poiss)

! material 1                ! rate-dependent vpl
mp,ex,1,young
mp,nuxy,1,0.3
tb,prony,1,,1,shear         ! define viscousity parameters
tbdata,1,a1,t1
tb,prony,1,,1,bulk          ! define viscousity parameters
tbdata,1,a1,t1
tb,shift,1,,2,100           ! Tool-Narayanaswamy shift function
tbdata,1,tr,b11,

! FE model and mesh

et,1,186
mat,1
block,0,1,0,1,0,1
esize,1
vmesh,1

nall
nsel,s,loc,x
d,all,ux
nall
nsel,s,loc,y
d,all,uy
nall
nsel,s,loc,z
d,all,uz

/solu
nlgeom,on
cnvtol,u,,1.0e-8
cnvtol,f,,1.0e-6
nsel,s,loc,y,1.000
d,all,uy,dy
nall
time,1.0e-8
nsubst,1,1,1
outres,all,-10
solve

nsel,s,loc,y,1.000
time,t1end
d,all,uy,dy
nall
nsubst,n1,n2,n3
outres,all,-10
outpr,all,last
solve

finish

/post1
set,last
/output
presol,s

/com, expected results   Sy=4490.0

finish
/exit,nosave

usrshift.py file#

import grpc
import sys
import math
from mapdl import *


class MapdlUserService(MapdlUser_pb2_grpc.MapdlUserServiceServicer):
    #   #################################################################

    def UsrShift(self, request, context):
        response = MapdlUser_pb2.UsrShiftResponse()
        one = 1.0
        half = 0.5
        quart = 0.25

        tref = request.propsh[0]
        temp = request.temp
        timinc = request.timinc
        dtemp = request.dtemp
        nTerms = request.nTerms

        thalf = temp - dtemp * half - tref
        t3quart = temp - dtemp * quart - tref

        c1 = 0.0
        c2 = 0.0

        for i in range(nTerms - 1):
            c1 = c1 + request.propsh[i + 1] * thalf ** (i + 1)
            c2 = c2 + request.propsh[i + 1] * t3quart ** (i + 1)

        dxi = math.exp(c1) * timinc
        dxihalf = math.exp(c2) * timinc * half

        response.dxi = dxi
        response.dxihalf = dxihalf

        return response


if __name__ == "__main__":
    upf.launch(sys.argv[0])

Python UserHyper subroutine#

This example models a block under simple uniaxial tension. The block is made of a user-defined hyper material that is identical to Arruda-Boyce hyperelasticity. Large deformation effects are included. The final stress is printed for comparison against the reference.

Input data#

/BATCH,LIST
/title, upf-py16s, 'test UserHyper.py with MAPDL'
/com, displacement-controlled uniaxial tension test for Boyce material model

/prep7

/upf,'userhyper.py'
tb,hyper,1,,,user
tbdata,1,2/100,0.2,2.8284

et,1,185

block,0,1,0,1,0,1
esize,1
vmesh,1

nsel,s,loc,x
d,all,ux
nsel,s,loc,y
d,all,uy
nsel,s,loc,z
d,all,uz
nall

nsel,s,loc,x,1.0
d,all,ux,0.3

nall

/solu

nlgeom,on
time,1
nsubst,5,20,5

/out,scratch
solve

/post1
/output

set,1,last
presol,s,x

/com, 'expected results from equivalent userhyper.F'
/com,    NODE     SX           SY           SZ           SXY          SYZ
/com,       2  0.20118      0.32054E-003 0.32054E-003 0.13752E-015 0.67903E-017
/com,       4  0.20118      0.32054E-003 0.32054E-003 0.13776E-015 0.40293E-017
/com,       3  0.20118      0.32054E-003 0.32054E-003 0.50933E-015-0.10653E-014
/com,       1  0.20118      0.32054E-003 0.32054E-003 0.50909E-015-0.54682E-015
/com,       5  0.20118      0.32054E-003 0.32054E-003-0.15222E-015 0.58245E-015
/com,       6  0.20118      0.32054E-003 0.32054E-003-0.15313E-015 0.10856E-014
/com,       7  0.20118      0.32054E-003 0.32054E-003-0.55356E-015 0.17421E-016
/com,       8  0.20118      0.32054E-003 0.32054E-003-0.55265E-015 0.28848E-016

finish
/exit,nosave

userhyper.py file#

import grpc
import sys
from mapdl import *
import math
import numpy as np

firstcall = 1


class MapdlUserService(MapdlUser_pb2_grpc.MapdlUserServiceServicer):
    #   #################################################################
    def UserHyper(self, request, context):
        global firstcall
        if firstcall == 1:
            print(">> Using Python UserHyper function\n")
            firstcall = 0

        prophy = np.copy(request.prophy)
        invar = np.copy(request.invar)

        response = MapdlUser_pb2.UserHyperResponse()

        ZERO = 0.0
        ONE = 1.0
        HALF = 0.5
        TWO = 2.0
        THREE = 3.0
        TOLER = 1.0e-12

        ci = (
            0.5,
            0.05,
            0.104761904761905e-01,
            0.271428571428571e-02,
            0.770315398886827e-03,
        )

        i1 = invar[0]
        jj = invar[2]
        mu = prophy[1]
        lm = prophy[2]
        oD1 = prophy[0]
        i1i = ONE
        im1 = ONE / i1
        t3i = ONE
        potential = ZERO
        pInvDer = np.zeros(9)

        for i in range(5):
            ia = i + 1
            t3i = t3i * THREE
            i1i = i1i * i1
            i1i1 = i1i * im1
            i1i2 = i1i1 * im1
            lm2 = ci[i] / (lm ** (TWO * (ia - ONE)))
            potential = potential + lm2 * (i1i - t3i)
            pInvDer[0] = pInvDer[0] + lm2 * ia * i1i1
            pInvDer[2] = pInvDer[2] + lm2 * ia * (ia - ONE) * i1i2

        potential = potential * mu
        pInvDer[0] = pInvDer[0] * mu
        pInvDer[2] = pInvDer[2] * mu

        j1 = ONE / jj
        pInvDer[7] = ZERO
        pInvDer[8] = ZERO

        if oD1 > TOLER:
            oD1 = ONE / oD1
            incomp = False
            potential = potential + oD1 * ((jj * jj - ONE) * HALF - math.log(jj))
            pInvDer[7] = oD1 * (jj - j1)
            pInvDer[8] = oD1 * (ONE + j1 * j1)

        response.potential = potential
        response.incomp = incomp
        response.pInvDer[:] = pInvDer[:]

        return response


if __name__ == "__main__":
    upf.launch(sys.argv[0])