void FieldVariableConditionFunctionSecondCopy_getVal( Node_LocalIndex node_lI, Variable_Index var_I, void* _context, void* data, void* _result ){
   DomainContext*  context = (DomainContext*)_context;
   double*                 coord;
	InterpolationResult	   retValue;
   Stream*                 errorStr = Journal_Register( Error_Type, FieldVariableConditionFunctionSecondCopy_Type  );
	
   FieldVariableConditionFunctionSecondCopy* self = (FieldVariableConditionFunctionSecondCopy*)LiveComponentRegister_Get( context->CF->LCRegister, (Name) FieldVariableConditionFunctionSecondCopy_Type );

   /* if the node is not on the current, local mesh don't interpolate the solution */
   if( node_lI >= Mesh_GetLocalSize( self->targetfeVariable->feMesh, MT_VERTEX ) )
     return; 
      
   coord = Mesh_GetVertex( self->targetfeVariable->feMesh, node_lI );

   /** interpolating the required values from the provided feVariable */
   retValue = FieldVariable_InterpolateValueAt( self->fieldVariable, coord, self->value);

   if(retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL){
      /* due to differences in machine precision, points of interrogation can sometimes appear to be outside the domain. 
         we perturb the interpolation coordinate to see if this fixes the issue. default tolerance is 0.001 the local domain size. 
         sometimes, where a deformed mesh is used, a greater tolerance may be required (as deformation may depend on resolution). */
      double localSizeMin[3], localSizeMax[3], deltaCoord[3];
      double testCoord[3];
      unsigned ii,jj;
      int updown[2] = {-1,1};

      /* determine perturbation */
      Mesh_GetLocalCoordRange( self->targetfeVariable->feMesh, localSizeMin, localSizeMax );      
      for( ii=0; ii< Mesh_GetDimSize(self->targetfeVariable->feMesh); ii++) deltaCoord[ii] = self->failTolerance*(localSizeMax[ii] - localSizeMin[ii]);
      
      /* step coord through +/- perturbation, one dimension at a time, and test */
      ii = 0;
      while( (retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL) && ii < Mesh_GetDimSize(self->targetfeVariable->feMesh) ){
         for( jj=0; jj< 2; jj++){
            memcpy( testCoord, coord, Mesh_GetDimSize(self->targetfeVariable->feMesh)*sizeof(double) );
            testCoord[ii] += updown[jj]*deltaCoord[ii];
            retValue = FieldVariable_InterpolateValueAt( self->fieldVariable, testCoord, self->value);
            if(!(retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL)) break;  /* if success, break */
         }
         ii++;
      }
      if(retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL){                  /* if still no success, report and bail */
         FieldVariable_GetMinAndMaxLocalCoords( self->fieldVariable, localSizeMin, localSizeMax );
         if(Mesh_GetDimSize(self->targetfeVariable->feMesh) == 2)
            Journal_Firewall(!(retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL), 
               errorStr,"\n\nError while trying to interpolate field for FieldVariable Initial Condition.\n"
               "Query location appears outside local domain min or max:\n\n   Location:  %f,%f\n\n   min:  %f,%f\n   max:  %f,%f.\n\n"
               "A tolerance of 0.001*(max-min) is used by default, though you may increase the factor by setting \'FailureTolerance\' within the plugin dictionary.\n\n",
               coord[0], coord[1], localSizeMin[0], localSizeMin[1],localSizeMax[0], localSizeMax[1] );
         else
            Journal_Firewall(!(retValue == OTHER_PROC || retValue == OUTSIDE_GLOBAL), 
               errorStr,"\n\nError while trying to interpolate field for FieldVariable Initial Condition.\n"
               "Query location appears outside local domain min or max:\n\n   Query Location:  %f,%f,%f\n\n   min:  %f,%f,%f\n   max:  %f,%f,%f.\n\n"
               "A tolerance of 0.001*(max-min) is used by default, though you may increase the factor by setting \'FailureTolerance\' within the plugin dictionary.\n\n",
               coord[0], coord[1], coord[2], localSizeMin[0], localSizeMin[1], localSizeMin[2], localSizeMax[0], localSizeMax[1], localSizeMax[2] );            
      }
      
   }
   FeVariable_SetValueAtNode( self->targetfeVariable, node_lI, self->value);
}
/* Old method: sampling in global coords, slower, assumes regular grid */
void lucIsosurface_SampleGlobal( void* drawingObject)
{
   lucIsosurface*             self = (lucIsosurface*)drawingObject;
   FieldVariable*             isosurfaceField = self->isosurfaceField;
   int                        i, j, k;
   double                     dx, dy, dz;
   Coord                      pos;
   Coord                      min, max;
   Vertex***                  vertex;
   double         lengths[3];

   /* Calculate a resolution for this local domain based on a sample size over the entire domain */
   FieldVariable_GetMinAndMaxLocalCoords( isosurfaceField, min, max );
   for (i=0; i<3; i++)
      lengths[i] = (self->globalMax[i] - self->globalMin[i])/((double)self->resolution[i]);
   /* force round up */
   self->nx = ceil((max[0] - min[0]) / lengths[0]) + 1;
   self->ny = ceil((max[1] - min[1]) / lengths[1]) + 1;
   self->nz = ceil((max[2] - min[2]) / lengths[2]) + 1;

   dx = (max[0] - min[0])/((double) self->nx - 1);
   dy = (max[1] - min[1])/((double) self->ny - 1);
   dz = (max[2] - min[2])/((double) self->nz - 1);
   if (self->isosurfaceField->dim == 2)
   {
      dz = 0.0;
      self->nz = 1;
   }

   vertex = Memory_Alloc_3DArray( Vertex , self->nx, self->ny, self->nz , (Name)"Vertex array" );

   /* Sample Field in in regular grid */
   for ( i = 0 ; i < self->nx ; i++ )
   {
      for ( j = 0 ; j < self->ny ; j++ )
      {
         for ( k = 0 ; k < self->nz ; k++ )
         {
            pos[ I_AXIS ] = min[ I_AXIS ] + dx * (double) i;
            pos[ J_AXIS ] = min[ J_AXIS ] + dy * (double) j;
            pos[ K_AXIS ] = min[ K_AXIS ] + dz * (double ) k;

            memcpy( vertex[i][j][k].pos, pos, 3 * sizeof(double) );

            if (!FieldVariable_InterpolateValueAt( isosurfaceField, pos, &vertex[i][j][k].value ))
               /* FieldVariable_InterpolateValueAt returns OTHER_PROC if point not found in mesh, so zero value */
               vertex[i][j][k].value = 0;
         }
      }
   }

   if (self->isosurfaceField->dim == 3)
      /* Find Surface with Marching Cubes */
      lucIsosurface_MarchingCubes( self, vertex );

   if (self->isosurfaceField->dim == 2 || self->drawWalls)
      lucIsosurface_DrawWalls( self, vertex );

   /* Free memory */
   Memory_Free( vertex );
}
void lucMeshCrossSection_Sample( void* drawingObject, Bool reverse)
{
   lucMeshCrossSection* self          = (lucMeshCrossSection*)drawingObject;
   FeVariable*          fieldVariable = (FeVariable*) self->fieldVariable;
   Mesh*                mesh          = (Mesh*) fieldVariable->feMesh;
   Grid*                vertGrid;
   Node_LocalIndex      crossSection_I;
   IJK                  node_ijk;
   Node_GlobalIndex     node_gI;
   Node_DomainIndex     node_dI;
   int                  i,j, d, sizes[3] = {1,1,1};
   Coord                globalMin, globalMax, min, max;

      int localcount = 0;

   vertGrid = *(Grid**)ExtensionManager_Get( mesh->info, mesh, self->vertexGridHandle );
   for (d=0; d<fieldVariable->dim; d++) sizes[d] = vertGrid->sizes[d];
   self->dim[0] = sizes[ self->axis ];
   self->dim[1] = sizes[ self->axis1 ];
   self->dim[2] = sizes[ self->axis2 ];

   crossSection_I = lucCrossSection_GetValue(self, 0, self->dim[0]-1);

   FieldVariable_GetMinAndMaxLocalCoords( fieldVariable, min, max );
   FieldVariable_GetMinAndMaxGlobalCoords( fieldVariable, globalMin, globalMax );

   Journal_Printf( lucDebug, "%s called on field %s, with axis of cross section as %d, crossSection_I as %d (dims %d,%d,%d) field dim %d\n",
                    __func__, fieldVariable->name, self->axis, crossSection_I, self->dim[0], self->dim[1], self->dim[2], self->fieldDim);

   /* Get mesh cross section self->vertices and values */
   self->resolutionA = self->dim[1];
   self->resolutionB = self->dim[2];
   lucCrossSection_AllocateSampleData(self, self->fieldDim);
   int lSize = Mesh_GetLocalSize( mesh, MT_VERTEX );
   double time = MPI_Wtime();
   Journal_Printf(lucInfo, "Sampling mesh (%s) %d x %d...  0%", self->name, self->dim[1], self->dim[2]);
   node_ijk[ self->axis ] = crossSection_I;
   for ( i = 0 ; i < self->dim[1]; i++ )
   {
      int percent = 100 * (i + 1) / self->dim[1];
      Journal_Printf(lucInfo, "\b\b\b\b%3d%%", percent);
      fflush(stdout);

      /* Reverse order if requested */
      int i0 = i;
      if (reverse) i0 = self->dim[1] - i - 1;

      node_ijk[ self->axis1 ] = i0;

      for ( j = 0 ; j < self->dim[2]; j++ )
      {
         self->vertices[i][j][0] = HUGE_VAL;
         self->vertices[i][j][2] = 0;
         node_ijk[ self->axis2 ] = j;
         node_gI = Grid_Project( vertGrid, node_ijk );
         /* Get coord and value if node is local... */
         if (Mesh_GlobalToDomain( mesh, MT_VERTEX, node_gI, &node_dI ) && node_dI < lSize)
         {  
            /* Found on this processor */
            double value[self->fieldDim];
            FeVariable_GetValueAtNode( fieldVariable, node_dI, value );
            double* pos = Mesh_GetVertex( mesh, node_dI );
            /*fprintf(stderr, "[%d] (%d,%d) Node %d %f,%f,%f value %f\n", self->context->rank, i, j, node_gI, pos[0], pos[1], pos[2], value);*/
         
            for (d=0; d<fieldVariable->dim; d++)
               self->vertices[i][j][d] = pos[d];

            for (d=0; d<self->fieldDim; d++)
               self->values[i][j][d] = (float)value[d];

            localcount++;
         }
      }
   }
   Journal_Printf(lucInfo, " %f sec. ", MPI_Wtime() - time);

   /* Collate */
   time = MPI_Wtime();
   for ( i=0 ; i < self->dim[1]; i++ )
   {
      for ( j=0 ; j < self->dim[2]; j++ )
      {
         /* Receive values at root */
         if (self->context->rank == 0)
         {
            /* Already have value? */
            if (self->vertices[i][j][0] != HUGE_VAL) {localcount--; continue; }

            /* Recv (pos and value together = (3 + fevar dims)*float) */
            float data[3 + self->fieldDim];
            (void)MPI_Recv(data, 3+self->fieldDim, MPI_FLOAT, MPI_ANY_SOURCE, i*self->dim[2]+j, self->context->communicator, MPI_STATUS_IGNORE);
            /* Copy */
            memcpy(self->vertices[i][j], data, 3 * sizeof(float));
            memcpy(self->values[i][j], &data[3], self->fieldDim * sizeof(float));
         }
         else
         {
            /* Found on this proc? */
            if (self->vertices[i][j][0] == HUGE_VAL) continue;

            /* Copy */
            float data[3 + self->fieldDim];
            memcpy(data, self->vertices[i][j], 3 * sizeof(float));
            memcpy(&data[3], self->values[i][j], self->fieldDim * sizeof(float));

            /* Send values to root (pos & value = 4 * float) */
            MPI_Ssend(data, 3+self->fieldDim, MPI_FLOAT, 0, i*self->dim[2]+j, self->context->communicator);
            localcount--;
         }
      }
   }
   MPI_Barrier(self->context->communicator);    /* Barrier required, prevent subsequent MPI calls from interfering with transfer */
   Journal_Printf(lucInfo, " Gather in %f sec.\n", MPI_Wtime() - time);
   Journal_Firewall(localcount == 0, lucError,
                     "Error - in %s: count of values sampled compared to sent/received by mpi on proc %d does not match (balance = %d)\n",
                     __func__, self->context->rank, localcount);
}