CubeRat.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. (* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
  2. (* Version 1, Update 2 *)
  3. MODULE CubeRat; (** AUTHOR "fof"; PURPOSE "3D matrix object of type Real."; *)
  4. IMPORT SYSTEM, NbrInt, ArrayXdBytes, ArrayXd := ArrayXdRat, NbrRat, DataErrors, CubeInt, DataIO;
  5. CONST
  6. (** The version number used when reading/writing a cube to file. *)
  7. VERSION* = 1;
  8. TYPE
  9. Value* = ArrayXd.Value; Index* = LONGINT; Array* = ArrayXd.Array; IntValue = ArrayXd.IntValue; ArrayC* = ArrayXd.Array3;
  10. Map* = ArrayXd.Map;
  11. (** Type Cube is DataIO registered, instances of it can therefore be made persistent. *)
  12. Cube* = OBJECT (ArrayXd.Array)
  13. VAR lenx-, leny-, lenz-: LONGINT; (* lenx = nr.Columns, leny = nr.Rows *)
  14. ox-, oy-, oz-: LONGINT;
  15. Get-: PROCEDURE {DELEGATE} ( x, y, z: Index ): Value;
  16. (* override *)
  17. PROCEDURE AlikeX*( ): ArrayXdBytes.Array;
  18. VAR copy: Cube;
  19. BEGIN
  20. NEW( copy, origin[0], len[0], origin[1], len[1], origin[2], len[2] ); RETURN copy;
  21. END AlikeX;
  22. PROCEDURE NewRangeX*( neworigin, newlen: ArrayXdBytes.IndexArray; copydata: BOOLEAN );
  23. BEGIN
  24. IF LEN( newlen ) # 3 THEN HALT( 1001 ) END;
  25. NewRangeX^( neworigin, newlen, copydata );
  26. END NewRangeX;
  27. PROCEDURE ValidateCache*;
  28. BEGIN
  29. ValidateCache^;
  30. IF dim # 3 THEN HALT( 100 ) END;
  31. lenx := len[0]; leny := len[1]; lenz := len[2]; ox := origin[0]; oy := origin[1]; oz := origin[2];
  32. END ValidateCache;
  33. PROCEDURE SetBoundaryCondition*( c: SHORTINT ); (* called by new, load and directly *)
  34. BEGIN
  35. SetBoundaryCondition^( c );
  36. CASE c OF
  37. ArrayXd.StrictBoundaryC:
  38. Get := Get3;
  39. | ArrayXd.AbsorbingBoundaryC:
  40. Get := Get3BAbsorbing;
  41. | ArrayXd.PeriodicBoundaryC:
  42. Get := Get3BPeriodic;
  43. | ArrayXd.SymmetricOnBoundaryC:
  44. Get := Get3BSymmetricOnB
  45. | ArrayXd.SymmetricOffBoundaryC:
  46. Get := Get3BSymmetricOffB
  47. | ArrayXd.AntisymmetricOnBoundaryC:
  48. Get := Get3BAntisymmetricOnB
  49. | ArrayXd.AntisymmetricOffBoundaryC:
  50. Get := Get3BAntisymmetricOffB
  51. END;
  52. END SetBoundaryCondition;
  53. (** new *)
  54. PROCEDURE & New*( ox, w, oy, h, oz, d: LONGINT );
  55. BEGIN
  56. NewXdB( ArrayXdBytes.Array3( ox, oy, oz ), ArrayXdBytes.Array3( w, h, d ) );
  57. END New;
  58. PROCEDURE Alike*( ): Cube;
  59. VAR copy: ArrayXdBytes.Array;
  60. BEGIN
  61. copy := AlikeX(); RETURN copy( Cube );
  62. END Alike;
  63. PROCEDURE NewRange*( ox, w, oy, h, oz, d: LONGINT; copydata: BOOLEAN );
  64. BEGIN
  65. IF (w # len[0]) OR (h # len[1]) OR (d # len[2]) OR (ox # origin[0]) OR (oy # origin[1]) OR (oz # origin[2]) THEN
  66. NewRangeX^( ArrayXdBytes.Array3( ox, oy, oz ), ArrayXdBytes.Array3( w, h, d ), copydata )
  67. END;
  68. END NewRange;
  69. PROCEDURE Copy*( ): Cube;
  70. VAR res: ArrayXdBytes.Array;
  71. BEGIN
  72. res := CopyX(); RETURN res( Cube );
  73. END Copy;
  74. PROCEDURE Set*( x, y, z: Index; v: Value );
  75. BEGIN
  76. ArrayXdBytes.Set3( SELF, x, y, z, v );
  77. END Set;
  78. (** copy methods using the current boundary condition SELF.bc*)
  79. PROCEDURE CopyToVec*( dest: Array; dim: Index; srcx, srcy, srcz, destx, len: Index );
  80. VAR slen: ArrayXdBytes.IndexArray;
  81. BEGIN
  82. IF (dest.dim # 1) THEN HALT( 1003 ) END;
  83. slen := ArrayXdBytes.Index3( 1, 1, 1 ); slen[dim] := len;
  84. CopyToArray( dest, ArrayXdBytes.Index3( srcx, srcy, srcz ), slen, ArrayXdBytes.Index1( destx ),
  85. ArrayXdBytes.Index1( len ) );
  86. END CopyToVec;
  87. PROCEDURE CopyToMtx*( dest: Array; dimx, dimy: Index; srcx, srcy, srcz, destx, desty, lenx, leny: Index );
  88. VAR slen: ArrayXdBytes.IndexArray;
  89. BEGIN
  90. IF (dest.dim # 2) OR (dimx >= dimy) THEN HALT( 1005 ) END;
  91. slen := ArrayXdBytes.Index3( 1, 1, 1 ); slen[dimx] := lenx; slen[dimy] := leny;
  92. CopyToArray( dest, ArrayXdBytes.Index3( srcx, srcy, srcz ), slen, ArrayXdBytes.Index2( destx, desty ),
  93. ArrayXdBytes.Index2( lenx, leny ) );
  94. END CopyToMtx;
  95. PROCEDURE CopyToCube*( dest: Array; srcx, srcy, srcz, destx, desty, destz, lenx, leny, lenz: Index );
  96. VAR slen: ArrayXdBytes.IndexArray;
  97. BEGIN
  98. IF (dest.dim # 3) THEN HALT( 1005 ) END;
  99. slen := ArrayXdBytes.Index3( lenx, leny, lenz );
  100. CopyToArray( dest, ArrayXdBytes.Index3( srcx, srcy, srcz ), slen, ArrayXdBytes.Index3( destx, desty, destz ), slen );
  101. END CopyToCube;
  102. PROCEDURE CopyToHCube*( dest: Array; dimx, dimy, dimz: Index;
  103. srcx, srcy, srcz, destx, desty, destz, destt, lenx, leny, lenz: Index );
  104. VAR slen: ArrayXdBytes.IndexArray;
  105. BEGIN
  106. IF (dest.dim # 4) OR (dimx >= dimy) OR (dimy >= dimz) THEN HALT( 1005 ) END;
  107. slen := ArrayXdBytes.Index4( 1, 1, 1, 1 ); slen[dimx] := lenx; slen[dimy] := leny; slen[dimz] := lenz;
  108. CopyToArray( dest, ArrayXdBytes.Index3( srcx, srcy, srcz ), ArrayXdBytes.Index3( lenx, leny, lenz ),
  109. ArrayXdBytes.Index4( destx, desty, destz, destt ), slen );
  110. END CopyToHCube;
  111. PROCEDURE CopyTo1dArray*( VAR dest: ARRAY OF Value; sx, sy, sz, slenx, sleny, slenz: Index; dpos, dlen: LONGINT );
  112. VAR destm: ArrayXdBytes.ArrayMemoryStructure;
  113. BEGIN
  114. destm :=
  115. ArrayXdBytes.MakeMemoryStructure( 1, ArrayXdBytes.Index1( 0 ), ArrayXdBytes.Index1( LEN( dest ) ), SIZEOF( Value ),
  116. ADDRESSOF( dest[0] ) );
  117. ArrayXd.CopyArrayToArrayPartB( SELF, destm, bc, ArrayXdBytes.Index3( sx, sy, sz ),
  118. ArrayXdBytes.Index3( slenx, sleny, slenz ), ArrayXdBytes.Index1( dpos ),
  119. ArrayXdBytes.Index1( dlen ) );
  120. END CopyTo1dArray;
  121. PROCEDURE CopyTo2dArray*( VAR dest: ARRAY OF ARRAY OF Value; sx, sy, sz, slenx, sleny, slenz: Index;
  122. dposx, dposy, dlenx, dleny: LONGINT );
  123. VAR destm: ArrayXdBytes.ArrayMemoryStructure;
  124. BEGIN
  125. destm :=
  126. ArrayXdBytes.MakeMemoryStructure( 2, ArrayXdBytes.Index2( 0, 0 ), ArrayXdBytes.Index2( LEN( dest, 1 ), LEN( dest, 0 ) ),
  127. SIZEOF( Value ), ADDRESSOF( dest[0, 0] ) );
  128. ArrayXd.CopyArrayToArrayPartB( SELF, destm, bc, ArrayXdBytes.Index3( sx, sy, sz ),
  129. ArrayXdBytes.Index3( slenx, sleny, slenz ), ArrayXdBytes.Index2( dposx, dposy ),
  130. ArrayXdBytes.Index2( dlenx, dleny ) );
  131. END CopyTo2dArray;
  132. PROCEDURE CopyTo3dArray*( VAR dest: ARRAY OF ARRAY OF ARRAY OF Value; sx, sy, sz, slenx, sleny, slenz: Index;
  133. dposx, dposy, dposz, dlenx, dleny, dlenz: LONGINT );
  134. VAR destm: ArrayXdBytes.ArrayMemoryStructure;
  135. BEGIN
  136. destm :=
  137. ArrayXdBytes.MakeMemoryStructure( 3, ArrayXdBytes.Index3( 0, 0, 0 ),
  138. ArrayXdBytes.Index3( LEN( dest, 2 ), LEN( dest, 1 ), LEN( dest, 0 ) ), SIZEOF( Value ),
  139. ADDRESSOF( dest[0, 0, 0] ) );
  140. ArrayXd.CopyArrayToArrayPartB( SELF, destm, bc, ArrayXdBytes.Index3( sx, sy, sz ),
  141. ArrayXdBytes.Index3( slenx, sleny, slenz ),
  142. ArrayXdBytes.Index3( dposx, dposy, dposz ),
  143. ArrayXdBytes.Index3( dlenx, dleny, dlenz ) );
  144. END CopyTo3dArray;
  145. PROCEDURE CopyTo4dArray*( VAR dest: ARRAY OF ARRAY OF ARRAY OF ARRAY OF Value; sx, sy, sz, slenx, sleny, slenz: Index;
  146. dposx, dposy, dposz, dpost, dlenx, dleny, dlenz, dlent: LONGINT );
  147. VAR destm: ArrayXdBytes.ArrayMemoryStructure;
  148. BEGIN
  149. destm :=
  150. ArrayXdBytes.MakeMemoryStructure( 4, ArrayXdBytes.Index4( 0, 0, 0, 0 ),
  151. ArrayXdBytes.Index4( LEN( dest, 3 ), LEN( dest, 2 ), LEN( dest, 1 ), LEN( dest, 0 ) ), SIZEOF( Value ),
  152. ADDRESSOF( dest[0, 0, 0, 0] ) );
  153. ArrayXd.CopyArrayToArrayPartB( SELF, destm, bc, ArrayXdBytes.Index3( sx, sy, sz ),
  154. ArrayXdBytes.Index3( slenx, sleny, slenz ),
  155. ArrayXdBytes.Index4( dposx, dposy, dposz, dpost ),
  156. ArrayXdBytes.Index4( dlenx, dleny, dlenz, dlent ) );
  157. END CopyTo4dArray;
  158. (** copy from without boundary conditions *)
  159. PROCEDURE CopyFrom1dArray*( VAR src: ARRAY OF Value; spos, slen: Index; dx, dy, dz, dlenx, dleny, dlenz: Index );
  160. VAR srcm: ArrayXdBytes.ArrayMemoryStructure;
  161. BEGIN
  162. srcm :=
  163. ArrayXdBytes.MakeMemoryStructure( 1, ArrayXdBytes.Index1( 0 ), ArrayXdBytes.Index1( LEN( src ) ), SIZEOF( Value ),
  164. ADDRESSOF( src[0] ) );
  165. ArrayXdBytes.CopyArrayPartToArrayPart( srcm, SELF, ArrayXdBytes.Index1( spos ), ArrayXdBytes.Index1( slen ),
  166. ArrayXdBytes.Index3( dx, dy, dz ),
  167. ArrayXdBytes.Index3( dlenx, dleny, dlenz ) );
  168. END CopyFrom1dArray;
  169. PROCEDURE CopyFrom2dArray*( VAR src: ARRAY OF ARRAY OF Value; sposx, spoxy, slenx, sleny: Index;
  170. dx, dy, dz, dlenx, dleny, dlenz: Index );
  171. VAR srcm: ArrayXdBytes.ArrayMemoryStructure;
  172. BEGIN
  173. srcm :=
  174. ArrayXdBytes.MakeMemoryStructure( 2, ArrayXdBytes.Index2( 0, 0 ), ArrayXdBytes.Index2( LEN( src, 1 ), LEN( src, 0 ) ),
  175. SIZEOF( Value ), ADDRESSOF( src[0, 0] ) );
  176. ArrayXdBytes.CopyArrayPartToArrayPart( srcm, SELF, ArrayXdBytes.Index2( sposx, spoxy ),
  177. ArrayXdBytes.Index2( slenx, sleny ), ArrayXdBytes.Index3( dx, dy, dz ),
  178. ArrayXdBytes.Index3( dlenx, dleny, dlenz ) );
  179. END CopyFrom2dArray;
  180. PROCEDURE CopyFrom3dArray*( VAR src: ARRAY OF ARRAY OF ARRAY OF Value; sposx, spoxy, sposz, slenx, sleny, slenz: Index;
  181. dx, dy, dz, dlenx, dleny, dlenz: Index );
  182. VAR srcm: ArrayXdBytes.ArrayMemoryStructure;
  183. BEGIN
  184. srcm :=
  185. ArrayXdBytes.MakeMemoryStructure( 3, ArrayXdBytes.Index3( 0, 0, 0 ),
  186. ArrayXdBytes.Index3( LEN( src, 2 ), LEN( src, 1 ), LEN( src, 0 ) ), SIZEOF( Value ),
  187. ADDRESSOF( src[0, 0, 0] ) );
  188. ArrayXdBytes.CopyArrayPartToArrayPart( srcm, SELF, ArrayXdBytes.Index3( sposx, spoxy, sposz ),
  189. ArrayXdBytes.Index3( slenx, sleny, slenz ),
  190. ArrayXdBytes.Index3( dx, dy, dz ),
  191. ArrayXdBytes.Index3( dlenx, dleny, dlenz ) );
  192. END CopyFrom3dArray;
  193. PROCEDURE CopyFrom4dArray*( VAR src: ARRAY OF ARRAY OF ARRAY OF ARRAY OF Value;
  194. sposx, spoxy, sposz, spost, slenx, sleny, slenz, slent: Index;
  195. dx, dy, dz, dlenx, dleny, dlenz: Index );
  196. VAR srcm: ArrayXdBytes.ArrayMemoryStructure;
  197. BEGIN
  198. srcm :=
  199. ArrayXdBytes.MakeMemoryStructure( 4, ArrayXdBytes.Index4( 0, 0, 0, 0 ),
  200. ArrayXdBytes.Index4( LEN( src, 3 ), LEN( src, 2 ), LEN( src, 1 ), LEN( src, 0 ) ), SIZEOF( Value ),
  201. ADDRESSOF( src[0, 0, 0, 0] ) );
  202. ArrayXdBytes.CopyArrayPartToArrayPart( srcm, SELF, ArrayXdBytes.Index4( sposx, spoxy, sposz, spost ),
  203. ArrayXdBytes.Index4( slenx, sleny, slenz, slent ),
  204. ArrayXdBytes.Index3( dx, dy, dz ),
  205. ArrayXdBytes.Index3( dlenx, dleny, dlenz ) );
  206. END CopyFrom4dArray;
  207. END Cube;
  208. OPERATOR ":="*( VAR l: Cube; VAR r: ARRAY OF ARRAY OF ARRAY OF Value );
  209. BEGIN
  210. (* IF r = NIL THEN l := NIL; RETURN END; *)
  211. IF l = NIL THEN NEW( l, 0, LEN( r, 2 ), 0, LEN( r, 1 ), 0, LEN( r, 0 ) ); ELSE l.NewRange( 0, LEN( r, 2 ), 0, LEN( r, 1 ), 0, LEN( r, 0 ), FALSE ); END;
  212. ArrayXdBytes.CopyMemoryToArrayPart( ADDRESSOF( r[0, 0, 0] ), l, LEN( r, 0 ) * LEN( r, 1 ) * LEN( r, 2 ), NIL , NIL );
  213. END ":=";
  214. OPERATOR ":="*( VAR l: Cube; r: CubeInt.Cube );
  215. VAR i, last: LONGINT;
  216. BEGIN
  217. IF r = NIL THEN l := NIL ELSE
  218. IF l = NIL THEN NEW( l, r.origin[0], r.len[0], r.origin[1], r.len[1], r.origin[2], r.len[2] ); END;
  219. last := LEN( r.data ) - 1;
  220. FOR i := 0 TO last DO l.data[i] := r.data[i]; END;
  221. END;
  222. END ":=";
  223. OPERATOR ":="*( VAR l: Cube; r: Value );
  224. BEGIN
  225. IF l # NIL THEN ArrayXd.Fill( l, r ); END;
  226. END ":=";
  227. OPERATOR ":="*( VAR l: Cube; r: IntValue );
  228. VAR r1: Value;
  229. BEGIN
  230. r1 := r; l := r1;
  231. END ":=";
  232. OPERATOR "+"*( l, r: Cube ): Cube;
  233. VAR res: Cube;
  234. BEGIN
  235. res := l.Alike(); ArrayXd.Add( l, r, res ); RETURN res;
  236. END "+";
  237. OPERATOR "-"*( l, r: Cube ): Cube;
  238. VAR res: Cube;
  239. BEGIN
  240. res := l.Alike(); ArrayXd.Sub( l, r, res ); RETURN res;
  241. END "-";
  242. OPERATOR "+"*( l: Cube; r: Value ): Cube;
  243. VAR res: Cube;
  244. BEGIN
  245. res := l.Alike(); ArrayXd.AddAV( l, r, res ); RETURN res;
  246. END "+";
  247. OPERATOR "+"*( l: Cube; r: IntValue ): Cube;
  248. VAR res: Cube; r1: Value;
  249. BEGIN
  250. res := l.Alike(); r1 := r; ArrayXd.AddAV( l, r1, res ); RETURN res;
  251. END "+";
  252. OPERATOR "+"*( l: Value; r: Cube ): Cube;
  253. BEGIN
  254. RETURN r + l
  255. END "+";
  256. OPERATOR "+"*( l: IntValue; r: Cube ): Cube;
  257. BEGIN
  258. RETURN r + l
  259. END "+";
  260. OPERATOR "-"*( l: Cube; r: Value ): Cube;
  261. VAR res: Cube;
  262. BEGIN
  263. res := l.Alike(); ArrayXd.SubAV( l, r, res ); RETURN res;
  264. END "-";
  265. OPERATOR "-"*( l: Cube; r: IntValue ): Cube;
  266. VAR res: Cube; r1: Value;
  267. BEGIN
  268. res := l.Alike(); r1 := r; ArrayXd.SubAV( l, r1, res ); RETURN res;
  269. END "-";
  270. OPERATOR "-"*( l: Value; r: Cube ): Cube;
  271. VAR res: Cube;
  272. BEGIN
  273. res := r.Alike(); ArrayXd.SubVA( l, r, res ); RETURN res;
  274. END "-";
  275. OPERATOR "-"*( l: IntValue; r: Cube ): Cube;
  276. VAR res: Cube; l1: Value;
  277. BEGIN
  278. res := r.Alike(); l1 := l; ArrayXd.SubVA( l1, r, res ); RETURN res;
  279. END "-";
  280. OPERATOR "-"*( l: Cube ): Cube;
  281. BEGIN
  282. RETURN 0 - l;
  283. END "-";
  284. OPERATOR "*"*( l: Cube; r: Value ): Cube;
  285. VAR res: Cube;
  286. BEGIN
  287. res := l.Alike(); ArrayXd.MulAV( l, r, res ); RETURN res;
  288. END "*";
  289. OPERATOR "*"*( l: Cube; r: IntValue ): Cube;
  290. VAR res: Cube; r1: Value;
  291. BEGIN
  292. res := l.Alike(); r1 := r; ArrayXd.MulAV( l, r1, res ); RETURN res;
  293. END "*";
  294. OPERATOR "*"*( l: Value; r: Cube ): Cube;
  295. BEGIN
  296. RETURN r * l;
  297. END "*";
  298. OPERATOR "*"*( l: IntValue; r: Cube ): Cube;
  299. BEGIN
  300. RETURN r * l;
  301. END "*";
  302. OPERATOR "/"*( l: Cube; r: Value ): Cube;
  303. VAR res: Cube;
  304. BEGIN
  305. res := l.Alike(); ArrayXd.DivAV( l, r, res ); RETURN res;
  306. END "/";
  307. OPERATOR "/"*( l: Cube; r: IntValue ): Cube;
  308. VAR res: Cube; r1: Value;
  309. BEGIN
  310. res := l.Alike(); r1 := r; ArrayXd.DivAV( l, r1, res ); RETURN res;
  311. END "/";
  312. OPERATOR "/"*( l: Value; r: Cube ): Cube;
  313. VAR res: Cube;
  314. BEGIN
  315. res := r.Alike(); ArrayXd.DivVA( l, r, res ); RETURN res;
  316. END "/";
  317. OPERATOR "/"*( l: IntValue; r: Cube ): Cube;
  318. VAR res: Cube; l1: Value;
  319. BEGIN
  320. res := r.Alike(); l1 := l; ArrayXd.DivVA( l1, r, res ); RETURN res;
  321. END "/";
  322. (* The procedures needed to register type Cube so that its instances can be made persistent. *)
  323. PROCEDURE LoadCube( R: DataIO.Reader; VAR obj: OBJECT );
  324. VAR a: Cube; version: SHORTINT; ver: NbrInt.Integer;
  325. BEGIN
  326. R.RawSInt( version );
  327. IF version = -1 THEN
  328. obj := NIL (* Version tag is -1 for NIL. *)
  329. ELSIF version = VERSION THEN NEW( a, 0, 0, 0, 0, 0, 0 ); a.Read( R ); obj := a
  330. ELSE ver := version; DataErrors.IntError( ver, "Alien version number encountered." ); HALT( 1000 )
  331. END
  332. END LoadCube;
  333. PROCEDURE StoreCube( W: DataIO.Writer; obj: OBJECT );
  334. VAR a: Cube;
  335. BEGIN
  336. IF obj = NIL THEN W.RawSInt( -1 ) ELSE W.RawSInt( VERSION ); a := obj( Cube ); a.Write( W ) END
  337. END StoreCube;
  338. PROCEDURE Register;
  339. VAR a: Cube;
  340. BEGIN
  341. NEW( a, 0, 0, 0, 0, 0, 0 ); DataIO.PlugIn( a, LoadCube, StoreCube )
  342. END Register;
  343. (** Load and Store are procedures for external use that read/write an instance of Cube from/to a file. *)
  344. PROCEDURE Load*( R: DataIO.Reader; VAR obj: Cube );
  345. VAR ptr: OBJECT;
  346. BEGIN
  347. R.Object( ptr ); obj := ptr( Cube )
  348. END Load;
  349. PROCEDURE Store*( W: DataIO.Writer; obj: Cube );
  350. BEGIN
  351. W.Object( obj )
  352. END Store;
  353. BEGIN
  354. Register
  355. END CubeRat.