void build_sources_and_dests(const size_t num_sources_x, const size_t num_sources_y,
	const size_t num_dests_x, const size_t num_dests_y,
	const size_t ts_size, const shyft::timeseries::utctimespan dt,
	const point_timeaxis& time_axis, bool insert_nans, SourceList& sources, DestinationList& dests,bool randomize=false) {
	const double x_min = 0.0; // [m]
	const double x_max = 100000.0; // [m]
	const double y_min = 0.0; // [m]
	const double y_max = 1000000.0; // [m]

	sources.reserve(num_sources_x*num_sources_y);
	dests.reserve(num_dests_x*num_dests_y);
	geo_point pt;
	double lower_bound = 0.0;
	double upper_bound = 10.0;
	std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
	std::default_random_engine re;
    vector<utctime> times;times.reserve(ts_size);
    for (size_t l = 0; l < ts_size; ++l)
        times.emplace_back(l*dt);
    times.emplace_back(shyft::core::max_utctime);
    point_timeaxis dta(times);
    geo_point p0(x_min,y_min,0.0);
    const double max_distance=geo_point::xy_distance(p0,geo_point(x_max,y_max,0.0));
    auto base_temp=[&unif,&re,randomize,&p0,max_distance](geo_point p1)->double {
        if(randomize)
            return unif(re);
        return 10+ 2.0*geo_point::xy_distance(p0,p1)/max_distance;
    };
	for (size_t i = 0; i < num_sources_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_sources_x - 1);
		for (size_t j = 0; j < num_sources_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_sources_y - 1);
			pt.z = 500 * std::sin(pt.x / x_max) + std::sin(pt.y / y_max) / 2;
			vector<double> pts; pts.reserve(ts_size);
			double b_t = base_temp(pt);
			for (size_t l = 0; l < ts_size; ++l)
				pts.emplace_back( b_t + pt.z*(0.6 / 100));
			sources.emplace_back(pt, xpts_t(dta,pts));
		}
	}
	for (size_t i = 0; i < num_dests_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_dests_x - 1);
		for (size_t j = 0; j < num_dests_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_dests_y - 1);
			pt.z = 500 * (std::sin(pt.x / x_max) + std::sin(pt.y / y_max)) / 2;
			dests.emplace_back(pt, time_axis);
		}
	}
}
void build_sources_and_dests(const size_t num_sources_x, const size_t num_sources_y,
	const size_t num_dests_x, const size_t num_dests_y,
	const size_t ts_size, const shyft::timeseries::utctimespan dt,
	const point_timeaxis& time_axis, bool insert_nans, SourceList& sources, DestinationList& dests) {
	const double x_min = 0.0; // [m]
	const double x_max = 100000.0; // [m]
	const double y_min = 0.0; // [m]
	const double y_max = 1000000.0; // [m]

	sources.reserve(num_sources_x*num_sources_y);
	dests.reserve(num_dests_x*num_dests_y);
	geo_point pt;
	double lower_bound = 0.0;
	double upper_bound = 10.0;
	std::uniform_real_distribution<double> unif(lower_bound, upper_bound);
	std::default_random_engine re;
    vector<utctime> times;times.reserve(ts_size);
    for (size_t l = 0; l < ts_size; ++l)
        times.emplace_back(l*dt);
    times.emplace_back(shyft::core::max_utctime);
    point_timeaxis dta(times);
	for (size_t i = 0; i < num_sources_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_sources_x - 1);
		for (size_t j = 0; j < num_sources_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_sources_y - 1);
			pt.z = 500 * std::sin(pt.x / x_max) + std::sin(pt.y / y_max) / 2;
			vector<double> pts; pts.reserve(ts_size);
			double b_t = unif(re);
			//std::cout << "Base temp at pos (i,j) = " << i << ", " << j << ") = " << b_t << std::endl;
			for (size_t l = 0; l < ts_size; ++l)
				pts.emplace_back( b_t + pt.z*(0.6 / 100));
			sources.emplace_back(pt, xpts_t(dta,pts));
		}
	}
	for (size_t i = 0; i < num_dests_x; ++i) {
		pt.x = x_min + i*(x_max - x_min) / (num_dests_x - 1);
		for (size_t j = 0; j < num_dests_y; ++j) {
			pt.y = y_min + j*(y_max - y_min) / (num_dests_y - 1);
			pt.z = 500 * (std::sin(pt.x / x_max) + std::sin(pt.y / y_max)) / 2;
			dests.emplace_back(pt, time_axis);
		}
	}
}