帖子探索了将子程序uexternaldb和disp联合进行仿真。
其中,子程序uexternaldb用于在计算分析之前读取预先准备的数据,并将数据处理成公共数据块,再利用子程序disp读取公共数据块中的内容,以位移荷载的形式施加在模型中。
以悬臂梁受随时间变化的位移荷载为例验证子程序计算准确性,最终计算结果表明,与abaqus计算结果保持一致,说明,二者联合仿真可以完成外界数据的导入和施加荷载的计算。帖子末尾给出了所有的计算文件和代码。
uexternaldb子程序是abaqus专门设计出来让子程序与外界的数据进行交互的。该子程序允许在不同的计算时刻调用,最大程度上满足了子程序与外界数据交互的需求,该子程序的接口为
SUBROUTINE UEXTERNALDB(LOP,LRESTART,TIME,DTIME,KSTEP,KINC)
C
INCLUDE 'ABA_PARAM.INC'
C
DIMENSION TIME(2)
C
user coding to set up the Fortran environment, open files, close files,
calculate user-defined model-independent history information,
write history information to external files,
recover history information during restart analyses, etc.
do not include calls to utility routine XIT
RETURN
END
这个子程序的参数并不复杂,下面逐一解释各个参数的含义和使用方法。abaqus对于参数的介绍是非常有逻辑性的,所有的参数一般被分为以下几种:需要我们定义的参数、传递进子程序作为信息的参数、可以更新的参数等等,在这个子程序中,不存在我们需要定义的参数,传递进子程序的所有参数都是我们可以直接使用的信息。 下面是具体的参数介绍。
disp子程序用于定义复杂的边界条件。abaqus所有的自由度均可以使用这个子程序,在这次帖子中,仅仅涉及到位移自由度,即1-3自由度的边界条件。这个子程序的接口为
SUBROUTINE DISP(U,KSTEP,KINC,TIME,NODE,NOEL,JDOF,COORDS)
C
INCLUDE 'ABA_PARAM.INC'
C
DIMENSION U(3),TIME(3),COORDS(3)
C
user coding to define U
RETURN
END
相较于uexternaldb子程序,disp子程序的参数更加简单,而且与上一个子程序的参数有重复,这里只介绍没重复的参数。
参数u就是disp最终向abaqus主程序输出的数据,这个数据要我们自己计算定义,这是一个数组,数组的长度为3,第一个是幅值本身,第二个是幅值的一阶导数,第三个是幅值的二阶导数。
参数node是当前传进子程序的节点编号,就是说,我们可以对不同的节点施加不同的边界条件,这个功能很强大!
参数noel是当前传进子程序的单元编号。
参数jdof是自由度编号。
参数coords是当前位置的坐标,我们还可以对坐标进行判断,给我们想要的位置施加边界条件,这非常方便。
以上是两个子程序的介绍,下面设计算例,在计算的过程中讲解这两个子程序是怎样交互数据的。
这里设计一个悬臂梁受随时间变化的位移荷载算例,悬臂梁尺寸为 ,材料弹性模量 ,密度 ,泊松比 ,悬臂梁的一段固定,悬臂端的所有节点施加同样的随时间变化的位移荷载,悬臂梁的荷载和边界条件示意图为 采用六面体单元离散模型,即C3D8单元,单元尺寸为 ,共计单元数目为250,节点数目为396,网格图为 在悬臂端施加随时间变化的位移荷载,位移荷载采用正弦曲线,即 ,曲线图为 上述算例采用dynamic implicit分析步计算,采用固定增量步长,计算总时长为10,增量步长为0.01,总体增量步数100。设置两种计算工况,分别为
1.完全采用abaqus计算。
2. 采用子程序完成上述计算。具体的步骤为
这里采用的是正弦曲线的位移荷载,可以直接通过excel表格生成。注意计算总时长为10,增量步长为0.01,excel的数值大致为 上面有两列数据,左边为时间序列,时间间隔就是增量步长0.01,右面一列是位移幅值,我们需要将右面一列复 制到一个txt文件中,便于后续的子程序读取。
除了包含位移荷载的txt文件,我们还需要准备一个记录数据总数的文件:“INP_PARAM.INC”,子程序运行的时候,会自动包含这个文件中生成的参数,这里的参数是位移荷载的个数,即总的增量步数,这个文件的书写遵循fortran语法,具体的内容为
PARAMETER (amp = 100) ! Number of INCs
这样就生成了一个变量amp,,子程序就可以直接引用这个变量。
到这里,我们准备了两个文件,一个储存位移荷载的txt文件,用于后续的子程序调用;一个储存增量步总数的文件,下面开始具体的程序讲解,所有的子程序都会在文末给出。
在程序正式开始工作之前,要先将变量和预先准备的文件引用一下
C引用准备的文件,用于储存位移荷载总数
INCLUDE 'INP_PARAM.INC'
我们需要在两个子程序之间传递数据,因此要声明一个公共的数据块COMMON
COMMON/ampinfo/AMPLITUDE(AMP)
下面开始读取数据,读取数据的工作只需要进行一次,即在正式的分析开始之前读取,储存起来,后续所有的增量步都不再读取,因此需要设置一个判断
C 只在分析步开始之前读取数据
if(lop.eq.0)then
C codes
endif
然后开始读取预先准备的txt文件,用open语句读取
OPEN(UNIT=111,FILE='C:\Users\nnn\Desktop\uexternaldb\user\
1patch.txt',STATUS='UNKNOWN')
打开要读取的文件之后,就开始读取并储存数据
C amp是储存在INP_PARAM.INC文件中的增量步总数
do ii=1,AMP
read(111,*)TEMP
C 将读取的temp数据赋值给AMPLITUDE数组
AMPLITUDE(II)=TEMP
enddo
与uexternaldb子程序类似,正式的计算之前也需要引用预先准备的数据,这里主要引用INP_PARAM.INC文件和uexternaldb子程序中声明的公共数据块
INCLUDE 'INP_PARAM.INC'
C
COMMON/ampinfo/AMPLITUDE(AMP)
引用了数据之后就是将位移荷载赋值给相应的参数,这里是位移荷载,因此按照增量步kinc将数据赋值给u(1),即
u(1)=amplitude(kinc)
以上就是子程序的所有主要内容,详细的内容在文末给出。下面是具体的计算结果
写这部分文字其实不如给大家讲述实现过程有意思,这个帖子所有的重点的内容在上面,我就简单放几个图,大家看看就好,需要详细的数据可以私信我。
这里施加的是数值向位移,我就随便选几个时间点的u2对比图放这里,3s的竖直向对比图为 5s的竖直向对比图为 10s的竖直向对比图为
计算inp文件太多了,全部写这里在太长了,我就放一下调用子程序的大致inp文件,需要详细的数据可以私信我。
*Heading
** Job name: Job-1 Model name: Model-1
** Generated by: Abaqus/CAE 2020
*Preprint, echo=NO, model=NO, history=NO, contact=NO
**
** PARTS
**
*Part, name=Part-1
*Node
1, 10., 10., 20.
......
396, 0., 0., 0.
*Element, type=C3D8R
1, 67, 68, 74, 73, 1, 2, 8, 7
....
250, 389, 390, 396, 395, 323, 324, 330, 329
*Nset, nset=Set-1, generate
1, 396, 1
*Elset, elset=Set-1, generate
1, 250, 1
*Nset, nset=load
1, 2, 3, 4, 5, 6, 67, 68, 69, 70, 71, 72, 133, 134, 135, 136
137, 138, 199, 200, 201, 202, 203, 204, 265, 266, 267, 268, 269, 270, 331, 332
333, 334, 335, 336
** Section: Section-1
*Solid Section, elset=Set-1, material=Material-1
,
*End Part
**
**
** ASSEMBLY
**
*Assembly, name=Assembly
**
*Instance, name=Part-1-1, part=Part-1
*End Instance
**
*Nset, nset=Set-1, instance=Part-1-1
61, 62, 63, 64, 65, 66, 127, 128, 129, 130, 131, 132, 193, 194, 195, 196
197, 198, 259, 260, 261, 262, 263, 264, 325, 326, 327, 328, 329, 330, 391, 392
393, 394, 395, 396
*Elset, elset=Set-1, instance=Part-1-1
46, 47, 48, 49, 50, 96, 97, 98, 99, 100, 146, 147, 148, 149, 150, 196
197, 198, 199, 200, 246, 247, 248, 249, 250
*Elset, elset=_Surf-1_S3, internal, instance=Part-1-1
1, 2, 3, 4, 5, 51, 52, 53, 54, 55, 101, 102, 103, 104, 105, 151
152, 153, 154, 155, 201, 202, 203, 204, 205
*Surface, type=ELEMENT, name=Surf-1
_Surf-1_S3, S3
*End Assembly
**
** MATERIALS
**
*Material, name=Material-1
*Density
0.,
*Elastic
1e+10, 0.25
** ----------------------------------------------------------------
**
** STEP: Step-1
**
*Step, name=Step-1, nlgeom=NO, inc=1000
*Dynamic,direct
0.1,10.,
**
** BOUNDARY CONDITIONS
**
** Name: BC-2 Type: Displacement/Rotation
**********************
**这里调用了disp子程序*
**********************
*Boundary, user
Part-1-1.load, 2, 2, 10000.
** Name: fixed Type: Displacement/Rotation
*Boundary
Set-1, 1, 1
Set-1, 2, 2
Set-1, 3, 3
**
** OUTPUT REQUESTS
**
*Restart, write, frequency=0
**
** FIELD OUTPUT: F-Output-1
**
*Output, field, variable=PRESELECT, frequency=1
**
** HISTORY OUTPUT: H-Output-1
**
*Output, history, variable=PRESELECT
*End Step
下面的子程序是完整的,只需要修改下文件路径就能运行。
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C 读取外界数据的子程序
SUBROUTINE UEXTERNALDB(LOP,LRESTART,TIME,DTIME,KSTEP,KINC)
C
INCLUDE 'ABA_PARAM.INC'
INCLUDE 'INP_PARAM.INC'
C
DIMENSION TIME(2)
C 定义全局数据块,所有的子程序都可以调用
COMMON/ampinfo/AMPLITUDE(AMP)
DOUBLE PRECISION TEMP
C 只在分析步开始的时候读取外部txt文件,其余的分析步不读取
if(lop.eq.0)then
C 这里的路径需要自己修改
OPEN(UNIT=111,FILE='C:\Users\nnn\Desktop\uexternaldb\user\
1patch.txt',STATUS='UNKNOWN')
C 读取外部txt文件
do ii=1,AMP
read(111,*)TEMP
AMPLITUDE(II)=TEMP
enddo
close(111)
write(*,*)"***外部数据读取完毕(仅在分析开始之前读取)***"
endif
RETURN
END
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
C 施加位移的子程序
SUBROUTINE DISP(U,KSTEP,KINC,TIME,NODE,NOEL,JDOF,COORDS)
C
INCLUDE 'ABA_PARAM.INC'
INCLUDE 'INP_PARAM.INC'
C
DIMENSION U(3),TIME(3),COORDS(3)
C
COMMON/ampinfo/AMPLITUDE(AMP)
write(*,*)amplitude(kinc)
u(1)=amplitude(kinc)
RETURN
END
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
上面的东西写的花里胡哨的,但是仔细一想,这不纯纯做无用功吗!abaqus自己就可以定义正弦曲线啊!那为什么还要费劲巴拉的在外部定义曲线,还通过两个子程序联合传递数据,这有什么意义呢?
是的,这个帖子如果就内容而言,纯纯没有任何实用价值,纯纯是六个手指头挠痒痒---多一道子!但是如果我们把这个工作流程进行抽象整理,我们再来看看这个帖子做了什么事。
我们首先生成了一些外部数据,然后用uexternaldb子程序读了进来,又通过公共数据快讲数据传递给了disp,最终施加了边界条件。
将上面的步骤拆开分析。uexternaldb可以用来读取外部数据,那这个外部数据的来源就值得考究,这个帖子就只是个简单的三角函数,而且只有一组数据,非常的简单,那假如我们需要导入的数据非常的复杂呢?而且没有任何的函数关系?再假如,如果我们导入的数据是别的软件或者程序实时生成并更新的呢?事情是不是的顿时变得非常有意思了?
一言以蔽之,uexternaldb子程序为abaqus与其他的程序进行联合方针埋下了伏笔!
再来分析一下disp施加边界条件的事情。这里只是施加了一个非常简单的位移边界条件,而且还是单个自由度的一组数据,非常简单,口算都行。但是,假如我们要给接触界面添加界面属性数据呢?假如我们要修改弹性模量呢,假如我们要给一道焊缝施加高斯热源呢?事情是不是的顿时变得非常有意思了?
复杂的事情都是由简单的事情组合起来的;麻雀虽小,五脏俱全,简单的事物也包含着复杂事物的所有基本流程。