Dear Yves, first, thanks for your detailed answers!
For the first question, at this point, i guess it's much more convenient at this point to share a script containing a minimal (not) working test regarding this difference. I have kept the incompressibility brick in both cases. For the second question, it seems clear, thanks. For the third question, providing the expression of the stress tensor directly instead is fine by me, it's not very difficult using the invariants already available in the GWFL combined with some macro. While i am at it, i have another question. It is somehow related to the one in the following thread but for the divergence of a tensor field https://lists.nongnu.org/archive/html/getfem-users/2015-03/msg00009.html I would like to check the satisfaction of the equilibrium equation (i.e. div(P) + f0, where Pi is a stress tensor and f0 is a volumic force). To do so, i gave it a try without volumic forces value=gf.asm_generic(mim=mim, order=0, expression= "Norm_sqr(Div(clambda*Trace(Green_Lagrange_E)*Id(2)+2*cmu*Green_Lagrange_E))", model=model,region=-1) where Green_Lagrange_E is a macro defined by model.add_macro("epsilon", "(Grad_u+(Grad_u)')/2") model.add_macro("Green_Lagrange_E", "epsilon+ (Grad_u)'*Grad_u/2") but it failed (Error in macro expansion. Only variable name are allowed for macro parameter preceded by Grad_ Hess_ Test_ or Test2_ prefixes) Next, i tried to check whether i could at least apply the Div operator to Grad_u directly instead, like that value=gf.asm_generic(mim=mim, order=0, expression= "Norm_sqr(Div(Grad_u))", model=model,region=-1) but it also failed, Grad_u was not recognized. Is there a way to do that? I see that it's possible to have access to the hessian of the model variables; is rebuilding div(P) from the hessian the only way to compute this quantity? Best regards, David. Le jeu. 26 mai 2022 à 10:17, <yves.ren...@insa-lyon.fr> a écrit : > Dear David, > > I do not see any reason why your expression for the Mooney-Rivlin hyper > elastic law would give a different result than the brick. At least if of > cours you keep the > incompressible brick > md.add_finite_strain_incompressibility_brick(mim, 'u', 'p') > (note that using sqr(expr) instead of pow(expr,2) is slightly more > efficient). > > Concerning the plane strain approximation, it is a priori possible to do > this in GWFL, yes. You can define a 3D matrix from your 2D gradient and use > the 3D hyperelastic law. > > For the computation of the Von Mises stress from the potential, it is a > little bit more tricky because the automatic differentiation of Getfem will > give you the directional derivative (in the direction of the test > function). So may be it is possible to extract the components with a > specific choice of test functions, but it could be not so easy ... I never > done that. Unfortunately it is preferable to give the expression of the law > in term of stress tensor directly. > > Best regards, > > Yves > > ------------------------------ > *De: *"David Danan" <daviddanan9...@gmail.com> > *À: *"getfem-users" <getfem-users@nongnu.org> > *Envoyé: *Lundi 23 Mai 2022 13:41:14 > *Objet: *[Getfem-users] Questions about user-defined strain energy > > Dear Getfem-users, > > to check whether i understand correctly the implementation (and because > it's actually much clearer in my code that way), i am trying to replace > some predefined bricks for strain energy by the equivalent version using > GWFL. > For that, i have several questions > > *First question* > For instance > lawname = 'SaintVenant Kirchhoff' > clambda,cmu = params["clambda"],params["cmu"] > model.add_initialized_data('paramsSVK', [clambda, cmu]) > idBrick=model.add_finite_strain_elasticity_brick(mim, lawname, 'u', > 'paramsSVK') > becomes > clambda,cmu = params["clambda"],params["cmu"] > model.add_initialized_data('paramsSVK', [clambda, cmu]) > idBrick=model.add_nonlinear_generic_assembly_brick(mim, > "(paramsSVK(1)/2)*pow(Trace(Green_Lagrange_E),2)+paramsSVK(2)*Trace(Green_Lagrange_E'*Green_Lagrange_E)" > ) > > And the results seems to be the same. > However, for the incompressible Mooney Rivlin strain energy case, it does > not behave as i expected > > Using the example there as a basis in a 3D case > > https://github.com/getfem-doc/getfem/blob/master/interface/tests/python/demo_nonlinear_elasticity.py > and after some simplifications > > I have tried to replace the last line in > lawname = 'Incompressible Mooney Rivlin' > model.add_initialized_data('paramsIMR', [1,1]) > model.add_finite_strain_elasticity_brick(mim, lawname, 'u', 'paramsIMR') > By this > model.add_nonlinear_generic_assembly_brick(mim, > "Incompressible_Mooney_Rivlin_potential(Grad_u, > [paramsIMR(1);paramsIMR(2)])") > Which was exactly the same, of course. Next, i have tried to replace it by > these lines > model.add_macro("F", "Grad_u+Id(3)") > model.add_nonlinear_generic_assembly_brick(mim, "paramsIMR(1)* ( > Matrix_j1(Right_Cauchy_Green(F)) - 3 )+ paramsIMR(2)* ( > Matrix_j2(Right_Cauchy_Green(F)) - 3 )") > Which failed to converge > > I thought this expression was consistent with the implementation of > Mooney_Rivlin_hyperelastic_law::strain_energy and the compute_invariants > here > > http://download-mirror.savannah.gnu.org/releases/getfem/doc/getfem_reference/getfem__nonlinear__elasticity_8cc_source.html > and the documentation > > https://getfem.org/userdoc/model_nonlinear_elasticity.html?highlight=finite%20strain > But, clearly, i am missing something. Could you explain what I am doing > wrong? > > Second question > In a 2D case, i would like to be able to use either a plane strain > approximation based on a given strain energy expression in 3D. > In the implementation, it is nicely done in scalar_type > plane_strain_hyperelastic_law::strain_energy there > > http://download-mirror.savannah.gnu.org/releases/getfem/doc/getfem_reference/getfem__nonlinear__elasticity_8cc_source.html > > Is it possible to do the same using the GWFL? > > *Third question* > I would like to be able to compute the von-mises field for any strain > energy function. > > If It is an existing brick, the method > md.compute_finite_strain_elasticity_Von_Mises(lawname, 'u', 'params', mfdu) > > will do the trick just fine. > > If it's not the case, i guess i can use something akin to the actual > implementation of compute_finite_strain_elasticity_Von_Mises > <http://download-mirror.savannah.gnu.org/releases/getfem/doc/getfem_reference/namespacegetfem.html#a9166bc2065a4f2b5633e2e933ec3e693> > > std::string expr = "sqrt(3/2)*Norm(Deviator(Cauchy_stress_from_PK2(" > + adapted_lawname + "_PK2(Grad_" + varname + "," + params + "),Grad_" > + varname + ")))"; > ga_interpolation_Lagrange_fem(md, expr, mf_vm, VM, rg); > } > > combined with local_projection to get the value at the elements. > The question is: is it possible to compute Piola Kirchhoff 2 from the > strain energy within the GWFL expression given to local_projection? > I have the impression it's the only thing i need to be able to do what i > want. > Let W be a strain energy function and E be the Green-Lagrange tensor > (defined as macros, let's say), is Diff(W, E) doing exactly what i am > expecting for this purpose? > If it's not the case, is there another way to do it? > > Thank you in advance, > kind regards, > David. > >
#!/usr/bin/env python # -*- coding: utf-8 -*- import numpy as np import getfem as gf gf.util('trace level', 1) def SolveBasic3DMecaProblem(version): N1 = 2; N2 = 4; h = 20.; DX = 1./N1; DY = (1.*h)/N2; m = gf.Mesh('cartesian', np.arange(-0.5, 0.5+DX,DX), np.arange(0., h+DY,DY), np.arange(-1.5, 1.5+3*DX,3*DX)) mfu = gf.MeshFem(m, 3) mfu.set_fem(gf.Fem('FEM_QK(3,2)')) mim = gf.MeshIm(m, gf.Integ('IM_GAUSS_PARALLELEPIPED(3,4)')) ftop = m.outer_faces_with_direction([0., 1., 0.], 0.5) fbot = m.outer_faces_with_direction([0., -1., 0.], 0.5) m.set_region(1, ftop) m.set_region(2, fbot) m.set_region(3, np.append(ftop,fbot,axis=1)); model = gf.Model('real') model.add_fem_variable('u', mfu) model.add_initialized_data('paramsIMR', [1,1]) if version=="Predefined": lawname = 'Incompressible Mooney Rivlin' model.add_finite_strain_elasticity_brick(mim, lawname, 'u', 'paramsIMR') elif version=="AssemblyPredefined": model.add_nonlinear_generic_assembly_brick(mim, "Incompressible_Mooney_Rivlin_potential(Grad_u, [paramsIMR(1);paramsIMR(2)])") elif version=="GWFL": model.add_macro("F", "Grad_u+Id(3)") model.add_nonlinear_generic_assembly_brick(mim, "paramsIMR(1)* ( Matrix_j1(Right_Cauchy_Green(F)) - 3 )\ + paramsIMR(2)* ( Matrix_j2(Right_Cauchy_Green(F)) - 3 )") else: raise Exception("Version not available") #Add finite strain incompressibility condition mfp = gf.MeshFem(m,1) mfp.set_classical_discontinuous_fem(1) model.add_fem_variable('p', mfp) model.add_finite_strain_incompressibility_brick(mim, 'u', 'p') model.add_initialized_data('f', [0,-0.1,0]) model.add_source_term_brick(mim, 'u', 'f') model.add_initialized_data('u_d', [0,0,0]) model.add_Dirichlet_condition_with_multipliers(mim, 'u', 1, 3, "u_d") model.variable_list() maxIter=50 solverIt=model.solve('very noisy','max_iter',maxIter, 'max_res',1e-7, 'lsearch','simplest') if not solverIt[0]<maxIter: raise Exception("Failed to converge") displacements = model.variable('u') return displacements def CheckConsistency_GWFL_PredefinedBrick(): print("Checking consitency between Predefined brick and AssemblyPredefined brick") solutionPredefined=SolveBasic3DMecaProblem(version="Predefined") solutionAssemblyPredefined=SolveBasic3DMecaProblem(version="AssemblyPredefined") np.testing.assert_almost_equal(solutionPredefined,solutionAssemblyPredefined) print("Checking consitency between Predefined brick and GWFL") solutionGWFL=SolveBasic3DMecaProblem(version="GWFL") np.testing.assert_almost_equal(solutionPredefined,solutionGWFL) if __name__ == '__main__': CheckConsistency_GWFL_PredefinedBrick()