平面问题IGA程序终稿 - case by case

平面问题IGA程序初稿有详细对问题的描述

程序

IGA_Plate.h 文件

#pragma once
#include<iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
#include <vector>

class  IGA_Plate
{
public:
	//初始物理量
	static double E, mu, t;          //弹性模量  泊松比  厚度
	static int p;                    //基函数次数

	static MatrixXd Node;           //节点信息矩阵,第一列为节点编号,2-4列分别为x,y(,z)坐标
	static MatrixXd ele;            //单元信息,第一列为单元编号,后面各列为单元上的节点编号

	static vector<double> U, V;     //节点向量

public:
	int num_GK = 2 * Node.rows();         //总刚的大小  2*12
	int num_Ke = ele.rows();                       //单刚的个数  2
	int num_ele_node = ele.cols();             //单刚中节点的个数  9
	int size_Ke = 2 * (ele.cols());   //单刚矩阵的大小 18
	int num_BasisFun_V = V.size() - p - 1;         //V 方向基函数个数

public:
	MatrixXd D_Matrix()
	{
		MatrixXd D(3, 3);
		D << 1, mu, 0,
			mu, 1, 0,
			0, 0, (1 - mu) / 2;
		D *= (E / (1 - mu * mu));
		return D;
	}
	MatrixXd D = D_Matrix();         // 弹性矩阵

	//求基函数的值 (函数求值)
	double OneBasisFun_withreturn(int p, int m, vector<double>& U, int i, double u)
	{
		// p: p次B样条    m:节点向量的个数-1   
		// U: 节点向量[u0,u1,...,um]   i:区间段[ui ui+1,...,ui+p+1]    
		// u:求p次B样条基函数 Ni,p 在u点的函数值
		double Nip;
		vector<double> N(p + 1);
		if ((i == 0 && u == U[0]) || (i == m - p - 1 && u == U[m]))
		{
			Nip = 1.0;
			return Nip;
		}
		if (u < U[i] || u >= U[i + p + 1])
		{
			Nip = 0.0;
			return Nip;
		}
		int jj, j;
		for (jj = 0; jj <= p; jj++) {
			if (u >= U[i + jj] && u < U[i + jj + 1])
				N[jj] = 1.0;
			else
				N[jj] = 0.0;
		}
		double saved;
		int k;
		for (k = 1; k <= p; k++)
		{
			if (N[0] == 0.0) saved = 0.0;
			else saved = ((u - U[i]) * N[0]) / (U[i + k] - U[i]);
			for (j = 0; j < p - k + 1; j++)
			{
				double Uleft = U[i + j + 1];
				double Uright = U[i + j + k + 1];
				if (N[j + 1] == 0.0)
				{
					N[j] = saved; saved = 0.0;
				}
				else
				{
					double temp = N[j + 1] / (Uright - Uleft);
					N[j] = saved + (Uright - u) * temp;
					saved = (u - Uleft) * temp;
				}
			}

		}
		Nip = N[0];
		return Nip;

	}

	//求单个基函数的导数
	double DersOneBasisFun_double_First_Ders(int p, vector<double>& U, int i, double u)
	{
		// 原先是DersOneBasisFun_double_First_Ders(int p,int m,vector<double> &U,int i,double u,int n)
		// 但是我看参数 n 没有用到,就将 int n   删除了
		// m:节点向量的个数-1  没有用到,就将 int m   删除了
		// p: p次B样条     
		// U: 节点向量[u0,u1,...,um]   i:区间段[ui ui+1,...,ui+p+1]    
		// u:求p次B样条基函数 Ni,p 在u点的导数值
		double DersOnebasisfun_value;
		if (p == 3) {
			double Onebasisfun_i_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i, u);
			double Onebasisfun_iplus1_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i + 1, u);
			double Uipi = 1.0 / (U[i + p] - U[i]);
			double Uip1i1 = 1.0 / (U[i + p + 1] - U[i + 1]);
			if ((U[i + p] - U[i]) == 0)
				Uipi = 0.0;
			if ((U[i + p + 1] - U[i + 1]) == 0)
				Uip1i1 = 0.0;
			DersOnebasisfun_value = p * (Onebasisfun_i_pminus1 * Uipi - Onebasisfun_iplus1_pminus1 * Uip1i1);
			if (u == 1.0)
			{
				u = 0.99999;
				double Onebasisfun_i_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i, u);
				double Onebasisfun_iplus1_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i + 1, u);
				double Uipi = 1.0 / (U[i + p] - U[i]);
				double Uip1i1 = 1.0 / (U[i + p + 1] - U[i + 1]);
				if ((U[i + p] - U[i]) == 0)
					Uipi = 0.0;
				if ((U[i + p + 1] - U[i + 1]) == 0)
					Uip1i1 = 0.0;
				double DersOnebasisfun_value_zero = p * (Onebasisfun_i_pminus1 * Uipi - Onebasisfun_iplus1_pminus1 * Uip1i1);
				DersOnebasisfun_value = -DersOnebasisfun_value_zero;
				//cout<< "Hehehehhe" <<  " " << i << " " << Onebasisfun_i_pminus1  << " " << Uipi  << " " <<  Onebasisfun_iplus1_pminus1  << " " << Uip1i1 << " " << DersOnebasisfun_value_zero << "\n";
			}

		}

		if (p == 2) {
			double Onebasisfun_i_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i, u);
			double Onebasisfun_iplus1_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i + 1, u);
			double Uipi = 1.0 / (U[i + p] - U[i]);
			double Uip1i1 = 1.0 / (U[i + p + 1] - U[i + 1]);
			if ((U[i + p] - U[i]) == 0)
				Uipi = 0.0;
			if ((U[i + p + 1] - U[i + 1]) == 0)
				Uip1i1 = 0.0;
			DersOnebasisfun_value = p * (Onebasisfun_i_pminus1 * Uipi - Onebasisfun_iplus1_pminus1 * Uip1i1);
			if (u == 1.0)
			{
				u = 0.99999;
				double Onebasisfun_i_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i, u);
				double Onebasisfun_iplus1_pminus1 = OneBasisFun_withreturn(p - 1, U.size() - 1, U, i + 1, u);
				double Uipi = 1.0 / (U[i + p] - U[i]);
				double Uip1i1 = 1.0 / (U[i + p + 1] - U[i + 1]);
				if ((U[i + p] - U[i]) == 0)
					Uipi = 0.0;
				if ((U[i + p + 1] - U[i + 1]) == 0)
					Uip1i1 = 0.0;
				double DersOnebasisfun_value_zero = p * (Onebasisfun_i_pminus1 * Uipi - Onebasisfun_iplus1_pminus1 * Uip1i1);
				DersOnebasisfun_value = -DersOnebasisfun_value_zero;
				//cout<< "Hehehehhe" <<  " " << i << " " << Onebasisfun_i_pminus1  << " " << Uipi  << " " <<  Onebasisfun_iplus1_pminus1  << " " << Uip1i1 << " " << DersOnebasisfun_value_zero << "\n";
			}

		}
		if (p == 1)
		{
			if (i == 0)
				DersOnebasisfun_value = -1;
			else {
				DersOnebasisfun_value = 1;
			}
		}

		return DersOnebasisfun_value;
	}

	//将第k个单元的节点编号  对应的坐标用9*2的向量存储
	Eigen::MatrixXd coor(int k)
	{
		// k从0开始  0对应第一个单元  1对应第二个单元...
		MatrixXd coor(num_ele_node, Node.cols());               // 每个单元的节点坐标存储为一个矩阵   节点坐标二维 Node.cols()
		MatrixXd _ele = ele.block(k, 0, 1, num_ele_node);       // 将第k个单元节点编号用向量存储起来

		for (int i = 0; i < num_ele_node; i++)
		{
			int j = _ele(i);             // j: 代表第几个节点编号
			coor(i, 0) = Node(j - 1, 0);
			coor(i, 1) = Node(j - 1, 1);
		}

		return coor;
	}

	//将节点向量中的重节点值去掉(只保存一个)
	vector<double> val_vector(vector<double> vec)
	{
		// 因为要用到高斯积分,第一步要将每个单元的积分上下限 和节点向量的值 对应起来
		vector<double> val_vec;                          //新定义一个向量,用于存储节点数值
		val_vec.push_back(vec[0]);

		for (int i = 0; i < vec.size() - 1; i++)
		{
			if (vec[i] != vec[i + 1])
			{
				val_vec.push_back(vec[i + 1]);          //用于存储节点向量U中  不同节点的值(重节点的值只保存一个)
			}
		}
		return val_vec;
	}

	//计算单元的雅克比矩阵
	Eigen::MatrixXd Jacobi(int k, double u, double v)
	{
		// k:表示的第k+1个单元
		// 计算雅克比矩阵 (每个单元有且只有一个雅克比矩阵)
		MatrixXd J(2, 2);       //雅克比矩阵
		J.setZero();

		MatrixXd _ele = ele.block(k, 0, 1, num_ele_node);   // 将第k个单元节点编号用向量存储起来
		MatrixXd coor1(num_ele_node, 2);
		coor1 = coor(k);                         //将第k个单元的节点编号  对应的坐标用9*2的向量存储

		MatrixXd der_eta_xi(2, 9);                          // 用于存储相应基函数的导数
		int num;
		int Length_U = U.size();
		int Length_V = V.size();

		for (int i = 0; i < num_ele_node; i++)
		{
			num = _ele(i);             // num : 代表k单元中第i个节点编号
			// 将节点编号和基函数对应起来      
			// 1 ---  N0,2 * M0,2   2 ---- N0,2 * M1,2   3 ---- N0,2 * M2,2
			// 4 ---  N1,2 * M0,2   5 ---- N1,2 * M1,2   6 ---- N1,2 * M2,2   7 ---  N2,2 * M0,2...... 
			// val1: 表示U方向的第几个基函数   对应求导函数DersOneBasisFun_double_First_Ders(p, U, i, u)中的i
			int val1 = (num - 1) / num_BasisFun_V;
			int val2 = (num - 1) % num_BasisFun_V;        // val2: 表示V方向的第几个基函数
			double U_xi = OneBasisFun_withreturn(p, Length_U - 1, U, val1, u);     //U方向基函数
			double V_eta = OneBasisFun_withreturn(p, Length_V - 1, V, val2, v);
			double der_U_xi = DersOneBasisFun_double_First_Ders(p, U, val1, u);    //U方向基函数导数
			double der_V_eta = DersOneBasisFun_double_First_Ders(p, V, val2, v);

			der_eta_xi(0, i) = der_U_xi * V_eta;
			der_eta_xi(1, i) = U_xi * der_V_eta;
		}
		J = der_eta_xi * coor1;
		return J;
	}

	// 计算单元应变矩阵B
	Eigen::MatrixXd B_matrix(int k, double u, double v)
	{
		// Nk:表示的第k+1个单元
		// 计算单元应变矩阵B
		MatrixXd B(3, 2 * num_ele_node);
		B.setZero();
		MatrixXd J = Jacobi(k, u, v);
		int num;
		int Length_U = U.size();
		int Length_V = V.size();
		MatrixXd der_Ni_xy(2, 1);
		MatrixXd der_Ni_xi_eta(2, 1);

		for (int i = 0; i < num_ele_node; i++)
		{
			MatrixXd _ele = ele.block(k, 0, 1, num_ele_node);   // 将第k个单元节点编号用向量存储起来
			num = _ele(i);             // num : 代表第几个节点编号
			// 1 ---  N0,2 * M0,2   2 ---- N0,2 * M1,2   3 ---- N0,2 * M2,2
			// 4 ---  N1,2 * M0,2   5 ---- N1,2 * M1,2   6 ---- N1,2 * M2,2   7 ---  N2,2 * M0,2...... 
			int val1 = (num - 1) / num_BasisFun_V;        // val1: 表示U方向的第几个基函数   对应求导函数DersOneBasisFun_double_First_Ders(p, U, i, u)中的i
			int val2 = (num - 1) % num_BasisFun_V;        // val2: 表示V方向的第几个基函数
			double  U_xi = OneBasisFun_withreturn(p, Length_U - 1, U, val1, u);    //U方向基函数
			double V_eta = OneBasisFun_withreturn(p, Length_V - 1, V, val2, v);
			double  der_U_xi = DersOneBasisFun_double_First_Ders(p, U, val1, u);   //U方向基函数导数
			double der_V_eta = DersOneBasisFun_double_First_Ders(p, V, val2, v);

			double der_Ni_xi = der_U_xi * V_eta;
			double der_Ni_eta = U_xi * der_V_eta;                //Ni对η(eta)的导数

			der_Ni_xi_eta(0, 0) = der_Ni_xi;
			der_Ni_xi_eta(1, 0) = der_Ni_eta;
			der_Ni_xy = J.inverse() * der_Ni_xi_eta;            //求出Ni在物理域上的导数

			B(0, 2 * i) = der_Ni_xy(0, 0);
			B(1, 2 * i + 1) = der_Ni_xy(1, 0);

			B(2, 2 * i) = der_Ni_xy(1, 0);
			B(2, 2 * i + 1) = der_Ni_xy(0, 0);

		}
		return B;
	}

	// 计算单元刚度矩阵 
	Eigen::MatrixXd IGA_Stiffness(int k)
	{
		// t:厚度  k:表示的第k+1个单元
		// 计算单元刚度矩阵
		// 因为要用到高斯积分,第一步要将每个单元的积分上下限 和节点向量的值 对应起来
		MatrixXd Ke(size_Ke, size_Ke);
		Ke.setZero();
		MatrixXd B(3, 2 * num_ele_node);
		B.setZero();
		MatrixXd J(2, 2);
		J.setZero();
		// 将节点向量中的重节点值去掉(重节点信息只保存一个)
		vector<double> val_U;
		val_U = val_vector(U);                // 调用函数 val_vector(vector<double> vec)   将节点向量中的重节点值去掉
		vector<double> val_V;
		val_V = val_vector(V);
		// 求U和V方向的积分上下限
		double U_a, U_b, V_a, V_b;
		double u, v;
		int num_U = k % val_U.size();         // U方向的第几个区间
		int num_V = k / val_U.size();

		U_a = val_U[num_U];                   // U方向上的积分下限(参数域区间左端点)
		U_b = val_U[num_U + 1];               // U方向上的积分上限(参数域区间右端点)
		V_a = val_V[num_V];
		V_b = val_V[num_V + 1];

		// Gauss积分   U和V方向都使用两点Gauss公式
		// 高斯点
		double Gauss[4][2];
		Gauss[0][0] = -0.57735;
		Gauss[0][1] = -0.57735;
		Gauss[1][0] = 0.577350;
		Gauss[1][1] = -0.57735;
		Gauss[2][0] = 0.57735;
		Gauss[2][1] = 0.57735;
		Gauss[3][0] = -0.57735;
		Gauss[3][1] = 0.57735;

		for (int j = 0; j < 4; j++)
		{
			u = (U_b - U_a) * Gauss[j][0] / 2 + (U_b + U_a) / 2;
			v = (V_b - V_a) * Gauss[j][1] / 2 + (V_b + V_a) / 2;
			B = B_matrix(k, u, v);
			J = Jacobi(k, u, v);
			Ke += t * (U_b - U_a) / 2 * (V_b - V_a) / 2 * B.transpose() * D * B * J.determinant();
		}
		return Ke;
	}

	// 组装总体刚度矩阵 
	Eigen::MatrixXd IGA_Assembly()
	{
		// Node: 节点坐标信息    ele:节点信息   k:表示的第k+1个单元
		// U:U方向的节点向量    p:B样条基函数的次数   t:厚度
		// 组装刚度矩阵
		MatrixXd Gk(num_GK, num_GK);
		Gk.setZero();

		MatrixXd Ke(size_Ke, size_Ke);                           //单元刚度矩阵
		Ke.setZero();

		for (int k = 0; k < num_Ke; k++)
		{
			Ke = IGA_Stiffness(k);     // 第k个单元刚度矩阵
			MatrixXd _ele = ele.block(k, 0, 1, 9);               // 将第k个单元节点编号用向量存储起来

			VectorXi Dof(num_ele_node * 2);                      // 定义一个  单刚中节点的个数*2  的向量(9*2)  用于组总刚
			for (int r = 0; r < num_ele_node; r++)
			{
				Dof(2 * r) = _ele(r) * 2 - 2;
				Dof(2 * r + 1) = _ele(r) * 2 - 1;
			}

			for (int n1 = 0; n1 < num_ele_node * 2; n1++)
			{
				for (int n2 = 0; n2 < num_ele_node * 2; n2++)
				{
					Gk(Dof(n1), Dof(n2)) = Gk(Dof(n1), Dof(n2)) + Ke(n1, n2);
				}
			}
		}

		return Gk;
	}

	//置“1”法求解方程组
	VectorXd Solve_1_Model(MatrixXd K, VectorXd U, VectorXd P, int len_U)
	{
		//置“1”法求解方程组
		//K:总刚   U:初始化的节点位移向量  P:节点力
		for (int j = 0; j < len_U; j++)
		{
			if (U(j) == 0)
			{
				K.block(j, 0, 1, K.cols()).setZero();    //将总刚矩阵K的行 置“0”  K.cols():K矩阵的列长
				K.block(0, j, K.rows(), 1).setZero();    //将总刚矩阵K的列 置“0”  K.rows():K矩阵的行长
				K(j, j) = 1;
				P(j) = 0;          //节点力置“0”
			}
		}
		// 节点位移
		U = K.lu().solve(P);         //LU分解求解线性方程组K * U = P
		return U;
	}

};


主程序文件

#include<iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
#include <vector>
#include "IGA_Plate.h"


//初始物理量
double IGA_Plate::E = 10;            // 弹性模量
double IGA_Plate::mu = 0.3;          // 泊松比
double IGA_Plate::t = 0.01;          // 厚度

//节点信息,第一列为节点编号,2-4列分别为x,y,z坐标
MatrixXd Node_Matrix()
{
	MatrixXd Node(12, 2);
	Node << 0, 0,
		0, 1,
		0, 2,
		0.5, 0,
		0.5, 1,
		0.5, 2,
		1.5, 0,
		1.5, 1,
		1.5, 2,
		2, 0,
		2, 1,
		2, 2;
	return Node;
}
MatrixXd IGA_Plate::Node = Node_Matrix();
// 输出矩阵的各个值
void Print(MatrixXd K)
{
	for (int j = 0; j < K.rows(); j++)
	{
		for (int i = 0; i < K.cols(); i++)
		{
			cout << K(j, i) << "  ";
		}
		cout << endl;
	}
}

MatrixXd ele_Matrix()
{
	MatrixXd ele(2, 9);
	ele << 1, 2, 3, 4, 5, 6, 7, 8, 9,
		4, 5, 6, 7, 8, 9, 10, 11, 12;
	return ele;
}
MatrixXd IGA_Plate::ele = ele_Matrix();

// 节点向量
vector<double> IGA_Plate::U = { 0,0,0,0.5,1,1,1 };
vector<double> IGA_Plate::V = { 0,0,0,1,1,1 };

int IGA_Plate::p = 2;

int main(void)
{
	//初始物理量
	IGA_Plate iga_2d;

	Print(iga_2d.coor(0));

	// 组装刚度矩阵
	int num_GK = iga_2d.ele.rows() * iga_2d.Node.rows();       //总刚的大小  2*12
	MatrixXd Gk(num_GK, num_GK);
	Gk.setZero();
	Gk = iga_2d.IGA_Assembly();

	// 载荷向量 
	VectorXd F(num_GK);
	F.setZero();
	F(18) = 1.0 / 3;
	F(20) = 1.0 / 3;
	F(22) = 1.0 / 3;

	VectorXd disp(num_GK);         // 位移 displacement 
	disp.setOnes();
	disp(0) = 0; disp(1) = 0; disp(2) = 0; disp(4) = 0;
	int len_disp = 2 * iga_2d.Node.rows();        //节点位移矩阵长度

	disp = iga_2d.Solve_1_Model(Gk, disp, F, len_disp);        //置“1”法求解方程组
	cout << "\n 节点位移 disp = \n" << disp << endl;

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值