forked from NVIDIA/modulus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ops.py
103 lines (91 loc) · 3.26 KB
/
ops.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# SPDX-FileCopyrightText: Copyright (c) 2023 - 2024 NVIDIA CORPORATION & AFFILIATES.
# SPDX-FileCopyrightText: All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import torch
import torch.nn.functional as F
def dx(inpt, dx, channel, dim, order=1, padding="zeros"):
"Compute first order numerical derivatives of input tensor"
var = inpt[:, channel : channel + 1, :, :]
# get filter
if order == 1:
ddx1D = torch.Tensor(
[
-0.5,
0.0,
0.5,
]
).to(inpt.device)
elif order == 3:
ddx1D = torch.Tensor(
[
-1.0 / 60.0,
3.0 / 20.0,
-3.0 / 4.0,
0.0,
3.0 / 4.0,
-3.0 / 20.0,
1.0 / 60.0,
]
).to(inpt.device)
ddx3D = torch.reshape(ddx1D, shape=[1, 1] + dim * [1] + [-1] + (1 - dim) * [1])
# apply convolution
if padding == "zeros":
var = F.pad(var, 4 * [(ddx1D.shape[0] - 1) // 2], "constant", 0)
elif padding == "replication":
var = F.pad(var, 4 * [(ddx1D.shape[0] - 1) // 2], "replicate")
output = F.conv2d(var, ddx3D, padding="valid")
output = (1.0 / dx) * output
if dim == 0:
output = output[:, :, :, (ddx1D.shape[0] - 1) // 2 : -(ddx1D.shape[0] - 1) // 2]
elif dim == 1:
output = output[:, :, (ddx1D.shape[0] - 1) // 2 : -(ddx1D.shape[0] - 1) // 2, :]
return output
def ddx(inpt, dx, channel, dim, order=1, padding="zeros"):
"Compute second order numerical derivatives of input tensor"
var = inpt[:, channel : channel + 1, :, :]
# get filter
if order == 1:
ddx1D = torch.Tensor(
[
1.0,
-2.0,
1.0,
]
).to(inpt.device)
elif order == 3:
ddx1D = torch.Tensor(
[
1.0 / 90.0,
-3.0 / 20.0,
3.0 / 2.0,
-49.0 / 18.0,
3.0 / 2.0,
-3.0 / 20.0,
1.0 / 90.0,
]
).to(inpt.device)
ddx3D = torch.reshape(ddx1D, shape=[1, 1] + dim * [1] + [-1] + (1 - dim) * [1])
# apply convolution
if padding == "zeros":
var = F.pad(var, 4 * [(ddx1D.shape[0] - 1) // 2], "constant", 0)
elif padding == "replication":
var = F.pad(var, 4 * [(ddx1D.shape[0] - 1) // 2], "replicate")
output = F.conv2d(var, ddx3D, padding="valid")
output = (1.0 / dx**2) * output
if dim == 0:
output = output[:, :, :, (ddx1D.shape[0] - 1) // 2 : -(ddx1D.shape[0] - 1) // 2]
elif dim == 1:
output = output[:, :, (ddx1D.shape[0] - 1) // 2 : -(ddx1D.shape[0] - 1) // 2, :]
return output