Coverage for pyxfem/solidmechanics/membrane.py: 44%

510 statements  

« prev     ^ index     » next       coverage.py v7.17.0, created at 2026-10-24 07:17 +0000

1""" Module to test ideas for hyper elastic membrane. For now splitting F in F1@iF0 """ 

2# pylint disable=invalid-name 

3from __future__ import annotations 

4import os 

5import sys 

6from typing import Literal 

7import numba 

8import numpy as np 

9import scipy as sp 

10import gmsh 

11from pyxfem.core.config import fhalf, IndexType, IndexArray 

12import pyxfem.core.mesh_simplex_one_level as sm 

13import pyxfem.solidmechanics.hyperelasticity as hyp 

14import pyxfem.core.gmsh_mesh_generator as mg 

15from pyxfem.core.smallsize_tensor import FASTMATH, npfloat, FloatArray, metric, dmetric, d2metric,\ 

16 inv, det, vecprodmat 

17 

18from pyxfem.core.nonlinear_solver import newton, arc_lenght_predictor_expansion, arc_lenght_predictor_a, arc_lenght_predictor_eval 

19import pyxfem.core.sparse_tools as spt 

20from pyxfem.core.sparse_tools import regular_block_diag_to_csc, vblock, mblock, split_vblock 

21import pyxfem.core.function_spaces as fs 

22from pyxfem.core.exec_tools import Profile 

23import pyxfem.solidmechanics.boundary_conditions as bc 

24import pyxfem.postpro.gmsh_post_pro_interface as gp 

25 

26# # Set the maximum number of threads for OpenMP and related backends 

27os.environ["OMP_NUM_THREADS"] = "8" # Change '4' to your desired core count 

28os.environ["MKL_NUM_THREADS"] = "8" 

29os.environ["OPENBLAS_NUM_THREADS"] = "8" 

30 

31 

32 

33 

34class AssemblerVector(): 

35 def __init__(self, Op, dofs:IndexArray|slice = slice(None,None, None)): 

36 # pylint: disable=invalid-name 

37 self.Op_f = Op[:, dofs] 

38 

39 def assemble(self, D): 

40 """ Assemble on the defined dofs """ 

41 return D.reshape(-1)@self.Op_f 

42 

43class AssemblerMatrix(): 

44 def __init__(self, OpLeft, OpRight, dofs:IndexArray|slice = slice(None)): 

45 self.OpL_f = OpLeft[dofs,:] 

46 self.OpR_f = OpRight[:, dofs] 

47 def assemble(self, D): 

48 Dcsr = spt.regular_block_diag_to_csc(D) 

49 return self.OpL_f@Dcsr@self.OpR_f 

50 

51class Membrane(): 

52 """ Class to represent membrane problem in 3d """ 

53 # pylint: disable=C0103 

54 def __init__(self, law:hyp.HyperElasticMaterial, mesh:sm.SMesh): 

55 assert law.hyp == hyp.MaterialHypothesis.PLANESTRESS 

56 self._B = None 

57 self._Natv = None 

58 self._N = None 

59 self.law = law 

60 self.mesh = mesh 

61 self.dofm = fs.VertexSpaceDofManager(mesh) 

62 self.free_dofs, self.fixed_dofs, self.fixed_values = [slice(None, None, None), None, None] 

63 self.initial_zstretch = 2. 

64 XYZ = mesh.vcoord() 

65 self.X = XYZ[self.dofm.vid] 

66 if self.X.shape[-1] == 2 : 

67 print("Assuming a plannar initial membrane") 

68 self.X = np.column_stack([self.X, np.zeros(self.X.shape[:-1])]) 

69 elif self.X.shape[-1] == 3 : 

70 print("The initial membrane is assumed to be a curved surface") 

71 else : 

72 raise ValueError("The mesh vertices must have 2d or 3d coordinates") 

73 # x = self.X.copy() 

74 # x[...,2] = initial_zstretch*x[...,2] 

75 # self.x = x 

76 self.F0 = self.getGrad(self.X) 

77 self.iF0 = inv(self.F0) 

78 self.M = metric(self.F0) 

79 self.J0 = np.sqrt(det(self.M)) 

80 self.iM = inv(self.M) 

81 self.setAssembler() 

82 

83 def getGrad(self, A:FloatArray, algo:Literal[0,1] = 0)-> FloatArray: 

84 """ return the gradient of the nodal vector field stored in A 

85 input A[i,j] coordinate j of field A at node j 

86 return G(nelem, 3, 2) matrix, such as : 

87 G[ie, j, 0] is the derivative of A in elem ie with regard to reference coordinate u 

88 G[ie, j, 1] is the derivative of A in elem ie with regard to reference coordinate v 

89 """ 

90 if algo == 0: 

91 return (self.getB()@A.flatten()).reshape((self.dofm.nelem, 3, 2)) 

92 if algo == 1: 

93 t2vf = self.dofm.a2dofs 

94 Atris = A[t2vf] 

95 BelemsT = np.array([[[-1., 1. ,0.],[-1.,0.,1.]]]).swapaxes(-1,-2) 

96 return Atris.swapaxes(-1,-2)@BelemsT 

97 

98 def getB(self)-> sp.sparse.spmatrix: 

99 """ return the sparse matrix B such as B@x return the values of the (FE) local gradient 

100 of the vector field x xith regard to the parameters uv of the point in the space 

101 of the referent element, for each element 

102 """ 

103 if self._B is None: 

104 nelem = self.dofm.nelem 

105 dN = np.array([[[-1., 1. ,0.],[-1.,0.,1.]]]) 

106 dN = np.broadcast_to(dN, (nelem,) + dN.shape) 

107 self._B = fs.op2sparse(dN, self.dofm.nscaldof, self.dofm.a2dofs, 3, 3, 1, 2 ) 

108 return self._B 

109 

110 def getNatVertices(self)-> sp.sparse.spmatrix: 

111 """ return the sparse matrix B such as B@x return the values of the (FE) local gradient 

112 of the vector field x xith regard to the parameters uv of the point in the space 

113 of the referent element, for each element 

114 """ 

115 if self._Natv is None: 

116 nelem = self.dofm.nelem 

117 N = np.array([[[1., 0. ,0.]], [[0.,1.,0.]], [[0.,0.,1.]] ]) 

118 N = np.broadcast_to(N, (nelem,) + N.shape) 

119 self._Natv = fs.op2sparse(N, self.dofm.nscaldof, self.dofm.a2dofs, 3, 3, 3, 1 ) 

120 return self._Natv 

121 

122 def getN(self)-> sp.sparse.spmatrix: 

123 """ return the sparse matrix N such as N@x return the values of the (FE) at gauss point 

124 (u,v) = (1/3, 1/3) (Gauss point of the triangle) 

125 """ 

126 if self._N is None: 

127 nelem = self.dofm.nelem 

128 N = np.array([[[1./3., 1./3. , 1./3.]]]) 

129 N = np.broadcast_to(N, (nelem,) + N.shape) 

130 self._N = fs.op2sparse(N, self.dofm.nscaldof, self.dofm.a2dofs, 3, 3, 1, 1 ) 

131 return self._N 

132 

133 def getF(self, x:FloatArray, algo:Literal[0,1] = 0)-> FloatArray: 

134 """ 

135 return an array of size nelem, 3, 3 

136 such as F[k].dX = dx where DX is is a tangent vector included 

137 in element k in the reference configuration 

138 """ 

139 if algo == 0 : 

140 return self.getGrad(x, algo = 0)@self.iF0 

141 if algo == 1 : 

142 return self.getGrad(x, algo = 1)@self.iF0 

143 

144 def surf0(self): 

145 """ return the initial surface of the membrane """ 

146 return 0.5*np.sum(self.J0) 

147 

148 def surf(self, x:FloatArray)-> npfloat: 

149 """ return the deformed surface of the membrane """ 

150 J1 = det(self.getGrad(x)) 

151 return fhalf*np.sum(J1) 

152 

153 def getC(self, F1:FloatArray)-> FloatArray: 

154 """ compute the C=FT@F component (2x2) for each element 

155 Where F1 contain the gradient with regard to local coordinates of the deformed position 

156 dx= F1@du 

157 """ 

158 m = metric(F1) 

159 return self.iM@m 

160 

161 def getdCdF1(self, F1:FloatArray, usenumba = False)-> FloatArray: 

162 """ return the derivative of C with regard to F1""" 

163 dm = dmetric(F1) 

164 if not usenumba: 

165 return np.einsum("...ak, ...kbic -> ...abic", self.iM, dm) 

166 else : 

167 N=F1.shape[0] 

168 dCdF1 = np.zeros((N, 2, 2, 3, 2), dtype = npfloat) 

169 Membrane._dCdF1_njit(self.iM, dm, dCdF1) 

170 return dCdF1 

171 

172 

173 # @staticmethod 

174 # @numba.njit(parallel=True, cache = True, fastmath = FASTMATH) 

175 # def _dCdF1_njit( iM, dm, dCdF1_out): 

176 # N = iM.shape[0] 

177 # for elem in numba.prange(N): # type ignore # pylint: disable=E1133 

178 # iMe, dme, dCdF1e = iM[elem], dm[elem], dCdF1_out[elem] 

179 # for a in range(2): 

180 # for c in range(2): 

181 # for i in range(3): 

182 # for d in range(2): 

183 # dCdF1e[a,c,i,d] = 0. 

184 # for b in range(2): 

185 # dCdF1e[a,c,i,d] += iMe[a,b] * dme[b,c,i,d] 

186 @staticmethod 

187 @numba.njit(parallel=True, cache=True, fastmath=FASTMATH) 

188 def _dCdF1_njit(iM, dm, dCdF1_out): 

189 N = iM.shape[0] 

190 for elem in numba.prange(N): # type ignore # pylint: disable=E1133 

191 iMe, dme, dCdF1e = iM[elem], dm[elem], dCdF1_out[elem] 

192 for a in range(2): 

193 for c in range(2): 

194 for i in range(3): 

195 for d in range(2): 

196 # Use a local accumulator for register speed 

197 acc = 0.0 

198 for b in range(2): 

199 acc += iMe[a,b] * dme[b,c,i,d] 

200 # Write to the element array exactly once 

201 dCdF1e[a,c,i,d] = acc 

202 

203 def getd2Cd2F1(self, F1:FloatArray, usenumba = False)-> FloatArray: 

204 """ return the second derivative of C with regard to F1""" 

205 d2m = d2metric(F1) 

206 #dm = 0.5*(dm+np.swapaxes(dm, -3,-4)) 

207 return np.einsum("...ak, ...kbicjd -> ...abicjd", self.iM, d2m) 

208 

209 def strain_energy(self, *, x:FloatArray|None=None, F1:FloatArray|None = None)-> npfloat: 

210 """ return the integrates strain energy """ 

211 if F1 is None: 

212 if x is not None: 

213 F1 = self.getGrad(x, algo = 0) 

214 else : 

215 raise ValueError("in put either x or F1") 

216 C = self.getC(F1) 

217 J0 = self.J0 

218 return fhalf*np.sum(J0*self.law.potentialC(C)) 

219 

220 def dpotentialdF1(self, F1: FloatArray, usenumba = False) -> FloatArray: 

221 """ return the first derivative of the strain enegy with regard to F1 fo each element 

222 (a stress measure) 

223 """ 

224 C = self.getC(F1) 

225 dCdF1 = self.getdCdF1(F1, usenumba=usenumba) 

226 dphidC = 0.5*self.law.PKII(C) 

227 def fint_terms(): 

228 if usenumba : 

229 N = F1.shape[0] 

230 dphidF1 = np.zeros((N, 3, 2), dtype = npfloat) 

231 Membrane._dpotentialdF1_njit(dphidC, dCdF1, self.J0, dphidF1) 

232 return dphidF1 

233 else: 

234 print("###") 

235 return np.einsum("...ef, ...efia, ... -> ...ia", dphidC, dCdF1, 0.5*self.J0 ) 

236 return fint_terms() 

237 

238 @staticmethod 

239 @numba.njit(parallel=True, cache = True, fastmath = FASTMATH) 

240 def _dpotentialdF1_njit( dphidC, dCdF1, J0, d2phid2F1_out): 

241 N = dphidC.shape[0] 

242 for elem in numba.prange(N): # type ignore # pylint: disable=E1133 

243 dphidCe, dCdF1e, J0e, d2phid2F1e = dphidC[elem], dCdF1[elem], J0[elem], d2phid2F1_out[elem] 

244 for i in range(3): 

245 for a in range(2): 

246 d2phid2F1e[i, a] = 0. 

247 for e in range(2): 

248 for f in range(2): 

249 d2phid2F1e[i, a] += 0.5*J0e*dphidCe[e,f]*dCdF1e[e,f, i,a] 

250 

251 def d2potentiald2F1(self, F1: FloatArray, usenumba = False) -> FloatArray: 

252 """ return the second derivative of the strain enegy with regard to F1 fo each element 

253 (a tangent stifness) 

254 """ 

255 C = self.getC(F1) 

256 dCdF1 = self.getdCdF1(F1, usenumba = usenumba) 

257 d2CdF1_2 = self.getd2Cd2F1(F1) 

258 dphidC = 0.5*self.law.PKII(C) 

259 d2phid2C = 0.5*self.law.dPKIIdC(C) 

260 

261 def kint_terms(): 

262 if usenumba: 

263 N = F1.shape[0] 

264 d2phid2CF1 = np.zeros((N,3,2,3,2), dtype=npfloat) 

265 Membrane._d2phid2CF1_njit( dCdF1, d2phid2C, dphidC, d2CdF1_2, self.J0, d2phid2CF1) 

266 else : 

267 print("ggg") 

268 dCdF1_d2phid2C_dCdF1 = np.einsum(" ...efia, ...efgh, ...ghjb -> ...iajb", 

269 dCdF1, d2phid2C, dCdF1) 

270 dphidC_d2Cd2F1 = np.einsum("...ef, ...efiajb , ...-> ...iajb", dphidC, d2CdF1_2, 0.5*self.J0) 

271 d2phid2CF1 = dCdF1_d2phid2C_dCdF1 + dphidC_d2Cd2F1 

272 return d2phid2CF1 

273 return kint_terms() 

274 

275 

276 @staticmethod 

277 @numba.njit(parallel=True, cache=True, fastmath=FASTMATH) 

278 def _d2phid2CF1_njit(dCdF1, d2phid2C, dphidC, d2CdF1_2, J0, d2phid2F1_out): 

279 N = dCdF1.shape[0] 

280 for elem in numba.prange(N): # type ignore # pylint: disable=E1133 

281 d2phid2F1e = d2phid2F1_out[elem] 

282 dCdF1e = dCdF1[elem] 

283 d2phid2Ce = d2phid2C[elem] 

284 dphidCe = dphidC[elem] 

285 d2CdF1_2e = d2CdF1_2[elem] 

286 # 1. Hoist the scalar weight calculation outside the tensor loops 

287 weight = 0.5 * J0[elem] 

288 for i in range(3): 

289 for a in range(2): 

290 for j in range(3): 

291 for b in range(2): 

292 # 2. Use a local scalar accumulator to stay in CPU registers 

293 acc = 0.0 

294 for e in range(2): 

295 for f in range(2): 

296 # Term 1 contribution 

297 acc += dphidCe[e,f] * d2CdF1_2e[e,f,i,a,j,b] 

298 # 3. Cache the array lookup for Term 2 

299 dCdF1e_efia = dCdF1e[e,f,i,a] 

300 for g in range(2): 

301 for h in range(2): 

302 # Term 2 contribution 

303 acc += dCdF1e_efia * d2phid2Ce[e,f,g,h] * dCdF1e[g,h,j,b] 

304 # Apply the element weight exactly once per final tensor component 

305 d2phid2F1e[i,a,j,b] = acc * weight 

306 

307 def internalForce(self, *, x:FloatArray|None =None, F1:FloatArray|None=None)-> FloatArray: 

308 """ return the finite element internal force vector """ 

309 if (x is None) and (F1 is None) : 

310 raise ValueError("input either x or F1") 

311 if F1 is None and x is not None: 

312 F1 = self.getGrad(x, algo = 0) 

313 if F1 is not None: 

314 dphidF1 = self.dpotentialdF1(F1, usenumba=True) 

315 return self.assemblerFint.assemble(dphidF1) 

316 #return dphidF1.flatten()@self.getB() 

317 raise ValueError("input either x or F1") 

318 

319 def internalStiffness(self, *, x:FloatArray|None =None, F1:FloatArray|None=None) \ 

320 -> sp.sparse.csr_array: 

321 """ return the finite element internal stifness as a asparse matrix """ 

322 if F1 is None: 

323 if x is not None : 

324 F1 = self.getGrad(x, algo = 0) 

325 else : 

326 raise ValueError("input either x or F1") 

327 #w = 0.5*self.J0.reshape(self.J0.shape + (1,)*4) 

328 d2phid2F1 = (self.d2potentiald2F1(F1, usenumba=True)).reshape(F1.shape[:-2]+(6,6)) 

329 return self.assemblerKint.assemble(d2phid2F1) 

330 

331 # def internalStiffnessSensibility(self, *, x:FloatArray, dx:FloatArray) \ 

332 # -> sp.sparse.csr_array: 

333 # """ return the finite element internal stifness sensibility in direction dx, as a asparse matrix """ 

334 # eps = 1.e-6 

335 # xp = x +eps*dx 

336 # F1p = self.getGrad(xp) 

337 # d2phid2F1p = self.d2potentiald2F1(F1p, usenumba=True) 

338 

339 # xm = x - eps*dx 

340 # F1m = self.getGrad(xm) 

341 # d2phid2F1m = self.d2potentiald2F1(F1m, usenumba=True) 

342 

343 # Dd2phidF1_dx = (d2phid2F1p -d2phid2F1m)/2/eps 

344 

345 # w = 0.5*self.J0.reshape(self.J0.shape + (1,)*4) 

346 # d2phid2F1 = (w*self.d2potentiald2F1(F1, usenumba=True)).reshape(F1.shape[:-2]+(6,6)) 

347 

348 # d2phid2F1 = spt.regular_block_diag_to_csr(d2phid2F1) 

349 # Ke = self.getB().T@d2phid2F1@self.getB() 

350 # return Ke 

351 

352 def normalPerElem(self, x:FloatArray|None =None, F1:FloatArray|None=None)-> FloatArray: 

353 """ return the normal to each triangle of the deformed membrane """ 

354 if (x is None) and (F1 is None) : 

355 raise ValueError("input either x or F1") 

356 if F1 is None and x is not None: 

357 F1 = self.getGrad(x, algo = 0) 

358 if F1 is not None : 

359 return np.cross(F1[...,0], F1[...,1]) 

360 raise ValueError("input either x or F1") 

361 

362 def dnormalPerElem(self, x:FloatArray|None =None, F1:FloatArray|None=None): 

363 """ return the derivatives of the normal per element as a function of x, 

364 the nodals positions""" 

365 if (x is None) and (F1 is None) : 

366 raise ValueError("input either x or F1") 

367 if F1 is None and x is not None: 

368 F1 = self.getGrad(x, algo = 0) 

369 if F1 is not None: 

370 Q0 = vecprodmat(F1[...,0]) 

371 Q1 = vecprodmat(F1[...,1]) 

372 dn_elem = np.zeros(F1.shape[:-2] + (3,6)) 

373 dn_elem[...,[0, 2, 4]] = -Q1 

374 dn_elem[...,[1, 3, 5]] = Q0 

375 dn_elem_sparse = regular_block_diag_to_csc(dn_elem) 

376 opdnormal = dn_elem_sparse@self.getB() 

377 opdnormal.sort_indices() 

378 return opdnormal 

379 else: 

380 raise ValueError("input either x or F1") 

381 

382 def pressureForcePerElem(self, *, p:float, x:FloatArray|None =None, F1:FloatArray|None=None)\ 

383 -> FloatArray: 

384 """ return the pressure force per element, as a function of p and x (or p and F1) """ 

385 return 0.5*p* self.normalPerElem(x = x, F1 = F1) 

386 

387 def pressureForce(self, *, p:float, x:FloatArray|None =None, F1:FloatArray|None=None)-> FloatArray: 

388 """ return the "nodal" pressure force per node, as a function of p and x (or p and F1) """ 

389 Fe = self.pressureForcePerElem(p=p, x=x, F1=F1) 

390 return self.assemblerFext.assemble(Fe) 

391 #N = self.getN() 

392 #return N.T@Fe.flatten() 

393 

394 def pressureStiffnessPerElem(self, *, p:float, x:FloatArray|None =None, F1:FloatArray|None=None)\ 

395 -> sp.sparse.csr_array: 

396 """ return the derivative of the pressure force per element with reagardto x 

397 (the deformed nodal position), as a function of p, x (or p F1)""" 

398 return 0.5*p*self.dnormalPerElem(x=x, F1 =F1) 

399 

400 def pressureStiffness(self, *, p:float, x:FloatArray|None =None, F1:FloatArray|None=None)\ 

401 -> sp.sparse.csr_array: 

402 """ return the finite element internal stiffness as a sparse matrix """ 

403 if (x is None) and (F1 is None) : 

404 raise ValueError("input either x or F1") 

405 if F1 is None and x is not None: 

406 F1 = self.getGrad(x, algo = 0) 

407 if F1 is not None: 

408 Q0 = vecprodmat(F1[...,0]) 

409 Q1 = vecprodmat(F1[...,1]) 

410 dn_elem = np.zeros(F1.shape[:-2] + (3,6)) 

411 dn_elem[...,[0, 2, 4]] = -Q1 

412 dn_elem[...,[1, 3, 5]] = Q0 

413 return self.assemblerKext.assemble(0.5*p*dn_elem) 

414 

415 def postProDofVector(self, U:FloatArray, pos:FloatArray|None = None): 

416 """ return X and U in A 3d array : U[i,j,k] is the displacement in direction k of node j of 

417 element i. Usefull for gmsh post-pro""" 

418 if pos is None : 

419 assert U.shape == (self.dofm.nscaldof,3) 

420 elemvertexVals = U[self.dofm.a2dofs] 

421 return self.mesh.t2v_coord(), elemvertexVals 

422 else: 

423 raise NotImplementedError() 

424 

425 def setDirichlet(self, physname2dirichlet:dict): 

426 ''' Compute and return the set of free dofs, fixed dofs and values for fixed dofs ''' 

427 gname2dofid, gname2dofxy = bc.get_dofs_and_interpolation_points( 

428 self.mesh, physname2dirichlet.keys(), self.dofm) 

429 self.free_dofs, self.fixed_dofs, self.fixed_values = bc.compute_dirichlet( 

430 self.dofm, physname2dirichlet, gname2dofid, gname2dofxy) 

431 #self.free_dofs = np.asarray(free_dofs, dtype = IndexType) 

432 self.setAssembler() 

433 

434 def setAssembler(self): 

435 free_dofs = self.free_dofs 

436 B = self.getB() 

437 N = self.getN() 

438 self.assemblerFint = AssemblerVector(B, dofs = free_dofs) 

439 self.assemblerFext = AssemblerVector(N, dofs = free_dofs) 

440 self.assemblerKint = AssemblerMatrix(B.T, B, dofs = free_dofs) 

441 self.assemblerKext = AssemblerMatrix(N.T, B, dofs = free_dofs) 

442 

443class membrane_operator_dirichlet(): 

444 def __init__(self, mem:Membrane, free_dofs): 

445 self.mem = mem 

446 self.free_dofs = free_dofs 

447 self.start_position :None | FloatArray = None 

448 self.ndofs = len(free_dofs) 

449 

450 def set_start(self, start_position: FloatArray): 

451 self.start_position = start_position 

452 

453 def x2position(self, x): 

454 if self.start_position is None: 

455 raise ValueError("Start Position not setup") 

456 position = self.start_position.flatten() 

457 position[self.free_dofs] = x 

458 return position.reshape((-1,3)) 

459 

460 def position2x(self, position): 

461 return position.flatten()[self.free_dofs] 

462 

463 def compute_equilibrium_res(self, x, p): 

464 position = self.x2position(x) 

465 mem = self.mem 

466 Fint = mem.internalForce(x = position) 

467 Fext = mem.pressureForce(p = p, x = position) 

468 return Fint-Fext 

469 

470 def compute_fext(self, x, p=1.): 

471 position = self.x2position(x) 

472 mem = self.mem 

473 return mem.pressureForce(p = p, x = position) 

474 

475 def compute_Kext(self, x, p=1.): 

476 position = self.x2position(x) 

477 mem = self.mem 

478 return mem.pressureStiffness(p= p, x=position) 

479 

480 def compute_equilibrium_jac(self, x, p): 

481 ''' compute the jacobian : derivative of the residual with regard to x''' 

482 position = self.x2position(x) 

483 mem = self.mem 

484 Kint = mem.internalStiffness(x=position) 

485 Kext = mem.pressureStiffness(p= p, x=position) 

486 K = Kint-Kext 

487 # rcond = spt.rcond_estimate(K) 

488 # print("rcond", rcond) 

489 return K 

490 

491 def compute_djacdx_u(self, x , p, u): 

492 ''' directional derivative of the jacobian in the direction u''' 

493 eps = 1.e-5 

494 Kt_p_u = self.compute_equilibrium_jac(x = x + eps*u, p = p)@u 

495 Kt_m_u = self.compute_equilibrium_jac(x = x - eps*u, p = p)@u 

496 return (Kt_p_u-Kt_m_u)/2./eps 

497 ## Alternative implementation using second order derivative of the residual, assuming the residual is zero at x 

498 # eps = 1.e-5 

499 # r_p = self.compute_equilibrium_res(x = x + eps*u, p = p) 

500 # r_m = self.compute_equilibrium_res(x = x - eps*u, p = p) 

501 # return (r_p + r_m)/eps/eps 

502 

503class membrane_solver_imposed_displacement(membrane_operator_dirichlet): 

504 def __init__(self, mem, free_dofs): 

505 super().__init__(mem, free_dofs) 

506 #self.memop = membrane_operator_dirichlet(mem, free_dofs) 

507 self.start_position = None 

508 self.p = None 

509 

510 def get_fun(self): 

511 return lambda x: self.compute_equilibrium_res(x, self.p) 

512 

513 def get_jac(self): 

514 return lambda x: self.compute_equilibrium_jac(x, self.p) 

515 

516 def get_linsolver(self): 

517 return sp.sparse.linalg.spsolve 

518 

519 def solve(self, start_position, p, *newton_args, **newton_kwargs): 

520 self.set_start(start_position) 

521 self.p = p 

522 x0 = self.position2x(start_position) 

523 newton_kwargs['jac'] = self.get_jac() 

524 newton_kwargs['linsolver'] = self.get_linsolver() 

525 # tol = 1.e-6, atol = 1.e-6, nitermax =10, 

526 # res = newton(self.get_fun(), x0, jac = self.get_jac(), 

527 # linsolver = self.get_linsolver(), rtol = 1.e-6, atol = 1.e-6, nitermax =10, *newton_args, **newton_kwargs) 

528 res = newton(self.get_fun(), x0, *newton_args, **newton_kwargs) 

529 if not res.success: 

530 print(f"newton failed after {res.nit}") 

531 return res.success, self.x2position(res.x) 

532 

533class membrane_solver_pressureloading_newton(membrane_operator_dirichlet): 

534 def __init__(self, mem, free_dofs): 

535 super().__init__(mem, free_dofs) 

536 self.start_position = None 

537 self.p = None 

538 

539 def get_fun(self): 

540 return lambda x: self.compute_equilibrium_res(x, self.p) 

541 

542 def get_jac(self): 

543 return lambda x: self.compute_equilibrium_jac(x, self.p) 

544 

545 def get_linsolver(self): 

546 return sp.sparse.linalg.spsolve 

547 

548 def solve(self, start_position, p, *newton_args, **newton_kwargs): 

549 self.set_start(start_position) 

550 self.p = p 

551 x0 = self.position2x(start_position) 

552 newton_kwargs['jac'] = self.get_jac() 

553 newton_kwargs['linsolver'] = self.get_linsolver() 

554 res = newton(self.get_fun(), x0, *newton_args, **newton_kwargs) 

555 if not res.success: 

556 print(f"newton failed after {res.nit}") 

557 return res.success, self.x2position(res.x) 

558 

559class membrane_solver_pressureloading_arclenght(membrane_operator_dirichlet): 

560 def __init__(self, mem, free_dofs): 

561 super().__init__(mem, free_dofs) 

562 # self.p0 = None 

563 # self.x0 = None 

564 self.alpha = None 

565 self.du_prev = None 

566 self.dp_prev = None 

567 

568 def xp2_block_x(self, x, p): 

569 return vblock(x, np.array([p])) 

570 

571 def block_x2xp(self, block_x): 

572 x = block_x[0] 

573 p = block_x[1][0] 

574 du = x - self.x0 

575 dp = p - self.p0 

576 return x, p, du, dp 

577 

578 def get_fun(self, a, alpha, scal_equ, scal_arc): 

579 def fun(block_x): 

580 x, p, du, dp = self.block_x2xp(block_x) 

581 #plot_disp(self.mem, self.x2position(x), "bl") 

582 res_equ = self.compute_equilibrium_res(x, p) 

583 n = len(x) 

584 res_arc = du.dot(du)/n + alpha*dp**2 - a**2 

585 return vblock(scal_equ*res_equ , np.array([scal_arc*res_arc])) 

586 return fun 

587 

588 def get_jac(self, alpha, scal_arc, scal_equ): 

589 def jac(block_x): 

590 n = self.ndofs 

591 x, p, du, dp = self.block_x2xp(block_x) 

592 k00 = scal_equ*self.compute_equilibrium_jac(x, p) 

593 k01 = scal_equ*self.compute_fext(x, p = -1.).reshape((-1,1)) 

594 k10 = scal_arc*2.*du.reshape((1, -1))/n 

595 k11 = scal_arc*2.*alpha*dp.reshape((1,1)) 

596 k = mblock(k00, k01, k10, k11) 

597 return k 

598 return jac 

599 

600 def get_linsolver(self): 

601 def solve(block_k, block_x): 

602 return spt.block_linsolve(block_k, block_x) 

603 return solve 

604 

605 def solve(self, start_position, p0, a = None, delta = None, afac=None, amax = 0.1, alpha =None, pred_order = 2, *newton_args, **newton_kwargs): 

606 du_prev = self.du_prev 

607 dp_prev = self.dp_prev 

608 if alpha is None: 

609 alpha = self.alpha # after the first step, we always keep the same alpha 

610 self.start_position = start_position.copy() 

611 x0 = self.position2x(start_position) 

612 self.x0 = x0 

613 self.p0 = p0 

614 K = self.compute_equilibrium_jac(x0, p0) 

615 dus, dls, alpha = arc_lenght_predictor_expansion( drdx = K, 

616 drdl = -self.compute_fext(x0, 1.), 

617 fd2rdx2_u = lambda u : self.compute_djacdx_u(x = x0, p=p0, u=u), 

618 d2rdxdl = -self.compute_Kext(x0, 1.), 

619 du_prev = du_prev, 

620 dl_prev = dp_prev, 

621 alpha = alpha, 

622 pred_order= pred_order 

623 ) 

624 if a is None: 

625 a = arc_lenght_predictor_a(dus, dls, alpha, delta, afac, amax) 

626 dx, dp = arc_lenght_predictor_eval(dus, dls, a) 

627 

628 x_pred = x0 + dx 

629 p_pred = p0 + dp 

630 self.alpha = alpha 

631 scal_arc = 1./a/a 

632 scal_equ = 1./np.max(K.diagonal())/a 

633 block_x_pred = self.xp2_block_x(x_pred ,p_pred) 

634 fun = self.get_fun(a=a, alpha=alpha, scal_equ=scal_equ, scal_arc= scal_arc) 

635 newton_kwargs['jac'] = self.get_jac(alpha, scal_arc, scal_equ) 

636 newton_kwargs['linsolver'] = self.get_linsolver() 

637 newton_kwargs['inplace_sub'] = spt.block_isub 

638 newton_kwargs['norm'] = spt.block_norm 

639 newton_kwargs.setdefault('nitermax', 4) 

640 newton_kwargs.setdefault('fail_on_increasing_res', True) 

641 res = newton(fun, block_x_pred, *newton_args, **newton_kwargs) 

642 if not res.success: 

643 print(f"newton failed after {res.nit}") 

644 x, p = split_vblock(res.x) 

645 p = p[0] 

646 self.du_prev = x - self.x0 

647 self.dp_prev = p - self.p0 

648 position = self.x2position(x) 

649 return res.success, res.nit, position, p, a 

650 

651def plot_disp(mem, x, name): 

652 gmsh.option.setNumber("PostProcessing.AnimationCycle", 1) 

653 gmsh.option.setNumber("Mesh.SurfaceEdges", 0) 

654 trisXYZ, trisDISP = mem.postProDofVector(x - mem.X) 

655 gp.listPlotFieldTri(trisXYZ, trisDISP, P0=False, 

656 viewname=f"{name}_disp", VectorType="Displacement", 

657 DisplacementFactor=1.) 

658 

659def cylindrical_membrane_under_pressure_load(): 

660 # Build hyperelastic law 

661 E = 1. 

662 nu = 0.2 

663 law1 = hyp.CompressibleNeoHookeen(E = E, nu = nu, hyp = hyp.PLANESTRESS) 

664 #initialize gmsh 

665 argv = sys.argv 

666 gmsh.initialize(argv) 

667 # build the mesh 

668 radius = 1. 

669 height = 1. 

670 ref = 2 

671 n_theta_quarter=10*ref 

672 n_z = 20*ref 

673 #modelname, physdic = mg.cylinder(radius, height, hscale) 

674 modelname, physdic = mg.structured_cylinder(radius, height, n_theta_quarter=n_theta_quarter, n_z = n_z) 

675 mesh1 = sm.gmshmodel2smesh(modelname, physdic.keys(), dim=3) 

676 nv, nt = (mesh1.nv(), mesh1.ntris()) 

677 print(f"nv: {nv:d}, nt {nt:d}") 

678 # print(physdic) show groups name 

679 # Create Membrane model 

680 mem = Membrane(law1, mesh1) 

681 diriBC = {'bottom': {'x':0., 'y':0., 'z':0.}, 'top': {'y':0.,'x':0., 'z':1.} } 

682 gname2dofid, gname2dofxy = bc.get_dofs_and_interpolation_points( 

683 mesh1, diriBC.keys(), mem.dofm) 

684 free_dofs, fixed_dofs, fixed_values = bc.compute_dirichlet(mem.dofm, diriBC, gname2dofid, gname2dofxy) 

685 x = mem.X.copy() 

686 p = 0 #1e3 

687 # plot initial position 

688 plot_disp(mem, x, "init") 

689 # set up the solver 

690 solver = membrane_solver_pressureloading_newton(mem, free_dofs=free_dofs) 

691 solver.mem.setDirichlet(diriBC) 

692 solver2 = membrane_solver_pressureloading_arclenght(mem, free_dofs=free_dofs) 

693 # First load increment : initial pull in the z direction 

694 lz = 1.1 # initial stretch in z direction 

695 inc = f"initial z pull {lz}" 

696 x[:,2] *= lz 

697 Profile.enable() 

698 converged, x = solver.solve(start_position = x, p = 0., nitermax = 20, rtol = 1.e-8, atol = 1.e-8) 

699 Profile.disable() 

700 if not converged : 

701 print(f"inc {inc} not converged. Stop") 

702 raise ValueError("solver.solve did not converge") 

703 print(f"inc {inc} converged ") 

704 plot_disp(mem, x, "zpull") 

705 inc = 0 

706 p = 0. 

707 delta0 = 1.e-4 

708 delta = delta0 

709 a0 = 0.05 

710 a = a0 

711 amax = 1. 

712 afac = 1. 

713 max_inc = 20 

714 

715 def solve(x, p, afac): 

716 return solver2.solve(start_position = x, p0 = p, a = None, delta = delta, afac = afac, amax = amax, 

717 pred_order = 2, nitermax = 10, verbose = True, atol = 1.e-10, rtol = 1.e-7) 

718 

719 while a > 1.e-6*a0 and delta > 1.e-6 * delta0 and inc < max_inc: 

720 xstart = x.copy() 

721 pstart = p 

722 while 1: 

723 Profile.enable() 

724 converged, nit, x, p, a = solve(x, p, afac) 

725 Profile.disable() 

726 if converged : 

727 inc += 1 

728 print(f"inc {inc:03d} a {a:.3e}, p {p:.3e} converged in {nit} iterations") 

729 #a = a/( nit/3) 

730 plot_disp(mem, x, f"inc_{inc:03d}_p_{p:.3e}") 

731 afac =1. 

732 break 

733 if not converged : 

734 x = xstart.copy() 

735 p = pstart 

736 afac = afac/2. 

737 print(f"inc {inc:03d} a {a:.3e}, p {p:.3e} not converged after {nit} iterations") 

738 

739if __name__ == "__main__": 

740 Profile.doprofile = True 

741 cylindrical_membrane_under_pressure_load() 

742 Profile.print_stats() 

743 

744 # Launch gmsh API 

745 gmsh.fltk.run() 

746 

747 

748 

749# inc 001 a 2.000e-02, p 3.021e+04 converged in 3 iterations 

750# inc 002 a 2.000e-02, p 5.870e+04 converged in 2 iterations 

751# inc 003 a 3.000e-02, p 9.887e+04 converged in 2 iterations 

752# inc 004 a 4.500e-02, p 1.541e+05 converged in 3 iterations 

753# inc 005 a 4.500e-02, p 2.038e+05 converged in 2 iterations 

754# inc 006 a 6.750e-02, p 2.705e+05 converged in 3 iterations 

755# inc 007 a 6.750e-02, p 3.276e+05 converged in 3 iterations 

756# inc 008 a 6.750e-02, p 3.755e+05 converged in 3 iterations 

757 

758 

759# ncalls tottime percall cumtime percall filename:lineno(function) 

760# 1 0.000 0.000 0.385 0.385 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:462(solve) 

761# 1 0.001 0.001 0.385 0.385 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/nonlinear_solver.py:13(newton) 

762# 2 0.000 0.000 0.213 0.107 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/linalg/_dsolve/linsolve.py:134(spsolve) 

763# 2 0.210 0.105 0.210 0.105 {built-in method scipy.sparse.linalg._dsolve._superlu.gssv} 

764# 2 0.000 0.000 0.137 0.069 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:457(<lambda>) 

765# 2 0.000 0.000 0.137 0.069 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:437(compute_equilibrium_jac) 

766# 2 0.001 0.000 0.114 0.057 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:288(internalStiffness) 

767# 2 0.000 0.000 0.071 0.035 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:230(d2potentiald2F1) 

768# 24 0.000 0.000 0.044 0.002 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_base.py:788(_matmul_dispatch) 

769# 21 0.000 0.000 0.043 0.002 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_base.py:919(__matmul__) 

770# 8 0.000 0.000 0.042 0.005 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_compressed.py:415(_matmul_sparse) 

771# 29 0.000 0.000 0.031 0.001 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numpy/_core/einsumfunc.py:1244(einsum) 

772# 29 0.031 0.001 0.031 0.001 {built-in method numpy._core._multiarray_umath.c_einsum} 

773# 3 0.000 0.000 0.030 0.010 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:454(<lambda>) 

774# 3 0.000 0.000 0.030 0.010 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:414(compute_equilibrium_res) 

775# 5 0.000 0.000 0.029 0.006 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:180(getdCdF1) 

776# 3 0.000 0.000 0.028 0.009 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:276(internalForce) 

777# 3 0.000 0.000 0.026 0.009 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:200(dpotentialdF1) 

778# 8 0.025 0.003 0.025 0.003 {built-in method scipy.sparse._sparsetools.csr_matmat} 

779# 5 0.011 0.002 0.023 0.005 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/core/smallsize_tensor.py:153(dmetric) 

780# 2 0.010 0.005 0.023 0.012 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:240(kint_terms) 

781# 2 0.000 0.000 0.021 0.010 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/dispatcher.py:344(_compile_for_args) 

782# 2 0.000 0.000 0.020 0.010 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/dispatcher.py:862(compile) 

783# 2 0.000 0.000 0.020 0.010 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/caching.py:713(load_overload) 

784# 47/41 0.000 0.000 0.018 0.000 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_compressed.py:30(__init__) 

785# 2 0.000 0.000 0.018 0.009 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:372(pressureStiffness) 

786# 2 0.000 0.000 0.017 0.008 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/caching.py:724(_load_overload) 

787# 2 0.000 0.000 0.016 0.008 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/caching.py:477(rebuild) 

788# 2 0.000 0.000 0.016 0.008 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/compiler.py:227(_rebuild) 

789# 2 0.004 0.002 0.013 0.007 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/hyperelasticity.py:500(dPKIIdC) 

790# 8 0.012 0.001 0.012 0.001 {built-in method scipy.sparse._sparsetools.csr_matmat_maxnnz} 

791# 2 0.000 0.000 0.012 0.006 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/codegen.py:1168(unserialize_library) 

792# 2 0.000 0.000 0.012 0.006 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/codegen.py:936(_unserialize) 

793# 5 0.004 0.001 0.011 0.002 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/hyperelasticity.py:474(PKII) 

794# 357/355 0.009 0.000 0.011 0.000 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/llvmlite/binding/ffi.py:210(__call__) 

795# 4 0.004 0.001 0.011 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_coo.py:383(_coo_to_compressed) 

796# 2 0.000 0.000 0.011 0.005 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:335(dnormalPerElem) 

797# 2 0.000 0.000 0.010 0.005 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/core/sparse_tools.py:54(regular_block_diag_to_csr) 

798# 7 0.000 0.000 0.009 0.001 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/hyperelasticity.py:430(C33_planestress) 

799# 7 0.009 0.001 0.009 0.001 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/special/_lambertw.py:6(lambertw) 

800# 3 0.001 0.000 0.008 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:207(fint_terms) 

801# 2 0.000 0.000 0.008 0.004 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:186(getd2Cd2F1) 

802# 4 0.007 0.002 0.007 0.002 {built-in method scipy.sparse._sparsetools.coo_tocsr} 

803# 2 0.000 0.000 0.006 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/codegen.py:792(_finalize_final_module) 

804# 2 0.000 0.000 0.006 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/codegen.py:1007(_finalize_specific) 

805# 8 0.000 0.000 0.006 0.001 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/numba/core/codegen.py:1069(wrapper) 

806# 2 0.000 0.000 0.006 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/llvmlite/binding/executionengine.py:94(finalize_object) 

807# 2 0.000 0.000 0.005 0.003 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/core/sparse_tools.py:72(regular_block_diag_to_csr_v2) 

808# 5 0.001 0.000 0.005 0.001 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/pyxfem/solidmechanics/membrane.py:172(getC) 

809# 10 0.000 0.000 0.004 0.000 /home/chevaugeon-n/Documents/RechercheUN/develop/PY_XFEM/.venv/lib/python3.12/site-packages/scipy/sparse/_base.py:451(asformat) 

810 

811 

812# The initial membrane is assumed to be a curved surface 

813# 0 0.00440687981439875 

814# 1 0.0007090203268567412 

815# 2 7.995410736685281e-07 

816# inc initial z pull 1.1 converged 

817# 32.22576608864403 40.067667319006084 

818# 0 3.4310598963475734 

819# 1 0.2935674403395363 

820# 2 0.01827820455432498 

821# 3 0.0002816147637323649 

822# 4 9.036886193951496e-08 

823# inc 001 a 5.000e-02, 3.426e-01, p 8.403e-01 converged in 4 iterations 

824# 32.225766088644036 42.96510692768051 

825# 0 0.36539286272311966 

826# 1 0.029378488740486756 

827# 2 0.00046313210328144475 

828# 3 5.788205975849805e-07 

829# 4 2.2703713941695908e-13 

830# inc 002 a 5.000e-02, 3.347e-01, p 1.071e+00 converged in 4 iterations 

831# 32.22576608864404 34.1846510483814 

832# 0 0.31496387608195736 

833# 1 2.1415147031750412 

834# newton failed after 1 

835# inc 002 p 1.071e+00 not converged after 1 iterations 

836# 32.22576608864404 34.1846510483814 

837# 0 0.19127906246138682 

838# 1 2.221491558000836 

839# newton failed after 1 

840# inc 002 p 1.071e+00 not converged after 1 iterations 

841# 32.22576608864404 34.1846510483814 

842# 0 0.11732610750436605 

843# 1 41.41408859196228 

844# newton failed after 1 

845# inc 002 p 1.071e+00 not converged after 1 iterations 

846# 32.22576608864404 34.1846510483814 

847# 0 0.07214008537315857 

848# 1 0.883440686809872 

849# newton failed after 1 

850# inc 002 p 1.071e+00 not converged after 1 iterations 

851# 32.22576608864404 34.1846510483814 

852# 0 0.044518527641326175 

853# 1 0.08708125448554915 

854# newton failed after 1 

855# inc 002 p 1.071e+00 not converged after 1 iterations 

856# 32.22576608864404 34.1846510483814 

857# 0 0.0275742096485467 

858# 1 0.017107224332357146 

859# 2 8.750321381946716e-05 

860# 3 3.631399800953893e-09 

861# 4 1.6966004494157222e-14 

862# inc 003 a 1.563e-03, 1.138e-01, p 1.091e+00 converged in 4 iterations 

863# 32.22576608864403 2584.6899989463413 

864# 0 4.660028981796859 

865# 1 1.0883871245650745 

866# 2 0.24051205442431087 

867# 3 0.07826732787845271 

868# 4 0.015068006598989521 

869# 5 0.0016632268498018973 

870# 6 1.168588040514311e-05 

871# 7 3.1948361642820114e-10 

872# inc 004 a 1.563e-03, 2.691e-02, p 1.090e+00 converged in 7 iterations 

873# 32.22576608864404 921.3652756624772 

874# 0 0.9095356315019443 

875# 1 0.13097402901504196 

876# 2 0.006575055412094633 

877# 3 8.462309488545935e-05 

878# 4 4.5710282161511506e-07 

879# 5 1.958417172507177e-12