# AceFEM: How to resolve a pre constrained DOF?

today I came up with the idea to build an element in AceGen which has a degree of freedom that can be "turned on and off". By this I want to control via an input parameter wether the element should enforce a constraint by a Lagrange Multiplier or not. Hence I defined a concerning node:

"SMSNodeID" -> {....., "Lagrange -LP -L"}


It works fine. But considering I give an input to the element turning off the constrain, I want to get rid of this dof with respect to my element matrices. Just turning of the constrain following the ansatz: $$\begin{equation} \begin{array}{c} \Pi_{Potential} = \Pi_{Solid Potential} + \omega \ \lambda \ (\text{constraint}) \\[.5cm] \omega = \text{1 or 0} \qquad \lambda \rightarrow \text{Lagrange Multiplier} \end{array} \end{equation}$$

Works but still does not reduce element matrices.

My Idea was to set a "constrained" flag to the node in this case. I tried to modify the following nodal field within the element:

SMSExport[-1, nd$$[6, "DOF", 1]];  At the first glance this works as the corresponding field is correctly modified SMTNodeData["ID" == "Lagrange" &, "DOF"] SMTNewtonIteration[]; SMTNodeData["ID" == "Lagrange" &, "DOF"] {{7}} {{-1}}  but it does not have the desired effect. I can put this constrain the dof by the command: SMTAddEssentialBoundary["ID" == "Lagrange" &, 1 -> 0]  but i wonder if there is a solution to do this from inside the element. I've prepared a little element now. There is an input parameter wether the constraint (in this case \varepsilon=0.001) enforced by a lagrange multiplier should be fulfilled. << AceGen; SMSInitialize["Truss", "Environment" -> "AceFEM", "Mode" -> "Prototype"]; SMSTemplate["SMSTopology" -> "C1", "SMSNoNodes" -> 3, "SMSDOFGlobal" -> {3, 3, 1}, "SMSNodeID" -> {"D", "D", "Lagrange -LP -L"}, "SMSAdditionalNodes" -> Hold[{Null} &], "SMSDefaultIntegrationCode" -> 0, "SMSDomainDataNames" -> {"Emod", "A", "Constraint epsilon\n1->False\n2->True"}, "SMSDefaultData" -> {21000, 1, 1}]; SMSStandardModule["Tangent and residual"]; {Emod, A} \[RightTee] SMSReal[{es$$["Data", 1], es$$["Data", 2]}]; Cons\[Lambda] \[DoubleRightTee] SMSIf[SMSReal[es$$["Data", 3]] == 1, 0, 1];
\[DoubleStruckCapitalX]IO \[RightTee]
Table[SMSReal[nd$$[i, "X", j]], {i, 2}, {j, 3}]; \[DoubleStruckU]IO \[RightTee] Table[SMSReal[nd$$[i, "at", j]], {i, 2}, {j, 3}];
\[Lambda] \[RightTee] SMSReal[nd$$[3, "at", 1]]; \[DoubleStruckX] \[DoubleRightTee] \[DoubleStruckCapitalX]IO + \ \[DoubleStruckU]IO; DOFVector = Flatten[{\[DoubleStruckU]IO, \[Lambda]}]; Le \[DoubleRightTee] SMSSqrt[(\[DoubleStruckCapitalX]IO[[ 1]] - \[DoubleStruckCapitalX]IO[[ 2]]).(\[DoubleStruckCapitalX]IO[[ 1]] - \[DoubleStruckCapitalX]IO[])]; le \[DoubleRightTee] SMSSqrt[(\[DoubleStruckX][] - \[DoubleStruckX][[ 2]]).(\[DoubleStruckX][] - \[DoubleStruckX][])]; \[CurlyEpsilon] \[DoubleRightTee] le/Le - 1; cons = 0.001; Pot \[DoubleRightTee] 1/2 Emod \[CurlyEpsilon]^2 + Cons\[Lambda] \[Lambda] (cons - \[CurlyEpsilon]); \[DoubleStruckCapitalR]e \[DoubleRightTee] A Le SMSD[Pot, DOFVector]; \[DoubleStruckCapitalK]e \[DoubleRightTee] SMSD[\[DoubleStruckCapitalR]e, DOFVector]; SMSExport[\[DoubleStruckCapitalR]e, p$$]; SMSExport[\
\[DoubleStruckCapitalK]e, s$$]; SMSWrite[];  It looks a bit messy in here due to the special characters but pasting it into a mathematica notebook works for me! A corresponding problem could be: << AceFEM; F = 5; L = 10; A = 1; Emod = 1000; disp = {}; Constrained = False; SMTInputData[]; SMTAddDomain["\[CapitalOmega]", "Truss", {"Emod" -> Emod, "A" -> A, "Cons*" -> If[Constrained, 2, 1]}]; SMTAddMesh[Line[{{0, 0, 0}, {L, 0, 0}}], "\[CapitalOmega]", "C1", 1]; SMTAddEssentialBoundary["X" == 0 &, 1 -> 0, 2 -> 0, 3 -> 0]; SMTAddNaturalBoundary["X" == L &, 1 -> F]; SMTAnalysis[]; Do[ SMTNextStep[.5, .5]; SMTNewtonIteration[]; AppendTo[ disp, {SMTData["Multiplier"], SMTNodeData["X" == L &, "at"][[1, 1]]}] , {i, 10}]; ListLinePlot[disp, AxesLabel -> {"\[Lambda]-load", "u1"}]  As you will notice, this approach works! My specific problem is, that the resulting system of equations for this specific example is of size 4 (4 unknowns/equations). In case that the constraint is not enforced, I want the system to reduce to 3 unknowns/equations. In order to do so I'd like to set a "constraint flag" to the \lambda-node, or set it initially as constraint in the SMSTemplate and release the constraint in case that I need to compute \lambda • Welcome to the site M.SE and thank you for the first question about finite element code generation with AceGen. You will increase the chances of getting an answer if you edit your question with self-contained minimal working example, so other users can copy/paste the code and try it themselves. – Pinti Mar 31 '17 at 9:45 ## 1 Answer By using the SMSIf[Cons\[Lambda] == 0, SMSExport[-1, nd$$[3, "DOF", 1]], SMSExport[0, nd[3, "DOF", 1]]] line inside element you will get the correct values in the "DOF" field:

SMTNodeData["DOF"]=={{-1, -1, -1}, {0, 1, 2}, {-1}}


But you have to use the command SMTIData["SetSolver", 1], which rebulds the tangent matrix from the current "DOF" values. But this can only be called after the call to the "Tangent and residual" module. So if you change the constrained to True from False, and run SMTNewtonIteration[], the global matrix used in the iteration will stil be 4x4, even though "DOF"=-1, then you can call SMTIData["SetSolver", 1] the next iteration will use 3x3 matrix. Or you can run the SMTData["TangentMatrix"] command which will cal each element and set the "DOF" values:

SMTDomainData["\[CapitalOmega]", "Data", "Cons*" -> 1]
SMTData["TangentMatrix"] // MatrixForm
SMTNodeData["DOF"]
SMTIData["SetSolver", 1];
SMTData["TangentMatrix"] // MatrixForm
SMTNewtonIteration[];


If you change the "Cons*" -> 1 to 2 you should see the change of matrix size from 3x3 to 4x4 or vice versa each time you change the value. But I would recomend using the SMTAddEssentialBoundary["ID" == "Lagrange" &, 1 -> 0], since it is not a good practice to change global variables from within the local element. Since the lambda parameter is specific only to each element it could be safe, but if multiple elements tried to write on the same position at the same time, there could be some problems. I would use AceFEM boundary commands when you want to make it constrained:

SMTData["TangentMatrix"] // MatrixForm
SMTAddEssentialBoundary["ID" == "Lagrange" &, 1 -> 0]
SMTData["TangentMatrix"] // MatrixForm


And to unconstrain:

SMTData["TangentMatrix"] // MatrixForm
SMTAddEssentialBoundary["ID" == "Lagrange" &, 1 -> Null]
SMTData["TangentMatrix"] // MatrixForm