46 T sn0_plus_sn1 = sorted_normal[0] + sorted_normal[1];
47 T sn0_times_sn1 = sorted_normal[0] * sorted_normal[1];
48 T sn2_volume = sorted_normal[2] * volume;
50 T min_sn0_plus_sn1_and_sn2 =
util::min(sn0_plus_sn1, sorted_normal[2]);
52 T d5 = sn2_volume + 0.5 * sn0_plus_sn1;
53 if(d5 > min_sn0_plus_sn1_and_sn2 && d5 <= sorted_normal[2]){
57 T d2 = 0.5 * sorted_normal[0] + 0.28867513 *
util::sqrt(
util::max(0., 24. * sorted_normal[1] * sn2_volume - sorted_normal[0]*sorted_normal[0]) );
59 if(d2 > sorted_normal[0] && d2 <= sorted_normal[1]){
63 T d1 = std::cbrt(6.0 * sn0_times_sn1 * sn2_volume);
64 if(d1 <= sorted_normal[0]){
68 T x3 = 81.0 * sn0_times_sn1 * (sn0_plus_sn1 - 2. * sn2_volume);
69 T y3 =
util::sqrt(
util::max(0., 23328. * sn0_times_sn1*sn0_times_sn1*sn0_times_sn1 - x3*x3 ));
70 T u3 = std::cbrt(x3*x3 + y3*y3);
71 T d3 = sn0_plus_sn1 - (7.5595264 * sn0_times_sn1 + 0.26456684 * u3) * (1./
util::sqrt(u3)) *
util::sin(0.5235988 - 0.3333334 *
util::atan(y3 / x3));
72 if(d3 > sorted_normal[1] && d3 <= min_sn0_plus_sn1_and_sn2){
76 T t4 = 9. *
util::pow(sn0_plus_sn1 + sorted_normal[2], 2) - 18.;
77 T x4 =
util::max(sn0_times_sn1 * sorted_normal[2] * (324. - 648. * volume), 1.1754944e-38);
79 T u4 = std::cbrt(x4*x4 + y4*y4);
80 T d4 = 0.5 * (sn0_plus_sn1 + sorted_normal[2]) - (0.20998684 * t4 + 0.13228342 * u4) * (1./
util::sqrt(u4)) *
util::sin(0.5235988- 0.3333334 *
util::atan(y4/x4));
88 const T sn0_p_sn1 = sn[0] + sn[1];
89 const T sn2_t_V = sn[2] * vol;
91 if(sn0_p_sn1 <= 2. * sn2_t_V){
92 return sn2_t_V + 0.5 * sn0_p_sn1;
95 const T sq_sn0 =
util::pow(sn[0],2), sn1_6 = 6. * sn[1], v1 = sq_sn0 / sn1_6;
97 if(v1 <= sn2_t_V && sn2_t_V < v1 + 0.5 * (sn[1]-sn[0])){
98 return 0.5 *(sn[0] +
util::sqrt(sq_sn0 + 8.0 * sn[1] * (sn2_t_V - v1)));
101 const T v6 = sn[0] * sn1_6 * sn2_t_V;
103 return std::cbrt(v6);
106 const T v3 = sn[2] < sn0_p_sn1 ? (
util::pow(sn[2],2) * (3. * sn0_p_sn1 - sn[2]) + sq_sn0 *(sn[0] - 3.0 * sn[2]) +
util::pow(sn[1],2)*(sn[1]-3.0 * sn[2])) / (sn[0] * sn1_6) : 0.5 * sn0_p_sn1;
110 const bool case34 = sn2_t_V < v3;
111 const T a = case34 ? v6_cb_sn0_sn1 : 0.5 * (v6_cb_sn0_sn1 -
util::pow(sn[2], 3));
112 const T b = case34 ? sq_sn0_sq_sn1 : 0.5 * (sq_sn0_sq_sn1 +
util::pow(sn[2], 2));
113 const T c = case34 ? sn0_p_sn1 : 0.5;
237 using DESCRIPTOR =
typename CELL::descriptor_t;
241 for(
size_t dim = 0; dim < CELL::descriptor_t::d; ++dim){
245 for(
int iPop = 1; iPop < DESCRIPTOR::q; iPop++) {
246 int omega_weight = 1;
247 if(descriptors::c<DESCRIPTOR>(iPop, 0) != 0){
250 if(descriptors::c<DESCRIPTOR>(iPop, 1) != 0){
255 if(CELL::descriptor_t::d == 3 && descriptors::c<DESCRIPTOR>(iPop)[2] != 0){
261 auto cellC = cell.neighbor(descriptors::c<DESCRIPTOR>(iPop));
262 V epsilon = getClampedEpsilon(cellC);
264 normal[0] -= omega_weight * (descriptors::c<DESCRIPTOR>(iPop, 0) * epsilon);
265 normal[1] -= omega_weight * (descriptors::c<DESCRIPTOR>(iPop, 1) * epsilon);
266 if(CELL::descriptor_t::d == 3){
267 normal[2] -= omega_weight * (descriptors::c<DESCRIPTOR>(iPop, 2) * epsilon);
363V calculateSurfaceTensionCurvature2D(CELL& cell) {
364 auto normal = computeParkerYoungInterfaceNormal(cell);
366 using DESCRIPTOR =
typename CELL::descriptor_t;
369 for(
size_t i = 0; i < DESCRIPTOR::d; ++i){
370 norm += normal[i] * normal[i];
379 for(
size_t i = 0; i <DESCRIPTOR::d; ++i){
389 constexpr size_t S = 2;
390 std::array<std::array<V,S>, S> lq_matrix;
391 std::array<V,S> b_rhs;
392 for(
size_t i = 0; i < S; ++i){
393 for(
size_t j = 0; j < S; ++j){
394 lq_matrix[i][j] = 0.;
400 V origin_offset = 0.;
402 V fill_level = getClampedEpsilon(cell);
403 origin_offset = calculateCubeOffset<V,DESCRIPTOR>(fill_level, normal);
407 std::size_t healthy_interfaces = 0;
409 for (
int iPop=1; iPop < DESCRIPTOR::q; ++iPop) {
410 auto cellC = cell.neighbor(descriptors::c<DESCRIPTOR>(iPop));
417 ++healthy_interfaces;
419 V fill_level = getClampedEpsilon(cellC);
421 V cube_offset = calculateCubeOffset<V,DESCRIPTOR>(fill_level, normal);
423 V x_pos = descriptors::c<DESCRIPTOR>(iPop,0);
424 V y_pos = descriptors::c<DESCRIPTOR>(iPop,1);
427 V rot_x_pos = x_pos * normal[1] - y_pos * normal[0];
428 V rot_y_pos = x_pos * normal[0] + y_pos * normal[1] + (cube_offset - origin_offset);
430 V rot_x_pos_2 = rot_x_pos * rot_x_pos;
431 V rot_x_pos_3 = rot_x_pos_2 * rot_x_pos;
432 V rot_x_pos_4 = rot_x_pos_3 * rot_x_pos;
434 lq_matrix[1][1] += rot_x_pos_2;
435 lq_matrix[1][0] += rot_x_pos_3;
436 lq_matrix[0][0] += rot_x_pos_4;
438 b_rhs[0] += rot_x_pos_2*(rot_y_pos);
439 b_rhs[1] += rot_x_pos*(rot_y_pos);
442 lq_matrix[0][1] = lq_matrix[1][0];
446 for(
size_t i = 0; i < DESCRIPTOR::d; ++i){
447 lq_matrix[i][i] += alpha;
451 std::array<V,S> solved_fit = FreeSurface::solvePivotedLU<V,S>(lq_matrix, b_rhs, healthy_interfaces);
454 V denom = std::sqrt(1. + solved_fit[1]*solved_fit[1]);
455 denom = denom * denom * denom;
456 V curvature = 2.*solved_fit[0] / denom;
461V calculateSurfaceTensionCurvature3D(CELL& cell){
463 auto normal = computeParkerYoungInterfaceNormal(cell);
465 using DESCRIPTOR =
typename CELL::descriptor_t;
468 for(
size_t i = 0; i < DESCRIPTOR::d; ++i){
469 norm += normal[i] * normal[i];
478 for(
size_t i = 0; i <DESCRIPTOR::d; ++i){
483 std::array<V,3> r_vec{
484 0.56270900, 0.32704452, 0.75921047
491 std::array<std::array<V,3>,3> rotation{{
494 {{normal[1] * r_vec[2] - normal[2] * r_vec[1], normal[2] * r_vec[0] - normal[0] * r_vec[2], normal[0] * r_vec[1] - normal[1] * r_vec[0]}},
495 {{normal[0], normal[1], normal[2]}}
504 for(
size_t i = 0; i < DESCRIPTOR::d; ++i){
505 cross_norm += rotation[1][i] * rotation[1][i];
509 if(cross_norm > 1e-6){
513 for(
size_t i = 0; i <DESCRIPTOR::d; ++i){
514 rotation[1][i] /= cross_norm;
525 for(
size_t i = 0; i < DESCRIPTOR::d; ++i){
526 cross_norm += rotation[1][i] * rotation[1][i];
531 for(
size_t i = 0; i <DESCRIPTOR::d; ++i){
532 rotation[1][i] /= cross_norm;
539 rotation[1][1] * normal[2] - rotation[1][2] * normal[1],
540 rotation[1][2] * normal[0] - rotation[1][0] * normal[2],
541 rotation[1][0] * normal[1] - rotation[1][1] * normal[0]
549 constexpr size_t S = 5;
550 std::array<std::array<V,S>, S> lq_matrix;
551 std::array<V,S> b_rhs;
552 for(
size_t i = 0; i < S; ++i){
553 for(
size_t j = 0; j < S; ++j){
554 lq_matrix[i][j] = 0.;
558 V origin_offset = 0.;
560 V fill_level = getClampedEpsilon(cell);
561 origin_offset = calculateCubeOffsetOpt<V,DESCRIPTOR>(fill_level, normal);
564 size_t healthy_interfaces = 0;
565 for(
int iPop = 1; iPop < DESCRIPTOR::q; iPop++){
566 auto cellC = cell.neighbor(descriptors::c<DESCRIPTOR>(iPop));
572 ++healthy_interfaces;
574 V fill_level = getClampedEpsilon(cellC);
576 V cube_offset = calculateCubeOffsetOpt<V, DESCRIPTOR>(fill_level, normal);
578 int i = descriptors::c<DESCRIPTOR>(iPop)[0];
579 int j = descriptors::c<DESCRIPTOR>(iPop)[1];
580 int k = descriptors::c<DESCRIPTOR>(iPop)[2];
582 std::array<V,3> pos{
static_cast<V
>(i),
static_cast<V
>(j),
static_cast<V
>(k)};
583 std::array<V,3> r_pos{0.,0.,cube_offset - origin_offset};
585 for(
size_t a = 0; a < DESCRIPTOR::d; ++a){
586 for(
size_t b = 0; b < DESCRIPTOR::d; ++b){
587 r_pos[a] += rotation[a][b] * pos[b];
591 V r_x_2 = r_pos[0] * r_pos[0];
592 V r_x_3 = r_x_2 * r_pos[0];
593 V r_x_4 = r_x_3 * r_pos[0];
595 V r_y_2 = r_pos[1] * r_pos[1];
596 V r_y_3 = r_y_2 * r_pos[1];
597 V r_y_4 = r_y_3 * r_pos[1];
599 V r_x_2_y_2 = r_x_2 * r_y_2;
600 V r_x_3_y = r_x_3 * r_pos[1];
601 V r_x_2_y = r_x_2 * r_pos[1];
603 V r_x_y_3 = r_pos[0] * r_y_3;
604 V r_x_y_2 = r_pos[0] * r_y_2;
606 V r_x_y = r_pos[0] * r_pos[1];
608 lq_matrix[0][0] += r_x_4;
609 lq_matrix[1][1] += r_y_4;
610 lq_matrix[2][2] += r_x_2_y_2;
611 lq_matrix[3][3] += r_x_2;
612 lq_matrix[4][4] += r_y_2;
615 lq_matrix[2][0] += r_x_3_y;
616 lq_matrix[3][0] += r_x_3;
617 lq_matrix[4][0] += r_x_2_y;
619 lq_matrix[2][1] += r_x_y_3;
620 lq_matrix[3][1] += r_x_y_2;
621 lq_matrix[4][1] += r_y_3;
626 lq_matrix[4][3] += r_x_y;
628 b_rhs[0] += r_x_2 * r_pos[2];
629 b_rhs[1] += r_y_2 * r_pos[2];
630 b_rhs[2] += r_x_y * r_pos[2];
631 b_rhs[3] += r_pos[0] * r_pos[2];
632 b_rhs[4] += r_pos[1] * r_pos[2];
635 lq_matrix[1][0] = lq_matrix[2][2];
636 lq_matrix[3][2] = lq_matrix[4][0];
637 lq_matrix[4][2] = lq_matrix[3][1];
639 for(
size_t i = 0; i < S; ++i){
640 for(
size_t j = i + 1; j < S; ++j){
641 lq_matrix[i][j] = lq_matrix[j][i];
648 for(
size_t i = 0; i < S; ++i){
649 lq_matrix[i][i] += alpha;
652 std::array<V,S> solved_fit = FreeSurface::solvePivotedLU<V,S>(lq_matrix, b_rhs, healthy_interfaces);
654 V denom = std::sqrt(1. + solved_fit[3]*solved_fit[3] + solved_fit[4]*solved_fit[4]);
655 denom = denom * denom * denom;
656 V curvature = ( (1.+solved_fit[4]*solved_fit[4]) * solved_fit[0] + (1. + solved_fit[3]*solved_fit[3] ) * solved_fit[1] - solved_fit[3] * solved_fit[4] * solved_fit[2] ) / denom;
665 for(
int i = 0; i < DESCRIPTOR::d; i++){
672 const T n1 = abs_normal[0];
673 const T n2 = abs_normal[1];
675 for(
int i = 0; i < DESCRIPTOR::d; i++){
676 if(abs_normal[i] < n1){
680 if(abs_normal[i] > n2){
685 T abs_normal_acc = 0;
686 for(
int i = 0; i < DESCRIPTOR::d; i++){
687 abs_normal_acc += abs_normal[i];
689 const T n3 = abs_normal_acc - n1 - n2;
690 const T d = 0.5 * (n1+n2+n3) -
util::abs(d_o);
693 if(DESCRIPTOR::d == 2){
695 vol = d * d / (2. * n1 * n2);
697 vol = d / n2 - n1 / (2. * n2);
701 if(DESCRIPTOR::d == 3){
703 vol = (d-0.5 *(n1+n3))/n2;
705 vol =
util::pow(d,3) / (6. * n1 * n2 * n3);
707 vol = (3.0 * d * (d-n1) + std::pow(n1,2))/(6. * n2 * n3);
713 return std::copysign(0.5 - vol, d_o) + 0.5;