SAGA API  v9.6
grid_memory.cpp
Go to the documentation of this file.
1 /**********************************************************
2  * Version $Id$
3  *********************************************************/
4 
6 // //
7 // SAGA //
8 // //
9 // System for Automated Geoscientific Analyses //
10 // //
11 // Application Programming Interface //
12 // //
13 // Library: SAGA_API //
14 // //
15 //-------------------------------------------------------//
16 // //
17 // grid_memory.cpp //
18 // //
19 // Copyright (C) 2005 by Olaf Conrad //
20 // //
21 //-------------------------------------------------------//
22 // //
23 // This file is part of 'SAGA - System for Automated //
24 // Geoscientific Analyses'. //
25 // //
26 // This library is free software; you can redistribute //
27 // it and/or modify it under the terms of the GNU Lesser //
28 // General Public License as published by the Free //
29 // Software Foundation, either version 2.1 of the //
30 // License, or (at your option) any later version. //
31 // //
32 // This library is distributed in the hope that it will //
33 // be useful, but WITHOUT ANY WARRANTY; without even the //
34 // implied warranty of MERCHANTABILITY or FITNESS FOR A //
35 // PARTICULAR PURPOSE. See the GNU Lesser General Public //
36 // License for more details. //
37 // //
38 // You should have received a copy of the GNU Lesser //
39 // General Public License along with this program; if //
40 // not, see <http://www.gnu.org/licenses/>. //
41 // //
42 //-------------------------------------------------------//
43 // //
44 // contact: Olaf Conrad //
45 // Institute of Geography //
46 // University of Goettingen //
47 // Goldschmidtstr. 5 //
48 // 37077 Goettingen //
49 // Germany //
50 // //
51 // e-mail: oconrad@saga-gis.org //
52 // //
54 
55 //---------------------------------------------------------
56 
57 
59 // //
60 // //
61 // //
63 
64 //---------------------------------------------------------
65 #include <memory.h>
66 
67 #include "grid.h"
68 #include "parameters.h"
69 
70 
72 // //
73 // Caching Options //
74 // //
76 
77 //---------------------------------------------------------
79 
80 //---------------------------------------------------------
82 {
83  return( gSG_Grid_Cache_Directory );
84 }
85 
86 //---------------------------------------------------------
87 void SG_Grid_Cache_Set_Directory(const SG_Char *Directory)
88 {
89  if( SG_Dir_Exists(Directory) )
90  {
91  gSG_Grid_Cache_Directory = Directory;
92  }
93 }
94 
95 
97 // //
99 
100 //---------------------------------------------------------
101 static int gSG_Grid_Cache_Mode = 0;
102 
103 //---------------------------------------------------------
105 {
106  gSG_Grid_Cache_Mode = Mode;
107 }
108 
109 //---------------------------------------------------------
111 {
112  return( gSG_Grid_Cache_Mode );
113 }
114 
115 
117 // //
119 
120 //---------------------------------------------------------
122 
123 //---------------------------------------------------------
125 {
126  if( nBytes >= 0 )
127  {
128  gSG_Grid_Cache_Threshold = nBytes;
129  }
130 }
131 
132 //---------------------------------------------------------
133 void SG_Grid_Cache_Set_Threshold_MB(double nMegabytes)
134 {
135  SG_Grid_Cache_Set_Threshold((int)(nMegabytes * N_MEGABYTE_BYTES));
136 }
137 
138 //---------------------------------------------------------
140 {
141  return( gSG_Grid_Cache_Threshold );
142 }
143 
144 //---------------------------------------------------------
146 {
147  return( (double)gSG_Grid_Cache_Threshold / (double)N_MEGABYTE_BYTES );
148 }
149 
150 
152 // //
153 // Memory //
154 // //
156 
157 //---------------------------------------------------------
158 bool CSG_Grid::_Memory_Create(bool bCached)
159 {
160  if( !m_System.is_Valid() || m_Type == SG_DATATYPE_Undefined )
161  {
162  return( false );
163  }
164 
165  _Memory_Destroy();
166 
167  if( bCached || _Cache_Check() )
168  {
169  return( _Cache_Create() );
170  }
171 
172  return( _Array_Create() );
173 }
174 
175 //---------------------------------------------------------
176 void CSG_Grid::_Memory_Destroy(void)
177 {
178  SG_FREE_SAFE(m_Index);
179 
180  if( is_Cached() )
181  {
182  _Cache_Destroy(false);
183  }
184 
185  _Array_Destroy();
186 }
187 
188 
190 // //
191 // Array //
192 // //
194 
195 //---------------------------------------------------------
196 bool CSG_Grid::_Array_Create(void)
197 {
198  if( m_System.is_Valid() && m_Type != SG_DATATYPE_Undefined )
199  {
200  _Array_Destroy();
201 
202  if( (m_Values = (void **)SG_Malloc(Get_NY() * sizeof(void *))) != NULL )
203  {
204  if( (m_Values[0] = (void *)SG_Calloc(Get_NY(), Get_nLineBytes())) != NULL )
205  {
206  char *pLine = (char *)m_Values[0];
207 
208  for(int y=0; y<Get_NY(); y++, pLine+=Get_nLineBytes())
209  {
210  m_Values[y] = pLine;
211  }
212 
213  return( true );
214  }
215 
216  SG_Free(m_Values);
217 
218  m_Values = NULL;
219  }
220 
221  SG_UI_Msg_Add_Error(CSG_String::Format("%s: %s [%.2fmb]", _TL("grid"), _TL("memory allocation failed"), (double)Get_NY() * Get_nLineBytes() / N_MEGABYTE_BYTES));
222  }
223 
224  return( false );
225 }
226 
227 //---------------------------------------------------------
228 void CSG_Grid::_Array_Destroy(void)
229 {
230  if( m_Values )
231  {
232  SG_Free(m_Values[0]);
233  SG_Free(m_Values);
234 
235  m_Values = NULL;
236  }
237 }
238 
239 
241 // //
242 // Cache //
243 // //
245 
246 //---------------------------------------------------------
247 #define CACHE_FILE_POS(x, y) (m_Cache_Offset + (m_Cache_bFlip ? Get_NY() - 1 - y : y) * m_nBytes_Line + x * m_nBytes_Value)
248 
249 //---------------------------------------------------------
250 #if defined(_SAGA_LINUX)
251 #define CACHE_FILE_SEEK fseek
252 #else
253 #define CACHE_FILE_SEEK _fseeki64
254 #endif
255 
256 //---------------------------------------------------------
257 bool CSG_Grid::Set_Cache(bool bOn)
258 {
259  if( bOn )
260  {
261  return( is_Cached()
262  || _Cache_Create(m_Cache_File , m_Type, m_Cache_Offset, m_Cache_bSwap, m_Cache_bFlip)
263  || _Cache_Create(SG_File_Make_Path("", Get_File_Name(), "dat"), m_Type, m_Cache_Offset, m_Cache_bSwap, m_Cache_bFlip)
264  || _Cache_Create(SG_File_Make_Path("", Get_File_Name(), "sdat"), m_Type, m_Cache_Offset, m_Cache_bSwap, m_Cache_bFlip)
265  || _Cache_Create()
266  );
267  }
268 
269  return( !is_Cached() || _Cache_Destroy(true) );
270 }
271 
272 
274 // //
276 
277 //---------------------------------------------------------
278 bool CSG_Grid::_Cache_Check(void)
279 {
280  sLong nBytes = m_System.Get_NCells() * Get_nValueBytes();
281 
282  if( SG_Grid_Cache_Get_Mode() > 0 && nBytes > SG_Grid_Cache_Get_Threshold() )
283  {
284  if( SG_Grid_Cache_Get_Mode() == 2 ) // confirm
285  {
286  CSG_String s;
287 
288  s.Printf("%s\n%s\n%s: %.2fMB",
289  _TL("Shall I activate file caching for new grid."),
290  m_System.Get_Name(),
291  _TL("Total memory size"),
292  (double)nBytes / (double)N_MEGABYTE_BYTES
293  );
294 
295  return( SG_UI_Dlg_Continue(s, _TL("Activate Grid File Cache?")) );
296  }
297 
298  return( true );
299  }
300 
301  return( false );
302 }
303 
304 
306 // //
308 
309 //---------------------------------------------------------
310 bool CSG_Grid::_Cache_Create(const CSG_String &File, TSG_Data_Type Data_Type, sLong Offset, bool bSwap, bool bFlip) // open existing file for caching
311 {
312  if( !m_System.is_Valid() || m_Type != Data_Type || !SG_File_Exists(File) )
313  {
314  return( false );
315  }
316 
317  if( (m_Cache_Stream = fopen(File, "r+b")) == NULL // read and write
318  && (m_Cache_Stream = fopen(File, "rb" )) == NULL ) // read only
319  {
320  return( false );
321  }
322 
323  m_Cache_File = File;
324  m_Cache_bTemp = false;
325  m_Cache_Offset = Offset;
326  m_Cache_bSwap = m_Type == SG_DATATYPE_Bit ? false : bSwap;
327  m_Cache_bFlip = bFlip;
328 
329  _Array_Destroy();
330 
331  return( true );
332 }
333 
334 //---------------------------------------------------------
335 bool CSG_Grid::_Cache_Create(void) // create temporary cache file
336 {
337  if( !m_System.is_Valid() || (m_Type == SG_DATATYPE_Undefined && is_Cached()) )
338  {
339  return( false );
340  }
341 
343 
344  if( (m_Cache_Stream = fopen(File, "w+b")) == NULL ) // read and write, create empty
345  {
346  return( false );
347  }
348 
349  m_Cache_File = File;
350  m_Cache_bTemp = true;
351  m_Cache_Offset = 0;
352  m_Cache_bSwap = false;
353  m_Cache_bFlip = false;
354 
355  CSG_Array Values(1, m_Values ? 0 : Get_nLineBytes()); // dummy
356 
357  for(int y=0; y<Get_NY() && SG_UI_Process_Set_Progress(y, Get_NY()); y++)
358  {
359  fwrite(m_Values ? m_Values[y] : Values.Get_Array(), 1, Get_nLineBytes(), m_Cache_Stream);
360  }
361 
363 
364  _Array_Destroy();
365 
366  return( true );
367 }
368 
369 //---------------------------------------------------------
370 bool CSG_Grid::_Cache_Destroy(bool bMemory_Restore)
371 {
372  if( is_Cached() )
373  {
374  if( bMemory_Restore && _Array_Create() && !CACHE_FILE_SEEK(m_Cache_Stream, m_Cache_Offset, SEEK_SET) )
375  {
376  for(int y=0; y<Get_NY() && SG_UI_Process_Set_Progress(y, Get_NY()); y++)
377  {
378  fread(m_Values[m_Cache_bFlip ? Get_NY() - 1 - y : y], 1, Get_nLineBytes(), m_Cache_Stream);
379 
380  if( m_Cache_bSwap )
381  {
382  char *pValue = (char *)m_Values[y];
383 
384  for(int x=0; x<Get_NX(); x++, pValue+=Get_nValueBytes())
385  {
386  _Swap_Bytes(pValue, Get_nValueBytes());
387  }
388  }
389  }
390 
392  }
393 
394  //-------------------------------------------------
395  fclose(m_Cache_Stream);
396 
397  m_Cache_Stream = NULL;
398 
399  if( m_Cache_bTemp )
400  {
401  SG_File_Delete(m_Cache_File);
402  }
403 
404  return( true );
405  }
406 
407  return( false );
408 }
409 
410 
412 // //
414 
415 //---------------------------------------------------------
416 void CSG_Grid::_Cache_Set_Value(int x, int y, double Value)
417 {
418  char Buffer[8];
419 
420  switch( m_Type )
421  {
422  case SG_DATATYPE_Float : (*(float *)Buffer) = (float )(Value); break;
423  case SG_DATATYPE_Double: (*(double *)Buffer) = (double )(Value); break;
424  case SG_DATATYPE_Byte : (*(BYTE *)Buffer) = SG_ROUND_TO_BYTE (Value); break;
425  case SG_DATATYPE_Char : (*(char *)Buffer) = SG_ROUND_TO_CHAR (Value); break;
426  case SG_DATATYPE_Word : (*(WORD *)Buffer) = SG_ROUND_TO_WORD (Value); break;
427  case SG_DATATYPE_Short : (*(short *)Buffer) = SG_ROUND_TO_SHORT(Value); break;
428  case SG_DATATYPE_DWord : (*(DWORD *)Buffer) = SG_ROUND_TO_DWORD(Value); break;
429  case SG_DATATYPE_Int : (*(int *)Buffer) = SG_ROUND_TO_INT (Value); break;
430  case SG_DATATYPE_Long : (*(sLong *)Buffer) = SG_ROUND_TO_SLONG(Value); break;
431 
432  default:
433  return;
434  }
435 
436  if( m_Cache_bSwap )
437  {
438  _Swap_Bytes(Buffer, Get_nValueBytes());
439  }
440 
441  if( !CACHE_FILE_SEEK(m_Cache_Stream, CACHE_FILE_POS(x, y), SEEK_SET) )
442  {
443  fwrite(Buffer, 1, Get_nValueBytes(), m_Cache_Stream);
444  }
445 }
446 
447 //---------------------------------------------------------
448 double CSG_Grid::_Cache_Get_Value(int x, int y) const
449 {
450  if( !CACHE_FILE_SEEK(m_Cache_Stream, CACHE_FILE_POS(x, y), SEEK_SET) )
451  {
452  char Buffer[8];
453 
454  if( fread(Buffer, 1, Get_nValueBytes(), m_Cache_Stream) == (size_t)Get_nValueBytes() )
455  {
456  switch( m_Type )
457  {
458  case SG_DATATYPE_Byte : return( (double)(*(BYTE *)Buffer) );
459  case SG_DATATYPE_Char : return( (double)(*(char *)Buffer) );
460  case SG_DATATYPE_Word : return( (double)(*(WORD *)Buffer) );
461  case SG_DATATYPE_Short : return( (double)(*(short *)Buffer) );
462  case SG_DATATYPE_DWord : return( (double)(*(DWORD *)Buffer) );
463  case SG_DATATYPE_Int : return( (double)(*(int *)Buffer) );
464  case SG_DATATYPE_Long : return( (double)(*(sLong *)Buffer) );
465  case SG_DATATYPE_Float : return( (double)(*(float *)Buffer) );
466  case SG_DATATYPE_Double: return( (double)(*(double *)Buffer) );
467 
468  default:
469  break;
470  }
471 
472  if( m_Cache_bSwap )
473  {
474  _Swap_Bytes(Buffer, Get_nValueBytes());
475  }
476  }
477  }
478 
479  return( 0.0 );
480 }
481 
482 
484 // //
485 // //
486 // //
488 
489 //---------------------------------------------------------
SG_DATATYPE_Int
@ SG_DATATYPE_Int
Definition: api_core.h:1000
SG_DATATYPE_Undefined
@ SG_DATATYPE_Undefined
Definition: api_core.h:1009
SG_FREE_SAFE
#define SG_FREE_SAFE(PTR)
Definition: api_core.h:205
CSG_String::Printf
int Printf(const char *Format,...)
Definition: api_string.cpp:308
_TL
#define _TL(s)
Definition: api_core.h:1489
SG_DATATYPE_DWord
@ SG_DATATYPE_DWord
Definition: api_core.h:999
SG_UI_Dlg_Continue
bool SG_UI_Dlg_Continue(const CSG_String &Message, const CSG_String &Caption)
Definition: api_callback.cpp:386
SG_ROUND_TO_INT
#define SG_ROUND_TO_INT(x)
Definition: mat_tools.h:155
SG_Dir_Exists
SAGA_API_DLL_EXPORT bool SG_Dir_Exists(const CSG_String &Directory)
Definition: api_file.cpp:743
CSG_Grid::Get_nLineBytes
int Get_nLineBytes(void) const
Definition: grid.h:524
SG_Malloc
SAGA_API_DLL_EXPORT void * SG_Malloc(size_t size)
Definition: api_memory.cpp:65
CSG_Grid::Get_nValueBytes
int Get_nValueBytes(void) const
Definition: grid.h:523
gSG_Grid_Cache_Mode
static int gSG_Grid_Cache_Mode
Definition: grid_memory.cpp:101
SG_DATATYPE_Byte
@ SG_DATATYPE_Byte
Definition: api_core.h:995
grid.h
CACHE_FILE_POS
#define CACHE_FILE_POS(x, y)
Definition: grid_memory.cpp:247
SG_ROUND_TO_SLONG
#define SG_ROUND_TO_SLONG(x)
Definition: mat_tools.h:158
SG_File_Delete
SAGA_API_DLL_EXPORT bool SG_File_Delete(const CSG_String &FileName)
Definition: api_file.cpp:856
SG_Free
SAGA_API_DLL_EXPORT void SG_Free(void *memblock)
Definition: api_memory.cpp:83
CSG_Grid::Set_Cache
bool Set_Cache(bool bOn)
Definition: grid_memory.cpp:257
SG_Calloc
SAGA_API_DLL_EXPORT void * SG_Calloc(size_t num, size_t size)
Definition: api_memory.cpp:71
SG_Grid_Cache_Get_Threshold
sLong SG_Grid_Cache_Get_Threshold(void)
Definition: grid_memory.cpp:139
SG_File_Exists
SAGA_API_DLL_EXPORT bool SG_File_Exists(const CSG_String &FileName)
Definition: api_file.cpp:850
CSG_Grid_System::Get_Name
const SG_Char * Get_Name(bool bShort=true)
Definition: grid_system.cpp:264
SG_DATATYPE_Long
@ SG_DATATYPE_Long
Definition: api_core.h:1002
SG_Grid_Cache_Set_Threshold_MB
void SG_Grid_Cache_Set_Threshold_MB(double nMegabytes)
Definition: grid_memory.cpp:133
sLong
signed long long sLong
Definition: api_core.h:158
CACHE_FILE_SEEK
#define CACHE_FILE_SEEK
Definition: grid_memory.cpp:253
SG_ROUND_TO_CHAR
#define SG_ROUND_TO_CHAR(x)
Definition: mat_tools.h:151
SG_ROUND_TO_WORD
#define SG_ROUND_TO_WORD(x)
Definition: mat_tools.h:152
CSG_Grid::Get_NY
int Get_NY(void) const
Definition: grid.h:538
SG_DATATYPE_Float
@ SG_DATATYPE_Float
Definition: api_core.h:1003
CSG_Data_Object::Get_File_Name
const SG_Char * Get_File_Name(bool bNative=true) const
Definition: dataobject.cpp:390
SG_Grid_Cache_Set_Threshold
void SG_Grid_Cache_Set_Threshold(int nBytes)
Definition: grid_memory.cpp:124
SG_ROUND_TO_BYTE
#define SG_ROUND_TO_BYTE(x)
Definition: mat_tools.h:150
SG_DATATYPE_Word
@ SG_DATATYPE_Word
Definition: api_core.h:997
parameters.h
CSG_String::Format
static CSG_String Format(const char *Format,...)
Definition: api_string.cpp:270
SG_Grid_Cache_Set_Mode
void SG_Grid_Cache_Set_Mode(int Mode)
Definition: grid_memory.cpp:104
SG_ROUND_TO_DWORD
#define SG_ROUND_TO_DWORD(x)
Definition: mat_tools.h:154
SG_Char
#define SG_Char
Definition: api_core.h:536
CSG_Array
Definition: api_core.h:308
CSG_String
Definition: api_core.h:563
gSG_Grid_Cache_Directory
static CSG_String gSG_Grid_Cache_Directory
Definition: grid_memory.cpp:78
CSG_Grid::Get_NX
int Get_NX(void) const
Definition: grid.h:537
SG_Grid_Cache_Get_Directory
const SG_Char * SG_Grid_Cache_Get_Directory(void)
Definition: grid_memory.cpp:81
SG_UI_Process_Set_Progress
bool SG_UI_Process_Set_Progress(int Position, int Range)
Definition: api_callback.cpp:255
N_MEGABYTE_BYTES
#define N_MEGABYTE_BYTES
Definition: mat_tools.h:115
SG_DATATYPE_Short
@ SG_DATATYPE_Short
Definition: api_core.h:998
SG_ROUND_TO_SHORT
#define SG_ROUND_TO_SHORT(x)
Definition: mat_tools.h:153
CSG_Grid::is_Cached
bool is_Cached(void) const
Definition: grid.h:607
SG_DATATYPE_Bit
@ SG_DATATYPE_Bit
Definition: api_core.h:994
SG_Grid_Cache_Get_Threshold_MB
double SG_Grid_Cache_Get_Threshold_MB(void)
Definition: grid_memory.cpp:145
SG_File_Get_Name_Temp
SAGA_API_DLL_EXPORT CSG_String SG_File_Get_Name_Temp(const CSG_String &Prefix)
Definition: api_file.cpp:862
SG_File_Make_Path
SAGA_API_DLL_EXPORT CSG_String SG_File_Make_Path(const CSG_String &Directory, const CSG_String &Name)
Definition: api_file.cpp:919
SG_Grid_Cache_Set_Directory
void SG_Grid_Cache_Set_Directory(const SG_Char *Directory)
Definition: grid_memory.cpp:87
SG_UI_Process_Set_Ready
bool SG_UI_Process_Set_Ready(void)
Definition: api_callback.cpp:305
TSG_Data_Type
TSG_Data_Type
Definition: api_core.h:993
SG_UI_Msg_Add_Error
void SG_UI_Msg_Add_Error(const char *Message)
Definition: api_callback.cpp:556
gSG_Grid_Cache_Threshold
static sLong gSG_Grid_Cache_Threshold
Definition: grid_memory.cpp:121
SG_DATATYPE_Char
@ SG_DATATYPE_Char
Definition: api_core.h:996
SG_Grid_Cache_Get_Mode
int SG_Grid_Cache_Get_Mode(void)
Definition: grid_memory.cpp:110
CSG_Grid_System::is_Valid
bool is_Valid(void) const
Definition: grid_system.cpp:258
CSG_Grid_System::Get_NCells
sLong Get_NCells(void) const
Definition: grid.h:236
SG_DATATYPE_Double
@ SG_DATATYPE_Double
Definition: api_core.h:1004