tensor_grid2.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. """Cauchy-Green and Green-Lagrange strain tensors on a 2D grid."""
  2. import numpy as np
  3. import vedo
  4. # Define a simple deformation function
  5. def deform(x, y):
  6. xd = np.array([x + 0.25 * x * x,
  7. y + 0.25 * x * y])
  8. # Add rotation to the deformation.
  9. # note that the rotation is applied to the deformed configuration
  10. # and it has no effect on the deformation gradient tensor C and E
  11. rotation_angle_degrees = 10
  12. rotation_angle_radians = np.radians(rotation_angle_degrees)
  13. cos_angle = np.cos(rotation_angle_radians)
  14. sin_angle = np.sin(rotation_angle_radians)
  15. x_def, y_def = xd
  16. x_rot = x_def * cos_angle - y_def * sin_angle
  17. y_rot = x_def * sin_angle + y_def * cos_angle
  18. return np.array([x_rot, y_rot])
  19. # Compute the deformation gradient tensor F
  20. def deformation_gradient(x, y, ds=0.001):
  21. # Compute the deformation gradient tensor F
  22. # F = (df/dx, df/dy)
  23. fxy = deform(x, y)
  24. fxy_x = deform(x + ds, y)
  25. fxy_y = deform(x, y + ds)
  26. F = np.zeros((2, 2))
  27. F[0, 0] = (fxy_x[0] - fxy[0]) / ds
  28. F[0, 1] = (fxy_y[0] - fxy[0]) / ds
  29. F[1, 0] = (fxy_x[1] - fxy[1]) / ds
  30. F[1, 1] = (fxy_y[1] - fxy[1]) / ds
  31. return F
  32. # Compute the right Cauchy-Green deformation tensor C
  33. def cauchy_green(F):
  34. return F.T @ F
  35. # Right Cauchy-Green tensor (C) is used to define the Green-Lagrange
  36. # strain tensor (E), which is a measure of deformation in the reference
  37. # (undeformed) configuration:
  38. def green_lagrange(C):
  39. return 0.5 * (C - np.eye(2))
  40. # Left Cauchy-Green tensor (B) is used to define the Almansi strain tensor (e),
  41. # which is a measure of deformation in the current (deformed) configuration:
  42. # e = 0.5 * (I - B^-1) (this is less used in practice)
  43. def almansi(F):
  44. B = F @ F.T
  45. return 0.5 * (np.eye(2) - np.linalg.inv(B))
  46. # Compute the principal stretches and directions
  47. def principal_stretches_directions(T):
  48. # T is a symmetric tensor
  49. # eigenvalues are sorted in ascending order
  50. eigenvalues, eigenvectors = np.linalg.eigh(T)
  51. principal_stretches = np.sqrt(np.abs(eigenvalues))*np.sign(eigenvalues)
  52. return principal_stretches, eigenvectors
  53. ######################################################################
  54. # Define the original grid (undeformed configuration)
  55. x, y = np.meshgrid(np.linspace(-1, 1, 8), np.linspace(-1, 1, 8))
  56. grid = vedo.Grid(s=(x[0], y.T[0]))
  57. grid_pts = grid.points
  58. grid_pts_defo = deform(grid_pts[:, 0], grid_pts[:, 1])
  59. grid_defo = grid.clone()
  60. grid_defo.points = grid_pts_defo.T
  61. # Initialize the vedo plotter
  62. plotter = vedo.Plotter()
  63. for i in range(x.shape[0]):
  64. for j in range(y.shape[1]):
  65. pt = x[i, j], y[i, j]
  66. displaced_pt = deform(*pt)
  67. F = deformation_gradient(*pt)
  68. C = cauchy_green(F)
  69. stretches, directions = principal_stretches_directions(C)
  70. ellipsoid_axes = np.diag(stretches) @ directions.T / 8
  71. ellipsoid_C = vedo.Ellipsoid(
  72. axis1=ellipsoid_axes[0],
  73. axis2=ellipsoid_axes[1],
  74. axis3=[0, 0, 0.01],
  75. pos=(*pt, 0),
  76. )
  77. ellipsoid_C.lighting("off").color("blue5")
  78. E = green_lagrange(C)
  79. # E = almansi(F)
  80. stretches, directions = principal_stretches_directions(E)
  81. ellipsoid_axes = np.diag(stretches) @ directions.T / 8
  82. ellipsoid_E = vedo.Ellipsoid(
  83. axis1=ellipsoid_axes[0],
  84. axis2=ellipsoid_axes[1],
  85. axis3=[0, 0, 0.01],
  86. pos=(*pt, 0),
  87. ).z(0.01)
  88. ellipsoid_E.lighting("off").color("purple5")
  89. if stretches[0] < 0 or stretches[1] < 0:
  90. ellipsoid_E.c("red4")
  91. # Plot the deformation gradient tensor, we cannot compute the
  92. # principal stretches and directions of the deformation gradient
  93. # tensor because it is not a symmetric tensor.
  94. # F = deformation_gradient(*pt)
  95. # circle = vedo.Circle(r=0.05).pos(*pt).color("black")
  96. # cpts = circle.points
  97. # cpts_defo = F @ cpts.T[:2]
  98. # circle.points = cpts_defo.T
  99. # Same as:
  100. circle = vedo.Circle(r=0.06).pos(*pt).color("black")
  101. cpts = circle.points
  102. cpts_defo = deform(cpts[:,0], cpts[:,1])
  103. circle.points = cpts_defo.T
  104. plotter += [ellipsoid_C, ellipsoid_E, circle]
  105. pts = np.array([x, y]).T.reshape(-1, 2)
  106. defo_pts = deform(x, y).T.reshape(-1, 2)
  107. plotter += vedo.Arrows2D(pts, defo_pts, s=0.2).color("blue5")
  108. plotter += grid_defo
  109. plotter += __doc__
  110. plotter.show(axes=8, zoom=1.2)
  111. #####################################################################
  112. # Resources:
  113. # https://en.wikipedia.org/wiki/Deformation_gradient
  114. # https://en.wikipedia.org/wiki/Almansi_strain_tensor
  115. # https://en.wikipedia.org/wiki/Principal_stretch
  116. # https://www.continuummechanics.org/deformationstrainintro.html