static inline jl_value_t *jl_iintrinsic_2(jl_value_t *a, jl_value_t *b, const char *name, char (*getsign)(void*, unsigned),
        jl_value_t* (*lambda2)(jl_value_t*, void*, void*, unsigned, unsigned, void*),
        void *list, int cvtb)
{
    jl_value_t *ty = jl_typeof(a);
    jl_value_t *tyb = jl_typeof(b);
    if (tyb != ty) {
        if (!cvtb)
            jl_errorf("%s: types of a and b must match", name);
        if (!jl_is_bitstype(tyb))
            jl_errorf("%s: b is not a bitstypes", name);
    }
    if (!jl_is_bitstype(ty))
        jl_errorf("%s: a is not a bitstypes", name);
    void *pa = jl_data_ptr(a), *pb = jl_data_ptr(b);
    unsigned sz = jl_datatype_size(ty);
    unsigned sz2 = next_power_of_two(sz);
    unsigned szb = jl_datatype_size(tyb);
    if (sz2 > sz) {
        /* round type up to the appropriate c-type and set/clear the unused bits */
        void *pa2 = alloca(sz2);
        memcpy(pa2, pa, sz);
        memset((char*)pa2 + sz, getsign(pa, sz), sz2 - sz);
        pa = pa2;
    }
    if (sz2 > szb) {
        /* round type up to the appropriate c-type and set/clear/truncate the unused bits */
        void *pb2 = alloca(sz2);
        memcpy(pb2, pb, szb);
        memset((char*)pb2 + szb, getsign(pb, sz), sz2 - szb);
        pb = pb2;
    }
    jl_value_t *newv = lambda2(ty, pa, pb, sz, sz2, list);
    return newv;
}
Exemple #2
0
int main (int    argc,
	  char** argv)
// ---------------------------------------------------------------------------
// Driver.
// ---------------------------------------------------------------------------
{
  Geometry::CoordSys         system;
  char                       *session, *dump, *func, fields[StrMax];
  int_t                      i, j, k, p, q;
  int_t                      np, nz, nel, allocSize, NCOM, NDIM;
  int_t                      iAdd = 0;
  bool                       add[FLAG_MAX], need[FLAG_MAX], gradient;
  ifstream                   file;
  FEML*                      F;
  Mesh*                      M;
  BCmgr*                     B;
  Domain*                    D;
  vector<Element*>           elmt;
  AuxField                   *Ens, *Hel, *Div, *Disc, *Strain;
  AuxField                   *Func, *Vtx, *DivL, *Nrg, *work;
  vector<AuxField*>          velocity, vorticity, lamb, addField(FLDS_MAX);
  vector<vector<AuxField*> > Vij;     // -- Usually computed, for internal use.
  vector<vector<real_t*> >   VijData; // -- For pointwise access in Vij.

  vector<real_t*> VorData; // -- Ditto in vorticity.
  vector<real_t*> LamData; // -- Ditto in Lamb vector.

  real_t          *DisData, *DivData, *StrData, *VtxData, *HelData, *EnsData;
  real_t          vel[3], vort[3], tensor[9];

  Femlib::initialize (&argc, &argv);
  for (i = 0; i < FLAG_MAX; i++) add [i] = need [i] = false;

  // -- Read command line.

  getargs (argc, argv, session, dump, func, add);

  file.open (dump);
  if (!file) message (prog, "can't open input field file", ERROR);

  // -- Set up domain.

  F      = new FEML (session);
  M      = new Mesh (F);
  nel    = M -> nEl ();  
  np     =  Femlib::ivalue ("N_P");
  nz     =  Femlib::ivalue ("N_Z");
  system = (Femlib::ivalue ("CYLINDRICAL") ) ?
                       Geometry::Cylindrical : Geometry::Cartesian;
  Geometry::set (np, nz, nel, system);

  allocSize = Geometry::nTotal();

  elmt.resize (nel);
  for (i = 0; i < nel; i++) elmt[i] = new Element (i, np, M);

  B = new BCmgr  (F, elmt);
  D = new Domain (F, elmt, B);

  if      (strstr (D -> field, "uvw")) NCOM = 3;
  else if (strstr (D -> field, "uv"))  NCOM = 2;
  else message (prog, "lacking velocity components: is session valid?", ERROR);
  NDIM = Geometry::nDim();

  velocity.resize   (NCOM);
  vorticity.resize ((NDIM == 2) ? 1 : 3);
  for (i = 0; i < NCOM; i++) velocity[i] = D -> u[i];

  // -- From the requested fields, flag dependencies.

  // -- First, only allow the "coherent structures" measures for flows
  //    that are 3D.

  if  (NDIM == 2)
    add[HELICITY]=add[DISCRIMINANT]=add[VORTEXCORE]=add[DIVLAMB] = false;

  for (p = 0, i = 0; i < FLAG_MAX; i++) p += (add[i]) ? 1 : 0;
  if  (p == 0) message (prog, "nothing to be done", ERROR);

  // -- Check if we just have the (first two) cases not requiring derivatives.

  for (p = 0, i = 0; i < FLAG_MAX; i++) p += (add[i]) ? (i + 1) : 0;
  if (p <= 2) gradient = false; else gradient = true;

  for (i = 0; i < FLAG_MAX; i++) need[i] = add[i];

  // -- If any gradients need to be computed, we make all of them.
  //    Vij = du_j/dx_i.  So j labels velocity component and i labels
  //    spatial dimension.

  // -- Despite the fact that it's overkill we will take the
  //    simple-minded approach and always make Vij as a 3x3 tensor.
  //    That's a wasteful for anything which is 2D but presumably for
  //    those cases the memory can be afforded.

  // -- The velocity gradient tensor is initially just a naive matrix
  //    of derivatives.  In cylindrical coordinates we need to make
  //    modifications.
  
  if (gradient) {
    Vij    .resize (3);
    VijData.resize (3);
    for (i = 0; i < 3; i++) {
      Vij    [i].resize (3);
      VijData[i].resize (3);
      for (j = 0; j < 3; j++) {
	VijData[i][j] = new real_t [allocSize];
	Vij    [i][j] = new AuxField (VijData[i][j], nz, elmt);
	*Vij   [i][j] = 0.0;
      }
    }
  }
  
  // -- Fields without dependants.

  if (need[ENERGY]) {
    Nrg = new AuxField (new real_t[allocSize], nz, elmt, 'q');
    addField[iAdd++] = Nrg;
  }

  if (need[FUNCTION]) {
    Func = new AuxField (new real_t[allocSize], nz, elmt, 'f');
    addField[iAdd++] = Func;
  }

  if (need[DIVERGENCE]) {
    DivData = new real_t [allocSize];
    *(Div  =  new AuxField (DivData, nz, elmt, 'd')) = 0.0;
    addField[iAdd++] = Div;
  }

  if (need[DISCRIMINANT]) {
    DisData = new real_t [allocSize];
    *(Disc = new AuxField (DisData, nz, elmt, 'D')) = 0.0;
    addField[iAdd++] = Disc;
  }

  if (need[STRAINRATE]) {
    StrData = new real_t [allocSize];
    Strain  = new AuxField (StrData, nz, elmt, 'g');
    addField[iAdd++] = Strain;
  }

  if (need[VORTEXCORE]) {
    VtxData = new real_t [allocSize];
    Vtx = new AuxField (VtxData, nz, elmt, 'J');
    addField[iAdd++] = Vtx;
  }

  if (need[VORTICITY])
    if (NDIM == 2) {
      vorticity.resize (1);
      VorData  .resize (1);
      VorData[0]       = new real_t [allocSize];
      vorticity[0]     = new AuxField (VorData[0], nz, elmt, 't');
      addField[iAdd++] = vorticity[0];
    } else {
      vorticity.resize (3);
      VorData  .resize (3);
      for (i = 0; i < 3; i++) {
	VorData[i]       = new real_t [allocSize];
	vorticity[i]     = new AuxField (VorData[i], nz, elmt, 'r' + i);
	addField[iAdd++] = vorticity[i];
      }
    }

  if (add[DIVLAMB]) { 		// -- Know also NDIM == 3.
    lamb   .resize (3);
    LamData.resize (3);
    for (i = 0; i < 3; i++) {
      LamData[i] = new real_t [allocSize];
      lamb[i]    = new AuxField (LamData[i], nz, elmt, 'L');
    }
    addField[iAdd++] = lamb[0];	// -- Where divergence will get stored.
  }

  if (need[ENSTROPHY]) {
    EnsData = new real_t[allocSize];
    Ens = new AuxField (EnsData, nz, elmt, 'e');
    if (add[ENSTROPHY]) addField[iAdd++] = Ens;
  }
  
  if (need[HELICITY]) {
    HelData = new real_t [allocSize];
    Hel = new AuxField (HelData, nz, elmt, 'H');
    if (add[HELICITY]) addField[iAdd++] = Hel;
  }

  // -- Cycle through field dump, first (if required) making the only
  //    two things which just need the velocity and no gradients, then
  //    if needed computing the full VG tensor and work forward from
  //    there.  The order of computation is determined by
  //    dependencies.  Then write requested output, listed in
  //    addField.
  
  while (getDump (D, file)) {
        
    if (need[FUNCTION]) *Func = func;

    if (need[ENERGY]) ((*Nrg) . innerProduct (velocity, velocity)) *= 0.5;

    if (gradient) {		// -- All other things.

      // -- First make all VG components.

      for (i = 0; i < NDIM ; i++)
	for (j = 0; j < NCOM ; j++) {
	  *Vij[i][j] = *velocity[j];
	  if (i == 2) Vij[i][j] -> transform (FORWARD);
	  Vij[i][j] -> gradient (i);
	  if (i == 2) Vij[i][j] -> transform (INVERSE);
	}

      if (Geometry::cylindrical()) {
	work = new AuxField (new real_t[allocSize],  nz, elmt);
	if (NDIM == 3) for (j = 0; j < NCOM; j++) Vij[2][j] -> divY();
	(*work = *velocity[1]) . divY(); *Vij[2][2] += *work;
#if 1
	if (NCOM == 3) { (*work = *velocity[2]) . divY(); *Vij[1][2] += *work; }
#else
	if (NCOM == 3) { (*work = *velocity[2]) . divY(); *Vij[1][2] -= *work; }
#endif
      }

#if 1
      // -- Loop over every point in the mesh and compute everything
      //    from Vij.  Quite likely this could be made more efficient
      //    but for now simplicity is the aim.

      for (i = 0; i < allocSize; i++) {

	for (k = 0, p = 0; p < 3; p++) {
	  for (q = 0; q < 3; q++, k++)
	    tensor [k] = VijData [p][q][i];
	}

	// -- These operations produce a simple scalar result from Vij.

	if (need[DIVERGENCE])   DivData[i] = tensor3::trace      (tensor);
	if (need[ENSTROPHY])    EnsData[i] = tensor3::enstrophy  (tensor);
	if (need[DISCRIMINANT]) DisData[i] = tensor3::discrimi   (tensor);
	if (need[STRAINRATE])   StrData[i] = tensor3::strainrate (tensor);
	if (need[VORTEXCORE])   VtxData[i] = tensor3::lambda2    (tensor);

	// -- Vorticity could be considered scalar in 2D.

	if (need[VORTICITY]) {
	  tensor3::vorticity (tensor, vort);
	  if (NDIM == 2) 
	    VorData[0][i] = vort[2];
	  else { 
	    VorData[0][i] = vort[0]; 
	    VorData[1][i] = vort[1]; 
	    VorData[2][i] = vort[2];
	  }
	}

	if (!(need[HELICITY] || need[DIVLAMB])) continue;

	// -- Last two measures need velocity too, only made for NDIM = 3.

	vel[0] = velocity[0] -> data()[i];
	vel[1] = velocity[1] -> data()[i];
	vel[2] = velocity[2] -> data()[i];

	if (need[HELICITY]) HelData[i] = tensor3::helicity (tensor, vel);


	if (need[DIVLAMB]) {
	  tensor3::lambvector (tensor, vel, vort); // -- vort is a dummy.
	  LamData[0][i] = vort[0]; 
	  LamData[1][i] = vort[1]; 
	  LamData[2][i] = vort[2];
	}
      }

      // -- For this case, we still need to compute a divergence:
      
      if (need[DIVLAMB]) {
	lamb[0] -> gradient (0);
	(*lamb[2]) . transform (FORWARD) . gradient (2) . transform(INVERSE);
	if (Geometry::cylindrical()) lamb[2] -> divY();
	*lamb[0] += *lamb[2];
	if (Geometry::cylindrical()) *lamb[0] += (*lamb[2] = *lamb[1]) . divY();
	*lamb[0] += (*lamb[1]) . gradient (1);
      }
    }
#else

      if (need[DISCRIMINANT]) {

	// -- 2nd invariant (Q from Chong et al.).
	
	InvQ -> times      (*Vij[0][0], *Vij[1][1]);
	InvQ -> timesMinus (*Vij[0][1], *Vij[1][0]);
	InvQ -> timesPlus  (*Vij[0][0], *Vij[2][2]);

	InvQ -> timesMinus (*Vij[0][2], *Vij[2][0]);
	InvQ -> timesPlus  (*Vij[1][1], *Vij[2][2]);
	InvQ -> timesMinus (*Vij[1][2], *Vij[2][1]);

	// -- 3rd invariant: determinant of Vij (R from Chong et al.).

	work -> times      (*Vij[1][1], *Vij[2][2]);
	work -> timesMinus (*Vij[2][1], *Vij[1][2]);
	InvR -> times      (*work,      *Vij[0][0]);

	work -> times      (*Vij[1][2], *Vij[2][0]);
	work -> timesMinus (*Vij[2][2], *Vij[1][0]);
	InvR -> timesPlus  (*work,      *Vij[0][1]);

	work -> times      (*Vij[2][1], *Vij[1][0]);
	work -> timesMinus (*Vij[1][1], *Vij[2][0]);
	InvR -> timesPlus  (*work,      *Vij[0][2]);

	// -- Discriminant L of Vij.
	//    NB: DIVERGENCE (P from Chong et al.) ASSUMED = 0.

	work -> times (*InvQ, *InvQ);
	Disc -> times (*work, *InvQ);
	work -> times (*InvR, *InvR);
	*work *= 6.75;
	*Disc += *work;
      }

      if (need[DIVERGENCE])
	for (i = 0; i < nComponent; i++) *Div += *Vij[i][i];

    
      if (need[VORTICITY]) {
	if (nComponent == 2) {
	  *vorticity[0]  = *Vij[1][0];
	  *vorticity[0] -= *Vij[0][1];
	} else {
	  *vorticity[0]  = *Vij[2][1];
	  *vorticity[0] -= *Vij[1][2];
	  *vorticity[1]  = *Vij[0][2];
	  *vorticity[1] -= *Vij[2][0];
	  *vorticity[2]  = *Vij[1][0];
	  *vorticity[2] -= *Vij[0][1];
	}
      }

      if (need[DIVLAMB]) {
	if (nComponent == 2) {
	  *lamb[0] = 0.0;
	  lamb[0] -> timesMinus (*D -> u[1], *vorticity[0]);
	  lamb[1] -> times      (*D -> u[0], *vorticity[0]);
	  *DivL  = (*work = *lamb[0]) . gradient (0);
	  *DivL += (*work = *lamb[1]) . gradient (1);
	  if (Geometry::cylindrical())
	    *DivL += (*work = *lamb[1]) . divY();
	} else {
	  lamb[0] -> times      (*D -> u[2], *vorticity[1]);
	  lamb[0] -> timesMinus (*D -> u[1], *vorticity[2]);
	  lamb[1] -> times      (*D -> u[0], *vorticity[2]);
	  lamb[1] -> timesMinus (*D -> u[2], *vorticity[0]);
	  lamb[2] -> times      (*D -> u[1], *vorticity[0]);
	  lamb[2] -> timesMinus (*D -> u[0], *vorticity[1]);
	  *DivL  = (*work = *lamb[0]) . gradient (0);
	  *DivL += (*work = *lamb[1]) . gradient (1);
	  (*work = *lamb[2]).transform(FORWARD).gradient(2).transform(INVERSE);
	  if (Geometry::cylindrical()) {
	    *DivL += work -> divY();
	    *DivL += (*work = *lamb[1]) . divY();
	  } else
	    *DivL += *work;
	}
      }
    
      if (need[ENSTROPHY])
	Ens -> innerProduct (vorticity, vorticity) *= 0.5;

      if (need[HELICITY])
	Hel -> innerProduct (vorticity, velocity)  *= 0.5;

      if (need[STRAINTENSOR]) {
	for (i = 0; i < nComponent; i++)
	  for (j = i; j < nComponent; j++) {
	    *Sij[i][j]  = *Vij[i][j];
	    *Sij[i][j] += *Vij[j][i];
	    *Sij[i][j] *= 0.5;
	  }
      }

      if (need[STRAINRATE]) {
	*Strain = 0.0;
	for (i = 0; i < nComponent; i++)
	  for (j = 0; j < nComponent; j++)
	    Strain -> timesPlus (*Sij[i][j], *Sij[j][i]);
	(*Strain *= 2.0) . sqroot();
      }

      if (need[VORTEXCORE])	// -- Only done for 3-component fields.
	for (i = 0; i < allocSize; i++) {
	  for (k = 0, p = 0; p < 3; p++)
	    for (q = 0; q < 3; q++, k++)
	      tensor [k] = VijData[p][q][i];
	  VtxData[i] = lambda2 (tensor);
	}
    }
#endif
    // -- Finally, add mass-projection smoothing on everything.

    for (i = 0; i < iAdd; i++) D -> u[0] -> smooth (addField[i]);

    putDump (D, addField, iAdd, cout);
  }
Exemple #3
0
        SSVUT_EXPECT(SSVPP_TPL_ELEM(SSVPP_TPL_PUSH_BACK((1, 2), 3), 0) == 1);
        SSVUT_EXPECT(SSVPP_TPL_ELEM(SSVPP_TPL_PUSH_BACK((1, 2), 3), 2) == 3);
    }

    {
        SSVUT_EXPECT(SSVPP_TPL_SIZE(SSVPP_TPL_FILL(())) == SSVPP_TPL_MAX_SIZE);
        SSVUT_EXPECT(SSVPP_TPL_SIZE(SSVPP_TPL_FILL((1))) == SSVPP_TPL_MAX_SIZE);
        SSVUT_EXPECT(SSVPP_TPL_SIZE(SSVPP_TPL_FILL((1, 1))) == SSVPP_TPL_MAX_SIZE);
        SSVUT_EXPECT(SSVPP_TPL_SIZE(SSVPP_TPL_FILL((1, 1, 1))) == SSVPP_TPL_MAX_SIZE);
    }

    {
#define SSVU_TEST_GEN_LMBD(mReturn, mName, mBody) auto mName = []() -> mReturn { mBody };

        SSVU_TEST_GEN_LMBD(__R(std::pair<int, int>), __R(lambda1), __R(return std::make_pair(1, 5);));
        SSVU_TEST_GEN_LMBD(__R(std::pair<int, std::pair<float, float>>), __R(lambda2), __R(return std::make_pair(2, std::pair<float, float>(1.5f, 2.5f));));

        SSVUT_EXPECT(lambda1().first == 1);
        SSVUT_EXPECT(lambda1().second == 5);

        SSVUT_EXPECT(lambda2().first == 2);
        SSVUT_EXPECT(lambda2().second.first == 1.5f);
        SSVUT_EXPECT(lambda2().second.second == 2.5f);

#undef SSVU_TEST_GEN_LMBD
    }
}

#endif
Exemple #4
0
RcppExport SEXP nsem3b(SEXP data,  
		      SEXP theta,
		      SEXP Sigma,
		      SEXP modelpar,
		    SEXP control
		    ) {   

  //  srand ( time(NULL) ); /* initialize random seed: */
  
  Rcpp::NumericVector Theta(theta);  
  Rcpp::NumericMatrix D(data);
  unsigned nobs = D.nrow(), k = D.ncol();
  mat Data(D.begin(), nobs, k, false); // Avoid copying
  Rcpp::NumericMatrix V(Sigma);  
  mat S(V.begin(), V.nrow(), V.ncol()); 
  S(0,0) = 1;
  mat iS = inv(S);
  double detS = det(S);
 

  Rcpp::List Modelpar(modelpar);
  // Rcpp::IntegerVector _nlatent = Modelpar["nlatent"]; unsigned nlatent = _nlatent[0];
  Rcpp::IntegerVector _ny0 = Modelpar["nvar0"]; unsigned ny0 = _ny0[0];
  Rcpp::IntegerVector _ny1 = Modelpar["nvar1"]; unsigned ny1 = _ny1[0];
  Rcpp::IntegerVector _ny2 = Modelpar["nvar2"]; unsigned ny2 = _ny2[0];
  Rcpp::IntegerVector _npred0 = Modelpar["npred0"]; unsigned npred0 = _npred0[0];
  Rcpp::IntegerVector _npred1 = Modelpar["npred1"]; unsigned npred1 = _npred1[0];
  Rcpp::IntegerVector _npred2 = Modelpar["npred2"]; unsigned npred2 = _npred2[0];
  Rcpp::List Control(control);   
  Rcpp::NumericVector _lambda = Control["lambda"]; double lambda = _lambda[0];
  Rcpp::NumericVector _niter = Control["niter"]; double niter = _niter[0];
  Rcpp::NumericVector _Dtol = Control["Dtol"]; double Dtol = _Dtol[0];


  rowvec mu0(ny0), lambda0(ny0);
  rowvec mu1(ny1), lambda1(ny1);
  rowvec mu2(ny2), lambda2(ny2);
  rowvec beta0(npred0); 
  rowvec beta1(npred1); 
  rowvec beta2(npred2);
  rowvec gamma(2);
  rowvec gamma2(2);  
  unsigned pos=0;
  for (unsigned i=0; i<ny0; i++) {
    mu0(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<ny1; i++) {
    mu1(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<ny2; i++) {
    mu2(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<ny0; i++) {
    lambda0(i) = Theta[pos];
    pos++;
  }
  lambda1(0) = 1;
  for (unsigned i=1; i<ny1; i++) {
    lambda1(i) = Theta[pos];
    pos++;
  }
  lambda2(0) = 1;
  for (unsigned i=1; i<ny2; i++) {
    lambda2(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<npred0; i++) {
    beta0(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<npred1; i++) {
    beta1(i) = Theta[pos];
    pos++;
  }
  for (unsigned i=0; i<npred2; i++) {
    beta2(i) = Theta[pos];
    pos++;
  }
  gamma(0) = Theta[pos]; gamma(1) = Theta[pos+1];
  gamma2(0) = Theta[pos+2]; gamma2(1) = Theta[pos+3];

  // cerr << "mu0=" << mu0 << endl;
  // cerr << "mu1=" << mu1 << endl;
  // cerr << "mu2=" << mu2 << endl;
  // cerr << "lambda0=" << lambda0 << endl;
  // cerr << "lambda1=" << lambda1 << endl;
  // cerr << "lambda2=" << lambda2 << endl;
  // cerr << "beta0=" << beta0 << endl;
  // cerr << "beta1=" << beta1 << endl;
  // cerr << "beta2=" << beta2 << endl;
  // cerr << "gamma=" << gamma << endl;
  // cerr << "gamma2=" << gamma2 << endl;
  
  mat lap(nobs,4);
  for (unsigned i=0; i<nobs; i++) {
    rowvec newlap = laNRb(Data.row(i), iS, detS,
			  mu0, mu1, mu2, 
			  lambda0, lambda1, lambda2, 
			  beta0,beta1, beta2, gamma, gamma2,
			  Dtol,niter,lambda);
    lap.row(i) = newlap;
  }

  List  res;
  res["indiv"] = lap;
  res["logLik"] = sum(lap.col(0)) + (3-V.nrow())*log(2.0*datum::pi)*nobs/2;
  res["norm0"] = (3-V.nrow())*log(2*datum::pi)/2;
  return res;
}
Exemple #5
0
static double refmap_tetra_f1(double x, double y, double z) { return lambda2(x, y, z); }
Exemple #6
0
int main (int    argc,
	  char** argv)
// ---------------------------------------------------------------------------
// Driver.
// ---------------------------------------------------------------------------
{
  Geometry::CoordSys         system;
  char                       *session, *dump, *func, fields[StrMax];
  int_t                      i, j, k, p, q;
  int_t                      np, nz, nel, allocSize, nComponent;
  int_t                      iAdd = 0;
  bool                       add[FLAG_MAX], need[FLAG_MAX], gradient;
  ifstream                   file;
  FEML*                      F;
  Mesh*                      M;
  BCmgr*                     B;
  Domain*                    D;
  vector<Element*>           elmt;
  AuxField                   *Ens, *Hel, *Div, *InvQ, *InvR, *Disc, *Strain;
  AuxField                   *Func, *Ell, *Egr, *Vtx, *work, *DivL, *Nrg;
  vector<AuxField*>          lamb, velocity, vorticity, addField(FLDS_MAX);
  vector<vector<AuxField*> > Sij;
  vector<vector<AuxField*> > Vij;     // -- Usually computed, for internal use.
  vector<vector<real_t*> >   VijData; // -- For pointwise access.
  real_t                     *egrow, *VtxData; // -- Ditto.
  real_t                     tensor[9];

  Femlib::initialize (&argc, &argv);
  for (i = 0; i < FLAG_MAX; i++) add [i] = need [i] = false;

  // -- Read command line.

  getargs (argc, argv, session, dump, func, add);

  file.open (dump);
  if (!file) message (prog, "can't open input field file", ERROR);

  // -- Set up domain.

  F      = new FEML (session);
  M      = new Mesh (F);
  nel    = M -> nEl ();  
  np     =  Femlib::ivalue ("N_P");
  nz     =  Femlib::ivalue ("N_Z");
  system = (Femlib::ivalue ("CYLINDRICAL") ) ?
                       Geometry::Cylindrical : Geometry::Cartesian;
  Geometry::set (np, nz, nel, system);
  if   (nz > 1) strcpy (fields, "uvwp");
  else          strcpy (fields, "uvp");
  nComponent = Geometry::nDim();
  allocSize  = Geometry::nTotal();

  elmt.resize (nel);
  for (i = 0; i < nel; i++) elmt[i] = new Element (i, np, M);

  B = new BCmgr  (F, elmt);
  D = new Domain (F, elmt, B);

  velocity.resize   (nComponent);
  vorticity.resize ((nComponent == 2) ? 1 : 3);
  for (i = 0; i < nComponent; i++) velocity[i] = D -> u[i];

  // -- From the requested fields, flag dependencies.

  if  (nComponent < 3)
    add[HELICITY] = add[DISCRIMINANT] = add[VORTEXCORE] = false;

  for (p = 0, i = 0; i < FLAG_MAX; i++) p += (add[i]) ? 1 : 0;
  if  (p == 0) message (prog, "nothing to be done", ERROR);

  for (p = 0, i = 0; i < FLAG_MAX; i++)
    p += (add[i]) ? (i + 1) : 0;
  if (p <= 3) gradient = false; else gradient = true;

  for (i = 0; i < FLAG_MAX; i++) need[i] = add[i];

  if (add[ENSTROPHY]) {
    need[VORTICITY]    = true;
    need[ENSTROPHY]    = true;
  }
  if (add[HELICITY]) {
    need[VORTICITY]    = true;
  }
  if (add[ELLIPTICITY]) {
    need[VORTICITY]    = true;
    need[ENSTROPHY]    = true;
    need[STRAINRATE]   = true;
    need[STRAINTENSOR] = true;
  }
  if (add[STRAINRATE]) {
    need[STRAINTENSOR] = true;
  }
  if (add[EGROWTH]) {
    need[VORTICITY]    = true;
    need[ENSTROPHY]    = true;
    need[STRAINRATE]   = true;
    need[STRAINTENSOR] = true;
    need[ELLIPTICITY]  = true;
  }
  if (add[LAMBVECTOR]) {
    need[VORTICITY]    = true;
    need[LAMBVECTOR]   = true;
  }

  // -- If any gradients need to be computed, we make all of them.
  
  if (gradient) {
    Vij    .resize (nComponent);
    VijData.resize (nComponent);
    for (i = 0; i < nComponent; i++) {
      Vij    [i].resize (nComponent);
      VijData[i].resize (nComponent);
      for (j = 0; j < nComponent; j++) {
	VijData[i][j] = new real_t [allocSize];
	Vij   [i][j] = new AuxField (VijData[i][j], nz, elmt);
	*Vij  [i][j] = 0.0;
      }
    }
  }
  
  // -- Fields without dependants.

  work = new AuxField (new real_t[allocSize], nz, elmt);

  if (need[ENERGY]) {
    Nrg = new AuxField (new real_t[allocSize], nz, elmt, 'q');
    addField[iAdd++] = Nrg;
  }

  if (need[FUNCTION]) {
    Func = new AuxField (new real_t[allocSize], nz, elmt, 'f');
    addField[iAdd++] = Func;
  }

  if (need[DIVERGENCE]) {
    Div  =  new AuxField (new real_t[allocSize], nz, elmt, 'd');
    *Div = 0.0;
    addField[iAdd++] = Div;
  }

  if (need[DISCRIMINANT]) {
    *(InvQ = new AuxField (new real_t[allocSize], nz, elmt, 'Q')) = 0.0;
    *(InvR = new AuxField (new real_t[allocSize], nz, elmt, 'R')) = 0.0;
    *(Disc = new AuxField (new real_t[allocSize], nz, elmt, 'L')) = 0.0;
    addField[iAdd++] = Disc;
  }

  if (need[VORTEXCORE]) {
    VtxData = new real_t [allocSize];
    Vtx = new AuxField (VtxData, nz, elmt, 'J');
    addField[iAdd++] = Vtx;
  }

  // -- Vorticity and its dependants.

  if (need[VORTICITY])
    if (nComponent == 2) {
      vorticity[0] = new AuxField (new real_t[allocSize], nz, elmt, 't');
      if (add[VORTICITY])
	addField[iAdd++] = vorticity[0];
    } else {
      for (i = 0; i < nComponent; i++)
	vorticity[i] = new AuxField (new real_t[allocSize], nz, elmt, 'r' + i);
      if (add[VORTICITY])
	for (i = 0; i < 3; i++) addField[iAdd++] = vorticity[i];
    }

  if (add[LAMBVECTOR]) {
    if (nComponent == 2) {
      lamb.resize(2);
      for (i = 0; i < nComponent; i++)
	lamb[i] = new AuxField (new real_t[allocSize], nz, elmt, 'm' + i);
      for (i = 0; i < 2; i++) addField[iAdd++] = lamb[i];
    } else {
      lamb.resize(3);
      for (i = 0; i < nComponent; i++)
	lamb[i] = new AuxField (new real_t[allocSize], nz, elmt, 'm' + i);
      for (i = 0; i < 3; i++) addField[iAdd++] = lamb[i];
    }
    DivL = new AuxField (new real_t[allocSize], nz, elmt, 'Q');
    addField[iAdd++] = DivL;
  }

  if (need[ENSTROPHY]) {
    Ens = new AuxField (new real_t[allocSize], nz, elmt, 'e');
    if (add[ENSTROPHY]) addField[iAdd++] = Ens;
  }
  
  if (need[HELICITY]) {
    Hel = new AuxField (new real_t[allocSize], nz, elmt, 'h');
    if (add[HELICITY]) addField[iAdd++] = Hel;
  }

  if (need[ELLIPTICITY]) {
    Ell = new AuxField (new real_t[allocSize], nz, elmt, 'b');
    if (add[ELLIPTICITY]) addField[iAdd++] = Ell;
  }

  // -- Rate of strain tensor and its dependants.

  if (need[STRAINTENSOR]) {
    Sij.resize (nComponent);
    for (k = 0, i = 0; i < nComponent; i++) {
      Sij[i].resize (nComponent);
      for (j = 0; j < nComponent; j++) {
	if (j >= i) {
	  Sij[i][j] = new AuxField (new real_t[allocSize], nz, elmt, 'i'+k++);
	} else
	  Sij[i][j] = Sij[j][i];
      }
    }
  }

  if (need[STRAINRATE]) {
    *(Strain = new AuxField (new real_t[allocSize], nz, elmt, 'g')) = 0.0;
    if (add[STRAINRATE]) addField[iAdd++] = Strain;
  }

  if (need[EGROWTH]) {
    egrow = new real_t[allocSize]; // -- A handle for direct access to data.
    Egr = new AuxField (egrow, nz, elmt, 'a');
    if (add[EGROWTH]) addField[iAdd++] = Egr;
  }
  
  // -- Cycle through field dump, first computing the velocity
  //    gradient tensor and then the needed quantities -- vorticity
  //    etc.  The order of computation is determined by dependencies.
  //    Then write requested output, listed in addField.
  
  while (getDump (D, file)) {
        
    if (need[FUNCTION]) *Func = func;

    // -- Velocity gradient tensor; transform required for z (2) gradient.  

    if (nComponent > 2) D -> transform (FORWARD);

    if (gradient)
      for (i = 0; i < nComponent ; i++)
	for (j = 0; j < nComponent ; j++) {
	  (*Vij[i][j] = *velocity[i]) . gradient (j);
	  Vij[i][j] -> transform (INVERSE);
	}

    if (need[ENERGY]) {
      *Nrg = 0.0;
      for (i = 0; i < nComponent ; i++)
	Nrg -> timesPlus (*D -> u[i], *D -> u[i]);
      *Nrg *= 0.5;
    }

    if (nComponent > 2) D -> transform (INVERSE);

    if (Geometry::cylindrical() && nComponent == 3) {
      for (i = 0; i < nComponent; i++) Vij[i][2] -> divY();
      (*work = *D -> u[2]) . divY();  *Vij[1][2] -= *work;
      (*work = *D -> u[1]) . divY();  *Vij[2][2] += *work;
    }
    
    if (need[DISCRIMINANT]) {

      // -- 2nd invariant (Q from Chong et al.).

      InvQ -> times      (*Vij[0][0], *Vij[1][1]);
      InvQ -> timesMinus (*Vij[0][1], *Vij[1][0]);
      InvQ -> timesPlus  (*Vij[0][0], *Vij[2][2]);
      InvQ -> timesMinus (*Vij[0][2], *Vij[2][0]);
      InvQ -> timesPlus  (*Vij[1][1], *Vij[2][2]);
      InvQ -> timesMinus (*Vij[1][2], *Vij[2][1]);

      // -- 3rd invariant: determinant of Vij (R from Chong et al.).

      work -> times      (*Vij[1][1], *Vij[2][2]);
      work -> timesMinus (*Vij[2][1], *Vij[1][2]);
      InvR -> times      (*work,      *Vij[0][0]);

      work -> times      (*Vij[1][2], *Vij[2][0]);
      work -> timesMinus (*Vij[2][2], *Vij[1][0]);
      InvR -> timesPlus  (*work,      *Vij[0][1]);

      work -> times      (*Vij[2][1], *Vij[1][0]);
      work -> timesMinus (*Vij[1][1], *Vij[2][0]);
      InvR -> timesPlus  (*work,      *Vij[0][2]);

      // -- Discriminant L of Vij.
      //    NB: DIVERGENCE (P from Chong et al.) ASSUMED = 0.

      work -> times (*InvQ, *InvQ);
      Disc -> times (*work, *InvQ);
      work -> times (*InvR, *InvR);
      *work *= 6.75;
      *Disc += *work;
    }
	
    if (need[DIVERGENCE])
      for (i = 0; i < nComponent; i++) *Div += *Vij[i][i];
    
    if (need[VORTICITY]) {
      if (nComponent == 2) {
	*vorticity[0]  = *Vij[1][0];
	*vorticity[0] -= *Vij[0][1];
      } else {
	*vorticity[0]  = *Vij[2][1];
	*vorticity[0] -= *Vij[1][2];
	*vorticity[1]  = *Vij[0][2];
	*vorticity[1] -= *Vij[2][0];
	*vorticity[2]  = *Vij[1][0];
 	*vorticity[2] -= *Vij[0][1];
      }
    }

    if (need[LAMBVECTOR]) {
      if (nComponent == 2) {
	*lamb[0] = 0.0;
	lamb[0] -> timesMinus (*D -> u[1], *vorticity[0]);
	lamb[1] -> times      (*D -> u[0], *vorticity[0]);
	*DivL  = (*work = *lamb[0]) . gradient (0);
	*DivL += (*work = *lamb[1]) . gradient (1);
	if (Geometry::cylindrical())
	  *DivL += (*work = *lamb[1]) . divY();
      } else {
	lamb[0] -> times      (*D -> u[2], *vorticity[1]);
	lamb[0] -> timesMinus (*D -> u[1], *vorticity[2]);
	lamb[1] -> times      (*D -> u[0], *vorticity[2]);
	lamb[1] -> timesMinus (*D -> u[2], *vorticity[0]);
	lamb[2] -> times      (*D -> u[1], *vorticity[0]);
	lamb[2] -> timesMinus (*D -> u[0], *vorticity[1]);
	*DivL  = (*work = *lamb[0]) . gradient (0);
	*DivL += (*work = *lamb[1]) . gradient (1);
	(*work = *lamb[2]).transform(FORWARD).gradient(2).transform(INVERSE);
	if (Geometry::cylindrical()) {
	  *DivL += work -> divY();
	  *DivL += (*work = *lamb[1]) . divY();
	} else
	  *DivL += *work;
      }
    }
    
    if (need[ENSTROPHY])
      Ens -> innerProduct (vorticity, vorticity) *= 0.5;

    if (need[HELICITY])
      Hel -> innerProduct (vorticity, velocity)  *= 0.5;

    if (need[STRAINTENSOR]) {
      for (i = 0; i < nComponent; i++)
	for (j = i; j < nComponent; j++) {
	  *Sij[i][j]  = *Vij[i][j];
	  *Sij[i][j] += *Vij[j][i];
	  *Sij[i][j] *= 0.5;
	}
    }

    if (need[STRAINRATE]) {
      *Strain = 0.0;
      for (i = 0; i < nComponent; i++)
	for (j = 0; j < nComponent; j++)
	  Strain -> timesPlus (*Sij[i][j], *Sij[j][i]);
      (*Strain *= 2.0) . sqroot();
    }

    if (need[ELLIPTICITY]) {
      ((*work = *Ens) . sqroot() *= 2.0) += 1.0e-1;
      Ell -> divide (*Strain, *work);
    }

    if (need[EGROWTH]) {
      *Egr = *Ell;
      Veclib::clip (allocSize, 0.0, 1.0, egrow, 1, egrow, 1);
      Veclib::spow (allocSize, 2.811,    egrow, 1, egrow, 1);
      Veclib::vneg (allocSize,           egrow, 1, egrow, 1);
      Veclib::sadd (allocSize, 1.0,      egrow, 1, egrow, 1);
      Veclib::spow (allocSize, 0.3914,   egrow, 1, egrow, 1);
      Veclib::smul (allocSize, 9.0/16.0, egrow, 1, egrow, 1);
      (*work = *Strain) *= sqrt (1.0/8.0);
      Egr -> times (*Egr, *work);
    }

    if (need[VORTEXCORE])	// -- Only done for 3-component fields.
      for (i = 0; i < allocSize; i++)
	for (k = 0, p = 0; p < 3; p++)
	  for (q = 0; q < 3; q++, k++) {
	    tensor [k] = VijData[p][q][i];
	    VtxData[i] = lambda2 (tensor);
	  }

    // -- Finally, add mass-projection smoothing on everything.

    for (i = 0; i < iAdd; i++) D -> u[0] -> smooth (addField[i]);

    putDump (D, addField, iAdd, cout);
  }
  
  file.close();
  Femlib::finalize();
  return EXIT_SUCCESS;
}