19
19
from __future__ import annotations
20
20
21
21
import itertools
22
+ import types
22
23
from typing import Callable
23
24
from typing import Dict
24
25
from typing import Optional
@@ -61,19 +62,23 @@ def __init__(
61
62
super ().__init__ (t0 , t1 )
62
63
self .t0 = t0
63
64
self .t1 = t1
65
+ assert (
66
+ time_step is None or timestamps is None
67
+ ), "time_step and timestamps cannot be both set."
64
68
self .time_step = time_step
65
- if timestamps is None :
66
- self .timestamps = None
67
- else :
69
+ if timestamps is not None :
68
70
self .timestamps = np .array (
69
71
timestamps , dtype = paddle .get_default_dtype ()
70
72
).reshape ([- 1 ])
71
- if time_step is not None :
72
- if time_step <= 0 :
73
- raise ValueError (f"time_step({ time_step } ) must be larger than 0." )
74
- self .num_timestamps = int (np .ceil ((t1 - t0 ) / time_step )) + 1
75
- elif timestamps is not None :
76
- self .num_timestamps = len (timestamps )
73
+ self .num_timestamps = len (self .timestamps )
74
+ elif time_step is not None :
75
+ # set timestamps manually with given time_step
76
+ self .timestamps = np .arange (
77
+ t0 , t1 , time_step , dtype = paddle .get_default_dtype ()
78
+ )
79
+ self .num_timestamps = len (self .timestamps )
80
+ else :
81
+ self .timestamps = None
77
82
78
83
def on_initial (self , t : np .ndarray ) -> np .ndarray :
79
84
"""Check if a specific time is on the initial time point.
@@ -115,6 +120,35 @@ def __init__(self, timedomain: TimeDomain, geometry: geometry.Geometry):
115
120
self .geometry = geometry
116
121
self .ndim = geometry .ndim + timedomain .ndim
117
122
123
+ if hasattr (self .geometry , "sdf_func" ):
124
+
125
+ def sdf_func (self , points : np .ndarray ) -> np .ndarray :
126
+ """Compute signed distance field.
127
+
128
+ Args:
129
+ points (np.ndarray): The temporal-spatial coordinate points used to calculate
130
+ the SDF value, the shape is [N, 1+D], where 1 represents the temporal
131
+ dimension and D represents the spatial dimensions.
132
+
133
+ Returns:
134
+ np.ndarray: SDF values of input points without squared, the shape is [N, 1].
135
+
136
+ NOTE: This function usually returns ndarray with negative values, because
137
+ according to the definition of SDF, the SDF value of the coordinate point inside
138
+ the object(interior points) is negative, the outside is positive, and the edge
139
+ is 0. Therefore, when used for weighting, a negative sign is often added before
140
+ the result of this function.
141
+ """
142
+ if points .shape [1 ] != self .ndim :
143
+ raise ValueError (
144
+ f"Shape of given points should be [*, { self .ndim } ], but got { points .shape } "
145
+ )
146
+ spatial_points = points [:, 1 :]
147
+ sdf = self .geometry .sdf_func (spatial_points )
148
+ return sdf
149
+
150
+ self .sdf_func = types .MethodType (sdf_func , self )
151
+
118
152
@property
119
153
def dim_keys (self ):
120
154
return ("t" ,) + self .geometry .dim_keys
@@ -153,11 +187,10 @@ def uniform_points(self, n: int, boundary: bool = True) -> np.ndarray:
153
187
>>> print(ts.shape)
154
188
(1000, 3)
155
189
"""
156
- if self .timedomain .time_step is not None :
157
- # exclude start time t0
158
- nt = int (np .ceil (self .timedomain .diam / self .timedomain .time_step ))
159
- nx = int (np .ceil (n / nt ))
160
- elif self .timedomain .timestamps is not None :
190
+ if (
191
+ self .timedomain .time_step is not None
192
+ or self .timedomain .timestamps is not None
193
+ ):
161
194
# exclude start time t0
162
195
nt = self .timedomain .num_timestamps - 1
163
196
nx = int (np .ceil (n / nt ))
@@ -211,7 +244,8 @@ def random_points(
211
244
criteria (Optional[Callable]): A method that filters on the generated random points. Defaults to None.
212
245
213
246
Returns:
214
- np.ndarray: A set of random spatial-temporal points.
247
+ np.ndarray: A array of random spatial-temporal points with shape [N, 1+D], where 1 represents the
248
+ temporal dimension and D represents the spatial dimensions.
215
249
216
250
Examples:
217
251
>>> import ppsci
@@ -225,63 +259,14 @@ def random_points(
225
259
if self .timedomain .time_step is None and self .timedomain .timestamps is None :
226
260
raise ValueError ("Either time_step or timestamps must be provided." )
227
261
# time evenly and geometry random, if time_step if specified
228
- if self .timedomain .time_step is not None :
229
- nt = int (np .ceil (self .timedomain .diam / self .timedomain .time_step ))
230
- t = np .linspace (
231
- self .timedomain .t1 ,
232
- self .timedomain .t0 ,
233
- num = nt ,
234
- endpoint = False ,
235
- dtype = paddle .get_default_dtype (),
236
- )[:, None ][
237
- ::- 1
238
- ] # [nt, 1]
262
+ if (
263
+ self .timedomain .time_step is not None
264
+ or self .timedomain .timestamps is not None
265
+ ):
239
266
# 1. sample nx points in static geometry with criteria
240
- nx = int (np .ceil (n / nt ))
241
- _size , _ntry , _nsuc = 0 , 0 , 0
242
- x = np .empty (
243
- shape = (nx , self .geometry .ndim ), dtype = paddle .get_default_dtype ()
244
- )
245
- while _size < nx :
246
- _x = self .geometry .random_points (nx , random )
247
- if criteria is not None :
248
- # fix arg 't' to None in criteria there
249
- criteria_mask = criteria (
250
- None , * np .split (_x , self .geometry .ndim , axis = 1 )
251
- ).flatten ()
252
- _x = _x [criteria_mask ]
253
- if len (_x ) > nx - _size :
254
- _x = _x [: nx - _size ]
255
- x [_size : _size + len (_x )] = _x
256
-
257
- _size += len (_x )
258
- _ntry += 1
259
- if len (_x ) > 0 :
260
- _nsuc += 1
261
-
262
- if _ntry >= 1000 and _nsuc == 0 :
263
- raise ValueError (
264
- "Sample points failed, "
265
- "please check correctness of geometry and given criteria."
266
- )
267
-
268
- # 2. repeat spatial points along time
269
- tx = []
270
- for ti in t :
271
- tx .append (
272
- np .hstack (
273
- (np .full ([nx , 1 ], ti , dtype = paddle .get_default_dtype ()), x )
274
- )
275
- )
276
- tx = np .vstack (tx )
277
- if len (tx ) > n :
278
- tx = tx [:n ]
279
- return tx
280
- elif self .timedomain .timestamps is not None :
281
- nt = self .timedomain .num_timestamps - 1
282
267
t = self .timedomain .timestamps [1 :]
268
+ nt = self .timedomain .num_timestamps - 1
283
269
nx = int (np .ceil (n / nt ))
284
-
285
270
_size , _ntry , _nsuc = 0 , 0 , 0
286
271
x = np .empty (
287
272
shape = (nx , self .geometry .ndim ), dtype = paddle .get_default_dtype ()
@@ -309,6 +294,7 @@ def random_points(
309
294
"please check correctness of geometry and given criteria."
310
295
)
311
296
297
+ # 2. repeat spatial points along time
312
298
tx = []
313
299
for ti in t :
314
300
tx .append (
0 commit comments