Beispiel #1
0
void nuc3d::tvdrk3rd::rk2nd(const VectorField &RHS,
                            const VectorField &u_n, // u_n
                            VectorField &u_i,
                            double dt)
{
    int nx=u_n.begin()->getSizeX();
    int ny=u_n.begin()->getSizeY();
    int nz=u_n.begin()->getSizeZ();
    
    auto beg=u_i.begin();
    auto end=u_i.end();
    
    
    for (auto iter=beg; iter!=end; ++iter)
    {
        for(int k=0;k<nz;++k)
        {
            for(int j=0;j<ny;++j)
            {
                for(int i=0;i<nx;++i)
                {
                    double rhs=-RHS[iter-beg].getValue(i,j,k);
                    double u=u_n[iter-beg].getValue(i, j, k);
                    double u1=iter->getValue(i, j, k);
                    
                    double u2 = coeff_tvdrk3_alpha0[1][0]*u
                    +coeff_tvdrk3_alpha0[1][1]*(rhs*dt+u1);
                    
                    iter->setValue(i,j,k,u2);
                }
            }
        }
    }
}
Beispiel #2
0
void mark(
    size_t const s,
    boost::shared_ptr<std::vector<bool> >& marked,
    bool const value,
    VectorField const& V,
    Incidences const& I)
{
    std::queue<size_t> queue;

    marked->at(s) = value;
    queue.push(s);

    while (not queue.empty())
    {
        size_t const a = queue.front();
        queue.pop();
        for (int i = 0; i < I.count(a); ++i)
        {
            size_t const b = I(a, i);
            if (V.defined(b) and V(b) != a)
            {
                size_t const c = V(b);
                if (c != b and marked->at(c) != value)
                {
                    queue.push(c);
                    marked->at(b) = marked->at(c) = value;
                }
            }
        }
    }
}
int main(int argc, char ** argv)
{
  const bool verbose = argc == 2 &&
    (strcmp(argv[1], "-v") == 0 ||
     strcmp(argv[1], "--verbose") == 0);

  /**
   * Create a model object and input data
   */

  const double length = 2000.0, width = 500.0;
  Triangulation<2> tria = testing::rectangular_glacier(length, width);
  const double dx = dealii::GridTools::minimal_cell_diameter(tria);

  const IceShelf ice_shelf(tria, 1);

  const Field<2> h = ice_shelf.interpolate(Thickness());
  const Field<2> theta = ice_shelf.interpolate(Temperature());
  const VectorField<2> u0 = ice_shelf.interpolate(Velocity());


  /**
   * Solve for the model adjoint around some velocity field
   */

  const DualVectorField<2> tau = ice_shelf.driving_stress(h);
  const DualVectorField<2> r = ice_shelf.residual(h, theta, u0, tau);
  check(norm(r) / norm(tau) < dx*dx);

  const DualVectorField<2> d_tau = transpose(ice_shelf.interpolate(DeltaTau()));
  const VectorField<2> lambda = ice_shelf.adjoint_solve(h, theta, u0, d_tau);

  if (verbose)
    lambda.write("lambda.ucd", "lambda");

  return 0;
}
Beispiel #4
0
double exchange(
	const Field &Ms,
	const Field &A,
	const VectorField &M,
	VectorField &H)
{
	const RectangularMesh &mesh = M.getMesh();

	int nx, ny, nz; mesh.getNumNodes(nx, ny, nz);
	double dx, dy, dz; mesh.getDelta(dx, dy, dz);
	std::string pbc; int pbc_reps; mesh.getPeriodicBC(pbc, pbc_reps);

	const bool px = pbc.find("x") != std::string::npos;
	const bool py = pbc.find("y") != std::string::npos;
	const bool pz = pbc.find("z") != std::string::npos;

	return exchange(nx, ny, nz, dx, dy, dz, px, py, pz, Ms, A, M, H);
}
void processLowerStar(Cell const v,
                      Scalars const& scalars,
                      VectorField& outputField,
                      Facets const& cofacets,
                      Vertices const& vertices)
{
    // The lower star with the current partial field.
    StarField<Cell, Scalars> star(v, cofacets, vertices, scalars);

    // Determines whether to look for edges or singular cells next. Alternates
    // between 0 and 1.
    int k = 1;

    while (true)
    {
        int cell;
        int partner = -1;

        // Find an unused cell with k unused faces and assign the first such
        // face to partner if k > 0, or the cell itself otherwise.
        for (int i = 0; i < star.size(); ++i)
        {
            cell = star.indexForRank(i);
            if (not star.defined(cell))
                partner = star.firstFreeFaceIfKFree(cell, k);

            if (partner >= 0)
                break;
        }

        if (partner >= 0)
        {
            // New pairing found; record and resume scanning.
            star.set(cell, partner);
            outputField.setPartner(star.cell(cell), star.cell(partner));
            k = 1;
        }
        else if (k == 1) // Scan for singular cells next.
            k = 0;
        else             // Nothing found; terminate inner loop.
            break;
    }
}
Beispiel #6
0
std::vector< mesh::Entity > GeomDecomp::entity_coordinates(stk::mesh::BulkData& bulk_data, const mesh::Entity                 & entity,
                                                                  const VectorField            & nodal_coor,
                                                                  std::vector<std::vector<double> >  & coordinates)
{
  coordinates.clear();
  std::vector< mesh::Entity > mesh_nodes;

  const mesh::EntityRank enttype   = bulk_data.entity_rank(entity);
  if ( enttype == NODE_RANK )
  {
    throw std::runtime_error("GeomDecomp::entity_coordinates Error: Can not be called for nodal entities.");
  } else {

    // Loop over node relations in mesh entities
    const percept::MyPairIterRelation nr   (bulk_data, entity , NODE_RANK);

    for (unsigned inr=0; inr < nr.size(); ++inr)
    {
      const percept::MyPairIterRelation::MyRelation  &rel = nr[inr];
      //if (rel.entity_rank() ==  NODE_RANK) { // %fixme: need to check for USES relation
      if (bulk_data.entity_rank(rel.entity()) ==  NODE_RANK) { // %fixme: need to check for USES relation
        const mesh::Entity nent = rel.entity();
        //const unsigned ndim(nodal_coor.max_size(NODE_RANK)/sizeof(double)); // TODO - is there a better way to get this info?
        const unsigned ndim(nodal_coor.max_size(NODE_RANK)); // TODO - is there a better way to get this info?
        double * coor = mesh::field_data(nodal_coor, nent);
        if (!coor) {
          throw std::runtime_error("GeomDecomp::entity_coordinates Error: The coordinate field does not exist.");
        }
        std::vector<double> temp(ndim);
        for ( unsigned i = 0; i < ndim; ++i ) { temp[i] = coor[i]; }
        coordinates.push_back(temp);
        mesh_nodes.push_back(nent);
      }
    }
  }
  return mesh_nodes;
}
Beispiel #7
0
void Ohm<Nz,Nx>::operator() (const VectorField<real,Nz,Nx>& B,
                             const VectorField<real,Nz,Nx>& J,
                             const ScalarField<real,Nz,Nx>& rho,
                             const VectorField<real,Nz,Nx>& ruu,
                             VectorField<real,Nz,Nx>* E)
{
    for (uint j = 0; j < 3; ++j) computeElectronVelocity (J[j], rho, ruu[j], &U[j]);
    
    for (uint k = ScalarField<real,Nz,Nx>::k1;
              k < ScalarField<real,Nz,Nx>::k2; ++k)
#ifdef __INTEL_COMPILER
#pragma vector aligned
#pragma ivdep
#endif
    for (uint i = ScalarField<real,Nz,Nx>::i1;
              i < ScalarField<real,Nz,Nx>::i2; ++i)
    {
        E->x (k,i) = U.z (k,i)*B.y (k,i) - U.y (k,i)*B.z (k,i);
        E->y (k,i) = U.x (k,i)*B.z (k,i) - U.z (k,i)*B.x (k,i);
        E->z (k,i) = U.y (k,i)*B.x (k,i) - U.x (k,i)*B.y (k,i);
    }
}
Beispiel #8
0
int main(void)
{
	float x[] = { 0.f, 0.f, 0.f, 0.f, 1.f, 1.f, 1.f, 1.f };
	float y[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
	float z[] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f };
	float s[] = { 1.f, 1.f, 1.f, 1.f, 0.f, 0.f, 0.f, 0.f };

	VectorField<float> flow;
	std::vector<float> scalars, entry;

	std::vector<Field<float> > fields(4);
	fields[0].set(x, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	fields[1].set(y, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	fields[2].set(z, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	fields[3].set(s, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	flow.set(fields);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "1" << std::endl;

	std::vector<float*> buffer(4);
	buffer[0] = x; buffer[1] = y; buffer[2] = z; buffer[3] = s;
	flow.set(buffer, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "2" << std::endl;

	float *raw[4];
	raw[0] = x; raw[1] = y; raw[2] = z; raw[3] = s;
	flow.set(raw, 4, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "3" << std::endl;

	std::vector<Field<float> > vFields(3);
	vFields[0].set(x, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	vFields[1].set(y, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	vFields[2].set(z, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	std::vector<Field<float> > sFields(1);
	sFields[0].set(s, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	flow.setVelocities(vFields);
	flow.setScalars(sFields);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "4" << std::endl;

	std::vector<float*> vBuffers(3);
	vBuffers[0] = x; vBuffers[1] = y; vBuffers[2] = z;
	std::vector<float*> sBuffers(1);
	sBuffers[0] = s;
	flow.setVelocities(vBuffers, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	flow.setScalars(sBuffers, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "5" << std::endl;

	float *vRaws[3];
	vRaws[0] = x; vRaws[1] = y; vRaws[2] = z;
	float *sRaws[1];
	sRaws[0] = s;
	flow.setVelocities(vRaws, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	flow.setScalars(sRaws, 1, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	assert(flow.getVelocity(Vector<>(0.5, 0.5, 0.5)) == Vector<>(0.5, 0.f, 0.f));
	scalars = flow.getScalars(Vector<>(0.5, 0.5, 0.5));
	assert(scalars.size() == 1);
	entry = flow.get(Vector<>(0.5, 0.5, 0.5));
	assert(entry.size() == 4);
	assert(fabs(entry[0] - 0.5) < 0.0001);
	assert(fabs(entry[1] - 0.f) < 0.0001);
	assert(fabs(entry[2] - 0.f) < 0.0001);
	assert(fabs(entry[3] - scalars[0]) < 0.0001);
	assert(fabs(entry[3] - 0.5) < 0.0001);
	std::cout << "6" << std::endl;

	flow.addScalar(s, Vector<3, int>(2, 2, 2), Field<float>::Vertex);
	assert(flow.getScalars(Vector<>(0.5, 0.5, 0.5)).size() == 2);

	return 0;
}
Beispiel #9
0
int main(int argc, char **argv )
{
   walberla::Environment env( argc, argv );

   const uint_t cells [] = { 6,5,3 };
   const uint_t blockCount [] = { 4, 3,2 };
   const uint_t nrOfTimeSteps = 20;

   // Create BlockForest
   auto blocks = blockforest::createUniformBlockGrid(blockCount[0],blockCount[1],blockCount[2],  //blocks
                                        cells[0],cells[1],cells[2], //cells
                                        1,                          //dx
                                        false,                      //one block per process
                                        true,true,true);            //periodicity

   LatticeModel latticeModel( lbm::collision_model::SRT(1.5 ) );

   // In addition to the normal GhostLayerField's  we allocated additionally a field containing the whole global simulation domain for each block
   // we can then check if the GhostLayer communication is correct, by comparing the small field to the corresponding part of the big field

   BlockDataID pdfField     = lbm::addPdfFieldToStorage( blocks, "PdfField", latticeModel );

   BlockDataID scalarField1 = field::addToStorage<ScalarField>( blocks, "ScalarFieldOneGl", real_t(0), field::zyxf,  1 );
   BlockDataID scalarField2 = field::addToStorage<ScalarField>( blocks, "ScalarFieldTwoGl", real_t(0), field::zyxf,  2 );
   BlockDataID vectorField  = field::addToStorage<VectorField>( blocks, "VectorField", Vector3<real_t>(0,0,0) );
   BlockDataID flagField    = field::addFlagFieldToStorage<FField>( blocks, "FlagField" );


   // Init src field with some values
   for( auto blockIt = blocks->begin(); blockIt != blocks->end(); ++blockIt ) // block loop
   {
      // Init PDF field
      PdfField * src = blockIt->getData<PdfField>(pdfField);
      for( auto cellIt = src->begin(); cellIt != src->end(); ++cellIt ) // over all x,y,z,f
      {
         Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() );
         blocks->transformBlockLocalToGlobalCell(cell, *blockIt);
         *cellIt = real_c( ( cell[0] + cell[1] + cell[2] + cellIt.f() ) % cell_idx_t(42) );
      }

      // Init scalarField1
      ScalarField * sf = blockIt->getData<ScalarField> ( scalarField1 );
      for( auto cellIt = sf->beginWithGhostLayer(); cellIt != sf->end(); ++cellIt ) // over all x,y,z
      {
         Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() );
         blocks->transformBlockLocalToGlobalCell(cell, *blockIt);
         *cellIt = real_c( ( cell[0] + cell[1] + cell[2] ) % cell_idx_t(42) );
      }

      // Init scalarField2
      sf = blockIt->getData<ScalarField> ( scalarField2 );
      for( auto cellIt = sf->beginWithGhostLayer(); cellIt != sf->end(); ++cellIt ) // over all x,y,z
      {
         Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() );
         blocks->transformBlockLocalToGlobalCell(cell, *blockIt);
         *cellIt = real_c( ( cell[0] + cell[1] + cell[2] ) % cell_idx_t(42) );
      }

      // Init vector field
      VectorField * vf = blockIt->getData<VectorField> ( vectorField );
      for ( auto cellIt = vf->beginWithGhostLayer(); cellIt != vf->end(); ++cellIt )
      {
         Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() );
         blocks->transformBlockLocalToGlobalCell(cell, *blockIt);
         *cellIt = Vector3<real_t>( real_c(cell[0]), real_c(cell[1]), real_c(cell[2]) );
      }

      // Init Flag field
      FField * ff = blockIt->getData<FField> ( flagField );
      auto flag1 = ff->registerFlag( "AFlag 1" );
      auto flag2 = ff->registerFlag( "BFlag 2" );
      for ( auto cellIt = ff->beginWithGhostLayer(); cellIt != ff->end(); ++cellIt )
      {
         Cell cell ( cellIt.x(), cellIt.y(), cellIt.z() );
         blocks->transformBlockLocalToGlobalCell( cell, *blockIt );
         if ( ( cell[0] + cell[1] + cell[2] ) % 2 )
            addFlag( cellIt, flag1);
         else
            addFlag( cellIt, flag2);
      }

   }

   // Create TimeLoop
   SweepTimeloop timeloop (blocks, nrOfTimeSteps );

   GUI gui (timeloop, blocks, argc, argv);
   lbm::connectToGui<LatticeModel>( gui );
   gui.run();
   //timeloop.singleStep();
   return EXIT_SUCCESS;
}
Beispiel #10
0
float Lowpass::main_body_quality(
  Streamline *st,
  float radius,
  int nsamples,
  float dist,
  Window2d *win,
  int &which_side
)
{
  int i;
  float rad;
  float delta;
  float x,y;
  float sum = 0;
  int count = 0;
  VectorField *vf = st->vf;

  /* kluge to work around problems at the image borders */

  float xmin = 2.0 / xsize;
  float ymin = 2.0 / ysize;
  float xmax = 1 - 2.0 / xsize;
  float ymax = image->getaspect() - 2.0 / ysize;

  /* measure the quality at several random positions along the streamline */

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

    int index = (int) (st->samples * drand48());
    SamplePoint *sample = &st->pts[index];

    x = sample->x;
    y = sample->y;

    /* don't measure near the borders */
    if (x < xmin || x > xmax || y < ymin || y > ymax)
      continue;

    rad = radius * rad_image->get_value(x,y) / xsize;
    delta = 0.3 * rad / nsamples;

    /* find out how to move perpendicular to the vector field */
    float dx = - delta * vf->yval(x,y);
    float dy =   delta * vf->xval(x,y);

    /* sample along either side of the streamline */
    float x1 = x + dx;
    float y1 = y + dy;
    float x2 = x - dx;
    float y2 = y - dy;

    /* measure the quality at the two points */
    float value1 = image->get_value(x1,y1);
    float value2 = image->get_value(x2,y2);
   // printf("value1: %f, value2: %f\n",value1,value2);

    sum += value1 - value2;

    count++;

  }

  /* return quality */

  if (count == 0)
    return (0.0);
  else {

    if (sum > 0)
      which_side = LEFT;
    else
      which_side = RIGHT;

    return (fabs (sum / count));
  }
}
Beispiel #11
0
float Lowpass::lengthen_quality(
  Streamline *st,
  float radius,
  int nsamples,
  float dist,
  Window2d *win,
  int &which_end
)
{
  int i;
  float rad;
  float delta;
  float x,y;
  float sum1 = 0;
  float sum2 = 0;
  int count1 = 0;
  int count2 = 0;
  VectorField *vf = st->vf;
  //printf("got vector field\n");

  /* kluge to work around problems at the image borders */

  float xmin = 2.0 / xsize;
  float ymin = 2.0 / ysize;
  float xmax = 1 - 2.0 / xsize;
  float ymax = image->getaspect() - 2.0 / ysize;

  /* measure the quality as we move away from the streamline's tail */

  x = st->pts[0].x;
  y = st->pts[0].y;
  rad = radius * rad_image->get_value(x,y) / xsize;
  delta = dist * rad / nsamples;

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

    /* don't go too near the borders */
    if (x < xmin || x > xmax || y < ymin || y > ymax)
      break;

    /* measure the point's quality */
    float value =  image->get_value(x,y);
   // printf("value in intial %f\n",value);
    if (value < target)
      sum1 += Square (target - value);
    count1++;


    /* move further away from the endpoint */
    x -= delta * vf->xval(x,y);
    y -= delta * vf->yval(x,y);
  }

  /* now measure from the head */

  x = st->pts[st->samples - 1].x;
  y = st->pts[st->samples - 1].y;
  rad = radius * rad_image->get_value(x,y) / xsize;
  delta = dist * rad / nsamples;

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

    /* don't go too near the borders */
    if (x < xmin || x > xmax || y < ymin || y > ymax)
      break;

    /* measure the point's quality */
    float value =  image->get_value(x,y);
    if (value < target)
      sum2 += Square (target - value);
    count2++;

    /* move further away from the endpoint */
    x += delta * vf->xval(x,y);
    y += delta * vf->yval(x,y);
  }

  /* determine quality */

  float qual = 0;

  if (count1 + count2 != 0)
    qual = (sum1 + sum2) / (count1 + count2);

  /* say which end needs change more */

  if (count1)
    sum1 /= count1;
  if (count2)
    sum2 /= count2;

  if (sum1 > sum2)
    which_end = TAIL;
  else
    which_end = HEAD;
  //printf("lengthen quality over\n");
  return (qual);
}
Beispiel #12
0
float Lowpass::shorten_quality(
  Streamline *st,
  float radius,
  int nsamples,
  float dist,
  Window2d *win,
  int &which_end
)
{
  int i;
  float rad;
  float delta;
  float x,y;
  float sum1 = 0;
  float sum2 = 0;
  int count1 = 0;
  int count2 = 0;
  VectorField *vf = st->vf;

  /* kluge to work around problems at the image borders */

  float xmin = 2.0 / xsize;
  float ymin = 2.0 / ysize;
  float xmax = 1 - 2.0 / xsize;
  float ymax = image->getaspect() - 2.0 / ysize;

  /* measure the quality as we move into the body of the streamline */
  /* from the tail endpoint */

  x = st->pts[0].x;
  y = st->pts[0].y;
  rad = radius * rad_image->get_value(x,y) / xsize;
  delta = dist * rad / nsamples;

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

    /* don't measure near the borders */
    if (x < xmin || x > xmax || y < ymin || y > ymax)
      continue;

    /* measure the point's quality */
    float value =  image->get_value(x,y);
    if (value > target)
      sum1 += Square (target - value);
    count1++;

    /* debug drawing of samples */
    if (win) {
      win->set_color_index (255);
      win->line (x, y, x, y);
    }

    /* move further away from the endpoint */
    x += delta * vf->xval(x,y);
    y += delta * vf->yval(x,y);
  }

  /* now measure from the head */

  x = st->pts[st->samples - 1].x;
  y = st->pts[st->samples - 1].y;
  rad = radius * rad_image->get_value(x,y) / xsize;
  delta = dist * rad / nsamples;

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

    /* don't measure near the borders */
    if (x < xmin || x > xmax || y < ymin || y > ymax)
      continue;

    /* measure the point's quality */
    float value =  image->get_value(x,y);
    if (value > target)
      sum2 += Square (target - value);
    count2++;

    /* debug drawing of samples */
    if (win) {
      win->set_color_index (255);
      win->line (x, y, x, y);
    }

    /* move further away from the endpoint */
    x -= delta * vf->xval(x,y);
    y -= delta * vf->yval(x,y);
  }

  /* determine quality */

  float qual = 0;

  if (count1 + count2 != 0)
    qual = (sum1 + sum2) / (count1 + count2);

  /* say which end needs change more */

  if (count1)
    sum1 /= count1;
  if (count2)
    sum2 /= count2;

  if (sum1 > sum2)
    which_end = TAIL;
  else
    which_end = HEAD;

  return (qual);
}