Feitan21 | Je cherche à modéliser des déformations d'un système avec un certain nombres de noeuds reliés entre eux par des ressorts.
J'ai un résultat un peu inattendu, lorsque mon noeud 0 est en position 0., 0., 0. et mon noeud 1 en position 1., 1., 1. tout fonctionne, et l'effet du ressort est bien cohérent. Le noeud 0 est toujours de masse infinie et le noeud 1 de masse 1 et j'applique une force similaire à la gravité en Y.
Le déplacement du noeud 1 en Y :
Par contre quand j'inverse la position des deux noeuds le ressort ne fait plus effet et mon noeud diverge vers l'infini.
Déplacement du noeud 1 en Y :
Je n'arrive pas à comprendre pourquoi j'obtiens ce résultat, je ne sais pas si c'est une instabilité numérique due au solver, ou si mon calcul de la force du ressort est erronée. J'ai pourtant essayé d'implementer une version standard avec des boucles imbriquées et une version vectorisée. Les deux donnent les mêmes résultats.
Voici mon code :
Code :
- import numpy as np
- from scipy.spatial.distance import cdist
- import matplotlib.pyplot as plt
- import scipy.integrate
- X = np.array([[0., 0., 0.], # 0
- [1., 1., 1.]]) # 1
- edges = np.array([[0, 1]])
- W = np.array([[0, 1],
- [1, 0]])
- d = cdist(X, X, "euclidean" )
- mass = 1 * np.ones(X.shape[0])
- mass[0] = np.inf
- mass[1] = 1
- Force = np.zeros((X.shape[0], 3))
- Force[1, 1] = 9.81
- N = X.shape[0]
- dt = 0.1
- T = int(1e4)
- k = 5
- def compute_F_spring_vec(X, W, di):
- d_inv = np.reciprocal(cdist(X, X, "euclidean" ))
- d_inv[np.arange(np.shape(d_inv)[0]),np.arange(np.shape(d_inv)[0])] = 0
- op1 = np.dot(W, X)
- op2 = X * np.repeat(np.sum(W, axis=1), 3).reshape(X.shape)
- op3 = np.dot(W * di * d_inv, X)
- op4 = X * np.repeat(np.sum(W * di * d_inv, axis=1), 3).reshape(X.shape)
- F_spring = - k * (-op1 + op2 + op3 - op4)
- return F_spring
- def compute_F_spring(X, W, d):
- F_spring = []
- for i in range(X.shape[0]):
- F_i = np.zeros(3)
- for j in range(X.shape[0]):
- if W[i,j]:
- F_i += -k * (np.linalg.norm(X[i, :] - X[j, :]) - d[i, j]) * (X[i, :] - X[j, :])/np.linalg.norm(X[i, :] - X[j, :])
- F_spring.append(F_i)
- return F_spring
- def fun(t, X):
- X = X.reshape((int(X.shape[0]/3), 3))
- F_spring = compute_F_spring_vec(X, W, d)
- F = F_spring + Force
- a = F / mass[:, np.newaxis]
- X = X + a*t
- return X.ravel()
- solver = scipy.integrate.RK45(fun, 0, X.ravel(), t_bound=100, rtol=0.001, vectorized=True)
- Ylast = np.inf
- X1 = []
- while solver.status == 'running' and solver.t < 10:
- error = solver.step()
- X1.append([solver.y[4], solver.t, solver.y[3], solver.y[5]])
- if (np.abs(X1[-1][0] - Ylast))/np.abs(Ylast) < 1e-6:
- break
- else:
- Ylast = X1[-1][0]
|
Quelques précisions : X contient les positions x,y,z de tous les nodes. Edges la liaison entre les nodes, ce qui me permet de déduire une matrice de connectivité W (1 les noeuds sont connectés, 0 ils ne le sont pas).
Et d la distance euclidienne entre chaque paire de noeuds
Pouvez-vous m'aider ? Merci Message édité par Feitan21 le 09-07-2019 à 17:09:07
|