• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Pablo1990 / pyVertexModel / 11836421490

14 Nov 2024 11:37AM UTC coverage: 0.789%. Remained the same
11836421490

push

github

Pablo1990
bugix

0 of 1010 branches covered (0.0%)

Branch coverage included in aggregate %.

0 of 2 new or added lines in 1 file covered. (0.0%)

1 existing line in 1 file now uncovered.

51 of 5454 relevant lines covered (0.94%)

0.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/pyVertexModel/algorithm/newtonRaphson.py
1
import logging
×
2

3
import numpy as np
×
4
from scipy.optimize import minimize, Bounds
×
5

6
from src.pyVertexModel.Kg.kgContractility import KgContractility
×
7
from src.pyVertexModel.Kg.kgContractility_external import KgContractilityExternal
×
8
from src.pyVertexModel.Kg.kgSubstrate import KgSubstrate
×
9
from src.pyVertexModel.Kg.kgSurfaceCellBasedAdhesion import KgSurfaceCellBasedAdhesion
×
10
from src.pyVertexModel.Kg.kgTriAREnergyBarrier import KgTriAREnergyBarrier
×
11
from src.pyVertexModel.Kg.kgTriEnergyBarrier import KgTriEnergyBarrier
×
12
from src.pyVertexModel.Kg.kgViscosity import KgViscosity
×
13
from src.pyVertexModel.Kg.kgVolume import KgVolume
×
14
from src.pyVertexModel.geometry.face import get_interface
×
15

16
logger = logging.getLogger("pyVertexModel")
×
17

18

19
def solve_remodeling_step(geo_0, geo_n, geo, dofs, c_set):
×
20
    """
21
    This function solves local problem to obtain the position of the newly remodeled vertices with prescribed settings
22
    (Set.***_LP), e.g. Set.lambda_LP.
23
    :param geo_0:
24
    :param geo_n:
25
    :param geo:
26
    :param dofs:
27
    :param c_set:
28
    :return:
29
    """
30

31
    logger.info('=====>> Solving Local Problem....')
×
32
    geo.remodelling = True
×
33
    original_nu = c_set.nu
×
34
    original_nu0 = c_set.nu0
×
35
    original_lambdaB = c_set.lambdaB
×
36
    original_lambdaR = c_set.lambdaR
×
37

38
    c_set.MaxIter = c_set.MaxIter0 * 3
×
39
    c_set.lambdaB = original_lambdaB * 2
×
40
    c_set.lambdaR = original_lambdaR * 0.0001
×
41

42
    for n_id, nu_factor in enumerate(np.linspace(10, 1, 3)):
×
43
        c_set.nu0 = original_nu0 * nu_factor
×
44
        c_set.nu = original_nu * nu_factor
×
45
        g, k, _, _ = KgGlobal(geo_0, geo_n, geo, c_set)
×
46

47
        dy = np.zeros(((geo.numY + geo.numF + geo.nCells) * 3, 1), dtype=np.float64)
×
48
        dyr = np.linalg.norm(dy[dofs.remodel, 0])
×
49
        gr = np.linalg.norm(g[dofs.remodel])
×
50
        logger.info(
×
51
            f'Local Problem ->Iter: 0, ||gr||= {gr:.3e} ||dyr||= {dyr:.3e}  nu/nu0={c_set.nu / c_set.nu0:.3e}  '
52
            f'dt/dt0={c_set.dt / c_set.dt0:.3g}')
53

54
        geo, g, k, energy, c_set, gr, dyr, dy = newton_raphson(geo_0, geo_n, geo, dofs, c_set, k, g, -1, -1)
×
55

56
        if gr > c_set.tol or dyr > c_set.tol or np.any(np.isnan(g[dofs.Free])) or np.any(np.isnan(dy[dofs.Free])):
×
57
            logger.info(f'Local Problem did not converge after {c_set.iter} iterations.')
×
58
            has_converged = False
×
59
            break
×
60
        else:
61
            logger.info(f'=====>> Local Problem converged in {c_set.iter} iterations.')
×
62
            has_converged = True
×
63

64
    geo.remodelling = False
×
65

66
    c_set.MaxIter = c_set.MaxIter0
×
67
    c_set.nu = original_nu
×
68
    c_set.nu0 = original_nu0
×
69
    c_set.lambdaB = original_lambdaB
×
70
    c_set.lambdaR = original_lambdaR
×
71

72
    return geo, c_set, has_converged
×
73

74

75
def newton_raphson(Geo_0, Geo_n, Geo, Dofs, Set, K, g, numStep, t, implicit_method=True):
×
76
    """
77
    Newton-Raphson method
78
    :param Geo_0:
79
    :param Geo_n:
80
    :param Geo:
81
    :param Dofs:
82
    :param Set:
83
    :param K:
84
    :param g:
85
    :param numStep:
86
    :param t:
87
    :return:
88
    """
89
    if Geo.remodelling:
×
90
        dof = Dofs.remodel
×
91
    else:
92
        dof = Dofs.Free
×
93

94
    dy = np.zeros(((Geo.numY + Geo.numF + Geo.nCells) * 3, 1), dtype=np.float64)
×
95
    dyr = np.linalg.norm(dy[dof, 0])
×
96
    gr = np.linalg.norm(g[dof])
×
97
    gr0 = gr
×
98

99
    logger.info(f"Step: {numStep}, Iter: 0 ||gr||= {gr} ||dyr||= {dyr} dt/dt0={Set.dt / Set.dt0:.3g}")
×
100

101
    Set.iter = 1
×
102
    auxgr = np.zeros(3, dtype=np.float64)
×
103
    auxgr[0] = gr
×
104
    ig = 0
×
105
    Energy = 0
×
106

107
    if implicit_method is True:
×
108
        while (gr > Set.tol or dyr > Set.tol) and Set.iter < Set.MaxIter:
×
109
            Energy, K, dyr, g, gr, ig, auxgr, dy = newton_raphson_iteration(Dofs, Geo, Geo_0, Geo_n, K, Set, auxgr, dof,
×
110
                                                                            dy, g, gr0, ig, numStep, t)
111
    else:
112
        Geo, dy, gr = newton_raphson_iteration_explicit(Geo, Set, dof, dy, g)
×
113
        dyr = 0
×
114

115
    return Geo, g, K, Energy, Set, gr, dyr, dy
×
116

117

118
def newton_raphson_iteration(Dofs, Geo, Geo_0, Geo_n, K, Set, aux_gr, dof, dy, g, gr0, ig, numStep, t):
×
119
    """
120
    Perform a single iteration of the Newton-Raphson method for solving a system of nonlinear equations.
121

122
    Parameters:
123
    Dofs (object): Object containing information about the degrees of freedom in the system.
124
    Geo (object): Object containing the current geometry of the system.
125
    Geo_0 (object): Object containing the initial geometry of the system.
126
    Geo_n (object): Object containing the geometry of the system at the previous time step.
127
    K (ndarray): The Jacobian matrix of the system.
128
    Set (object): Object containing various settings for the simulation.
129
    aux_gr (ndarray): Array containing the norms of the gradient at the previous three steps.
130
    dof (ndarray): Array containing the indices of the free degrees of freedom in the system.
131
    dy (ndarray): Array containing the current guess for the solution of the system.
132
    g (ndarray): The gradient of the system.
133
    gr0 (float): The norm of the gradient at the start of the current time step.
134
    ig (int): Index used to cycle through the elements of aux_gr.
135
    numStep (int): The current time step number.
136
    t (float): The current time.
137

138
    Returns:
139
    energy_total (float): The total energy of the system after the current iteration.
140
    K (ndarray): The updated Jacobian matrix of the system.
141
    dyr (float): The norm of the change in the solution guess during the current iteration.
142
    g (ndarray): The updated gradient of the system.
143
    gr (float): The norm of the updated gradient of the system.
144
    ig (int): The updated index used to cycle through the elements of aux_gr.
145
    aux_gr (ndarray): The updated array containing the norms of the gradient at the previous three steps.
146
    dy (ndarray): The updated guess for the solution of the system.
147
    """
148
    dy[dof, 0] = ml_divide(K, dof, g)
×
149

150
    alpha = line_search(Geo_0, Geo_n, Geo, dof, Set, g, dy)
×
151
    dy_reshaped = np.reshape(dy * alpha, (Geo.numF + Geo.numY + Geo.nCells, 3))
×
152
    Geo.update_vertices(dy_reshaped)
×
153
    Geo.update_measures()
×
154
    g, K, energy_total, _ = KgGlobal(Geo_0, Geo_n, Geo, Set)
×
155

156
    dyr = np.linalg.norm(dy[dof, 0])
×
157
    gr = np.linalg.norm(g[dof])
×
158
    logger.info(f"Step: {numStep}, Iter: {Set.iter}, Time: {t} ||gr||= {gr:.3e} ||dyr||= {dyr:.3e} alpha= {alpha:.3e}"
×
159
                f" nu/nu0={Set.nu / Set.nu0:.3g}")
160
    Set.iter += 1
×
161

162
    # Checking if the three previous steps are very similar. Thus, the solution is not converging
163
    aux_gr[ig] = gr
×
164
    ig = 0 if ig == 2 else ig + 1
×
165
    if (
×
166
            all(aux_gr[i] != 0 for i in range(3)) and
167
            abs(aux_gr[0] - aux_gr[1]) / aux_gr[0] < 1e-3 and
168
            abs(aux_gr[0] - aux_gr[2]) / aux_gr[0] < 1e-3 and
169
            abs(aux_gr[2] - aux_gr[1]) / aux_gr[2] < 1e-3
170
    ) or (
171
            gr0 != 0 and abs((gr0 - gr) / gr0) > 1e3
172
    ):
173
        Set.iter = Set.MaxIter
×
174

175
    return energy_total, K, dyr, g, gr, ig, aux_gr, dy
×
176

177

178
def newton_raphson_iteration_explicit(Geo, Set, dof, dy, g):
×
179
    """
180
    Explicit update method
181
    :param Geo_0:
182
    :param Geo_n:
183
    :param Geo:
184
    :param Dofs:
185
    :param Set:
186
    :return:
187
    """
188
    # Bottom nodes
189
    all_bottom_nodes = []
×
190
    for cell in Geo.Cells:
×
191
        if cell.AliveStatus is not None:
×
192
            all_bottom_nodes.extend(cell.globalIds[np.any(np.isin(cell.T, Geo.XgBottom), axis=1)])
×
193
            for face in cell.Faces:
×
194
                if get_interface(face.InterfaceType) == get_interface('Bottom'):
×
195
                    all_bottom_nodes.append(face.globalIds)
×
196

197
    all_bottom_nodes_pos = all_bottom_nodes * 3
×
NEW
198
    all_bottom_nodes_pos.extend(3 * [i + 1 for i in all_bottom_nodes])
×
NEW
199
    all_bottom_nodes_pos.extend(3 * [i + 2 for i in all_bottom_nodes])
×
UNCOV
200
    dof_bottom = np.unique(all_bottom_nodes_pos)
×
201

202
    # Update the bottom nodes with the same displacement as the corresponding real nodes
203
    dy[dof, 0] = -Set.dt / Set.nu * g[dof]
×
204
    dy[dof_bottom, 0] = -Set.dt / Set.nu_bottom * g[dof_bottom]
×
205

206
    # Update border ghost nodes with the same displacement as the corresponding real nodes
207
    dy = map_vertices_periodic_boundaries(Geo, dy)
×
208

209
    dy_reshaped = np.reshape(dy, (Geo.numF + Geo.numY + Geo.nCells, 3))
×
210
    Geo.update_vertices(dy_reshaped)
×
211
    Geo.update_measures()
×
212

213
    g, energies = gGlobal(Geo, Geo, Geo, Set, Set.implicit_method)
×
214
    gr = np.linalg.norm(g[dof])
×
215
    Set.iter = Set.MaxIter
×
216

217
    return Geo, dy, gr
×
218

219

220
def map_vertices_periodic_boundaries(Geo, dy):
×
221
    """
222
    Update the border ghost nodes with the same displacement as the corresponding real nodes
223
    :param Geo:
224
    :param dy:
225
    :return:
226
    """
227
    for numCell in Geo.BorderCells:
×
228
        cell = Geo.Cells[numCell]
×
229

230
        tets_to_check = cell.T[np.any(np.isin(cell.T, Geo.BorderGhostNodes), axis=1)]
×
231
        global_ids_to_update = cell.globalIds[np.any(np.isin(cell.T, Geo.BorderGhostNodes), axis=1)]
×
232

233
        for i, tet in enumerate(tets_to_check):
×
234
            for j, node in enumerate(tet):
×
235
                if node in Geo.BorderGhostNodes:
×
236
                    global_id = global_ids_to_update[i]
×
237

238
                    # Check if the object has the attribute opposite_cell
239
                    if not hasattr(Geo.Cells[int(node)], 'opposite_cell'):
×
240
                        return dy
×
241

242
                    # Iterate over each element in tet and access the opposite_cell attribute
243
                    opposite_cell = Geo.Cells[Geo.Cells[int(node)].opposite_cell]
×
244
                    opposite_cells = np.unique(
×
245
                        [Geo.Cells[int(t)].opposite_cell for t in tet if Geo.Cells[int(t)].opposite_cell is not None])
246

247
                    # Get the most similar tetrahedron in the opposite cell
248
                    if len(opposite_cells) < 3:
×
249
                        possible_tets = opposite_cell.T[
×
250
                            [np.sum(np.isin(opposite_cells, tet)) == len(opposite_cells) for tet in opposite_cell.T]]
251
                    else:
252
                        possible_tets = opposite_cell.T[
×
253
                            [np.sum(np.isin(opposite_cells, tet)) >= 2 for tet in opposite_cell.T]]
254

255
                    if possible_tets.shape[0] == 0:
×
256
                        possible_tets = opposite_cell.T[
×
257
                            [np.sum(np.isin(opposite_cells, tet)) == 1 for tet in opposite_cell.T]]
258

259
                    if possible_tets.shape[0] > 0:
×
260
                        # Filter the possible tets to get its correct location (XgTop, XgBottom or XgLateral)
261
                        if possible_tets.shape[0] > 1:
×
262
                            old_possible_tets = possible_tets
×
263
                            scutoid = False
×
264
                            if np.isin(tet, Geo.XgTop).any():
×
265
                                possible_tets = possible_tets[np.isin(possible_tets, Geo.XgTop).any(axis=1)]
×
266
                            elif np.isin(tet, Geo.XgBottom).any():
×
267
                                possible_tets = possible_tets[np.isin(possible_tets, Geo.XgBottom).any(axis=1)]
×
268
                            else:
269
                                # Get the tets that are not in the top or bottom
270
                                possible_tets = possible_tets[
×
271
                                    np.logical_not(np.isin(possible_tets, Geo.XgTop).any(axis=1))]
272
                                scutoid = True
×
273

274
                            if possible_tets.shape[0] == 0:
×
275
                                possible_tets = old_possible_tets
×
276

277
                        # Compare tets with the number of ghost nodes
278
                        if possible_tets.shape[0] > 1 and not scutoid:
×
279
                            old_possible_tets = possible_tets
×
280
                            # Get the tets that have the same number of ghost nodes as the original tet
281
                            possible_tets = possible_tets[
×
282
                                np.sum(np.isin(tet[tet != node], Geo.XgID)) == np.sum(np.isin(possible_tets, Geo.XgID),
283
                                                                                      axis=1)]
284

285
                            if possible_tets.shape[0] == 0:
×
286
                                possible_tets = old_possible_tets
×
287

288
                        if possible_tets.shape[0] > 1 and not scutoid:
×
289
                            old_possible_tets = possible_tets
×
290
                            # Get the tet that has the same number of ghost nodes as the original tet
291
                            possible_tets = possible_tets[np.sum(np.isin(tet[tet != node], Geo.XgID)) == np.sum(
×
292
                                np.isin(possible_tets, np.concatenate([Geo.XgTop, Geo.XgBottom])), axis=1)]
293

294
                            if possible_tets.shape[0] == 0:
×
295
                                possible_tets = old_possible_tets
×
296
                    else:
297
                        print('Error in Tet ID: ', tet)
×
298

299
                    if possible_tets.shape[0] == 1:
×
300
                        opposite_global_id = opposite_cell.globalIds[
×
301
                            np.where(np.all(opposite_cell.T == possible_tets[0], axis=1))[0][0]]
302
                        dy[global_id * 3:global_id * 3 + 3, 0] = dy[opposite_global_id * 3:opposite_global_id * 3 + 3,
×
303
                                                                 0]
304
                    elif possible_tets.shape[0] > 1:
×
305
                        # TODO: what happens if it is an scutoid
306
                        if scutoid:
×
307
                            avg_dy = np.zeros(3)
×
308
                            # Average of the dys
309
                            for c_tet in possible_tets:
×
310
                                opposite_global_id = opposite_cell.globalIds[
×
311
                                    np.where(np.all(opposite_cell.T == c_tet, axis=1))[0][0]]
312
                                avg_dy += dy[opposite_global_id * 3:opposite_global_id * 3 + 3, 0]
×
313
                            avg_dy /= possible_tets.shape[0]
×
314

315
                            # NOW IT IS 0, WITH THE AVERAGE IT THERE WERE ERRORS
316
                            dy[global_id * 3:global_id * 3 + 3, 0] = 0
×
317
                        else:
318
                            opposite_global_id = opposite_cell.globalIds[
×
319
                                np.where(np.all(opposite_cell.T == possible_tets[0], axis=1))[0][0]]
320
                            dy[global_id * 3:global_id * 3 + 3, 0] = dy[
×
321
                                                                     opposite_global_id * 3:opposite_global_id * 3 + 3,
322
                                                                     0]
323
    return dy
×
324

325

326
def ml_divide(K, dof, g):
×
327
    """
328
    Solve the linear system K * dy = g
329
    :param K:
330
    :param dof:
331
    :param g:
332
    :return:
333
    """
334
    # dy[dof] = kg_functions.mldivide_np(K[np.ix_(dof, dof)], g[dof])
335
    return -np.linalg.solve(K[np.ix_(dof, dof)], g[dof])
×
336

337

338
def line_search(Geo_0, Geo_n, geo, dof, Set, gc, dy):
×
339
    """
340
    Line search to find the best alpha to minimize the energy
341
    :param Geo_0:   Initial geometry.
342
    :param Geo_n:   Geometry at the previous time step
343
    :param geo:     Current geometry
344
    :param Dofs:    Dofs object
345
    :param Set:     Set object
346
    :param gc:      Gradient at the current step
347
    :param dy:      Displacement at the current step
348
    :return:        alpha
349
    """
350
    dy_reshaped = np.reshape(dy, (geo.numF + geo.numY + geo.nCells, 3))
×
351

352
    # Create a copy of geo to not change the original one
353
    Geo_copy = geo.copy()
×
354

355
    Geo_copy.update_vertices(dy_reshaped)
×
356
    Geo_copy.update_measures()
×
357

358
    g, _ = gGlobal(Geo_0, Geo_n, Geo_copy, Set)
×
359

360
    gr0 = np.linalg.norm(gc[dof])
×
361
    gr = np.linalg.norm(g[dof])
×
362

363
    if gr0 < gr:
×
364
        R0 = np.dot(dy[dof, 0], gc[dof])
×
365
        R1 = np.dot(dy[dof, 0], g[dof])
×
366

367
        R = R0 / R1
×
368
        alpha1 = (R / 2) + np.sqrt((R / 2) ** 2 - R)
×
369
        alpha2 = (R / 2) - np.sqrt((R / 2) ** 2 - R)
×
370

371
        if np.isreal(alpha1) and 2 > alpha1 > 1e-3:
×
372
            alpha = alpha1
×
373
        elif np.isreal(alpha2) and 2 > alpha2 > 1e-3:
×
374
            alpha = alpha2
×
375
        else:
376
            alpha = 0.1
×
377
    else:
378
        alpha = 1
×
379

380
    return alpha
×
381

382

383
def KgGlobal(Geo_0, Geo_n, Geo, Set, implicit_method=True):
×
384
    """
385
    Compute the global Jacobian matrix and the global gradient
386
    :param Geo_0:
387
    :param Geo_n:
388
    :param Geo:
389
    :param Set:
390
    :param implicit_method:
391
    :return:
392
    """
393

394
    # Surface Energy
395
    kg_SA = KgSurfaceCellBasedAdhesion(Geo)
×
396
    kg_SA.compute_work(Geo, Set)
×
397
    g = kg_SA.g
×
398
    K = kg_SA.K
×
399
    energy_total = kg_SA.energy
×
400
    energies = {"Surface": kg_SA.energy}
×
401

402
    # Volume Energy
403
    kg_Vol = KgVolume(Geo)
×
404
    kg_Vol.compute_work(Geo, Set)
×
405
    K += kg_Vol.K
×
406
    g += kg_Vol.g
×
407
    energy_total += kg_Vol.energy
×
408
    energies["Volume"] = kg_Vol.energy
×
409

410
    # # TODO: Plane Elasticity
411
    # if Set.InPlaneElasticity:
412
    #     gt, Kt, EBulk = KgBulk(geo_0, Geo, Set)
413
    #     K += Kt
414
    #     g += gt
415
    #     E += EBulk
416
    #     Energies["Bulk"] = EBulk
417

418
    # Bending Energy
419
    # TODO
420

421
    # Propulsion Forces
422
    # TODO
423

424
    # Contractility
425
    if Set.Contractility:
×
426
        kg_lt = KgContractility(Geo)
×
427
        kg_lt.compute_work(Geo, Set)
×
428
        g += kg_lt.g
×
429
        K += kg_lt.K
×
430
        energy_total += kg_lt.energy
×
431
        energies["Contractility"] = kg_lt.energy
×
432

433
    if Set.Contractility_external:
×
434
        kg_ext = KgContractilityExternal(Geo)
×
435
        kg_ext.compute_work(Geo, Set)
×
436
        g += kg_ext.g
×
437
        K += kg_ext.K
×
438
        energy_total += kg_ext.energy
×
439
        energies["Contractility_external"] = kg_ext.energy
×
440

441
    # Substrate
442
    if Set.Substrate == 2:
×
443
        kg_subs = KgSubstrate(Geo)
×
444
        kg_subs.compute_work(Geo, Set)
×
445
        g += kg_subs.g
×
446
        K += kg_subs.K
×
447
        energy_total += kg_subs.energy
×
448
        energies["Substrate"] = kg_subs.energy
×
449

450
    # Triangle Energy Barrier
451
    if Set.EnergyBarrierA:
×
452
        kg_Tri = KgTriEnergyBarrier(Geo)
×
453
        kg_Tri.compute_work(Geo, Set)
×
454
        g += kg_Tri.g
×
455
        K += kg_Tri.K
×
456
        energy_total += kg_Tri.energy
×
457
        energies["TriEnergyBarrier"] = kg_Tri.energy
×
458

459
    # Triangle Energy Barrier Aspect Ratio
460
    if Set.EnergyBarrierAR:
×
461
        kg_TriAR = KgTriAREnergyBarrier(Geo)
×
462
        kg_TriAR.compute_work(Geo, Set)
×
463
        g += kg_TriAR.g
×
464
        K += kg_TriAR.K
×
465
        energy_total += kg_TriAR.energy
×
466
        energies["TriEnergyBarrierAR"] = kg_TriAR.energy
×
467

468
    if implicit_method is True:
×
469
        # Viscous Energy
470
        kg_Viscosity = KgViscosity(Geo)
×
471
        kg_Viscosity.compute_work(Geo, Set, Geo_n)
×
472
        g += kg_Viscosity.g
×
473
        K += kg_Viscosity.K
×
474
        energy_total = kg_Viscosity.energy
×
475
        energies["Viscosity"] = kg_Viscosity.energy
×
476

477
    return g, K, energy_total, energies
×
478

479

480
def gGlobal(Geo_0, Geo_n, Geo, Set, implicit_method=True):
×
481
    """
482
    Compute the global gradient
483
    :param Geo_0:
484
    :param Geo_n:
485
    :param Geo:
486
    :param Set:
487
    :param implicit_method:
488
    :return:
489
    """
490
    g = np.zeros((Geo.numY + Geo.numF + Geo.nCells) * 3, dtype=np.float64)
×
491
    energies = {}
×
492

493
    # Surface Energy
494
    if Set.lambdaS1 > 0:
×
495
        kg_SA = KgSurfaceCellBasedAdhesion(Geo)
×
496
        kg_SA.compute_work(Geo, Set, None, False)
×
497
        g += kg_SA.g
×
498
        energies["Surface"] = kg_SA.energy
×
499

500
    # Volume Energy
501
    if Set.lambdaV > 0:
×
502
        kg_Vol = KgVolume(Geo)
×
503
        kg_Vol.compute_work(Geo, Set, None, False)
×
504
        g += kg_Vol.g[:]
×
505
        energies["Volume"] = kg_Vol.energy
×
506

507
    if implicit_method is True:
×
508
        # Viscous Energy
509
        kg_Viscosity = KgViscosity(Geo)
×
510
        kg_Viscosity.compute_work(Geo, Set, Geo_n, False)
×
511
        g += kg_Viscosity.g
×
512
        energies["Viscosity"] = kg_Viscosity.energy
×
513

514
    # # TODO: Plane Elasticity
515
    # if Set.InPlaneElasticity:
516
    #     gt, Kt, EBulk = KgBulk(geo_0, Geo, Set)
517
    #     K += Kt
518
    #     g += gt
519
    #     E += EBulk
520
    #     Energies["Bulk"] = EBulk
521

522
    # Bending Energy
523
    # TODO
524

525
    # Triangle Energy Barrier
526
    if Set.EnergyBarrierA:
×
527
        kg_Tri = KgTriEnergyBarrier(Geo)
×
528
        kg_Tri.compute_work(Geo, Set, None, False)
×
529
        g += kg_Tri.g
×
530
        energies["TriEnergyBarrier"] = kg_Tri.energy
×
531

532
    # Triangle Energy Barrier Aspect Ratio
533
    if Set.EnergyBarrierAR:
×
534
        kg_TriAR = KgTriAREnergyBarrier(Geo)
×
535
        kg_TriAR.compute_work(Geo, Set, None, False)
×
536
        g += kg_TriAR.g
×
537
        energies["TriEnergyBarrierAR"] = kg_TriAR.energy
×
538

539
    # Propulsion Forces
540
    # TODO
541

542
    # Contractility
543
    if Set.Contractility:
×
544
        kg_lt = KgContractility(Geo)
×
545
        kg_lt.compute_work(Geo, Set, None, False)
×
546
        g += kg_lt.g
×
547
        energies["Contractility"] = kg_lt.energy
×
548

549
    # Contractility as external force
550
    if Set.Contractility_external:
×
551
        kg_ext = KgContractilityExternal(Geo)
×
552
        kg_ext.compute_work(Geo, Set, None, False)
×
553
        g += kg_ext.g
×
554
        energies["Contractility_external"] = kg_ext.energy
×
555

556
    # Substrate
557
    if Set.Substrate == 2:
×
558
        kg_subs = KgSubstrate(Geo)
×
559
        kg_subs.compute_work(Geo, Set, None, False)
×
560
        g += kg_subs.g
×
561
        energies["Substrate"] = kg_subs.energy
×
562

563
    return g, energies
×
564

565

566
def remeshing_cells(Geo_0, Geo_n, Geo, Dofs, Set, cells_to_change, ghost_node):
×
567
    """
568
    Newton-Raphson method
569
    :param Geo_0:
570
    :param Geo_n:
571
    :param Geo:
572
    :param Dofs:
573
    :param Set:s
574
    :return:
575
    """
576

577
    def objective_function(dy, dof):
×
578
        # Reshape dy to match the geometry of the system
579
        dy_reshaped = np.reshape(dy, (Geo.numF + Geo.numY + Geo.nCells, 3))
×
580

581
        # Create a copy of Geo to not change the original one
582
        Geo_copy = Geo.copy()
×
583

584
        # Update the vertices in the copy
585
        Geo_copy.update_vertices(dy_reshaped)
×
586

587
        # Update the measures in the copy
588
        Geo_copy.update_measures()
×
589

590
        # Compute the energies
591
        g, _, energy_total, _ = KgGlobal(Geo_0, Geo_n, Geo_copy, Set)
×
592

593
        logger.info('Energy: ' + str(energy_total))
×
594
        gr = np.linalg.norm(g[dof])
×
595
        logger.info('||gr||= ' + str(gr))
×
596

597
        # Return the total energy
598
        return gr
×
599

600
    def gradient_function(dy, dof):
×
601
        # Reshape dy to match the geometry of the system
602
        dy_reshaped = np.reshape(dy, (Geo.numF + Geo.numY + Geo.nCells, 3))
×
603

604
        # Create a copy of Geo to not change the original one
605
        Geo_copy = Geo.copy()
×
606

607
        # Update the vertices in the copy
608
        Geo_copy.update_vertices(dy_reshaped)
×
609

610
        # Update the measures in the copy
611
        Geo_copy.update_measures()
×
612

613
        # Compute the energies
614
        g, _, _, _ = KgGlobal(Geo_0, Geo_n, Geo_copy, Set)
×
615

616
        g[dof == False] = 0
×
617

618
        # Return the gradient
619
        return g.flatten()
×
620

621
    Geo.remeshing = True
×
622

623
    if np.isin(ghost_node, Geo.XgBottom).any():
×
624
        interface_type = 2
×
625
    elif np.isin(ghost_node, Geo.XgTop).any():
×
626
        interface_type = 0
×
627

628
    Dofs.get_remeshing_dofs(Geo, cells_to_change, interface_type)
×
629

630
    # Set the degrees of freedom
631
    dof = Dofs.remeshing
×
632

633
    dy_initial = np.zeros((Geo.numY + Geo.numF + Geo.nCells) * 3, dtype=np.float64)
×
634
    g, K, _, _ = KgGlobal(Geo_0, Geo_n, Geo, Set)
×
635
    dy_initial[dof] = ml_divide(K, dof, g)
×
636

637
    lower_bounds = np.zeros_like(dy_initial)
×
638
    upper_bounds = 10e-1 * np.ones_like(dy_initial)
×
639
    bounds = Bounds(lower_bounds, upper_bounds)
×
640

641
    result = minimize(
×
642
        fun=objective_function,  # Defined as before
643
        x0=dy_initial,
644
        args=(dof,),
645
        method='L-BFGS-B',  # Newton-CG
646
        jac=gradient_function,
647
        bounds=bounds,
648
        options={'disp': True}
649
    )
650

651
    dy_reshaped = np.reshape(result.x, (Geo.numF + Geo.numY + Geo.nCells, 3))
×
652
    return dy_reshaped
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc