I am trying to model a cantilever beam which can vibrate. On the left the beam is clamped. I am largely following user21 here and also the example in help. I start by doing a static beam which works then I work out the vibration modes (eigenvectors) of a beam with no boundary constraint, this works, and then it all goes wrong when I try to do the eigenvectors of the clamped beam. I start with some helper modules.
Needs["NDSolve`FEM`"];
(*plane stress equations two versions with and without time *)
ClearAll[planeStress];
planeStress::usage =
"planeStress[u,v,x,y,Y,\[Nu]] (no time) or planeStress[u,v,t,x,y,Y,\
\[Nu]] (with time) Y is modulus of elasticity and \[Nu] is Poission \
ratio. ";
planeStress[u_, v_, x_, y_,
Y_, \[Nu]_] := {Inactive[
Div][{{0, -((Y*\[Nu])/(1 - \[Nu]^2))}, {-(Y*(1 - \[Nu]))/(2*(1 - \
\[Nu]^2)), 0}}.Inactive[Grad][v[x, y], {x, y}], {x, y}] +
Inactive[
Div][{{-(Y/(1 - \[Nu]^2)),
0}, {0, -(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2))}}.Inactive[Grad][
u[x, y], {x, y}], {x, y}],
Inactive[Div][{{0, -(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2))}, \
{-((Y*\[Nu])/(1 - \[Nu]^2)), 0}}.Inactive[Grad][u[x, y], {x, y}], {x,
y}] + Inactive[
Div][{{-(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2)),
0}, {0, -(Y/(1 - \[Nu]^2))}}.Inactive[Grad][
v[x, y], {x, y}], {x, y}]}
planeStress[u_, v_, t_, x_, y_,
Y_, \[Nu]_] := {Inactive[
Div][{{0, -((Y*\[Nu])/(1 - \[Nu]^2))}, {-(Y*(1 - \[Nu]))/(2*(1 - \
\[Nu]^2)), 0}}.Inactive[Grad][v[t, x, y], {x, y}], {x, y}] +
Inactive[
Div][{{-(Y/(1 - \[Nu]^2)),
0}, {0, -(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2))}}.Inactive[Grad][
u[t, x, y], {x, y}], {x, y}],
Inactive[Div][{{0, -(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2))}, \
{-((Y*\[Nu])/(1 - \[Nu]^2)), 0}}.Inactive[Grad][
u[t, x, y], {x, y}], {x, y}] +
Inactive[
Div][{{-(Y*(1 - \[Nu]))/(2*(1 - \[Nu]^2)),
0}, {0, -(Y/(1 - \[Nu]^2))}}.Inactive[Grad][
v[t, x, y], {x, y}], {x, y}]}
ClearAll[finiteElementData];
finiteElementData::usate =
"finiteElementData[start] Extract the finite element data";
finiteElementData[state_] :=
Module[{femdata, initBCs, methodData, initCoeffs, vd, sd,
discretePDE, discreteBCs, load, stiffness, damping, spans, dimDM},
femdata = state["FiniteElementData"];
initBCs = femdata["BoundaryConditionData"];
methodData = femdata["FEMMethodData"];
initCoeffs = femdata["PDECoefficientData"];
vd = methodData["VariableData"];
sd = NDSolve`SolutionData[{"Space" -> ToNumericalRegion[mesh]}];
(*Discretize the PDE and the boundary conditions:*)
discretePDE = DiscretizePDE[initCoeffs, methodData, sd];
discreteBCs = DiscretizeBoundaryConditions[initBCs, methodData, sd];
(*Extract the system matrices:*)
load = discretePDE["LoadVector"];
stiffness = discretePDE["StiffnessMatrix"];
damping = discretePDE["DampingMatrix"];
DeployBoundaryConditions[{load, stiffness, damping}, discreteBCs];
spans =
Span @@@
Transpose[{Most[# + 1], Rest[#]} &[methodData["IncidentOffsets"]]];
dimDM = Dimensions[discreteBCs["DirichletMatrix"]];
{load, stiffness, damping, methodData, spans, dimDM}
]
ClearAll[solveEigensystem];
solveEigensystem::usage =
"solveEigensystem[n,mesh,data] where n is the number of \
eigenvalues, and data is the output from finiteElementData";
solveEigensystem[n_,
mesh_, {load_, stiffness_, damping_, methodData_, spans_, dimDM_}] :=
Module[{nDiri, numEigen, mm, res, eigenValues, eigenVectors,
eigenVectorsIF},
nDiri = If[Length[#] > 0, First[#], 0] &[dimDM];
numEigen = n + nDiri;
mm = LinearSolve[damping, stiffness];
res = Eigensystem[mm, -numEigen];
res = Reverse /@ res;
eigenValues = res[[1, nDiri + 1 ;; Abs[numEigen]]];
eigenVectors = res[[2, nDiri + 1 ;; Abs[numEigen]]];
eigenVectors =
Transpose[
Developer`ToPackedArray[eigenVectors[[All, #]] & /@ spans], {2, 1,
3}];
eigenVectorsIF = Table[{}, {n}, {Length[spans]}];
Do[eigenVectorsIF[[i, j]] =
NDSolve`FEM`ElementMeshInterpolation[{mesh},
eigenVectors[[i, j]]], {i, n}, {j, Length[spans]}];
{eigenValues, eigenVectorsIF}
]
Here is the beam
(* make mesh *)
\[CapitalOmega] = ImplicitRegion[True, {x, y}];
mesh = ToElementMesh[\[CapitalOmega], {{0, 5}, {0, 0.25}},
"MaxCellMeasure" -> 0.005];
mesh["Wireframe"]
Starting with the static case -all is good
(* Set up boundary conditions and PDE*)
bcs = DirichletCondition[{u[x, y] == 0, v[x, y] == 0}, x == 0];
pde2D = planeStress[u, v, x, y, 10^3, 33/100] == {0,
NeumannValue[0.1, x == 5]};
{state} =
NDSolve`ProcessEquations[{pde2D, bcs}, {u, v}, {x, y} \[Element]
mesh,
Method -> {"PDEDiscretization" -> {"FiniteElement"}}];
Extract the data, solve and plot.
{load, stiffness, damping, methodData, spans, dimDM} =
finiteElementData[state];
solution = LinearSolve[stiffness, load];
uif = ElementMeshInterpolation[{mesh}, solution[[spans[[1]]]]];
vif = ElementMeshInterpolation[{mesh}, solution[[spans[[2]]]]];
dmesh = ElementMeshDeformation[mesh, {uif, vif}];
Show[{
mesh["Wireframe"],
dmesh["Wireframe"[
"ElementMeshDirective" -> Directive[EdgeForm[Red], FaceForm[]]]]}]
Next for vibration of the beam with no supports
(* Set up boundary conditions and PDE *)
bcs = Sequence[];
pde2D = {D[u[t, x, y], t], D[v[t, x, y], t]} +
planeStress[u, v, t, x, y, 10^3, 33/100] == {0, 0};
{state} =
NDSolve`ProcessEquations[{pde2D, bcs, u[0, x, y] == 0,
v[0, x, y] == 0}, {u, v}, {t, 0, 1}, {x, y} \[Element] mesh,
Method -> {"PDEDiscretization" -> {"MethodOfLines",
"SpatialDiscretization" -> {"FiniteElement"}}}];
fed = finiteElementData[state];
{eigenValues, eigenVectorsIF} = solveEigensystem[8, mesh, fed];
The theoretical values can be calculated assuming a slender beam. The first three are zero corresponding to rigid body modes i.e. moving horizontally, vertically and rocking with no flexure. The next four are transverse flexural vibration. The last value corresponds to longitudinal vibration.
theory = {0, 0, 0, 22/L^2 Sqrt[(Y d^2)/(12 1)],
61.7/L^2 Sqrt[(Y d^2)/(12 1)], 121/L^2 Sqrt[(Y d^2)/(12 1)],
200/L^2 Sqrt[(Y d^2)/(12 1)], \[Pi]/L Sqrt[Y/1.]} /. {Y -> 10^3,
d -> 0.25, L -> 5};
TableForm[Transpose[{Sqrt[Abs[eigenValues]], theory}],
TableHeadings -> {Automatic, { "Calculated", "Theory"}}]
The eigenvectors plot as
Column[Table[uif = eigenVectorsIF[[n, 1]];
vif = eigenVectorsIF[[n, 2]];
dmesh =
ElementMeshDeformation[mesh, {uif, vif}, "ScalingFactor" -> 10];
Show[{
mesh["Wireframe"],
dmesh[
"Wireframe"[
"ElementMeshDirective" ->
Directive[EdgeForm[Red], FaceForm[]]]]}],
{n, 8}]]
The first three mode shapes need normalizing to give the three rigid body modes corresponding to each coordinate. Now things go wrong - I put in the boundary conditions
bcs = DirichletCondition[{u[t, x, y] == 0, v[t, x, y] == 0}, x == 0];
pde2D = {D[u[t, x, y], t], D[v[t, x, y], t]} +
planeStress[u, v, t, x, y, 10^3, 33/100] == {0, 0};
{state} =
NDSolve`ProcessEquations[{pde2D, bcs, u[0, x, y] == 0,
v[0, x, y] == 0}, {u, v}, {t, 0, 1}, {x, y} \[Element] mesh,
Method -> {"PDEDiscretization" -> {"MethodOfLines",
"SpatialDiscretization" -> {"FiniteElement"}}}];
fed = finiteElementData[state];
{eigenValues, eigenVectorsIF} = solveEigensystem[5, mesh, fed];
The theoretical solutions are as follows (note that the fourth solution is for longitudinal vibration)
theory = {3.52 Sqrt[(Y d^2)/(12 L^4)], 22 Sqrt[(Y d^2)/(12 L^4)],
61.7 Sqrt[(Y d^2)/(12 L^4)], \[Pi] /2 Sqrt[Y/L^2],
121 Sqrt[(Y d^2)/(12 L^4)]} /. {Y -> 10^3, d -> 0.25, L -> 5.};
TableForm[Transpose[{Sqrt[Abs[eigenValues]], theory}],
TableHeadings -> {Automatic, { "Calculated", "Theory"}}]
Column[Table[uif = eigenVectorsIF[[n, 1]];
vif = eigenVectorsIF[[n, 2]];
dmesh =
ElementMeshDeformation[mesh, {uif, vif}, "ScalingFactor" -> 10];
Show[{
mesh["Wireframe"],
dmesh[
"Wireframe"[
"ElementMeshDirective" ->
Directive[EdgeForm[Red], FaceForm[]]]]}],
{n, 5}]]
The first mode frequency and mode shape are wrong. The solution is badly distorted at the left hand end. If we try with a mesh that is fine at the left hand end we get
Lx = 5; Ly = 0.25;
inc = 0.01;
pts = Flatten[
Join[{{{0, 0}, {Lx, 0}, {Lx, Ly}, {0, Ly}},
Table[{0, y}, {y, Ly - inc, inc, -inc}]}], 1];
boundarymesh = ToBoundaryMesh[Polygon[pts]];
mesh = ToElementMesh[boundarymesh, "MaxCellMeasure" -> 0.005];
mesh["Wireframe"]
(* Set up boundary conditions and PDE *)
bcs = DirichletCondition[{u[t, x, y] == 0, v[t, x, y] == 0}, x == 0];
pde2D = {D[u[t, x, y], t], D[v[t, x, y], t]} +
planeStress[u, v, t, x, y, 10^3, 33/100] == {0, 0};
{state} =
NDSolve`ProcessEquations[{pde2D, bcs, u[0, x, y] == 0,
v[0, x, y] == 0}, {u, v}, {t, 0, 1}, {x, y} \[Element] mesh,
Method -> {"PDEDiscretization" -> {"MethodOfLines",
"SpatialDiscretization" -> {"FiniteElement"}}}];
fed = finiteElementData[state];
{eigenValues, eigenVectorsIF} = solveEigensystem[5, mesh, fed];
TableForm[Transpose[{Sqrt[Abs[eigenValues]], theory}],
TableHeadings -> {Automatic, { "Calculated", "Theory"}}]
Column[Table[uif = eigenVectorsIF[[n, 1]];
vif = eigenVectorsIF[[n, 2]];
dmesh =
ElementMeshDeformation[mesh, {uif, vif}, "ScalingFactor" -> 10];
Show[{
mesh["Wireframe"],
dmesh[
"Wireframe"[
"ElementMeshDirective" ->
Directive[EdgeForm[Red], FaceForm[]]]]}],
{n, 5}]]
Again the first mode is wrong. It is clear that the left hand end elements are badly distorted. What is going wrong? Thanks