Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

# This file is part of the pyMOR project (http://www.pymor.org). 

# Copyright Holders: Rene Milk, Stephan Rave, Felix Schindler 

# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause) 

 

from __future__ import absolute_import, division, print_function 

 

import numpy as np 

 

from pymor.grids.interfaces import AffineGridInterface 

from pymor.grids.referenceelements import square 

 

 

class RectGrid(AffineGridInterface): 

    '''Basic implementation of a rectangular |Grid| on a rectangular domain. 

 

    The global face, edge and vertex indices are given as follows :: 

 

                 x1 

                 ^ 

                 | 

 

                 6--10---7--11---8 

                 |       |       | 

                 3   2   4   3   5 

                 |       |       | 

                 3---8---4---9---5 

                 |       |       | 

                 0   0   1   1   2 

                 |       |       | 

                 0---6---1---7---2  --> x0 

 

    Parameters 

    ---------- 

    num_intervals 

        Tuple `(n0, n1)` determining a grid with `n0` x `n1` codim-0 entities. 

    domain 

        Tuple `(ll, ur)` where `ll` defines the lower left and `ur` the upper right 

        corner of the domain. 

    ''' 

 

    dim = 2 

    dim_outer = 2 

    reference_element = square 

 

    def __init__(self, num_intervals=(2, 2), domain=[[0, 0], [1, 1]], 

                 identify_left_right=False, identify_bottom_top=False): 

        if identify_left_right: 

            assert num_intervals[0] > 1 

        if identify_bottom_top: 

            assert num_intervals[1] > 1 

        self.num_intervals = num_intervals 

        self.domain = np.array(domain) 

 

        self.x0_num_intervals = num_intervals[0] 

        self.x1_num_intervals = num_intervals[1] 

        self.x0_range = self.domain[:, 0] 

        self.x1_range = self.domain[:, 1] 

        self.x0_width = self.x0_range[1] - self.x0_range[0] 

        self.x1_width = self.x1_range[1] - self.x1_range[0] 

        self.x0_diameter = self.x0_width / self.x0_num_intervals 

        self.x1_diameter = self.x1_width / self.x1_num_intervals 

        self.diameter_max = max(self.x0_diameter, self.x1_diameter) 

        self.diameter_min = min(self.x0_diameter, self.x1_diameter) 

        n_elements = self.x0_num_intervals * self.x1_num_intervals 

        ni0, ni1 = num_intervals 

 

        # TOPOLOGY 

 

        # mapping of structured indices to global indices 

        structured_to_global_0 = np.arange(ni0 * ni1, dtype=np.int32).reshape((ni1, ni0)).swapaxes(0, 1) 

        structured_to_global_2 = (np.arange((ni0 + 1) * (ni1 + 1), dtype=np.int32) 

                                  .reshape(((ni1 + 1), (ni0 + 1))).swapaxes(0, 1)) 

        self._structured_to_global = [structured_to_global_0, None, structured_to_global_2] 

        global_to_structured_0 = np.empty((ni0 * ni1, 2), dtype=np.int32) 

        global_to_structured_0[:, 0] = np.tile(np.arange(ni0, dtype=np.int32), ni1) 

        global_to_structured_0[:, 1] = np.repeat(np.arange(ni1, dtype=np.int32), ni0) 

        global_to_structured_1 = np.empty(((ni0 + 1) * (ni1 + 1), 2), dtype=np.int32) 

        global_to_structured_1[:, 0] = np.tile(np.arange(ni0 + 1, dtype=np.int32), ni1 + 1) 

        global_to_structured_1[:, 1] = np.repeat(np.arange(ni1 + 1, dtype=np.int32), ni0 + 1) 

        self._global_to_structured = [global_to_structured_0, None, global_to_structured_1] 

 

        # calculate subentities -- codim-0 

        codim1_subentities = np.empty((ni1, ni0, 4), dtype=np.int32) 

        if identify_left_right: 

            codim1_subentities[:, :,  3] = np.arange(ni0 * ni1).reshape((ni1, ni0)) 

            codim1_subentities[:, :,  1] = codim1_subentities[:, :, 3] + 1 

            codim1_subentities[:, -1, 1] = codim1_subentities[:, 0, 3] 

        else: 

            codim1_subentities[:, :,  3] = (np.arange(ni0)[np.newaxis, :] + (np.arange(ni1) * (ni0 + 1))[:, np.newaxis]) 

            codim1_subentities[:, :,  1] = codim1_subentities[:, :, 3] + 1 

        offset = np.max(codim1_subentities[:, :, [1, 3]]) + 1 

        codim1_subentities[:, :, 0] = (np.arange(ni0 * ni1) + offset).reshape((ni1, ni0)) 

        codim1_subentities[:, :, 2] = codim1_subentities[:, :, 0] + num_intervals[0] 

        if identify_bottom_top: 

            codim1_subentities[-1, :, 2] = codim1_subentities[0, :, 0] 

        codim1_subentities = codim1_subentities.reshape((-1, 4)) 

 

        # calculate subentities -- codim-1 

        codim2_subentities = np.empty((ni1, ni0, 4), dtype=np.int32) 

        if identify_left_right: 

            codim2_subentities[:, :,  0] = np.arange(ni0 * ni1).reshape((ni1, ni0)) 

            codim2_subentities[:, :,  1] = codim2_subentities[:, :, 0] + 1 

            codim2_subentities[:, -1, 1] = codim2_subentities[:, 0, 0] 

            codim2_subentities[:, :,  3] = codim2_subentities[:, :, 0] + ni0 

            codim2_subentities[:, :,  2] = codim2_subentities[:, :, 1] + ni0 

        else: 

            codim2_subentities[:, :,  0] = (np.arange(ni0)[np.newaxis, :] + 

                                            (np.arange(ni1) * (ni0 + 1))[:, np.newaxis]) 

            codim2_subentities[:, :,  1] = codim2_subentities[:, :, 0] + 1 

            codim2_subentities[:, :,  3] = codim2_subentities[:, :, 0] + (ni0 + 1) 

            codim2_subentities[:, :,  2] = codim2_subentities[:, :, 0] + (ni0 + 2) 

        if identify_bottom_top: 

            codim2_subentities[-1, :, 3] = codim2_subentities[0, :, 0] 

            codim2_subentities[-1, :, 2] = codim2_subentities[0, :, 1] 

        codim2_subentities = codim2_subentities.reshape((-1, 4)) 

 

        self.__subentities = (codim1_subentities, codim2_subentities) 

 

        # calculate number of elements 

        self.__sizes = (n_elements, 

                        np.max(codim1_subentities) + 1, 

                        np.max(codim2_subentities) + 1) 

 

        # GEOMETRY 

 

        # embeddings 

        x0_shifts = np.arange(self.x0_num_intervals) * self.x0_diameter + self.x0_range[0] 

        x1_shifts = np.arange(self.x1_num_intervals) * self.x1_diameter + self.x1_range[0] 

        shifts = np.array(np.meshgrid(x0_shifts, x1_shifts)).reshape((2, -1)) 

        A = np.tile(np.diag([self.x0_diameter, self.x1_diameter]), (n_elements, 1, 1)) 

        B = shifts.T 

        self.__embeddings = (A, B) 

 

    def __str__(self): 

        return (('Rect-Grid on domain [{xmin},{xmax}] x [{ymin},{ymax}]\n' + 

                'x0-intervals: {x0ni}, x1-intervals: {x1ni}\n' + 

                'faces: {faces}, edges: {edges}, vertices: {vertices}') 

                .format(xmin=self.x0_range[0], xmax=self.x0_range[1], 

                        ymin=self.x1_range[0], ymax=self.x1_range[1], 

                        x0ni=self.x0_num_intervals, x1ni=self.x1_num_intervals, 

                        faces=self.size(0), edges=self.size(1), vertices=self.size(2))) 

 

    def size(self, codim=0): 

        assert 0 <= codim <= 2, 'Invalid codimension' 

        return self.__sizes[codim] 

 

    def subentities(self, codim, subentity_codim): 

        assert 0 <= codim <= 2, 'Invalid codimension' 

        assert codim <= subentity_codim <= self.dim, 'Invalid subentity codimensoin' 

        if codim == 0: 

            if subentity_codim == 0: 

                return np.arange(self.size(0), dtype='int32')[:, np.newaxis] 

            else: 

                return self.__subentities[subentity_codim - 1] 

        else: 

            return super(RectGrid, self).subentities(codim, subentity_codim) 

 

    def embeddings(self, codim=0): 

        if codim == 0: 

            return self.__embeddings 

        else: 

            return super(RectGrid, self).embeddings(codim) 

 

    def structured_to_global(self, codim): 

        '''Returns an array which maps structured indices to global codim-`codim` indices. 

 

        In other words `structed_to_global(codim)[i, j]` is the global index of the i-th in 

        x0-direction and j-th in x1-direction codim-`codim` entity of the grid. 

        ''' 

        if codim not in (0, 2): 

            raise NotImplementedError 

        return self._structured_to_global[codim] 

 

    def global_to_structured(self, codim): 

        '''Returns an array which maps global codim-`codim` indices to structured indices. 

 

        I.e. if `GTS = global_to_structured(codim)` and `STG = structured_to_global(codim)`, then 

        `STG[GTS[:, 0], GTS[:, 1]] == numpy.arange(size(codim))`. 

        ''' 

        if codim not in (0, 2): 

            raise NotImplementedError 

        return self._global_to_structured[codim] 

 

    def vertex_coordinates(self, dim): 

        '''Returns an array of the x_dim koordinates of the grid vertices. 

 

        I.e. :: 

 

           centers(2)[structured_to_global(2)[i, j]] == np.array([vertex_coordinates(0)[i], vertex_coordinates(1)[j]]) 

        ''' 

        assert 0 <= dim < 2 

        return np.linspace(self.domain[0, dim], self.domain[1, dim], self.num_intervals[dim] + 1) 

 

    @staticmethod 

    def test_instances(): 

        return [RectGrid((2, 4)),  RectGrid((1, 1)), RectGrid((42, 42)), 

                RectGrid((2, 4), identify_left_right=True), 

                RectGrid((2, 4), identify_bottom_top=True), 

                RectGrid((2, 4), identify_left_right=True, identify_bottom_top=True), 

                RectGrid((2, 1), identify_left_right=True), 

                RectGrid((1, 2), identify_bottom_top=True), 

                RectGrid((2, 2), identify_left_right=True, identify_bottom_top=True)]