1# -*- coding: utf-8 -*-
2#
3# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU Lesser General Public License as published
7# by the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU Lesser General Public License for more details.
14#
15# You should have received a copy of the GNU Lesser General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17#
18
19"""
20Rectilinear Grid Class for CSXCAD
21"""
22
23import numpy as np
24cimport CSRectGrid
25from Utilities import CheckNyDir
26from CSXCAD.SmoothMeshLines import SmoothMeshLines
27
28cdef class CSRectGrid:
29    """
30    Rectilinear Grid Class for CSXCAD. The grid can be defined e.g. as a Cartesian
31    or cylindrical mesh and can hold mesh lines in the 3 fundamental directions.
32    E.g. x,y and z for the Cartesian and rho, a and z for the cylindrical mesh.
33
34    :param CoordSystem: define the coordinate system (default 0 : Cartesian)
35    """
36    def __cinit__(self, *args, no_init=False, **kw):
37        self.no_init = no_init
38        if no_init==False:
39            self.thisptr = new _CSRectGrid()
40            if 'CoordSystem' in kw:
41                self.SetMeshType(kw['CoordSystem'])
42                del kw['CoordSystem']
43            elif 'cs_type' in kw:
44                self.SetMeshType(kw['cs_type'])
45                del kw['cs_type']
46        else:
47            self.thisptr = NULL
48
49        assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw)
50
51    def __dealloc__(self):
52        if not self.no_init:
53            del self.thisptr
54
55    def SetMeshType(self, cs_type):
56        """ SetMeshType(cs_type)
57
58        Set the coordinate system type (Cartesian or cylindrical) for this mesh.
59
60        :param cs_type: coordinate system (0 : Cartesian, 1 : Cylindrical)
61        """
62        assert cs_type in [CARTESIAN, CYLINDRICAL], 'Unknown coordinate system: {}'.format(cs_type)
63        self.thisptr.SetMeshType(cs_type)
64
65    def GetMeshType(self):
66        return self.thisptr.GetMeshType()
67
68    def SetLines(self, ny, lines):
69        """ SetLines(ny, lines)
70
71        Set an array of lines. This will clear all previous defined lines in
72        the given direction.
73
74        :param ny: int or str -- direction definition
75        :param lines: array -- list of lines to be set in the given direction
76        """
77        ny = CheckNyDir(ny)
78
79        assert len(lines)>0, 'SetLines: "lines" must be an array or list'
80        self.thisptr.ClearLines(ny)
81        for n in range(len(lines)):
82            self.thisptr.AddDiscLine(ny, lines[n])
83
84    def AddLine(self, ny, line):
85        """ AddLine(ny, lines)
86
87        Add an array of lines. This will *not* clear the previous defined lines in
88        the given direction.
89
90        :param ny: int or str -- direction definition
91        :param lines: array -- list of lines to be added in the given direction
92        """
93        ny = CheckNyDir(ny)
94        if np.isscalar(line):
95            self.thisptr.AddDiscLine(ny, line)
96            return
97        assert len(line)>0, 'AddLine: "lines" must be a float, array or list'
98        for n in range(len(line)):
99            self.thisptr.AddDiscLine(ny, line[n])
100
101    def GetQtyLines(self, ny):
102        """ GetQtyLines(ny)
103
104        :param ny: int or str -- direction definition
105        """
106        ny = CheckNyDir(ny)
107        return self.thisptr.GetQtyLines(ny)
108
109    def GetLine(self, ny, idx):
110        """ GetLine(ny, idx)
111
112        Get the line in a given direction `ny` and index
113
114        :param ny: int or str -- direction definition
115        :param idx: int  -- line index
116        """
117        ny = CheckNyDir(ny)
118        return self.thisptr.GetLine(ny, idx)
119
120    def GetLines(self, ny, do_sort=False):
121        """ GetLines(ny, do_sort=False)
122
123        Get all lines in a given direction `ny`.
124
125        :param ny: int or str -- direction definition
126        :param do_sort: bool  -- sort lines
127        """
128        ny = CheckNyDir(ny)
129        cdef unsigned int N = 0
130        cdef double* array = NULL
131        array = self.thisptr.GetLines(ny, array, N, do_sort)
132        lines = np.zeros(N)
133        for n in range(N):
134            lines[n] = array[n]
135        return lines
136
137    def ClearLines(self, ny):
138        """ ClearLines(ny)
139
140        Clear all lines in a given direction `ny`.
141
142        :param ny: int or str -- direction definition
143        """
144        ny = CheckNyDir(ny)
145        self.thisptr.ClearLines(ny)
146
147    def SmoothMeshLines(self, ny, max_res, ratio=1.5):
148        """ SmoothMeshLines(ny, max_res, ratio=1.5)
149
150        Smooth all mesh lines in the given direction with a max. allowed resolution.
151
152        :param ny: int or str -- direction definition or 'all' for all directions
153        :param max_res: float -- max. allowed resolution
154        :param ratio:   float -- max. allowed ration of mesh smoothing de/increase
155        """
156        if ny=='all':
157            for n in range(3):
158                self.SmoothMeshLines(n, max_res, ratio)
159        else:
160            lines = self.GetLines(ny)
161            lines = SmoothMeshLines(lines, max_res, ratio)
162            self.SetLines(ny, lines)
163
164    def Clear(self):
165        """
166        Clear all lines and delta unit.
167        """
168        self.thisptr.clear()
169
170    def SetDeltaUnit(self, unit):
171        """ SetDeltaUnit(unit)
172
173        Set the drawing unit for all mesh lines. Default is 1 (m)
174        """
175        self.thisptr.SetDeltaUnit(unit)
176
177    def GetDeltaUnit(self):
178        """
179        Get the drawing unit for all mesh lines.
180        """
181        return self.thisptr.GetDeltaUnit()
182
183    def Sort(self, ny='all'):
184        """ Sort(ny='all')
185
186        Sort mesh lines in the given direction or all directions.
187        """
188        if ny=='all':
189            for n in range(3):
190                self.thisptr.Sort(n)
191        else:
192            ny = CheckNyDir(ny)
193            self.thisptr.Sort(ny)
194
195    def Snap2LineNumber(self, ny, value):
196        """ Snap2LineNumber(ny, value)
197
198        Find a fitting mesh line index for the given direction and value.
199        """
200        ny = CheckNyDir(ny)
201        cdef bool inside=False
202        pos = self.thisptr.Snap2LineNumber(ny, value, inside)
203        return pos, inside>0
204
205    def GetSimArea(self):
206        """
207        Get the simulation area as defined by the mesh.
208
209        :returns: (2,3) array -- Simulation domain box
210        """
211        bb = np.zeros([2,3])
212        cdef double *_bb = self.thisptr.GetSimArea()
213        for n in range(3):
214            bb[0,n] = _bb[2*n]
215            bb[1,n] = _bb[2*n+1]
216        return bb
217
218    def IsValid(self):
219        """
220        Check if the mesh is valid. That is at least 2 mesh lines in all directions.
221        """
222        return self.thisptr.isValid()
223