You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2465 lines
100 KiB
C++
2465 lines
100 KiB
C++
|
1 month ago
|
/*------------------------------------------------------------------------------
|
||
|
|
* Copyright (c) 2023 by Bai Bing (seread@163.com)
|
||
|
|
* See COPYING file for copying and redistribution conditions.
|
||
|
|
*
|
||
|
|
* Alians IT Studio.
|
||
|
|
*----------------------------------------------------------------------------*/
|
||
|
|
|
||
|
|
#include <algorithm>
|
||
|
|
#include <array>
|
||
|
|
#include <cfloat>
|
||
|
|
#include <chrono>
|
||
|
|
#include <climits>
|
||
|
|
#include <cmath>
|
||
|
|
#include <cstdlib>
|
||
|
|
#include <execution>
|
||
|
|
#include <fstream>
|
||
|
|
#include <functional>
|
||
|
|
#include <future>
|
||
|
|
#include <iomanip>
|
||
|
|
#include <list>
|
||
|
|
#include <map>
|
||
|
|
#include <memory>
|
||
|
|
#include <numeric>
|
||
|
|
#include <stdexcept>
|
||
|
|
#include <thread>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "core/FunCheck.h"
|
||
|
|
#include "core/Time.h"
|
||
|
|
#include "utils/Misc.h"
|
||
|
|
#include "ASTriangle.h"
|
||
|
|
#include "ASPolygon.h"
|
||
|
|
#include "ASGridInterpolator.h"
|
||
|
|
#include "ASGridInterpolatorBlock.h"
|
||
|
|
#include "interpolator/ASInterpolatorSupport.h"
|
||
|
|
#include "interpolator/ASInterpolateMethod.h"
|
||
|
|
#include "linalg/lstsq.h"
|
||
|
|
|
||
|
|
#define _LIKELY(x) (x)
|
||
|
|
|
||
|
|
namespace ais
|
||
|
|
{
|
||
|
|
GridInterpolator::GridInterpolator() : maxIteration_(2000), residual_(0.0001), fillValue_(0), zMean_(std::nan("1")),
|
||
|
|
dxSize_(0), dySize_(0), alpha_(std::nan("1")), beta_(std::nan("1")), flagSucceed_(false)
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
GridInterpolator::~GridInterpolator()
|
||
|
|
{
|
||
|
|
}
|
||
|
|
|
||
|
|
GridInterpolator::GridInterpolator(const std::vector<ais::PointXYZ> &randomPoints, // random sample points
|
||
|
|
const std::vector<ais::Point> &areaPoints, // result grid area corners points
|
||
|
|
std::shared_ptr<ais::FMatrix> targetMatrix, // output result values
|
||
|
|
const std::vector<ais::BreakLine> &breaklines, // break lines
|
||
|
|
const std::vector<ais::Fault> &faults // faults
|
||
|
|
) : randomPoints_(randomPoints), areaPoints_(areaPoints), targetMatrixPtr_(targetMatrix), breaklines_(breaklines), faults_(faults)
|
||
|
|
{
|
||
|
|
generate_grid_params(targetMatrixPtr_);
|
||
|
|
|
||
|
|
// data statistics included point positions' distance, so it should be called after coordinates_points
|
||
|
|
if(randomPoints.size() < 1000)
|
||
|
|
generate_data_statistics();
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::set_area_points(const std::vector<ais::Point> &points)
|
||
|
|
{
|
||
|
|
if (points.size() >= 2)
|
||
|
|
{
|
||
|
|
areaPoints_.clear();
|
||
|
|
areaPoints_ = points;
|
||
|
|
|
||
|
|
// update internal vars
|
||
|
|
auto xs = getAxisValues(areaPoints_, Axis3DType::X);
|
||
|
|
auto ys = getAxisValues(areaPoints_, Axis3DType::Y);
|
||
|
|
xMinMax_ = getMinMax(xs);
|
||
|
|
yMinMax_ = getMinMax(ys);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::start(InterpolationMethod method)
|
||
|
|
{
|
||
|
|
// before start interpolation, checkout required params
|
||
|
|
if (targetMatrixPtr_->size() == 0 || areaPoints_.empty())
|
||
|
|
THROW_INVALID_ARGUMENT("Grid interpolator require completed target matrix and sample points");
|
||
|
|
|
||
|
|
// fault may affect the constraint value, do it first
|
||
|
|
build_fault_impact_matrix(targetMatrixPtr_, pointInFaultMatrixPtr_, faultAffectMatrixPtr_);
|
||
|
|
|
||
|
|
// build the constraint matrix
|
||
|
|
build_constraint_matrix(targetMatrixPtr_, constrainMatrixPtr_);
|
||
|
|
|
||
|
|
// update edge nodes by nearest neighbors or fill value
|
||
|
|
update_edge_node(targetMatrixPtr_);
|
||
|
|
|
||
|
|
// check the grid size, if the grid size is too smell to get a smooth result,
|
||
|
|
// try to estimate a grid with bigger grid size
|
||
|
|
detect_estimate_factor();
|
||
|
|
scale_estimate();
|
||
|
|
|
||
|
|
// estimate the target matrix for better output
|
||
|
|
if (estimateMatrixPtr_.get())
|
||
|
|
estimate_gradients_surface(targetMatrixPtr_);
|
||
|
|
|
||
|
|
// update nan nodes with fill value
|
||
|
|
update_nan_node(targetMatrixPtr_);
|
||
|
|
|
||
|
|
// update whole matrix
|
||
|
|
start_interpolation(targetMatrixPtr_, constrainMatrixPtr_, pointInFaultMatrixPtr_, faultAffectMatrixPtr_, method);
|
||
|
|
|
||
|
|
flagEnd_ = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::report()
|
||
|
|
{
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << "Iteration: " << iteration_ << " times, interpolations " << (flagSucceed_ ? "Succeed" : "Failed") << std::endl;
|
||
|
|
if (!faults_.empty())
|
||
|
|
{
|
||
|
|
ss << "No data node: " << faultNodesCount_ << std::endl;
|
||
|
|
}
|
||
|
|
ss << "Iteration execution time: " << iteration_time() << std::endl;
|
||
|
|
ss << "Result information: " << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
ss << header_info();
|
||
|
|
ss << std::endl;
|
||
|
|
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::points_info()
|
||
|
|
{
|
||
|
|
std::stringstream ss;
|
||
|
|
|
||
|
|
auto pCount = randomPoints_.size();
|
||
|
|
ss << "Total " << pCount << " simple points : " << std::endl;
|
||
|
|
ss << "x, y, z" << std::endl;
|
||
|
|
|
||
|
|
if (pCount <= 10)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < pCount; i++)
|
||
|
|
{
|
||
|
|
auto &p = randomPoints_[i];
|
||
|
|
ss << p.x << ", " << p.y << ", " << p.z << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
for (int i = 0; i <= 5; i++)
|
||
|
|
{
|
||
|
|
auto &p = randomPoints_[i];
|
||
|
|
ss << p.x << ", " << p.y << ", " << p.z << std::endl;
|
||
|
|
}
|
||
|
|
ss << "...";
|
||
|
|
for (auto pi = randomPoints_.cend() - 6; pi != randomPoints_.cend(); pi++)
|
||
|
|
{
|
||
|
|
auto &p = *pi;
|
||
|
|
ss << p.x << ", " << p.y << ", " << p.z << std::endl;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::header_info(std::shared_ptr<ais::FMatrix> dataMatrixPtr)
|
||
|
|
{
|
||
|
|
if (!dataMatrixPtr.get())
|
||
|
|
dataMatrixPtr = targetMatrixPtr_;
|
||
|
|
|
||
|
|
auto shape = dataMatrixPtr->shape();
|
||
|
|
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << shape.cols << " " << shape.rows << std::endl;
|
||
|
|
ss << std::fixed << std::setprecision(4);
|
||
|
|
ss << xMinMax_.first << " " << xMinMax_.second << std::endl;
|
||
|
|
ss << yMinMax_.first << " " << yMinMax_.second << std::endl;
|
||
|
|
ss << zMinMax_.first << " " << zMinMax_.second << std::endl;
|
||
|
|
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::data_info(std::shared_ptr<ais::FMatrix> dataMatrixPtr)
|
||
|
|
{
|
||
|
|
if (!dataMatrixPtr.get())
|
||
|
|
dataMatrixPtr = targetMatrixPtr_;
|
||
|
|
|
||
|
|
auto shape = dataMatrixPtr->shape();
|
||
|
|
|
||
|
|
std::string out_string;
|
||
|
|
out_string.reserve(256 * 1024 * 1024);
|
||
|
|
for (size_t r = 0; r < shape.rows; r++)
|
||
|
|
{
|
||
|
|
std::string line;
|
||
|
|
line.reserve(16 * 1024 * 1024);
|
||
|
|
for (size_t c = 0; c < shape.cols; c++)
|
||
|
|
{
|
||
|
|
line += std::to_string(dataMatrixPtr->at(r, c)) + " ";
|
||
|
|
}
|
||
|
|
|
||
|
|
out_string += line + "\n\n";
|
||
|
|
}
|
||
|
|
|
||
|
|
return out_string;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::iteration_time()
|
||
|
|
{
|
||
|
|
std::stringstream ss;
|
||
|
|
|
||
|
|
auto durSecs = std::chrono::duration_cast<std::chrono::milliseconds>(endTime_ - startTime_).count() / 1000.0;
|
||
|
|
auto hours = int(durSecs / 3600);
|
||
|
|
auto minutes = int((durSecs - hours * 3600) / 60);
|
||
|
|
auto seconds = durSecs - hours * 3600 - minutes * 60;
|
||
|
|
ss << hours << ":" << minutes << ":" << std::setprecision(3) << seconds;
|
||
|
|
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::get_progress_msg()
|
||
|
|
{
|
||
|
|
std::stringstream ss;
|
||
|
|
|
||
|
|
if (!interpolationMsgs_.empty())
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
|
||
|
|
for (auto &s : interpolationMsgs_)
|
||
|
|
ss << s << std::endl;
|
||
|
|
|
||
|
|
// all strings have been transformed to ss, clean internal caches
|
||
|
|
interpolationMsgs_.clear();
|
||
|
|
}
|
||
|
|
return ss.str();
|
||
|
|
};
|
||
|
|
|
||
|
|
void GridInterpolator::dump_result(const char *filename, std::shared_ptr<ais::FMatrix> dataMatrixPtr)
|
||
|
|
{
|
||
|
|
if (!dataMatrixPtr.get())
|
||
|
|
dataMatrixPtr = targetMatrixPtr_;
|
||
|
|
|
||
|
|
std::lock_guard<std::mutex> lk(dataMutex_);
|
||
|
|
|
||
|
|
std::ofstream outfile;
|
||
|
|
outfile.open(filename, std::ios::out);
|
||
|
|
|
||
|
|
// header
|
||
|
|
outfile << "DSAA" << std::endl;
|
||
|
|
outfile << header_info(dataMatrixPtr);
|
||
|
|
// data
|
||
|
|
outfile << data_info(dataMatrixPtr);
|
||
|
|
|
||
|
|
outfile.close();
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::dump_result_async(const std::string &filename, std::shared_ptr<ais::FMatrix> dataMatrixPtr, int8_t detailLevel)
|
||
|
|
{
|
||
|
|
/*
|
||
|
|
if (detailLevel <= this->detailLevel_ )
|
||
|
|
auto ret = std::async(std::launch::async,
|
||
|
|
[this, &filename, &dataMatrixPtr]()
|
||
|
|
{
|
||
|
|
dump_result(filename.c_str(), dataMatrixPtr);
|
||
|
|
return;
|
||
|
|
});
|
||
|
|
*/
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::generate_grid_params(std::shared_ptr<ais::FMatrix> targetMatrixPtr)
|
||
|
|
{
|
||
|
|
if (targetMatrixPtr->size() != 0)
|
||
|
|
{
|
||
|
|
// config default parameters by input samplePoints, areaPoints, and result matrix
|
||
|
|
auto shape = targetMatrixPtr->shape();
|
||
|
|
auto totalGridPoints = targetMatrixPtr->size();
|
||
|
|
// max iteration suggested 1~2 times the number of grid nodes by suffer
|
||
|
|
maxIteration_ = uint64_t(totalGridPoints * 2);
|
||
|
|
|
||
|
|
if (!areaPoints_.empty())
|
||
|
|
{
|
||
|
|
auto xs = getAxisValues(areaPoints_, Axis3DType::X);
|
||
|
|
auto ys = getAxisValues(areaPoints_, Axis3DType::Y);
|
||
|
|
xMinMax_ = getMinMax(xs);
|
||
|
|
yMinMax_ = getMinMax(ys);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
xMinMax_ = getMinMax(getAxisValues(randomPoints_, Axis3DType::X));
|
||
|
|
yMinMax_ = getMinMax(getAxisValues(randomPoints_, Axis3DType::Y));
|
||
|
|
}
|
||
|
|
|
||
|
|
auto zs = getAxisValues(randomPoints_, Axis3DType::Z);
|
||
|
|
zMinMax_ = getMinMax(zs);
|
||
|
|
zMean_ = std::accumulate(zs.begin(), zs.end(), 0.0) / zs.size();
|
||
|
|
|
||
|
|
// residual, default residual_ * (zMax - zMin)
|
||
|
|
epsMax_ = residual_ * std::abs(zMinMax_.second - zMinMax_.first);
|
||
|
|
|
||
|
|
// get spacing of grid matrix
|
||
|
|
dxSize_ = (xMinMax_.second - xMinMax_.first) / (shape.cols - 1);
|
||
|
|
dySize_ = (yMinMax_.second - yMinMax_.first) / (shape.rows - 1);
|
||
|
|
|
||
|
|
alpha_ = dxSize_ / dySize_;
|
||
|
|
beta_ = dySize_ / dxSize_;
|
||
|
|
|
||
|
|
x_ = generateAxisPoints(xMinMax_.first, xMinMax_.second, shape.cols);
|
||
|
|
y_ = generateAxisPoints(yMinMax_.first, yMinMax_.second, shape.rows);
|
||
|
|
|
||
|
|
// update random point position by current grid params, such as dxSize, dySize
|
||
|
|
randomPointPositions_ = coordinates_points(randomPoints_);
|
||
|
|
}
|
||
|
|
|
||
|
|
// grid require params incomplete, do nothing.
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::generate_data_statistics()
|
||
|
|
{
|
||
|
|
auto shape = targetMatrixPtr_->shape();
|
||
|
|
|
||
|
|
// distance for random point matrix
|
||
|
|
auto dx = xMinMax_.second - xMinMax_.first;
|
||
|
|
auto dy = yMinMax_.second - yMinMax_.first;
|
||
|
|
double distanceMax = 0.0, distanceMin = std::sqrt(dx * dx + dy * dy) + 1;
|
||
|
|
for (auto pia = randomPoints_.begin(); pia != randomPoints_.end() - 1; pia++)
|
||
|
|
for (auto pib = pia + 1; pib != randomPoints_.end(); pib++)
|
||
|
|
{
|
||
|
|
auto distance = pia->distance2D(*pib);
|
||
|
|
if (distance > distanceMax)
|
||
|
|
distanceMax = distance;
|
||
|
|
if (distance < distanceMin)
|
||
|
|
distanceMin = distance;
|
||
|
|
}
|
||
|
|
|
||
|
|
dataStatistics_["distance_min"] = distanceMin;
|
||
|
|
dataStatistics_["distance_max"] = distanceMax;
|
||
|
|
|
||
|
|
// distance for position matrix
|
||
|
|
distanceMax = 0.0, distanceMin = std::sqrt(shape.cols * shape.cols + shape.rows * shape.rows) + 1;
|
||
|
|
for (auto pia = randomPointPositions_.begin(); pia != randomPointPositions_.end() - 1; pia++)
|
||
|
|
for (auto pib = pia + 1; pib != randomPointPositions_.end(); pib++)
|
||
|
|
{
|
||
|
|
auto distance = pia->distance2D(*pib);
|
||
|
|
if (distance > distanceMax)
|
||
|
|
distanceMax = distance;
|
||
|
|
if (distance < distanceMin)
|
||
|
|
distanceMin = distance;
|
||
|
|
}
|
||
|
|
|
||
|
|
dataStatistics_["position_distance_min"] = distanceMin;
|
||
|
|
dataStatistics_["position_distance_max"] = distanceMax;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::shared_ptr<ais::Matrix<double>> GridInterpolator::matrix()
|
||
|
|
{
|
||
|
|
return targetMatrixPtr_;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::map<std::string, std::any> GridInterpolator::params()
|
||
|
|
{
|
||
|
|
auto shape = targetMatrixPtr_->shape();
|
||
|
|
|
||
|
|
std::map<std::string, std::any> ret;
|
||
|
|
|
||
|
|
ret["x_min"] = xMinMax_.first;
|
||
|
|
ret["x_max"] = xMinMax_.second;
|
||
|
|
ret["y_min"] = yMinMax_.first;
|
||
|
|
ret["y_max"] = yMinMax_.second;
|
||
|
|
ret["z_min"] = zMinMax_.first;
|
||
|
|
ret["z_max"] = zMinMax_.second;
|
||
|
|
|
||
|
|
ret["x_nodes"] = shape.cols;
|
||
|
|
ret["y_nodes"] = shape.rows;
|
||
|
|
ret["x_grid_size"] = dxSize_;
|
||
|
|
ret["y_grid_size"] = dySize_;
|
||
|
|
|
||
|
|
ret["max_iterations"] = maxIteration_;
|
||
|
|
ret["residual"] = residual_;
|
||
|
|
ret["eps_max"] = epsMax_;
|
||
|
|
ret["fill_value"] = fillValue_;
|
||
|
|
ret["use_multi_threads"] = flagMultiThread_;
|
||
|
|
ret["detail_level"] = detailLevel_;
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::params_info()
|
||
|
|
{
|
||
|
|
auto shape = targetMatrixPtr_->shape();
|
||
|
|
|
||
|
|
std::stringstream ss;
|
||
|
|
ss << std::fixed << std::setprecision(4);
|
||
|
|
ss << "Simple points info:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
ss << "points count: " << randomPoints_.size() << std::endl;
|
||
|
|
ss << "x_min: " << xMinMax_.first << ", x_max: " << xMinMax_.second << std::endl;
|
||
|
|
ss << "y_min: " << yMinMax_.first << ", y_max: " << yMinMax_.second << std::endl;
|
||
|
|
ss << "z_min: " << zMinMax_.first << ", z_max: " << zMinMax_.second << std::endl;
|
||
|
|
ss << std::endl;
|
||
|
|
|
||
|
|
ss << "Target grid info:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
ss << "Target area:" << std::endl;
|
||
|
|
for (auto &point : areaPoints_)
|
||
|
|
{
|
||
|
|
ss << "\t(" << point.x << ", " << point.y << ")" << std::endl;
|
||
|
|
}
|
||
|
|
ss << std::endl;
|
||
|
|
ss << "x_nodes: " << shape.cols << ", y_nodes: " << shape.rows << std::endl;
|
||
|
|
ss << "x_grid_size: " << dxSize_ << ", y_grid_size: " << dySize_ << std::endl;
|
||
|
|
ss << "output detail level: " << int(detailLevel_) << std::endl;
|
||
|
|
ss << std::endl;
|
||
|
|
|
||
|
|
if (!breaklines_.empty())
|
||
|
|
{
|
||
|
|
ss << "Breaklines info:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
for (auto &line : breaklines_)
|
||
|
|
{
|
||
|
|
ss << line << std::endl;
|
||
|
|
}
|
||
|
|
ss << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!faults_.empty())
|
||
|
|
{
|
||
|
|
ss << "Faults info:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
for (auto &fault : faults_)
|
||
|
|
{
|
||
|
|
ss << fault << std::endl;
|
||
|
|
}
|
||
|
|
ss << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
ss << "Interpolation info:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
ss << "max_iteration: " << maxIteration_ << std::endl;
|
||
|
|
ss << "residual: " << residual_ << std::endl;
|
||
|
|
ss << "eps_max: " << epsMax_ << std::endl;
|
||
|
|
ss << "fill_value: " << fillValue_ << std::endl;
|
||
|
|
ss << "use_multi_threads: " << (flagMultiThread_ ? "True" : "False") << std::endl;
|
||
|
|
ss << "corner_weight: " << cornerWeight_ << std::endl;
|
||
|
|
ss << std::endl;
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
std::string GridInterpolator::dump_data_statistics()
|
||
|
|
{
|
||
|
|
// output the data statistics
|
||
|
|
std::stringstream ss;
|
||
|
|
|
||
|
|
ss << "Origin point data statistics:" << std::endl;
|
||
|
|
ss << "---------------------------------------" << std::endl;
|
||
|
|
for (auto &kv : dataStatistics_)
|
||
|
|
ss << kv.first << ": " << kv.second << std::endl;
|
||
|
|
|
||
|
|
ss << std::endl;
|
||
|
|
|
||
|
|
return ss.str();
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::update_grid_params(const std::map<std::string, std::any> ¶ms)
|
||
|
|
{
|
||
|
|
for (auto &kv : params)
|
||
|
|
{
|
||
|
|
auto key = kv.first;
|
||
|
|
auto value = kv.second;
|
||
|
|
if (key == "max_iteration")
|
||
|
|
maxIteration_ = std::any_cast<size_t>(value);
|
||
|
|
else if (key == "residual")
|
||
|
|
{
|
||
|
|
residual_ = std::any_cast<double>(value);
|
||
|
|
epsMax_ = residual_ * (zMinMax_.second - zMinMax_.first);
|
||
|
|
}
|
||
|
|
else if (key == "fill_value")
|
||
|
|
fillValue_ = std::any_cast<double>(value);
|
||
|
|
else if (key == "use_multi_threads")
|
||
|
|
flagMultiThread_ = std::any_cast<bool>(value);
|
||
|
|
else if (key == "fault_edge_level")
|
||
|
|
faultEdgeLevel_ = std::any_cast<int8_t>(value);
|
||
|
|
else if (key == "estimate_factor")
|
||
|
|
estimateFactor_ = std::any_cast<int32_t>(value);
|
||
|
|
else if (key == "corner_weight")
|
||
|
|
cornerWeight_ = std::any_cast<int16_t>(value);
|
||
|
|
else if (key == "detail_level")
|
||
|
|
detailLevel_ = std::any_cast<int8_t>(value);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// setup constraints matrix
|
||
|
|
void GridInterpolator::setup_constraint_point(std::shared_ptr<ais::PMatrix> &cmp, size_t xi, size_t yi, double xGap, double yGap, const ais::PointXYZ &point)
|
||
|
|
{
|
||
|
|
auto shape = cmp->shape();
|
||
|
|
if ((0 <= xi && xi < shape.cols) && (0 <= yi && yi < shape.rows))
|
||
|
|
{
|
||
|
|
auto &p = cmp->at(yi, xi);
|
||
|
|
|
||
|
|
// test the constraint point in fault or not by its real position
|
||
|
|
auto cpx = xMinMax_.first + xi * dxSize_;
|
||
|
|
auto cpy = yMinMax_.first + yi * dySize_;
|
||
|
|
ais::Point realPosition{cpx, cpy};
|
||
|
|
|
||
|
|
bool inFault = false;
|
||
|
|
for (auto &fault : faults_)
|
||
|
|
{
|
||
|
|
// if (realPosition.in_box(fault.box) && (realPosition.in_polylines(fault.points) || realPosition.in_polygon(fault.polygon, 4, dxSize_, dySize_)))
|
||
|
|
if (realPosition.in_box(fault.box) && (realPosition.in_polylines(fault.points) || realPosition.in_polygon(fault.polygon)))
|
||
|
|
{
|
||
|
|
inFault = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
// test line rp--cp cross fault line or not
|
||
|
|
auto m = fault.points.size();
|
||
|
|
ais::Point p{point.x, point.y};
|
||
|
|
for (auto mi = 0; mi < m - 1; mi++)
|
||
|
|
{
|
||
|
|
if (line_cross(p, realPosition, fault.points[mi], fault.points[mi + 1]))
|
||
|
|
{
|
||
|
|
inFault = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (inFault)
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((!inFault) && (!p.has_value() || std::abs(xGap * xGap + yGap * yGap) < std::abs(p.x * p.x + p.y * p.y)))
|
||
|
|
{
|
||
|
|
// setup constraints point while there is no constraint or current point is more close, and point not in Fault
|
||
|
|
cmp->put(yi, xi, ais::PointXYZ{xGap, yGap, point.z});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
std::vector<PointXYZ> GridInterpolator::generate_constraint_points(const ais::BreakLine &breakline)
|
||
|
|
{
|
||
|
|
std::vector<PointXYZ> result;
|
||
|
|
|
||
|
|
// build up the breaklines
|
||
|
|
std::vector<std::pair<ais::PointXYZ, ais::PointXYZ>> lines;
|
||
|
|
for (auto iter = breakline.points.begin(); iter != breakline.points.end(); iter++)
|
||
|
|
{
|
||
|
|
if (iter + 1 != breakline.points.end())
|
||
|
|
lines.emplace_back(std::make_pair(*iter, *(iter + 1)));
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto &line : lines)
|
||
|
|
{
|
||
|
|
auto pStart = line.first;
|
||
|
|
auto pEnd = line.second;
|
||
|
|
|
||
|
|
// added points at start and end
|
||
|
|
result.push_back(pStart);
|
||
|
|
result.push_back(pEnd);
|
||
|
|
|
||
|
|
if (pStart.x > pEnd.x)
|
||
|
|
std::swap(pStart, pEnd);
|
||
|
|
|
||
|
|
// added points on line, interpolation point every grid node
|
||
|
|
double dx = pEnd.x - pStart.x;
|
||
|
|
double dy = pEnd.y - pStart.y;
|
||
|
|
double dz = pEnd.z - pStart.z;
|
||
|
|
|
||
|
|
if (dx != 0.0 && std::abs(dy / dx) <= 1.0)
|
||
|
|
{
|
||
|
|
// use x as interpolation factor
|
||
|
|
size_t startIndex = (size_t)std::ceil((pStart.x - xMinMax_.first) / dxSize_);
|
||
|
|
size_t endIndex = (size_t)std::ceil((pEnd.x - xMinMax_.first) / dxSize_);
|
||
|
|
|
||
|
|
for (size_t i = startIndex; i < endIndex; i++)
|
||
|
|
{
|
||
|
|
auto x = xMinMax_.first + i * dxSize_;
|
||
|
|
|
||
|
|
auto y = (x - pStart.x) * dy / dx + pStart.y;
|
||
|
|
auto z = (x - pStart.x) * dz / dx + pStart.z;
|
||
|
|
|
||
|
|
result.push_back({x, y, z});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// use y as interpolation factor
|
||
|
|
size_t startIndex = (size_t)std::ceil((pStart.y - yMinMax_.first) / dySize_);
|
||
|
|
size_t endIndex = (size_t)std::ceil((pEnd.y - yMinMax_.first) / dySize_);
|
||
|
|
|
||
|
|
for (size_t i = startIndex; i < endIndex; i++)
|
||
|
|
{
|
||
|
|
auto y = yMinMax_.first + i * dySize_;
|
||
|
|
|
||
|
|
auto x = (y - pStart.y) * dx / dy + pStart.x;
|
||
|
|
auto z = (y - pStart.y) * dz / dy + pStart.z;
|
||
|
|
|
||
|
|
result.push_back({x, y, z});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<PointXYZ> GridInterpolator::get_nearest_samples(size_t x_index, size_t y_index, size_t min_count, size_t max_count)
|
||
|
|
{
|
||
|
|
std::vector<PointXYZ> result;
|
||
|
|
|
||
|
|
auto centerPoint = PointXYZ(x_index, y_index);
|
||
|
|
|
||
|
|
size_t space_count = 0;
|
||
|
|
while (result.size() < min_count)
|
||
|
|
{
|
||
|
|
// build the test area
|
||
|
|
space_count++;
|
||
|
|
|
||
|
|
double volatile xMin = centerPoint.x - space_count;
|
||
|
|
double volatile xMax = centerPoint.x + space_count;
|
||
|
|
double volatile yMin = centerPoint.y - space_count;
|
||
|
|
double volatile yMax = centerPoint.y + space_count;
|
||
|
|
|
||
|
|
auto xMaxPosition = (xMinMax_.second - xMinMax_.first) / dxSize_;
|
||
|
|
auto yMaxPosition = (yMinMax_.second - yMinMax_.first) / dySize_;
|
||
|
|
|
||
|
|
xMin = xMin < 0 ? 0 : xMin;
|
||
|
|
xMax = xMax > xMaxPosition ? xMaxPosition : xMax;
|
||
|
|
yMin = yMin < 0 ? 0 : yMin;
|
||
|
|
yMax = yMax > yMaxPosition ? yMaxPosition : yMax;
|
||
|
|
|
||
|
|
filter_copy_points({xMin, yMin}, {xMax, yMax}, randomPointPositions_, result);
|
||
|
|
}
|
||
|
|
|
||
|
|
// remove some to far points while the result is more than max_count
|
||
|
|
if (result.size() > max_count)
|
||
|
|
{
|
||
|
|
std::vector<std::pair<double, PointXYZ>> pointDistances;
|
||
|
|
for (auto iter = result.begin(); iter != result.end(); iter++)
|
||
|
|
{
|
||
|
|
// get all distances
|
||
|
|
auto &p = *iter;
|
||
|
|
auto dis = centerPoint.distance(p);
|
||
|
|
pointDistances.push_back(std::make_pair(dis, p));
|
||
|
|
}
|
||
|
|
|
||
|
|
// sort their distances
|
||
|
|
std::sort(pointDistances.begin(), pointDistances.end(), [](auto &a, auto &b)
|
||
|
|
{ return a.first < b.first; });
|
||
|
|
|
||
|
|
while (pointDistances.size() > max_count)
|
||
|
|
{
|
||
|
|
// filter too far points
|
||
|
|
pointDistances.pop_back();
|
||
|
|
}
|
||
|
|
|
||
|
|
// set result
|
||
|
|
result.clear();
|
||
|
|
for (auto &i : pointDistances)
|
||
|
|
result.push_back(i.second);
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<PointXYZ> GridInterpolator::get_range_samples(size_t xIndex, size_t yIndex, double xGridSize, double yGridSize, const std::vector<PointXYZ> &randoms, double radius)
|
||
|
|
{
|
||
|
|
auto xMinMaxPosition = getMinMax(getAxisValues(randoms, Axis3DType::X));
|
||
|
|
auto yMinMaxPosition = getMinMax(getAxisValues(randoms, Axis3DType::Y));
|
||
|
|
|
||
|
|
auto dX = xMinMaxPosition.second - xMinMaxPosition.first;
|
||
|
|
auto dY = yMinMaxPosition.second - yMinMaxPosition.first;
|
||
|
|
|
||
|
|
// default is the max value of grid space / 8
|
||
|
|
double r = radius <= 0.0 ? std::max(dX, dY) / 8 : radius;
|
||
|
|
|
||
|
|
std::vector<PointXYZ> result;
|
||
|
|
PointXYZ center{xMinMaxPosition.first + xIndex * xGridSize,
|
||
|
|
yMinMaxPosition.first + yIndex * yGridSize};
|
||
|
|
for (auto &p : randoms)
|
||
|
|
{
|
||
|
|
if (center.distance(p) <= r)
|
||
|
|
result.push_back(p);
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<PointXYZ> GridInterpolator::coordinates_points(const std::vector<PointXYZ> &points)
|
||
|
|
{
|
||
|
|
std::vector<PointXYZ> result;
|
||
|
|
|
||
|
|
for (auto &p : points)
|
||
|
|
{
|
||
|
|
auto xPosition = (p.x - xMinMax_.first) / dxSize_;
|
||
|
|
auto yPosition = (p.y - yMinMax_.first) / dySize_;
|
||
|
|
|
||
|
|
result.push_back({xPosition, yPosition, p.z});
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
std::map<size_t, PointXYZ> GridInterpolator::points_hash_map(const std::vector<PointXYZ> &points)
|
||
|
|
{
|
||
|
|
std::map<size_t, PointXYZ> result;
|
||
|
|
|
||
|
|
for (auto &p : points)
|
||
|
|
{
|
||
|
|
result[p.hash2D()] = p;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::build_constraint_matrix(std::shared_ptr<ais::FMatrix> targetMatrixPtr, std::shared_ptr<ais::PMatrix> &constrainMatrixPtr)
|
||
|
|
{
|
||
|
|
std::stringstream msg;
|
||
|
|
msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
interpolationMsgs_.push_back(msg.str());
|
||
|
|
|
||
|
|
if (!targetMatrixPtr)
|
||
|
|
THROW_INVALID_ARGUMENT("Target matrix not have been initialized");
|
||
|
|
|
||
|
|
if (randomPoints_.empty())
|
||
|
|
THROW_INVALID_ARGUMENT("Random points list is empty");
|
||
|
|
|
||
|
|
// build the constraint matrix and filled nan
|
||
|
|
if (!constrainMatrixPtr.get())
|
||
|
|
{
|
||
|
|
constrainMatrixPtr = std::make_shared<ais::PMatrix>(targetMatrixPtr->shape());
|
||
|
|
constrainMatrixPtr->emptys();
|
||
|
|
}
|
||
|
|
|
||
|
|
auto eps_x = dxSize_ > 1 ? DBL_EPSILON * dxSize_ : DBL_EPSILON;
|
||
|
|
auto eps_y = dySize_ > 1 ? DBL_EPSILON * dySize_ : DBL_EPSILON;
|
||
|
|
|
||
|
|
// fill constraint points by input param
|
||
|
|
auto fill_constraint_points = [&](const std::vector<PointXYZ> &points)
|
||
|
|
{
|
||
|
|
auto size = points.size();
|
||
|
|
auto threads = size_t(std::thread::hardware_concurrency() * 1.5);
|
||
|
|
auto count = size_t(size / threads);
|
||
|
|
std::vector<std::future<uint64_t>> execs;
|
||
|
|
|
||
|
|
for (int t = 0; t < threads; t++)
|
||
|
|
{
|
||
|
|
// get begin and end param for each thread
|
||
|
|
auto begin = count * t;
|
||
|
|
// ensure the last thread fill all rest
|
||
|
|
auto end = (t == (threads - 1)) ? size : begin + count;
|
||
|
|
|
||
|
|
execs.emplace_back(std::async(
|
||
|
|
std::launch::async, [this, &constrainMatrixPtr, &points, &eps_x, &eps_y](size_t begin, size_t end)
|
||
|
|
{
|
||
|
|
|
||
|
|
for (size_t i = begin; i < end; i++)
|
||
|
|
{
|
||
|
|
auto& point = points[i];
|
||
|
|
|
||
|
|
// skip any point in the fault
|
||
|
|
bool inFault = false;
|
||
|
|
for (auto& fault : faults_)
|
||
|
|
{
|
||
|
|
//if (point.in_box(fault.box) && (point.in_polylines(fault.points) || point.in_polygon(fault.polygon, 4, dxSize_, dySize_)))
|
||
|
|
if (point.in_box(fault.box) && (point.in_polylines(fault.points) || point.in_polygon(fault.polygon)))
|
||
|
|
{
|
||
|
|
inFault = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (inFault)
|
||
|
|
{
|
||
|
|
// if point in a fault range, don't set its constraint, because it have been invalid by fault
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get x axis constraints i1--p----i2
|
||
|
|
auto xk = (point.x - xMinMax_.first) / dxSize_;
|
||
|
|
size_t i1 = size_t(xk);
|
||
|
|
size_t i2 = i1 + 1;
|
||
|
|
auto xGap1 = point.x - (xMinMax_.first + i1 * dxSize_);
|
||
|
|
auto xGap2 = point.x - (xMinMax_.first + i2 * dxSize_);
|
||
|
|
if (std::abs(xGap1) < eps_x)
|
||
|
|
{
|
||
|
|
// point is on the node, reset i2 & xGap2
|
||
|
|
i2 = i1;
|
||
|
|
xGap2 = xGap1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get y axis constraints j1-----p-j2
|
||
|
|
auto yk = (point.y - yMinMax_.first) / dySize_;
|
||
|
|
size_t j1 = size_t(yk);
|
||
|
|
size_t j2 = j1 + 1;
|
||
|
|
auto yGap1 = point.y - (yMinMax_.first + j1 * dySize_);
|
||
|
|
auto yGap2 = point.y - (yMinMax_.first + j2 * dySize_);
|
||
|
|
if (std::abs(yGap1) < eps_y)
|
||
|
|
{
|
||
|
|
// point is on the node, reset j2 & yGap2
|
||
|
|
j2 = j1;
|
||
|
|
yGap2 = yGap1;
|
||
|
|
}
|
||
|
|
|
||
|
|
setup_constraint_point(constrainMatrixPtr, i1, j1, xGap1, yGap1, point);
|
||
|
|
setup_constraint_point(constrainMatrixPtr, i1, j2, xGap1, yGap2, point);
|
||
|
|
setup_constraint_point(constrainMatrixPtr, i2, j1, xGap2, yGap1, point);
|
||
|
|
setup_constraint_point(constrainMatrixPtr, i2, j2, xGap2, yGap2, point);
|
||
|
|
}
|
||
|
|
|
||
|
|
return end - begin; },
|
||
|
|
begin, end));
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t filled = 0;
|
||
|
|
for (auto &e : execs)
|
||
|
|
{
|
||
|
|
e.wait();
|
||
|
|
filled += e.get();
|
||
|
|
}
|
||
|
|
|
||
|
|
if (filled != size)
|
||
|
|
{
|
||
|
|
THROW_RUNTIME_ERROR("Setup constraint matrix failed!!");
|
||
|
|
exit(-1);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
fill_constraint_points(randomPoints_);
|
||
|
|
|
||
|
|
// update constraints by breakline
|
||
|
|
for (auto &bl : breaklines_)
|
||
|
|
{
|
||
|
|
auto blConstraintPoints = generate_constraint_points(bl);
|
||
|
|
fill_constraint_points(blConstraintPoints);
|
||
|
|
}
|
||
|
|
|
||
|
|
// finally, copy the constraint matrix point value to target
|
||
|
|
std::vector<double> zList;
|
||
|
|
for (const ais::PointXYZ &p : *constrainMatrixPtr)
|
||
|
|
{
|
||
|
|
zList.push_back(p.z);
|
||
|
|
}
|
||
|
|
|
||
|
|
targetMatrixPtr->putMany(0, zList);
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::update_edge_node(std::shared_ptr<ais::FMatrix> &targetMatrixPtr, EdgeNodeValueMethod method)
|
||
|
|
{
|
||
|
|
auto tmp = targetMatrixPtr;
|
||
|
|
// const for shape
|
||
|
|
auto row = tmp->rows();
|
||
|
|
auto col = tmp->columns();
|
||
|
|
|
||
|
|
auto setEdgeByFillValue = [&](int64_t begin, int64_t end, int64_t step)
|
||
|
|
{
|
||
|
|
// pos is the flatten index offset of the point
|
||
|
|
for (int64_t pos = begin; pos < end; pos += step)
|
||
|
|
{
|
||
|
|
auto iter = tmp->begin() + pos;
|
||
|
|
if (ais::isnan(*iter))
|
||
|
|
{
|
||
|
|
tmp->put(pos, this->fillValue_);
|
||
|
|
|
||
|
|
// add edge point to constrainMatrixPtr_
|
||
|
|
// auto [r, c] = targetMatrixPtr_->get_pos(iter);
|
||
|
|
// constrainMatrixPtr_->put(pos, {double(r), double(c) ,this->fillValue_ });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
auto setEdgeByNearestValue = [&](int64_t begin, int64_t end, int64_t step)
|
||
|
|
{
|
||
|
|
// pos is the flatten index offset of the point
|
||
|
|
for (int64_t pos = begin; pos < end; pos += step)
|
||
|
|
{
|
||
|
|
auto iter = tmp->begin() + pos;
|
||
|
|
size_t validCount = 0;
|
||
|
|
double mean = 0.0;
|
||
|
|
|
||
|
|
auto [pos_row, pos_col] = tmp->get_pos(iter);
|
||
|
|
|
||
|
|
// loop to setup null points
|
||
|
|
if (std::isnan(*iter))
|
||
|
|
{
|
||
|
|
// set radius to found non-zero value
|
||
|
|
int32_t radius = 1;
|
||
|
|
while (validCount == 0)
|
||
|
|
{
|
||
|
|
int32_t col_increase = static_cast<int64_t>(pos_col) + static_cast<int64_t>(radius);
|
||
|
|
int32_t row_increase = static_cast<int64_t>(pos_row) + static_cast<int64_t>(radius);
|
||
|
|
int32_t cMin = (pos_col - radius) < 0 ? 0 : pos_col - radius;
|
||
|
|
int32_t cMax = (col_increase) >= col ? (col - 1) : col_increase;
|
||
|
|
|
||
|
|
int32_t rMin = (pos_row - radius) < 0 ? 0 : pos_row - radius;
|
||
|
|
int32_t rMax = (row_increase) >= row ? (row - 1) : row_increase;
|
||
|
|
|
||
|
|
for (auto r = rMin; r <= rMax; r++)
|
||
|
|
{
|
||
|
|
for (auto c = cMin; c <= cMax; c++)
|
||
|
|
{
|
||
|
|
double zValue = *(tmp->begin() + r * col + c);
|
||
|
|
if (!std::isnan(zValue))
|
||
|
|
{
|
||
|
|
mean += zValue;
|
||
|
|
validCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// zoom out for more neighbors
|
||
|
|
radius++;
|
||
|
|
}
|
||
|
|
|
||
|
|
mean /= validCount;
|
||
|
|
tmp->put(pos_row, pos_col, mean);
|
||
|
|
|
||
|
|
// add edge point to constrainMatrixPtr_
|
||
|
|
// auto [r, c] = targetMatrixPtr_->get_pos(iter);
|
||
|
|
// constrainMatrixPtr_->put(pos, { double(r), double(c) ,this->fillValue_ });
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
std::function<void(int64_t, int64_t, int64_t)> fun;
|
||
|
|
if (method == EdgeNodeValueMethod::FILL)
|
||
|
|
fun = setEdgeByFillValue;
|
||
|
|
else
|
||
|
|
fun = setEdgeByNearestValue;
|
||
|
|
|
||
|
|
// row-0, bottom border
|
||
|
|
fun(0, col, 1);
|
||
|
|
// row-n, top border
|
||
|
|
fun((row - 1) * col, row * col, 1);
|
||
|
|
// column-0, left border
|
||
|
|
fun(0, row * col, col);
|
||
|
|
// column-n, right border
|
||
|
|
fun(col - 1, row * col, col);
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::update_nan_node(std::shared_ptr<ais::FMatrix> &targetMatrixPtr)
|
||
|
|
{
|
||
|
|
auto tmp = targetMatrixPtr;
|
||
|
|
size_t count = std::count_if(std::execution::par_unseq, tmp->cbegin(), tmp->cend(), [](double v) {return std::isnan(v); });
|
||
|
|
|
||
|
|
if (count > 0 && !std::isnan(fillValue_))
|
||
|
|
{
|
||
|
|
// only replace nan when fillValue_ is not nan and count > 0
|
||
|
|
tmp->replace(std::nan("1"), this->fillValue_);
|
||
|
|
|
||
|
|
std::string msg = "Total update nan nodes: " + std::to_string(count);
|
||
|
|
interpolationMsgs_.push_back(msg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
std::vector<double> build_xy_data(const Point3D &p)
|
||
|
|
{
|
||
|
|
std::vector<double> r{p.x, p.y, 1.0};
|
||
|
|
return r;
|
||
|
|
};
|
||
|
|
|
||
|
|
bool all_filled(std::shared_ptr<ais::FMatrix> target, size_t begin_index, size_t end_index)
|
||
|
|
{
|
||
|
|
|
||
|
|
const auto function = [](double i) -> bool
|
||
|
|
{ return !(std::isnan(i) || std::isinf(i)); };
|
||
|
|
|
||
|
|
if ((target->cbegin() + begin_index) > target->cend() || (target->cbegin() + end_index) > target->cend())
|
||
|
|
{
|
||
|
|
THROW_INVALID_ARGUMENT("Out of target range.");
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ret = std::all_of(std::execution::par_unseq, target->cbegin() + begin_index, target->cend() + end_index, function);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t GridInterpolator::detect_estimate_factor()
|
||
|
|
{
|
||
|
|
// After many test, we found when the points count >= 1.5% of total gird node count, the minimum curvature
|
||
|
|
// will output smooth result after estimated. So the main point for this function is try to found out the
|
||
|
|
// scale factor for input X/Y grid size, then use this scale factor to increase grid size to get the
|
||
|
|
// estimate grid, later use the estimate grid and interpolate
|
||
|
|
// scale * randomPoints.size() / (x grid count * y grid count) > 1.5%
|
||
|
|
if (estimateFactor_ == 0)
|
||
|
|
{
|
||
|
|
auto temp = ((xMinMax_.second - xMinMax_.first) / dxSize_) * ((yMinMax_.second - yMinMax_.first) / dySize_) * .015 / randomPoints_.size();
|
||
|
|
size_t scale = (size_t)std::ceil(std::sqrt(temp));
|
||
|
|
|
||
|
|
if (scale > 1)
|
||
|
|
estimateFactor_ = scale;
|
||
|
|
}
|
||
|
|
|
||
|
|
return estimateFactor_;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::scale_estimate()
|
||
|
|
{
|
||
|
|
// function start message
|
||
|
|
std::stringstream msg;
|
||
|
|
msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
interpolationMsgs_.push_back(msg.str());
|
||
|
|
|
||
|
|
// only do estimation while the estimateFactor_ is more than 1
|
||
|
|
if (estimateFactor_ > 1)
|
||
|
|
{
|
||
|
|
std::string m = "Estimate factor: " + std::to_string(estimateFactor_);
|
||
|
|
interpolationMsgs_.push_back(m);
|
||
|
|
|
||
|
|
// 1. build estimate matrix by estimateFactor
|
||
|
|
// the estimate matrix area is same as target matrix,
|
||
|
|
// so must reset some class internal vars
|
||
|
|
dxSize_ *= estimateFactor_;
|
||
|
|
dySize_ *= estimateFactor_;
|
||
|
|
|
||
|
|
size_t xCount = (size_t)std::ceil((xMinMax_.second - xMinMax_.first) / dxSize_) + 1;
|
||
|
|
size_t yCount = (size_t)std::ceil((yMinMax_.second - yMinMax_.first) / dySize_) + 1;
|
||
|
|
|
||
|
|
ais::Shape estimateShape = {yCount, xCount};
|
||
|
|
estimateMatrixPtr_ = std::make_shared<ais::FMatrix>(estimateShape);
|
||
|
|
estimateMatrixPtr_->zeros();
|
||
|
|
generate_grid_params(estimateMatrixPtr_);
|
||
|
|
|
||
|
|
// 2. setup estimate matrix faults impact
|
||
|
|
// matrix which storage the points in fault for estimate
|
||
|
|
std::shared_ptr<ais::FMatrix> estimatePointInFaultMatrixPtr;
|
||
|
|
// matrix which storage the fault affect block values for estimate
|
||
|
|
std::shared_ptr<ais::FMatrix> estimateFaultAffectMatrixPtr;
|
||
|
|
build_fault_impact_matrix(estimateMatrixPtr_, estimatePointInFaultMatrixPtr, estimateFaultAffectMatrixPtr);
|
||
|
|
|
||
|
|
// 3. setup the constrict matrix and initial estimate matrix
|
||
|
|
std::shared_ptr<ais::PMatrix> estimateConstrainMatrixPtr;
|
||
|
|
build_constraint_matrix(estimateMatrixPtr_, estimateConstrainMatrixPtr);
|
||
|
|
|
||
|
|
// 4. update estimate matrix edge
|
||
|
|
update_edge_node(estimateMatrixPtr_);
|
||
|
|
|
||
|
|
// 5. estimate surface for estimate matrix
|
||
|
|
estimate_gradients_surface(estimateMatrixPtr_);
|
||
|
|
|
||
|
|
// 6. update nan nodes in estimate matrix
|
||
|
|
update_nan_node(estimateMatrixPtr_);
|
||
|
|
|
||
|
|
// 7. go interpolation
|
||
|
|
start_interpolation(estimateMatrixPtr_, estimateConstrainMatrixPtr, estimatePointInFaultMatrixPtr, estimateFaultAffectMatrixPtr);
|
||
|
|
|
||
|
|
//dump_result_async("output_estimated.grd", estimateMatrixPtr_);
|
||
|
|
|
||
|
|
// 8. interpolate the estimate to target matrix
|
||
|
|
interpolate_estimate_2_target();
|
||
|
|
|
||
|
|
// release inter vars
|
||
|
|
estimateConstrainMatrixPtr.reset();
|
||
|
|
estimatePointInFaultMatrixPtr.reset();
|
||
|
|
estimateFaultAffectMatrixPtr.reset();
|
||
|
|
|
||
|
|
// finally reset minimum curvature params for real interpolation
|
||
|
|
generate_grid_params(targetMatrixPtr_);
|
||
|
|
//dump_result_async("estimated2target.grd", targetMatrixPtr_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::interpolate_estimate_2_target()
|
||
|
|
{
|
||
|
|
// function start message
|
||
|
|
std::stringstream msg;
|
||
|
|
msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
interpolationMsgs_.push_back(msg.str());
|
||
|
|
|
||
|
|
auto tShape = targetMatrixPtr_->shape();
|
||
|
|
auto eShape = estimateMatrixPtr_->shape();
|
||
|
|
|
||
|
|
auto threads = size_t(std::thread::hardware_concurrency() * 1.5);
|
||
|
|
auto rowInThread = size_t(tShape.rows / threads);
|
||
|
|
std::vector<std::future<uint64_t>> execs;
|
||
|
|
for (int t = 0; t < threads; t++)
|
||
|
|
{
|
||
|
|
// get begin and end param for each thread
|
||
|
|
auto begin = rowInThread * t;
|
||
|
|
// ensure the last thread fill all rest
|
||
|
|
auto end = (t == (threads - 1)) ? tShape.rows : begin + rowInThread;
|
||
|
|
|
||
|
|
// multi-thread execution
|
||
|
|
execs.emplace_back(std::async(
|
||
|
|
std::launch::async,
|
||
|
|
[this, &tShape, &eShape](size_t begin, size_t end)
|
||
|
|
{
|
||
|
|
std::atomic<size_t> failedCount = 0;
|
||
|
|
auto rows = tShape.rows;
|
||
|
|
auto cols = tShape.cols;
|
||
|
|
|
||
|
|
for (int j = begin; j < end; j++)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < tShape.cols; i++)
|
||
|
|
{
|
||
|
|
auto pos = j * tShape.cols + i;
|
||
|
|
auto z = targetMatrixPtr_->at(pos);
|
||
|
|
|
||
|
|
if (std::isnan(z) || std::abs(z - fillValue_) < 1e-6)
|
||
|
|
{
|
||
|
|
// put the interpolate value to target matrix while the value is nan or close to fill value
|
||
|
|
size_t ei = std::floor(i / estimateFactor_);
|
||
|
|
size_t ej = std::floor(j / estimateFactor_);
|
||
|
|
|
||
|
|
size_t mi = i % estimateFactor_;
|
||
|
|
size_t mj = j % estimateFactor_;
|
||
|
|
|
||
|
|
double zVertical = fillValue_;
|
||
|
|
double p0z = estimateMatrixPtr_->at(ej, ei);
|
||
|
|
|
||
|
|
if (ei < (eShape.cols-1) && ej < (eShape.rows-1))
|
||
|
|
{
|
||
|
|
// for all node in good range, use bilinear interpolation
|
||
|
|
double p1z = estimateMatrixPtr_->at(ej, ei + 1);
|
||
|
|
double p2z = estimateMatrixPtr_->at(ej + 1, ei + 1);
|
||
|
|
double p3z = estimateMatrixPtr_->at(ej + 1, ei);
|
||
|
|
|
||
|
|
// get z value by bilinear interpolation
|
||
|
|
double zHorizontal2 = (p2z - p3z) * mi / estimateFactor_ + p3z;
|
||
|
|
double zHorizontal1 = (p1z - p0z) * mi / estimateFactor_ + p0z;
|
||
|
|
zVertical = (zHorizontal2 - zHorizontal1) * mj / estimateFactor_ + zHorizontal1;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// for other node(botoom and right edge), just copy p0z point value
|
||
|
|
zVertical = p0z;
|
||
|
|
}
|
||
|
|
|
||
|
|
targetMatrixPtr_->put(pos, zVertical);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return end - begin;
|
||
|
|
},
|
||
|
|
begin, end));
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t rowFilled = 0;
|
||
|
|
for (auto &e : execs)
|
||
|
|
{
|
||
|
|
e.wait();
|
||
|
|
auto filledInThread = e.get();
|
||
|
|
rowFilled += filledInThread;
|
||
|
|
|
||
|
|
// std::string msg = "Interpolate estimate to target row: " + std::to_string(rowFilled);
|
||
|
|
// interpolationMsgs_.push_back(msg);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::estimate_gradients_surface(std::shared_ptr<ais::FMatrix> &targetMatrixPtr)
|
||
|
|
{
|
||
|
|
// function start message
|
||
|
|
std::stringstream msg;
|
||
|
|
msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
interpolationMsgs_.push_back(msg.str());
|
||
|
|
|
||
|
|
std::atomic<size_t> count = 0;
|
||
|
|
auto tmp = targetMatrixPtr;
|
||
|
|
auto shape = targetMatrixPtr->shape();
|
||
|
|
|
||
|
|
// before delaunay triangles, added rectangle corner points to cover all rectangle
|
||
|
|
double rows = shape.rows;
|
||
|
|
double cols = shape.cols;
|
||
|
|
|
||
|
|
// add corner points with its origin value, will reset it later if the value is 0 by the gaussian filter
|
||
|
|
Point3D p0{0, 0, tmp->at(0, 0)};
|
||
|
|
Point3D p1{0, rows - 1, tmp->at(rows - 1, 0)};
|
||
|
|
Point3D p2{cols - 1, rows - 1, tmp->at(rows - 1, cols - 1)};
|
||
|
|
Point3D p3{cols - 1, 0, tmp->at(0, cols - 1)};
|
||
|
|
|
||
|
|
randomPointPositions_.push_back(p0);
|
||
|
|
randomPointPositions_.push_back(p1);
|
||
|
|
randomPointPositions_.push_back(p2);
|
||
|
|
randomPointPositions_.push_back(p3);
|
||
|
|
|
||
|
|
std::set<size_t> cornerHashs = {
|
||
|
|
p0.hash2D(), p1.hash2D(), p2.hash2D(), p3.hash2D()};
|
||
|
|
|
||
|
|
// build the delaunay triangles with random point positions, which will use point's grid position to simple calculation
|
||
|
|
// eg: point(2342.22, 1242.23, 23.3) ==> position(6.1, 42.23, 23.3)
|
||
|
|
std::vector<Triangle<Point3D>> triangles;
|
||
|
|
ais::delaunay_triangulation(randomPointPositions_, triangles);
|
||
|
|
|
||
|
|
// remove triangle without z value, means the triangle contact to super-triangles
|
||
|
|
for (auto iter = triangles.begin(); iter != triangles.end();)
|
||
|
|
{
|
||
|
|
auto t = (*iter);
|
||
|
|
auto pz = t.points[0].z * t.points[1].z * t.points[2].z;
|
||
|
|
|
||
|
|
if (std::isnan(pz) || std::isinf(pz))
|
||
|
|
iter = triangles.erase(iter);
|
||
|
|
else
|
||
|
|
iter++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get triangles info, such as triangle points' distance min/max
|
||
|
|
std::map<size_t, std::set<size_t>> trianglePointLinkMap;
|
||
|
|
double distanceMax = 0.0, distanceMin = std::numeric_limits<double>::max();
|
||
|
|
get_triangle_info(triangles, trianglePointLinkMap, distanceMin, distanceMax);
|
||
|
|
|
||
|
|
auto updateCornerPointEstimateZ = [this, &trianglePointLinkMap, &rows, &cols, &tmp, &cornerHashs](size_t rowPos, size_t colPos)
|
||
|
|
{
|
||
|
|
double ret = std::nan("1");
|
||
|
|
Point3D point{(double)colPos, (double)rowPos, INFINITY};
|
||
|
|
|
||
|
|
auto linkPoints = trianglePointLinkMap[point.hash2D()];
|
||
|
|
|
||
|
|
std::vector<double> estimates;
|
||
|
|
|
||
|
|
for (auto &rp : randomPointPositions_)
|
||
|
|
{
|
||
|
|
if (linkPoints.find(rp.hash2D()) != linkPoints.end() && cornerHashs.find(rp.hash2D()) == cornerHashs.end())
|
||
|
|
{
|
||
|
|
// estimate z value by Gaussian with no-corner linked point
|
||
|
|
double estimateZ = point.gaussian_interpolation_z_value(point.distance2D(rp), rp.z, rows, cols, cornerWeight_);
|
||
|
|
if (estimateZ > 1e-6)
|
||
|
|
estimates.push_back(estimateZ);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (estimates.size() > 0)
|
||
|
|
{
|
||
|
|
ret = std::accumulate(estimates.begin(), estimates.end(), 0.0) / estimates.size();
|
||
|
|
|
||
|
|
// update point z for targetMatrixPtr & randomPointPositions_
|
||
|
|
tmp->put(rowPos, colPos, ret);
|
||
|
|
for (auto rp = randomPointPositions_.begin(); rp != randomPointPositions_.end(); rp++)
|
||
|
|
{
|
||
|
|
if (rp->hash2D() == point.hash2D())
|
||
|
|
{
|
||
|
|
rp->z = ret;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
};
|
||
|
|
|
||
|
|
// reset the corner points' z-value to make the rect value more smooth
|
||
|
|
double updatedZ = updateCornerPointEstimateZ(0, 0);
|
||
|
|
updatedZ = updateCornerPointEstimateZ(rows - 1, 0);
|
||
|
|
updatedZ = updateCornerPointEstimateZ(rows - 1, cols - 1);
|
||
|
|
updatedZ = updateCornerPointEstimateZ(0, cols - 1);
|
||
|
|
|
||
|
|
// reset triangles
|
||
|
|
triangles.clear();
|
||
|
|
ais::delaunay_triangulation(randomPointPositions_, triangles);
|
||
|
|
|
||
|
|
// remove triangle without z value, means the triangle contact to super-triangles
|
||
|
|
for (auto iter = triangles.begin(); iter != triangles.end();)
|
||
|
|
{
|
||
|
|
auto t = (*iter);
|
||
|
|
auto pz = t.points[0].z * t.points[1].z * t.points[2].z;
|
||
|
|
|
||
|
|
if (std::isnan(pz) || std::isinf(pz))
|
||
|
|
iter = triangles.erase(iter);
|
||
|
|
else
|
||
|
|
iter++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// get all coe for all random points
|
||
|
|
ais::Matrix<double> allXYMatrix(randomPointPositions_.size(), 3);
|
||
|
|
ais::Matrix<double> allZMatrix(1, randomPointPositions_.size());
|
||
|
|
for (int pi = 0; pi < randomPointPositions_.size(); pi++)
|
||
|
|
{
|
||
|
|
auto &p = randomPointPositions_[pi];
|
||
|
|
allXYMatrix.putMany(pi, 0, build_xy_data(p));
|
||
|
|
allZMatrix.put(0, pi, p.z);
|
||
|
|
}
|
||
|
|
auto allCoe = ais::linalg::lstsq(allXYMatrix, allZMatrix);
|
||
|
|
|
||
|
|
// use multi thread to speed up
|
||
|
|
auto threads = size_t(std::thread::hardware_concurrency() * 1.5);
|
||
|
|
// threads = 1;
|
||
|
|
auto rowInThread = size_t(shape.rows / threads);
|
||
|
|
|
||
|
|
std::vector<std::future<uint64_t>> execs;
|
||
|
|
for (int t = 0; t < threads; t++)
|
||
|
|
{
|
||
|
|
// get begin and end param for each thread
|
||
|
|
auto begin = rowInThread * t;
|
||
|
|
// ensure the last thread fill all rest
|
||
|
|
auto end = (t == (threads - 1)) ? shape.rows : begin + rowInThread;
|
||
|
|
|
||
|
|
// multi-thread execution
|
||
|
|
execs.emplace_back(std::async(
|
||
|
|
std::launch::async, [this, &shape, &tmp, &count, &triangles, &allCoe](size_t begin, size_t end)
|
||
|
|
{
|
||
|
|
std::atomic<size_t> failedCount = 0;
|
||
|
|
auto tsize = triangles.size();
|
||
|
|
auto rows = shape.rows;
|
||
|
|
auto cols = shape.cols;
|
||
|
|
|
||
|
|
for (size_t nodeJ = begin; nodeJ < end; nodeJ++)
|
||
|
|
{
|
||
|
|
for (size_t nodeI = 0; nodeI < shape.cols; nodeI++)
|
||
|
|
{
|
||
|
|
auto z = tmp->at(nodeJ, nodeI);
|
||
|
|
if (ais::isnan(z) || std::abs(z - fillValue_) < 1e-6)
|
||
|
|
{
|
||
|
|
std::vector<std::pair<double, double>> interpolations;
|
||
|
|
|
||
|
|
// use index as the point position to simple calculation
|
||
|
|
Point3D nodePoint{ (double)nodeI, (double)nodeJ, INFINITY };
|
||
|
|
|
||
|
|
for (int ti = 0 ; ti < tsize; ti++)
|
||
|
|
{
|
||
|
|
auto& t = triangles[ti];
|
||
|
|
if (nodePoint.in_box(t.min_max[0], t.min_max[1]) && nodePoint.in_polygon(t.polygon))
|
||
|
|
{
|
||
|
|
auto pa = t.points[0];
|
||
|
|
auto pb = t.points[1];
|
||
|
|
auto pc = t.points[2];
|
||
|
|
|
||
|
|
auto da = nodePoint.distance(pa);
|
||
|
|
auto db = nodePoint.distance(pb);
|
||
|
|
auto dc = nodePoint.distance(pc);
|
||
|
|
|
||
|
|
auto za = nodePoint.point_interpolate(pb, pc, pa);
|
||
|
|
auto zb = nodePoint.point_interpolate(pc, pa, pb);
|
||
|
|
auto zc = nodePoint.point_interpolate(pa, pb, pc);
|
||
|
|
|
||
|
|
interpolations.push_back({ da, za });
|
||
|
|
interpolations.push_back({ db, zb });
|
||
|
|
interpolations.push_back({ dc, zc });
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (interpolations.size() > 0)
|
||
|
|
{
|
||
|
|
double avg_inter = interpolations.size() == 0 ? interpolations[0].second : ais::get_mean(interpolations);
|
||
|
|
if (!std::isinf(avg_inter))
|
||
|
|
tmp->put(nodeJ, nodeI, avg_inter);
|
||
|
|
else
|
||
|
|
tmp->put(nodeJ, nodeI, fillValue_);
|
||
|
|
|
||
|
|
count++;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// debug usage
|
||
|
|
failedCount++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return end - begin; },
|
||
|
|
begin, end));
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t rowFilled = 0;
|
||
|
|
for (auto &e : execs)
|
||
|
|
{
|
||
|
|
e.wait();
|
||
|
|
auto filledInThread = e.get();
|
||
|
|
rowFilled += filledInThread;
|
||
|
|
|
||
|
|
// std::string msg = "Estimated row: " + std::to_string(rowFilled);
|
||
|
|
// interpolationMsgs_.push_back(msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (count > 0)
|
||
|
|
{
|
||
|
|
std::string msg = "Total estimated nodes: " + std::to_string(count);
|
||
|
|
interpolationMsgs_.push_back(msg);
|
||
|
|
}
|
||
|
|
|
||
|
|
// dump after estimate value
|
||
|
|
{
|
||
|
|
// update zMin and zMax
|
||
|
|
zMinMax_ = getMinMax(*targetMatrixPtr);
|
||
|
|
|
||
|
|
// std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
// std::string msg = "Estimated completed";
|
||
|
|
// interpolationMsgs_.push_back(msg);
|
||
|
|
|
||
|
|
/*
|
||
|
|
auto ret = std::async(std::launch::async, [&]()
|
||
|
|
{
|
||
|
|
std::string filename = "2_Estimated_" + std::to_string(shape.rows) + "x" + std::to_string(shape.cols) + ".grd";
|
||
|
|
dump_result(filename.c_str());
|
||
|
|
return; });
|
||
|
|
*/
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::estimate_gradients_surface_2(InitTargetMatrixMethod method)
|
||
|
|
{
|
||
|
|
// // if (!estimateTargetMatrix_)
|
||
|
|
// // return;
|
||
|
|
//
|
||
|
|
// // function start message
|
||
|
|
// std::stringstream msg;
|
||
|
|
// msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
// interpolationMsgs_.push_back(msg.str());
|
||
|
|
//
|
||
|
|
// std::atomic<size_t> count = 0;
|
||
|
|
// auto tmp = targetMatrixPtr_;
|
||
|
|
// auto shape = targetMatrixPtr_->shape();
|
||
|
|
//
|
||
|
|
// ais::FMatrix updateMatrix(shape);
|
||
|
|
// updateMatrix.nans();
|
||
|
|
//
|
||
|
|
// // storage the constrict values to map
|
||
|
|
// std::map<size_t, double> constrictValues;
|
||
|
|
// for (size_t i = 0; i < shape.size(); i++)
|
||
|
|
// {
|
||
|
|
// double value = tmp->at(i);
|
||
|
|
// if (!std::isnan(value) && value != 0.0)
|
||
|
|
// constrictValues[i] = value;
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// // build the delaunay triangles with random point positions, which will use point's grid position to simple calculation
|
||
|
|
// // eg: p(2342.22, 1242.23, 23.3) ==> p(12.2, 42.23, 23.3)
|
||
|
|
// std::vector<Triangle<Point3D>> triangles;
|
||
|
|
// ais::delaunay_triangulation(randomPointPositions_, triangles);
|
||
|
|
//
|
||
|
|
// // get all coe for all random points
|
||
|
|
// ais::Matrix<double> allXYMatrix(randomPointPositions_.size(), 3);
|
||
|
|
// ais::Matrix<double> allZMatrix(1, randomPointPositions_.size());
|
||
|
|
// for (int pi = 0; pi < randomPointPositions_.size(); pi++)
|
||
|
|
// {
|
||
|
|
// auto & p = randomPointPositions_[pi];
|
||
|
|
// allXYMatrix.putMany(pi, 0, build_xy_data(p));
|
||
|
|
// allZMatrix.put(0, pi, p.z);
|
||
|
|
// }
|
||
|
|
// auto allCoe = ais::linalg::lstsq(allXYMatrix, allZMatrix);
|
||
|
|
//
|
||
|
|
// // remove triangle without z value, means the triangle contact to super-triangles
|
||
|
|
// for (auto iter = triangles.begin(); iter != triangles.end();)
|
||
|
|
// {
|
||
|
|
// auto t = (*iter);
|
||
|
|
// auto pz = t.points[0].z * t.points[1].z * t.points[2].z;
|
||
|
|
//
|
||
|
|
// if (std::isnan(pz) || std::isinf(pz))
|
||
|
|
// iter = triangles.erase(iter);
|
||
|
|
// else
|
||
|
|
// iter++;
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// std::map<size_t, std::set<size_t>> trianglePointLinkMap;
|
||
|
|
// double distanceMax = 0.0, distanceMin = std::numeric_limits<double>::max();
|
||
|
|
// get_triangle_info(triangles, trianglePointLinkMap, distanceMin, distanceMax);
|
||
|
|
//
|
||
|
|
//
|
||
|
|
// // use multi thread to speed up
|
||
|
|
// auto threads = size_t(std::thread::hardware_concurrency() * 1.5);
|
||
|
|
// #if defined(_DEBUG)
|
||
|
|
// //threads = 1; // debug usage
|
||
|
|
// #endif
|
||
|
|
// auto rowInThread = size_t(shape.rows / threads);
|
||
|
|
//
|
||
|
|
// bool allFilled = false;
|
||
|
|
//
|
||
|
|
// // check the target matrix have been filled or not
|
||
|
|
// {
|
||
|
|
// std::lock_guard<std::mutex> lk(dataMutex_);
|
||
|
|
// auto zeroCount = std::count(std::execution::par_unseq, tmp->begin(), tmp->end(), 0.0);
|
||
|
|
// allFilled = all_filled(tmp, 0, shape.size());
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// while (!allFilled)
|
||
|
|
// {
|
||
|
|
// // copy target matrix data to update matrix
|
||
|
|
// {
|
||
|
|
// std::lock_guard<std::mutex> lk(dataMutex_);
|
||
|
|
// updateMatrix.putMany(0, *tmp);
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// std::vector<std::future<uint64_t>> execs;
|
||
|
|
// for (int t = 0; t < threads; t++)
|
||
|
|
// {
|
||
|
|
// // get begin and end param for each thread
|
||
|
|
// auto begin = rowInThread * t;
|
||
|
|
// // ensure the last thread fill all rest
|
||
|
|
// auto end = (t == (threads - 1)) ? shape.rows : begin + rowInThread;
|
||
|
|
//
|
||
|
|
// //============== Solution 5, MA Gaussian filter for all point =========================
|
||
|
|
// execs.emplace_back(std::async(
|
||
|
|
// std::launch::async, [this, &shape, &tmp, &count, &constrictValues, &updateMatrix](size_t begin, size_t end)
|
||
|
|
// {
|
||
|
|
// for (size_t j = begin; j < end; j++)
|
||
|
|
// {
|
||
|
|
// for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
// {
|
||
|
|
// // use index as the point position to simple calculation
|
||
|
|
// Point3D girdPoint{ (double)i, (double)j };
|
||
|
|
// size_t pos = j * shape.cols + i;
|
||
|
|
//
|
||
|
|
// double z = tmp->at(pos);
|
||
|
|
// if (ais::isnan(z) || constrictValues.find(pos) == constrictValues.end())
|
||
|
|
// {
|
||
|
|
// // update all nodes which is not in constrict values
|
||
|
|
// z = ma_gaussian_filter(i, j, tmp, shape);
|
||
|
|
// if(!std::isnan(z))
|
||
|
|
// updateMatrix.put(pos, z);
|
||
|
|
// }
|
||
|
|
// else
|
||
|
|
// {
|
||
|
|
// // for all constrict values, just copy it
|
||
|
|
// updateMatrix.put(pos, z);
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// return end - begin;
|
||
|
|
// },
|
||
|
|
// begin, end));
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// // wait for multi-thread exec
|
||
|
|
// uint64_t rowFilled = 0;
|
||
|
|
// for (auto& e : execs)
|
||
|
|
// {
|
||
|
|
// e.wait();
|
||
|
|
// auto filledInThread = e.get();
|
||
|
|
// rowFilled += filledInThread;
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// std::string msg = "Completed loop: " + std::to_string(count);
|
||
|
|
// interpolationMsgs_.push_back(msg);
|
||
|
|
//
|
||
|
|
// // copy the update matrix to target
|
||
|
|
// {
|
||
|
|
// std::lock_guard<std::mutex> lk(dataMutex_);
|
||
|
|
// tmp->putMany(0, updateMatrix);
|
||
|
|
// auto zeroCount = std::count(std::execution::par_unseq, tmp->begin(), tmp->end(), 0.0);
|
||
|
|
// allFilled = all_filled(tmp, 0, shape.size());
|
||
|
|
// }
|
||
|
|
// count++;
|
||
|
|
// }
|
||
|
|
//
|
||
|
|
// if (count > 0)
|
||
|
|
// {
|
||
|
|
// std::string msg = "Total estimated loops: " + std::to_string(count);
|
||
|
|
// interpolationMsgs_.push_back(msg);
|
||
|
|
// }
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::build_fault_impact_matrix(std::shared_ptr<ais::FMatrix> targetMatrixPtr,
|
||
|
|
std::shared_ptr<ais::FMatrix> &pointInFaultMatrixPtr, std::shared_ptr<ais::FMatrix> &faultAffectMatrixPtr)
|
||
|
|
{
|
||
|
|
// do nothing while the fault is empty
|
||
|
|
if (faults_.empty())
|
||
|
|
return;
|
||
|
|
|
||
|
|
std::stringstream msg;
|
||
|
|
msg << ais::time_str() << " " << __FUNCTION__;
|
||
|
|
interpolationMsgs_.push_back(msg.str());
|
||
|
|
|
||
|
|
// pointInFaultMatrix means for all grid points which are in the fault
|
||
|
|
auto shape = targetMatrixPtr->shape();
|
||
|
|
if (!pointInFaultMatrixPtr.get())
|
||
|
|
pointInFaultMatrixPtr = std::make_shared<ais::FMatrix>(shape);
|
||
|
|
|
||
|
|
// faultAffectMatrix means for all grid points which iteration block have been affect fault
|
||
|
|
if (!faultAffectMatrixPtr.get())
|
||
|
|
{
|
||
|
|
faultAffectMatrixPtr = std::make_shared<ais::FMatrix>(shape.rows + 4, shape.cols + 4);
|
||
|
|
faultAffectMatrixPtr->zeros();
|
||
|
|
}
|
||
|
|
// build up point-in-fault matrix, used for add fault line on output grid
|
||
|
|
for (size_t j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
// build the node point
|
||
|
|
auto x = xMinMax_.first + i * dxSize_;
|
||
|
|
auto y = yMinMax_.first + j * dySize_;
|
||
|
|
auto ui = i + 2;
|
||
|
|
auto uj = j + 2;
|
||
|
|
ais::Point p{x, y};
|
||
|
|
|
||
|
|
// loop fault to check the node point in fault or not
|
||
|
|
for (auto &fault : faults_)
|
||
|
|
{
|
||
|
|
// use loose test(in_polygon(controlPoints=0) for identification the node point in fault as more as possible
|
||
|
|
if (p.in_box(fault.box) && (p.in_polylines(fault.points) || p.in_polygon(fault.polygon)))
|
||
|
|
{
|
||
|
|
// build a fault point box for fault line constrict
|
||
|
|
std::vector<ais::Point> faultPointBox = {
|
||
|
|
{x - 0.5 * dxSize_, y - 0.5 * dySize_},
|
||
|
|
{x - 0.5 * dxSize_, y + 0.5 * dySize_},
|
||
|
|
{x + 0.5 * dxSize_, y + 0.5 * dySize_},
|
||
|
|
{x + 0.5 * dxSize_, y - 0.5 * dySize_}};
|
||
|
|
|
||
|
|
int hitCount = 0;
|
||
|
|
for (auto &fpb : faultPointBox)
|
||
|
|
{
|
||
|
|
if (fpb.in_polygon(fault.polygon))
|
||
|
|
hitCount++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// node point in fault, flag it and break loop for next point
|
||
|
|
faultAffectMatrixPtr->put(uj, ui, double(1 << hitCount));
|
||
|
|
// the faults will not overlapped, so don't test anymore when hit one fault, just break loop
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// block point check position
|
||
|
|
// iterated points which need be analysis are below
|
||
|
|
// 0,2
|
||
|
|
// -1,1 0,1 1,1
|
||
|
|
// -2,0 -1,0 0,0 1,0 2,0
|
||
|
|
// -1,-1 0,-1 1,-1
|
||
|
|
// 0,-2
|
||
|
|
const std::vector<std::pair<int, int>> insidePoint1 = {{0, 1}, {-1, 0}, {1, 0}, {0, -1}};
|
||
|
|
const std::vector<std::pair<int, int>> insidePoint2 = {{-1, 1}, {-1, -1}, {1, 1}, {1, -1}};
|
||
|
|
|
||
|
|
const std::vector<std::pair<int, int>> insidePoint3 = {
|
||
|
|
{-2, 2}, {-2, 1}, {-2, 0}, {-2, -1}, {-2, -2}, {-1, 2}, {-1, -2}, {0, 2}, {0, -2}, {1, 2}, {1, -2}, {2, 2}, {2, 1}, {2, 0}, {2, -1}, {2, -2}};
|
||
|
|
|
||
|
|
// get block point fault tag value
|
||
|
|
auto pointFaultTagValue = [](const std::shared_ptr<ais::FMatrix> pifMatrixPtr, size_t i, size_t j, const std::pair<int, int> &p, bool force = false)
|
||
|
|
{
|
||
|
|
long ret = 0;
|
||
|
|
auto shape = pifMatrixPtr->shape();
|
||
|
|
auto pos = (j + 2 + p.second) * shape.cols + i + 2 + p.first;
|
||
|
|
auto pInFault = pifMatrixPtr->at(pos);
|
||
|
|
if (pInFault > 0.0 || force)
|
||
|
|
{
|
||
|
|
ret = 1 << ((p.second + 2) * 5 + (p.first + 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
};
|
||
|
|
|
||
|
|
// get point fault tag for faults
|
||
|
|
auto pointFaultAffectValue = [&insidePoint1, &insidePoint2, &insidePoint3, this, &pointFaultTagValue](const std::shared_ptr<ais::FMatrix> pifMatrixPtr, size_t i, size_t j, const ais::Fault &fault)
|
||
|
|
{
|
||
|
|
long ret = 0;
|
||
|
|
|
||
|
|
auto &fps = fault.points;
|
||
|
|
size_t m = fault.points.size();
|
||
|
|
|
||
|
|
auto x = xMinMax_.first + i * dxSize_;
|
||
|
|
auto y = yMinMax_.first + j * dySize_;
|
||
|
|
ais::Point p1{x, y};
|
||
|
|
|
||
|
|
auto faultBoxMin = fault.box[0];
|
||
|
|
auto faultBoxMax = fault.box[2];
|
||
|
|
|
||
|
|
if (x < (faultBoxMin.x - 2 * dxSize_) || x > (faultBoxMax.x + 2 * dxSize_) ||
|
||
|
|
y < (faultBoxMin.y - 2 * dySize_) || y > (faultBoxMax.y + 2 * dySize_))
|
||
|
|
{
|
||
|
|
// any point out of fault box will skip it.
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
// check insidePoint1
|
||
|
|
for (auto &p : insidePoint1)
|
||
|
|
{
|
||
|
|
// loop inside nodes to build the line p(0,0) --- p(inside point)
|
||
|
|
auto x2 = xMinMax_.first + (i + p.first) * dxSize_;
|
||
|
|
auto y2 = yMinMax_.first + (j + p.second) * dySize_;
|
||
|
|
ais::Point p2{x2, y2};
|
||
|
|
|
||
|
|
for (auto mi = 0; mi < m - 1; mi++)
|
||
|
|
// loop fault line points to build another line
|
||
|
|
if (line_cross(p1, p2, fps[mi], fps[((mi + 1) % m)]))
|
||
|
|
{
|
||
|
|
// the fault node line cross fault line
|
||
|
|
ret |= pointFaultTagValue(pifMatrixPtr, i, j, p, true);
|
||
|
|
|
||
|
|
// for expend point
|
||
|
|
if (p.first != 0)
|
||
|
|
{
|
||
|
|
// for x axis
|
||
|
|
auto newX = p.first > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (p.second + 2) * 5 + (newX + 2);
|
||
|
|
ret |= 1 << pExtPos;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// for y axis
|
||
|
|
auto newY = p.second > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (newY + 2) * 5 + (p.first + 2);
|
||
|
|
ret |= 1 << pExtPos;
|
||
|
|
}
|
||
|
|
|
||
|
|
// bingo, the line p1--p2 cross fault, break loop check next
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// check insidePoint2
|
||
|
|
for (auto &p : insidePoint2)
|
||
|
|
{
|
||
|
|
// loop inside nodes to build the line p(0,0) --- p(inside point)
|
||
|
|
auto x2 = xMinMax_.first + (i + p.first) * dxSize_;
|
||
|
|
auto y2 = yMinMax_.first + (j + p.second) * dySize_;
|
||
|
|
ais::Point p2{x2, y2};
|
||
|
|
|
||
|
|
for (auto mi = 0; mi < m - 1; mi++)
|
||
|
|
// loop fault line points to build another line
|
||
|
|
if (line_cross(p1, p2, fps[mi], fps[((mi + 1) % m)]))
|
||
|
|
{
|
||
|
|
// the fault box node line cross fault line
|
||
|
|
ret |= pointFaultTagValue(pifMatrixPtr, i, j, p, true);
|
||
|
|
|
||
|
|
// for expend point
|
||
|
|
auto newX = p.first > 0 ? 2 : -2;
|
||
|
|
auto newY = p.second > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (newY + 2) * 5 + (newX + 2);
|
||
|
|
|
||
|
|
ret |= 1 << pExtPos;
|
||
|
|
|
||
|
|
// bingo, the line p1--p2 cross fault, break loop check next
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// check insidePoint3
|
||
|
|
for (auto &p : insidePoint3)
|
||
|
|
{
|
||
|
|
if (ret | pointFaultTagValue(pifMatrixPtr, i, j, p, true))
|
||
|
|
{
|
||
|
|
// already have been setup, skip and continue
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto x2 = xMinMax_.first + (i + p.first) * dxSize_;
|
||
|
|
auto y2 = yMinMax_.first + (j + p.second) * dySize_;
|
||
|
|
ais::Point p2{x2, y2};
|
||
|
|
|
||
|
|
for (auto mi = 0; mi < m - 1; mi++)
|
||
|
|
if (line_cross(p1, p2, fps[mi], fps[((mi + 1) % m)]))
|
||
|
|
{
|
||
|
|
ret |= pointFaultTagValue(pifMatrixPtr, i, j, p, true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
};
|
||
|
|
|
||
|
|
// build up pointInFaultMatrixPtr_
|
||
|
|
for (size_t j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
// 0 means the point not effected by fault
|
||
|
|
long tempZ = 0;
|
||
|
|
|
||
|
|
// check center point first
|
||
|
|
tempZ |= pointFaultTagValue(faultAffectMatrixPtr, i, j, {0, 0});
|
||
|
|
if (tempZ > 0)
|
||
|
|
{
|
||
|
|
// central point in the fault, break fault loop to flag it and check next point
|
||
|
|
pointInFaultMatrixPtr->put(j, i, double(tempZ));
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 1. for node points in fault polygon
|
||
|
|
for (auto &p : insidePoint1)
|
||
|
|
{
|
||
|
|
// check inner point, if in polygon, flag it and it's expanded point
|
||
|
|
auto pValue = pointFaultTagValue(faultAffectMatrixPtr, i, j, p);
|
||
|
|
if (pValue > 0)
|
||
|
|
{
|
||
|
|
tempZ |= pValue;
|
||
|
|
if (p.first != 0)
|
||
|
|
{
|
||
|
|
auto newX = p.first > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (p.second + 2) * 5 + (newX + 2);
|
||
|
|
tempZ |= 1 << pExtPos;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
auto newY = p.second > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (newY + 2) * 5 + (p.first + 2);
|
||
|
|
tempZ |= 1 << pExtPos;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// if (j == 470 && i == 495)
|
||
|
|
//{
|
||
|
|
// std::cerr << "After pass point1 Point(470, 495): " << tempZ << std::endl;
|
||
|
|
// }
|
||
|
|
|
||
|
|
for (auto &p : insidePoint2)
|
||
|
|
{
|
||
|
|
// check inner point, if in polygon, flag it and it's expanded point
|
||
|
|
auto pValue = pointFaultTagValue(faultAffectMatrixPtr, i, j, p);
|
||
|
|
if (pValue > 0)
|
||
|
|
{
|
||
|
|
tempZ |= pValue;
|
||
|
|
|
||
|
|
auto newX = p.first > 0 ? 2 : -2;
|
||
|
|
auto newY = p.second > 0 ? 2 : -2;
|
||
|
|
auto pExtPos = (newY + 2) * 5 + (newX + 2);
|
||
|
|
tempZ |= 1 << pExtPos;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (j == 470 && i == 495)
|
||
|
|
{
|
||
|
|
std::cerr << "After pass point2 Point(470, 495): " << tempZ << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
for (auto &p : insidePoint3)
|
||
|
|
{
|
||
|
|
tempZ |= pointFaultTagValue(faultAffectMatrixPtr, i, j, p);
|
||
|
|
}
|
||
|
|
if (j == 470 && i == 495)
|
||
|
|
{
|
||
|
|
std::cerr << "After pass point3 Point(470, 495): " << tempZ << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. for fault line cross block but not on the point
|
||
|
|
for (auto &fault : faults_)
|
||
|
|
{
|
||
|
|
tempZ |= pointFaultAffectValue(faultAffectMatrixPtr, i, j, fault);
|
||
|
|
}
|
||
|
|
if (j == 470 && i == 495)
|
||
|
|
{
|
||
|
|
std::cerr << "After pass line cross check Point(470, 495): " << tempZ << std::endl;
|
||
|
|
}
|
||
|
|
|
||
|
|
// finally put the point fault effect to the matrix
|
||
|
|
pointInFaultMatrixPtr->put(j, i, double(tempZ));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::start_interpolation(std::shared_ptr<ais::FMatrix> &targetMatrixPtr, std::shared_ptr<ais::PMatrix> &constrainMatrixPtr,
|
||
|
|
std::shared_ptr<ais::FMatrix> &pointInFaultMatrixPtr, std::shared_ptr<ais::FMatrix> &faultAffectMatrixPtr,
|
||
|
|
InterpolationMethod method)
|
||
|
|
{
|
||
|
|
if (method != InterpolationMethod::MINIMUM_CURVATURE)
|
||
|
|
THROW_INVALID_ARGUMENT("Only support minimum curvature interpolations method right now.");
|
||
|
|
|
||
|
|
startTime_ = std::chrono::system_clock::now();
|
||
|
|
|
||
|
|
// setup running flag
|
||
|
|
flagRunning_ = true;
|
||
|
|
|
||
|
|
// selected interpolation method to start working thread
|
||
|
|
update_min_curv_interpolation(targetMatrixPtr, constrainMatrixPtr, pointInFaultMatrixPtr, faultAffectMatrixPtr);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool GridInterpolator::update_min_curv_interpolation(std::shared_ptr<ais::FMatrix> &targetMatrixPtr, std::shared_ptr<ais::PMatrix> &constrainMatrixPtr,
|
||
|
|
std::shared_ptr<ais::FMatrix> &pointInFaultMatrixPtr, std::shared_ptr<ais::FMatrix> &faultAffectMatrixPtr,
|
||
|
|
const std::vector<ais::Point> &targetArea)
|
||
|
|
{
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
interpolationMsgs_.push_back(ais::time_str() + " Start interpolations:");
|
||
|
|
interpolationMsgs_.push_back("=======================================");
|
||
|
|
}
|
||
|
|
|
||
|
|
// build a expansion matrix for minimum curvature interpolation
|
||
|
|
// due to the principle of minimum curvature interpolation,
|
||
|
|
// we need to expand 2 additional points on each edge of the target matrix
|
||
|
|
// PS: all matrix object in this function should alloc in heap, due the matrix is very big
|
||
|
|
auto shape = targetMatrixPtr->shape();
|
||
|
|
auto updateMatrixPtr = std::make_shared<ais::FMatrix>(shape.rows + 4, shape.cols + 4);
|
||
|
|
updateMatrixPtr->emptys();
|
||
|
|
|
||
|
|
// build a interpolation params matrix
|
||
|
|
auto interpolationParamsPtr = std::make_shared<ais::Matrix<ais::MCI_APoints>>(shape);
|
||
|
|
interpolationParamsPtr->emptys();
|
||
|
|
|
||
|
|
auto sPtr = std::make_shared<ais::FMatrix>(shape);
|
||
|
|
auto tPtr = std::make_shared<ais::FMatrix>(shape);
|
||
|
|
sPtr->zeros();
|
||
|
|
tPtr->zeros();
|
||
|
|
|
||
|
|
// origin matrix reference for share_ptr<ais::Matrix>
|
||
|
|
auto &umo = *updateMatrixPtr;
|
||
|
|
|
||
|
|
auto &cmp = *constrainMatrixPtr;
|
||
|
|
|
||
|
|
// calc interpolation alpha
|
||
|
|
double alpha0 = -1.0 / (6 + 8 * alpha_ * alpha_ + 6 * (std::pow(alpha_, 4)));
|
||
|
|
double alpha1 = std::pow(alpha_, 4);
|
||
|
|
double alpha2 = 2 * (alpha_ * alpha_);
|
||
|
|
double alpha3 = -4 * (1 + alpha_ * alpha_);
|
||
|
|
double alpha4 = -4 * (1 + alpha_ * alpha_) * alpha_ * alpha_;
|
||
|
|
double alpha5 = -2 * (1 + alpha_ * alpha_);
|
||
|
|
double alpha6 = -2 * (1 + alpha_ * alpha_) * alpha_ * alpha_;
|
||
|
|
|
||
|
|
double beta1 = 2 * std::pow((1 + alpha_ * alpha_), 2);
|
||
|
|
double beta2 = (1 + std::pow(alpha_, 4));
|
||
|
|
|
||
|
|
// loop constraint matrix to get the interpolated params
|
||
|
|
for (int j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
auto cp = cmp(j, i);
|
||
|
|
if (!ais::isnan(cp))
|
||
|
|
{
|
||
|
|
sPtr->at(j, i) = cp.x > 0 ? 1 : -1;
|
||
|
|
tPtr->at(j, i) = cp.y > 0 ? 1 : -1;
|
||
|
|
|
||
|
|
ais::PointXYZ up{std::abs(cp.x / dxSize_), std::abs(cp.y / dySize_), cp.z};
|
||
|
|
constrainMatrixPtr->put(j, i, up);
|
||
|
|
|
||
|
|
double denominator = beta2 * (up.x + up.y) * (1 + up.x + up.y) +
|
||
|
|
beta1 * (up.x * up.y + up.x + up.y + 1);
|
||
|
|
denominator *= 2.0;
|
||
|
|
|
||
|
|
double a0 = -(up.x + up.y) * (1 + up.x + up.y) / denominator;
|
||
|
|
double a1 = beta1 * up.x * (1 + up.x + 2 * up.y) / denominator;
|
||
|
|
double a2 = -2 * beta1 * up.x * (up.x + up.y) / denominator;
|
||
|
|
double a3 = -2 * beta1 * up.y * (up.x + up.y) / denominator;
|
||
|
|
double a4 = -beta1 * up.x * (1 + up.x) / denominator;
|
||
|
|
double a5 = 2 * beta1 / denominator;
|
||
|
|
|
||
|
|
interpolationParamsPtr->put(j, i, {a0, a1, a2, a3, a4, a5});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// copy original data to expected matrix for interpolation
|
||
|
|
for (int j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
auto zValue = targetMatrixPtr->at(j, i);
|
||
|
|
umo(j + 2, i + 2) = zValue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// setup the starting values for interpolation
|
||
|
|
double epsError = std::abs(epsMax_) * 2;
|
||
|
|
iteration_ = 0;
|
||
|
|
|
||
|
|
// setup the thread start row index vector
|
||
|
|
std::list<size_t> threadRowIndex;
|
||
|
|
auto threadRowStep = 6;
|
||
|
|
for (size_t tri = 0; tri < shape.rows; tri += threadRowStep)
|
||
|
|
{
|
||
|
|
threadRowIndex.push_back(tri);
|
||
|
|
}
|
||
|
|
|
||
|
|
auto copy_to_target_matrix = [&](const ais::FMatrix &source)
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(dataMutex_);
|
||
|
|
|
||
|
|
// copy interpolation value to target matrix
|
||
|
|
for (int j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (int i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
targetMatrixPtr->at(j, i) = source(j + 2, i + 2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
// thread function
|
||
|
|
std::function<double(size_t, size_t, const ais::Shape &)> iterationWorker = [&umo, &cmp, &interpolationParamsPtr,
|
||
|
|
&sPtr, &tPtr, this,
|
||
|
|
&alpha0, &alpha1, &alpha2, &alpha3,
|
||
|
|
&alpha4, &alpha5, &alpha6](size_t rowStart, size_t step, const ais::Shape &shape)
|
||
|
|
{
|
||
|
|
size_t rowEnd = rowStart + step > shape.rows ? shape.rows : rowStart + step;
|
||
|
|
|
||
|
|
double epsErrorInThread = 0.0;
|
||
|
|
|
||
|
|
for (size_t j = rowStart; j < rowEnd; j++)
|
||
|
|
{
|
||
|
|
for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
auto ui = i + 2;
|
||
|
|
auto uj = j + 2;
|
||
|
|
auto cp = cmp(j, i);
|
||
|
|
double temp = 0;
|
||
|
|
|
||
|
|
if (_LIKELY(std::isnan(cp.z)))
|
||
|
|
{
|
||
|
|
// WITHOUT constrain point
|
||
|
|
temp = (umo(uj, ui + 2) + umo(uj, ui - 2)) +
|
||
|
|
alpha1 * (umo(uj + 2, ui) + umo(uj - 2, ui)) +
|
||
|
|
alpha2 * (umo(uj + 1, ui + 1) + umo(uj + 1, ui - 1) + umo(uj - 1, ui + 1) + umo(uj - 1, ui - 1)) +
|
||
|
|
alpha3 * (umo(uj, ui + 1) + umo(uj, ui - 1)) +
|
||
|
|
alpha4 * (umo(uj + 1, ui) + umo(uj - 1, ui));
|
||
|
|
temp *= alpha0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// with constrain point
|
||
|
|
auto ias = interpolationParamsPtr->at(j, i);
|
||
|
|
auto s = sPtr->at(j, i);
|
||
|
|
auto t = tPtr->at(j, i);
|
||
|
|
|
||
|
|
temp = (umo(uj, ui + 2) + umo(uj, ui - 2)) +
|
||
|
|
alpha1 * (umo(uj + 2, ui) + umo(uj - 2, ui)) +
|
||
|
|
alpha2 * (umo(uj + 1, ui + 1) + umo(uj + 1, ui - 1) + umo(uj - 1, ui + 1) + umo(uj - 1, ui - 1)) +
|
||
|
|
alpha5 * (umo(uj, ui + 1) + umo(uj, ui - 1)) + alpha6 * (umo(uj + 1, ui) + umo(uj - 1, ui));
|
||
|
|
temp *= ias[0];
|
||
|
|
temp += ias[0] * alpha5 * (-umo(uj + t, ui - s) + 2 * umo(uj, ui - s) + alpha2 * umo(uj - t, ui) + umo(uj - t, ui + s)) +
|
||
|
|
ias[1] * umo(uj + t, ui - s) + ias[2] * umo(uj, ui - s) +
|
||
|
|
ias[3] * umo(uj - t, ui) + ias[4] * umo(uj - t, ui + s) +
|
||
|
|
ias[5] * cp.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
// over relaxation adjustments
|
||
|
|
temp = temp * 1.4 - 0.4 * umo(uj, ui);
|
||
|
|
|
||
|
|
epsErrorInThread = std::max(std::abs(temp - umo(uj, ui)), epsErrorInThread);
|
||
|
|
{
|
||
|
|
umo(uj, ui) = temp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return epsErrorInThread;
|
||
|
|
};
|
||
|
|
|
||
|
|
// thread function with fault
|
||
|
|
std::function<double(size_t, size_t, const ais::Shape &)> iterationFaultWorker = [&umo, &cmp, &interpolationParamsPtr,
|
||
|
|
&sPtr, &tPtr, this,
|
||
|
|
&alpha0, &alpha1, &alpha2, &alpha3,
|
||
|
|
&alpha4, &alpha5, &alpha6](size_t rowStart, size_t step, const ais::Shape &shape)
|
||
|
|
{
|
||
|
|
size_t rowEnd = rowStart + step > shape.rows ? shape.rows : rowStart + step;
|
||
|
|
|
||
|
|
double epsErrorInThread = 0.0;
|
||
|
|
|
||
|
|
for (size_t j = rowStart; j < rowEnd; j++)
|
||
|
|
{
|
||
|
|
for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
auto ui = i + 2;
|
||
|
|
auto uj = j + 2;
|
||
|
|
auto cp = cmp(j, i);
|
||
|
|
|
||
|
|
// check fault condition
|
||
|
|
long fpz = long(pointInFaultMatrixPtr_->at(j, i));
|
||
|
|
|
||
|
|
double temp = 0.0;
|
||
|
|
|
||
|
|
if (fpz > 0)
|
||
|
|
{
|
||
|
|
// fault inspected node, build the block data for iteration
|
||
|
|
|
||
|
|
// copy umo data to a block
|
||
|
|
ais::GridInterpolatorBlock blockData(umo, uj, ui);
|
||
|
|
auto pos = umo.index(uj, ui);
|
||
|
|
|
||
|
|
// use pre-iter block if existed
|
||
|
|
ais::GridInterpolatorBlock<> blockIter(fillValue_);
|
||
|
|
ais::GridInterpolatorBlock<> &block = blockIter;
|
||
|
|
|
||
|
|
if (faultEdgePointExpandBoxes_.find(pos) != faultEdgePointExpandBoxes_.cend())
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(mapMutex_);
|
||
|
|
block = faultEdgePointExpandBoxes_[pos];
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// make init values for block
|
||
|
|
for (int index = 0; index < 25; index++)
|
||
|
|
{
|
||
|
|
if (fpz & (1 << index))
|
||
|
|
{
|
||
|
|
// build init value for block nodes
|
||
|
|
block[index] = blockData.mock_value9(fpz, index, alpha_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// if(j == 470 && i == 495)
|
||
|
|
//{
|
||
|
|
// std::cerr << "-----------------------------------------" << std::endl;
|
||
|
|
// std::cerr << "Point: " << pos << " Mask: " << fpz << std::endl;
|
||
|
|
// block.print();
|
||
|
|
// std::cerr << "-----------------------------------------" << std::endl;
|
||
|
|
// }
|
||
|
|
}
|
||
|
|
|
||
|
|
// Due to the fault mock value based on the pre-data value, so split this operations into 2 loop, don't merge them
|
||
|
|
// 1. copy pre-data to block
|
||
|
|
for (int index = 0; index < 25; index++)
|
||
|
|
{
|
||
|
|
if ((fpz & (1 << index)) == 0)
|
||
|
|
{
|
||
|
|
// copy non-fault value from origin data
|
||
|
|
block[index] = blockData[index];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (j == 470 && i == 495 && iteration_ < 100)
|
||
|
|
{
|
||
|
|
std::cerr << "--------------Before Mock-------------" << std::endl;
|
||
|
|
std::cerr << "Point: " << pos << " Mask: " << fpz << " Iteration: " << iteration_ << std::endl;
|
||
|
|
block.print();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 2. mock fault inspect node in block
|
||
|
|
if (faultEdgePointExpandBoxes_.find(pos) != faultEdgePointExpandBoxes_.cend())
|
||
|
|
{
|
||
|
|
for (int index = 0; index < 25; index++)
|
||
|
|
{
|
||
|
|
if (fpz & (1 << index))
|
||
|
|
{
|
||
|
|
// block[index] = block.mock_value(fpz);
|
||
|
|
block[index] = block.mock_value4(fpz, index);
|
||
|
|
// block[index] = block.mock_value10(fpz, index, alpha_);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (j == 470 && i == 495 && iteration_ < 100)
|
||
|
|
{
|
||
|
|
std::cerr << "--------------After Mock-------------" << std::endl;
|
||
|
|
std::cerr << "Point: " << pos << " Mask: " << fpz << " Iteration: " << iteration_ << std::endl;
|
||
|
|
block.print();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// storage the block to map, for next iteration
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(mapMutex_);
|
||
|
|
faultEdgePointExpandBoxes_[pos] = block;
|
||
|
|
}
|
||
|
|
// use data block to calculate node value
|
||
|
|
if (std::isnan(cp.z))
|
||
|
|
{
|
||
|
|
// WITHOUT constrain point
|
||
|
|
temp = (block(0, 2) + block(0, -2)) +
|
||
|
|
alpha1 * (block(2, 0) + block(-2, 0)) +
|
||
|
|
alpha2 * (block(1, 1) + block(1, -1) + block(-1, 1) + block(-1, -1)) +
|
||
|
|
alpha3 * (block(0, 1) + block(0, -1)) +
|
||
|
|
alpha4 * (block(1, 0) + block(-1, 0));
|
||
|
|
temp *= alpha0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// with constrain point
|
||
|
|
auto ias = interpolationParamsPtr->at(j, i);
|
||
|
|
auto s = sPtr->at(j, i);
|
||
|
|
auto t = tPtr->at(j, i);
|
||
|
|
|
||
|
|
temp = (block(0, 2) + block(0, -2));
|
||
|
|
temp += alpha1 * (block(2, 0) + block(-2, 0));
|
||
|
|
temp += alpha2 * (block(1, 1) + block(1, -1) + block(-1, 1) + block(-1, -1));
|
||
|
|
temp += alpha5 * (block(0, 1) + block(0, -1));
|
||
|
|
temp += alpha6 * (block(1, 0) + block(-1, 0));
|
||
|
|
temp *= ias[0];
|
||
|
|
temp += ias[0] * alpha5 * (-block(t, -s) + 2 * block(0, -s) + alpha2 * block(-t, 0) + block(-t, s));
|
||
|
|
temp += ias[1] * block(t, -s) + ias[2] * block(0, -s) + ias[3] * block(-t, 0) + ias[4] * block(-t, s) + ias[5] * cp.z;
|
||
|
|
}
|
||
|
|
|
||
|
|
// flash in-fault (0,0) point in map for next iteration
|
||
|
|
if (fpz & (1 << 12))
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(mapMutex_);
|
||
|
|
faultEdgePointExpandBoxes_[pos][12] = temp * 1.4 - 0.4 * umo(uj, ui);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// normal node
|
||
|
|
if (std::isnan(cp.z))
|
||
|
|
{
|
||
|
|
// WITHOUT constrain point
|
||
|
|
temp = (umo(uj, ui + 2) + umo(uj, ui - 2)) +
|
||
|
|
alpha1 * (umo(uj + 2, ui) + umo(uj - 2, ui)) +
|
||
|
|
alpha2 * (umo(uj + 1, ui + 1) + umo(uj + 1, ui - 1) + umo(uj - 1, ui + 1) + umo(uj - 1, ui - 1)) +
|
||
|
|
alpha3 * (umo(uj, ui + 1) + umo(uj, ui - 1)) +
|
||
|
|
alpha4 * (umo(uj + 1, ui) + umo(uj - 1, ui));
|
||
|
|
temp *= alpha0;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// with constrain point
|
||
|
|
auto ias = interpolationParamsPtr->at(j, i);
|
||
|
|
auto s = sPtr->at(j, i);
|
||
|
|
auto t = tPtr->at(j, i);
|
||
|
|
|
||
|
|
temp = (umo(uj, ui + 2) + umo(uj, ui - 2)) +
|
||
|
|
alpha1 * (umo(uj + 2, ui) + umo(uj - 2, ui)) +
|
||
|
|
alpha2 * (umo(uj + 1, ui + 1) + umo(uj + 1, ui - 1) + umo(uj - 1, ui + 1) + umo(uj - 1, ui - 1)) +
|
||
|
|
alpha5 * (umo(uj, ui + 1) + umo(uj, ui - 1)) + alpha6 * (umo(uj + 1, ui) + umo(uj - 1, ui));
|
||
|
|
temp *= ias[0];
|
||
|
|
temp += ias[0] * alpha5 * (-umo(uj + t, ui - s) + 2 * umo(uj, ui - s) + alpha2 * umo(uj - t, ui) + umo(uj - t, ui + s)) +
|
||
|
|
ias[1] * umo(uj + t, ui - s) + ias[2] * umo(uj, ui - s) +
|
||
|
|
ias[3] * umo(uj - t, ui) + ias[4] * umo(uj - t, ui + s) +
|
||
|
|
ias[5] * cp.z;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// over relaxation adjustments
|
||
|
|
temp = temp * 1.4 - 0.4 * umo(uj, ui);
|
||
|
|
|
||
|
|
epsErrorInThread = std::max(std::abs(temp - umo(uj, ui)), epsErrorInThread);
|
||
|
|
{
|
||
|
|
umo(uj, ui) = temp;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return epsErrorInThread;
|
||
|
|
};
|
||
|
|
|
||
|
|
// dump init value
|
||
|
|
{
|
||
|
|
|
||
|
|
// copy middle iteration result to target
|
||
|
|
copy_to_target_matrix(umo);
|
||
|
|
|
||
|
|
// update zMin and zMax
|
||
|
|
zMinMax_ = getMinMax(*targetMatrixPtr);
|
||
|
|
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
std::string msg = "Iterating: " + std::to_string(iteration_);
|
||
|
|
interpolationMsgs_.push_back(msg);
|
||
|
|
|
||
|
|
//auto ret = std::async(std::launch::async, [&]()
|
||
|
|
// { std::string filename = "init_0.grd";
|
||
|
|
//dump_result(filename.c_str());
|
||
|
|
//return; });
|
||
|
|
}
|
||
|
|
|
||
|
|
// main interpolation loop
|
||
|
|
while (epsError > epsMax_ && iteration_ < maxIteration_ && flagRunning_)
|
||
|
|
{
|
||
|
|
epsError = 0.0;
|
||
|
|
update_min_curv_boundary(updateMatrixPtr, shape.cols, shape.rows, alpha_);
|
||
|
|
|
||
|
|
// dump updated boundary value
|
||
|
|
if (iteration_ == 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
// copy middle iteration result to target
|
||
|
|
copy_to_target_matrix(umo);
|
||
|
|
|
||
|
|
// update zMin and zMax
|
||
|
|
zMinMax_ = getMinMax(*targetMatrixPtr);
|
||
|
|
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
std::string msg = "Iterating: " + std::to_string(iteration_);
|
||
|
|
interpolationMsgs_.push_back(msg);
|
||
|
|
|
||
|
|
//auto ret = std::async(std::launch::async, [&]()
|
||
|
|
// { std::string filename = "updated_edge_0.grd";
|
||
|
|
//dump_result(filename.c_str());
|
||
|
|
//return; });
|
||
|
|
}
|
||
|
|
|
||
|
|
if (flagMultiThread_)
|
||
|
|
{
|
||
|
|
// ********* multi-thread *********
|
||
|
|
std::list<size_t> rowIndex = threadRowIndex;
|
||
|
|
std::vector<double> threadEpsErrors;
|
||
|
|
std::vector<std::future<double>> epsFutures;
|
||
|
|
|
||
|
|
// start threads
|
||
|
|
while (!rowIndex.empty())
|
||
|
|
{
|
||
|
|
size_t rowStart = rowIndex.front();
|
||
|
|
rowIndex.pop_front();
|
||
|
|
|
||
|
|
if (faults_.empty())
|
||
|
|
{
|
||
|
|
epsFutures.emplace_back(std::async(std::launch::async, iterationWorker, rowStart, threadRowStep, shape));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
epsFutures.emplace_back(std::async(std::launch::async, iterationFaultWorker, rowStart, threadRowStep, shape));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// waiting for results
|
||
|
|
for (auto &ef : epsFutures)
|
||
|
|
{
|
||
|
|
ef.wait();
|
||
|
|
threadEpsErrors.push_back(ef.get());
|
||
|
|
}
|
||
|
|
|
||
|
|
epsError = *std::max_element(std::execution::par_unseq, threadEpsErrors.begin(), threadEpsErrors.end());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// ********* 1 thread async iterative *********
|
||
|
|
// auto worker = std::async(std::launch::async, iterationWorker, 0, shape.rows, shape);
|
||
|
|
// worker.wait();
|
||
|
|
// epsError = worker.get();
|
||
|
|
|
||
|
|
// ********* main thread sync iterative *********
|
||
|
|
|
||
|
|
if (faults_.empty())
|
||
|
|
{
|
||
|
|
epsError = iterationWorker(0, shape.rows, shape);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
epsError = iterationFaultWorker(0, shape.rows, shape);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// dump progress while every 100 iteration
|
||
|
|
if (iteration_ % 100 == 0)
|
||
|
|
{
|
||
|
|
|
||
|
|
// copy middle iteration result to target
|
||
|
|
copy_to_target_matrix(umo);
|
||
|
|
|
||
|
|
// update zMin and zMax
|
||
|
|
zMinMax_ = getMinMax(*targetMatrixPtr);
|
||
|
|
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
std::string msg = "Iterating: " + std::to_string(iteration_);
|
||
|
|
interpolationMsgs_.push_back(msg);
|
||
|
|
|
||
|
|
//auto ret = std::async(std::launch::async, [&]()
|
||
|
|
std::string filename = "progress_" + std::to_string(iteration_) + ".grd";
|
||
|
|
int8_t level = iteration_ % 1000 == 0 ? 1 : 2;
|
||
|
|
//dump_result_async(filename, targetMatrixPtr_, level);
|
||
|
|
}
|
||
|
|
|
||
|
|
iteration_++;
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
std::lock_guard<std::mutex> lk(msgMutex_);
|
||
|
|
interpolationMsgs_.push_back("=======================================");
|
||
|
|
interpolationMsgs_.push_back(ais::time_str() + " Completed interpolations:\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
// copy to target and update zMin and zMax
|
||
|
|
copy_to_target_matrix(umo);
|
||
|
|
zMinMax_ = getMinMax(*targetMatrixPtr);
|
||
|
|
|
||
|
|
// setup fault point, due to the surfer will not set points to infinity, not sure this behavior make reasonable
|
||
|
|
if (!faults_.empty() && faultEdgeLevel_ >= 0)
|
||
|
|
{
|
||
|
|
int faultEdgeLimitation = 1 << faultEdgeLevel_;
|
||
|
|
|
||
|
|
for (size_t j = 0; j < shape.rows; j++)
|
||
|
|
{
|
||
|
|
for (size_t i = 0; i < shape.cols; i++)
|
||
|
|
{
|
||
|
|
auto pointInFault = faultAffectMatrixPtr_->at(j + 2, i + 2);
|
||
|
|
if (pointInFault >= faultEdgeLimitation)
|
||
|
|
{
|
||
|
|
targetMatrixPtr->put(j, i, INFINITY);
|
||
|
|
faultNodesCount_++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
endTime_ = std::chrono::system_clock::now();
|
||
|
|
|
||
|
|
// std::cout << "------------------End of min curv interpolation-----------------" << std::endl;
|
||
|
|
// std::cout << data_info();
|
||
|
|
|
||
|
|
// release unused memory
|
||
|
|
updateMatrixPtr.reset();
|
||
|
|
interpolationParamsPtr.reset();
|
||
|
|
pointInFaultMatrixPtr_.reset();
|
||
|
|
faultAffectMatrixPtr_.reset();
|
||
|
|
sPtr.reset();
|
||
|
|
tPtr.reset();
|
||
|
|
|
||
|
|
flagSucceed_ = (iteration_ < maxIteration_);
|
||
|
|
return flagSucceed_;
|
||
|
|
}
|
||
|
|
|
||
|
|
void GridInterpolator::update_min_curv_boundary(std::shared_ptr<ais::FMatrix> &updateMatrixPtr, size_t column, size_t row, double alpha)
|
||
|
|
{
|
||
|
|
// updateMatrixPtr are extened matrix, [0:x+3, 0:y+3],
|
||
|
|
// extened 2 point at each side of the matrix
|
||
|
|
//
|
||
|
|
// e, e, e, e, ~, e, e, e, e | y+3
|
||
|
|
// e, i, i, i, ~ ,i ,i, i, e | y+2
|
||
|
|
// e ,i ,0 ,0, ~, 0 ,0, i, e | y+1
|
||
|
|
// e ,i ,0 ,0, ~, 0 ,0, i, e | y
|
||
|
|
// ... ... |
|
||
|
|
// e, i, 0, 0, ~, 0, 0, i, e | 2
|
||
|
|
// e, i, i, i, ~, i, i, i, e | 1
|
||
|
|
// e, e, e, e, ~, e, e, e, e | 0
|
||
|
|
// ----------------------------+
|
||
|
|
// 0 1 2 3 ~ x x+1 x+2 x+3
|
||
|
|
|
||
|
|
// std::cout << "--------------------Update min curv boundary--------------------" << std::endl;
|
||
|
|
// updateMatrixPtr->print();
|
||
|
|
// std::cout << "----------------------------------------------------------------" << std::endl;
|
||
|
|
|
||
|
|
auto &ump = *updateMatrixPtr;
|
||
|
|
|
||
|
|
auto up_shape = ump.shape();
|
||
|
|
if (up_shape.rows != (row + 4) || up_shape.cols != (column + 4))
|
||
|
|
{
|
||
|
|
THROW_INVALID_ARGUMENT("Extended matrix values not matching");
|
||
|
|
}
|
||
|
|
|
||
|
|
auto ej = row + 2; // extened matrix j for y axis
|
||
|
|
auto ei = column + 2; // extened matrix i for x axis
|
||
|
|
|
||
|
|
// points at left&right side of extended boundary
|
||
|
|
for (size_t j = 0; j < row; j++)
|
||
|
|
{
|
||
|
|
auto uj = j + 2;
|
||
|
|
auto ui = ei;
|
||
|
|
ump(uj, 1) = 2 * ump(uj, 2) - ump(uj, 3); // left
|
||
|
|
ump(uj, ui) = 2 * ump(uj, ui - 1) - ump(uj, ui - 2); // right
|
||
|
|
}
|
||
|
|
|
||
|
|
// points at down&top side of extended boundary
|
||
|
|
for (size_t i = 0; i <= column; i++)
|
||
|
|
{
|
||
|
|
auto uj = ej;
|
||
|
|
auto ui = i + 2;
|
||
|
|
ump(1, ui) = 2 * ump(2, ui) - ump(3, ui); // bottom
|
||
|
|
ump(uj, ui) = 2 * ump(uj - 1, ui) - ump(uj - 2, ui); // top
|
||
|
|
}
|
||
|
|
|
||
|
|
// points at corners
|
||
|
|
ump(1, 1) = ump(1, 3) + ump(3, 1) - ump(3, 3); // left-down
|
||
|
|
ump(1, ei) = ump(3, ei) + ump(1, ei - 2) - ump(3, ei - 2); // right-down
|
||
|
|
ump(ej, 1) = ump(ej, 3) + ump(ej - 2, 1) - ump(ej - 2, 3); // left-top
|
||
|
|
ump(ej, ei) = ump(ej - 2, ei) + ump(ej, ei - 2) - ump(ej - 2, ei - 2); // right-top
|
||
|
|
|
||
|
|
// exterior extension points
|
||
|
|
double alpha1 = alpha * alpha;
|
||
|
|
double alpha2 = -2 * (1 + alpha1);
|
||
|
|
|
||
|
|
double beta = 1 / alpha;
|
||
|
|
double beta1 = beta * beta;
|
||
|
|
double beta2 = -2 * (1 + beta1);
|
||
|
|
|
||
|
|
for (size_t j = 0; j < row; j++)
|
||
|
|
{
|
||
|
|
auto uj = j + 2;
|
||
|
|
auto p_ij = [&](size_t i)
|
||
|
|
{
|
||
|
|
auto a1 = alpha1 * (ump(uj + 1, i + 1) - ump(uj + 1, i - 1) + ump(uj - 1, i + 1) - ump(uj - 1, i - 1));
|
||
|
|
auto a2 = alpha2 * (ump(uj, i + 1) - ump(uj, i - 1));
|
||
|
|
return a1 + a2;
|
||
|
|
};
|
||
|
|
|
||
|
|
// left
|
||
|
|
ump(uj, 0) = ump(uj, 4) + p_ij(2);
|
||
|
|
// right
|
||
|
|
ump(uj, column + 3) = ump(uj, column - 1) - p_ij(column + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (size_t i = 0; i < column; i++)
|
||
|
|
{
|
||
|
|
auto ui = i + 2;
|
||
|
|
auto q_ij = [&](size_t j)
|
||
|
|
{
|
||
|
|
auto b1 = beta1 * (ump(j + 1, ui + 1) - ump(j - 1, ui + 1) + ump(j + 1, ui - 1) - ump(j - 1, ui - 1));
|
||
|
|
auto b2 = beta2 * (ump(j + 1, ui) - ump(j - 1, ui));
|
||
|
|
return b1 + b2;
|
||
|
|
};
|
||
|
|
|
||
|
|
// bottom
|
||
|
|
ump(0, ui) = ump(4, ui) + q_ij(2);
|
||
|
|
// top
|
||
|
|
ump(row + 3, ui) = ump(row - 1, ui) - q_ij(row + 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
// std::cout << "--------------------End of min curv boundary--------------------" << std::endl;
|
||
|
|
// updateMatrixPtr->print();
|
||
|
|
// std::cout << "----------------------------------------------------------------" << std::endl;
|
||
|
|
|
||
|
|
// std::cout << ump(79, 34) << std::endl;
|
||
|
|
// ais::GridInterpolatorBlock block(ump, 79, 34);
|
||
|
|
// block.print();
|
||
|
|
}
|
||
|
|
} // namespace ais
|