19
19
from __future__ import annotations
20
20
21
21
import itertools
22
+ from typing import Callable
23
+ from typing import Dict
22
24
from typing import Optional
23
25
from typing import Tuple
24
26
@@ -60,17 +62,37 @@ def __init__(
60
62
self .t0 = t0
61
63
self .t1 = t1
62
64
self .time_step = time_step
63
- self .timestamps = np .array (
64
- timestamps , dtype = paddle .get_default_dtype ()
65
- ).reshape ([- 1 ])
65
+ if timestamps is None :
66
+ self .timestamps = None
67
+ else :
68
+ self .timestamps = np .array (
69
+ timestamps , dtype = paddle .get_default_dtype ()
70
+ ).reshape ([- 1 ])
66
71
if time_step is not None :
67
72
if time_step <= 0 :
68
73
raise ValueError (f"time_step({ time_step } ) must be larger than 0." )
69
74
self .num_timestamps = int (np .ceil ((t1 - t0 ) / time_step )) + 1
70
75
elif timestamps is not None :
71
76
self .num_timestamps = len (timestamps )
72
77
73
- def on_initial (self , t ):
78
+ def on_initial (self , t : np .ndarray ):
79
+ """Check if a specific time is on the initial time point.
80
+
81
+ Args:
82
+ t (np.ndarray): The time to be checked.
83
+
84
+ Returns:
85
+ bool: True or False for whether the specific time is on the initial time point.
86
+
87
+ Examples:
88
+ >>> import paddle
89
+ >>> import ppsci
90
+ >>> geom = ppsci.geometry.TimeDomain(0, 1)
91
+ >>> T = [0, 0.01, 0.126, 0.2, 0.3]
92
+ >>> check = geom.on_initial(T)
93
+ >>> print(check)
94
+ [ True False False False False]
95
+ """
74
96
return np .isclose (t , self .t0 ).flatten ()
75
97
76
98
@@ -110,11 +132,26 @@ def boundary_normal(self, x):
110
132
normal = self .geometry .boundary_normal (x [:, 1 :])
111
133
return np .hstack ((x [:, :1 ], normal ))
112
134
113
- def uniform_points (self , n , boundary = True ):
135
+ def uniform_points (self , n : int , boundary : bool = True ):
114
136
"""Uniform points on the spatial-temporal domain.
115
-
116
137
Geometry volume ~ bbox.
117
138
Time volume ~ diam.
139
+
140
+ Args:
141
+ n (int): The total number of sample points to be generated.
142
+ boundary (bool): Indicates whether boundary points are included, default is True.
143
+
144
+ Returns:
145
+ np.ndarray: a set of spatial-temporal coordinate points 'tx' that represent sample points evenly distributed within the spatial-temporal domain.
146
+
147
+ Examples:
148
+ >>> import ppsci
149
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1, 0.001)
150
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
151
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
152
+ >>> ts = time_geom.uniform_points(1000)
153
+ >>> print(ts.shape)
154
+ (1000, 3)
118
155
"""
119
156
if self .timedomain .time_step is not None :
120
157
# exclude start time t0
@@ -163,7 +200,30 @@ def uniform_points(self, n, boundary=True):
163
200
tx = tx [:n ]
164
201
return tx
165
202
166
- def random_points (self , n , random = "pseudo" , criteria = None ):
203
+ def random_points (
204
+ self , n : int , random : str = "pseudo" , criteria : Optional [Callable ] = None
205
+ ):
206
+ """Generate random points on the spatial-temporal domain.
207
+
208
+ Args:
209
+ n (int): The total number of random points to generate.
210
+ random (string): Specifies the way to generate random points, default is "pseudo" , which means that a pseudo-random number generator is used.
211
+ criteria (Optional[Callable]): A method that filters on the generated random points, defualt is None.
212
+
213
+ Returns:
214
+ np.ndarray: A set of random spatial-temporal points.
215
+
216
+ Examples:
217
+ >>> import ppsci
218
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1, 0.001)
219
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
220
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
221
+ >>> ts = time_geom.random_points(1000)
222
+ >>> print(ts.shape)
223
+ (1000, 3)
224
+ """
225
+ if self .timedomain .time_step is None and self .timedomain .timestamps is None :
226
+ raise ValueError ("Either time_step or timestamps must be provided." )
167
227
# time evenly and geometry random, if time_step if specified
168
228
if self .timedomain .time_step is not None :
169
229
nt = int (np .ceil (self .timedomain .diam / self .timedomain .time_step ))
@@ -287,11 +347,26 @@ def random_points(self, n, random="pseudo", criteria=None):
287
347
t = np .random .permutation (t )
288
348
return np .hstack ((t , x ))
289
349
290
- def uniform_boundary_points (self , n , criteria = None ):
350
+ def uniform_boundary_points (self , n : int , criteria : Optional [ Callable ] = None ):
291
351
"""Uniform boundary points on the spatial-temporal domain.
292
-
293
352
Geometry surface area ~ bbox.
294
353
Time surface area ~ diam.
354
+
355
+ Args:
356
+ n (int): The total number of boundary points on the spatial-temporal domain to be generated that are evenly distributed across geometry boundaries.
357
+ criteria (Optional[Callable]): Used to filter the generated boundary points, only points that meet certain conditions are retained. Default is None.
358
+
359
+ Returns:
360
+ np.ndarray: A set of point coordinates evenly distributed across geometry boundaries on the spatial-temporal domain.
361
+
362
+ Examples:
363
+ >>> import ppsci
364
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1)
365
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
366
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
367
+ >>> ts = time_geom.uniform_boundary_points(1000)
368
+ >>> print(ts.shape)
369
+ (1000, 3)
295
370
"""
296
371
if self .geometry .ndim == 1 :
297
372
nx = 2
@@ -350,7 +425,30 @@ def uniform_boundary_points(self, n, criteria=None):
350
425
tx = tx [:n ]
351
426
return tx
352
427
353
- def random_boundary_points (self , n , random = "pseudo" , criteria = None ):
428
+ def random_boundary_points (
429
+ self , n : int , random : str = "pseudo" , criteria : Optional [Callable ] = None
430
+ ):
431
+ """Random boundary points on the spatial-temporal domain.
432
+
433
+ Args:
434
+ n (int): The total number of spatial-temporal points generated on a given geometry boundary.
435
+ random (string): Controls the way to generate random points. Default is "pseudo".
436
+ criteria (Optional[Callable]): Used to filter the generated boundary points, only points that meet certain conditions are retained. Default is None.
437
+
438
+ Returns:
439
+ np.ndarray: A set of point coordinates randomly distributed across geometry boundaries on the spatial-temporal domain.
440
+
441
+ Examples:
442
+ >>> import ppsci
443
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1, 0.001)
444
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
445
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
446
+ >>> ts = time_geom.random_boundary_points(1000)
447
+ >>> print(ts.shape)
448
+ (1000, 3)
449
+ """
450
+ if self .timedomain .time_step is None and self .timedomain .timestamps is None :
451
+ raise ValueError ("Either time_step or timestamps must be provided." )
354
452
if self .timedomain .time_step is not None :
355
453
# exclude start time t0
356
454
nt = int (np .ceil (self .timedomain .diam / self .timedomain .time_step ))
@@ -523,19 +621,78 @@ def random_boundary_points(self, n, random="pseudo", criteria=None):
523
621
else :
524
622
return t_x
525
623
526
- def uniform_initial_points (self , n ):
624
+ def uniform_initial_points (self , n : int ):
625
+ """Generate evenly distributed point coordinates on the spatial-temporal domain at the initial moment.
626
+
627
+ Args:
628
+ n (int): The total number of generated points.
629
+
630
+ Returns:
631
+ np.ndarray: A set of point coordinates evenly distributed on the spatial-temporal domain at the initial moment.
632
+
633
+ Examples:
634
+ >>> import ppsci
635
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1)
636
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
637
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
638
+ >>> ts = time_geom.uniform_initial_points(1000)
639
+ >>> print(ts.shape)
640
+ (1000, 3)
641
+ """
527
642
x = self .geometry .uniform_points (n , True )
528
643
t = self .timedomain .t0
529
644
if len (x ) > n :
530
645
x = x [:n ]
531
646
return np .hstack ((np .full ([n , 1 ], t , dtype = paddle .get_default_dtype ()), x ))
532
647
533
- def random_initial_points (self , n , random = "pseudo" ):
648
+ def random_initial_points (self , n : int , random : str = "pseudo" ):
649
+ """Generate randomly distributed point coordinates on the spatial-temporal domain at the initial moment.
650
+
651
+ Args:
652
+ n (int): The total number of generated points.
653
+ random (string): Controls the way to generate random points. Default is "pseudo".
654
+
655
+ Returns:
656
+ np.ndarray: A set of point coordinates randomly distributed on the spatial-temporal domain at the initial moment.
657
+
658
+ Examples:
659
+ >>> import ppsci
660
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1)
661
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
662
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
663
+ >>> ts = time_geom.random_initial_points(1000)
664
+ >>> print(ts.shape)
665
+ (1000, 3)
666
+ """
534
667
x = self .geometry .random_points (n , random = random )
535
668
t = self .timedomain .t0
536
669
return np .hstack ((np .full ([n , 1 ], t , dtype = paddle .get_default_dtype ()), x ))
537
670
538
- def periodic_point (self , x , component ):
671
+ def periodic_point (self , x : Dict [str , np .ndarray ], component : int ):
672
+ """process given point coordinates to satisfy the periodic boundary conditions of the geometry.
673
+
674
+ Args:
675
+ x (Dict[str, np.ndarray]): Contains the coordinates and timestamps of the points. It represents the coordinates of the point to be processed.
676
+ component (int): Specifies the components or dimensions of specific spatial coordinates that are periodically processed.
677
+
678
+ Returns:
679
+ Dict[str, np.ndarray] : contains the original timestamps and the coordinates of the spatial point after periodic processing.
680
+
681
+ Examples:
682
+ >>> import ppsci
683
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1, 0.1)
684
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
685
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
686
+ >>> ts = time_geom.sample_boundary(1000)
687
+ >>> result = time_geom.periodic_point(ts, 0)
688
+ >>> for k,v in result.items():
689
+ ... print(k, v.shape)
690
+ t (1000, 1)
691
+ x (1000, 1)
692
+ y (1000, 1)
693
+ normal_x (1000, 1)
694
+ normal_y (1000, 1)
695
+ """
539
696
xp = self .geometry .periodic_point (x , component )
540
697
txp = {"t" : x ["t" ], ** xp }
541
698
return txp
@@ -544,11 +701,35 @@ def sample_initial_interior(
544
701
self ,
545
702
n : int ,
546
703
random : str = "pseudo" ,
547
- criteria = None ,
548
- evenly = False ,
704
+ criteria : Optional [ Callable ] = None ,
705
+ evenly : bool = False ,
549
706
compute_sdf_derivatives : bool = False ,
550
707
):
551
- """Sample random points in the time-geometry and return those meet criteria."""
708
+ """Sample random points in the time-geometry and return those meet criteria.
709
+
710
+ Args:
711
+ n (int): The total number of interior points generated.
712
+ random (string): The method used to specify the initial point of generation. Default is "pseudo".
713
+ criteria (Optional[Callable]): Used to filter the generated interior points, only points that meet certain conditions are retained. Default is None.
714
+ evenly (bool): Indicates whether the initial points are generated evenly. Default is False.
715
+ compute_sdf_derivatives (bool): Indicates whether to calculate the derivative of signed distance function or not. Default is False.
716
+
717
+ Returns:
718
+ np.ndarray: Contains the coordinates of the initial internal point generated, as well as the potentially computed signed distance function and its derivative.
719
+
720
+ Examples:
721
+ >>> import ppsci
722
+ >>> timedomain = ppsci.geometry.TimeDomain(0, 1)
723
+ >>> geom = ppsci.geometry.Rectangle((0, 0), (1, 1))
724
+ >>> time_geom = ppsci.geometry.TimeXGeometry(timedomain, geom)
725
+ >>> ts = time_geom.sample_initial_interior(1000)
726
+ >>> for k,v in ts.items():
727
+ ... print(k, v.shape)
728
+ t (1000, 1)
729
+ x (1000, 1)
730
+ y (1000, 1)
731
+ sdf (1000, 1)
732
+ """
552
733
x = np .empty (shape = (n , self .ndim ), dtype = paddle .get_default_dtype ())
553
734
_size , _ntry , _nsuc = 0 , 0 , 0
554
735
while _size < n :
0 commit comments