HyPar  1.0
Finite-Difference Hyperbolic-Parabolic PDE Solver on Cartesian Grids
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
NavierStokes3DIBForces.c File Reference

Compute aerodynamic forces on immersed body, if present. More...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <basic.h>
#include <common.h>
#include <arrayfunctions.h>
#include <mathfunctions.h>
#include <immersedboundaries.h>
#include <physicalmodels/navierstokes3d.h>
#include <mpivars.h>
#include <hypar.h>

Go to the source code of this file.

Functions

int NavierStokes3DComputePressure (double *, const double *const, void *)
 
int NavierStokes3DComputeTemperature (double *, const double *const, void *)
 
static int ComputeShear (void *s, void *m, const double *const u, double **const sf)
 
static int WriteSurfaceData (void *m, void *ib, const double *const p_surface, const double *const T_surface, const double *const ngrad_p_surface, const double *const ngrad_T_surface, const double *const shear, char *filename)
 
int NavierStokes3DIBForces (void *s, void *m, double a_t)
 

Detailed Description

Compute aerodynamic forces on immersed body, if present.

Author
Debojyoti Ghosh

Definition in file NavierStokes3DIBForces.c.

Function Documentation

int NavierStokes3DComputePressure ( double *  P,
const double *const  u,
void *  s 
)

Compute the pressure from the conserved solution on a grid

Parameters
PArray to hold the computed pressure (same layout as u)
uArray with the solution vector
sSolver object of type HyPar

Definition at line 31 of file NavierStokes3DFunctions.c.

35 {
36  HyPar *solver = (HyPar*) s;
37  NavierStokes3D *param = (NavierStokes3D*) solver->physics;
38  int i;
39 
40  int *dim = solver->dim_local;
41  int ghosts = solver->ghosts;
42  int ndims = solver->ndims;
43  int index[ndims], bounds[ndims], offset[ndims];
44 
45  /* set bounds for array index to include ghost points */
46  _ArrayCopy1D_(dim,bounds,ndims);
47  for (i=0; i<ndims; i++) bounds[i] += 2*ghosts;
48 
49  /* set offset such that index is compatible with ghost point arrangement */
50  _ArraySetValue_(offset,ndims,-ghosts);
51 
52  int done = 0; _ArraySetValue_(index,ndims,0);
53  while (!done) {
54  int idx; _ArrayIndex1DWO_(ndims,dim,index,offset,ghosts,idx);
55  double rho, vx, vy, vz, e, pressure;
56  _NavierStokes3DGetFlowVar_((u+_MODEL_NVARS_*idx),_NavierStokes3D_stride_,rho,vx,vy,vz,e,pressure,param->gamma);
57  P[idx] = pressure;
58  _ArrayIncrementIndex_(ndims,bounds,index,done);
59  }
60 
61  return(0);
62 }
#define _NavierStokes3DGetFlowVar_(u, stride, rho, vx, vy, vz, e, P, gamma)
#define _ArraySetValue_(x, size, value)
#define _ArrayIncrementIndex_(N, imax, i, done)
#define _MODEL_NVARS_
Definition: euler1d.h:58
void * physics
Definition: hypar.h:266
int * dim_local
Definition: hypar.h:37
int ghosts
Definition: hypar.h:52
#define _ArrayIndex1DWO_(N, imax, i, offset, ghost, index)
#define _ArrayCopy1D_(x, y, size)
Structure containing variables and parameters specific to the 3D Navier Stokes equations. This structure contains the physical parameters, variables, and function pointers specific to the 3D Navier-Stokes equations.
int ndims
Definition: hypar.h:26
Structure containing all solver-specific variables and functions.
Definition: hypar.h:23
static const int _NavierStokes3D_stride_
int NavierStokes3DComputeTemperature ( double *  T,
const double *const  u,
void *  s 
)

Compute the temperature from the conserved solution on a grid

Parameters
TArray to hold the computed pressure (same layout as u)
uArray with the solution vector
sSolver object of type HyPar

Definition at line 65 of file NavierStokes3DFunctions.c.

69 {
70  HyPar *solver = (HyPar*) s;
71  NavierStokes3D *param = (NavierStokes3D*) solver->physics;
72  int i;
73 
74  int *dim = solver->dim_local;
75  int ghosts = solver->ghosts;
76  int ndims = solver->ndims;
77  int index[ndims], bounds[ndims], offset[ndims];
78 
79  /* set bounds for array index to include ghost points */
80  _ArrayCopy1D_(dim,bounds,ndims);
81  for (i=0; i<ndims; i++) bounds[i] += 2*ghosts;
82 
83  /* set offset such that index is compatible with ghost point arrangement */
84  _ArraySetValue_(offset,ndims,-ghosts);
85 
86  int done = 0; _ArraySetValue_(index,ndims,0);
87  while (!done) {
88  int idx; _ArrayIndex1DWO_(ndims,dim,index,offset,ghosts,idx);
89  double rho, vx, vy, vz, e, pressure;
90  _NavierStokes3DGetFlowVar_((u+_MODEL_NVARS_*idx),_NavierStokes3D_stride_,rho,vx,vy,vz,e,pressure,param->gamma);
91  T[idx] = pressure/rho;
92  _ArrayIncrementIndex_(ndims,bounds,index,done);
93  }
94 
95  return(0);
96 }
#define _NavierStokes3DGetFlowVar_(u, stride, rho, vx, vy, vz, e, P, gamma)
#define _ArraySetValue_(x, size, value)
#define _ArrayIncrementIndex_(N, imax, i, done)
#define _MODEL_NVARS_
Definition: euler1d.h:58
void * physics
Definition: hypar.h:266
int * dim_local
Definition: hypar.h:37
int ghosts
Definition: hypar.h:52
#define _ArrayIndex1DWO_(N, imax, i, offset, ghost, index)
#define _ArrayCopy1D_(x, y, size)
Structure containing variables and parameters specific to the 3D Navier Stokes equations. This structure contains the physical parameters, variables, and function pointers specific to the 3D Navier-Stokes equations.
int ndims
Definition: hypar.h:26
Structure containing all solver-specific variables and functions.
Definition: hypar.h:23
static const int _NavierStokes3D_stride_
static int ComputeShear ( void *  s,
void *  m,
const double *const  u,
double **const  sf 
)
static

Calculate the shear forces on the immersed body surface: for each "local facet", i.e., facets (of the immersed body surface) that lie within the local computational domain of this MPI rank, compute the shear forces at the facet centroid from the flow variables at the grid points surrounding the facet.

The array to hold the computed shear forces must be NULL when this function is called. If the current subdomain contains a part of the immersed body, they will point to arrays with the local data. Otherwise, they will remain NULL.

The shear force array will be of the size (4 X ImmersedBoundary::nfacets_local), where the ordering of the data is: x-component, y-component, z-component, magnitude.

Parameters
sSolver object of type HyPar
mMPI object of type MPIVariables
uArray containing the conserved flow variables
sfArray for (x,y,z)-components & magnitude of shear

Definition at line 37 of file NavierStokes3DIBForces.c.

42 {
43  HyPar *solver = (HyPar*) s;
44  MPIVariables *mpi = (MPIVariables*) m;
45  NavierStokes3D *physics = (NavierStokes3D*) solver->physics;
46  ImmersedBoundary *IB = (ImmersedBoundary*) solver->ib;
47 
48  if ((*sf) != NULL) {
49  fprintf(stderr, "Error in ComputeShear()\n");
50  fprintf(stderr, " shear force array is not NULL!\n");
51  return 1;
52  }
53 
54  if (!solver->flag_ib) return(0);
55 
56  int nfacets_local = IB->nfacets_local;
57  FacetMap *fmap = IB->fmap;
58  static double v[_MODEL_NVARS_];
59 
60  int nv = 4;
61 
62  if (nfacets_local > 0) {
63 
64  (*sf) = (double*) calloc (nv*nfacets_local, sizeof(double));
65 
66  if (physics->Re > 0) {
67 
68  for (int n = 0; n < nfacets_local; n++) {
69 
70  double *alpha;
71  int *nodes, j, k;
72 
73  alpha = &(fmap[n].interp_coeffs[0]);
74  nodes = &(fmap[n].interp_nodes[0]);
76  for (j=0; j<_IB_NNODES_; j++) {
77  for (k=0; k<_MODEL_NVARS_; k++) {
78  v[k] += ( alpha[j] * u[_MODEL_NVARS_*nodes[j]+k] );
79  }
80  }
81  double rho_c, uvel_c, vvel_c, wvel_c, energy_c, pressure_c;
82  _NavierStokes3DGetFlowVar_(v,_NavierStokes3D_stride_,rho_c,uvel_c,vvel_c,wvel_c,energy_c,pressure_c,physics->gamma);
83 
84  alpha = &(fmap[n].interp_coeffs_ns[0]);
85  nodes = &(fmap[n].interp_nodes_ns[0]);
87  for (j=0; j<_IB_NNODES_; j++) {
88  for (k=0; k<_MODEL_NVARS_; k++) {
89  v[k] += ( alpha[j] * u[_MODEL_NVARS_*nodes[j]+k] );
90  }
91  }
92  double rho_ns, uvel_ns, vvel_ns, wvel_ns, energy_ns, pressure_ns;
93  _NavierStokes3DGetFlowVar_(v,_NavierStokes3D_stride_,rho_ns,uvel_ns,vvel_ns,wvel_ns,energy_ns,pressure_ns,physics->gamma);
94 
95  double u_x = (uvel_ns - uvel_c) / fmap[n].dx;
96  double v_x = (vvel_ns - vvel_c) / fmap[n].dx;
97  double w_x = (wvel_ns - wvel_c) / fmap[n].dx;
98 
99  double u_y = (uvel_ns - uvel_c) / fmap[n].dy;
100  double v_y = (vvel_ns - vvel_c) / fmap[n].dy;
101  double w_y = (wvel_ns - wvel_c) / fmap[n].dy;
102 
103  double u_z = (uvel_ns - uvel_c) / fmap[n].dz;
104  double v_z = (vvel_ns - vvel_c) / fmap[n].dz;
105  double w_z = (wvel_ns - wvel_c) / fmap[n].dz;
106 
107  double nx = fmap[n].facet->nx;
108  double ny = fmap[n].facet->ny;
109  double nz = fmap[n].facet->nz;
110 
111  double T = physics->gamma*pressure_c/rho_c;
112  double mu = raiseto(T, 0.76);
113  double inv_Re = 1.0/physics->Re;
114 
115  double tau_x = (mu*inv_Re) * (2*u_x*nx + (u_y+v_x)*ny + (u_z+w_x)*nz);
116  double tau_y = (mu*inv_Re) * ((v_x+u_y)*nx + 2*v_y*ny + (v_z+w_y)*nz);
117  double tau_z = (mu*inv_Re) * ((w_x+u_z)*nx + (w_y+v_z)*ny + 2*w_z*nz);
118 
119  (*sf)[n*nv+_XDIR_] = tau_x;
120  (*sf)[n*nv+_YDIR_] = tau_y;
121  (*sf)[n*nv+_ZDIR_] = tau_z;
122 
123  (*sf)[n*nv+_ZDIR_+1] = sqrt(tau_x*tau_x + tau_y*tau_y + tau_z*tau_z);
124  }
125 
126  } else {
127 
128  _ArraySetValue_((*sf), nv*nfacets_local, 0.0);
129 
130  }
131 
132  }
133 
134  return 0;
135 }
Facet3D * facet
#define _YDIR_
Definition: euler2d.h:41
#define _NavierStokes3DGetFlowVar_(u, stride, rho, vx, vy, vz, e, P, gamma)
#define _ArraySetValue_(x, size, value)
double interp_coeffs[_IB_NNODES_]
#define raiseto(x, a)
Definition: math_ops.h:37
Structure containing variables for immersed boundary implementation.
Structure defining a facet map.
void * ib
Definition: hypar.h:443
#define _MODEL_NVARS_
Definition: euler1d.h:58
void * physics
Definition: hypar.h:266
int flag_ib
Definition: hypar.h:441
#define _ZDIR_
double interp_coeffs_ns[_IB_NNODES_]
int interp_nodes_ns[_IB_NNODES_]
int interp_nodes[_IB_NNODES_]
Structure containing variables and parameters specific to the 3D Navier Stokes equations. This structure contains the physical parameters, variables, and function pointers specific to the 3D Navier-Stokes equations.
Structure of MPI-related variables.
Structure containing all solver-specific variables and functions.
Definition: hypar.h:23
#define _IB_NNODES_
#define _XDIR_
Definition: euler1d.h:75
static const int _NavierStokes3D_stride_
static int WriteSurfaceData ( void *  m,
void *  ib,
const double *const  p_surface,
const double *const  T_surface,
const double *const  ngrad_p_surface,
const double *const  ngrad_T_surface,
const double *const  shear,
char *  filename 
)
static

Write the surface data on the immersed body to a ASCII Tecplot file.

Parameters
mMPI object of type MPIVariables
ibImmersed body object of type ImmersedBoundary
p_surfacearray with local surface pressure data
T_surfacearray with local surface temperature data
ngrad_p_surfacearray with local normal gradient of surface pressure data
ngrad_T_surfacearray with local normal gradient of surface temperature data
sheararray with local shear data
filenameName of file to write

Definition at line 138 of file NavierStokes3DIBForces.c.

147 {
148  MPIVariables *mpi = (MPIVariables*) m;
150  int ierr;
151 
152 #ifndef serial
153  MPI_Status status;
154 #endif
155 
156  /* collect the surface data into global arrays */
157  double* p_surface_g = NULL;
158  ierr = IBAssembleGlobalFacetData(mpi, IB, p_surface, &p_surface_g, 1);
159  if (ierr) {
160  fprintf(stderr,"IBAssembleGlobalFacetData() returned with an error.\n");
161  return 1;
162  }
163  double* T_surface_g = NULL;
164  ierr = IBAssembleGlobalFacetData(mpi, IB, T_surface, &T_surface_g, 1);
165  if (ierr) {
166  fprintf(stderr,"IBAssembleGlobalFacetData() returned with an error.\n");
167  return 1;
168  }
169  double* ngrad_p_surface_g = NULL;
170  ierr = IBAssembleGlobalFacetData(mpi, IB, ngrad_p_surface, &ngrad_p_surface_g, 1);
171  if (ierr) {
172  fprintf(stderr,"IBAssembleGlobalFacetData() returned with an error.\n");
173  return 1;
174  }
175  double* ngrad_T_surface_g = NULL;
176  ierr = IBAssembleGlobalFacetData(mpi, IB, ngrad_T_surface, &ngrad_T_surface_g, 1);
177  if (ierr) {
178  fprintf(stderr,"IBAssembleGlobalFacetData() returned with an error.\n");
179  return 1;
180  }
181  double* shear_g = NULL;
182  ierr = IBAssembleGlobalFacetData(mpi, IB, shear, &shear_g, 4);
183  if (ierr) {
184  fprintf(stderr,"IBAssembleGlobalFacetData() returned with an error.\n");
185  return 1;
186  }
187 
188  /* Rank 0 writes the file */
189  if (!mpi->rank) {
190 
191  int nfacets_global = IB->body->nfacets;
192  const Facet3D* const facets = IB->body->surface;
193 
194  FILE *out;
195  out = fopen(filename,"w");
196  fprintf(out,"TITLE = \"Surface data created by HyPar.\"\n");
197  fprintf(out,"VARIABLES = \"X\", \"Y\", \"Z\", ");
198  fprintf(out,"\"Surface_Pressure\", ");
199  fprintf(out,"\"Surface_Temperature\", ");
200  fprintf(out,"\"Normal_Grad_Surface_Pressure\", ");
201  fprintf(out,"\"Normal_Grad_Surface_Temperature\", ");
202  fprintf(out,"\"Shear_x\", ");
203  fprintf(out,"\"Shear_y\", ");
204  fprintf(out,"\"Shear_z\", ");
205  fprintf(out,"\"Shear_magn\"");
206  fprintf(out,"\n");
207  fprintf(out,"ZONE N = %d, E = %d, DATAPACKING = POINT, ZONETYPE = FETRIANGLE\n",3*nfacets_global,nfacets_global);
208 
209  for (int n = 0; n < nfacets_global; n++) {
210  fprintf( out, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
211  facets[n].x1,
212  facets[n].y1,
213  facets[n].z1,
214  p_surface_g[n],
215  T_surface_g[n],
216  ngrad_p_surface_g[n],
217  ngrad_T_surface_g[n],
218  shear_g[4*n+_XDIR_],
219  shear_g[4*n+_YDIR_],
220  shear_g[4*n+_ZDIR_],
221  shear_g[4*n+_ZDIR_+1] );
222  fprintf( out, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
223  facets[n].x2,
224  facets[n].y2,
225  facets[n].z2,
226  p_surface_g[n],
227  T_surface_g[n],
228  ngrad_p_surface_g[n],
229  ngrad_T_surface_g[n],
230  shear_g[4*n+_XDIR_],
231  shear_g[4*n+_YDIR_],
232  shear_g[4*n+_ZDIR_],
233  shear_g[4*n+_ZDIR_+1] );
234  fprintf( out, "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf\n",
235  facets[n].x3,
236  facets[n].y3,
237  facets[n].z3,
238  p_surface_g[n],
239  T_surface_g[n],
240  ngrad_p_surface_g[n],
241  ngrad_T_surface_g[n],
242  shear_g[4*n+_XDIR_],
243  shear_g[4*n+_YDIR_],
244  shear_g[4*n+_ZDIR_],
245  shear_g[4*n+_ZDIR_+1] );
246  }
247  for (int n = 0; n < nfacets_global; n++) fprintf(out,"%d %d %d\n",3*n+1,3*n+2,3*n+3);
248  fclose(out);
249  }
250 
251  if (p_surface_g) free(p_surface_g);
252  if (T_surface_g) free(T_surface_g);
253  if (ngrad_p_surface_g) free(ngrad_p_surface_g);
254  if (ngrad_T_surface_g) free(ngrad_T_surface_g);
255  if (shear_g) free(shear_g);
256 
257  return 0;
258 }
#define _YDIR_
Definition: euler2d.h:41
Structure containing variables for immersed boundary implementation.
Structure defining a facet.
int IBAssembleGlobalFacetData(void *, void *, const double *const, double **const, int)
Facet3D * surface
#define _ZDIR_
Structure of MPI-related variables.
#define _XDIR_
Definition: euler1d.h:75
int NavierStokes3DIBForces ( void *  s,
void *  m,
double  a_t 
)

Calculate the aerodynamic forces on the immersed body surface and write them to file

Parameters
sSolver object of type HyPar
mMPI object of type MPIVariables
a_tCurrent simulation time

Definition at line 264 of file NavierStokes3DIBForces.c.

267 {
268  HyPar *solver = (HyPar*) s;
269  MPIVariables *mpi = (MPIVariables*) m;
270  NavierStokes3D *physics = (NavierStokes3D*) solver->physics;
271  ImmersedBoundary *IB = (ImmersedBoundary*) solver->ib;
272  int ierr;
273 
274  if (!solver->flag_ib) return(0);
275 
276  int npts = solver->npoints_local_wghosts;
277 
278  double* pressure = (double*) calloc (npts, sizeof(double));
279  ierr = NavierStokes3DComputePressure(pressure, solver->u, solver);
280  if (ierr) {
281  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
282  fprintf(stderr," NavierStokes3DComputePressure() returned with error.\n");
283  return 1;
284  }
285  double* temperature = (double*) calloc(npts, sizeof(double));
286  ierr = NavierStokes3DComputeTemperature(temperature, solver->u, solver);
287  if (ierr) {
288  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
289  fprintf(stderr," NavierStokes3DComputeTemperature() returned with error.\n");
290  return 1;
291  }
292 
293  /* Compute surface pressure */
294  double* p_surface = NULL;
295  ierr = IBComputeFacetVar(solver, mpi, pressure, 1, &p_surface);
296  if (ierr) {
297  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
298  fprintf(stderr," IBComputeFacetVar() returned with error.\n");
299  return 1;
300  }
301  /* Compute surface temperature */
302  double* T_surface = NULL;
303  ierr = IBComputeFacetVar(solver, mpi, temperature, 1, &T_surface);
304  if (ierr) {
305  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
306  fprintf(stderr," IBComputeFacetVar() returned with error.\n");
307  return 1;
308  }
309  /* Compute normal surface pressure gradient */
310  double *ngrad_p_surface = NULL;
311  ierr = IBComputeNormalGradient(solver, mpi, pressure, 1, &ngrad_p_surface);
312  if (ierr) {
313  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
314  fprintf(stderr," IBComputeNormalGradient() returned with error.\n");
315  return 1;
316  }
317  /* Compute normal temperature gradient */
318  double *ngrad_T_surface = NULL;
319  ierr = IBComputeNormalGradient(solver, mpi, temperature, 1, &ngrad_T_surface);
320  if (ierr) {
321  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
322  fprintf(stderr," IBComputeNormalGradient() returned with error.\n");
323  return 1;
324  }
325  /* Compute shear forces */
326  double *shear = NULL;
327  ierr = ComputeShear(solver, mpi, solver->u, &shear);
328  if (ierr) {
329  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
330  fprintf(stderr," ComputeShear() returned with error.\n");
331  return 1;
332  }
333 
334  char surface_filename[_MAX_STRING_SIZE_] = "surface";
335  if (solver->nsims == 1) {
336  if (!strcmp(solver->op_overwrite,"no")) {
337  strcat(surface_filename,solver->filename_index);
338  }
339  } else {
340  char index[_MAX_STRING_SIZE_];
341  GetStringFromInteger(solver->my_idx, index, (int)log10(solver->nsims)+1);
342  strcat(surface_filename, "_");
343  strcat(surface_filename, index);
344  strcat(surface_filename, "_");
345  }
346  strcat(surface_filename,".dat");
347  if (!mpi->rank) {
348  printf("Writing immersed body surface data file %s.\n",surface_filename);
349  }
350  ierr = WriteSurfaceData( mpi,
351  IB,
352  p_surface,
353  T_surface,
354  ngrad_p_surface,
355  ngrad_T_surface,
356  shear,
357  surface_filename );
358  if (ierr) {
359  fprintf(stderr,"Error in NavierStokes3DIBForces()\n");
360  fprintf(stderr," WriteSurfaceData() returned with error\n");
361  return 1;
362  }
363 
364  free(pressure);
365  free(temperature);
366  if (p_surface) free(p_surface);
367  if (T_surface) free(T_surface);
368  if (ngrad_p_surface) free(ngrad_p_surface);
369  if (ngrad_T_surface) free(ngrad_T_surface);
370  if (shear) free(shear);
371 
372  return 0;
373 }
int npoints_local_wghosts
Definition: hypar.h:42
static int ComputeShear(void *s, void *m, const double *const u, double **const sf)
int NavierStokes3DComputePressure(double *P, const double *const u, void *s)
Structure containing variables for immersed boundary implementation.
double * u
Definition: hypar.h:116
void * ib
Definition: hypar.h:443
void GetStringFromInteger(int, char *, int)
static int WriteSurfaceData(void *m, void *ib, const double *const p_surface, const double *const T_surface, const double *const ngrad_p_surface, const double *const ngrad_T_surface, const double *const shear, char *filename)
void * physics
Definition: hypar.h:266
int NavierStokes3DComputeTemperature(double *T, const double *const u, void *s)
int flag_ib
Definition: hypar.h:441
int nsims
Definition: hypar.h:64
char * filename_index
Definition: hypar.h:197
#define _MAX_STRING_SIZE_
Definition: basic.h:14
int IBComputeFacetVar(void *, void *, const double *const, int, double **const)
char op_overwrite[_MAX_STRING_SIZE_]
Definition: hypar.h:191
Structure containing variables and parameters specific to the 3D Navier Stokes equations. This structure contains the physical parameters, variables, and function pointers specific to the 3D Navier-Stokes equations.
int my_idx
Definition: hypar.h:61
Structure of MPI-related variables.
int IBComputeNormalGradient(void *, void *, const double *const, int, double **const)
Structure containing all solver-specific variables and functions.
Definition: hypar.h:23