ABAQUS二次开发通常可分为两种,一种是涉及到计算内核的二次开发,如:UEL、UMAT、DLOAD等子程序,可以采用FORTRAN或者C++程序编写。另一种是用于模型构建或者后处理的二次开发,可以采用Python或者C++开发,其中,关于Python的资料非常的多,我试过用ai编写读取ODB文件数据的程序,ai可以胜任部分工作。
但是Python在读取大模型文件,尤其是涉及到动力计算,时间步非常的多,计算时间随着时间步的增加而大幅度增加,针对这个问题,官方文档建议使用C++进行处理,C++是官方提供的用于高性能计算的二次开发接口,所有Python能够实现的功能,都能用C++以更快的速度实现,这为我们处理大模型提供了一条思路。
帖子从ABAQUS官方文档中选取一个二次开发案例,采用C++读取ABAQUS的ODB结果文件,讲解了C++程序的编译和运行方法,不涉及到复杂的操作,仅仅给大家提供入门的内容学习。文中给出了详细的源代码。
经常看我帖子的朋友们都知道,我的老演员算例:悬臂梁!悬臂梁的尺寸为 ,悬臂梁弹性模量 ,泊松比 ,密度 ,本算例不做对比计算,因此单位不重要。悬臂梁一端为固定约束条件,另一端受动荷载,荷载表达式为
幅值曲线为
计算总时长为6.28 ,固定增量步长为0.01 ,计算总增量步数为628。悬臂梁边界条件和荷载示意图为
网格图为
对于上面的模型,每一个增量步都输出计算结果,一共628个增量步。
详细的代码我放在了帖子的末尾,这里先讲解程序的编译。具体步骤为
1.进入cmd命令行界面
2.用“cd”命令,将工作路径切换到cpp程序所在的文件夹,如:
cd C:\Users\liunon\Desktop\odb
abaqus make job=name.cpp
上面的命令行之后,当前文件夹会出现可执行exe文件,如:
name.exe
注意不要关闭当前命令行,后续运行程序还要用!命令行输出的内容为:
C:\Users\liunon\Desktop\odb>abq2018 make job=a.cpp
Intel(R) MPI Library 2019 Update 6 for Windows* Target Build Environment for Intel(R) 64 applications
Copyright 2007-2019 Intel Corporation.
Copyright (C) 1985-2019 Intel Corporation. All rights reserved.
Intel(R) Compiler 19.1 (package 164)
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.4.27
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
Abaqus JOB a
Begin Compiling User Post-Processing Program
4/22/2025 8:14:17 PM
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.24.28325 版
版权所有(C) Microsoft Corporation。保留所有权利。
a.cpp
End Compiling User Post-Processing Program
4/22/2025 8:14:21 PM
Begin Compiling User Post-Processing Program
4/22/2025 8:14:21 PM
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.24.28325 版
版权所有(C) Microsoft Corporation。保留所有权利。
main_21004.C
End Compiling User Post-Processing Program
4/22/2025 8:14:22 PM
Begin Linking User Post-Processing Program
4/22/2025 8:14:22 PM
4/22/2025 8:14:22 PM
End Linking User Post-Processing Program
Abaqus JOB a COMPLETED
3.运行程序
在刚刚编译程序的命令行中输入命令:
abaqus name.exe -odb job-1.odb -elset “Part-1-1.set-1”
下面挨个解释上面命令的含义。
abaqus就是自己的abaqus;name是C++程序编译后生成的可执行文件;-odb是引导后面的odb名称:job-1.odb,-elset也是为了引导后面的单元集 合名称:“Part-1-1.set-1”。
输入上述代码后,命令行的输出内容为
PS F:\PSBFEM\odb> abaqus a.exe -odb job-1.odb
Intel(R) MPI Library 2019 Update 6 for Windows* Target Build Environment for Intel(R) 64 applications
Copyright 2007-2019 Intel Corporation.
Copyright (C) 1985-2019 Intel Corporation. All rights reserved.
Intel(R) Compiler 19.1 (package 164)
**********************************************************************
** Visual Studio 2019 Developer Command Prompt v16.4.27
** Copyright (c) 2019 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'
Processing Step: Step-1
Num of Elements:320
Num of ElementNodes:8
Num of Comp:6
Maximum von Mises stress over the entire model is 28.3661 in element 11
Location: frame # 520 step: Step-1
/***************************************************************
Finding the maximum value of von Mises stress
odbMaxMises.cpp
Code to determine the location and value of the maximum
von-mises stress in an output database.
Usage: abaqus odbMaxMises -odb odbName -elset(optional)
elsetName
Requirements:
1. -odb : Name of the output database.
2. -elset : Name of the assembly level element set.
Search will be done only for element belonging
to this set. If this parameter is not provided,
search will be performed over the entire model.
3. -help : Print usage
****************************************************************/
#if (defined(HP) && (! defined(HKS_HPUXI)))
#include <iostream.h>
#else
#include <iostream>
using namespace std;
#endif
#include <odb_API.h>
#include <sys/stat.h>
/*
***************
utility functions
***************
*/
bool fileExists(const odb_String &string);
void rightTrim(odb_String &string, const char* char_set);
void printExecutionSummary();
/***************************************************************/
int ABQmain(int argc, char **argv)
{
odb_String odbPath;
bool ifOdbName = false;
odb_String elsetName;
bool ifElset = false;
odb_Set myElset;
odb_String region = "over the entire model";
char msg[256];
char *abaCmd = argv[0];
for (int arg = 0; arg < argc; arg++)
{
if (strncmp(argv[arg], "-o**", 2) == 0)
{
arg++;
odbPath = argv[arg];
rightTrim(odbPath, ".odb");
if (!fileExists(odbPath))
{
cerr << "**ERROR** output database " << odbPath.CStr()
<< " does not exist\n" << endl;
exit(1);
}
ifOdbName = true;
}
elseif (strncmp(argv[arg], "-e**", 2) == 0)
{
arg++;
elsetName = argv[arg];
ifElset = true;
}
elseif (strncmp(argv[arg], "-h**", 2) == 0)
{
printExecutionSummary();
exit(0);
}
}
if (!ifOdbName)
{
cerr << "**ERROR** output database name is not provided\n";
printExecutionSummary();
exit(1);
}
// Open the output database
odb_Odb& myOdb = openOdb(odbPath);
odb_Assembly& myAssembly = myOdb.rootAssembly();
if (ifElset) {
if (myAssembly.elementSets().isMember(elsetName)) {
myElset = myAssembly.elementSets()[elsetName];
region = " in the element set : " + elsetName;
}
else
{
cerr << "An assembly level elset " << elsetName.CStr()
<< " does not exist in the output database :"
<< myOdb.name().CStr() << endl;
myOdb.close();
exit(0);
}
}
// Initialize maximum values.
float maxMises = -0.1;
int numFV = 0;
int maxElem = 0;
odb_String maxStep = "__None__";
int maxFrame = -1;
static const odb_String Stress = "S";
bool isStressPresent = false;
int numBD = 0, numElems = 0, numIP = 0, numComp = 0, position = 0;
// Iterate over all available steps
odb_StepRepository& sRep1 = myOdb.steps();
odb_StepRepositoryIT sIter1(sRep1);
for (sIter1.first(); !sIter1.isDone(); sIter1.next())
{
odb_Step& step = sRep1[sIter1.currentKey()];
cout << "Processing Step: " << step.name().CStr() << endl;
odb_SequenceFrame& frameSequence = step.frames();
int numFrames = frameSequence.size();
for (int f = 0; f < numFrames; f++)
{
odb_Frame& frame = frameSequence[f];
odb_FieldOutputRepository& fieldRep = frame.fieldOutputs();
if (fieldRep.isMember(Stress))
{
isStressPresent = true;
odb_FieldOutput field = fieldRep.get(Stress);
if (ifElset)
field = field.getSubset(myElset);
const odb_SequenceFieldBulkData& seqVal =
field.bulkDataBlocks();
int numBlocks = seqVal.size();
for (int iblock = 0; iblock < numBlocks; iblock++)
{
const odb_FieldBulkData& bulkData = seqVal[iblock];
numBD = bulkData.length();
numElems = bulkData.numberOfElements();
numIP = numBD / numElems;
numComp = bulkData.width();
float* mises = bulkData.mises();
int* elementLabels = bulkData.elementLabels();
int* integrationPoints = bulkData.integrationPoints();
for (int elem = 0; elem < numElems; elem++)
{
for (int ip = 0; ip < numIP; ip++)
{
position = elem * numIP + ip;
float misesData = mises[position];
if (misesData > maxMises)
{
maxMises = misesData;
maxElem = elementLabels[elem];
maxStep = step.name();
maxFrame = frame.incrementNumber();
}
}
}
}
}
}
}
cout << "Num of Elements:"<< numElems << endl;
cout << "Num of ElementNodes:"<< numIP << endl;
cout << "Num of Comp:"<< numComp << endl;
if (isStressPresent)
{
cout << "Maximum von Mises stress " << region.CStr()
<< " is " << maxMises << " in element "
<< maxElem << endl;
cout << "Location: frame # " << maxFrame << " step: "
<< maxStep.CStr() << endl;
}
else
{
cout << " Stress output is not available in the "
<< "output database : " << myOdb.name().CStr() << endl;
}
// close the output database before exiting the program
myOdb.close();
return(0);
}
bool fileExists(const odb_String &string)
{
bool exists = false;
struct stat buf;
if (stat(string.CStr(), &buf) == 0)
exists = true;
return exists;
}
void rightTrim(odb_String &string, const char* char_set)
{
int length = string.Length();
if (string.Find(char_set) == length)
string.append(odb_String(char_set));
}
void printExecutionSummary()
{
cout << " Code to determine the location and value of the\n"
<< " maximum von-mises stress in an output database.\n"
<< " Usage: abaqus odbMaxMises -odb odbName \n"
<< " -elset(optional), -elsetName\n"
<< " Requirements:\n"
<< " 1. -odb : Name of the output database.\n"
<< " 2. -elset : Name of the assembly level element set.\n"
<< " Search will be done only for element \n"
<< " belonging to this set.\n"
<< " If this parameter is not provided, search \n"
<< " will be performed over the entire model.\n"
<< " 3. -help : Print usage\n";
}