Minor header fixes
[charm.git] / src / libs / ck-libs / ParFUM / ParFUM.h
1 /*Charm++ Finite Element Framework:
2 C interface file
3 */
4 #ifndef __PARFUM_H
5 #define __PARFUM_H
6 #include "charm++.h"
7 #include "pup_c.h"  /* for pup_er */
8 #include "idxlc.h"
9 #include "collidec.h"  // from collision framework
10 #include "charm-api.h"
11 #include "ckvector3d.h"
12 #include "tcharm.h"
13
14
15 // Forward declaration
16 class FEM_Entity;
17 class FEM_Mesh;
18 class FEM_Elem;
19 class FEM_Node;
20 class femMeshModify;
21 class FEM_Adapt_Algs;
22 class FEM_Adapt;
23 class FEM_AdaptL;
24 class IDXL_Chunk;
25 class l2g_t;
26 class FEM_ElemAdj_Layer;
27 class chunkListMsg;
28
29 /* BUG: this should not be used */
30 void _registerParFUM(void);
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 /* datatypes: keep in sync with ParFUMf.h and idxl */
37 #define FEM_BYTE   IDXL_BYTE
38 #define FEM_INT    IDXL_INT
39 #define FEM_REAL   IDXL_REAL
40 #define FEM_FLOAT FEM_REAL /*alias*/
41 #define FEM_DOUBLE IDXL_DOUBLE
42 #define FEM_INDEX_0  IDXL_INDEX_0
43 #define FEM_INDEX_1  IDXL_INDEX_1 
44 #define FEM_VAR_INDEX (IDXL_FIRST_DATATYPE+6)
45
46 /* reduction operations: keep in sync with ParFUMf.h */
47 #define FEM_SUM IDXL_SUM
48 #define FEM_PROD IDXL_PROD
49 #define FEM_MAX IDXL_MAX
50 #define FEM_MIN IDXL_MIN
51
52 /* element types, by their number of nodes */
53 #define FEM_TRIANGULAR    3
54 #define FEM_TETRAHEDRAL   4
55 #define FEM_HEXAHEDRAL    8
56 #define FEM_QUADRILATERAL 4
57
58 /* initialization flags */
59 #define FEM_INIT_READ    2
60 #define FEM_INIT_WRITE   4
61
62 #define FEM_MESH_OUTPUT 0
63 #define FEM_MESH_UPDATE 1
64 #define FEM_MESH_FINALIZE 2
65   typedef void (*FEM_Update_mesh_fn)(int userTag);
66   typedef void (*FEM_Update_mesh_fortran_fn)(int *userTag);
67
68   typedef void (*FEM_PupFn)(pup_er, void*);
69
70   typedef void (*FEM_Mesh_alloc_fn)(void *param,int *size,int *maxSize);
71   
72   /* This should be MPI_Comm, but I want it for Fortran too */
73   typedef int FEM_Comm_t; 
74
75   /* Initialize the FEM framework (must have called MPI_Init) */
76   void FEM_Init(FEM_Comm_t defaultCommunicator);
77   void FEM_Done(void);
78
79   /*Utility*/
80   int FEM_My_partition(void);
81   int FEM_Num_partitions(void);
82   double FEM_Timer(void);
83   void FEM_Print(const char *str);
84   void FEM_Print_partition(void);
85
86 /* Mesh manipulation */
87 #define FEM_MESH_FIRST 1650000000 /*This is the first mesh ID:*/
88   /* mesh creation */
89   int FEM_Mesh_allocate(void); /* build new mesh */
90   int FEM_Mesh_copy(int fem_mesh); /* copy existing mesh */
91   void FEM_Mesh_deallocate(int fem_mesh); /* delete this mesh */
92
93   int FEM_Mesh_read(const char *prefix,int partNo,int nParts);
94   void FEM_Mesh_write(int fem_mesh,const char *prefix,int partNo,int nParts); 
95
96   int FEM_Mesh_assemble(int nParts,const int *srcMeshes);
97   void FEM_Mesh_partition(int fem_mesh,int nParts,int *destMeshes);
98   
99   int FEM_Mesh_recv(int fromRank,int tag,FEM_Comm_t comm_context);
100   void FEM_Mesh_send(int fem_mesh,int toRank,int tag,FEM_Comm_t comm_context);
101
102   int FEM_Mesh_reduce(int fem_mesh,int toRank,FEM_Comm_t comm_context);
103   int FEM_Mesh_broadcast(int fem_mesh,int fromRank,FEM_Comm_t comm_context);
104
105   void FEM_Mesh_copy_globalno(int src_mesh,int dest_mesh);
106   void FEM_Mesh_print(int fem_mesh);
107   
108 /* Mesh entity codes: (keep in sync with ParFUMf.h) */
109 #define FEM_ENTITY_FIRST 1610000000 /*This is the first entity code:*/
110 #define FEM_NODE (FEM_ENTITY_FIRST+0) /*The unique node type*/
111 #define FEM_ELEM (FEM_ENTITY_FIRST+1000) /*First element type (can add the user-defined element type) */
112 #define FEM_ELEMENT FEM_ELEM /*alias*/
113 #define FEM_SPARSE (FEM_ENTITY_FIRST+2000) /* First sparse entity (face) type */
114 #define FEM_EDGE FEM_SPARSE /* alias */
115 #define FEM_FACE FEM_SPARSE /* alias */
116 #define FEM_GHOST 10000  /* (entity add-in) Indicates we want the ghost values, not real values */
117 #define FEM_ENTITY_LAST (FEM_ENTITY_FIRST+3000+FEM_GHOST)
118
119 /* Mesh entity "attributes": per-entity data */
120 #define FEM_DATA   0  /* Backward-compatability routines' solution data: tag 0 */
121 #define FEM_ATTRIB_TAG_MAX 1000000000 /*Largest allowable user "tag" attribute*/
122 #define FEM_ATTRIB_FIRST 1620000000 /*This is the first system attribute code: one of*/
123 #define FEM_CONN   (FEM_ATTRIB_FIRST+1) /* Element-node connectivity (FEM_ELEM or FEM_SPARSE, FEM_INDEX only) */
124 #define FEM_CONNECTIVITY FEM_CONN /*alias*/
125
126   /* rarely-used external attributes */
127 #define FEM_SPARSE_ELEM (FEM_ATTRIB_FIRST+2) /* Elements each sparse data record applies to (FEM_SPARSE, 2*FEM_INDEX only) */
128 #define FEM_COOR   (FEM_ATTRIB_FIRST+3) /* Node coordinates (FEM_NODE, FEM_DOUBLE only) */
129 #define FEM_COORD FEM_COOR /*alias*/
130 #define FEM_COORDINATES FEM_COOR /*alias*/
131 #define FEM_GLOBALNO  (FEM_ATTRIB_FIRST+4) /* Global item numbers (width=1, datatype=FEM_INDEX) */
132 #define FEM_PARTITION (FEM_ATTRIB_FIRST+5) /* Destination chunk numbers (elements only; width=1, datatype=FEM_INDEX) */
133 #define FEM_SYMMETRIES (FEM_ATTRIB_FIRST+6) /* Symmetries present (width=1, datatype=FEM_BYTE) */
134 #define FEM_NODE_PRIMARY (FEM_ATTRIB_FIRST+7) /* This chunk owns this node (nodes only; width=1, datatype=FEM_BYTE) */
135 #define FEM_CHUNK (FEM_ATTRIB_FIRST+8) /* For Nodes and Elements. Used during ghost creation
136 to mark the chunk to which a ghost node or element belongs datatype=FEM_INDEX*/
137 #define FEM_BOUNDARY (FEM_ATTRIB_FIRST+9) /*provides the boundary flag for nodes, elements and sparse elements FEM_INT*/
138 #define FEM_NODE_ELEM_ADJACENCY (FEM_ATTRIB_FIRST+10) /*node to element adjacency FEM_VAR_INDEX only */
139 #define FEM_NODE_NODE_ADJACENCY (FEM_ATTRIB_FIRST+11) /*node to node adjacency FEM_VAR_INDEX only */
140 #define FEM_ELEM_ELEM_ADJACENCY (FEM_ATTRIB_FIRST+12) /*element to element adjacency FEM_VAR_INDEX only */
141 #define FEM_ELEM_ELEM_ADJ_TYPES (FEM_ATTRIB_FIRST+13) /*stores element types for those element id's listed in 
142                                                                                                                 FEM_ELEM_ELEM_ADJACENCY, needed when using 
143                                                                                                                 multiple element types*/
144 #define FEM_IS_VALID_ATTR (FEM_ATTRIB_FIRST+14) /* Stores a flag(an IDXL_BYTE) for each element or node specifying whether the entity 
145                                                                                    exists or is valid. It may be 0 whenever a mesh modification occurs that deletes the 
146                                                                                    corresponding node or element */
147
148 #define FEM_MESH_SIZING (FEM_ATTRIB_FIRST+15) /* Target edge length attr. */
149 #define FEM_ATTRIB_LAST (FEM_ATTRIB_FIRST+16) /*This is the last valid attribute code*/
150
151   /* Specialized routines: */
152   void FEM_Mesh_set_conn(int fem_mesh,int entity,
153         const int *conn, int firstItem, int length, int width);
154   void FEM_Mesh_get_conn(int fem_mesh,int entity,
155         int *conn, int firstItem, int length, int width);
156
157   void FEM_Mesh_set_data(int fem_mesh,int entity,int attr,
158         const void *data, int firstItem, int length, int datatype,int width);
159   void FEM_Mesh_get_data(int fem_mesh,int entity,int attr,
160         void *data, int firstItem, int length, int datatype,int width);
161   void FEM_Mesh_conn(int fem_mesh,int entity,
162         int *conn, int firstItem, int length, int width);
163   
164   int FEM_Mesh_get_length(int fem_mesh,int entity);
165   
166   /* General purpose routines: */
167   void FEM_Mesh_data(int fem_mesh,int entity,int attr,
168         void *data, int firstItem, int length, int datatype,int width);
169   void FEM_Mesh_data_layout(int fem_mesh,int entity,int attr,
170         void *data, int firstItem, int length, IDXL_Layout_t layout);
171   void FEM_Mesh_data_offset(int fem_mesh,int entity,int attr,
172         void *data, int firstItem, int length, 
173         int type,int width, int offsetBytes,int distanceBytes,int skewBytes);
174         
175   void FEM_Register_array(int fem_mesh,int entity,int attr,
176                           void *data, int datatype,int width);
177
178   void FEM_Register_array_layout(int fem_mesh,int entity,int attr,      
179                                  void *data, IDXL_Layout_t layout);     
180   
181   //TODO:add the most important parameter.. the function pointer to the resize function
182   void FEM_Register_entity(int fem_mesh,int entity,void *data,int len,int max,FEM_Mesh_alloc_fn fn);    
183   
184   void FEM_Mesh_set_length(int fem_mesh,int entity,int newLength);
185   int FEM_Mesh_get_width(int fem_mesh,int entity,int attr);
186   void FEM_Mesh_set_width(int fem_mesh,int entity,int attr,int newWidth);
187   int FEM_Mesh_get_datatype(int fem_mesh,int entity,int attr);
188   int FEM_Mesh_get_entities(int fem_mesh, int *entities);
189   int FEM_Mesh_get_attributes(int fem_mesh,int entity,int *attributes);
190   
191   const char *FEM_Get_entity_name(int entity,char *storage);
192   const char *FEM_Get_attr_name(int attr,char *storage);
193   const char *FEM_Get_datatype_name(int datatype,char *storage);
194
195   int FEM_Mesh_is_get(int fem_mesh); /* return 1 if this is a readable mesh */
196   int FEM_Mesh_is_set(int fem_mesh); /* return 1 if this is a writing mesh */
197   void FEM_Mesh_become_get(int fem_mesh); /* Make this a readable mesh */
198   void FEM_Mesh_become_set(int fem_mesh); /* Make this a writing mesh */
199
200   typedef void (*FEM_Userdata_fn)(pup_er p,void *data);
201   void FEM_Mesh_pup(int fem_mesh,int dataTag,FEM_Userdata_fn fn,void *data);
202
203 /* ghosts and spatial symmetries */
204 #define FEM_Is_ghost_index(idx) ((idx)<-1)
205 #define FEM_To_ghost_index(idx) (-(idx)-2)
206 #define FEM_From_ghost_index(idx) (-(idx)-2)
207
208   void FEM_Add_ghost_layer(int nodesPerTuple,int doAddNodes);
209   void FEM_Add_ghost_elem(int elType,int tuplesPerElem,const int *elem2tuple);
210
211   void FEM_Add_ghost_stencil(int nElts,int addNodes,
212         const int *ends,const int *adj);
213   void FEM_Add_ghost_stencil_type(int elType,int nElts,int addNodes,
214         const int *ends,const int *adj2);
215
216   void FEM_Add_elem2face_tuples(int fem_mesh, int elem_type, int nodesPerTuple, int tuplesPerElem,const int *elem2tuple);
217
218   void FEM_Add_linear_periodicity(int nFaces,int nPer,
219         const int *facesA,const int *facesB,
220         int nNodes,const double *nodeLocs);
221   void FEM_Sym_coordinates(int who,double *d_locs);
222   
223   void FEM_Set_sym_nodes(const int *canon,const int *sym);
224   void FEM_Get_sym(int who,int *destSym);
225   /**
226     Based on shared node communication list, compute 
227     FEM_NODE FEM_GLOBALNO and FEM_NODE_PRIMARY
228   */
229   void FEM_Make_node_globalno(int fem_mesh,FEM_Comm_t comm_context);
230
231 /* Communication: see idxlc.h */
232   IDXL_Layout_t FEM_Create_simple_field(int base_type,int vec_len);
233   IDXL_Layout_t FEM_Create_field(int base_type, int vec_len, int init_offset, 
234                        int distance);
235   
236   IDXL_t FEM_Comm_shared(int fem_mesh,int entity);
237   IDXL_t FEM_Comm_ghost(int fem_mesh,int entity);
238
239   void FEM_Get_roccom_pconn_size(int fem_mesh,int *total_len,int *ghost_len);
240   void FEM_Get_roccom_pconn(int fem_mesh,const int *paneFmChunk,int *pconn);
241   void FEM_Set_roccom_pconn(int fem_mesh,const int *paneFmChunk,const int *src,int total_len,int ghost_len);
242
243   /*Migration */
244   int FEM_Register(void *userData,FEM_PupFn _pup_ud);
245   void FEM_Migrate(void);
246   void *FEM_Get_userdata(int n);
247   
248   void FEM_Barrier(void);
249   
250   /* to be provided by the application */
251   void init(void);
252   void driver(void);
253   
254   /* Create additional mesh adjacency information */
255   void FEM_Mesh_create_node_elem_adjacency(int fem_mesh);
256   void FEM_Mesh_create_node_node_adjacency(int fem_mesh);
257   void FEM_Mesh_create_elem_elem_adjacency(int fem_mesh);
258
259   void FEM_Print_n2n(int mesh, int nodeid);
260   void FEM_Print_n2e(int mesh, int nodeid);
261   void FEM_Print_e2e(int mesh, int eid);
262   void FEM_Print_e2n(int mesh, int eid);
263
264   /* Create and modify the FEM_IS_VALID Attribute */
265   void FEM_Mesh_allocate_valid_attr(int fem_mesh, int entity_type);
266   void FEM_set_entity_valid(int mesh, int entityType, int entityIdx);
267   void FEM_set_entity_invalid(int mesh, int entityType, int entityIdx);
268   int FEM_is_valid(int mesh, int entityType, int entityIdx);
269   unsigned int FEM_count_valid(int mesh, int entityType);
270
271   /* Easy set method for coordinates, that may be helpful when creating a mesh */
272   void FEM_set_entity_coord2(int mesh, int entityType, int entityIdx, double x, double y);
273   void FEM_set_entity_coord3(int mesh, int entityType, int entityIdx, double x, double y, double z);
274   
275
276   /* Backward compatability routines: */
277   int FEM_Mesh_default_read(void);  /* return mesh used for get calls below */
278   int FEM_Mesh_default_write(void); /* return mesh used for set calls below */
279   void FEM_Mesh_set_default_read(int fem_mesh);
280   void FEM_Mesh_set_default_write(int fem_mesh);
281   
282   void FEM_Exchange_ghost_lists(int who,int nIdx,const int *localIdx);
283   int FEM_Get_ghost_list_length(void);
284   void FEM_Get_ghost_list(int *dest);
285
286   void FEM_Update_field(int fid, void *nodes);
287   void FEM_Update_ghost_field(int fid, int elTypeOrMinusOne, void *nodes);
288   void FEM_Reduce_field(int fid, const void *nodes, void *outbuf, int op);
289   void FEM_Reduce(int fid, const void *inbuf, void *outbuf, int op);
290   
291   void FEM_Read_field(int fid, void *nodes, const char *fname);
292
293   void FEM_Set_node(int nNodes,int doublePerNode);
294   void FEM_Set_node_data(const double *data);
295   void FEM_Set_elem(int elType,int nElem,int doublePerElem,int nodePerElem);
296   void FEM_Set_elem_data(int elType,const double *data);
297   void FEM_Set_elem_conn(int elType,const int *conn);
298   void FEM_Set_sparse(int uniqueIdentifier,int nRecords,
299         const int *nodes,int nodesPerRec,
300         const void *data,int dataPerRec,int dataType);
301   void FEM_Set_sparse_elem(int uniqueIdentifier,const int *rec2elem);
302
303   void FEM_Get_node(int *nNodes,int *doublePerNode);
304   void FEM_Get_node_data(double *data);
305   void FEM_Get_elem(int elType,int *nElem,int *doublePerElem,int *nodePerElem);
306   void FEM_Get_elem_data(int elType,double *data);
307   void FEM_Get_elem_conn(int elType,int *conn);
308   int  FEM_Get_sparse_length(int uniqueIdentifier); 
309   void FEM_Get_sparse(int uniqueIdentifier,int *nodes,void *data);
310   
311   void FEM_Set_mesh(int nelem, int nnodes, int nodePerElem, int* conn);
312   
313   int FEM_Get_node_ghost(void);
314   int FEM_Get_elem_ghost(int elemType);  
315
316   void FEM_Update_mesh(FEM_Update_mesh_fn callFn,int userValue,int doWhat);
317   
318   void FEM_Set_partition(int *elem2chunk);
319
320
321   /* Public functions that modify the mesh */
322   int FEM_add_node(int mesh, int* adjacent_nodes=0, int num_adjacent_nodes=0, int *chunks=0, int numChunks=0, int forceShared=0, int upcall=0);
323   int FEM_add_element(int mesh, int* conn, int conn_size, int elem_type=0, int chunkNo=-1);
324   void FEM_remove_node(int mesh,int node);
325   int FEM_remove_element(int mesh, int element, int elem_type=0, int permanent=-1);
326   int FEM_Modify_Lock(int mesh, int* affectedNodes, int numAffectedNodes, int* affectedElts=0, int numAffectedElts=0, int elemtype=0);
327   int FEM_Modify_Unlock(int mesh);
328   int FEM_Modify_LockN(int mesh, int nodeId, int readLock);
329   int FEM_Modify_UnlockN(int mesh, int nodeId, int readLock);
330   void FEM_REF_INIT(int mesh, int dim);
331   
332  
333
334   
335   // To help debugging:
336   void FEM_Print_Mesh_Summary(int mesh);
337
338 /* Routines we wish didn't exist: */
339   void FEM_Serial_split(int nchunks);
340   void FEM_Serial_begin(int chunkNo);
341   
342   void FEM_Serial_read(int chunkNo,int nChunks);
343   void FEM_Serial_assemble(void);
344   
345   int FEM_Get_comm_partners(void);
346   int FEM_Get_comm_partner(int partnerNo);
347   int FEM_Get_comm_count(int partnerNo);
348   void FEM_Get_comm_nodes(int partnerNo,int *nodeNos);
349
350
351 /* Routines that no longer exist:
352   void FEM_Composite_elem(int newElType);
353    -> Replace with IDXL_Create
354   void FEM_Combine_elem(int srcElType,int destElType,
355         int newInteriorStartIdx,int newGhostStartIdx);  
356    -> Replace with IDXL_Combine
357 */
358
359
360
361
362 /* 
363 ParFUM Collision Interface File
364
365 A few outstanding questions:
366
367 Is the use of an element based attribute to store any needed collision data a good thing?
368 Perhaps we should just use the user data attributes for the element. This may require there 
369 to be consequtive user data attributes. I.e. no FEM_DATA+5,FEM_DATA+82, without those inbetween.
370 Do we need to transmit nodal data for each element?
371 Does the user need anything beyond just some data attributes for the one remote element which is 
372 colliding locally?
373
374 THESE FUNCTIONS ARE NOT YET IMPLEMENTED!
375
376 Author: Isaac Dooley 11-09-2005
377 */
378
379   struct ParFUM_collider {
380         collide_t collide_grid;
381         double box_padding;
382         int dimension;
383
384         unsigned int *boxToElementMapping;
385         unsigned int numCollidableElements; // size of boxToElementMapping array
386   };
387
388
389
390   /* ParFUM_Collide_init() will initialize the collision library. 
391      It should be called once in driver after mesh has been loaded.
392      
393      dimension should reflect the number of coordinates associated 
394      with a node. This cannot exceed 3 with the current Collision
395      Library. The user's nodal coordinates must be registered as a 
396      particular attribute in order to determine the optimal grid sizing.
397
398      Algorithm:
399        Determine Grid Sizing
400        Call COLLIDE_Init()
401      
402   */   
403   ParFUM_collider ParFUM_Collide_Init(int dimension);
404
405
406   /* ParFUM_Collide() will create bounding boxes for each element in the local mesh chunk.
407      It will then collide these bounding boxes with those both locally and remotely.
408      It should be called at each timestep for which collisions are being tested.
409     
410      Algorithm: 
411        Create Bounding boxes for all valid elements, and priority array
412        Call COLLIDE_Boxes_prio()
413        return the number of collisions which involve a local element
414   */  
415   int ParFUM_Collide(ParFUM_collider *c, double box_padding = 0.0);
416
417   /* ParFUM_Collide_GetCollisions() is used to get the data for any remote elements which 
418      It should be called after Collide even if ParFUM_Collide returned 0
419
420      The data it returns will be double precision values associated with the
421      element attribute ParFUM_COLLISION_DATA
422
423      results should be an array allocated by the user with length equal to the number of 
424      collisions times the amount of space needed for each item in the ParFUM_COLLISION_DATA 
425      attribute
426           
427      Algorithm: 
428
429
430
431   */  
432   void ParFUM_Collide_GetCollisions(ParFUM_collider *c, void* results);
433
434   void ParFUM_Collide_Destroy(ParFUM_collider *c);
435
436
437 // End of Collision interface
438
439
440
441 // User functions for adaptivity
442
443 void FEM_ADAPT_Init(int meshID);
444 FDECL void FTN_NAME(FEM_ADAPT_INIT,fem_adapt_init)(int *meshID);
445
446
447 void FEM_ADAPT_Refine(int meshID, int qm, int method, double factor, double *sizes);
448 FDECL void FTN_NAME(FEM_ADAPT_REFINE,fem_adapt_refine)(int* meshID, 
449         int *qm, int *method, double *factor, double *sizes);
450
451
452 void FEM_ADAPT_Coarsen(int meshID, int qm, int method, double factor, 
453         double *sizes);
454 FDECL void FTN_NAME(FEM_ADAPT_COARSEN,fem_adapt_coarsen)(int* meshID, 
455         int *qm, int *method, double *factor, double *sizes);
456
457 void FEM_ADAPT_AdaptMesh(int meshID, int qm, int method, double factor, double *sizes);
458 FDECL void FTN_NAME(FEM_ADAPT_ADAPTMESH,fem_adapt_adaptmesh)(int* meshID, 
459         int *qm, int *method, double *factor, double *sizes);
460
461 void FEM_ADAPT_SetElementSizeField(int meshID, int elem, double size);
462 FDECL void FTN_NAME(FEM_ADAPT_SETELEMENTSIZEFIELD,fem_adapt_setelementsizefield)(int *meshID, int *elem, double *size);
463
464
465 void FEM_ADAPT_SetElementsSizeField(int meshID, double *sizes);
466 FDECL void FTN_NAME(FEM_ADAPT_SETELEMENTSSIZEFIELD,fem_adapt_setelementssizefield)(int *meshID, double *sizes);
467
468
469 void FEM_ADAPT_SetReferenceMesh(int meshID);
470 FDECL void FTN_NAME(FEM_ADAPT_SETREFERENCEMESH, fem_adapt_setreferencemesh)(int* meshID);
471
472
473 void FEM_ADAPT_GradateMesh(int meshID, double smoothness);
474 FDECL void FTN_NAME(FEM_ADAPT_GRADATEMESH, fem_adapt_gradatemesh)(int* meshID, double* smoothness);
475
476   // End Adaptivity interface
477
478 }
479 #endif
480
481