【FastCAE源码阅读8】调用gmsh生成网格

FastCAE使用gmsh进行网格划分,划分的时候直接启动一个新的gmsh进程,个人猜测这么设计是为了规避gmsh的GPL协议风险。
进行网格划分时,其大体运行如下图:
在这里插入图片描述

一、Python到gmshModule模块

GUI操作到Python这步不再分析,比较简单。执行的Python代码大概如下:

gmsher = Mesher.Gmsher()
gmsher.setDim(3)
gmsher.selectedAll()
gmsher.setElementType("Tet")
gmsher.setElementOrder(1)
gmsher.setMethod(1)
gmsher.setSizeFactor(1)
gmsher.setMinSize(0)
gmsher.setMaxSize(100)
gmsher.cleanGeo()
gmsher.startGenerationThread()

这些代码可以在控制台找到,如下图:
在这里插入图片描述
这样创建了一个gmsher对象,赋予网格划分的控制参数,最后调用startGenerationThread()方法,这个方法的源码在Mesher.py文件中。对于三维问题,会调用gmshModule模块的接口GenerateMesh3D()。gmshModule同样提供了针对二维、流体网格的划分接口,代码在GmshPy.h文件中,如下图所示。
在这里插入图片描述

二、启动gmsh线程,写出gmsh文件,生成网格

在GmshPy::GenerateMesh3D()函数中,只是准备网格划分的参数,最后会调用到GmshModule::generateSlot()函数中。

void GmshModule::generateSlot(GMshPara *para)
{
	GmshThread *thread = iniGmshThread(para);
	auto processBar = new ModuleBase::ProcessBar(_mainwindow, tr("Gmsh Working..."));
	_threadManager->insertThread(processBar, thread); // 运行gmsh线程
}

// 初始化gmsh线程
GmshThread *GmshModule::iniGmshThread(GMshPara *para)
{
	if (_threadManager->isRuning())
	{
		delete para;
		ModuleBase::Message m(Common::Message::Error, QString("Gmsh is running !"));
		emit printMessageToMessageWindow(m);
	}
	GmshThread *thread = new GmshThread(_mainwindow, _preWindow, this, para->_dim);
	thread->setPara(para);
	delete para;
	return thread;
}

在GmshModule::generateSlot函数中,会初始化一个线程,并启动运行。
再打开GmshThread的run方法,大体流程就是合并几何对象,形成一个TopoDS_Compound对象,调用BRepTools::Write写出geometry.brep文件。写出gmsh控制文件,最后调用gmsh命令生成网格文件。

	void GmshThread::run()
	{
		this->mergeGeometry(); // 写出几何文件
		this->initGmshEnvoirment(); // 写出gmsh的控制文件
		this->generate(); // 执行gmsh命令
	}

	void GmshThread::mergeGeometry()
	{
		QString exelPath = QCoreApplication::applicationDirPath();
		const QString tempDir = exelPath + "/../temp/";
		QDir dir(tempDir);
		if (!dir.exists())
			dir.mkpath(tempDir);
        
        // 清理之前的临时文件
		const QString meshfilename = exelPath + "/../temp/mesh.vtk";
		if (QFile::exists(meshfilename))
			QFile::remove(meshfilename);

		const QString geofilename = exelPath + "/../temp/geometry.brep";
		if (QFile::exists(geofilename))
			QFile::remove(geofilename);

		const QString gmshfilename = exelPath + "/../temp/gmsh.Geo";
		if (QFile::exists(gmshfilename))
			QFile::remove(gmshfilename);

		const QString tempPath = tempDir + QString("geometry.brep");

		if (_fluidMesh)
			_fluidMeshProcess->mergeFluidField(_compounnd, _solidHash);
		else if (_selectall)
			mergeAllGeo();       // 将需要划分网格的组成一个compounnd对象
		else if (_selectvisible)
			mergeVisibleGeo();
		else
			mergeSelectGeo();
		QByteArray arr = tempPath.toLatin1();
		BRepTools::Write(*_compounnd, arr.data()); // 使用BRepTools写出geometry.brep文件
	}

	void GmshThread::initGmshEnvoirment()
	{
		QString exelPath = QCoreApplication::applicationDirPath();
		const QString tempDir = exelPath + "/../temp/";
		// const QString gmshDir = exelPath + "/gmsh/";
		QFile::remove(tempDir + "gmsh.Geo");

		_scriptWriter->setCompound(_compounnd);
		setGmshScriptData();

		if (_fluidMesh)
		{
			QList<int> curve = _fluidMeshProcess->getInerMember(1);
			QList<int> surface = _fluidMeshProcess->getInerMember(2);
			_scriptWriter->writeFluidMeshScript(tempDir, _solidHash, curve, surface);
		}
		else
			_scriptWriter->writeGmshScript(tempDir); //  写出gmsh控制文件
	}

	void GmshThread::generate()
	{
		QString exelPath = QCoreApplication::applicationDirPath();
		const QString tempDir = exelPath + "/../temp/";
		// const QString gmshDir = exelPath + "/gmsh/";
		QString gmshexe = exelPath + "/gmsh";

		bool ok = false;
#ifdef Q_OS_WIN
		ok = QFile::exists(gmshexe + ".exe");
#endif
#ifdef Q_OS_LINUX
		ok = QFile::exists(gmshexe);
#endif
		if (!ok)
		{
			QMessageBox::warning(_mainwindow, QString(tr("Warning")), QString(tr("Gmsh is not exist !")));
			return;
		}

        // 调用gmsh生成网格
		QString startProcess = QString("%1 %2 -format vtk -bin -o %3 -%4").arg(gmshexe).arg(tempDir + "gmsh.Geo").arg(tempDir + "mesh.vtk").arg(_dim);

		if (gmshexe.contains(" "))
			startProcess = QString("\"%1\"").arg(startProcess);
		qDebug() << startProcess;

		_process.start(startProcess);
	}

最后调用的gmsh命令大体如下,生成mesh.vtk网格文件。
C:/workspace/FastCAE/build/Debug/gmsh C:/workspace/FastCAE/build/Debug/…/temp/gmsh.Geo -format vtk -bin -o C:/workspace/FastCAE/build/Debug/…/temp/mesh.vtk -3

三、读取网格文件

读取网格文件代码在GmshThread::readMesh函数中,注意执行这段代码时gmsh线程已经结束了。

void GmshThread::readMesh()
{
	MeshData::MeshData *data = MeshData::MeshData::getInstance();
	QString exelPath = QCoreApplication::applicationDirPath();
	const QString fileName = exelPath + "/../temp/mesh.vtk";
	QTextCodec *codec = QTextCodec::codecForName("GB18030");
	QByteArray ba = codec->fromUnicode(fileName);
	vtkSmartPointer<vtkDataSetReader> vtkReader = vtkSmartPointer<vtkDataSetReader>::New();
	vtkReader->SetFileName(ba);
	vtkReader->Update();
	vtkDataSet *dataset = vtkReader->GetOutput();
	if (dataset == nullptr)
		return;
	if (!_isSaveToKernal)
		emit writeToSolveFileSig(dataset);
	else
	{
		auto k = new MeshData::MeshKernal();
		k->setName(QString("Mesh_%1").arg(k->getID()));
		k->setMeshData(dataset);
		data->appendMeshKernal(k);
		if (!_fluidMesh)
			setGmshSettingData(k);
		emit _gmshModule->updateMeshTree();
		emit _gmshModule->updateSetTree();
		//			emit _preWindow->updateMeshActorSig();
		emit _gmshModule->updateActions();
		emit updateMeshActor();
	}
}

由于gmsh输出的是vtk文件,这里直接使用vtkDataSetReader读取的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值