首页/文章/ 详情

ABAQUS C++二次开发案例学习

4小时前浏览1

概述

  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
  1. 采用如下命令编译cpp程序
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

完整C++代码

/***************************************************************
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";
}

来源:有限元先生

AbaqusSTEPS二次开发pythonUMCST
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-05-05
最近编辑:4小时前
外太空土豆儿
博士 我们穷极一生,究竟在追寻什么?
获赞 38粉丝 19文章 77课程 0
点赞
收藏
作者推荐

开源fem程序calculix中的线单元积分点讲解

概述  开源程序calculix采用fortran语言编写,该程序自带前处理界面,从abaqus导出的inp文件可以直接被calculix读取计算,我在之前的帖子中讲过如何用calculix导入喷气发动机模型,下面是一个图片,有兴趣可以点击链接看看。  本次帖子学习开源fem程序calculix中的积分点子程序,子程序的名字为gauss.f,里面包含calculix所有单元的积分点数据,包括gauss积分和hammer积分,详细给出了低阶和高阶积分的积分点坐标和权重数据,下面详细讲解这个子程序。子程序概况  这个子程序在开始给出了一系列的注释,主要是说明这个子程序包含了所有单元的gauss和hammer数值积分点坐标以及对应的积分权重。如下所示!!containsGausspointinformation!!gauss1d1:lin,1-pointintegration(1integrationpoint)!gauss1d2:lin,2-pointintegration(2integrationpoints)!gauss1d3:lin,3-pointintegration(3integrationpoints)!gauss2d1:quad,1-pointintegration(1integrationpoint)!gauss2d2:quad,2-pointintegration(4integrationpoints)!gauss2d3:quad,3-pointintegration(9integrationpoints)!gauss2d4:tri,1integrationpoint!gauss2d5:tri,3integrationpoints!gauss2d6:tri,7integrationpoints!gauss3d1:hex,1-pointintegration(1integrationpoint)!gauss3d2:hex,2-pointintegration(8integrationpoints)!gauss3d3:hex,3-pointintegration(27integrationpoints)!gauss3d4:tet,1integrationpoint!gauss3d5:tet,4integrationpoints!gauss3d6:tet,15integrationpoints!gauss3d7:wedge,2integrationpoints!gauss3d8:wedge,9integrationpoints!gauss3d9:wedge,18integrationpoints!gauss3d10:wedge,6integrationpoints!gauss3d11:wedge,1integrationpoints!gauss3d12:hex,14integrationpoints(forc3d27)!gauss3d13:hex,2x5x5=50integrationpoints(forbeams)!gauss3d14:wedge,1integrationpoint!!weight2d1,...containstheweights!!  可见calculix中的单元大致可分为三类:线单元(line)、二维单元(2d)和三维单元(3d)。积分点的数据表示为:gaussxdy,其中,表达式里面的x代表单元的维度,当x=1时,单元是一维的,即线单元,以此类推;y代表积分点的个数;当y=1时,只采用一个积分点,以此类推,假如y=14,则说明单元采用了14个积分点。  下面我会在每一类单元中给出若干个单元的图示,包括单元的形状和积分点位置图示。线单元积分公式  根据等参元理论,在一维线单元中,刚度矩阵或者质量矩阵,总可以写成如下形式  上述公式是连续的积分,如果无法导出解析解,那就无法直接用计算机求解,虽然一些简单的单元,如线单元和三角形单元可以将刚度矩阵解析求解,但为了通用性,我们还是经常采用数值求解,常常采用的数值积分有gauss积分和hammer积分,对于线单元的gauss积分有如下表达式  其中为积分点个数,为积分点坐标对应的权重。下面就依次讲解calculix线单元的三种gauss积分方式。  线单元(line)1点积分  线单元的1个积分点坐标对应的代码为gauss1d1=reshape((/0.d0/),(/1,1/))  对应的权重代码为weight1d1=(/2.d0/)  采用1个积分点计算线单元,则图示为  上面1个标有颜色的点,就是积分点的位置,根据等参元及数值积分的理论,当时,有线单元(line)2点积分  线单元的2个积分点坐标对应的代码为gauss1d2=reshape((/&amp;-0.577350269189626d0,0.577350269189626d0/),(/1,2/))  对应的权重代码为weight1d2=(/1.d0,1.d0/)  采用2个积分点计算线单元,则图示为  上面两个标有颜色的点,就是积分点的位置,根据等参元及数值积分的理论,当时,有  对于质量矩阵的求解,有类似的表达式,在此不过多赘述。线单元(line)3点积分  线单元的2个积分点坐标对应的代码为gauss1d3=reshape((/&amp;-0.774596669241483d0,0.d0,0.774596669241483d0/),(/1,3/))  对应的权重代码为weight1d3=(/0.555555555555555d0,0.888888888888888d0,&amp;0.555555555555555d0/)  采用3个积分点计算线单元,则图示为  上面3个标有颜色的点,就是积分点的位置,根据等参元及数值积分的理论,当时,有  对于质量矩阵的求解,有类似的表达式,在此不过多赘述。来源:有限元先生

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈