warp-lang 1.4.1__py3-none-manylinux2014_aarch64.whl → 1.5.0__py3-none-manylinux2014_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of warp-lang might be problematic. Click here for more details.

Files changed (164) hide show
  1. warp/__init__.py +4 -0
  2. warp/autograd.py +43 -8
  3. warp/bin/warp-clang.so +0 -0
  4. warp/bin/warp.so +0 -0
  5. warp/build.py +21 -2
  6. warp/build_dll.py +23 -6
  7. warp/builtins.py +1920 -111
  8. warp/codegen.py +186 -62
  9. warp/config.py +2 -2
  10. warp/context.py +322 -73
  11. warp/examples/assets/pixel.jpg +0 -0
  12. warp/examples/benchmarks/benchmark_cloth_paddle.py +86 -0
  13. warp/examples/benchmarks/benchmark_gemm.py +121 -0
  14. warp/examples/benchmarks/benchmark_interop_paddle.py +158 -0
  15. warp/examples/benchmarks/benchmark_tile.py +179 -0
  16. warp/examples/core/example_dem.py +2 -1
  17. warp/examples/core/example_mesh_intersect.py +3 -3
  18. warp/examples/fem/example_adaptive_grid.py +37 -10
  19. warp/examples/fem/example_apic_fluid.py +3 -2
  20. warp/examples/fem/example_convection_diffusion_dg.py +4 -5
  21. warp/examples/fem/example_deformed_geometry.py +1 -1
  22. warp/examples/fem/example_diffusion_3d.py +47 -4
  23. warp/examples/fem/example_distortion_energy.py +220 -0
  24. warp/examples/fem/example_magnetostatics.py +127 -85
  25. warp/examples/fem/example_nonconforming_contact.py +5 -5
  26. warp/examples/fem/example_stokes.py +3 -1
  27. warp/examples/fem/example_streamlines.py +12 -19
  28. warp/examples/fem/utils.py +38 -15
  29. warp/examples/optim/example_walker.py +2 -2
  30. warp/examples/sim/example_cloth.py +2 -25
  31. warp/examples/sim/example_jacobian_ik.py +6 -2
  32. warp/examples/sim/example_quadruped.py +2 -1
  33. warp/examples/tile/example_tile_convolution.py +58 -0
  34. warp/examples/tile/example_tile_fft.py +47 -0
  35. warp/examples/tile/example_tile_filtering.py +105 -0
  36. warp/examples/tile/example_tile_matmul.py +79 -0
  37. warp/examples/tile/example_tile_mlp.py +375 -0
  38. warp/fem/__init__.py +8 -0
  39. warp/fem/cache.py +16 -12
  40. warp/fem/dirichlet.py +1 -1
  41. warp/fem/domain.py +44 -1
  42. warp/fem/field/__init__.py +1 -2
  43. warp/fem/field/field.py +31 -19
  44. warp/fem/field/nodal_field.py +101 -49
  45. warp/fem/field/virtual.py +794 -0
  46. warp/fem/geometry/__init__.py +2 -2
  47. warp/fem/geometry/deformed_geometry.py +3 -105
  48. warp/fem/geometry/element.py +13 -0
  49. warp/fem/geometry/geometry.py +165 -5
  50. warp/fem/geometry/grid_2d.py +3 -6
  51. warp/fem/geometry/grid_3d.py +31 -28
  52. warp/fem/geometry/hexmesh.py +3 -46
  53. warp/fem/geometry/nanogrid.py +3 -2
  54. warp/fem/geometry/{quadmesh_2d.py → quadmesh.py} +280 -159
  55. warp/fem/geometry/tetmesh.py +2 -43
  56. warp/fem/geometry/{trimesh_2d.py → trimesh.py} +354 -186
  57. warp/fem/integrate.py +683 -261
  58. warp/fem/linalg.py +404 -0
  59. warp/fem/operator.py +101 -18
  60. warp/fem/polynomial.py +5 -5
  61. warp/fem/quadrature/quadrature.py +45 -21
  62. warp/fem/space/__init__.py +45 -11
  63. warp/fem/space/basis_function_space.py +451 -0
  64. warp/fem/space/basis_space.py +58 -11
  65. warp/fem/space/function_space.py +146 -5
  66. warp/fem/space/grid_2d_function_space.py +80 -66
  67. warp/fem/space/grid_3d_function_space.py +113 -68
  68. warp/fem/space/hexmesh_function_space.py +96 -108
  69. warp/fem/space/nanogrid_function_space.py +62 -110
  70. warp/fem/space/quadmesh_function_space.py +208 -0
  71. warp/fem/space/shape/__init__.py +45 -7
  72. warp/fem/space/shape/cube_shape_function.py +328 -54
  73. warp/fem/space/shape/shape_function.py +10 -1
  74. warp/fem/space/shape/square_shape_function.py +328 -60
  75. warp/fem/space/shape/tet_shape_function.py +269 -19
  76. warp/fem/space/shape/triangle_shape_function.py +238 -19
  77. warp/fem/space/tetmesh_function_space.py +69 -37
  78. warp/fem/space/topology.py +38 -0
  79. warp/fem/space/trimesh_function_space.py +179 -0
  80. warp/fem/utils.py +6 -331
  81. warp/jax_experimental.py +3 -1
  82. warp/native/array.h +55 -40
  83. warp/native/builtin.h +124 -43
  84. warp/native/bvh.h +4 -0
  85. warp/native/coloring.cpp +600 -0
  86. warp/native/cuda_util.cpp +14 -0
  87. warp/native/cuda_util.h +2 -1
  88. warp/native/fabric.h +8 -0
  89. warp/native/hashgrid.h +4 -0
  90. warp/native/marching.cu +8 -0
  91. warp/native/mat.h +14 -3
  92. warp/native/mathdx.cpp +59 -0
  93. warp/native/mesh.h +4 -0
  94. warp/native/range.h +13 -1
  95. warp/native/reduce.cpp +9 -1
  96. warp/native/reduce.cu +7 -0
  97. warp/native/runlength_encode.cpp +9 -1
  98. warp/native/runlength_encode.cu +7 -1
  99. warp/native/scan.cpp +8 -0
  100. warp/native/scan.cu +8 -0
  101. warp/native/scan.h +8 -1
  102. warp/native/sparse.cpp +8 -0
  103. warp/native/sparse.cu +8 -0
  104. warp/native/temp_buffer.h +7 -0
  105. warp/native/tile.h +1857 -0
  106. warp/native/tile_gemm.h +341 -0
  107. warp/native/tile_reduce.h +210 -0
  108. warp/native/volume_builder.cu +8 -0
  109. warp/native/volume_builder.h +8 -0
  110. warp/native/warp.cpp +10 -2
  111. warp/native/warp.cu +369 -15
  112. warp/native/warp.h +12 -2
  113. warp/optim/adam.py +39 -4
  114. warp/paddle.py +29 -12
  115. warp/render/render_opengl.py +137 -65
  116. warp/sim/graph_coloring.py +292 -0
  117. warp/sim/integrator_euler.py +4 -2
  118. warp/sim/integrator_featherstone.py +115 -44
  119. warp/sim/integrator_vbd.py +6 -0
  120. warp/sim/model.py +90 -17
  121. warp/stubs.py +651 -85
  122. warp/tape.py +12 -7
  123. warp/tests/assets/pixel.npy +0 -0
  124. warp/tests/aux_test_instancing_gc.py +18 -0
  125. warp/tests/test_array.py +207 -48
  126. warp/tests/test_closest_point_edge_edge.py +8 -8
  127. warp/tests/test_codegen.py +120 -1
  128. warp/tests/test_codegen_instancing.py +30 -0
  129. warp/tests/test_collision.py +110 -0
  130. warp/tests/test_coloring.py +241 -0
  131. warp/tests/test_context.py +34 -0
  132. warp/tests/test_examples.py +18 -4
  133. warp/tests/test_fabricarray.py +33 -0
  134. warp/tests/test_fem.py +453 -113
  135. warp/tests/test_func.py +48 -1
  136. warp/tests/test_generics.py +52 -0
  137. warp/tests/test_iter.py +68 -0
  138. warp/tests/test_mat_scalar_ops.py +1 -1
  139. warp/tests/test_mesh_query_point.py +5 -4
  140. warp/tests/test_module_hashing.py +23 -0
  141. warp/tests/test_paddle.py +27 -87
  142. warp/tests/test_print.py +191 -1
  143. warp/tests/test_spatial.py +1 -1
  144. warp/tests/test_tile.py +700 -0
  145. warp/tests/test_tile_mathdx.py +144 -0
  146. warp/tests/test_tile_mlp.py +383 -0
  147. warp/tests/test_tile_reduce.py +374 -0
  148. warp/tests/test_tile_shared_memory.py +190 -0
  149. warp/tests/test_vbd.py +12 -20
  150. warp/tests/test_volume.py +43 -0
  151. warp/tests/unittest_suites.py +23 -2
  152. warp/tests/unittest_utils.py +4 -0
  153. warp/types.py +339 -73
  154. warp/utils.py +22 -1
  155. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/METADATA +33 -7
  156. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/RECORD +159 -132
  157. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/WHEEL +1 -1
  158. warp/fem/field/test.py +0 -180
  159. warp/fem/field/trial.py +0 -183
  160. warp/fem/space/collocated_function_space.py +0 -102
  161. warp/fem/space/quadmesh_2d_function_space.py +0 -261
  162. warp/fem/space/trimesh_2d_function_space.py +0 -153
  163. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/LICENSE.md +0 -0
  164. {warp_lang-1.4.1.dist-info → warp_lang-1.5.0.dist-info}/top_level.txt +0 -0
@@ -12,6 +12,8 @@
12
12
  # grid and the PicQuadrature class.
13
13
  ###########################################################################
14
14
 
15
+ from typing import Any
16
+
15
17
  import numpy as np
16
18
 
17
19
  import warp as wp
@@ -123,7 +125,7 @@ def scalar_vector_multiply(
123
125
  @wp.kernel
124
126
  def scale_transposed_divergence_mat(
125
127
  tr_divergence_mat_offsets: wp.array(dtype=int),
126
- tr_divergence_mat_values: wp.array(dtype=wp.mat(shape=(3, 1), dtype=float)),
128
+ tr_divergence_mat_values: wp.array(dtype=Any),
127
129
  inv_fraction_int: wp.array(dtype=float),
128
130
  ):
129
131
  # In-place scaling of gradient operator rows with inverse mass
@@ -203,7 +205,6 @@ class Example:
203
205
  particle_grid_offset = wp.vec3(self.radius, self.radius, self.radius)
204
206
 
205
207
  # Initialize warp.sim model, spawn particles
206
- np.random.seed(0)
207
208
  builder = wp.sim.ModelBuilder()
208
209
  builder.add_particle_grid(
209
210
  dim_x=particle_grid_res[0],
@@ -88,7 +88,7 @@ class Example:
88
88
  geo,
89
89
  discontinuous=True,
90
90
  degree=degree,
91
- family=fem.Polynomial.GAUSS_LEGENDRE,
91
+ family=fem.Polynomial.LOBATTO_GAUSS_LEGENDRE,
92
92
  )
93
93
 
94
94
  # Assemble transport, diffusion and inertia matrices
@@ -110,23 +110,22 @@ class Example:
110
110
 
111
111
  side_test = fem.make_test(space=scalar_space, domain=sides)
112
112
  side_trial = fem.make_trial(space=scalar_space, domain=sides)
113
-
114
- matrix_transport += fem.integrate(
113
+ fem.integrate(
115
114
  upwind_transport_form,
116
115
  fields={"phi": side_trial, "psi": side_test},
117
116
  values={"ang_vel": ang_vel},
117
+ output=matrix_transport,
118
+ add=True,
118
119
  )
119
120
 
120
121
  matrix_diffusion = fem.integrate(
121
122
  diffusion_form,
122
123
  fields={"u": trial, "v": self._test},
123
124
  )
124
-
125
125
  matrix_diffusion += fem.integrate(
126
126
  sip_diffusion_form,
127
127
  fields={"phi": side_trial, "psi": side_test},
128
128
  )
129
-
130
129
  self._matrix = matrix_inertia + matrix_transport + viscosity * matrix_diffusion
131
130
 
132
131
  # Initial condition
@@ -28,7 +28,7 @@ def deformation_field_expr(
28
28
  domain: fem.Domain,
29
29
  ):
30
30
  """
31
- Deformation field mapping the unique square to a circular band
31
+ Deformation field mapping the unit square to a circular band
32
32
  """
33
33
  x = domain(s)
34
34
 
@@ -16,6 +16,8 @@
16
16
  # and homogeneous Dirichlet boundary conditions other sides.
17
17
  ###########################################################################
18
18
 
19
+ import numpy as np
20
+
19
21
  import warp as wp
20
22
  import warp.examples.fem.utils as fem_example_utils
21
23
  import warp.fem as fem
@@ -24,7 +26,7 @@ from warp.sparse import bsr_axpy
24
26
 
25
27
 
26
28
  @fem.integrand
27
- def vert_boundary_projector_form(
29
+ def vertical_boundary_projector_form(
28
30
  s: fem.Sample,
29
31
  domain: fem.Domain,
30
32
  u: fem.Field,
@@ -36,6 +38,18 @@ def vert_boundary_projector_form(
36
38
  return w * u(s) * v(s)
37
39
 
38
40
 
41
+ @fem.integrand
42
+ def y_boundary_projector_form(
43
+ s: fem.Sample,
44
+ domain: fem.Domain,
45
+ u: fem.Field,
46
+ v: fem.Field,
47
+ ):
48
+ # Constrain Y edges
49
+ tangent = fem.deformation_gradient(domain, s)
50
+ return wp.abs(tangent[1]) * u(s) * v(s)
51
+
52
+
39
53
  class Example:
40
54
  def __init__(
41
55
  self,
@@ -77,6 +91,28 @@ class Example:
77
91
  bounds_hi=bounds_hi,
78
92
  )
79
93
  self._geo = fem.Nanogrid(volume)
94
+ elif mesh == "tri":
95
+ pos, quad_vtx_indices = fem_example_utils.gen_trimesh(
96
+ res=res,
97
+ bounds_lo=bounds_lo,
98
+ bounds_hi=bounds_hi,
99
+ )
100
+ pos = pos.numpy()
101
+ pos_z = np.cos(3.0 * pos[:, 0]) * np.sin(4.0 * pos[:, 1])
102
+ pos = np.hstack((pos, np.expand_dims(pos_z, axis=1)))
103
+ pos = wp.array(pos, dtype=wp.vec3)
104
+ self._geo = fem.Trimesh3D(quad_vtx_indices, pos)
105
+ elif mesh == "quad":
106
+ pos, quad_vtx_indices = fem_example_utils.gen_quadmesh(
107
+ res=res,
108
+ bounds_lo=bounds_lo,
109
+ bounds_hi=bounds_hi,
110
+ )
111
+ pos = pos.numpy()
112
+ pos_z = np.cos(3.0 * pos[:, 0]) * np.sin(4.0 * pos[:, 1])
113
+ pos = np.hstack((pos, np.expand_dims(pos_z, axis=1)))
114
+ pos = wp.array(pos, dtype=wp.vec3)
115
+ self._geo = fem.Quadmesh3D(quad_vtx_indices, pos)
80
116
  else:
81
117
  self._geo = fem.Grid3D(
82
118
  res=res,
@@ -108,7 +144,12 @@ class Example:
108
144
 
109
145
  bd_test = fem.make_test(space=self._scalar_space, domain=boundary)
110
146
  bd_trial = fem.make_trial(space=self._scalar_space, domain=boundary)
111
- bd_matrix = fem.integrate(vert_boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
147
+
148
+ # Pick boundary conditions depending on whether our geometry is a 3d surface or a volume
149
+ boundary_projector_form = (
150
+ vertical_boundary_projector_form if self._geo.cell_dimension == 3 else y_boundary_projector_form
151
+ )
152
+ bd_matrix = fem.integrate(boundary_projector_form, fields={"u": bd_trial, "v": bd_test}, nodal=True)
112
153
 
113
154
  # Diffusion form
114
155
  trial = fem.make_trial(space=self._scalar_space, domain=domain)
@@ -146,7 +187,9 @@ if __name__ == "__main__":
146
187
  parser.add_argument(
147
188
  "--boundary_compliance", type=float, default=0.0, help="Dirichlet boundary condition compliance."
148
189
  )
149
- parser.add_argument("--mesh", choices=("grid", "tet", "hex", "nano", "anano"), default="grid", help="Mesh type.")
190
+ parser.add_argument(
191
+ "--mesh", choices=("grid", "tet", "hex", "nano", "anano", "tri", "quad"), default="grid", help="Mesh type."
192
+ )
150
193
  parser.add_argument(
151
194
  "--headless",
152
195
  action="store_true",
@@ -171,4 +214,4 @@ if __name__ == "__main__":
171
214
  example.render()
172
215
 
173
216
  if not args.headless:
174
- example.renderer.plot(backend="matplotlib")
217
+ example.renderer.plot()
@@ -0,0 +1,220 @@
1
+ # Copyright (c) 2022 NVIDIA CORPORATION. All rights reserved.
2
+ # NVIDIA CORPORATION and its licensors retain all intellectual property
3
+ # and proprietary rights in and to this software, related documentation
4
+ # and any modifications thereto. Any use, reproduction, disclosure or
5
+ # distribution of this software and related documentation without an express
6
+ # license agreement from NVIDIA CORPORATION is strictly prohibited.
7
+
8
+ ###########################################################################
9
+ # Example Distortion Energy
10
+ #
11
+ # This example illustrates using a Newton loop to minimize distortion of a
12
+ # 3D surface (u,v) parameterization under a Symmetric Dirichlet energy,
13
+ #
14
+ # E(F) = 1/2 |F|^2 + |F^{-1}|^2
15
+ #
16
+ # with F := dx/du
17
+ ###########################################################################
18
+
19
+ import numpy as np
20
+
21
+ import warp as wp
22
+ import warp.examples.fem.utils as fem_example_utils
23
+ import warp.fem as fem
24
+
25
+
26
+ @fem.integrand
27
+ def distortion_gradient_form(s: fem.Sample, u_cur: fem.Field, v: fem.Field):
28
+ # Symmetric Dirichlet energy gradient (linear form)
29
+ # E = 1/2 (F:F + F^-T:F^-T)
30
+
31
+ F = fem.grad(u_cur, s)
32
+
33
+ F_inv_sq = wp.inverse(F * wp.transpose(F))
34
+ F_inv = F_inv_sq * F
35
+
36
+ dE_dF = F - F_inv_sq * F_inv
37
+
38
+ return wp.ddot(fem.grad(v, s), dE_dF)
39
+
40
+
41
+ @fem.integrand
42
+ def distortion_hessian_form(s: fem.Sample, u_cur: fem.Field, u: fem.Field, v: fem.Field):
43
+ # Symmetric Dirichlet energy approximate hessian (bilinear form)
44
+
45
+ # F:F term
46
+ H = wp.ddot(fem.grad(v, s), fem.grad(u, s))
47
+
48
+ # F^-T:F^-T term
49
+ F = fem.grad(u_cur, s)
50
+ F_inv_sq = wp.inverse(F * wp.transpose(F))
51
+
52
+ # Gauss--Newton (ignore F^-2 derivative)
53
+ H += wp.ddot(F_inv_sq * fem.grad(v, s), F_inv_sq * F_inv_sq * fem.grad(u, s))
54
+
55
+ return H
56
+
57
+
58
+ @fem.integrand
59
+ def initial_guess(
60
+ s: fem.Sample,
61
+ domain: fem.Domain,
62
+ ):
63
+ # initialization for UV parameter
64
+ x = domain(s)
65
+ return wp.vec2(x[0], x[1])
66
+
67
+
68
+ @fem.integrand
69
+ def boundary_projector_form(
70
+ s: fem.Sample,
71
+ domain: fem.Domain,
72
+ u: fem.Field,
73
+ v: fem.Field,
74
+ ):
75
+ # Fix a single point
76
+ # (underconstrained, solution up to a rotation in UV space)
77
+ w = wp.select(s.qp_index == 0, 0.0, 1.0)
78
+ return w * wp.dot(u(s), v(s))
79
+
80
+
81
+ @fem.integrand
82
+ def checkerboard(s: fem.Sample, domain: fem.Domain, u: fem.Field):
83
+ # checkerboard pattern for parameter visualization
84
+ u_s = u(s)
85
+ return wp.sign(wp.cos(16.0 * u_s[0]) * wp.sin(16.0 * u_s[1]))
86
+
87
+
88
+ class Example:
89
+ def __init__(
90
+ self,
91
+ quiet=False,
92
+ degree=2,
93
+ resolution=25,
94
+ mesh="grid",
95
+ nonconforming_stresses=False,
96
+ ):
97
+ self._quiet = quiet
98
+
99
+ def deform_along_z(positions, z_scale=1.0):
100
+ pos = positions.numpy()
101
+ pos_z = z_scale * np.cos(3.0 * pos[:, 0]) * np.sin(4.0 * pos[:, 1])
102
+ pos = np.hstack((pos, np.expand_dims(pos_z, axis=1)))
103
+ return wp.array(pos, dtype=wp.vec3)
104
+
105
+ # Grid or mesh geometry
106
+ if mesh == "tri":
107
+ positions, tri_vidx = fem_example_utils.gen_trimesh(res=wp.vec2i(resolution))
108
+ self._uv_geo = fem.Trimesh2D(tri_vertex_indices=tri_vidx, positions=wp.zeros_like(positions))
109
+
110
+ positions = deform_along_z(positions)
111
+ self._geo = fem.Trimesh3D(tri_vertex_indices=tri_vidx, positions=positions)
112
+ elif mesh == "quad":
113
+ positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
114
+ self._uv_geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=wp.zeros_like(positions))
115
+
116
+ positions = deform_along_z(positions)
117
+ self._geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=positions)
118
+ else:
119
+ positions, quad_vidx = fem_example_utils.gen_quadmesh(res=wp.vec2i(resolution))
120
+ self._uv_geo = fem.Quadmesh2D(quad_vertex_indices=quad_vidx, positions=wp.zeros_like(positions))
121
+
122
+ undef_positions = deform_along_z(positions, z_scale=0.0)
123
+ flat_geo = fem.Quadmesh3D(quad_vertex_indices=quad_vidx, positions=undef_positions)
124
+
125
+ deformation_field = fem.make_discrete_field(fem.make_polynomial_space(flat_geo, dtype=wp.vec3))
126
+ deformation_field.dof_values = deform_along_z(positions)
127
+
128
+ self._geo = deformation_field.make_deformed_geometry(relative=False)
129
+
130
+ # parameter space
131
+ self._u_space = fem.make_polynomial_space(self._geo, degree=degree, dtype=wp.vec2)
132
+ self._u_field = self._u_space.make_field()
133
+ self._du_field = self._u_space.make_field()
134
+ fem.interpolate(initial_guess, dest=self._u_field)
135
+
136
+ # scalar parameter visualization function
137
+ viz_space = fem.make_polynomial_space(self._geo, degree=3, dtype=float)
138
+ self.viz_field = viz_space.make_field()
139
+ # For visualization of uv in 2D space
140
+ uv_space = fem.make_polynomial_space(self._uv_geo, degree=degree, dtype=wp.vec2)
141
+ self._uv_field = uv_space.make_field()
142
+
143
+ self.renderer = fem_example_utils.Plot()
144
+
145
+ def step(self):
146
+ boundary = fem.BoundarySides(self._geo)
147
+ domain = fem.Cells(geometry=self._geo)
148
+
149
+ # Parameter boundary conditions
150
+ u_bd_test = fem.make_test(space=self._u_space, domain=boundary)
151
+ u_bd_trial = fem.make_trial(space=self._u_space, domain=boundary)
152
+ u_bd_matrix = fem.integrate(
153
+ boundary_projector_form, fields={"u": u_bd_trial, "v": u_bd_test}, nodal=True, output_dtype=float
154
+ )
155
+ fem.normalize_dirichlet_projector(u_bd_matrix)
156
+
157
+ u_test = fem.make_test(space=self._u_space, domain=domain)
158
+ u_trial = fem.make_trial(space=self._u_space, domain=domain)
159
+
160
+ # Newton iterations (without line-search for simplicity)
161
+ for _newton_iteration in range(10):
162
+ u_matrix = fem.integrate(
163
+ distortion_hessian_form, fields={"u_cur": self._u_field, "u": u_trial, "v": u_test}, output_dtype=float
164
+ )
165
+
166
+ u_rhs = fem.integrate(
167
+ distortion_gradient_form, fields={"u_cur": self._u_field, "v": u_test}, output_dtype=wp.vec2
168
+ )
169
+
170
+ fem.project_linear_system(u_matrix, u_rhs, u_bd_matrix, normalize_projector=False)
171
+
172
+ # Solve for uv increment
173
+ du = self._du_field.dof_values
174
+ du.zero_()
175
+ fem_example_utils.bsr_cg(u_matrix, b=u_rhs, x=du, quiet=self._quiet)
176
+
177
+ # Accumulate to UV field
178
+ fem.utils.array_axpy(x=du, y=self._u_field.dof_values, alpha=-1.0, beta=1.0)
179
+
180
+ def render(self):
181
+ # Visualization
182
+ fem.interpolate(checkerboard, fields={"u": self._u_field}, dest=self.viz_field)
183
+
184
+ self._uv_field.dof_values = wp.clone(self._u_field.dof_values)
185
+
186
+ self.renderer.add_field("pattern", self.viz_field)
187
+ self.renderer.add_field("uv", self._uv_field)
188
+
189
+
190
+ if __name__ == "__main__":
191
+ import argparse
192
+
193
+ wp.set_module_options({"enable_backward": False})
194
+
195
+ parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
196
+ parser.add_argument("--device", type=str, default=None, help="Override the default Warp device.")
197
+ parser.add_argument("--resolution", type=int, default=25, help="Grid resolution.")
198
+ parser.add_argument("--degree", type=int, default=1, help="Polynomial degree of shape functions.")
199
+ parser.add_argument("--mesh", choices=("tri", "quad", "deformed"), default="tri", help="Mesh type")
200
+ parser.add_argument(
201
+ "--headless",
202
+ action="store_true",
203
+ help="Run in headless mode, suppressing the opening of any graphical windows.",
204
+ )
205
+ parser.add_argument("--quiet", action="store_true", help="Suppresses the printing out of iteration residuals.")
206
+
207
+ args = parser.parse_known_args()[0]
208
+
209
+ with wp.ScopedDevice(args.device):
210
+ example = Example(
211
+ quiet=args.quiet,
212
+ degree=args.degree,
213
+ resolution=args.resolution,
214
+ mesh=args.mesh,
215
+ )
216
+ example.step()
217
+ example.render()
218
+
219
+ if not args.headless:
220
+ example.renderer.plot(options={"uv": {"displacement": {}}})