Blockstructured Adaptive Mesh Refinement in object-oriented C++
00001 #ifndef _included_GridData_2_h 00002 #define _included_GridData_2_h 00003 00009 #include "DAGHParams.h" 00010 #include "GridDataParams.h" 00011 00012 #ifdef DEBUG_PRINT_GD_MEMORY 00013 #include "DAGHMemoryTrace.h" 00014 #endif 00015 00016 #include "BBox.h" 00017 #include "Coords.h" 00018 #include "PackedGridDataBucket.h" 00019 00020 #ifdef DEBUG_PRINT 00021 #include "CommServer.h" 00022 #endif 00023 00024 #include "IndexGridData2.h" 00025 00026 #ifndef GridData 00027 #define GridData(dim) name2(GridData,dim) 00028 #endif 00029 00030 #ifndef gd_OperateRegion 00031 #define gd_OperateRegion(op) name2(gd_OperateRegion,op) 00032 #endif 00033 00034 #include "GDIterator.h" 00035 00045 template <class Type> class GridData(2) 00046 { 00047 BBox _bbox; 00048 Coords _extents; 00049 Coords _step; 00050 int _size; 00051 int _bottom; 00052 Type *_data; 00053 00054 public: 00055 GridData(2)(void); 00056 GridData(2)(BBox const &bbox); 00057 GridData(2)(int const i, int const j, 00058 int const ii, int const jj); 00059 GridData(2)(int const i, int const j, 00060 int const ii, int const jj, int const s); 00061 GridData(2)(int const i, int const j, 00062 int const ii, int const jj, 00063 int const s, int const ss); 00064 GridData(2)(BBox const &bbox, Type *databuf); 00065 GridData(2)(GridDataBucket<Type> &gdbkt); 00066 GridData(2)(GridDataBucket<Type> &gdbkt, int const n); 00067 /* A "psuedo" copy-constructor */ 00068 GridData(2) (GridData(2)<Type> const &other); 00069 00070 inline ~GridData(2)(void) 00071 { 00072 if (_data) { 00073 delete [] _data; 00074 #ifdef DEBUG_PRINT_GD_MEMORY 00075 DAGHMemoryTrace::free(sizeof(Type)*_size); 00076 #endif 00077 } 00078 } 00079 00080 void allocate(BBox const &bbox); 00081 void allocate(BBox const &bbox, Type *databuf); 00082 00083 inline void allocate(Type *databuf) 00084 { 00085 if (_data) { 00086 delete [] _data; _data = (Type*)0; 00087 #ifdef DEBUG_PRINT_GD_MEMORY 00088 DAGHMemoryTrace::free(sizeof(Type)*_size); 00089 #endif 00090 } 00091 _data = databuf; 00092 } 00093 00094 inline void deallocate() 00095 { 00096 if (_data) { 00097 delete [] _data; _data = (Type*)0; 00098 #ifdef DEBUG_PRINT_GD_MEMORY 00099 DAGHMemoryTrace::free(sizeof(Type)*_size); 00100 #endif 00101 } 00102 } 00103 inline void deallocate(Type*& databuf) 00104 { databuf = _data; _data = (Type*) 0; } 00105 00106 void* databuffer() { return ((void*) _data); } 00107 00108 /* Query funtions */ 00109 /* Define some inline functions for getting at region extents */ 00110 00111 inline const Coords& lower() const { return(_bbox.lower()); } 00112 inline const Coords& upper() const { return(_bbox.upper()); } 00113 inline const Coords& extents() const { return(_extents); } 00114 inline const Coords& stepsize() const { return(_step); } 00115 inline Coords lower() { return(_bbox.lower()); } 00116 inline Coords upper() { return(_bbox.upper()); } 00117 inline Coords extents() { return(_extents); } 00118 inline Coords stepsize() { return(_step); } 00119 inline int bottom() const { return(_bottom); } 00120 inline int lower(const int i) const { return(_bbox.lower(i)); } 00121 inline int upper(const int i) const { return(_bbox.upper(i)); } 00122 inline int extents(const int i) const { return(_extents(i)); } 00123 inline int stepsize(int const i) const { return(_step(i)); } 00124 inline const BBox& bbox() const { return(_bbox); } 00125 00126 inline int ok_to_index() { return(_data != (Type *) NULL); } 00127 inline int size() const { return(_size); } 00128 00129 inline int idx(const int i, const int j) const 00130 { return( _bottom+(i/_step(0)+_extents(0)*(j/_step(1))) ); } 00131 00132 inline const Type& operator () (const int i, const int j) const 00133 { assert(idx(i,j) >= 0 && idx(i,j) < _size); return(_data[idx(i,j)]); } 00134 inline Type& operator () (const int i, const int j) 00135 { assert(idx(i,j) >= 0 && idx(i,j) < _size); return(_data[idx(i,j)]); } 00136 00137 inline const Type& operator () (const Coords& c) const 00138 { assert(idx(c(0),c(1)) >= 0 && idx(c(0),c(1)) < _size); return(_data[idx(c(0),c(1))]); } 00139 inline Type& operator () (const Coords& c) 00140 { assert(idx(c(0),c(1)) >= 0 && idx(c(0),c(1)) < _size); return(_data[idx(c(0),c(1))]); } 00141 00142 inline const Type *ptr(const int i, const int j) const 00143 { assert(idx(i,j) >= 0 && idx(i,j) < _size); return(_data + idx(i,j)); } 00144 inline Type *ptr(const int i, const int j) 00145 { assert(idx(i,j) >= 0 && idx(i,j) < _size); return(_data + idx(i,j)); } 00146 00147 inline const Type *ptr(const Coords& c) const 00148 { assert(idx(c(0),c(1)) >= 0 && idx(c(0),c(1)) < _size); return(_data + idx(c(0),c(1))); } 00149 inline Type *ptr(const Coords& c) 00150 { assert(idx(c(0),c(1)) >= 0 && idx(c(0),c(1)) < _size); return(_data + idx(c(0),c(1))); } 00151 00152 inline const Type *data() const { return(_data); } 00153 inline Type *data() { return(_data); } 00154 00155 void fill(Type const &val); 00156 00157 /* Define the copy functions for communication between objects */ 00158 void copy(GridData(2)<Type> const &gd); 00159 void copy(GridData(2)<Type> const &gd, BBox const &where); 00160 void copy(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00161 00162 void copy(GridDataBucket<Type> const &gdbkt); 00163 void copy(GridDataBucket<Type> const &gdbkt, BBox const &where); 00164 void copy(GridDataBucket<Type> const &gdbkt, BBox const &to, 00165 BBox const &from); 00166 00167 void copy(GridDataBucket<Type> const &gdbkt, int const n); 00168 void copy(GridDataBucket<Type> const &gdbkt, int const n, BBox const &where); 00169 void copy(GridDataBucket<Type> const &gdbkt, int const n, BBox const &to, 00170 BBox const &from); 00171 00172 /* Linear interpolation */ 00173 void lin_interp(GridData(2)<Type> const &gd1, double const frac1, 00174 GridData(2)<Type> const &gd2, double const frac2, 00175 BBox const &where); 00176 inline void lin_interp(GridData(2)<Type> const &gd1, double const frac1, 00177 GridData(2)<Type> const &gd2, double const frac2) 00178 { GridData(2)<Type>::lin_interp(gd1,frac1,gd2,frac2,_bbox); } 00179 00180 /* first moment (i think) sum(q(i,j)*i) */ 00181 Type moment1(int const axis, BBox const &where); 00182 inline Type moment1(int const axis) 00183 { return (GridData(2)<Type>::moment1(axis,_bbox)); } 00184 00185 /* sum of squares - for calculating L2-norm */ 00186 double sumsqrd(BBox const &where); 00187 inline double sumsqrd() 00188 { return (GridData(2)<Type>::sumsqrd(_bbox)); } 00189 00190 /* sum of absolute values - for calculating L1-norm */ 00191 double sumabs(BBox const &where); 00192 inline double sumabs() 00193 { return (GridData(2)<Type>::sumabs(_bbox)); } 00194 00195 /* Maximum of absolute values - for calculating Loo-norm */ 00196 double maxabs(BBox const &where); 00197 inline double maxabs() 00198 { return (GridData(2)<Type>::maxabs(_bbox)); } 00199 00200 /* operator == */ 00201 BBox is_eq(Type const &val, BBox const &where); 00202 inline BBox is_eq(Type const &val) 00203 { return (GridData(2)<Type>::is_eq(val, _bbox)); } 00204 00205 BBox is_eq(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00206 inline BBox is_eq(GridData(2)<Type> const &gd) 00207 { return (GridData(2)<Type>::is_eq(gd, gd._bbox, gd._bbox)); } 00208 inline BBox is_eq(GridData(2)<Type> const &gd, BBox const &where) 00209 { return (GridData(2)<Type>::is_eq(gd, where, where)); } 00210 00211 /* operator != */ 00212 BBox is_neq(Type const &val, BBox const &where); 00213 inline BBox is_neq(Type const &val) 00214 { return (GridData(2)<Type>::is_neq(val, _bbox)); } 00215 00216 BBox is_neq(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00217 inline BBox is_neq(GridData(2)<Type> const &gd) 00218 { return (GridData(2)<Type>::is_neq(gd, gd._bbox, gd._bbox)); } 00219 inline BBox is_neq(GridData(2)<Type> const &gd, BBox const &where) 00220 { return (GridData(2)<Type>::is_neq(gd, where, where)); } 00221 00222 /* operator > */ 00223 BBox is_gt(Type const &val, BBox const &where); 00224 inline BBox is_gt(Type const &val) 00225 { return (GridData(2)<Type>::is_gt(val, _bbox)); } 00226 00227 BBox is_gt(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00228 inline BBox is_gt(GridData(2)<Type> const &gd) 00229 { return (GridData(2)<Type>::is_gt(gd, gd._bbox, gd._bbox)); } 00230 inline BBox is_gt(GridData(2)<Type> const &gd, BBox const &where) 00231 { return (GridData(2)<Type>::is_gt(gd, where, where)); } 00232 00233 /* operator >= */ 00234 BBox is_ge(Type const &val, BBox const &where); 00235 inline BBox is_ge(Type const &val) 00236 { return (GridData(2)<Type>::is_ge(val, _bbox)); } 00237 00238 BBox is_ge(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00239 inline BBox is_ge(GridData(2)<Type> const &gd) 00240 { return (GridData(2)<Type>::is_ge(gd, gd._bbox, gd._bbox)); } 00241 inline BBox is_ge(GridData(2)<Type> const &gd, BBox const &where) 00242 { return (GridData(2)<Type>::is_ge(gd, where, where)); } 00243 00244 /* operator < */ 00245 BBox is_lt(Type const &val, BBox const &where); 00246 inline BBox is_lt(Type const &val) 00247 { return (GridData(2)<Type>::is_lt(val, _bbox)); } 00248 00249 BBox is_lt(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00250 inline BBox is_lt(GridData(2)<Type> const &gd) 00251 { return (GridData(2)<Type>::is_lt(gd, gd._bbox, gd._bbox)); } 00252 inline BBox is_lt(GridData(2)<Type> const &gd, BBox const &where) 00253 { return (GridData(2)<Type>::is_lt(gd, where, where)); } 00254 00255 /* operator <= */ 00256 BBox is_le(Type const &val, BBox const &where); 00257 inline BBox is_le(Type const &val) 00258 { return (GridData(2)<Type>::is_le(val, _bbox)); } 00259 00260 BBox is_le(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00261 inline BBox is_le(GridData(2)<Type> const &gd) 00262 { return (GridData(2)<Type>::is_le(gd, gd._bbox, gd._bbox)); } 00263 inline BBox is_le(GridData(2)<Type> const &gd, BBox const &where) 00264 { return (GridData(2)<Type>::is_le(gd, where, where)); } 00265 00266 /* operator = */ 00267 void equals(Type const &val, BBox const &where); 00268 inline void equals(Type const &val) 00269 { GridData(2)<Type>::equals(val, _bbox); } 00270 00271 void equals(GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00272 inline void equals(GridData(2)<Type> const &gd) 00273 { GridData(2)<Type>::equals(gd, gd._bbox, gd._bbox); } 00274 inline void equals(GridData(2)<Type> const &gd, BBox const &where) 00275 { GridData(2)<Type>::equals(gd, where, where); } 00276 00277 /* operator += */ 00278 void plus (Type const &val, BBox const &where); 00279 inline void plus (Type const &val) 00280 { GridData(2)<Type>::plus(val, _bbox); } 00281 00282 void plus (GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00283 inline void plus (GridData(2)<Type> const &gd) 00284 { GridData(2)<Type>::plus(gd, gd._bbox, gd._bbox); } 00285 inline void plus (GridData(2)<Type> const &gd, BBox const &where) 00286 { GridData(2)<Type>::plus(gd, where, where); } 00287 00288 /* operator -= */ 00289 void minus (Type const &val, BBox const &where); 00290 inline void minus (Type const &val) 00291 { GridData(2)<Type>::minus(val, _bbox); } 00292 00293 void minus (GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00294 inline void minus (GridData(2)<Type> const &gd) 00295 { GridData(2)<Type>::minus(gd, gd._bbox, gd._bbox); } 00296 inline void minus (GridData(2)<Type> const &gd, BBox const &where) 00297 { GridData(2)<Type>::minus(gd, where, where); } 00298 00299 /* operator *= */ 00300 void multiply(Type const &val, BBox const &where); 00301 inline void multiply(Type const &val) 00302 { GridData(2)<Type>::multiply(val, _bbox); } 00303 00304 void multiply (GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00305 inline void multiply (GridData(2)<Type> const &gd) 00306 { GridData(2)<Type>::multiply(gd, gd._bbox, gd._bbox); } 00307 inline void multiply (GridData(2)<Type> const &gd, BBox const &where) 00308 { GridData(2)<Type>::multiply(gd, where, where); } 00309 00310 /* operator /= */ 00311 void divide (Type const &val, BBox const &where); 00312 inline void divide (Type const &val) 00313 { GridData(2)<Type>::divide(val, _bbox); } 00314 00315 void divide (GridData(2)<Type> const &gd, BBox const &to, BBox const &from); 00316 inline void divide (GridData(2)<Type> const &gd) 00317 { GridData(2)<Type>::divide(gd, gd._bbox, gd._bbox); } 00318 inline void divide (GridData(2)<Type> const &gd, BBox const &where) 00319 { GridData(2)<Type>::divide(gd, where, where); } 00320 00321 /**********************************************************************/ 00322 inline BBox operator == (Type const &val) 00323 { return (GridData(2)<Type>::is_eq(val, _bbox)); } 00324 inline BBox operator == (GridData(2)<Type> const &gd) 00325 { return (GridData(2)<Type>::is_eq(gd, gd._bbox, gd._bbox)); } 00326 00327 inline BBox operator != (Type const &val) 00328 { return (GridData(2)<Type>::is_neq(val, _bbox)); } 00329 inline BBox operator != (GridData(2)<Type> const &gd) 00330 { return (GridData(2)<Type>::is_neq(gd, gd._bbox, gd._bbox)); } 00331 00332 inline BBox operator > (Type const &val) 00333 { return (GridData(2)<Type>::is_gt(val, _bbox)); } 00334 inline BBox operator > (GridData(2)<Type> const &gd) 00335 { return (GridData(2)<Type>::is_gt(gd, gd._bbox, gd._bbox)); } 00336 00337 inline BBox operator >= (Type const &val) 00338 { return (GridData(2)<Type>::is_ge(val, _bbox)); } 00339 inline BBox operator >= (GridData(2)<Type> const &gd) 00340 { return (GridData(2)<Type>::is_ge(gd, gd._bbox, gd._bbox)); } 00341 00342 inline BBox operator < (Type const &val) 00343 { return (GridData(2)<Type>::is_lt(val, _bbox)); } 00344 inline BBox operator < (GridData(2)<Type> const &gd) 00345 { return (GridData(2)<Type>::is_lt(gd, gd._bbox, gd._bbox)); } 00346 00347 inline BBox operator <= (Type const &val) 00348 { return (GridData(2)<Type>::is_le(val, _bbox)); } 00349 inline BBox operator <= (GridData(2)<Type> const &gd) 00350 { return (GridData(2)<Type>::is_le(gd, gd._bbox, gd._bbox)); } 00351 00352 inline void operator = (Type const &val) 00353 { GridData(2)<Type>::equals(val, _bbox); } 00354 inline void operator = (GridData(2)<Type> const &gd) 00355 { GridData(2)<Type>::equals(gd, gd._bbox, gd._bbox); } 00356 00357 inline void operator += (Type const &val) 00358 { GridData(2)<Type>::plus(val, _bbox); } 00359 inline void operator += (GridData(2)<Type> const &gd) 00360 { GridData(2)<Type>::plus(gd, gd._bbox, gd._bbox); } 00361 00362 inline void operator -= (Type const &val) 00363 { GridData(2)<Type>::minus(val, _bbox); } 00364 inline void operator -= (GridData(2)<Type> const &gd) 00365 { GridData(2)<Type>::minus(gd, gd._bbox, gd._bbox); } 00366 00367 inline void operator *= (Type const &val) 00368 { GridData(2)<Type>::multiply(val, _bbox); } 00369 inline void operator *= (GridData(2)<Type> const &gd) 00370 { GridData(2)<Type>::multiply(gd, gd._bbox, gd._bbox); } 00371 00372 inline void operator /= (Type const &val) 00373 { GridData(2)<Type>::divide(val, _bbox); } 00374 inline void operator /= (GridData(2)<Type> const &gd) 00375 { GridData(2)<Type>::divide(gd, gd._bbox, gd._bbox); } 00376 /**********************************************************************/ 00377 00378 /**********************************************************************/ 00379 // Reduction Operations 00380 /**********************************************************************/ 00381 Type maxval (BBox const &where); 00382 inline Type maxval (void) 00383 { return (GridData(2)<Type>::maxval(_bbox)); } 00384 00385 Type minval (BBox const &where); 00386 inline Type minval (void) 00387 { return (GridData(2)<Type>::minval(_bbox)); } 00388 00389 Type sum (BBox const &where); 00390 inline Type sum (void) 00391 { return (GridData(2)<Type>::sum(_bbox)); } 00392 00393 Type product (BBox const &where); 00394 inline Type product (void) 00395 { return (GridData(2)<Type>::product(_bbox)); } 00396 /**********************************************************************/ 00397 00398 private: 00399 void gd_CopyRegion(GridData(2)<Type> const &gd, BBox const &to, 00400 BBox const &from, Coords const &step); 00401 void gdb_CopyRegion(GridDataBucket<Type> const &gdbkt, BBox const &to, 00402 BBox const &from, Coords const &step); 00403 void gdb_CopyRegion(GridDataBucket<Type> const &gdbkt, int const n, BBox const &to, 00404 BBox const &from, Coords const &step); 00405 00406 void gd_OperateRegion(is_eq)(Type const &val, BBox const &to, 00407 BBox const &from, Coords const &step, BBox &bb); 00408 void gd_OperateRegion(is_eq)(GridData(2)<Type> const &gd, BBox const &to, 00409 BBox const &from, Coords const &step, BBox &bb); 00410 00411 void gd_OperateRegion(is_neq)(Type const &val, BBox const &to, 00412 BBox const &from, Coords const &step, BBox &bb); 00413 void gd_OperateRegion(is_neq)(GridData(2)<Type> const &gd, BBox const &to, 00414 BBox const &from, Coords const &step, BBox &bb); 00415 00416 void gd_OperateRegion(is_gt)(Type const &val, BBox const &to, 00417 BBox const &from, Coords const &step, BBox &bb); 00418 void gd_OperateRegion(is_gt)(GridData(2)<Type> const &gd, BBox const &to, 00419 BBox const &from, Coords const &step, BBox &bb); 00420 00421 void gd_OperateRegion(is_ge)(Type const &val, BBox const &to, 00422 BBox const &from, Coords const &step, BBox &bb); 00423 void gd_OperateRegion(is_ge)(GridData(2)<Type> const &gd, BBox const &to, 00424 BBox const &from, Coords const &step, BBox &bb); 00425 00426 void gd_OperateRegion(is_lt)(Type const &val, BBox const &to, 00427 BBox const &from, Coords const &step, BBox &bb); 00428 void gd_OperateRegion(is_lt)(GridData(2)<Type> const &gd, BBox const &to, 00429 BBox const &from, Coords const &step, BBox &bb); 00430 00431 void gd_OperateRegion(is_le)(Type const &val, BBox const &to, 00432 BBox const &from, Coords const &step, BBox &bb); 00433 void gd_OperateRegion(is_le)(GridData(2)<Type> const &gd, BBox const &to, 00434 BBox const &from, Coords const &step, BBox &bb); 00435 00436 void gd_OperateRegion(equal)(Type const &val, BBox const &to, 00437 BBox const &from, Coords const &step); 00438 void gd_OperateRegion(equal)(GridData(2)<Type> const &gd, BBox const &to, 00439 BBox const &from, Coords const &step); 00440 00441 void gd_OperateRegion(plus)(Type const &val, BBox const &to, 00442 BBox const &from, Coords const &step); 00443 void gd_OperateRegion(plus)(GridData(2)<Type> const &gd, BBox const &to, 00444 BBox const &from, Coords const &step); 00445 00446 void gd_OperateRegion(minus)(Type const &val, BBox const &to, 00447 BBox const &from, Coords const &step); 00448 void gd_OperateRegion(minus)(GridData(2)<Type> const &gd, BBox const &to, 00449 BBox const &from, Coords const &step); 00450 00451 void gd_OperateRegion(mult)(Type const &val, BBox const &to, 00452 BBox const &from, Coords const &step); 00453 void gd_OperateRegion(mult)(GridData(2)<Type> const &gd, BBox const &to, 00454 BBox const &from, Coords const &step); 00455 00456 void gd_OperateRegion(div)(Type const &val, BBox const &to, 00457 BBox const &from, Coords const &step); 00458 void gd_OperateRegion(div)(GridData(2)<Type> const &gd, BBox const &to, 00459 BBox const &from, Coords const &step); 00460 00461 public: 00462 /* Perform efficient buffer packing/unpacking and data movement */ 00463 void PackRegion(Type *sendbuf, BBox const &from) const; 00464 void UnPackRegion(Type const *recvbuf, BBox const &to); 00465 00466 #if (!defined(Want_c_files) && (defined(RS6000) || defined(SPX))) 00467 friend ostream& operator << (ostream&, const GridData(2)<Type>&); 00468 friend ofstream& operator << (ofstream&, const GridData(2)<Type>&); 00469 friend ifstream& operator >> (ifstream&, GridData(2)<Type>&); 00470 friend strstream& operator << (strstream&, const GridData(2)<Type>&); 00471 friend strstream& operator >> (strstream&, GridData(2)<Type>&); 00472 #endif 00473 00474 }; 00475 00476 #if defined(Want_c_files) || (!defined(RS6000) && !defined(SPX)) 00477 #include "GridData2.c" 00478 #endif 00479 00480 /*********************************************************************/ 00481 template <class Type> 00482 inline Coords lower(GridData(2)<Type> &gd) { return(gd.lower()); } 00483 template <class Type> 00484 inline Coords upper(GridData(2)<Type> &gd) { return(gd.upper()); } 00485 template <class Type> 00486 inline Coords extents(GridData(2)<Type> &gd) { return(gd.extents()); } 00487 template <class Type> 00488 inline int lower(GridData(2)<Type> &gd, const int i) { return(gd.lower(i)); } 00489 template <class Type> 00490 inline int upper(GridData(2)<Type> &gd, const int i) { return(gd.upper(i)); } 00491 template <class Type> 00492 inline int extents(GridData(2)<Type> &gd, const int i) { return(gd.extents(i)); } 00493 template <class Type> 00494 inline BBox bbox(GridData(2)<Type> &gd) { return(gd.bbox()); } 00495 template <class Type> 00496 inline int size(GridData(2)<Type> &gd) { return(gd.size()); } 00497 template <class Type> 00498 inline Coords stepsize(GridData(2)<Type> &gd) { return(gd.stepsize()); } 00499 00500 #endif
Quickstart Users Guide Programmers Reference Installation Examples Download
AMROC Main Home Contactlast update: 06/01/04