Jessedbrown commited on
Commit
2ed2c55
·
0 Parent(s):

Add space-time simulator Python script

Browse files
Files changed (1) hide show
  1. py_new.py +176 -0
py_new.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ from typing import Tuple, Union
3
+
4
+ # Simulate your friend's typing_ and backend modules
5
+ # In your real code, replace these with your actual imports.
6
+ Number = Union[float, int]
7
+ Tensorlike = np.ndarray
8
+ bd = np
9
+
10
+ # Constants (if needed)
11
+ # from . import constants as const
12
+ # For now we won't define constants as none were used explicitly.
13
+
14
+ def curl_E(E: Tensorlike) -> Tensorlike:
15
+ """
16
+ Transforms an E-type field into an H-type field by performing a curl operation.
17
+ E is located on edges (integer gridpoints), result is on faces (half-integer grid points).
18
+ """
19
+ curl = bd.zeros(E.shape)
20
+
21
+ # Following the original indexing logic
22
+ curl[:, :-1, :, 0] += E[:, 1:, :, 2] - E[:, :-1, :, 2]
23
+ curl[:, :, :-1, 0] -= E[:, :, 1:, 1] - E[:, :, :-1, 1]
24
+
25
+ curl[:, :, :-1, 1] += E[:, :, 1:, 0] - E[:, :, :-1, 0]
26
+ curl[:-1, :, :, 1] -= E[1:, :, :, 2] - E[:-1, :, :, 2]
27
+
28
+ curl[:-1, :, :, 2] += E[1:, :, :, 1] - E[:-1, :, :, 1]
29
+ curl[:, :-1, :, 2] -= E[:, 1:, :, 0] - E[:, :-1, :, 0]
30
+
31
+ return curl
32
+
33
+ def curl_edge_to_face(v: Tensorlike) -> Tensorlike:
34
+ """
35
+ Compute the curl of a vector field v on edges to get a field on faces.
36
+ """
37
+ return curl_E(v)
38
+
39
+ def curl_H(H: Tensorlike) -> Tensorlike:
40
+ """
41
+ Transforms an H-type field (faces) into an E-type field (edges) by performing a curl operation.
42
+ """
43
+ curl = bd.zeros(H.shape)
44
+
45
+ curl[:, 1:, :, 0] += H[:, 1:, :, 2] - H[:, :-1, :, 2]
46
+ curl[:, :, 1:, 0] -= H[:, :, 1:, 1] - H[:, :, :-1, 1]
47
+
48
+ curl[:, :, 1:, 1] += H[:, :, 1:, 0] - H[:, :, :-1, 0]
49
+ curl[1:, :, :, 1] -= H[1:, :, :, 2] - H[:-1, :, :, 2]
50
+
51
+ curl[1:, :, :, 2] += H[1:, :, :, 1] - H[:-1, :, :, 1]
52
+ curl[:, 1:, :, 2] -= H[:, 1:, :, 0] - H[:, :-1, :, 0]
53
+
54
+ return curl
55
+
56
+ def curl_face_to_edge(A: Tensorlike) -> Tensorlike:
57
+ """
58
+ Compute the curl of a vector field A on faces, resulting in a field on edges.
59
+ """
60
+ return curl_H(A)
61
+
62
+ def div(v: Tensorlike) -> Tensorlike:
63
+ """
64
+ Compute the divergence of a vector field v defined on edges.
65
+ The result is a scalar field on faces.
66
+ """
67
+ # Based on your your old code
68
+ div_v = bd.zeros((v.shape[0], v.shape[1], v.shape[2], 1))
69
+
70
+ # x-component
71
+ div_v[1:-1, :, :, 0] += (v[1:-1, :, :, 0] - v[:-2, :, :, 0])
72
+ div_v[:-2, :, :, 0] -= (v[1:-1, :, :, 0] - v[2:, :, :, 0])
73
+
74
+ # y-component
75
+ div_v[:, 1:-1, :, 0] += (v[:, 1:-1, :, 1] - v[:, :-2, :, 1])
76
+ div_v[:, :-2, :, 0] -= (v[:, 1:-1, :, 1] - v[:, 2:, :, 1])
77
+
78
+ # z-component
79
+ div_v[:, :, 1:-1, 0] += (v[:, :, 1:-1, 2] - v[:, :, :-2, 2])
80
+ div_v[:, :, :-2, 0] -= (v[:, :, 1:-1, 2] - v[:, :, 2:, 2])
81
+
82
+ return div_v
83
+
84
+ def grad(p: Tensorlike) -> Tensorlike:
85
+ """
86
+ Compute the gradient of a scalar field p located on grid points.
87
+ p has shape (Nx+1, Ny+1, Nz+1, 1).
88
+ Returns (Nx+1, Ny+1, Nz+1, 3).
89
+ """
90
+ grad = bd.zeros((p.shape[0], p.shape[1], p.shape[2], 3))
91
+
92
+ grad[:-1, :, :, 0] = (p[1:, :, :, 0] - p[:-1, :, :, 0])
93
+ grad[:, :-1, :, 1] = (p[:, 1:, :, 0] - p[:, :-1, :, 0])
94
+ grad[:, :, :-1, 2] = (p[:, :, 1:, 0] - p[:, :, :-1, 0])
95
+
96
+ return grad
97
+
98
+ ############################################
99
+ # Additional functionalities and example
100
+ ############################################
101
+
102
+ def laplacian_vector_field(v: Tensorlike) -> Tensorlike:
103
+ """
104
+ Compute the vector Laplacian Δv using the provided curl and div.
105
+ Δv = ∇(∇·v) - ∇×(∇×v)
106
+ To do this correctly, we might need v and p fields on compatible staggered grids.
107
+ Here we assume the same indexing as your friend's code.
108
+ """
109
+ # As an example, let's just apply curl and div in a way similar to the previous code
110
+ # Note: The original code doesn't provide dx, dy, dz, we assume uniform spacing of 1.
111
+ div_v = div(v) # scalar field
112
+ grad_div_v = grad(div_v) # vector field
113
+ c = curl_edge_to_face(v) # curl moves edges->faces
114
+ curl_c = curl_face_to_edge(c) # curl moves faces->edges
115
+ return grad_div_v - curl_c # Δv = ∇(∇·v) - ∇×(∇×v)
116
+
117
+ def apply_second_order_operator(v: Tensorlike, k: float = 1.0) -> Tensorlike:
118
+ """
119
+ Apply d/dt = -k Δ to a vector field v on edges.
120
+ Here Δv = laplacian_vector_field(v).
121
+ """
122
+ lap_v = laplacian_vector_field(v)
123
+ return -k * lap_v
124
+
125
+ # Boundary conditions
126
+ def apply_dirichlet_condition(field: np.ndarray, value: float = 0.0):
127
+ field[0, :, :, :] = value
128
+ field[-1, :, :, :] = value
129
+ field[:, 0, :, :] = value
130
+ field[:, -1, :, :] = value
131
+ field[:, :, 0, :] = value
132
+ field[:, :, -1, :] = value
133
+
134
+ def apply_neumann_condition(field: np.ndarray):
135
+ field[0, :, :, :] = field[1, :, :, :]
136
+ field[-1, :, :, :] = field[-2, :, :, :]
137
+ field[:, 0, :, :] = field[:, 1, :, :]
138
+ field[:, -1, :, :] = field[:, -2, :, :]
139
+ field[:, :, 0, :] = field[:, :, 1, :]
140
+ field[:, :, -1, :] = field[:, :, -2, :]
141
+
142
+ def apply_periodic_condition(field: np.ndarray):
143
+ field[0, :, :, :] = field[-2, :, :, :]
144
+ field[-1, :, :, :] = field[1, :, :, :]
145
+ field[:, 0, :, :] = field[:, -2, :, :]
146
+ field[:, -1, :, :] = field[:, 1, :, :]
147
+ field[:, :, 0, :] = field[:, :, -2, :]
148
+ field[:, :, -1, :] = field[:, :, 1, :]
149
+
150
+ if __name__ == "__main__":
151
+ # Example usage:
152
+ # Suppose Nx, Ny, Nz are the number of cells in each direction
153
+ # The given code suggests fields on staggered grids. Adjust sizes as needed.
154
+ Nx, Ny, Nz = 20, 20, 20
155
+ v_field = bd.random.randn(Nx, Ny, Nz, 3) # A random vector field
156
+
157
+ # Choose a boundary type
158
+ boundary_type = 'dirichlet' # 'dirichlet', 'neumann', 'periodic'
159
+ dt = 0.1
160
+ k = 1.0
161
+ num_timesteps = 5
162
+
163
+ for _ in range(num_timesteps):
164
+ dv_dt = apply_second_order_operator(v_field, k)
165
+ v_field = v_field + dt * dv_dt
166
+
167
+ # Apply chosen boundary condition
168
+ if boundary_type == 'dirichlet':
169
+ apply_dirichlet_condition(v_field, value=0.0)
170
+ elif boundary_type == 'neumann':
171
+ apply_neumann_condition(v_field)
172
+ elif boundary_type == 'periodic':
173
+ apply_periodic_condition(v_field)
174
+
175
+ print("Final field shape:", v_field.shape)
176
+ print("Simulation complete.")