We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
DVF to DDF
**Is your feature request related to a problem? Please describe.**
The current repository only supports warping based on DDF, but not on DVF.

**Describe the solution you'd like**
Implement a DVF to DDF transformation layer. So for models outputting DVF, we can first transform DVF to DDF and then used the existing Warp layer to resample input image based on the transformed DDF.

**Describe alternatives you've considered**
N/A

**Additional context**
DeepReg implementation of [IntDVF](https://github.com/DeepRegNet/DeepReg/blob/80854094feafec998fa6237199066556c73f31f9/deepreg/model/layer.py#L508-L535)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `monai/networks/blocks/__init__.py`
Content:
```
1 # Copyright 2020 - 2021 MONAI Consortium
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at
5 #     http://www.apache.org/licenses/LICENSE-2.0
6 # Unless required by applicable law or agreed to in writing, software
7 # distributed under the License is distributed on an "AS IS" BASIS,
8 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 # See the License for the specific language governing permissions and
10 # limitations under the License.
11 
12 from .acti_norm import ADN
13 from .activation import Mish, Swish
14 from .aspp import SimpleASPP
15 from .convolutions import Convolution, ResidualUnit
16 from .downsample import MaxAvgPool
17 from .dynunet_block import UnetBasicBlock, UnetOutBlock, UnetResBlock, UnetUpBlock, get_output_padding, get_padding
18 from .fcn import FCN, GCN, MCFCN, Refine
19 from .localnet_block import LocalNetDownSampleBlock, LocalNetFeatureExtractorBlock, LocalNetUpSampleBlock
20 from .segresnet_block import ResBlock
21 from .squeeze_and_excitation import (
22     ChannelSELayer,
23     ResidualSELayer,
24     SEBlock,
25     SEBottleneck,
26     SEResNetBottleneck,
27     SEResNeXtBottleneck,
28 )
29 from .upsample import SubpixelUpsample, Subpixelupsample, SubpixelUpSample, Upsample, UpSample
30 from .warp import Warp
31
```

Path: `monai/networks/blocks/warp.py`
Content:
```
1 from typing import List, Optional, Union
2 
3 import torch
4 from torch import nn
5 from torch.nn import functional as F
6 
7 from monai.utils import GridSamplePadMode
8 
9 
10 class Warp(nn.Module):
11     """
12     Warp an image with given DDF.
13     """
14 
15     def __init__(
16         self,
17         spatial_dims: int,
18         mode: int = 1,
19         padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,
20     ):
21         """
22         Args:
23             spatial_dims: {2, 3}. number of spatial dimensions
24             mode: interpolation mode to calculate output values, defaults to 1.
25                 Possible values are::
26 
27                     - 0 or 'nearest'    or InterpolationType.nearest
28                     - 1 or 'linear'     or InterpolationType.linear
29                     - 2 or 'quadratic'  or InterpolationType.quadratic
30                     - 3 or 'cubic'      or InterpolationType.cubic
31                     - 4 or 'fourth'     or InterpolationType.fourth
32                     - etc.
33             padding_mode: {``"zeros"``, ``"border"``, ``"reflection"``}
34                 Padding mode for outside grid values. Defaults to ``"border"``.
35                 See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample
36         """
37         super(Warp, self).__init__()
38         if spatial_dims not in [2, 3]:
39             raise ValueError(f"got unsupported spatial_dims={spatial_dims}, only support 2-d and 3-d input")
40         self.spatial_dims = spatial_dims
41         if mode < 0:
42             raise ValueError(f"do not support negative mode, got mode={mode}")
43         self.mode = mode
44         self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)
45 
46     @staticmethod
47     def get_reference_grid(ddf: torch.Tensor) -> torch.Tensor:
48         mesh_points = [torch.arange(0, dim) for dim in ddf.shape[2:]]
49         grid = torch.stack(torch.meshgrid(*mesh_points), dim=0)  # (spatial_dims, ...)
50         grid = torch.stack([grid] * ddf.shape[0], dim=0)  # (batch, spatial_dims, ...)
51         grid = grid.to(ddf)
52         return grid
53 
54     @staticmethod
55     def normalize_grid(grid: torch.Tensor) -> torch.Tensor:
56         # (batch, ..., self.spatial_dims)
57         for i, dim in enumerate(grid.shape[1:-1]):
58             grid[..., i] = grid[..., i] * 2 / (dim - 1) - 1
59         return grid
60 
61     def forward(self, image: torch.Tensor, ddf: torch.Tensor) -> torch.Tensor:
62         """
63         Args:
64             image: Tensor in shape (batch, num_channels, H, W[, D])
65             ddf: Tensor in the same spatial size as image, in shape (batch, spatial_dims, H, W[, D])
66 
67         Returns:
68             warped_image in the same shape as image (batch, num_channels, H, W[, D])
69         """
70         if len(image.shape) != 2 + self.spatial_dims:
71             raise ValueError(f"expecting {self.spatial_dims + 2}-d input, " f"got input in shape {image.shape}")
72         if len(ddf.shape) != 2 + self.spatial_dims or ddf.shape[1] != self.spatial_dims:
73             raise ValueError(
74                 f"expecting {self.spatial_dims + 2}-d ddf with {self.spatial_dims} channels, "
75                 f"got ddf in shape {ddf.shape}"
76             )
77         if image.shape[0] != ddf.shape[0] or image.shape[2:] != ddf.shape[2:]:
78             raise ValueError(
79                 "expecting image and ddf of same batch size and spatial size, "
80                 f"got image of shape {image.shape}, ddf of shape {ddf.shape}"
81             )
82 
83         grid = self.get_reference_grid(ddf) + ddf
84         grid = grid.permute([0] + list(range(2, 2 + self.spatial_dims)) + [1])  # (batch, ..., self.spatial_dims)
85 
86         if self.mode > 1:
87             raise ValueError(f"{self.mode}-order interpolation not yet implemented.")
88             # if not USE_COMPILED:
89             #     raise ValueError(f"cannot perform {self.mode}-order interpolation without C compile.")
90             # _padding_mode = self.padding_mode.value
91             # if _padding_mode == "zeros":
92             #     bound = 7
93             # elif _padding_mode == "border":
94             #     bound = 0
95             # else:
96             #     bound = 1
97             # warped_image: torch.Tensor = grid_pull(
98             #     image,
99             #     grid,
100             #     bound=bound,
101             #     extrapolate=True,
102             #     interpolation=self.mode,
103             # )
104         else:
105             grid = self.normalize_grid(grid)
106             index_ordering: List[int] = list(range(self.spatial_dims - 1, -1, -1))
107             grid = grid[..., index_ordering]  # z, y, x -> x, y, z
108             _interp_mode = "bilinear" if self.mode == 1 else "nearest"
109             warped_image = F.grid_sample(
110                 image, grid, mode=_interp_mode, padding_mode=self.padding_mode.value, align_corners=True
111             )
112 
113         return warped_image
114
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/monai/networks/blocks/__init__.py b/monai/networks/blocks/__init__.py
--- a/monai/networks/blocks/__init__.py
+++ b/monai/networks/blocks/__init__.py
@@ -27,4 +27,4 @@
     SEResNeXtBottleneck,
 )
 from .upsample import SubpixelUpsample, Subpixelupsample, SubpixelUpSample, Upsample, UpSample
-from .warp import Warp
+from .warp import DVF2DDF, Warp
diff --git a/monai/networks/blocks/warp.py b/monai/networks/blocks/warp.py
--- a/monai/networks/blocks/warp.py
+++ b/monai/networks/blocks/warp.py
@@ -62,7 +62,7 @@
         """
         Args:
             image: Tensor in shape (batch, num_channels, H, W[, D])
-            ddf: Tensor in the same spatial size as image, in shape (batch, spatial_dims, H, W[, D])
+            ddf: Tensor in the same spatial size as image, in shape (batch, ``spatial_dims``, H, W[, D])
 
         Returns:
             warped_image in the same shape as image (batch, num_channels, H, W[, D])
@@ -111,3 +111,40 @@
             )
 
         return warped_image
+
+
+class DVF2DDF(nn.Module):
+    """
+    Layer calculates a dense velocity field (DVF) from a dense displacement field (DDF)
+    with scaling and squaring.
+
+    Adapted from:
+        DeepReg (https://github.com/DeepRegNet/DeepReg)
+
+    """
+
+    def __init__(
+        self,
+        spatial_dims: int,
+        num_steps: int = 7,
+        mode: int = 1,
+        padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,
+    ):
+        super(DVF2DDF, self).__init__()
+        if num_steps <= 0:
+            raise ValueError(f"expecting positive num_steps, got {num_steps}")
+        self.num_steps = num_steps
+        self.warp_layer = Warp(spatial_dims=spatial_dims, mode=mode, padding_mode=padding_mode)
+
+    def forward(self, dvf):
+        """
+        Args:
+            dvf: dvf to be transformed, in shape (batch, ``spatial_dims``, H, W[,D])
+
+        Returns:
+
+        """
+        ddf: torch.Tensor = dvf / (2 ** self.num_steps)
+        for _ in range(self.num_steps):
+            ddf = ddf + self.warp_layer(image=ddf, ddf=ddf)
+        return ddf

{"golden_diff": "diff --git a/monai/networks/blocks/__init__.py b/monai/networks/blocks/__init__.py\n--- a/monai/networks/blocks/__init__.py\n+++ b/monai/networks/blocks/__init__.py\n@@ -27,4 +27,4 @@\n     SEResNeXtBottleneck,\n )\n from .upsample import SubpixelUpsample, Subpixelupsample, SubpixelUpSample, Upsample, UpSample\n-from .warp import Warp\n+from .warp import DVF2DDF, Warp\ndiff --git a/monai/networks/blocks/warp.py b/monai/networks/blocks/warp.py\n--- a/monai/networks/blocks/warp.py\n+++ b/monai/networks/blocks/warp.py\n@@ -62,7 +62,7 @@\n         \"\"\"\n         Args:\n             image: Tensor in shape (batch, num_channels, H, W[, D])\n-            ddf: Tensor in the same spatial size as image, in shape (batch, spatial_dims, H, W[, D])\n+            ddf: Tensor in the same spatial size as image, in shape (batch, ``spatial_dims``, H, W[, D])\n \n         Returns:\n             warped_image in the same shape as image (batch, num_channels, H, W[, D])\n@@ -111,3 +111,40 @@\n             )\n \n         return warped_image\n+\n+\n+class DVF2DDF(nn.Module):\n+    \"\"\"\n+    Layer calculates a dense velocity field (DVF) from a dense displacement field (DDF)\n+    with scaling and squaring.\n+\n+    Adapted from:\n+        DeepReg (https://github.com/DeepRegNet/DeepReg)\n+\n+    \"\"\"\n+\n+    def __init__(\n+        self,\n+        spatial_dims: int,\n+        num_steps: int = 7,\n+        mode: int = 1,\n+        padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,\n+    ):\n+        super(DVF2DDF, self).__init__()\n+        if num_steps <= 0:\n+            raise ValueError(f\"expecting positive num_steps, got {num_steps}\")\n+        self.num_steps = num_steps\n+        self.warp_layer = Warp(spatial_dims=spatial_dims, mode=mode, padding_mode=padding_mode)\n+\n+    def forward(self, dvf):\n+        \"\"\"\n+        Args:\n+            dvf: dvf to be transformed, in shape (batch, ``spatial_dims``, H, W[,D])\n+\n+        Returns:\n+\n+        \"\"\"\n+        ddf: torch.Tensor = dvf / (2 ** self.num_steps)\n+        for _ in range(self.num_steps):\n+            ddf = ddf + self.warp_layer(image=ddf, ddf=ddf)\n+        return ddf\n", "issue": "DVF to DDF\n**Is your feature request related to a problem? Please describe.**\r\nThe current repository only supports warping based on DDF, but not on DVF.\r\n\r\n**Describe the solution you'd like**\r\nImplement a DVF to DDF transformation layer. So for models outputting DVF, we can first transform DVF to DDF and then used the existing Warp layer to resample input image based on the transformed DDF.\r\n\r\n**Describe alternatives you've considered**\r\nN/A\r\n\r\n**Additional context**\r\nDeepReg implementation of [IntDVF](https://github.com/DeepRegNet/DeepReg/blob/80854094feafec998fa6237199066556c73f31f9/deepreg/model/layer.py#L508-L535)\r\n\n", "before_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom .acti_norm import ADN\nfrom .activation import Mish, Swish\nfrom .aspp import SimpleASPP\nfrom .convolutions import Convolution, ResidualUnit\nfrom .downsample import MaxAvgPool\nfrom .dynunet_block import UnetBasicBlock, UnetOutBlock, UnetResBlock, UnetUpBlock, get_output_padding, get_padding\nfrom .fcn import FCN, GCN, MCFCN, Refine\nfrom .localnet_block import LocalNetDownSampleBlock, LocalNetFeatureExtractorBlock, LocalNetUpSampleBlock\nfrom .segresnet_block import ResBlock\nfrom .squeeze_and_excitation import (\n    ChannelSELayer,\n    ResidualSELayer,\n    SEBlock,\n    SEBottleneck,\n    SEResNetBottleneck,\n    SEResNeXtBottleneck,\n)\nfrom .upsample import SubpixelUpsample, Subpixelupsample, SubpixelUpSample, Upsample, UpSample\nfrom .warp import Warp\n", "path": "monai/networks/blocks/__init__.py"}, {"content": "from typing import List, Optional, Union\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\nfrom monai.utils import GridSamplePadMode\n\n\nclass Warp(nn.Module):\n    \"\"\"\n    Warp an image with given DDF.\n    \"\"\"\n\n    def __init__(\n        self,\n        spatial_dims: int,\n        mode: int = 1,\n        padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,\n    ):\n        \"\"\"\n        Args:\n            spatial_dims: {2, 3}. number of spatial dimensions\n            mode: interpolation mode to calculate output values, defaults to 1.\n                Possible values are::\n\n                    - 0 or 'nearest'    or InterpolationType.nearest\n                    - 1 or 'linear'     or InterpolationType.linear\n                    - 2 or 'quadratic'  or InterpolationType.quadratic\n                    - 3 or 'cubic'      or InterpolationType.cubic\n                    - 4 or 'fourth'     or InterpolationType.fourth\n                    - etc.\n            padding_mode: {``\"zeros\"``, ``\"border\"``, ``\"reflection\"``}\n                Padding mode for outside grid values. Defaults to ``\"border\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n        \"\"\"\n        super(Warp, self).__init__()\n        if spatial_dims not in [2, 3]:\n            raise ValueError(f\"got unsupported spatial_dims={spatial_dims}, only support 2-d and 3-d input\")\n        self.spatial_dims = spatial_dims\n        if mode < 0:\n            raise ValueError(f\"do not support negative mode, got mode={mode}\")\n        self.mode = mode\n        self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)\n\n    @staticmethod\n    def get_reference_grid(ddf: torch.Tensor) -> torch.Tensor:\n        mesh_points = [torch.arange(0, dim) for dim in ddf.shape[2:]]\n        grid = torch.stack(torch.meshgrid(*mesh_points), dim=0)  # (spatial_dims, ...)\n        grid = torch.stack([grid] * ddf.shape[0], dim=0)  # (batch, spatial_dims, ...)\n        grid = grid.to(ddf)\n        return grid\n\n    @staticmethod\n    def normalize_grid(grid: torch.Tensor) -> torch.Tensor:\n        # (batch, ..., self.spatial_dims)\n        for i, dim in enumerate(grid.shape[1:-1]):\n            grid[..., i] = grid[..., i] * 2 / (dim - 1) - 1\n        return grid\n\n    def forward(self, image: torch.Tensor, ddf: torch.Tensor) -> torch.Tensor:\n        \"\"\"\n        Args:\n            image: Tensor in shape (batch, num_channels, H, W[, D])\n            ddf: Tensor in the same spatial size as image, in shape (batch, spatial_dims, H, W[, D])\n\n        Returns:\n            warped_image in the same shape as image (batch, num_channels, H, W[, D])\n        \"\"\"\n        if len(image.shape) != 2 + self.spatial_dims:\n            raise ValueError(f\"expecting {self.spatial_dims + 2}-d input, \" f\"got input in shape {image.shape}\")\n        if len(ddf.shape) != 2 + self.spatial_dims or ddf.shape[1] != self.spatial_dims:\n            raise ValueError(\n                f\"expecting {self.spatial_dims + 2}-d ddf with {self.spatial_dims} channels, \"\n                f\"got ddf in shape {ddf.shape}\"\n            )\n        if image.shape[0] != ddf.shape[0] or image.shape[2:] != ddf.shape[2:]:\n            raise ValueError(\n                \"expecting image and ddf of same batch size and spatial size, \"\n                f\"got image of shape {image.shape}, ddf of shape {ddf.shape}\"\n            )\n\n        grid = self.get_reference_grid(ddf) + ddf\n        grid = grid.permute([0] + list(range(2, 2 + self.spatial_dims)) + [1])  # (batch, ..., self.spatial_dims)\n\n        if self.mode > 1:\n            raise ValueError(f\"{self.mode}-order interpolation not yet implemented.\")\n            # if not USE_COMPILED:\n            #     raise ValueError(f\"cannot perform {self.mode}-order interpolation without C compile.\")\n            # _padding_mode = self.padding_mode.value\n            # if _padding_mode == \"zeros\":\n            #     bound = 7\n            # elif _padding_mode == \"border\":\n            #     bound = 0\n            # else:\n            #     bound = 1\n            # warped_image: torch.Tensor = grid_pull(\n            #     image,\n            #     grid,\n            #     bound=bound,\n            #     extrapolate=True,\n            #     interpolation=self.mode,\n            # )\n        else:\n            grid = self.normalize_grid(grid)\n            index_ordering: List[int] = list(range(self.spatial_dims - 1, -1, -1))\n            grid = grid[..., index_ordering]  # z, y, x -> x, y, z\n            _interp_mode = \"bilinear\" if self.mode == 1 else \"nearest\"\n            warped_image = F.grid_sample(\n                image, grid, mode=_interp_mode, padding_mode=self.padding_mode.value, align_corners=True\n            )\n\n        return warped_image\n", "path": "monai/networks/blocks/warp.py"}], "after_files": [{"content": "# Copyright 2020 - 2021 MONAI Consortium\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#     http://www.apache.org/licenses/LICENSE-2.0\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nfrom .acti_norm import ADN\nfrom .activation import Mish, Swish\nfrom .aspp import SimpleASPP\nfrom .convolutions import Convolution, ResidualUnit\nfrom .downsample import MaxAvgPool\nfrom .dynunet_block import UnetBasicBlock, UnetOutBlock, UnetResBlock, UnetUpBlock, get_output_padding, get_padding\nfrom .fcn import FCN, GCN, MCFCN, Refine\nfrom .localnet_block import LocalNetDownSampleBlock, LocalNetFeatureExtractorBlock, LocalNetUpSampleBlock\nfrom .segresnet_block import ResBlock\nfrom .squeeze_and_excitation import (\n    ChannelSELayer,\n    ResidualSELayer,\n    SEBlock,\n    SEBottleneck,\n    SEResNetBottleneck,\n    SEResNeXtBottleneck,\n)\nfrom .upsample import SubpixelUpsample, Subpixelupsample, SubpixelUpSample, Upsample, UpSample\nfrom .warp import DVF2DDF, Warp\n", "path": "monai/networks/blocks/__init__.py"}, {"content": "from typing import List, Optional, Union\n\nimport torch\nfrom torch import nn\nfrom torch.nn import functional as F\n\nfrom monai.utils import GridSamplePadMode\n\n\nclass Warp(nn.Module):\n    \"\"\"\n    Warp an image with given DDF.\n    \"\"\"\n\n    def __init__(\n        self,\n        spatial_dims: int,\n        mode: int = 1,\n        padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,\n    ):\n        \"\"\"\n        Args:\n            spatial_dims: {2, 3}. number of spatial dimensions\n            mode: interpolation mode to calculate output values, defaults to 1.\n                Possible values are::\n\n                    - 0 or 'nearest'    or InterpolationType.nearest\n                    - 1 or 'linear'     or InterpolationType.linear\n                    - 2 or 'quadratic'  or InterpolationType.quadratic\n                    - 3 or 'cubic'      or InterpolationType.cubic\n                    - 4 or 'fourth'     or InterpolationType.fourth\n                    - etc.\n            padding_mode: {``\"zeros\"``, ``\"border\"``, ``\"reflection\"``}\n                Padding mode for outside grid values. Defaults to ``\"border\"``.\n                See also: https://pytorch.org/docs/stable/nn.functional.html#grid-sample\n        \"\"\"\n        super(Warp, self).__init__()\n        if spatial_dims not in [2, 3]:\n            raise ValueError(f\"got unsupported spatial_dims={spatial_dims}, only support 2-d and 3-d input\")\n        self.spatial_dims = spatial_dims\n        if mode < 0:\n            raise ValueError(f\"do not support negative mode, got mode={mode}\")\n        self.mode = mode\n        self.padding_mode: GridSamplePadMode = GridSamplePadMode(padding_mode)\n\n    @staticmethod\n    def get_reference_grid(ddf: torch.Tensor) -> torch.Tensor:\n        mesh_points = [torch.arange(0, dim) for dim in ddf.shape[2:]]\n        grid = torch.stack(torch.meshgrid(*mesh_points), dim=0)  # (spatial_dims, ...)\n        grid = torch.stack([grid] * ddf.shape[0], dim=0)  # (batch, spatial_dims, ...)\n        grid = grid.to(ddf)\n        return grid\n\n    @staticmethod\n    def normalize_grid(grid: torch.Tensor) -> torch.Tensor:\n        # (batch, ..., self.spatial_dims)\n        for i, dim in enumerate(grid.shape[1:-1]):\n            grid[..., i] = grid[..., i] * 2 / (dim - 1) - 1\n        return grid\n\n    def forward(self, image: torch.Tensor, ddf: torch.Tensor) -> torch.Tensor:\n        \"\"\"\n        Args:\n            image: Tensor in shape (batch, num_channels, H, W[, D])\n            ddf: Tensor in the same spatial size as image, in shape (batch, ``spatial_dims``, H, W[, D])\n\n        Returns:\n            warped_image in the same shape as image (batch, num_channels, H, W[, D])\n        \"\"\"\n        if len(image.shape) != 2 + self.spatial_dims:\n            raise ValueError(f\"expecting {self.spatial_dims + 2}-d input, \" f\"got input in shape {image.shape}\")\n        if len(ddf.shape) != 2 + self.spatial_dims or ddf.shape[1] != self.spatial_dims:\n            raise ValueError(\n                f\"expecting {self.spatial_dims + 2}-d ddf with {self.spatial_dims} channels, \"\n                f\"got ddf in shape {ddf.shape}\"\n            )\n        if image.shape[0] != ddf.shape[0] or image.shape[2:] != ddf.shape[2:]:\n            raise ValueError(\n                \"expecting image and ddf of same batch size and spatial size, \"\n                f\"got image of shape {image.shape}, ddf of shape {ddf.shape}\"\n            )\n\n        grid = self.get_reference_grid(ddf) + ddf\n        grid = grid.permute([0] + list(range(2, 2 + self.spatial_dims)) + [1])  # (batch, ..., self.spatial_dims)\n\n        if self.mode > 1:\n            raise ValueError(f\"{self.mode}-order interpolation not yet implemented.\")\n            # if not USE_COMPILED:\n            #     raise ValueError(f\"cannot perform {self.mode}-order interpolation without C compile.\")\n            # _padding_mode = self.padding_mode.value\n            # if _padding_mode == \"zeros\":\n            #     bound = 7\n            # elif _padding_mode == \"border\":\n            #     bound = 0\n            # else:\n            #     bound = 1\n            # warped_image: torch.Tensor = grid_pull(\n            #     image,\n            #     grid,\n            #     bound=bound,\n            #     extrapolate=True,\n            #     interpolation=self.mode,\n            # )\n        else:\n            grid = self.normalize_grid(grid)\n            index_ordering: List[int] = list(range(self.spatial_dims - 1, -1, -1))\n            grid = grid[..., index_ordering]  # z, y, x -> x, y, z\n            _interp_mode = \"bilinear\" if self.mode == 1 else \"nearest\"\n            warped_image = F.grid_sample(\n                image, grid, mode=_interp_mode, padding_mode=self.padding_mode.value, align_corners=True\n            )\n\n        return warped_image\n\n\nclass DVF2DDF(nn.Module):\n    \"\"\"\n    Layer calculates a dense velocity field (DVF) from a dense displacement field (DDF)\n    with scaling and squaring.\n\n    Adapted from:\n        DeepReg (https://github.com/DeepRegNet/DeepReg)\n\n    \"\"\"\n\n    def __init__(\n        self,\n        spatial_dims: int,\n        num_steps: int = 7,\n        mode: int = 1,\n        padding_mode: Optional[Union[GridSamplePadMode, str]] = GridSamplePadMode.ZEROS,\n    ):\n        super(DVF2DDF, self).__init__()\n        if num_steps <= 0:\n            raise ValueError(f\"expecting positive num_steps, got {num_steps}\")\n        self.num_steps = num_steps\n        self.warp_layer = Warp(spatial_dims=spatial_dims, mode=mode, padding_mode=padding_mode)\n\n    def forward(self, dvf):\n        \"\"\"\n        Args:\n            dvf: dvf to be transformed, in shape (batch, ``spatial_dims``, H, W[,D])\n\n        Returns:\n\n        \"\"\"\n        ddf: torch.Tensor = dvf / (2 ** self.num_steps)\n        for _ in range(self.num_steps):\n            ddf = ddf + self.warp_layer(image=ddf, ddf=ddf)\n        return ddf\n", "path": "monai/networks/blocks/warp.py"}]}