DiscontinuousFunc<scalar>* NeighborSearch::init_ext_fn(MeshFunction* fu) { ensure_active_segment(this); ensure_set_quad_order(central_quad); ensure_set_quad_order(neighb_quad); if(fu->get_active_element() != central_el) { // Just in case - the input function should have the active element set to the central element from get_next_state // called in the assembling procedure. fu->set_active_element(central_el); fu->set_transform(original_central_el_transform); } if (neighborhood_type == H2D_DG_GO_DOWN) // Shrink the bigger central element to match the smaller neighbor (shrinks the active edge to the active segment). for(int i = 0; i < n_trans[active_segment]; i++) fu->push_transform(transformations[active_segment][i]); Func<scalar>* fn_central = init_fn(fu, fu->get_refmap(), get_quad_eo(false)); // Change the active element of the function. Note that this also resets the transformations on the function. fu->set_active_element(neighb_el); if (neighborhood_type == H2D_DG_GO_UP) // Shrink the bigger neighbor to match the smaller central element. for(int i = 0; i < n_trans[active_segment]; i++) fu->push_transform(transformations[active_segment][i]); Func<scalar>* fn_neighbor = init_fn(fu, fu->get_refmap(), get_quad_eo(true)); // Restore the original function. fu->set_active_element(central_el); fu->set_transform(original_central_el_transform); return new DiscontinuousFunc<scalar>(fn_central, fn_neighbor, (neighbor_edges[active_segment].orientation == 1)); //NOTE: This function is not very efficient, since it sets the active elements and possibly pushes transformations // for each mesh function in each cycle of the innermost assembly loop. This is neccessary because only in // this innermost cycle (in function DiscreteProblem::eval_form), we know the quadrature order (dependent on // the actual basis and test function), which is needed for creating the Func<scalar> objects via init_fn. // The reason for storing the central and neighbor values of any given function in these objects is that otherwise // we would have to have one independent copy of the function for each of the neighboring elements. However, it // could unify the way PrecalcShapesets and MeshFunctions are treated in NeighborSearch and maybe these additional // deep memory copying, performed only after setting the active edge part (before the nested loops over basis and // test functions), would be actually more efficient than this. This would require implementing copy for Filters. }
double* NeighborSearch::init_jwt(double** ext_cache_jwt) { ensure_central_pss_rm(this); ensure_active_segment(this); int eo = get_quad_eo(); if (n_neighbors == 1) // go-up or no-transf neighborhood { // Do the same as if assembling standard (non-DG) surface forms. if (ext_cache_jwt[eo] == NULL) { int np = get_quad_np(); double3* pt = get_quad_pt(); double3* tan = central_rm->get_tangent(active_edge, eo); ext_cache_jwt[eo] = new double[np]; for(int i = 0; i < np; i++) ext_cache_jwt[eo][i] = pt[i][2] * tan[i][2]; } return ext_cache_jwt[eo]; } else // go-down neighborhood { // Also take into account the transformations of the central element. Key key(eo, active_segment); if (cache_jwt[key] == NULL) { int np = get_quad_np(); double3* pt = get_quad_pt(); double3* tan = central_rm->get_tangent(active_edge, eo); cache_jwt[key] = new double[np]; for(int i = 0; i < np; i++) cache_jwt[key][i] = pt[i][2] * tan[i][2]; } return cache_jwt[key]; } }