bool ParametricCurveTests::testTransfiniteInterpolant()
{
  bool success = true;

  // to begin, just let's do a simple quad mesh
  double width=4, height=3;
  double x0 = 0, y0 = 0;
  double x1 = width, y1 = 0;
  double x2 = width, y2 = height;
  double x3 = 0, y3 = height;

  vector< ParametricCurvePtr > edges(4);
  edges[0] = ParametricCurve::line(x0, y0, x1, y1);
  edges[1] = ParametricCurve::line(x1, y1, x2, y2);
  edges[2] = ParametricCurve::line(x2, y2, x3, y3);
  edges[3] = ParametricCurve::line(x3, y3, x0, y0);

  ParametricSurfacePtr transfiniteInterpolant = ParametricSurface::transfiniteInterpolant(edges);

  double x0_actual, y0_actual, x2_actual, y2_actual;
  transfiniteInterpolant->value(0, 0, x0_actual, y0_actual);
  transfiniteInterpolant->value(1, 1, x2_actual, y2_actual);

  double tol=1e-14;
  if ((abs(x0_actual-x0) > tol) || (abs(y0_actual-y0) > tol))
  {
    success = false;
    cout << "transfinite interpolant doesn't interpolate (x0,y0).\n";
  }
  if ((abs(x2_actual-x2) > tol) || (abs(y2_actual-y2) > tol))
  {
    success = false;
    cout << "transfinite interpolant doesn't interpolate (x2,y2).\n";
  }

  // the transfinite interpolant should be just (4t1, 3t2)
  FunctionPtr t1 = Function::xn(1);
  FunctionPtr t2 = Function::yn(1);
  FunctionPtr xPart = 4 * t1;
  FunctionPtr yPart = 3 * t2;
  FunctionPtr expected_tfi = Function::vectorize(xPart, yPart);

  int cubatureDegree = 4;
  BasisCachePtr parametricCache = BasisCache::parametricQuadCache(cubatureDegree);

  // a couple quick sanity checks:
  if (! expected_tfi->equals(expected_tfi, parametricCache))
  {
    success = false;
    cout << "ERROR in Function::equals(): vector Function does not equal itself.\n";
  }
  if (! transfiniteInterpolant->equals(transfiniteInterpolant, parametricCache))
  {
    success = false;
    cout << "Weird error: transfiniteInterpolant does not equal itself.\n";
  }

  // check that the transfiniteInterpolant's value() method matches values()
  {
    int numCells = 1;
    int numPoints = parametricCache->getRefCellPoints().dimension(0);
    int spaceDim = 2;
    FieldContainer<double> values(numCells,numPoints,spaceDim);
    transfiniteInterpolant->values(values, parametricCache);
    int cellIndex = 0;
    for (int ptIndex=0; ptIndex<numPoints; ptIndex++)
    {
      double t1 = parametricCache->getPhysicalCubaturePoints()(cellIndex,ptIndex,0);
      double t2 = parametricCache->getPhysicalCubaturePoints()(cellIndex,ptIndex,1);
      double x, y;
      transfiniteInterpolant->value(t1, t2, x, y);
      double x_expected = values(cellIndex,ptIndex,0);
      double y_expected = values(cellIndex,ptIndex,1);
      if (abs(x-x_expected) > tol)
      {
        cout << "transfinite interpolant value() does not match values()\n";
        success = false;
      }
      if (abs(y-y_expected) > tol)
      {
        cout << "transfinite interpolant value() does not match values()\n";
        success = false;
      }
    }
  }

  if (! expected_tfi->equals(transfiniteInterpolant, parametricCache, tol))
  {
    cout << "transfinite interpolant doesn't match expected.\n";
    success = false;
    int numCells = 1;
    int numPoints = parametricCache->getRefCellPoints().dimension(0);
    int spaceDim = 2;
    FieldContainer<double> values(numCells,numPoints,spaceDim);
    FieldContainer<double> expected_values(numCells,numPoints,spaceDim);
    expected_tfi->values(expected_values, parametricCache);
    transfiniteInterpolant->values(values, parametricCache);
    reportFunctionValueDifferences(parametricCache->getPhysicalCubaturePoints(), expected_values,
                                   values, tol);
  }

  // derivatives
  FunctionPtr xPart_dt1 = Function::constant(4);
  FunctionPtr yPart_dt1 = Function::constant(0);
  FunctionPtr expected_tfi_dt1 = Function::vectorize(xPart_dt1, yPart_dt1);
  if (! expected_tfi_dt1->equals(transfiniteInterpolant->dt1(), parametricCache, tol))
  {
    cout << "d/dt1 of transfinite interpolant doesn't match expected.\n";
    success = false;
    int numCells = 1;
    int numPoints = parametricCache->getRefCellPoints().dimension(0);
    int spaceDim = 2;
    FieldContainer<double> values(numCells,numPoints,spaceDim);
    FieldContainer<double> expected_values(numCells,numPoints,spaceDim);
    expected_tfi_dt1->values(expected_values, parametricCache);
    transfiniteInterpolant->dt1()->values(values, parametricCache);
    reportFunctionValueDifferences(parametricCache->getPhysicalCubaturePoints(), expected_values,
                                   values, tol);
  }

  FunctionPtr xPart_dt2 = Function::constant(0);
  FunctionPtr yPart_dt2 = Function::constant(3);
  FunctionPtr expected_tfi_dt2 = Function::vectorize(xPart_dt2, yPart_dt2);
  if (! expected_tfi_dt2->equals(transfiniteInterpolant->dt2(), parametricCache, tol))
  {
    cout << "d/dt2 of transfinite interpolant doesn't match expected.\n";
    success = false;
    int numCells = 1;
    int numPoints = parametricCache->getRefCellPoints().dimension(0);
    int spaceDim = 2;
    FieldContainer<double> values(numCells,numPoints,spaceDim);
    FieldContainer<double> expected_values(numCells,numPoints,spaceDim);
    expected_tfi_dt2->values(expected_values, parametricCache);
    transfiniteInterpolant->dt2()->values(values, parametricCache);
    reportFunctionValueDifferences(parametricCache->getPhysicalCubaturePoints(), expected_values,
                                   values, tol);
  }

  BasisCachePtr physicalBasisCache = BasisCache::quadBasisCache(width, height, cubatureDegree);

  FunctionPtr one = Function::constant(1);
  FunctionPtr expected_tfi_dx = Function::vectorize(one, Function::zero());
  FunctionPtr expected_tfi_dy = Function::vectorize(Function::zero(), one);

  FunctionPtr expected_tfi_grad = Function::vectorize(expected_tfi_dx, expected_tfi_dy);

  if (! expected_tfi_grad->equals(transfiniteInterpolant->grad(), physicalBasisCache, tol))
  {
    cout << "grad of transfinite interpolant doesn't match expected.\n";
    success = false;
    int numCells = 1;
    int numPoints = physicalBasisCache->getRefCellPoints().dimension(0);
    int spaceDim = 2;
    FieldContainer<double> values(numCells,numPoints,spaceDim,spaceDim);
    FieldContainer<double> expected_values(numCells,numPoints,spaceDim,spaceDim);
    expected_tfi_grad->values(expected_values, physicalBasisCache);
    transfiniteInterpolant->grad()->values(values, physicalBasisCache);
    reportFunctionValueDifferences(physicalBasisCache->getPhysicalCubaturePoints(), expected_values,
                                   values, tol);
  }

  return success;
}
void ProcessRemovalsByLength::Execute() {
  LOG_TRACE();
  /**
   * Verify our cached partition and partition sizes are correct
   */
//  auto categories = model_->categories();
  unsigned year = model_->current_year();
  unsigned year_index = year - model_->start_year();
  unsigned time_step = model_->managers().time_step()->current_time_step();
  auto cached_partition_iter = cached_partition_->Begin();
  auto partition_iter = partition_->Begin(); // vector<vector<partition::Category> >
  map<unsigned, map<string, map<string, vector<Double>>>> &Removals_at_age = mortality_instantaneous_->catch_at();

  /**
   * Loop through the provided categories. Each provided category (combination) will have a list of observations
   * with it. We need to build a vector of proportions for each length using that combination and then
   * compare it to the observations.
   */
  for (unsigned category_offset = 0; category_offset < category_labels_.size(); ++category_offset, ++partition_iter, ++cached_partition_iter) {
    LOG_FINEST() << "category: " << category_labels_[category_offset];
    Double start_value = 0.0;
    Double end_value = 0.0;
    Double number_at_age = 0.0;

//    LOG_WARNING() << "This is bad code because it allocates memory in the middle of an execute";
    vector<Double> expected_values(number_bins_, 0.0);
    vector<Double> numbers_at_length;
    vector<vector<Double>> age_length_matrix;

    /**
     * Loop through the 2 combined categories building up the
     * expected proportions values.
     */
    auto category_iter = partition_iter->begin();
    auto cached_category_iter = cached_partition_iter->begin();
    for (; category_iter != partition_iter->end(); ++cached_category_iter, ++category_iter) {
//      AgeLength* age_length = categories->age_length((*category_iter)->name_);

//      LOG_WARNING() << "This is bad code because it allocates memory in the middle of an execute";
      age_length_matrix.resize((*category_iter)->data_.size());

      vector<Double> age_frequencies(length_bins_.size(), 0.0);
      const auto& age_length_proportions = model_->partition().age_length_proportions((*category_iter)->name_)[year_index][time_step];

      for (unsigned data_offset = 0; data_offset < (*category_iter)->data_.size(); ++data_offset) {
        unsigned age = ((*category_iter)->min_age_ + data_offset);

        // Calculate the age structure removed from the fishing process
        number_at_age = Removals_at_age[year][method_][(*category_iter)->name_][data_offset];
        LOG_FINEST() << "Numbers at age = " << age << " = " << number_at_age << " start value : " << start_value << " end value : " << end_value;
        // Implement an algorithm similar to DoAgeLengthConversion() to convert numbers at age to numbers at length
        // This is different to DoAgeLengthConversion as this number is now not related to the partition
//        Double mu= (*category_iter)->mean_length_by_time_step_age_[time_step][age];

//        LOG_FINEST() << "mean = " << mu << " cv = " << age_length->cv(year, time_step, age) << " distribution = " << age_length->distribution_label() << " and length plus group = " << length_plus_;
//        age_length->CummulativeNormal(mu, age_length->cv(year, time_step, age), age_frequencies, length_bins_, length_plus_);

//        LOG_WARNING() << "This is bad code because it allocates memory in the middle of an execute";
        age_length_matrix[data_offset].resize(number_bins_);

        // Loop through the length bins and multiple the partition of the current age to go from
        // length frequencies to age length numbers
        for (unsigned j = 0; j < number_bins_; ++j) {
          age_length_matrix[data_offset][j] = number_at_age * age_length_proportions[data_offset][j];
          LOG_FINEST() << "The proportion of fish in length bin : " << length_bins_[j] << " = " << age_frequencies[j];
        }
      }

      if (age_length_matrix.size() == 0)
        LOG_CODE_ERROR()<< "if (age_length_matrix_.size() == 0)";

      numbers_at_length.assign(age_length_matrix[0].size(), 0.0);
      for (unsigned i = 0; i < age_length_matrix.size(); ++i) {
        for (unsigned j = 0; j < age_length_matrix[i].size(); ++j) {
          numbers_at_length[j] += age_length_matrix[i][j];
        }
      }

      for (unsigned length_offset = 0; length_offset < number_bins_; ++length_offset) {
        LOG_FINEST() << " numbers for length bin : " << length_bins_[length_offset] << " = " << numbers_at_length[length_offset];
        expected_values[length_offset] += numbers_at_length[length_offset];

        LOG_FINE() << "----------";
        LOG_FINE() << "Category: " << (*category_iter)->name_ << " at length " << length_bins_[length_offset];
        LOG_FINE() << "start_value: " << start_value << "; end_value: " << end_value << "; final_value: " << numbers_at_length[length_offset];
        LOG_FINE() << "expected_value becomes: " << expected_values[length_offset];
      }
    }

    if (expected_values.size() != proportions_[model_->current_year()][category_labels_[category_offset]].size())
      LOG_CODE_ERROR()<< "expected_values.size(" << expected_values.size() << ") != proportions_[category_offset].size("
      << proportions_[model_->current_year()][category_labels_[category_offset]].size() << ")";

      /**
       * save our comparisons so we can use them to generate the score from the likelihoods later
       */
    for (unsigned i = 0; i < expected_values.size(); ++i) {
      SaveComparison(category_labels_[category_offset], 0, length_bins_[i], expected_values[i], proportions_[model_->current_year()][category_labels_[category_offset]][i],
          process_errors_by_year_[model_->current_year()], error_values_[model_->current_year()][category_labels_[category_offset]][i], 0.0, delta_, 0.0);
    }
  }
}
void ProportionsMigrating::Execute() {
  LOG_TRACE();

  /**
   * Verify our cached partition and partition sizes are correct
   */
  auto cached_partition_iter  = cached_partition_->Begin();
  auto partition_iter         = partition_->Begin(); // vector<vector<partition::Category> >

  /**
   * Loop through the provided categories. Each provided category (combination) will have a list of observations
   * with it. We need to build a vector of proportions for each age using that combination and then
   * compare it to the observations.
   */
  LOG_FINEST() << "Number of categories " << category_labels_.size();
  for (unsigned category_offset = 0; category_offset < category_labels_.size(); ++category_offset, ++partition_iter, ++cached_partition_iter) {
    Double      start_value        = 0.0;
    Double      end_value          = 0.0;


    vector<Double> expected_values(age_spread_, 0.0);
    vector<Double> numbers_age_before((model_->age_spread() + 1), 0.0);
    vector<Double> numbers_age_after((model_->age_spread() + 1), 0.0);

    /**
     * Loop through the 2 combined categories building up the
     * expected proportions values.
     */
    auto category_iter = partition_iter->begin();
    auto cached_category_iter = cached_partition_iter->begin();
    for (; category_iter != partition_iter->end(); ++cached_category_iter, ++category_iter) {
      for (unsigned data_offset = 0; data_offset < (*category_iter)->data_.size(); ++data_offset) {
        // We now need to loop through all ages to apply ageing misclassification matrix to account
        // for ages older than max_age_ that could be classified as an individual within the observation range
        unsigned age = ( (*category_iter)->min_age_ + data_offset);

        start_value   = (*cached_category_iter).data_[data_offset];
        end_value     = (*category_iter)->data_[data_offset];

        numbers_age_before[data_offset] += start_value;
        numbers_age_after[data_offset] += end_value;

        LOG_FINE() << "----------";
        LOG_FINE() << "Category: " << (*category_iter)->name_ << " at age " << age;
        LOG_FINE() << "start_value: " << start_value << "; end_value: " << end_value;
      }
    }

    /*
    *  Apply Ageing error on numbers at age before and after
    */
    if (ageing_error_label_ != "") {
      vector<vector<Double>>& mis_matrix = ageing_error_->mis_matrix();
      vector<Double> temp_before(numbers_age_before.size(), 0.0);
      vector<Double> temp_after(numbers_age_after.size(), 0.0);

      for (unsigned i = 0; i < mis_matrix.size(); ++i) {
        for (unsigned j = 0; j < mis_matrix[i].size(); ++j) {
          temp_before[j] += numbers_age_before[i] * mis_matrix[i][j];
          temp_after[j] += numbers_age_after[i] * mis_matrix[i][j];
        }
      }
      numbers_age_before = temp_before;
      numbers_age_after = temp_after;
    }


    /*
     *  Now collapse the number_age into out expected values
     */
    Double plus_before = 0, plus_after = 0;
    for (unsigned k = 0; k < numbers_age_before.size(); ++k) {
      // this is the difference between the
      unsigned age_offset = min_age_ - model_->min_age();
      if (numbers_age_before[k] > 0) {
        if (k >= age_offset && (k - age_offset + min_age_) <= max_age_) {
          expected_values[k - age_offset] = (numbers_age_before[k] - numbers_age_after[k]) / numbers_age_before[k];
          LOG_FINEST() << "Numbers before migration = " << numbers_age_before[k] << " numbers after migration = " << numbers_age_after[k]
                   << " proportion migrated = " <<   expected_values[k - age_offset];
        }
        if (((k - age_offset + min_age_) > max_age_) && age_plus_) {
          plus_before += numbers_age_before[k];
          plus_after += numbers_age_after[k];
        }
      } else {
          if (k >= age_offset && (k - age_offset + min_age_) <= max_age_)
            expected_values[k] = 0;
          if (((k - age_offset + min_age_) > max_age_) && age_plus_) {
            plus_before += 0;
            plus_after += 0;
          }
      }
    }
    LOG_FINEST() << "Plus group before migration = " << plus_before << " Plus group after migration = " << plus_after;
    if (age_plus_)
      expected_values[age_spread_ - 1] = (plus_before - plus_after) / plus_before;


    if (expected_values.size() != proportions_[model_->current_year()][category_labels_[category_offset]].size())
      LOG_CODE_ERROR() << "expected_values.size(" << expected_values.size() << ") != proportions_[category_offset].size("
        << proportions_[model_->current_year()][category_labels_[category_offset]].size() << ")";

    /**
     * save our comparisons so we can use them to generate the score from the likelihoods later
     */

    for (unsigned i = 0; i < expected_values.size(); ++i) {
      LOG_FINEST() << " Numbers at age " << min_age_ + i << " = " << expected_values[i];
      SaveComparison(category_labels_[category_offset], min_age_ + i ,0.0 ,expected_values[i], proportions_[model_->current_year()][category_labels_[category_offset]][i],
          process_errors_by_year_[model_->current_year()], error_values_[model_->current_year()][category_labels_[category_offset]][i], delta_, 0.0);
    }
  }
}