Skip to content

Commit 42e8e36

Browse files
committed
Add 1D averaging operators and clean up average interface
1 parent 199aa52 commit 42e8e36

File tree

4 files changed

+109
-42
lines changed

4 files changed

+109
-42
lines changed

dedalus/core/basis.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,29 @@ def _full_matrix(input_basis, output_basis):
689689
return integ_vector[None, :] * input_basis.COV.stretch
690690

691691

692+
class AverageJacobi(operators.Average, operators.SpectralOperator1D):
693+
"""Jacobi polynomial averaging."""
694+
695+
input_coord_type = Coordinate
696+
input_basis_type = Jacobi
697+
subaxis_dependence = [True]
698+
subaxis_coupling = [True]
699+
700+
@staticmethod
701+
def _output_basis(input_basis):
702+
return None
703+
704+
@staticmethod
705+
def _full_matrix(input_basis, output_basis):
706+
# Build native integration vector
707+
N = input_basis.size
708+
a, b = input_basis.a, input_basis.b
709+
integ_vector = jacobi.integration_vector(N, a, b)
710+
ave_vector = integ_vector / 2
711+
# Rescale and return with shape (1, N)
712+
return ave_vector[None, :]
713+
714+
692715
class LiftJacobi(operators.Lift, operators.Copy):
693716
"""Jacobi polynomial lift."""
694717

@@ -949,6 +972,30 @@ def _group_matrix(group, input_basis, output_basis):
949972
raise ValueError("This should never happen.")
950973

951974

975+
class AverageComplexFourier(operators.Average, operators.SpectralOperator1D):
976+
"""ComplexFourier averaging."""
977+
978+
input_coord_type = Coordinate
979+
input_basis_type = ComplexFourier
980+
subaxis_dependence = [True]
981+
subaxis_coupling = [False]
982+
983+
@staticmethod
984+
def _output_basis(input_basis):
985+
return None
986+
987+
@staticmethod
988+
def _group_matrix(group, input_basis, output_basis):
989+
# Rescale group (native wavenumber) to get physical wavenumber
990+
k = group / input_basis.COV.stretch
991+
# integ exp(1j*k*x) / L = δ(k, 0)
992+
if k == 0:
993+
return np.array([[1]])
994+
else:
995+
# Constructor should only loop over group 0.
996+
raise ValueError("This should never happen.")
997+
998+
952999
class RealFourier(FourierBase, metaclass=CachedClass):
9531000
"""
9541001
Fourier real sine/cosine basis.
@@ -1152,6 +1199,31 @@ def _group_matrix(group, input_basis, output_basis):
11521199
raise ValueError("This should never happen.")
11531200

11541201

1202+
class AverageRealFourier(operators.Average, operators.SpectralOperator1D):
1203+
"""RealFourier averaging."""
1204+
1205+
input_coord_type = Coordinate
1206+
input_basis_type = RealFourier
1207+
subaxis_dependence = [True]
1208+
subaxis_coupling = [False]
1209+
1210+
@staticmethod
1211+
def _output_basis(input_basis):
1212+
return None
1213+
1214+
@staticmethod
1215+
def _group_matrix(group, input_basis, output_basis):
1216+
# Rescale group (native wavenumber) to get physical wavenumber
1217+
k = group / input_basis.COV.stretch
1218+
# integ cos(k*x) / L = δ(k, 0)
1219+
# integ -sin(k*x) / L = 0
1220+
if k == 0:
1221+
return np.array([[1, 0]])
1222+
else:
1223+
# Constructor should only loop over group 0.
1224+
raise ValueError("This should never happen.")
1225+
1226+
11551227
# class HilbertTransformFourier(operators.HilbertTransform):
11561228
# """Fourier series Hilbert transform."""
11571229

dedalus/core/evaluator.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,8 @@ def setup_file(self, file, virtual_file=False):
578578
scale_group.create_dataset(name='timestep', shape=(0,), maxshape=(None,), dtype=np.float64)
579579
scale_group.create_dataset(name='world_time', shape=(0,), maxshape=(None,), dtype=np.float64)
580580
scale_group.create_dataset(name='wall_time', shape=(0,), maxshape=(None,), dtype=np.float64)
581-
scale_group.create_dataset(name='iteration', shape=(0,), maxshape=(None,), dtype=np.int)
582-
scale_group.create_dataset(name='write_number', shape=(0,), maxshape=(None,), dtype=np.int)
581+
scale_group.create_dataset(name='iteration', shape=(0,), maxshape=(None,), dtype=int)
582+
scale_group.create_dataset(name='write_number', shape=(0,), maxshape=(None,), dtype=int)
583583
scale_group.create_dataset(name='constant', data=np.array([0.], dtype=np.float64))
584584
scale_group['constant'].make_scale()
585585

dedalus/core/operators.py

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,27 +1073,16 @@ def _expand_multiply(self, operand, vars):
10731073
return prod([self.new_operand(arg) for arg in operand.args])
10741074

10751075

1076-
@parseable('integrate', 'integ')
1077-
def integrate(arg, spaces=None):
1078-
if spaces is None:
1079-
spaces = tuple(b.coords for b in arg.domain.bases)
1080-
# Identify domain
1081-
#domain = unify_attributes((arg,)+spaces, 'domain', require=False)
1082-
# Apply iteratively
1083-
for space in spaces:
1084-
#space = domain.get_space_object(space)
1085-
arg = Integrate(arg, space)
1086-
return arg
1087-
10881076
@alias("integ")
10891077
class Integrate(LinearOperator, metaclass=MultiClass):
10901078
"""
1091-
Definite integration over operand bases.
1079+
Integrate over operand bases.
10921080
10931081
Parameters
10941082
----------
10951083
operand : number or Operand object
10961084
coords : Coordinate or CoordinateSystem object, or list of these
1085+
10971086
"""
10981087

10991088
name = "Integrate"
@@ -1154,17 +1143,38 @@ def new_operand(self, operand, **kw):
11541143
@alias("ave")
11551144
class Average(LinearOperator, metaclass=MultiClass):
11561145
"""
1157-
Average along one dimension.
1146+
Average over operand bases.
11581147
11591148
Parameters
11601149
----------
11611150
operand : number or Operand object
1162-
space : Space object
1151+
coords : Coordinate or CoordinateSystem object, or list of these
11631152
11641153
"""
11651154

11661155
name = "Average"
11671156

1157+
@classmethod
1158+
def _preprocess_args(cls, operand, coord=None):
1159+
# Handle numbers
1160+
if isinstance(operand, Number):
1161+
raise SkipDispatchException(output=operand)
1162+
# Average over all operand bases by default
1163+
if coord is None:
1164+
coord = [basis.coordsystem for basis in operand.domain.bases]
1165+
# Recurse over multiple coordinates
1166+
if isinstance(coord, (tuple, list)):
1167+
if len(coord) > 1:
1168+
operand = Average(operand, coord[:-1])
1169+
coord = coord[-1]
1170+
# Resolve strings to coordinates
1171+
if isinstance(coord, str):
1172+
coord = operand.domain.get_coord(coord)
1173+
# Check coordinate type
1174+
if not isinstance(coord, (coords.Coordinate, coords.CoordinateSystem)):
1175+
raise ValueError("coords must be Coordinate or str")
1176+
return (operand, coord), {}
1177+
11681178
@classmethod
11691179
def _check_args(cls, operand, coords):
11701180
# Dispatch by operand basis
@@ -1175,22 +1185,6 @@ def _check_args(cls, operand, coords):
11751185
return True
11761186
return False
11771187

1178-
@classmethod
1179-
def _preprocess_args(cls, operand, coord=None):
1180-
if isinstance(operand, Number):
1181-
raise SkipDispatchException(output=operand)
1182-
if coord is None:
1183-
coord = operand.dist.single_coordsys
1184-
if coord is False:
1185-
raise ValueError("coordsys must be specified.")
1186-
elif isinstance(coord, (coords.Coordinate, coords.CoordinateSystem)):
1187-
pass
1188-
elif isinstance(coord, str):
1189-
coord = operand.domain.get_coord(coord)
1190-
else:
1191-
raise ValueError("coord must be Coordinate or str")
1192-
return (operand, coord), {}
1193-
11941188
def __init__(self, operand, coord):
11951189
SpectralOperator.__init__(self, operand)
11961190
# Require integrand is a scalar

docs/notebooks/dedalus_tutorial_2.ipynb

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@
2424
"name": "stdout",
2525
"output_type": "stream",
2626
"text": [
27-
"2022-02-11 14:29:22,407 dedalus 0/1 WARNING :: Threading has not been disabled. This may massively degrade Dedalus performance.\n",
28-
"2022-02-11 14:29:22,408 dedalus 0/1 WARNING :: We strongly suggest setting the \"OMP_NUM_THREADS\" environment variable to \"1\".\n",
29-
"2022-02-11 14:29:22,543 numexpr.utils 0/1 INFO :: Note: NumExpr detected 10 cores but \"NUMEXPR_MAX_THREADS\" not set, so enforcing safe limit of 8.\n",
30-
"2022-02-11 14:29:22,543 numexpr.utils 0/1 INFO :: NumExpr defaulting to 8 threads.\n"
27+
"2022-02-15 17:16:52,150 dedalus 0/1 WARNING :: Threading has not been disabled. This may massively degrade Dedalus performance.\n",
28+
"2022-02-15 17:16:52,151 dedalus 0/1 WARNING :: We strongly suggest setting the \"OMP_NUM_THREADS\" environment variable to \"1\".\n",
29+
"2022-02-15 17:16:52,255 numexpr.utils 0/1 INFO :: Note: NumExpr detected 10 cores but \"NUMEXPR_MAX_THREADS\" not set, so enforcing safe limit of 8.\n",
30+
"2022-02-15 17:16:52,256 numexpr.utils 0/1 INFO :: NumExpr defaulting to 8 threads.\n"
3131
]
3232
}
3333
],
@@ -224,7 +224,7 @@
224224
"name": "stderr",
225225
"output_type": "stream",
226226
"text": [
227-
"/var/folders/gl/8q1_pm2s1490lvyfvm_8yby80000gn/T/ipykernel_82069/1812536267.py:4: RuntimeWarning: divide by zero encountered in log10\n",
227+
"/var/folders/gl/8q1_pm2s1490lvyfvm_8yby80000gn/T/ipykernel_62829/1812536267.py:4: RuntimeWarning: divide by zero encountered in log10\n",
228228
" log_mag = lambda xmesh, ymesh, data: (xmesh, ymesh, np.log10(np.abs(data)))\n"
229229
]
230230
},
@@ -751,18 +751,19 @@
751751
"name": "stdout",
752752
"output_type": "stream",
753753
"text": [
754-
"f integral: [[9.42458659]]\n"
754+
"f integral: [[9.42458659]]\n",
755+
"f average: [[0.74998477]]\n"
755756
]
756757
}
757758
],
758759
"source": [
759760
"# Total integral of the field\n",
760-
"f_int = d3.Integrate(d3.Integrate(f, 'x'), 'y')\n",
761+
"f_int = d3.Integrate(f, ('x', 'y'))\n",
761762
"print('f integral:', f_int.evaluate()['g'])\n",
762763
"\n",
763764
"# Average of the field\n",
764-
"#f_ave = d3.Average(d3.Average(f, 'x'), 'y')\n",
765-
"#print('f average:', f_ave.evaluate()['g'])"
765+
"f_ave = d3.Average(f, ('x', 'y'))\n",
766+
"print('f average:', f_ave.evaluate()['g'])"
766767
]
767768
},
768769
{

0 commit comments

Comments
 (0)