• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

csdms / bmi-example-python / 11444543281

21 Oct 2024 04:29PM UTC coverage: 92.784% (-0.3%) from 93.048%
11444543281

Pull #36

github

mcflugen
use np.float64 instead of np.float_
Pull Request #36: Add type annotations

70 of 71 new or added lines in 3 files covered. (98.59%)

1 existing line in 1 file now uncovered.

180 of 194 relevant lines covered (92.78%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/heat/heat.py
1
"""The 2D heat model."""
2
from __future__ import annotations
1✔
3

4
from io import TextIOBase
1✔
5

6
import numpy as np
1✔
7
import yaml
1✔
8
from numpy.typing import NDArray
1✔
9
from scipy import ndimage
1✔
10

11

12
def solve_2d(
1✔
13
    temp: NDArray[np.float64],
14
    spacing: tuple[float, ...],
15
    out: NDArray[np.float64] | None = None,
16
    alpha: float = 1.0,
17
    time_step: float = 1.0,
18
) -> NDArray[np.float64]:
19
    """Solve the 2D Heat Equation on a uniform mesh.
20

21
    Parameters
22
    ----------
23
    temp : ndarray
24
        Temperature.
25
    spacing : array_like
26
        Grid spacing in the row and column directions.
27
    out : ndarray (optional)
28
        Output array.
29
    alpha : float (optional)
30
        Thermal diffusivity.
31
    time_step : float (optional)
32
        Time step.
33

34
    Returns
35
    -------
36
    result : ndarray
37
        The temperatures after time *time_step*.
38

39
    Examples
40
    --------
41
    >>> from heat import solve_2d
42
    >>> z0 = np.zeros((3, 3))
43
    >>> z0[1:-1, 1:-1] = 1.
44
    >>> solve_2d(z0, (1., 1.), alpha=.25)
45
    array([[0. , 0. , 0. ],
46
           [0. , 0.5, 0. ],
47
           [0. , 0. , 0. ]])
48
    """
49
    dy2, dx2 = spacing[0] ** 2, spacing[1] ** 2
1✔
50
    stencil = (
1✔
51
        np.array([[0.0, dy2, 0.0], [dx2, -2.0 * (dx2 + dy2), dx2], [0.0, dy2, 0.0]])
52
        * alpha
53
        * time_step
54
        / (2.0 * (dx2 * dy2))
55
    )
56

57
    if out is None:
1✔
58
        out = np.empty_like(temp)
1✔
59

60
    ndimage.convolve(temp, stencil, output=out)
1✔
61
    out[(0, -1), :] = 0.0
1✔
62
    out[:, (0, -1)] = 0.0
1✔
63
    return np.add(temp, out, out=out)
1✔
64

65

66
class Heat:
1✔
67

68
    """Solve the Heat equation on a grid.
69

70
    Examples
71
    --------
72
    >>> heat = Heat()
73
    >>> heat.time
74
    0.0
75
    >>> heat.time_step
76
    0.25
77
    >>> heat.advance_in_time()
78
    >>> heat.time
79
    0.25
80

81
    >>> heat = Heat(shape=(5, 5))
82
    >>> heat.temperature = np.zeros_like(heat.temperature)
83
    >>> heat.temperature[2, 2] = 1.
84
    >>> heat.advance_in_time()
85

86
    >>> heat = Heat(alpha=.5)
87
    >>> heat.time_step
88
    0.5
89
    >>> heat = Heat(alpha=.5, spacing=(2., 3.))
90
    >>> heat.time_step
91
    2.0
92
    """
93

94
    def __init__(
1✔
95
        self,
96
        shape: tuple[int, int] = (10, 20),
97
        spacing: tuple[float, float] = (1.0, 1.0),
98
        origin: tuple[float, float] = (0.0, 0.0),
99
        alpha: float = 1.0,
100
    ) -> None:
101
        """Create a new heat model.
102

103
        Parameters
104
        ---------
105
        shape : array_like, optional
106
            The shape of the solution grid as (*rows*, *columns*).
107
        spacing : array_like, optional
108
            Spacing of grid rows and columns.
109
        origin : array_like, optional
110
            Coordinates of lower left corner of grid.
111
        alpha : float
112
            Alpha parameter in the heat equation.
113
        """
114
        self._shape = shape
1✔
115
        self._spacing = spacing
1✔
116
        self._origin = origin
1✔
117
        self._time = 0.0
1✔
118
        self._alpha = alpha
1✔
119
        self._time_step = min(spacing) ** 2 / (4.0 * self._alpha)
1✔
120

121
        self._temperature = np.random.random(self._shape)
1✔
122
        self._next_temperature = np.empty_like(self._temperature)
1✔
123

124
    @property
1✔
125
    def time(self) -> float:
1✔
126
        """Current model time."""
127
        return self._time
1✔
128

129
    @property
1✔
130
    def temperature(self) -> NDArray[np.float64]:
1✔
131
        """Temperature of the plate."""
132
        return self._temperature
1✔
133

134
    @temperature.setter
1✔
135
    def temperature(self, new_temp: float) -> None:
1✔
136
        """Set the temperature of the plate.
137

138
        Parameters
139
        ----------
140
        new_temp : array_like
141
            The new temperatures.
142
        """
143
        self._temperature[:] = new_temp
1✔
144

145
    @property
1✔
146
    def time_step(self) -> float:
1✔
147
        """Model time step."""
148
        return self._time_step
1✔
149

150
    @time_step.setter
1✔
151
    def time_step(self, time_step: float) -> None:
1✔
152
        """Set model time step."""
153
        self._time_step = time_step
1✔
154

155
    @property
1✔
156
    def shape(self) -> tuple[int, int]:
1✔
157
        """Shape of the model grid."""
158
        return self._shape
1✔
159

160
    @property
1✔
161
    def spacing(self) -> tuple[float, float]:
1✔
162
        """Spacing between nodes of the model grid."""
163
        return self._spacing
1✔
164

165
    @property
1✔
166
    def origin(self) -> tuple[float, float]:
1✔
167
        """Origin coordinates of the model grid."""
168
        return self._origin
1✔
169

170
    @classmethod
1✔
171
    def from_file_like(cls: type[Heat], file_like: TextIOBase) -> Heat:
1✔
172
        """Create a Heat object from a file-like object.
173

174
        Parameters
175
        ----------
176
        file_like : file_like
177
            Input parameter file.
178

179
        Returns
180
        -------
181
        Heat
182
            A new instance of a Heat object.
183
        """
184
        config = yaml.safe_load(file_like)
1✔
185
        return cls(**config)
1✔
186

187
    def advance_in_time(self) -> None:
1✔
188
        """Calculate new temperatures for the next time step."""
189
        solve_2d(
1✔
190
            self._temperature,
191
            self._spacing,
192
            out=self._next_temperature,
193
            alpha=self._alpha,
194
            time_step=self._time_step,
195
        )
196
        np.copyto(self._temperature, self._next_temperature)
1✔
197

198
        self._time += self._time_step
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc