Commit 165dc472 authored by ESTERIE Pierre's avatar ESTERIE Pierre
Browse files

Units for non homogenous fmm

parent 83579aec
......@@ -54,6 +54,8 @@
namespace scalfmm::interpolation
{
// uniform_interpolator is a CRTP based class
// meaning that it implements the functions needed by the interpolator class
template<typename ValueType, std::size_t Dimension, typename FarFieldMatrixKernel>
struct uniform_interpolator : public interpolator<uniform_interpolator<ValueType, Dimension, FarFieldMatrixKernel>>
{
......@@ -286,10 +288,12 @@ namespace scalfmm::interpolation
inline auto generate_interactions_matrixes_impl(value_type width, std::size_t tree_height) -> void
{
std::size_t number_of_level{1};
std::size_t number_of_interactions{this->m2l_interactions()};
const std::size_t number_of_interactions{this->m2l_interactions()};
// here width is the root width
// so first level of cell is of width because we skip level 0 (the root) and (the first level)):
value_type current_width{width};
const value_type half{0.5};
const value_type quarter{0.25};
// we get the half width to scale the roots
if constexpr (base_type::homogeneity_tag == matrix_kernels::homogeneity::non_homogenous)
......@@ -297,10 +301,10 @@ namespace scalfmm::interpolation
// (tree_heigh = 4 -> [0-3]) the bottom cells and leaves have the same symbolic level !
// but we remove level 0 (the root ie simulaton box) and level 1.
number_of_level = tree_height-2;
current_width = width*0.25;
current_width = width*quarter;
}
value_type half_width{current_width*0.5};
value_type half_width{current_width*half};
// we need to keep the tensorial view
// let the same view goes down to tensorial of point
// X and Y are Td tensors storing point.
......@@ -390,8 +394,8 @@ namespace scalfmm::interpolation
meta::looper_range<dimension>{}(generate_all_interactions, starts, stops);
// we divide the widths for the next tree level
current_width *= 0.5;
half_width *= 0.5;
current_width *= half;
half_width *= half;
}
}
......
// --------------------------------
// See LICENCE file at project root
// File : matrix_kernels/debug.hpp
// --------------------------------
#ifndef SCALFMM_MATRIX_KERNELS_DEBUG_HPP
#define SCALFMM_MATRIX_KERNELS_DEBUG_HPP
#include <array>
#include <cmath>
#include <limits>
#include <tuple>
#include <type_traits>
#include <utility>
#include <xtensor/xmath.hpp>
#include "scalfmm/meta/utils.hpp"
#include <scalfmm/container/point.hpp>
#include <scalfmm/matrix_kernels/mk_common.hpp>
#include <scalfmm/meta/utils.hpp>
#include <scalfmm/utils/math.hpp>
namespace scalfmm::matrix_kernels::debug
{
// This matrix kernel is here to debug the non homogenous case
struct one_over_r_non_homogenous
{
static constexpr auto homogeneity_tag{homogeneity::non_homogenous};
static constexpr std::size_t km{1};
static constexpr std::size_t kn{1};
template<typename ValueType>
[[nodiscard]] inline constexpr auto mutual_coefficient() const
{
return std::make_tuple(ValueType(1.));
}
template<typename ValueType, std::size_t Dim>
[[nodiscard]] inline auto evaluate(container::point<ValueType, Dim> const& x,
container::point<ValueType, Dim> const& y) const noexcept
{
return variadic_evaluate(x, y, std::make_index_sequence<Dim>{});
}
template<typename ValueType>
[[nodiscard]] inline auto scale_factor(ValueType cell_width) const noexcept
{
return std::make_tuple(ValueType(1.));
}
template<typename ValueType>
[[nodiscard]] inline auto scale_factor(ValueType cell_width, std::size_t tree_level) const noexcept
{
return scale_factor(cell_width / math::pow(ValueType(2.), tree_level));
}
template<typename ValueType, std::size_t Dim, std::size_t... Is>
[[nodiscard]] inline auto variadic_evaluate(container::point<ValueType, Dim> const& xs,
container::point<ValueType, Dim> const& ys,
std::index_sequence<Is...> is) const noexcept
{
using std::sqrt;
return std::make_tuple(ValueType(1.0) / sqrt((((xs.at(Is) - ys.at(Is)) * (xs.at(Is) - ys.at(Is))) + ...)));
}
const std::size_t separation_criterion{1};
};
}
#endif // SCALFMM_MATRIX_KERNELS_DEBUG_HPP
......@@ -71,6 +71,7 @@ namespace scalfmm::matrix_kernels::laplace
}
const std::size_t separation_criterion{1};
};
///////
/// \brief The like_mrhs simulates two FMMs with independent charges
///
......
......@@ -5,6 +5,7 @@
#ifndef SCALFMM_TREE_FOR_EACH_HPP
#define SCALFMM_TREE_FOR_EACH_HPP
#include <bits/c++config.h>
#include <functional>
#include <utility>
......@@ -39,6 +40,29 @@ namespace scalfmm::component
return f;
}
template<typename InputTreeIterator, typename BinaryFunction>
inline auto for_each_leaf(InputTreeIterator begin, InputTreeIterator end, InputTreeIterator begin2, BinaryFunction f) -> BinaryFunction
{
auto group_leaf_iterator_begin = std::get<0>(begin);
auto group_leaf_iterator_end = std::get<0>(end);
auto group_leaf_iterator_begin2 = std::get<0>(begin2);
for(; group_leaf_iterator_begin != group_leaf_iterator_end; ++group_leaf_iterator_begin)
{
auto begin_leaf = std::begin((*group_leaf_iterator_begin)->block());
auto begin_leaf2 = std::begin((*group_leaf_iterator_begin2)->block());
for(std::size_t i{0}; i<(*group_leaf_iterator_begin)->block().size(); ++i)
{
f(*begin_leaf, *begin_leaf2);
++begin_leaf;
++begin_leaf2;
}
++group_leaf_iterator_begin2;
}
return f;
}
template<typename InputTreeIterator, typename UnaryFunction>
inline auto for_each_cell(InputTreeIterator begin, InputTreeIterator end, std::size_t level, UnaryFunction f)
-> UnaryFunction
......
......@@ -8,6 +8,7 @@ set(source_tests_files
operators/l2p.cpp
fmm/test_dimension.cpp
fmm/count_kernel.cpp
fmm/test_non_homogenous.cpp
)
set(TEST_FILES_PATH ${CMAKE_SOURCE_DIR}/units/fmm/)
......@@ -47,36 +48,3 @@ endforeach(exec)
add_custom_target(units ALL DEPENDS ${SCALFMM_UNITS_TARGETS})
#if(SCALFMM_ONLY_DEVEL)
# set(source_check_files
# operators/interp.cpp
# operators/l2p.cpp
# )
# foreach(exec ${source_check_files})
# set(compile_exec TRUE)
# get_filename_component( execname ${exec} NAME_WE )
# foreach(fuse_key ${FUSE_DEP_AVAILABLE})
# file(STRINGS "${exec}" lines_fuse REGEX "@FUSE_${fuse_key}")
# if(lines_fuse AND NOT ${fuse_key} IN_LIST FUSE_LIST)
# message( STATUS "This needs ${fuse_key} = ${exec}" )
# set(compile_exec FALSE)
# endif()
# endforeach()
# # Dependency are OK
# if( compile_exec )
# add_executable( check.${execname} ${exec})
# set_target_properties(check.${execname} PROPERTIES
# RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BUILD_TYPE}
# )
# target_link_libraries( check.${execname} PRIVATE ${CMAKE_PROJECT_NAME})
# target_include_directories(check.${execname} PRIVATE ${CMAKE_SOURCE_DIR}/modules/external/catch2/)
# # list(APPEND SCALFMM_UNITS_TARGETS check.${execname})
# endif()
# endforeach(exec)
#endif(SCALFMM_ONLY_DEVEL)
......@@ -47,7 +47,6 @@ using namespace scalfmm;
template<int Dimension, typename CONTAINER_T, typename POINT_T, typename VALUE_T>
void read_data(const std::string& filename, CONTAINER_T*& container, POINT_T& Centre, VALUE_T& width)
{
// std::cout << "READ DATA " << std::endl << std::flush;
using particle_type = typename CONTAINER_T::particle_type;
scalfmm::tools::FFmaGenericLoader<VALUE_T, Dimension> loader(filename);
......@@ -55,14 +54,9 @@ void read_data(const std::string& filename, CONTAINER_T*& container, POINT_T& Ce
const int number_of_particles = loader.getNumberOfParticles();
width = loader.getBoxWidth();
Centre = loader.getBoxCenter();
// std::size_t i{0};
// for(auto& e: Centre)
// {
// e = Centre_3D[i++];
// }
auto nb_val_to_red_per_part = loader.getNbRecordPerline();
double* values_to_read = new double[nb_val_to_red_per_part]{0};
VALUE_T* values_to_read = new VALUE_T[nb_val_to_red_per_part]{0};
container = new CONTAINER_T(number_of_particles);
std::cout << "number_of_particles " << number_of_particles << std::endl;
for(std::size_t idx = 0; idx < number_of_particles; ++idx)
......@@ -104,10 +98,10 @@ auto inline check_results(const Tree_T& tree, const Container_T& reference, cons
return ok;
}
template<int Dimension, class FMM_OPERATOR_TYPE>
template<int Dimension, class FMM_OPERATOR_TYPE, typename TestType>
auto run(const std::string& input_file, const int& tree_height, const int& group_size, const int& order) -> int
{
using value_type = double;
using value_type = TestType;
using near_matrix_kernel_type = typename FMM_OPERATOR_TYPE::near_field_type::matrix_kernel_type;
using far_field_type = typename FMM_OPERATOR_TYPE::far_field_type;
using interpolator_type = typename far_field_type::approximation_type;
......@@ -207,10 +201,10 @@ TEMPLATE_TEST_CASE("test fmm", "[test-fmm]", double, float)
using matrix_kernel_type = scalfmm::matrix_kernels::others::one_over_r2;
using near_field_type = scalfmm::operators::near_field_operator<matrix_kernel_type>;
//
using interpolator_type = scalfmm::interpolation::uniform_interpolator<double, dim, matrix_kernel_type>;
using interpolator_type = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type>;
using far_field_type = scalfmm::operators::far_field_operator<interpolator_type>;
path.append("test_1d_ref.fma");
run<1, scalfmm::operators::fmm_operators<near_field_type, far_field_type>>(path, 4, 2,
run<dim, scalfmm::operators::fmm_operators<near_field_type, far_field_type>, value_type>(path, 4, 2,
5);
}
SECTION("fmm test 2D", "[fmm-test-2D]")
......@@ -220,10 +214,10 @@ TEMPLATE_TEST_CASE("test fmm", "[test-fmm]", double, float)
using matrix_kernel_type = scalfmm::matrix_kernels::others::one_over_r2;
using near_field_type = scalfmm::operators::near_field_operator<matrix_kernel_type>;
//
using interpolator_type = scalfmm::interpolation::uniform_interpolator<double, dim, matrix_kernel_type>;
using interpolator_type = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type>;
using far_field_type = scalfmm::operators::far_field_operator<interpolator_type>;
path.append("test_2d_ref.fma");
run<1, scalfmm::operators::fmm_operators<near_field_type, far_field_type>>(path, 4, 2,
run<dim, scalfmm::operators::fmm_operators<near_field_type, far_field_type>, value_type>(path, 4, 2,
5);
}
SECTION("fmm test 3D", "[fmm-test-3D]")
......@@ -233,10 +227,10 @@ TEMPLATE_TEST_CASE("test fmm", "[test-fmm]", double, float)
using matrix_kernel_type = scalfmm::matrix_kernels::others::one_over_r2;
using near_field_type = scalfmm::operators::near_field_operator<matrix_kernel_type>;
//
using interpolator_type = scalfmm::interpolation::uniform_interpolator<double, dim, matrix_kernel_type>;
using interpolator_type = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type>;
using far_field_type = scalfmm::operators::far_field_operator<interpolator_type>;
path.append("test_3d_ref.fma");
run<1, scalfmm::operators::fmm_operators<near_field_type, far_field_type>>(path, 4, 2,
run<dim, scalfmm::operators::fmm_operators<near_field_type, far_field_type>, value_type>(path, 4, 2,
5);
}
SECTION("fmm test 4D", "[fmm-test-4D]")
......@@ -246,10 +240,10 @@ TEMPLATE_TEST_CASE("test fmm", "[test-fmm]", double, float)
using matrix_kernel_type = scalfmm::matrix_kernels::others::one_over_r2;
using near_field_type = scalfmm::operators::near_field_operator<matrix_kernel_type>;
//
using interpolator_type = scalfmm::interpolation::uniform_interpolator<double, dim, matrix_kernel_type>;
using interpolator_type = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type>;
using far_field_type = scalfmm::operators::far_field_operator<interpolator_type>;
path.append("test_4d_ref.fma");
run<1, scalfmm::operators::fmm_operators<near_field_type, far_field_type>>(path, 4, 2,
run<dim, scalfmm::operators::fmm_operators<near_field_type, far_field_type>, value_type>(path, 4, 2,
5);
}
}
......
//
// Units for test fmm non homogenous
// ---------------------------------
#include "scalfmm/tree/for_each.hpp"
#include "units_fmm.hpp"
#include "scalfmm/algorithms/common.hpp"
#include "scalfmm/container/particle.hpp"
#include "scalfmm/container/particle_container.hpp"
#include "scalfmm/container/point.hpp"
#include "scalfmm/interpolation/uniform.hpp"
#include "scalfmm/operators/fmmOperators.hpp"
#include "scalfmm/matrix_kernels/debug.hpp"
#include "scalfmm/matrix_kernels/laplace.hpp"
#include "scalfmm/algorithms/sequential/sequential.hpp"
#include "scalfmm/tools/colorized.hpp"
#include "scalfmm/tree/box.hpp"
#include "scalfmm/tree/cell.hpp"
#include "scalfmm/tree/group_tree.hpp"
#include "scalfmm/tree/leaf.hpp"
#include "scalfmm/utils/sort.hpp"
#include "scalfmm/tools/fma_loader.hpp"
#include "scalfmm/utils/accurater.hpp"
#include "scalfmm/utils/timer.hpp"
#include <algorithm>
#include <array>
#include <bits/c++config.h>
#include <chrono>
#include <cstdio>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <thread>
#include <tuple>
#include <unistd.h>
#include <utility>
#include <vector>
#define CATCH_CONFIG_RUNNER
#include <catch2/catch.hpp>
using namespace scalfmm;
template<int Dimension, typename CONTAINER_T, typename POINT_T, typename VALUE_T>
void read_data(const std::string& filename, CONTAINER_T*& container, POINT_T& Centre, VALUE_T& width)
{
using particle_type = typename CONTAINER_T::particle_type;
scalfmm::tools::FFmaGenericLoader<VALUE_T, Dimension> loader(filename);
const int number_of_particles = loader.getNumberOfParticles();
width = loader.getBoxWidth();
Centre = loader.getBoxCenter();
auto nb_val_to_red_per_part = loader.getNbRecordPerline();
VALUE_T* values_to_read = new VALUE_T[nb_val_to_red_per_part]{0};
container = new CONTAINER_T(number_of_particles);
std::cout << "number_of_particles " << number_of_particles << std::endl;
for(std::size_t idx = 0; idx < number_of_particles; ++idx)
{
loader.fillParticle(values_to_read, nb_val_to_red_per_part);
particle_type p;
std::size_t ii{0};
for(auto& e: p.position())
{
e = values_to_read[ii++];
}
for(auto& e: p.inputs())
{
e = values_to_read[ii++];
}
p.variables(values_to_read[ii++], idx);
container->push_particle(idx, p);
}
}
template<typename Tree_T, typename Container_T, typename Value_T>
auto inline check_results(const Tree_T& tree, const Container_T& reference, const Value_T& eps) -> bool
{
scalfmm::utils::accurater<Value_T> error;
scalfmm::component::for_each_leaf(std::cbegin(tree), std::cend(tree), [&reference, &error](auto& leaf) {
const auto& container = leaf.cparticles();
const auto nb_elt = std::distance(container.begin(), container.end());
for(std::size_t i = 0; i < nb_elt; ++i)
{
const auto& p = container.particle(i);
const auto& idx = std::get<1>(p.variables());
error.add(std::get<0>(p.outputs()), std::get<0>(reference.variables(idx)));
}
});
bool ok = (error.get_relative_l2_norm() < eps);
std::cout << "Error " << error << std::endl;
return ok;
}
template<typename Tree_T>
auto inline check_equal(const Tree_T& tree, const Tree_T& tree2) -> bool
{
bool ok{true};
scalfmm::component::for_each_leaf(std::cbegin(tree), std::cend(tree), std::cbegin(tree2), [&ok](auto const& leaf, auto const& leaf2)
{
auto const& particles = leaf.cparticles();
auto const& particles2 = leaf2.cparticles();
const auto nb_elt = std::distance(particles.begin(), particles.end());
for(std::size_t i = 0; i < nb_elt; ++i)
{
const auto& p = particles.particle(i);
const auto& p2 = particles2.particle(i);
ok &= (std::get<0>(p.outputs()) == std::get<0>(p2.outputs()));
}
}
);
return ok;
}
template<int Dimension, class FMM_OPERATOR_TYPE, class FMM_OPERATOR_TYPE2, typename ValueType>
auto run(const std::string& input_file, const int& tree_height, const int& group_size, const int& order) -> bool
{
using value_type = ValueType;
using near_matrix_kernel_type = typename FMM_OPERATOR_TYPE::near_field_type::matrix_kernel_type;
using far_field_type = typename FMM_OPERATOR_TYPE::far_field_type;
using near_field_type = typename FMM_OPERATOR_TYPE::near_field_type;
using interpolator_type = typename far_field_type::approximation_type;
using near_matrix_kernel_type2 = typename FMM_OPERATOR_TYPE2::near_field_type::matrix_kernel_type;
using far_field_type2 = typename FMM_OPERATOR_TYPE2::far_field_type;
using near_field_type2 = typename FMM_OPERATOR_TYPE2::near_field_type;
using interpolator_type2 = typename far_field_type2::approximation_type;
using far_matrix_kernel_type = typename interpolator_type::matrix_kernel_type;
using far_matrix_kernel_type2 = typename interpolator_type2::matrix_kernel_type;
//
//
std::cout << scalfmm::colors::blue << "Entering tree test...\n" << scalfmm::colors::reset;
// The matrix kernel
//
static constexpr std::size_t nb_inputs_near{near_matrix_kernel_type::km};
static constexpr std::size_t nb_outputs_near{near_matrix_kernel_type::kn};
static constexpr std::size_t nb_inputs_far{far_matrix_kernel_type::km};
static constexpr std::size_t nb_outputs_far{far_matrix_kernel_type::kn};
std::cout << scalfmm::colors::blue << "<params> Runtime order : " << order << scalfmm::colors::reset << '\n';
// Open particle file
scalfmm::utils::timer time{};
// ---------------------------------------
using particle_type = scalfmm::container::particle<value_type, Dimension, value_type, nb_inputs_near, value_type,
nb_outputs_near, value_type, std::size_t>;
using container_type = scalfmm::container::particle_container<particle_type>;
using position_type = typename particle_type::position_type;
using cell_type =
scalfmm::component::cell<value_type, Dimension, nb_inputs_far, nb_outputs_far, std::complex<value_type>>;
using leaf_type = scalfmm::component::leaf<particle_type>;
using box_type = scalfmm::component::box<position_type>;
using group_tree_type = scalfmm::component::group_tree<cell_type, leaf_type, box_type>;
std::cout << scalfmm::colors::green << "Creating & Inserting particles ...\n" << scalfmm::colors::reset;
scalfmm::container::point<value_type, Dimension> box_center{};
value_type box_width{};
time.tic();
container_type* container{};
read_data<Dimension>(input_file, container, box_center, box_width);
time.tac();
std::cout << scalfmm::colors::green << "... Done.\n" << scalfmm::colors::reset;
std::cout << scalfmm::colors::green << "Box center = " << box_center << " box width = " << box_width
<< scalfmm::colors::reset << '\n';
std::cout << scalfmm::colors::yellow << "Container loaded in " << time.elapsed() << "ms\n"
<< scalfmm::colors::reset;
time.tic();
box_type box(box_width, box_center);
group_tree_type tree(static_cast<std::size_t>(tree_height), order, box, static_cast<std::size_t>(group_size),
*container);
group_tree_type tree2(static_cast<std::size_t>(tree_height), order, box, static_cast<std::size_t>(group_size),
*container);
time.tac();
std::cout << scalfmm::colors::yellow << "Group tree created in " << time.elapsed() << "ms\n"
<< scalfmm::colors::reset;
time.tic();
far_matrix_kernel_type mk_far{};
interpolator_type interpolator(mk_far, order, static_cast<std::size_t>(tree_height), box.width(0));
near_matrix_kernel_type mk_near{};
near_field_type near_field(mk_near);
far_field_type far_field(interpolator);
FMM_OPERATOR_TYPE fmm_operator(near_field, far_field);
far_matrix_kernel_type2 mk_far2{};
interpolator_type2 interpolator2(mk_far2, order, static_cast<std::size_t>(tree_height), box.width(0));
near_matrix_kernel_type2 mk_near2{};
near_field_type2 near_field2(mk_near2);
far_field_type2 far_field2(interpolator2);
FMM_OPERATOR_TYPE2 fmm_operator2(near_field2, far_field2);
time.tac();
std::cout << scalfmm::colors::yellow << "Kernel and Interp created in " << time.elapsed() << "ms\n"
<< scalfmm::colors::reset;
auto operator_to_proceed = scalfmm::algorithms::all;
scalfmm::algorithms::sequential(tree, std::move(fmm_operator), operator_to_proceed);
scalfmm::algorithms::sequential(tree2, std::move(fmm_operator2), operator_to_proceed);
value_type eps = std::pow(10.0, 1 - order);
bool works_non_homogenous = check_results(tree, *container, eps);
std::cout << ((works_non_homogenous == true) ? "Non Homogenous passed!\n" : "Non Homogenous failed!\n");
bool works_homogenous = check_results(tree2, *container, eps);
std::cout << ((works_homogenous == true) ? "Homogenous passed!\n" : "Homogenous failed!\n");
bool homogenous_eq_non_homogenous = check_equal(tree, tree2);
std::cout << ((homogenous_eq_non_homogenous == true) ? "Homogenous against Non Homogenous passed!\n" : "Homogenous against Non Homogenous failed!\n");
delete container;
return works_homogenous & works_non_homogenous & homogenous_eq_non_homogenous;
}
TEMPLATE_TEST_CASE("test fmm non homogenous", "[test-fmm]", double, float)
{
using value_type = TestType;
std::string path{TEST_FILES_PATH};
SECTION("fmm test non homogenous", "[fmm-test-non_homogenous]")
{
constexpr int dim = 3;
using matrix_kernel_type = scalfmm::matrix_kernels::debug::one_over_r_non_homogenous;
using matrix_kernel_type2 = scalfmm::matrix_kernels::laplace::one_over_r;
using near_field_type = scalfmm::operators::near_field_operator<matrix_kernel_type>;
using near_field_type2 = scalfmm::operators::near_field_operator<matrix_kernel_type2>;
//
using interpolator_type = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type>;
using interpolator_type2 = scalfmm::interpolation::uniform_interpolator<value_type, dim, matrix_kernel_type2>;
using far_field_type = scalfmm::operators::far_field_operator<interpolator_type>;
using far_field_type2 = scalfmm::operators::far_field_operator<interpolator_type2>;
path.append("xyzq100_ref.fma");
REQUIRE(run<dim, scalfmm::operators::fmm_operators<near_field_type, far_field_type>,
scalfmm::operators::fmm_operators<near_field_type2, far_field_type2>, value_type>(path, 4, 2, 5));
}
}
int main(int argc, char* argv[])
{
// global setup...
int result = Catch::Session().run(argc, argv);
// global clean-up...
// int result = 0;
// test_l2p<double, 2, 1>(9);
return result;
}
8 5 3 1
100 0.5 0.5 0.5 0.5
0.00717844472183415 0.934543986429588 0.0322223347994957 0.396464773760275 61.3170761317188
0.950688413201483 0.880593979393854 0.304711507385932 0.840485369411425 81.8727655266629
0.140502847867847 0.0526234894469653 0.182492646147157 0.353336097245244 80.6102843650929
0.159643730440393 0.0059697732956856 0.0569848010686442 0.446583434796544 68.8668417151561
0.67522320061197 0.960051698924659 0.737878337808521 0.318692772311881 90.2409618908103
0.277524543315046 0.298188193905677 0.515409712562388 0.886428433223031 109.454763871254
0.149195421085505 0.527361281988313 0.881246665792691 0.0155828494083288 87.404626733154
0.139318619902539 0.691573701834979 0.293013663245937 0.584090220317272 97.3731547457086
0.114485311016526 0.18957681493913 0.581056807750524 0.159368626531805 90.0078651904238
0.748215780263799 0.534864987166475 0.970116769109453 0.383715874807194 88.037355817385
0.365319655214815 0.233134323484755 0.42289790045891 0.691004373382196 114.005783114718
0.77244481877878 0.691415431464304 0.103511602358658 0.0588589135927364 104.64187471695
0.768276949612034 0.113278477391859 0.299773895804687 0.899854306161604 87.8521633079526
0.53996180406758 0.414020340072998 0.624310313199999 0.163545950630365 112.348886093286
0.730145169875339 0.868314511224163 0.254094513717622 0.159071502581806 101.055671382097
0.226666990357344 0.0160042624003118 0.686318598431392 0.533064714021855 79.7115879773282
0.897644485285529 0.0995279757209175 0.856444543834254 0.604144189711239 73.0874400682146
0.0196052293987421 0.560025648737355 0.967997228386295 0.582699021207219 69.6411754287321
0.682738563313503 0.380599844522543 0.461052826925741 0.269971117907016 110.51065263633
0.593784476344297 0.427602296855849 0.908733825957519 0.390478195463409 93.6408823131746
0.646643598958168 0.273277007153823 0.108959444316891 0.293400570118951 122.759003000587
0.300126015731898 0.671841563897264 0.116519819692002 0.742377406033981 94.8921469591946
0.959986065706641 0.451796504890076 0.83969399949304 0.298525606318119 84.3303771735622
0.89844806436507 0.379867977596941 0.251979170484752 0.0755380785377824 96.9768093544518
0.85838516297159 0.107032502141919 0.504594230008518 0.404982633583334 87.284398569835
0.737379374984563 0.613274070016121 0.244032800907021 0.857377942708183 107.845396028407
0.466934965855895 0.544068121813659 0.834061790468756 0.941968323291899 101.220616289071
0.510656423420443 0.145331341249129 0.725527843796279 0.662830659789996 90.5424594663154
0.431350927455373 0.296069207119942 0.311704268203268 0.846475779930007 107.785076004069
0.264206950742299 0.170616813090849 0.710499054603645 0.00275508142688352 98.9869876758025