第一个例子:求解泊松方程

适合学习有限元编程的小白!有限元法求解一维泊松方程MATLAB程序及详解,纯原创。(程序含注释) 一维泊松方程,有限元法,MATLAB。 阅读详情
本人为个人学习之便在此转载,局部加工,版权归原作者:李若所有,更多文章请访问 作者的BLOG。
(转载时请注明作者和出处。未经许可,请勿用于商业用途)

[摘要]
  1. 狄氏边值问题的泊松方程
  2. EasyMesh 输入文件示例
  3. 程序的注释版!!!

第一个例子:求解泊松方程

AFEPack /老弱 

AFEPack 的基本使用方法,我们通过下面的求解泊松方程的程序来具体讲解。假设我们现在需要在区域
$ /Omega = [0, 1]/times[0, 1] $ 上来求解一个 狄氏边值问题的泊松方程

/[
  -/Delta u = f, /qquad u |_{/partial /Omega} = u_b.
/]

作为有限元程序,第一个问题就是要对区域进行剖分,得到网格的数据。我们这里使用一个简单的二维三角形网格剖分软件 EasyMesh来对区域进行剖分。 EasyMesh有一个一页纸的说明书,请读者自己去阅读它。EasyMesh需要用户手工写一个对区域进行描述的文件作为输入文件,我们使用的文件名为 D.d,其内容如下:

/begin{verbatim}
4 # 区域的顶点的个数 #
0: 0.0 0.0 0.05 1
1: 1.0 0.0 0.05 1
2: 1.0 1.0 0.05 1
3: 0.0 1.0 0.05 1

4 # 区域的边界上边的条数 #
0: 0 1 1
1: 1 2 1
2: 2 3 1
3: 3 0 1
/end{verbatim}

其中前面一个部分描述区域中的顶点,共有4个,然后每一行描述一个顶点的信息,其意义为

/begin{verbatim}
顶点的序号:    x坐标    y坐标    剖分密度h    材料标识
/end{verbatim}

后面一个部分则描述区域的边界上的边的条数,共有4条,然后每一行描述一条
边的信息,其意义为

/begin{verbatim}
边的序号:    起始顶点序号    结束顶点序号    材料标识
/end{verbatim}

以这个文件的主文件名 D 作为输入,运行 easymesh D,即可获得网格数据,存储在三个不同的文件中,名为 D.n,D.s,D.e,存储的分别是节点、边和单元的信息。EasyMesh 的说明中有对这些文件格式的详细说明,而 AFEPack 也提供了对这种数据格式的文件读入的接口。

在得到了网格数据以后,我们即可以开始对程序进行说明。我们的 整个程序的原文和详细的说明如下:
#include  < stdio.h >
#include 
< dlfcn.h >

#include 
< iostream >
#include 
< fstream >

#include 
< base / exceptions.h >
#include 
< lac / vector.h >
#include 
< lac / sparsity_pattern.h >
#include 
< lac / sparse_matrix.h >

#include 
< AFEPack / AMGSolver.h >          /// 代数多重网格求解器
#include  < AFEPack / TemplateElement.h >    /// 参考单元
#include  < AFEPack / FEMSpace.h >           /// 有限元空间
#include  < AFEPack / Operator.h >           /// 算子
#include  < AFEPack / BilinearOperator.h >   /// 双线性算子
#include  < AFEPack / Functional.h >         /// 泛函
#include  < AFEPack / EasyMesh.h >           /// EasyMesh 接口

#define  DIM 2                /**< 区域的维数 */
#define  PI (4.0*atan(1.0))   /**< 常数 pi   */

/** 
 * 精确解 u 的表达式
 * 
 * @param p 区域上的点的坐标: x = p[0], y = p[1]
 * 
 * @return u(x, y)
 
*/

double  _u_( const   double   *  p)
{
  
return sin(PI*p[0]) * sin(2*PI*p[1]);
}


/** 
 *  右端项函数 f 的表达式
 * 
 * @param p 区域上的点的坐标: x = p[0], y = p[1]
 * 
 * @return f(x, y)
 
*/

double  _f_( const   double   *  p)
{
  
return 5*PI*PI*_u_(p);
}


/** 
 * 主函数:程序在运行的时候,我们要求有一个命令行参数,即为网格数据
 *         文件名 D。
 * 
 * @param argc 命令行参数个数
 * @param argv 命令行参数列表
 * 
 * @return 返回 0
 
*/

int  main( int  argc,  char   *  argv[])
{
  
/**
   * AFEPack 中的 EasyMesh 类能够读入 EasyMesh 产生的数据文件的接口,
   * 它本身是由网格类 Mesh 派生出来的,可以当成一个网格使用
   
*/

  EasyMesh mesh; 
  mesh.readData(argv[
1]); /// 以第一个命令行参数为文件名,读入网格数据

  
/**
   * 下面这个段落是为有限元空间准备参考单元的数据。AFEPack 将参考单元
   * 的数据分成为四个不同的信息,包括:
   *
   *   - 参考单元的几何信息
   *   - 参考单元到网格中的单元的坐标变换
   *   - 单元上的自由度分布
   *   - 单元上的基函数
   *
   * 使用这几个信息反复组合,可以得到很多种不同的参考单元。这四个信息
   * 的管理使用了四个不同的类,名为 TemplateGeometry, CoordTransform,
   * TemplateDOF 和 BasisFunctionAdmin。这四个类都可以从数据文件中读入
   * 信息来构造其自身的结构,而对于很多常用的单元,这些数据文件都已经
   * 准备在了 AFEPack 的 template 子目录下。这些数据文件的数据格式在
   * AFEPack 的文档之中有比较详细的说明。为了能够使得 AFEPack 顺利的找
   * 到这些数据文件,我们需要设置环境变量 AFEPACK_TEMPLATE_PATH。比如
   * 对于我们这个问题的计算,我们需要设置(假设 bash)
   *
   * <pre>
   *   $ export AFEPACK_TEMPLATE_PATH=$AFEPACK_PATH/template/triangle
   * </pre>
   *
   * 其中 AFEPACK_PATH 假设为 AFEPack 的安装路径。
   
*/


  
/**
   * 参考单元的几何信息:其中模板参数 DIM 为参考单元的维数,对于我们现
   * 在的三角形来说就是 2。参考单元的几何信息中包括参考单元的几何结构,
   * 以及进行数值积分的时候的一系列积分公式的信息。
   * 
   
*/

  TemplateGeometry
<DIM> triangle_template_geometry;
  triangle_template_geometry.readData(
"triangle.tmp_geo");

  
/**
   * 从参考单元到网格中的单元的坐标变换:这个类有两个模板参数,分别为
   * 参考单元的维数和网格中单元的维数。这两个数可能是不一样的,比如从
   * 标准三角形到球面三角形的坐标变换。这个类中提供了将参考单元中的点
   * 和实际网格单元中的点相互进行变换以及变换的雅可比行列式的计算方法。
   
*/

  CoordTransform
<DIM,DIM> triangle_coord_transform;
  triangle_coord_transform.readData(
"triangle.crd_trs");

  
/**
   * 自由度分布指定了在单元的每个构件几何体上分布的自由度的个数,因此
   * 它需要在知道了参考单元的几何构型的情况下进行初始化。
   
*/

  TemplateDOF
<DIM> triangle_template_dof(triangle_template_geometry);
  triangle_template_dof.readData(
"triangle.1.tmp_dof");

  
/**
   * 类 BasisFunctionAdmin 事实上管理着一组基函数,每个基函数为指定自
   * 己依赖的几何体,在参考单元上的插值点,一组称为"基函数识别协议"的
   * 信息,以及每个基函数的函数值和函数梯度的计算方法。
   
*/

  BasisFunctionAdmin
<double,DIM,DIM> triangle_basis_function(triangle_template_dof);
  triangle_basis_function.readData(
"triangle.1.bas_fun");

  
/**
   * 将上面的这四个信息组合到类 TemplateElement 中,就得到了一个完整的
   * 参考单元。而建立有限元空间需要一个网格和一组参考单元,现在我们只
   * 使用一个参考单元。
   
*/

  std::vector
<TemplateElement<double,DIM,DIM> > template_element(1);
  template_element[
0].reinit(triangle_template_geometry,
                             triangle_template_dof,
                             triangle_coord_transform,
                             triangle_basis_function);

  
/**
   * 使用我们读入的 EasyMesh 得到的网格,和刚刚创建的参考单元组来初始
   * 化有限元空间。
   
*/

  FEMSpace
<double,DIM> fem_space(mesh, template_element);
        
  
/**
   * 我们先取出网格中的单元的个数,然后据此为有限元空间中的单元保留网
   * 格中的几何体单元同样数量的空间。此后,我们使得有限元空间中的每个
   * 单元是根据网格中的相应序号的几何体单元映射上第零号参考单元得到的。
   
*/

  
int n_element = mesh.n_geometry(DIM);
  fem_space.element().resize(n_element);
  
for (int i = 0;i < n_element;i ++) {
    fem_space.element(i).reinit(fem_space,i,
0);
  }


  
/**
   * 下面三行分别建立有限元空间中的单元的内部数据结构,然后在整个网格
   * 上分布自由度以及为所有的自由度确定材料标识。自此,整个有限元空间
   * 的所有数据就都准备好了。
   
*/

  fem_space.buildElement();
  fem_space.buildDof();
  fem_space.buildDofBoundaryMark();

  
/**
   * 在上面建立的这个有限元空间上,我们计算一个刚度矩阵,就是由元素
   *
   *  [
   *    a_{ij} = int_Omega  abla phi^i cdot  abla phi^j dx
   *  ]
   *
   * 所构成的矩阵。由于这是常用矩阵,因此库中间有准备这个矩阵。建立这
   * 个矩阵,我们先使用上面的有限元空间构造这个矩阵的对象,然后设置计
   * 算矩阵时候使用的数值积分公式的代数精度的阶数。最后,调用函数
   * build 即可将矩阵计算出来。
   
*/

  StiffMatrix
<DIM,double> stiff_matrix(fem_space);
  stiff_matrix.algebricAccuracy() 
= 3;
  stiff_matrix.build();

  
/**
   * 有限元函数 u_h 用来逼近解函数 u
   
*/

  FEMFunction
<double,DIM> u_h(fem_space);

  
/**
   * 向量 f_h 用来计算右端项 f 在离散过后得到的向量,其元素为
   *
   *  [
   *    f_i = int_Omega f phi^i dx
   *  ]
   *
   * 函数 Operator::L2Discretize 帮助我们完成这个向量的计算。
   
*/

  Vector
<double> f_h;
  Operator::L2Discretize(
&_f_, fem_space, f_h, 3);

  
/**
   * 下面这段是使用上狄氏边值条件:我们为材料标识为 1 的自由度使用函数
   * 表达式计算了其函数值,从而应用上了想要的边值条件。我们通过直接修
   * 改获得的线性系统中的稀疏矩阵和右端项来达成这样的结果。
   
*/

  BoundaryFunction
<double,DIM> boundary(BoundaryConditionInfo::DIRICHLET, 1, &_u_);
  BoundaryConditionAdmin
<double,DIM> boundary_admin(fem_space);
  boundary_admin.add(boundary);
  boundary_admin.apply(stiff_matrix, u_h, f_h);

  
/**
   * 调用 AFEPack 中的代数多重网格求解器,求解线性系统
   
*/

  AMGSolver solver(stiff_matrix);
  solver.solve(u_h, f_h, 
0, 0, 50);      

  
/**
   * 将解输出到一个数据文件中。我们这里使用了 Open Data Explorer 的数
   * 据文件格式,输出的数据可以使用该软件来做可视化。
   
*/

  u_h.writeOpenDXData(
"u.dx");

  
/**
   * 由于这个问题有精确解,我们计算一下数值解和精确解的 L^2 误差。
   
*/

  
double error = Functional::L2Error(u_h, FunctionFunction<double>(&_u_), 3);
  std::cerr 
<< " L2 error = " << error << std::endl;

  
return 0;
}
;

这个程序是使用 AFEPack 进行程序设计的基本套路,虽然其中基本上没有用户输入的关于计算方面的内容,但是很多问题都可以通过对这个程序进行不多的修改就能完成计算。

下面是上面程序的一个算例的图形:
1.网格

2.解的等高线
使用Python求解泊松方程 阅读详情

相关推荐

格林函数求解泊松方程介绍

泊松方程是静电场问题的基础,下面我们以此方法为基础 自由空间中的泊松方程 可以证明这个方程的解为 用相同的方法,这个解记作格林函数 在自由空间下,任意泊松方程的 解可以写为            这就是静电场的叠加原理 如果不是自由空间,这个公式是不成立的,因为有除了空间内电荷,还有感应电荷分布。 这个公式的完整形式是 第一项就是之前算的源电荷的积分所产生的影响。...

wwxy1995的博客 1万+

EasyMesh最简单的入门级介绍

由于不少同学和我说说看EasyMesh协议太费劲,能否通过通俗点讲一下EasyMesh,因此我用最简短的语言和最通俗的描述来介绍EasyMesh,希望对大家有帮助。 目录 重要概念 EasyMesh网络 Controller Agent Fronthaul 与Backhaul 导入、发现、配置过程 特色功能   EasyMesh的简单的理解就是:就是传统的AP Clinet模式 + 一定规则的自动配置。 省去了以前用户手动配置SSID密码的过程,增加了一些提高用户体验的特性。达到2台或以上无线路由器设备,可以自动连接到一起组网的协议。 EasyMesh协议在Wi-Fi联盟那里叫:Multi-

有限元-二维泊松方程求解实战(矩形网格、三角单元)

本文详细介绍了有限元方法在二维泊松方程求解中的实战应用,重点讲解了矩形网格的三角剖分技术、线性基函数构造及矩阵组装过程。通过MATLAB代码示例展示了从网格生成到边界条件处理的全流程,并验证了方法的精度与收敛性,为工程计算中的热传导等问题提供了实用解决方案。

weixin_30952535的博客 494

离散域下的泊松方程求解(python实现)

目录 一、背景 二、原理 1、离散Laplace算子介绍 2、Laplace卷积 3、Possion方程解法介绍 三、验证 四、Python下的算法实现 a、DCT求解 1、定义函数calMSE计算误差Mean Square Error 2、导入原图并记下大小 3、拓展原图 4、卷积并求DCT变换 5、除以分母 6、逆变换、拉回低频并显示。 7、打印误差与耗时 b、DST求解 五、误差与结果 六、源码 一、背景 数字化之后的图...

qq_57731481的博客 8511

OpenMP的调度-以泊松方程求解为例子

OpenMP的调度主要包括static,dynamic,guided,runtime,auto这5种,下面我们重点介绍前面4种调度方式。我们将针对九点差分法求解泊松方程来考虑这几种调度方式的使用。使用的从句是schedule(type,chunk) Makefile run.slurm omp_schedule.c **这里注意schedule从句和ordered从句只能跟#pragma omp parallel for,不能跟#pragma omp parallel,**为了方便后面打印不同线程的分配任务

forrestguang的博客 538

深度ritz方法求解高维泊松方程

此时样本数目过于庞大,一定会导致训练特别耗时。为此可以采取的策略是,每训练一定次数,就重新撒点,对于边界点也是类似的。举例子,如果我们在区域内部采集1000个样本点,扩散到每个维度,那么每个维度最多采集了2个点,因为。,这样导致样本数目过小,如果一开始每个维度采集20个点,那么需要采集的样本数目就是。长度因子需要满足在边界上取值为0,在内部区域恒大于0.,利用netg训练边界数据,构建均方误差函数,训练完以后netg满足。表示区域维度,这里我们使用PFNN算法来求解这个问题。即可,这个思想非常简单。

forrestguang的博客 1506

FEniCS学习笔记03:求解泊松方程数学原理及程序实现

内容来自官网tutorial,第一次运行可能会报错

huahua_xiao的博客 2669

cuda编程:稀疏矩阵乘法结合MINRES算法求解泊松方程的并行编程

稀疏矩阵主要指的是存在大量零元素的矩阵,常见的稀疏矩阵比如说社交媒体的邻接矩阵,微分方程数值解钟差分法形成的矩阵和有限元方法搭建的刚度矩阵。对于稀疏矩阵,如果对于矩阵每个元素都分配内存存储,将会造成大量的内存浪费,同时做矩阵运算的时候由于读取过程中反复读取零元素将会增大内存访问的时间。因此,为了降低存储空间同时提高访问效率,一种高效的稀疏矩阵存储方法势在必行,下面主要介绍两种稀疏矩阵乘法,我们以一个5×55 \times 55×5的稀疏矩阵存储来举例子。

forrestguang的博客 1481

数值代数课设(99分)--基于Jacobi迭代,GS迭代,SOR迭代对泊松方程的求解[matlab](上)

基于Jacobi迭代,GS迭代,SOR迭代对泊松方程的求解 摘要 随着大数据时代的到来,人们需要处理的数据越来越多,所需要考虑的条件因素也在增加。在工程方面,人们所需要处理的问题往往会转化为找出大规模方程组的解的问题,而找出大规模方程组的解的计算复杂度非常的高,因此设计一些高效并且较为精准的算法来求解大规模方程组的近似解显的尤为重要。本文以着一维和二维泊松方程为例子,考虑了Jacobi迭代,GS迭代,SOR迭代这三种经典迭代对于求解一维和二维泊松方程的速度与准度,用matlab 写出了相关代码,并且进行了对

zhulinhao的博客 5130

ANSYS求解二维泊松方程:电磁场有限元教学案例详解

在工程电磁场分析中,泊松方程是描述静电场、电流场等物理场分布的基础偏微分方程。当求解域边界几何复杂或存在非均匀介质时,解析解难以获得,数值方法成为必然选择。有限元法通过变分原理将偏微分方程转化为泛函极值问题,再经区域离散与单元插值,最终归结为求解大规模稀疏线性方程组。ANSYS作为通用有限元分析软件,为电磁场仿真提供了完整的建模、求解与后处理工具。以二维平板电容器为例,通过网格划分、电压边界条件施加及电场云图后处理,可直观验证电场在介质分界面处的重新分布规律。该案例适用于电气工程专业教学,也适合工程技术人员

weixin_28720573的博客 210

用MATLAB从零实现PINN求解二维泊松方程(附完整代码)

偏微分方程(PDE)的数值求解在科学计算和工程仿真中始终占据核心地位,传统有限差分、有限元等方法依赖网格剖分,面对复杂几何与反问题时往往捉襟见肘。物理信息神经网络(PINN)通过将物理方程直接嵌入深度学习网络的损失函数,无需网格即可逼近PDE的解,为这一古老领域注入了全新活力。其核心原理是利用自动微分精确计算网络输出对输入坐标的各阶导数,以方程残差和边界条件作为监督信号训练网络,从而在连续空间上获得满足物理规律的近似解。该技术不仅适用于泊松方程等椭圆型问题,还能便捷地推广到热传导、波动方程乃至参数识别反问题

weixin_32642109的博客 281

泊松方程

原文链接​ 泊松方程(英语:Poisson's equation)是数学中一个常见于静电学、机械工程和理论物理的偏微分方程,因法国数学家、几何学家及物理学家泊松而得名的。 泊松方程为 在这里代表的是拉普拉斯算子,而f和φ可以是在流形上的实数或复数值的方程。当流形属于欧几里得空间,而拉普拉斯算子通常表示为,因此泊松方程通常写成 在三维直角坐标系,可以写成 如果有恒等于0,这个方...

weixin_30527143的博客 2440

EasyMesh -平面有限元网格剖分

很好用二维有限元网格剖分程序,基于开源软件构建,VC2012下测试通过

泊松方程 matlab,MATLAB编程求解二维泊松方程

《MATLAB编程求解二维泊松方程》由会员分享,可在线阅读,更多相关《MATLAB编程求解二维泊松方程(3页珍藏版)》请在人人文库网上搜索。1、 真解 u=sin(pi*x)*sin(pi*y) % 方程 -Laplace(u)=f % f=2*pi2*sin(pi*x)*sin(pi*y) %difference code for elliptic equations with constant...

weixin_29672983的博客 1044

matlab求解泊松方程代码-Drift-Diffusion_Python:用Python编写的一维模型,可使用有限差分求解半导体泊松-漂移-

matlab优化泊松方程代码漂移扩散模型 这是用Python编写的一维模型,该模型使用有限差分求解半导体泊松漂移扩散方程。 该模型模拟了光照下的太阳能电池,但也可以适用于其他半导体器件。 可以对其进行修改以解决其他系统(即,通过更改边界条件,添加重组率和修改生成率)。 使用称为Gummel方法的自洽迭代方法求解方程。 为了确保连续性方程的数值稳定性,使用了Scharfetter Gummel离散化以及新旧解决方案的线性混合。 表现 使用Numba @jit装饰器可以加速代码。 示例CPU时间:不使用Numba:469.7秒使用Numba:73.7秒 得出的结论是,Numba的工作量很轻,而且性能显着提高。 您可以在此处阅读有关Numba的信息: C ++和Matlab实现 您可以在这里找到相同模型的C ++和Matlab实现以及2D和3D版本: 性能比较: 对于网格尺寸为dx = 0.25nm,系统尺寸为300nm的一维代码: Python:69.8秒Matlab:40秒C ++:3.7秒 因此,当前的C ++版本要快得多,可能具有阅读不太优雅的缺点。

MATLAB——求指定区域上泊松方程的数值解

本代码主要利用MATLAB工具实现MATLAB——求指定区域上泊松方程的数值解,简单明了,易于理解

AFEPack 使用 Tutorial(三):解三维泊松方程

AFEPack Step by Step Tutorial 3: solve 3D Poisson Equation 这个 Tutorial 和前面两个不同。前面两个 Tutorial 都是 AFEPack 自带的例子,这个 Tutorial 可以认为是在 2D Poisson Equation 的基础上改进,将原来的 2D 方程变成 3D。 3D Poisson Equation 这里,三维泊松方程定义 {−Δu(x,y,z)=f(x,y,z),(x,y,z)∈Ωu(x,y,z)∣∂Ω=u0(x,y,z)

努力中的老周的专栏 3235

poisson方程的数值求解

利用matlab,解决possion方程的数值求解问题。

上一篇: 理解Emacs的缓冲区(Buffers)、窗口(Windows)和框架(Frames)
下一篇: Mathematica 讲座
HateCode
博客等级 码龄20年 25粉丝 11原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值