From 621c573c6926cf457a5a651ff4e8e2a939341c05 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 2 Jun 2017 14:14:32 +0200 Subject: [PATCH 001/366] First changes to add the C1-multipatch, for two patches --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 234 ++++++++++++++++++ .../multipatch/@sp_multipatch_C1/subsasgn.m | 4 + .../multipatch/@sp_multipatch_C1/subsref.m | 4 + 3 files changed, 242 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m new file mode 100644 index 00000000..d0459362 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -0,0 +1,234 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +%XXXX ncomp = 1 ncomp (scalar) number of components of the functions of the space (equal to msh.rdim) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +%XXXX transform (string) one of 'grad-preserving', 'curl-preserving' and 'div-preserving' +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +%XXXX dofs_ornt (1 x npatch cell-array) global orientation of the degrees for freedom, for curl-conforming and div-conforming spaces +%XXXX boundary (1 x 1 object) a (ndim-1) dimensional "sp_multipatch" object for the whole boundary +%XXXX dofs (1 x ndof vector) only for boundary spaces, degrees of freedom that do not vanish on the boundary +%XXXX orientation (1 x ndof vector) only for boundary spaces with 'curl-preserving' transform, global orientation +%XXXX of the boundary dofs with respect to the volumetric one. +% constructor function handle function handle to construct the same discrete space in a different msh +% +% % % % METHODS +% % % % Methods that give a structure with all the functions computed in a certain subset of the mesh +% % % % sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% % % % +% % % % Methods for post-processing, that require a computed vector of degrees of freedom +% % % % sp_h1_error: compute the error in H1 norm +% % % % sp_l2_error: compute the error in L2 norm +% % % % sp_hcurl_error: compute the error in H(curl) norm +% % % % sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% % % % +% % % % Methods for basic connectivity operations +% % % % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% % % % sp_get_cells: compute the cells on which a list of functions do not vanish +% % % % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) + + sp_class = class (spaces{1}); + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + +% XXXX FIX THIS, TO COMPUTE ALSO THE BOUNDARY + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + +% if (~all ([aux.ncomp] == sp.ncomp)) + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch +% if (~strcmpi (spaces{iptc}.transform, sp.transform)) + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Computation of the number of degrees of freedom +% I need to give a global numbering to the C^1 basis functions +% I start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + sp.interior_dofs_per_patch{iptc} = []; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (sp.interior_dofs_per_patch{iptc}); + end + sp.ndof_interface = 0; % The number of functions in V^2 + sp.ndof = sp.ndof_interior + sp.ndof_interface; + + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% Here we should call the function compute_coefficients below + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + + global_indices = (sp.ndof_interior+1):sp.ndof; + Cpatch{iptc}(:,global_indices) = []; % The coefficients computed by Mario + end + + sp.interfaces = interfaces; + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +function compute_coefficients (space, msh, geometry, interfaces) + + for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; + patch(2) = interfaces(iref).patch2; + side(1) = interfaces(iref).side1; + side(2) = interfaces(iref).side2; + +% Compute the Greville points, and the auxiliary mesh and space objects + msh_side_int = []; + for ii = 1:2 % The two patches + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + sp_grev(ii) = struct (sp_precompute (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); + end +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); + + end + + +%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% +% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R +% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) +% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) +% and the jacobian (jacdet) at the Greville points. The last index +% indicates the Greville point. +% sp_grev(ii) is a structure with the value of the basis functions +% (.shape_functions) at the Greville points. The last index indicates the Greville point. +% The previous one indicates the basis functions that are non-null on the +% element. This also includes functions from the interior. + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m b/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m new file mode 100644 index 00000000..1c89450c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m @@ -0,0 +1,4 @@ +%% override private write access of objects in this class +function obj = subsasgn (obj, S, value) +obj = builtin('subsasgn', obj, S, value); +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m b/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m new file mode 100644 index 00000000..9f7048b6 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m @@ -0,0 +1,4 @@ +%% override private read access of object data +function value = subsref (obj, S) +value = builtin ('subsref', obj, S); +end \ No newline at end of file From 96b34298801cd2a4cbdf29f0a9dc3f75c2cf4dd4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 2 Jun 2017 14:25:21 +0200 Subject: [PATCH 002/366] Building the C1 example --- .../inst/examples/base/ex_two_patches_C1.m | 105 ++++++++++++++ geopdes/inst/multipatch/mp_solve_laplace_C1.m | 129 ++++++++++++++++++ 2 files changed, 234 insertions(+) create mode 100644 geopdes/inst/examples/base/ex_two_patches_C1.m create mode 100644 geopdes/inst/multipatch/mp_solve_laplace_C1.m diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m new file mode 100644 index 00000000..0c41a4d4 --- /dev/null +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -0,0 +1,105 @@ +% EX_LAPLACE_LSHAPED_MP: solve the Poisson problem in the multipatch L-shaped domain with a B-spline discretization. + +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); +nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); + +problem_data.geo_name = nrb; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [1 2 3 4 5 6]; + +% Physical parameters +problem_data.c_diff = @(x, y) ones(size(x)); + +% Source and boundary terms +problem_data.f = @(x, y) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); +problem_data.g = @(x, y, ind) test_Lshaped_mp_g_nmnn (x, y, ind); +problem_data.h = @(x, y, ind) exp(x) .* sin (x.*y); + +% Exact solution (optional) +problem_data.uex = @(x, y) exp(x) .* sin (x.*y); +problem_data.graduex = @(x, y) cat (1, ... + reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... + reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); + +% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +method_data.degree = [3 3]; % Degree of the splines +method_data.regularity = [2 2]; % Regularity of the splines +method_data.nsub = [9 9]; % Number of subdivisions +method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule + +% 3) CALL TO THE SOLVER +[geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); + +% 4) POST-PROCESSING +% EXPORT TO PARAVIEW +output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; + +vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; +fprintf ('The result is saved in the file %s.pvd \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') + +figure +sp_plot_solution (u, space, geometry, vtk_pts) + +% COMPARISON WITH THE EXACT SOLUTION +[error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) + +%!demo +%! ex_laplace_Lshaped_mp + +%!test +%! problem_data.geo_name = 'geo_Lshaped_mp.txt'; +%! problem_data.nmnn_sides = [3 4 5 6]; +%! problem_data.drchlt_sides = [1 2]; +%! problem_data.c_diff = @(x, y) ones(size(x)); +%! problem_data.f = @(x, y) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); +%! problem_data.g = @(x, y, ind) test_Lshaped_mp_g_nmnn (x, y, ind); +%! problem_data.h = @(x, y, ind) exp(x) .* sin (x.*y); +%! problem_data.uex = @(x, y) exp(x) .* sin (x.*y); +%! problem_data.graduex = @(x, y) cat (1, ... +%! reshape ( exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... +%! reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); +%! method_data.degree = [3 3]; % Degree of the splines +%! method_data.regularity = [2 2]; % Regularity of the splines +%! method_data.nsub = [9 9]; % Number of subdivisions +%! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule +%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); +%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); +%! assert (error_l2, 3.00642608570282e-07, 1e-16) +%! assert (error_h1, 1.77524941085757e-05, 1e-16) +%! assert (space.ndof, 408) +%! for iptc = 1:space.boundary.npatch +%! patch = msh.boundary.patch_numbers(iptc); +%! side = msh.boundary.side_numbers(iptc); +%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) +%! end +%! +%! problem_data.geo_name = 'geo_Lshaped_mp_b.txt'; +%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); +%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); +%! assert (error_l2, 3.00642608570282e-07, 1e-16) +%! assert (error_h1, 1.77524941085757e-05, 1e-16) +%! assert (space.ndof, 408) +%! for iptc = 1:space.boundary.npatch +%! patch = msh.boundary.patch_numbers(iptc); +%! side = msh.boundary.side_numbers(iptc); +%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) +%! end +%! +%! problem_data.geo_name = 'geo_Lshaped_mp_c.txt'; +%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); +%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); +%! assert (error_l2, 3.00642608570282e-07, 1e-16) +%! assert (error_h1, 1.77524941085757e-05, 1e-16) +%! assert (space.ndof, 408) +%! for iptc = 1:space.boundary.npatch +%! patch = msh.boundary.patch_numbers(iptc); +%! side = msh.boundary.side_numbers(iptc); +%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) +%! end diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m new file mode 100644 index 00000000..9181e4d8 --- /dev/null +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -0,0 +1,129 @@ +% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. +% +% Example to solve the diffusion problem +% +% - div ( epsilon(x) grad (u)) = f in Omega +% epsilon(x) du/dn = g on Gamma_N +% u = h on Gamma_D +% +% where the domain \Omega is formed by several patches of the form F((0,1)^n). +% +% USAGE: +% +% [geometry, msh, space, u] = +% mp_solve_laplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: array of geometry structures (see geo_load) +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% u: the computed degrees of freedom +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2010, 2011, 2013, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 2 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_laplace_C1 (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +msh = msh_multipatch (msh, boundaries); +space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space_C1 = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); +clear sp + +% Compute and assemble the matrices +stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); +rhs = op_f_v_mp (space, msh, f); + +% Apply Neumann boundary conditions +Nbnd = cumsum ([0, boundaries.nsides]); +for iref = nmnn_sides + iref_patch_list = Nbnd(iref)+1:Nbnd(iref+1); + gref = @(varargin) g(varargin{:},iref); + rhs_nmnn = op_f_v_mp (space.boundary, msh.boundary, gref, iref_patch_list); + rhs(space.boundary.dofs) = rhs(space.boundary.dofs) + rhs_nmnn; +end + +% Apply Dirichlet boundary conditions +u = zeros (space.ndof, 1); +[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); +u(drchlt_dofs) = u_drchlt; + +int_dofs = setdiff (1:space.ndof, drchlt_dofs); +rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; + +% Solve the linear system +u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); + +end + +%!demo +%! ex_laplace_Lshaped_mp + +%!demo +%! ex_laplace_cube_mp + +%!demo +%! ex_laplace_thick_L_mp From 4c464e3967076cfe99131e1d8f44e207226d0bd1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 2 Jun 2017 14:49:06 +0200 Subject: [PATCH 003/366] First version of some files. I think they should work like that --- .../multipatch/@sp_multipatch_C1/op_u_v_mp.m | 61 ++++++++++++++ .../@sp_multipatch_C1/sp_l2_error.m | 48 +++++++++++ .../@sp_multipatch_C1/sp_multipatch_C1.m | 1 - .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 82 +++++++++++++++++++ 4 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m new file mode 100644 index 00000000..06151fde --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m @@ -0,0 +1,61 @@ +% OP_U_V_MP: assemble the mass matrix M = [m(i,j)], m(i,j) = (mu u_j, v_i), in a multipatch domain. +% +% mat = op_u_v_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled mass matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_u_v_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_u_v_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + +% if (~isempty (spv.dofs_ornt)) +% vs = spv.dofs_ornt{iptc}(rs)' .* vs; +% end +% if (~isempty (spu.dofs_ornt)) +% vs = vs .* spu.dofs_ornt{iptc}(cs)'; +% end + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m new file mode 100644 index 00000000..abbbc9ef --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -0,0 +1,48 @@ +% SP_L2_ERROR: Evaluate the error in L^2 norm. +% +% errl2 = sp_l2_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% +% OUTPUT: +% +% errl2: error in L^2 norm +% +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function errl2 = sp_l2_error (space, msh, u, uex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d0459362..ee61db39 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -190,7 +190,6 @@ function compute_coefficients (space, msh, geometry, interfaces) side(2) = interfaces(iref).side2; % Compute the Greville points, and the auxiliary mesh and space objects - msh_side_int = []; for ii = 1:2 % The two patches brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m new file mode 100644 index 00000000..e3d71569 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -0,0 +1,82 @@ +% SP_TO_VTK: Export multipatch results to VTK format for plotting. +% +% sp_to_vtk (u, space, geometry, npts, filename, fieldnames, [option], [lambda_lame, mu_lame]) +% +% INPUT: +% +% u: vector of dof weights +% space: object representing the space of discrete functions (see sp_multipatch) +% geometry: geometry structure (see geo_load) +% npts: number of points along each parametric direction where to evaluate +% filename: name of the output file. +% fieldnames: how to name the saved variables in the vtk file +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient', +% and for vectors also 'curl', 'divergence', 'stress' +% lambda_lame: function handle to the first Lame coefficient (only needed to compute 'stress') +% mu_lame: function handle for the second Lame coefficient (only needed to compute 'stress') +% +% OUTPUT: +% +% none +% +% Copyright (C) 2010 Carlo de Falco, Rafael Vazquez +% Copyright (C) 2011, 2012, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) + + str1 = cat (2,' \n', ... +' \n', ... +' \n'); + + str2 = cat (2, ' \n'); + + str3 = cat (2, ... +'\n', ... +' \n'); + + if (length (filename) < 4 || ~strcmp (filename(end-3:end), '.pvd')) + pvd_filename = cat (2, filename, '.pvd'); + else + pvd_filename = filename; + filename = filename (1:end-4); + end + + fid = fopen (pvd_filename, 'w'); + if (fid < 0) + error ('mp_sp_to_vtk: could not open file %s', pvd_filename); + end + + fprintf (fid, str1); + ind = union (find (filename == '/', 1, 'last'), find (filename == '\', 1, 'last')) + 1; + if (isempty (ind)); ind = 1; end + for iptc = 1:space.npatch + filename_patch_without_path = cat (2, filename(ind:end), '_', num2str (iptc)); + filename_patch = cat (2, filename, '_', num2str (iptc)); + fprintf (fid, str2, iptc, filename_patch_without_path); +% if (isempty (space.dofs_ornt)) + sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + filename_patch, fieldname, varargin{:}) +% else +% sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... +% filename_patch, fieldname, varargin{:}) +% end + end + fprintf (fid, str3); + + fclose (fid); + +end From 84d9d5d928c35d30db8e696b03d2c5cd324abecc Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 2 Jun 2017 16:22:16 +0200 Subject: [PATCH 004/366] Functions related to the support of the functions --- .../sp_get_basis_functions.m | 41 +++++++++++++++ .../@sp_multipatch_C1/sp_get_cells.m | 52 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m new file mode 100644 index 00000000..76edf5c8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m @@ -0,0 +1,41 @@ +% SP_GET_BASIS_FUNCTIONS: Compute the indices of tensor-product B-splines acting on a list of cells. +% +% fun_indices = sp_get_basis_functions (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the cells. +% +% OUTPUT: +% fun_indices: indices of the basis functions acting on the cells. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function function_indices = sp_get_basis_functions (space, msh, cell_indices) + +function_indices = []; +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [~,local_cell_indices,~] = intersect ((Nelem(iptc)+1):Nelem(iptc+1), cell_indices); + if (~isempty (local_cell_indices)) + aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); + [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); + function_indices = union (function_indices, dofs); + end +end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m new file mode 100644 index 00000000..440471ae --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -0,0 +1,52 @@ +% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function. +% +% [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% cell_indices: indices of the cells within the support of the basis functions. +% indices_per_function: indices of the cells within the support of each basis function. +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [cell_indices, indices_per_function] = sp_get_cells (space, msh, fun_indices) + +fun_indices = fun_indices(:).'; + +indices_per_function = cell (numel (fun_indices), 1); +cell_indices = []; + +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + patch_indices = patch_indices(:).'; + [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + + cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices); + +% if (nargout == 2) +% local_funs = local_funs(:).'; +% for ifun = 1:numel(patch_indices) +% indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); +% end +% end + end +end From 6d9b623d476c061ff3cfc9aae2b83d044d29aa39 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 6 Jun 2017 12:04:11 +0200 Subject: [PATCH 005/366] Changes for Mario --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index ee61db39..a3a7201f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -66,7 +66,6 @@ function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) - sp_class = class (spaces{1}); if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') end @@ -123,6 +122,8 @@ % Computation of the coefficients for basis change % The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof % Here we should call the function compute_coefficients below + + Cpatch = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); for iptc = 1:sp.npatch @@ -133,6 +134,13 @@ global_indices = (sp.ndof_interior+1):sp.ndof; Cpatch{iptc}(:,global_indices) = []; % The coefficients computed by Mario + +disp ('We should fill Cpatch using the coefficients, computed as in Section 7') +disp('Mario, use F11 (step In) or F10 (Step) to see where we are') +keyboard + + compute_coefficients (sp, msh, geometry, interfaces) + end sp.interfaces = interfaces; @@ -211,7 +219,7 @@ function compute_coefficients (space, msh, geometry, interfaces) msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - sp_grev(ii) = struct (sp_precompute (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); + sp_grev(ii) = struct (sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); end % For now I assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); @@ -229,5 +237,6 @@ function compute_coefficients (space, msh, geometry, interfaces) % (.shape_functions) at the Greville points. The last index indicates the Greville point. % The previous one indicates the basis functions that are non-null on the % element. This also includes functions from the interior. +% The number of the non-vanishing basis functions is in connectivity end From f2890a382018ec5285f7388f8610e55eeadf6d1e Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 4 Jul 2017 18:21:12 +0200 Subject: [PATCH 006/366] Changes after discussion with Mario --- .../inst/examples/base/ex_two_patches_C1.m | 4 +-- .../@sp_multipatch_C1/sp_multipatch_C1.m | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index 0c41a4d4..dd19a2ae 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -28,9 +28,9 @@ % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data -method_data.degree = [3 3]; % Degree of the splines +method_data.degree = [4 4]; % Degree of the splines method_data.regularity = [2 2]; % Regularity of the splines -method_data.nsub = [9 9]; % Number of subdivisions +method_data.nsub = [4 4]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule % 3) CALL TO THE SOLVER diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index a3a7201f..84243007 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -197,6 +197,26 @@ function compute_coefficients (space, msh, geometry, interfaces) side(1) = interfaces(iref).side1; side(2) = interfaces(iref).side2; +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% I assume that the regularity is degree-2, otherwise things become more complicated +% Only univariate knot vectors are computed + if (side(1) < 3) + knots = space.sp_patch{patch(1)}.knots{2}; + degree = space.sp_patch{patch(1)}.degree(2); + nel_univ = msh.msh_patch{patch(1)}.nel_dir(2); + else + knots = space.sp_patch{patch(1)}.knots{1}; + degree = space.sp_patch{patch(1)}.degree(1); + nel_univ = msh.msh_patch{patch(1)}.nel_dir(1); + end + regularity = degree - 2; + + nel_geo = numel (unique (geometry(patch(1)).boundary(side(1)).nurbs.knots)) - 1; + nsub = nel_univ / nel_geo; + + knots0 = kntrefine (geometry(patch(1)).boundary(side(1)).nurbs.knots, nsub-1, degree, regularity+1); + knots1 = kntrefine (geometry(patch(1)).boundary(side(1)).nurbs.knots, nsub-1, degree-1, regularity); + % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches brk = cell (1,msh.ndim); @@ -220,6 +240,12 @@ function compute_coefficients (space, msh, geometry, interfaces) sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); msh_side_int{ii} = msh_precompute (msh_side_int{ii}); sp_grev(ii) = struct (sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); + +% The univariate spaces for the N0 and N1 basis functions + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute (sp0, msh_grev.boundary(side(ii))); + sp1_struct = sp_precompute (sp1, msh_grev.boundary(side(ii))); end % For now I assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); From 6c2d08df074b3ccc8ca48ff5e1dfcd3e635be07c Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 14 Jul 2017 10:06:31 +0200 Subject: [PATCH 007/366] Changes after meeting with Mario in Linz --- .../inst/examples/base/ex_two_patches_C1.m | 10 ++++---- .../@sp_multipatch_C1/sp_multipatch_C1.m | 24 ++++++++++++++++--- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index dd19a2ae..d86d915e 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -3,8 +3,10 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file -nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); -nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); +%nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); +%nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); +nrb(1) = nrb4surf ([0 0], [-4 -1/2], [0 3], [-10/3 16/5]); +nrb(2) = nrb4surf ([0 0], [8/3 -2/5], [0 3], [10/3 22/7]); problem_data.geo_name = nrb; @@ -28,8 +30,8 @@ % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data -method_data.degree = [4 4]; % Degree of the splines -method_data.regularity = [2 2]; % Regularity of the splines +method_data.degree = [3 3]; % Degree of the splines +method_data.regularity = [1 1]; % Regularity of the splines method_data.nsub = [4 4]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 84243007..341a462f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -218,7 +218,7 @@ function compute_coefficients (space, msh, geometry, interfaces) knots1 = kntrefine (geometry(patch(1)).boundary(side(1)).nurbs.knots, nsub-1, degree-1, regularity); % Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches + for ii = 1:2 % The two patches (L-R) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; for idim = 1:msh.ndim @@ -244,8 +244,26 @@ function compute_coefficients (space, msh, geometry, interfaces) % The univariate spaces for the N0 and N1 basis functions sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute (sp0, msh_grev.boundary(side(ii))); - sp1_struct = sp_precompute (sp1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + ind = [2 2 1 1]; + knotsn = sp_aux.knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); + end + + alpha{ii} = geopdes_det__ (msh_side_int{ii}.geo_map_jac); + numerator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,1,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + denominator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,2,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + beta{ii} = numerator ./ denominator; + + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_functions(:,:,jj)); + end end % For now I assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); From f9161d3c0128807b137b882ac18660dbaaa8302e Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 14 Jul 2017 14:10:07 +0200 Subject: [PATCH 008/366] Computation of the coefficients for the two-patch case. Seems to work --- .../inst/examples/base/ex_two_patches_C1.m | 2 +- .../@sp_multipatch_C1/sp_multipatch_C1.m | 82 +++++++++++++++---- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index d86d915e..7aba1308 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -6,7 +6,7 @@ %nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); %nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); nrb(1) = nrb4surf ([0 0], [-4 -1/2], [0 3], [-10/3 16/5]); -nrb(2) = nrb4surf ([0 0], [8/3 -2/5], [0 3], [10/3 22/7]); +nrb(2) = nrb4surf ([0 0], [8/3 -2/5], [0 3], [10/3 23/7]); problem_data.geo_name = nrb; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 341a462f..3902a5d2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -110,12 +110,20 @@ % Compute the local indices of the functions in V^1 % and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES, AND WITH THE ORDERING IN THE PAPER sp.ndof_interior = 0; for iptc = 1:sp.npatch - sp.interior_dofs_per_patch{iptc} = []; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (sp.interior_dofs_per_patch{iptc}); + ndof_dir = sp.sp_patch{iptc}.ndof_dir; + xx = 3:ndof_dir(1); yy = 1:ndof_dir(2); + [XX, YY] = ndgrid (xx, yy); + interior_dofs = sub2ind (ndof_dir, XX, YY); + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); end - sp.ndof_interface = 0; % The number of functions in V^2 + + [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + + sp.ndof_interface = ndof; % The number of functions in V^2 sp.ndof = sp.ndof_interior + sp.ndof_interface; @@ -133,17 +141,11 @@ speye (numel (sp.interior_dofs_per_patch{iptc})); global_indices = (sp.ndof_interior+1):sp.ndof; - Cpatch{iptc}(:,global_indices) = []; % The coefficients computed by Mario - -disp ('We should fill Cpatch using the coefficients, computed as in Section 7') -disp('Mario, use F11 (step In) or F10 (Step) to see where we are') -keyboard - - compute_coefficients (sp, msh, geometry, interfaces) - + Cpatch{iptc}(:,global_indices) = CC{iptc}; % The coefficients computed by Mario end sp.interfaces = interfaces; + sp.Cpatch = Cpatch; % XXXX No boundary for now % % Boundary construction @@ -189,7 +191,7 @@ end -function compute_coefficients (space, msh, geometry, interfaces) +function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) for iref = 1:numel(interfaces) patch(1) = interfaces(iref).patch1; @@ -197,6 +199,7 @@ function compute_coefficients (space, msh, geometry, interfaces) side(1) = interfaces(iref).side1; side(2) = interfaces(iref).side2; + % The knot vectors for the N0 and N1 basis functions, as in Mario's notation % I assume that the regularity is degree-2, otherwise things become more complicated % Only univariate knot vectors are computed @@ -204,10 +207,16 @@ function compute_coefficients (space, msh, geometry, interfaces) knots = space.sp_patch{patch(1)}.knots{2}; degree = space.sp_patch{patch(1)}.degree(2); nel_univ = msh.msh_patch{patch(1)}.nel_dir(2); + degu = space.sp_patch{patch(1)}.degree(1); + knt = unique (space.sp_patch{patch(1)}.knots{1}); + tau1 = knt(2) - knt(1); else knots = space.sp_patch{patch(1)}.knots{1}; degree = space.sp_patch{patch(1)}.degree(1); nel_univ = msh.msh_patch{patch(1)}.nel_dir(1); + degu = space.sp_patch{patch(1)}.degree(2); + knt = unique (space.sp_patch{patch(1)}.knots{2}); + tau1 = knt(2) - knt(1); end regularity = degree - 2; @@ -232,6 +241,8 @@ function compute_coefficients (space, msh, geometry, interfaces) end msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); % msh_side contains only the univariate parametrization of the boundary (dependence on u) % msh_side_int contains information for the bivariate parametrization (dependence on u and v) % sp_grev contains the value and derivatives of the basis functions, at the Greville points @@ -240,7 +251,7 @@ function compute_coefficients (space, msh, geometry, interfaces) sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); msh_side_int{ii} = msh_precompute (msh_side_int{ii}); sp_grev(ii) = struct (sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); - + % The univariate spaces for the N0 and N1 basis functions sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); @@ -250,23 +261,62 @@ function compute_coefficients (space, msh, geometry, interfaces) knotsn = sp_aux.knots{ind(side(ii))}; spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); +% Matrix for the linear systems, (14)-(16) in Mario's notes A = sparse (msh_side(ii).nel, msh_side(ii).nel); for jj = 1:msh_side(ii).nel A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); end - + alpha{ii} = geopdes_det__ (msh_side_int{ii}.geo_map_jac); numerator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,1,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); denominator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,2,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); beta{ii} = numerator ./ denominator; +% RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); for jj = 1:msh_side(ii).nel rhss(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_functions(:,:,jj)); end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER + val = val * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel + val_aux = val * beta{ii}(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_function_gradients(:,:,:,jj)) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER + val = val * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj); + rhsc(jj,sp1_struct.connectivity(:,jj)) = squeeze (sp1_struct.shape_functions(:,:,jj)) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ind0 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); +% ind2 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + + CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; + CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii}; end -% For now I assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); + end From 7db8398e4eda2643c0f74b85ecb602ed4b7bdf5a Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 14 Jul 2017 14:15:52 +0200 Subject: [PATCH 009/366] Operator for the right hand side --- .../multipatch/@sp_multipatch_C1/op_f_v_mp.m | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m new file mode 100644 index 00000000..561a3415 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m @@ -0,0 +1,51 @@ +% OP_F_V_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% +% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_v_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_v_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_v_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + +% if (~isempty (space.dofs_ornt)) +% rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); +% end + rhs = rhs + space.Cpatch{iptc}.' * rhs_loc; + end + +end \ No newline at end of file From 32232002e960fcffbb25657ee45b20642ef5cc44 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 6 Oct 2017 16:43:20 +0200 Subject: [PATCH 010/366] Three new operators for C1 multipatch --- .../op_gradgradu_gradgradv_mp.m | 54 ++++++++++++++++++ .../@sp_multipatch_C1/op_gradu_gradv_mp.m | 54 ++++++++++++++++++ .../op_laplaceu_laplacev_mp.m | 55 +++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m new file mode 100644 index 00000000..7abebba3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADGRADU_GRADGRADV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon grad grad u_j, grad grad v_i), in a multipatch domain. +% +% mat = op_gradgradu_gradgradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradgradu_gradgradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradgradu_gradgradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m new file mode 100644 index 00000000..953bba5b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADU_GRADV_MP: assemble the stiffness matrix A = [a(i,j)], a(i,j) = (epsilon grad u_j, grad v_i), in a multipatch domain. +% +% mat = op_gradu_gradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled stiffness matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradu_gradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradu_gradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m new file mode 100644 index 00000000..55ba64ac --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m @@ -0,0 +1,55 @@ +% OP_LAPLACEU_LAPLACEV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon laplace u_j, laplace v_i), in a multipatch domain. +% +% mat = op_laplaceu_laplacev_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_laplaceu_laplacev_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_laplaceu_laplacev_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + + end + +end From 852fc34fac1fd5fdd265c24137be72fdd34c9606 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 6 Oct 2017 16:57:36 +0200 Subject: [PATCH 011/366] Error functions --- .../@sp_multipatch_C1/sp_h1_error.m | 54 +++++++++++++++++ .../@sp_multipatch_C1/sp_h2_error.m | 59 +++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m new file mode 100644 index 00000000..f727b7d2 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m @@ -0,0 +1,54 @@ +% SP_H1_ERROR: Evaluate the error in H^1 norm. +% +% [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% +% OUTPUT: +% +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h1(iptc), error_l2(iptc), error_h1s(iptc)] = ... + sp_h1_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m new file mode 100644 index 00000000..a40be7cb --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -0,0 +1,59 @@ +% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% hessuex: function handle to evaluate the hessian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h2(iptc), error_h1(iptc), error_l2(iptc), error_h2s(iptc), error_h1s(iptc)] = ... + sp_h2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex, hessuex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + errh2 = sqrt (sum (error_h2 .* error_h2)); + errh2s = sqrt (sum (error_h2s .* error_h2s)); + +end From bfc9166d3b2c621fd5521ad93fd7e7d0820e11ff Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 6 Oct 2017 17:41:31 +0200 Subject: [PATCH 012/366] New function --- .../@sp_multipatch_C1/sp_plot_solution.m | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m new file mode 100644 index 00000000..4175c601 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -0,0 +1,58 @@ +% SP_PLOT_SOLUTION: Plot the computed solution, given the degrees of freedom. +% +% [eu, F] = sp_plot_solution (u, space, geometry, pts, [ncuts=2]); +% [eu, F] = sp_plot_solution (u, space, geometry, [npts], [ncuts=2]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_multipatch_C1) +% geometry: an array of geometry structures (see mp_geo_load) +% pts: cell array with coordinates of points along each parametric direction +% npts: number of points along each parametric direction +% ncuts: only for volumetric domains, number of internal "cuts" in each parametric direction. +% The zero value will plot the solution on the boundary. +% +% Copyright (C) 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_plot_solution (u, space, geometry, npts, ncuts) + +if (nargin < 4) + npts = []; +end +if (nargin < 5) + ncuts = []; +end + +% if (isa (space.sp_patch{1}, 'sp_vector')) +% disp ('Warning: a different scaling is used for each patch') +% end + +hold_flag = ishold ; +for iptc = 1:space.npatch +% if (isempty (space.dofs_ornt)) + sp_plot_solution (space.Cpatch{iptc}* u, space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% else +% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% end + hold on +end + +if (~hold_flag) + hold off +end + +end \ No newline at end of file From 93aaf96328ebc76ed53a24b6bb1f350695d98882 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 10 Oct 2017 16:31:05 +0200 Subject: [PATCH 013/366] Changes in help and comments --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 3902a5d2..339c650a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -18,35 +18,29 @@ % % FIELD_NAME (SIZE) DESCRIPTION % npatch (scalar) number of patches -%XXXX ncomp = 1 ncomp (scalar) number of components of the functions of the space (equal to msh.rdim) +% ncomp (scalar) number of components of the functions of the space (always equal to one) % ndof (scalar) total number of degrees of freedom after gluing patches together % ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing % interior_dofs_per_patch % ndof_interior % ndof_interface % sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -%XXXX transform (string) one of 'grad-preserving', 'curl-preserving' and 'div-preserving' % gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -%XXXX dofs_ornt (1 x npatch cell-array) global orientation of the degrees for freedom, for curl-conforming and div-conforming spaces -%XXXX boundary (1 x 1 object) a (ndim-1) dimensional "sp_multipatch" object for the whole boundary -%XXXX dofs (1 x ndof vector) only for boundary spaces, degrees of freedom that do not vanish on the boundary -%XXXX orientation (1 x ndof vector) only for boundary spaces with 'curl-preserving' transform, global orientation -%XXXX of the boundary dofs with respect to the volumetric one. % constructor function handle function handle to construct the same discrete space in a different msh % -% % % % METHODS -% % % % Methods that give a structure with all the functions computed in a certain subset of the mesh +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh % % % % sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% % % % -% % % % Methods for post-processing, that require a computed vector of degrees of freedom -% % % % sp_h1_error: compute the error in H1 norm -% % % % sp_l2_error: compute the error in L2 norm -% % % % sp_hcurl_error: compute the error in H(curl) norm -% % % % sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% % % % -% % % % Methods for basic connectivity operations -% % % % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% % % % sp_get_cells: compute the cells on which a list of functions do not vanish +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish % % % % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one % % Copyright (C) 2015, 2017 Rafael Vazquez @@ -66,6 +60,8 @@ function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) +% XXX SHOULD ADD A CHECK ABOUT DEGREE AND REGULARITY + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') end @@ -76,7 +72,7 @@ error ('The list of spaces does not correspond to the mesh') end -% XXXX FIX THIS, TO COMPUTE ALSO THE BOUNDARY +% XXX FIX THIS, TO COMPUTE ALSO THE BOUNDARY if (msh.ndim ~= 2 || msh.rdim ~= 2) error ('Only implemented for planar surfaces') end @@ -110,7 +106,8 @@ % Compute the local indices of the functions in V^1 % and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES, AND WITH THE ORDERING IN THE PAPER +% XXX FOR NOW ONLY FOR TWO PATCHES, AND WITH THE ORDERING AS IN THE PAPER +% XXX THE TWO PATCHES ARE ALSO ORIENTED AS IN THE PAPER sp.ndof_interior = 0; for iptc = 1:sp.npatch ndof_dir = sp.sp_patch{iptc}.ndof_dir; @@ -129,8 +126,7 @@ % Computation of the coefficients for basis change % The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% Here we should call the function compute_coefficients below - +% The coefficients for basis change have been stored in CC Cpatch = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); @@ -141,7 +137,7 @@ speye (numel (sp.interior_dofs_per_patch{iptc})); global_indices = (sp.ndof_interior+1):sp.ndof; - Cpatch{iptc}(:,global_indices) = CC{iptc}; % The coefficients computed by Mario + Cpatch{iptc}(:,global_indices) = CC{iptc}; end sp.interfaces = interfaces; From f2d9f72c1987f60e6f5309df076ee21dfba91b21 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 24 Oct 2017 18:12:55 +0200 Subject: [PATCH 014/366] Weak Dirichlet and Neumann boundary conditions. Everything seems to work fine. --- .../sp_weak_drchlt_bc_laplace.m | 95 +++++++++++++++++++ geopdes/inst/multipatch/mp_solve_laplace_C1.m | 36 +++---- 2 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m new file mode 100644 index 00000000..e6242b67 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -0,0 +1,95 @@ +% SP_WEAK_DRCHLT_BC_LAPLACE: compute the matrix and right hand-side to impose +% the Dirichlet boundary conditions in weak form for Laplace (Poisson) problem. +% +% The code computes the following terms in the left hand-side +% +% - \int_{Gamma_D} mu*{du/dn v - dv/dn u + (Cpen / he) * (u v)} +% +% and in the right hand-side +% +% - \int_{Gamma_D} mu*{dv/dn g + (Cpen / he) * (v g)} +% +% with u the trial function, v the test function, he the normal characteristic length, +% and g the boundary condition to be imposed. +% +% +% [N_mat, N_rhs] = sp_weak_drchlt_bc_stokes (space, msh, refs, bnd_func, coeff, Cpen) +% +% INPUTS: +% +% space_v: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch). +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% refs: boundary sides on which the Dirichlet condition is imposed +% bnd_func: the condition to be imposed (g in the equations) +% coeff: function handle for the viscosity coefficient (mu in the equation) +% Cpen: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% N_rhs: the computed right hand-side +% +% Copyright (C) 2014 Adriano Cortes, Rafael Vazquez +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A, rhs] = sp_weak_drchlt_bc_laplace (space, msh, refs, bnd_func, coeff, Cpen, varargin) + + if (nargin < 6 || isempty (Cpen)) + Cpen = 10 * (min (space.sp_patch{1}.degree) + 1); + end + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros (space.ndof, 1); + +% Compute the matrices to impose the tangential boundary condition weakly + for iref = refs + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + + coeff_at_qnodes = coeff (x{:}); + + % Since trial and test spaces are the same, we can use B' + B = op_gradv_n_u (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + gradv_n_g = op_gradv_n_f (sp_bnd, msh_side, g_times_coeff); + + coeff_at_qnodes = coeff_at_qnodes * Cpen ./ msh_side.charlen; + C = op_u_v (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); + + A = A + space.Cpatch{iptc}.' * (B + B' - C) * space.Cpatch{iptc}; + rhs = rhs + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); +% dofs = space.gnum{iptc}; +% A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); +% rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; + end + end + +end diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index 9181e4d8..90bfe344 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -39,7 +39,7 @@ % u: the computed degrees of freedom % % Copyright (C) 2009, 2010 Carlo de Falco -% Copyright (C) 2010, 2011, 2013, 2015 Rafael Vazquez +% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -89,8 +89,8 @@ end msh = msh_multipatch (msh, boundaries); -space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); -space_C1 = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); +% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); clear sp % Compute and assemble the matrices @@ -98,24 +98,28 @@ rhs = op_f_v_mp (space, msh, f); % Apply Neumann boundary conditions -Nbnd = cumsum ([0, boundaries.nsides]); for iref = nmnn_sides - iref_patch_list = Nbnd(iref)+1:Nbnd(iref+1); - gref = @(varargin) g(varargin{:},iref); - rhs_nmnn = op_f_v_mp (space.boundary, msh.boundary, gref, iref_patch_list); - rhs(space.boundary.dofs) = rhs(space.boundary.dofs) + rhs_nmnn; + gref = @(varargin) g(varargin{:}, iref); + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh.msh_patch{iptc}.boundary(iside); + sp_side = space.sp_patch{iptc}.boundary(iside); + rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); + rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; + end end -% Apply Dirichlet boundary conditions -u = zeros (space.ndof, 1); -[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); -u(drchlt_dofs) = u_drchlt; - -int_dofs = setdiff (1:space.ndof, drchlt_dofs); -rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; +% Apply Dirichlet boundary conditions in weak form, by Nitsche's method +if (exist ('weak_drchlt_sides', 'var')) + [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, weak_drchlt_sides, h, c_diff, Cpen); + stiff_mat = stiff_mat - N_mat; + rhs = rhs + N_rhs; +end % Solve the linear system -u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); +u = stiff_mat \ rhs; end From 7848d058c667e8294e6205d69f44cdd6c33db46d Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 25 Oct 2017 11:31:59 +0200 Subject: [PATCH 015/366] Date --- geopdes/inst/solve/solve_laplace_iso.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/solve/solve_laplace_iso.m b/geopdes/inst/solve/solve_laplace_iso.m index 892785e0..2d199774 100644 --- a/geopdes/inst/solve/solve_laplace_iso.m +++ b/geopdes/inst/solve/solve_laplace_iso.m @@ -38,7 +38,7 @@ % See also EX_LAPLACE_ISO_RING and EX_LAPLACE_ISO_THICK_RING for examples. % % Copyright (C) 2009, 2010, 2011 Carlo de Falco -% Copyright (C) 2011, 2015 Rafael Vazquez +% Copyright (C) 2011, 2015, 2017 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by From e543444db3b3e9c7fa7626db3e4407ef3c57c197 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 26 Oct 2017 12:09:46 +0200 Subject: [PATCH 016/366] Arbitrary regularity --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 339c650a..b208e23b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -60,8 +60,6 @@ function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) -% XXX SHOULD ADD A CHECK ABOUT DEGREE AND REGULARITY - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') end @@ -72,21 +70,35 @@ error ('The list of spaces does not correspond to the mesh') end -% XXX FIX THIS, TO COMPUTE ALSO THE BOUNDARY if (msh.ndim ~= 2 || msh.rdim ~= 2) error ('Only implemented for planar surfaces') end + for iptc = 1:numel(geometry) + if (any (geometry(iptc).nurbs.order > 2)) + error ('For now, only bilinear patches are implemented') + end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + sp.ncomp = spaces{1}.ncomp; sp.transform = spaces{1}.transform; -% if (~all ([aux.ncomp] == sp.ncomp)) if (~all ([aux.ncomp] == 1)) error ('The number of components should be the same for all the spaces, and equal to one') end for iptc = 1:sp.npatch -% if (~strcmpi (spaces{iptc}.transform, sp.transform)) if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') end @@ -100,8 +112,8 @@ sp.sp_patch = spaces; % Computation of the number of degrees of freedom -% I need to give a global numbering to the C^1 basis functions -% I start numbering those away from the interface (V^1) patch by patch +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch % And then generate the numbering for the functions close to the interface (V^2) % Compute the local indices of the functions in V^1 @@ -195,33 +207,29 @@ side(1) = interfaces(iref).side1; side(2) = interfaces(iref).side2; - % The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% I assume that the regularity is degree-2, otherwise things become more complicated % Only univariate knot vectors are computed if (side(1) < 3) knots = space.sp_patch{patch(1)}.knots{2}; degree = space.sp_patch{patch(1)}.degree(2); - nel_univ = msh.msh_patch{patch(1)}.nel_dir(2); degu = space.sp_patch{patch(1)}.degree(1); knt = unique (space.sp_patch{patch(1)}.knots{1}); tau1 = knt(2) - knt(1); else knots = space.sp_patch{patch(1)}.knots{1}; degree = space.sp_patch{patch(1)}.degree(1); - nel_univ = msh.msh_patch{patch(1)}.nel_dir(1); degu = space.sp_patch{patch(1)}.degree(2); knt = unique (space.sp_patch{patch(1)}.knots{2}); tau1 = knt(2) - knt(1); end - regularity = degree - 2; - nel_geo = numel (unique (geometry(patch(1)).boundary(side(1)).nurbs.knots)) - 1; - nsub = nel_univ / nel_geo; + breaks = unique (knots); + mult = histc (knots, breaks); + mult0 = mult; mult0(2:end-1) = mult(2:end-1) - 1; + mult1 = mult - 1; + knots0 = kntbrkdegmult (breaks, degree, mult0); % Same degree, regularity + 1 + knots1 = kntbrkdegmult (breaks, degree-1, mult1); % Degree - 1, same regularity - knots0 = kntrefine (geometry(patch(1)).boundary(side(1)).nurbs.knots, nsub-1, degree, regularity+1); - knots1 = kntrefine (geometry(patch(1)).boundary(side(1)).nurbs.knots, nsub-1, degree-1, regularity); - % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) brk = cell (1,msh.ndim); From 65c6f0ea80cf3d5e5a1b469d824e43fc8bc5b3d4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 27 Oct 2017 18:00:17 +0200 Subject: [PATCH 017/366] It works for arbitrary orientation. To be checked --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 145 +++++++++++++----- 1 file changed, 106 insertions(+), 39 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index b208e23b..21519503 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -120,12 +120,16 @@ % and sum them up to get the whole space V^1 % XXX FOR NOW ONLY FOR TWO PATCHES, AND WITH THE ORDERING AS IN THE PAPER % XXX THE TWO PATCHES ARE ALSO ORIENTED AS IN THE PAPER + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end sp.ndof_interior = 0; + sides = [interfaces(1).side1, interfaces(1).side2]; for iptc = 1:sp.npatch - ndof_dir = sp.sp_patch{iptc}.ndof_dir; - xx = 3:ndof_dir(1); yy = 1:ndof_dir(2); - [XX, YY] = ndgrid (xx, yy); - interior_dofs = sub2ind (ndof_dir, XX, YY); +% This should be a loop on the interfaces to which the patch belongs + sp_bnd = spaces{iptc}.boundary(sides(iptc)); + interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); end @@ -199,6 +203,11 @@ end +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) for iref = 1:numel(interfaces) @@ -209,27 +218,19 @@ % The knot vectors for the N0 and N1 basis functions, as in Mario's notation % Only univariate knot vectors are computed - if (side(1) < 3) - knots = space.sp_patch{patch(1)}.knots{2}; - degree = space.sp_patch{patch(1)}.degree(2); - degu = space.sp_patch{patch(1)}.degree(1); - knt = unique (space.sp_patch{patch(1)}.knots{1}); - tau1 = knt(2) - knt(1); - else - knots = space.sp_patch{patch(1)}.knots{1}; - degree = space.sp_patch{patch(1)}.degree(1); - degu = space.sp_patch{patch(1)}.degree(2); - knt = unique (space.sp_patch{patch(1)}.knots{2}); - tau1 = knt(2) - knt(1); - end - - breaks = unique (knots); - mult = histc (knots, breaks); +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(1)/2); + ind1 = setdiff (1:msh.ndim, ind2); + knots_int = space.sp_patch{patch(1)}.knots{ind1}; + degree = space.sp_patch{patch(1)}.degree(ind1); + + breaks = unique (knots_int); + mult = histc (knots_int, breaks); mult0 = mult; mult0(2:end-1) = mult(2:end-1) - 1; mult1 = mult - 1; knots0 = kntbrkdegmult (breaks, degree, mult0); % Same degree, regularity + 1 knots1 = kntbrkdegmult (breaks, degree-1, mult1); % Degree - 1, same regularity - + % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) brk = cell (1,msh.ndim); @@ -245,6 +246,21 @@ end msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + + if (ii == 2 && interfaces(iref).ornt == -1) + knots0 = fliplr (1 - knots0); + knots1 = fliplr (1 - knots1); + end + % For now I assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); % msh_side contains only the univariate parametrization of the boundary (dependence on u) @@ -254,55 +270,85 @@ msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - sp_grev(ii) = struct (sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true)); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element -% The univariate spaces for the N0 and N1 basis functions +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) ind = [2 2 1 1]; - knotsn = sp_aux.knots{ind(side(ii))}; + knotsn = knots{ind(side(ii))}; spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + % Matrix for the linear systems, (14)-(16) in Mario's notes A = sparse (msh_side(ii).nel, msh_side(ii).nel); for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); +% A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); end - alpha{ii} = geopdes_det__ (msh_side_int{ii}.geo_map_jac); - numerator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,1,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - denominator = reshape (sum (msh_side_int{ii}.geo_map_jac(:,2,:,:) .* msh_side_int{ii}.geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); +% XXX This is only valid for the orientation as in the paper + geo_map_jac = msh_side_int{ii}.geo_map_jac; + alpha{ii} = geopdes_det__ (geo_map_jac); + if (side(ii) == 1 || side(ii) == 2) + numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + else +% alpha{ii} = geopdes_det__ (permute (geo_map_jac, [2 1 3 4])); + numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); + end beta{ii} = numerator ./ denominator; % RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_functions(:,:,jj)); + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); end coeff0{ii} = A \ rhss; coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse % RHS for the second linear system, (15) in Mario's notes rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER - val = val * (tau1 / degu)^2; +% val_grad = spn_struct.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER +% val_grad = sp_grev.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER + if (side(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; for jj = 1:msh_side(ii).nel val_aux = val * beta{ii}(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_function_gradients(:,:,:,jj)) * val_aux; + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; +% rhsb(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_function_gradients(:,:,:,jj)) * val_aux; end rhsb = rhsb + rhss; coeff1{ii} = A \ rhsb; coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse % RHS for the third linear system, (16) in Mario's notes +% I need this change of sign to make it work for general orientation. I don't understand why I +% didn't need it in the previous computation. Weird... + val_grad = val_grad * (-1)^(side(ii)+1); + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER - val = val * (tau1 / degu)^2; +% val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER +% val = sp_grev.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER + val = val_grad * (tau1 / degu)^2; for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj); - rhsc(jj,sp1_struct.connectivity(:,jj)) = squeeze (sp1_struct.shape_functions(:,:,jj)) * val_aux; + val_aux = val * abs (alpha{ii}(jj)); + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; +% rhsc(jj,sp1_struct.connectivity(:,jj)) = squeeze (sp1_struct.shape_functions(:,:,jj)) * val_aux; end coeff2{ii} = A \ rhsc; coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse @@ -312,13 +358,34 @@ ndof = sp0_struct.ndof + sp1_struct.ndof; CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); - ind0 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end % ind2 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + if (ii == 2 && interfaces(iref).ornt == -1) + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii}; + CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); end From 6df5e073c12e98a9e8ef3d1ffe8086b18b749e2b Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 30 Oct 2017 16:51:28 +0100 Subject: [PATCH 018/366] Now it works for arbitrary orientation (hopefully) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 21519503..d33ea23e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -292,14 +292,13 @@ % A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); end -% XXX This is only valid for the orientation as in the paper +% Absolute value of the determinant, to make it work for arbitrary orientation geo_map_jac = msh_side_int{ii}.geo_map_jac; - alpha{ii} = geopdes_det__ (geo_map_jac); + alpha{ii} = abs (geopdes_det__ (geo_map_jac)); if (side(ii) == 1 || side(ii) == 2) numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); else -% alpha{ii} = geopdes_det__ (permute (geo_map_jac, [2 1 3 4])); numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); end @@ -315,8 +314,6 @@ % RHS for the second linear system, (15) in Mario's notes rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); -% val_grad = spn_struct.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER -% val_grad = sp_grev.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER if (side(ii) == 1) val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); elseif (side(ii) == 2) @@ -337,18 +334,15 @@ coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse % RHS for the third linear system, (16) in Mario's notes -% I need this change of sign to make it work for general orientation. I don't understand why I -% didn't need it in the previous computation. Weird... +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. val_grad = val_grad * (-1)^(side(ii)+1); rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); -% val = squeeze (spn_struct.shape_function_gradients(:,:,2,1)); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER -% val = sp_grev.shape_function_gradients(1,1,2,1); % XXX THIS IS ONLY VALID FOR THE ORDERING USED IN THE PAPER val = val_grad * (tau1 / degu)^2; for jj = 1:msh_side(ii).nel - val_aux = val * abs (alpha{ii}(jj)); + val_aux = val * alpha{ii}(jj); rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; -% rhsc(jj,sp1_struct.connectivity(:,jj)) = squeeze (sp1_struct.shape_functions(:,:,jj)) * val_aux; end coeff2{ii} = A \ rhsc; coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse @@ -372,7 +366,6 @@ ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); end -% ind2 = sub2ind (space.sp_patch{patch(ii)}.ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); if (ii == 2 && interfaces(iref).ornt == -1) ind0 = fliplr (ind0); @@ -382,7 +375,6 @@ coeff2{2} = flipud (fliplr (coeff2{2})); end - CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); From fae163619bc1a176be5e7f58309f17674a460154 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 31 Oct 2017 10:49:46 +0100 Subject: [PATCH 019/366] Minor things --- .../inst/examples/base/ex_two_patches_C1.m | 41 ++++++++++++------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index 7aba1308..fe495573 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -3,16 +3,20 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file -%nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); -%nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); -nrb(1) = nrb4surf ([0 0], [-4 -1/2], [0 3], [-10/3 16/5]); -nrb(2) = nrb4surf ([0 0], [8/3 -2/5], [0 3], [10/3 23/7]); +% nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); +% nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); +p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; +nrb(1) = nrb4surf (p2, p1, p4, p3); + +p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; +nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; problem_data.geo_name = nrb; % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; -problem_data.drchlt_sides = [1 2 3 4 5 6]; +problem_data.drchlt_sides = []; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; % Physical parameters problem_data.c_diff = @(x, y) ones(size(x)); @@ -28,24 +32,33 @@ reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); + +% problem_data.f = @(x, y) zeros (size(x)); +% problem_data.h = @(x, y, ind) exp(x) .* sin (y); +% problem_data.uex = @(x, y) exp (x) .* sin (y); +% problem_data.graduex = @(x, y) cat (1, ... +% reshape (exp(x).*sin(y), [1, size(x)]), ... +% reshape (exp(x).*cos(y), [1, size(x)])); + % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [4 4]; % Number of subdivisions -method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule +method_data.nsub = [3 3]; % Number of subdivisions +method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); % 3) CALL TO THE SOLVER [geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); -% 4) POST-PROCESSING -% EXPORT TO PARAVIEW -output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; - +% % 4) POST-PROCESSING +% % EXPORT TO PARAVIEW +% output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; +% vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; -fprintf ('The result is saved in the file %s.pvd \n \n', output_file); -sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') - +% fprintf ('The result is saved in the file %s.pvd \n \n', output_file); +% sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') +% figure sp_plot_solution (u, space, geometry, vtk_pts) From 44b2264d46c9b5c3896519153e6e3b319a18babf Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 31 Oct 2017 10:49:59 +0100 Subject: [PATCH 020/366] New function, not finished --- .../sp_evaluate_element_list.m | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m new file mode 100644 index 00000000..a7da09a7 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -0,0 +1,148 @@ +% SP_EVALUATE_ELEMENT_LIST: compute the basis functions in a given list of elements. +% +% sp = sp_evaluate_element_list (space, msh_elems, 'option1', value1, ...) +% +% INPUTS: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh_elems: structure containing the information of quadrature or +% visualization points, for a given list of elements and patches +% (see msh_multipatch/msh_evaluate_element_list) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% hessian | false | compute shape_function_hessians (only scalars) +% laplacian | false | compute shape_function_laplacians (only scalars) +% div | false | compute shape_function_divs (only vectors) +% curl | false | compute shape_function_curls (only vectors) +% +% OUTPUT: +% +% sp: struct representing the discrete function space, with the following fields: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space +% ndof (scalar) total number of degrees of freedom +% nsh (1 x nel) number of non-vanishing functions on each element +% nsh_max (scalar) maximum number of nsh +% connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element +% shape_functions, shape_function_gradients... (see sp_evaluate_col for details) +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_evaluate_element_list (space, msh, varargin) + + is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); + + sp.npatch = space.npatch; + sp.ncomp = space.ncomp; + sp.ndof = space.ndof; + + if (isempty (msh.elem_list)), return, end + + sp.nsh_max = []; + if (is_scalar) + fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', 'shape_function_laplacians'}; + cat_position = [2, 2, 3, 4, 5, 3]; +% else +% fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', ... +% 'shape_function_laplacians', 'shape_function_divs', 'shape_function_curls'}; +% if (msh.ndim == 2 || msh.ndim == 1) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 3]; +% elseif (msh.ndim == 3) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 4]; +% end + end + for ii = 1:numel(fields) + sp.(fields{ii}) = []; + end + + for iptc = 1:space.npatch +% msh_patch = msh_evaluate_element_list (msh.msh_patch{iptc}, msh.elem_list_of_patch{iptc}); % Not working anymore + msh_patch = msh_restrict_to_patch (msh, iptc); + + sp_patch = sp_evaluate_element_list (space.sp_patch{iptc}, msh_patch, varargin{:}); + Cpatch = space.Cpatch{iptc}; + + nsh = zeros (1, msh_patch.nel); + connectivity = zeros (1, msh_patch.nel); + shape_funs = sp_patch.shape_functions; + + for iel = 1:msh_patch.nel + conn_iel = sp_patch.connectivity(:,iel); + [ii,jj] = find (Cpatch(conn_iel,:)); + funs = unique (jj); + nsh(iel) = numel (funs); + connectivity(1:nsh(iel),iel) = funs; + Cpatch_iel = Cpatch(conn_iel, funs); + + shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + end + + sp.nsh = cat (2, sp.nsh, nsh); + sp.connectivity = cat (2, sp.connectivity, connectivity); + sp.shape_functions = cat (3, sp.shape_functions, shape_funs); + +% for ii = 1:numel(fields) +% if (isfield (sp_patch, fields{ii})) +% sp.(fields{ii}) = cat (cat_position(ii), sp.(fields{ii}), sp_patch.(fields{ii})); +% end +% end + end + sp.nsh_max = max (sp.nsh); + + for ii = 1:numel(fields) + if (isempty (sp.(fields{ii}))) + sp = rmfield (sp, fields{ii}); + end + end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSH_RESTRICT_TO_PATCH: extracts the fields corresponding to the selected elements of a given patch, +% from the ones of a mesh struct, computed with msh_multipatch/msh_evaluate_element_list. +% The result is the same as calling msh_cartesian/msh_evaluate_element_list, but avoids recomputing. +% +function msh_ptc = msh_restrict_to_patch (msh, patch) + + msh_ptc.ndim = msh.ndim; + msh_ptc.rdim = msh.rdim; + msh_ptc.elem_list = msh.elem_list_of_patch{patch}(:).'; + + msh_ptc.nel = msh.nel_per_patch(patch); + msh_ptc.nel_dir = msh.nel_dir_of_patch{patch}; + msh_ptc.nqn = msh.nqn; + msh_ptc.nqn_dir = msh.nqn_dir; + + if (isempty (msh_ptc.elem_list)), return, end + + Nelem = cumsum ([0, msh.nel_per_patch]); + + global_elem_list = Nelem(patch)+1:Nelem(patch+1); + msh_ptc.quad_weights = msh.quad_weights(:,global_elem_list); + msh_ptc.geo_map = msh.geo_map(:,:,global_elem_list); + msh_ptc.geo_map_jac = msh.geo_map_jac(:,:,:,global_elem_list); + msh_ptc.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); + msh_ptc.jacdet = msh.jacdet(:,global_elem_list); + msh_ptc.element_size = msh.element_size(:,global_elem_list); + +end \ No newline at end of file From c4e43ce72862f91950e05fdd895fdd4ac1858ee5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 31 Oct 2017 11:51:16 +0100 Subject: [PATCH 021/366] Not nice, but it works --- .../sp_evaluate_element_list.m | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index a7da09a7..082544b2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -83,7 +83,10 @@ nsh = zeros (1, msh_patch.nel); connectivity = zeros (1, msh_patch.nel); - shape_funs = sp_patch.shape_functions; + shape_funs = zeros (msh_patch.nqn, 1, msh_patch.nel); + shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, 1, msh_patch.nel); + shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, 1, msh_patch.nel); + shape_fun_lapl = zeros (msh_patch.nqn, 1, msh_patch.nel); for iel = 1:msh_patch.nel conn_iel = sp_patch.connectivity(:,iel); @@ -93,12 +96,34 @@ connectivity(1:nsh(iel),iel) = funs; Cpatch_iel = Cpatch(conn_iel, funs); - shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + if (isfield (sp_patch, 'shape_functions')) + shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_gradients')) + for idim = 1:msh.rdim + shape_fun_grads(idim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_gradients(idim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + if (isfield (sp_patch, 'shape_function_laplacians')) + shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_hessians')) + for idim = 1:msh.rdim; + for jdim = 1:msh.rdim + shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + end end - + sp.nsh = cat (2, sp.nsh, nsh); sp.connectivity = cat (2, sp.connectivity, connectivity); - sp.shape_functions = cat (3, sp.shape_functions, shape_funs); + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end % for ii = 1:numel(fields) % if (isfield (sp_patch, fields{ii})) From 62325d6a09c20e1c8df83fd782d3b5aad518a82d Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 31 Oct 2017 17:03:48 +0100 Subject: [PATCH 022/366] New function --- .../@sp_multipatch_C1/sp_get_neighbors.m | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m new file mode 100644 index 00000000..36a4ec2c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -0,0 +1,41 @@ +% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions +% +% neighbors_indices = sp_get_neighbors (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% neighbors_indices: indices of the functions that interact with the given ones. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function neighbors_indices = sp_get_neighbors (space, msh, fun_indices) + +neighbors_indices = []; + +for iptc = 1:space.npatch + [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); + neighbors_indices = union (neighbors_indices, global_indices); + end +end + +end From cd67990c7464770c7e383e75e0134f0cccec7f46 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 5 Dec 2017 18:07:08 +0100 Subject: [PATCH 023/366] Store the knots of the auxiliary spaces --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d33ea23e..7dbd0765 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -30,7 +30,7 @@ % % METHODS % Methods that give a structure with all the functions computed in a certain subset of the mesh -% % % % sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements % % Methods for post-processing, that require a computed vector of degrees of freedom % sp_l2_error: compute the error in L2 norm @@ -41,7 +41,7 @@ % Methods for basic connectivity operations % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements % sp_get_cells: compute the cells on which a list of functions do not vanish -% % % % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one % % Copyright (C) 2015, 2017 Rafael Vazquez % @@ -110,6 +110,25 @@ sp.ndof = 0; sp.ndof_per_patch = [aux.ndof]; sp.sp_patch = spaces; + +% Assuming that the starting knot space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; % Computation of the number of degrees of freedom % We need to give a global numbering to the C^1 basis functions @@ -221,16 +240,21 @@ %% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] ind2 = ceil (side(1)/2); ind1 = setdiff (1:msh.ndim, ind2); - knots_int = space.sp_patch{patch(1)}.knots{ind1}; - degree = space.sp_patch{patch(1)}.degree(ind1); +% knots_int = space.sp_patch{patch(1)}.knots{ind1}; +% degree = space.sp_patch{patch(1)}.degree(ind1); - breaks = unique (knots_int); - mult = histc (knots_int, breaks); - mult0 = mult; mult0(2:end-1) = mult(2:end-1) - 1; - mult1 = mult - 1; - knots0 = kntbrkdegmult (breaks, degree, mult0); % Same degree, regularity + 1 - knots1 = kntbrkdegmult (breaks, degree-1, mult1); % Degree - 1, same regularity +% breaks = unique (knots_int); +% mult = histc (knots_int, breaks); +% mult0 = mult; mult0(2:end-1) = mult(2:end-1) - 1; +% mult1 = mult - 1; +% knots0 = kntbrkdegmult (breaks, degree, mult0); % Same degree, regularity + 1 +% knots1 = kntbrkdegmult (breaks, degree-1, mult1); % Degree - 1, same regularity + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(1)}{ind1}; + knots1 = space.knots1_patches{patch(1)}{ind1}; + % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) brk = cell (1,msh.ndim); From dc41cc7395c8a2553bdf7851085ff19cbac044f7 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 5 Dec 2017 18:07:25 +0100 Subject: [PATCH 024/366] Added new function --- .../multipatch/@sp_multipatch_C1/sp_refine.m | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m new file mode 100644 index 00000000..3c8861d4 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -0,0 +1,66 @@ +% SP_REFINE: construct a refined space from a given one. The function only +% refines the space, the mesh must be refined separately. +% +% [sp_fine, Proj] = sp_refine (space, msh, nsub, [degree], [regularity]); +% +% The same number of subdivisions, degree and regularity is applied to every patch +% +% INPUTS: +% +% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch) +% msh: an object of the msh_multipatch class, usuallly the refined mesh (see msh_multipatch) +% nsub: number of uniform subdivisions to apply on each knot span, and for each direction +% degree: degree of the fine space, and for each direction +% regularity: regularity for the new space, and for each direction +% +% OUTPUT: +% +% sp_fine: the refined space, an object of the class sp_multipatch (see sp_multipatch) +% Proj: the coefficients relating 1D splines of the coarse and the fine spaces for each patch. +% A cell-array of size 1 x npatch, each entry containing the +% coefficients for the patch (either for scalar or vector-valued spaces). +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [sp_fine, Proj, Proj0, Proj1] = sp_refine (space, msh, nsub, degree, regularity) + + if (nargin < 4) + degree = space.sp_patch{1}.degree; + end + if (nargin < 5) + regularity = degree - 2; + end + + sp_fine = cell (1, space.npatch); + Proj = cell (1, space.npatch); + Proj0 = cell (1, space.npatch); + Proj1 = cell (1, space.npatch); + for iptc = 1:space.npatch + if (nargout > 1) + [sp_fine{iptc}, Proj{iptc}] = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); +% Refine also the spaces of degree p, regularity r+1; and degree p-1, regularity r + knots0_fine = kntrefine (space.knots0_patches{iptc}, nsub-1, degree, regularity+1); + knots1_fine = kntrefine (space.knots1_patches{iptc}, nsub-1, degree-1, regularity); + for idim = 1:msh.ndim + Proj0{iptc}{idim} = basiskntins (degree(idim), space.knots0_patches{iptc}{idim}, knots0_fine{idim}); + Proj1{iptc}{idim} = basiskntins (degree(idim)-1, space.knots1_patches{iptc}{idim}, knots1_fine{idim}); + end + else + sp_fine = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); + end + end + +end \ No newline at end of file From 27f708d5f3dda2d6d9ca4a18d88e9322852ba776 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Dec 2017 11:01:44 +0100 Subject: [PATCH 025/366] Removed the demo and test part --- .../inst/examples/base/ex_two_patches_C1.m | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index fe495573..ed10db3f 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -65,56 +65,3 @@ % COMPARISON WITH THE EXACT SOLUTION [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) -%!demo -%! ex_laplace_Lshaped_mp - -%!test -%! problem_data.geo_name = 'geo_Lshaped_mp.txt'; -%! problem_data.nmnn_sides = [3 4 5 6]; -%! problem_data.drchlt_sides = [1 2]; -%! problem_data.c_diff = @(x, y) ones(size(x)); -%! problem_data.f = @(x, y) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); -%! problem_data.g = @(x, y, ind) test_Lshaped_mp_g_nmnn (x, y, ind); -%! problem_data.h = @(x, y, ind) exp(x) .* sin (x.*y); -%! problem_data.uex = @(x, y) exp(x) .* sin (x.*y); -%! problem_data.graduex = @(x, y) cat (1, ... -%! reshape ( exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... -%! reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); -%! method_data.degree = [3 3]; % Degree of the splines -%! method_data.regularity = [2 2]; % Regularity of the splines -%! method_data.nsub = [9 9]; % Number of subdivisions -%! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule -%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); -%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); -%! assert (error_l2, 3.00642608570282e-07, 1e-16) -%! assert (error_h1, 1.77524941085757e-05, 1e-16) -%! assert (space.ndof, 408) -%! for iptc = 1:space.boundary.npatch -%! patch = msh.boundary.patch_numbers(iptc); -%! side = msh.boundary.side_numbers(iptc); -%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) -%! end -%! -%! problem_data.geo_name = 'geo_Lshaped_mp_b.txt'; -%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); -%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); -%! assert (error_l2, 3.00642608570282e-07, 1e-16) -%! assert (error_h1, 1.77524941085757e-05, 1e-16) -%! assert (space.ndof, 408) -%! for iptc = 1:space.boundary.npatch -%! patch = msh.boundary.patch_numbers(iptc); -%! side = msh.boundary.side_numbers(iptc); -%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) -%! end -%! -%! problem_data.geo_name = 'geo_Lshaped_mp_c.txt'; -%! [geometry, msh, space, u] = mp_solve_laplace (problem_data, method_data); -%! [error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex); -%! assert (error_l2, 3.00642608570282e-07, 1e-16) -%! assert (error_h1, 1.77524941085757e-05, 1e-16) -%! assert (space.ndof, 408) -%! for iptc = 1:space.boundary.npatch -%! patch = msh.boundary.patch_numbers(iptc); -%! side = msh.boundary.side_numbers(iptc); -%! assert (space.gnum{patch}(space.sp_patch{patch}.boundary(side).dofs)(:), space.boundary.dofs(space.boundary.gnum{iptc})(:)) -%! end From 83dea97eda7da7254eff7ffaadc420db2bf7bde4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Dec 2017 11:03:58 +0100 Subject: [PATCH 026/366] Changed the example --- geopdes/inst/examples/base/ex_two_patches_C1.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index ed10db3f..b7f76238 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -33,18 +33,18 @@ reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); -% problem_data.f = @(x, y) zeros (size(x)); -% problem_data.h = @(x, y, ind) exp(x) .* sin (y); -% problem_data.uex = @(x, y) exp (x) .* sin (y); -% problem_data.graduex = @(x, y) cat (1, ... -% reshape (exp(x).*sin(y), [1, size(x)]), ... -% reshape (exp(x).*cos(y), [1, size(x)])); +problem_data.f = @(x, y) zeros (size(x)); +problem_data.h = @(x, y, ind) exp(y) .* sin (x); +problem_data.uex = @(x, y) exp (y) .* sin (x); +problem_data.graduex = @(x, y) cat (1, ... + reshape (exp(y).*cos(x), [1, size(x)]), ... + reshape (exp(y).*sin(x), [1, size(x)])); % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [3 3]; % Number of subdivisions +method_data.nsub = [2 2]; % Number of subdivisions method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); @@ -55,7 +55,7 @@ % % EXPORT TO PARAVIEW % output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; % -vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; +vtk_pts = {linspace(0, 1, 120), linspace(0, 1, 120)}; % fprintf ('The result is saved in the file %s.pvd \n \n', output_file); % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') % From 755b40d729dc84239124b8a9e6b629af8489084b Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Dec 2017 11:04:35 +0100 Subject: [PATCH 027/366] Minor change in the example --- geopdes/inst/examples/base/ex_two_patches_C1.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index b7f76238..a4f06fad 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -44,7 +44,7 @@ clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [2 2]; % Number of subdivisions +method_data.nsub = [8 8]; % Number of subdivisions method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); @@ -55,7 +55,7 @@ % % EXPORT TO PARAVIEW % output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; % -vtk_pts = {linspace(0, 1, 120), linspace(0, 1, 120)}; +vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; % fprintf ('The result is saved in the file %s.pvd \n \n', output_file); % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') % From c5d949771ecabc9464dd56e949d42a7164fbb679 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Dec 2017 11:36:15 +0100 Subject: [PATCH 028/366] Minor changes for orientation, and using the patch information --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 7dbd0765..6256ab9a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -111,11 +111,12 @@ sp.ndof_per_patch = [aux.ndof]; sp.sp_patch = spaces; -% Assuming that the starting knot space has degree p and regularity r, +% Assuming that the starting space has degree p and regularity r, % r <= p-2, we compute the knot vectors of the auxiliary spaces: % knots0: degree p, regularity r+1. % knots1: degree p-1, regularity r. + knots0 = cell (sp.npatch, 1); knots1 = knots0; for iptc = 1:sp.npatch knots = spaces{iptc}.knots; breaks = cellfun (@unique, knots, 'UniformOutput', false); @@ -137,13 +138,14 @@ % Compute the local indices of the functions in V^1 % and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES, AND WITH THE ORDERING AS IN THE PAPER -% XXX THE TWO PATCHES ARE ALSO ORIENTED AS IN THE PAPER +% XXX FOR NOW ONLY FOR TWO PATCHES if (numel (interfaces) > 1 || msh.npatch > 2) error ('For now, the implementation only works for two patches') end + sp.ndof_interior = 0; +% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 sides = [interfaces(1).side1, interfaces(1).side2]; for iptc = 1:sp.npatch % This should be a loop on the interfaces to which the patch belongs @@ -234,31 +236,21 @@ patch(2) = interfaces(iref).patch2; side(1) = interfaces(iref).side1; side(2) = interfaces(iref).side2; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(1)/2); - ind1 = setdiff (1:msh.ndim, ind2); -% knots_int = space.sp_patch{patch(1)}.knots{ind1}; -% degree = space.sp_patch{patch(1)}.degree(ind1); - -% breaks = unique (knots_int); -% mult = histc (knots_int, breaks); -% mult0 = mult; mult0(2:end-1) = mult(2:end-1) - 1; -% mult1 = mult - 1; -% knots0 = kntbrkdegmult (breaks, degree, mult0); % Same degree, regularity + 1 -% knots1 = kntbrkdegmult (breaks, degree-1, mult1); % Degree - 1, same regularity - - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(1)}{ind1}; - knots1 = space.knots1_patches{patch(1)}{ind1}; % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; for idim = 1:msh.ndim grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); grev_pts{idim} = grev_pts{idim}(:)'; @@ -280,11 +272,6 @@ tau1 = knt(end) - knt(end-1); end - if (ii == 2 && interfaces(iref).ornt == -1) - knots0 = fliplr (1 - knots0); - knots1 = fliplr (1 - knots1); - end - % For now I assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); % msh_side contains only the univariate parametrization of the boundary (dependence on u) @@ -313,7 +300,6 @@ A = sparse (msh_side(ii).nel, msh_side(ii).nel); for jj = 1:msh_side(ii).nel A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); -% A(jj,spn_struct.connectivity(:,jj)) = squeeze (spn_struct.shape_functions(:,:,jj)); end % Absolute value of the determinant, to make it work for arbitrary orientation @@ -351,7 +337,6 @@ for jj = 1:msh_side(ii).nel val_aux = val * beta{ii}(jj); rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; -% rhsb(jj,sp0_struct.connectivity(:,jj)) = squeeze (sp0_struct.shape_function_gradients(:,:,:,jj)) * val_aux; end rhsb = rhsb + rhss; coeff1{ii} = A \ rhsb; From ffd98f9c9e96f97c6d991d55bb9ef99efa0343ad Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Dec 2017 12:07:35 +0100 Subject: [PATCH 029/366] Bug in refinement. Store geometry, to simplify my life --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 1 + geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 6256ab9a..3755591f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -179,6 +179,7 @@ sp.interfaces = interfaces; sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity % XXXX No boundary for now % % Boundary construction diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m index 3c8861d4..f8f87553 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -59,8 +59,10 @@ Proj1{iptc}{idim} = basiskntins (degree(idim)-1, space.knots1_patches{iptc}{idim}, knots1_fine{idim}); end else - sp_fine = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); + sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); end end + sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, []); + end \ No newline at end of file From c06def243722e37da7323732a46313ae77bbc0ae Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 6 Feb 2018 17:00:29 +0100 Subject: [PATCH 030/366] Check number of elements in the patch --- .../@sp_multipatch_C1/sp_evaluate_element_list.m | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 082544b2..e68a54e0 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -119,11 +119,13 @@ end sp.nsh = cat (2, sp.nsh, nsh); - sp.connectivity = cat (2, sp.connectivity, connectivity); - if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end - if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end - if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end - if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end + if (msh_patch.nel > 0) + sp.connectivity = cat (2, sp.connectivity, connectivity); + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end + end % for ii = 1:numel(fields) % if (isfield (sp_patch, fields{ii})) From 61e31f10ccaa4551d16153e125637c02c960c2b5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 21 Feb 2018 10:41:04 +0100 Subject: [PATCH 031/366] Necessary for hierarchical refinement --- .../inst/multipatch/@sp_multipatch_C1/sp_get_cells.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m index 440471ae..874f4e92 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -42,11 +42,11 @@ cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices); -% if (nargout == 2) -% local_funs = local_funs(:).'; -% for ifun = 1:numel(patch_indices) -% indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); -% end -% end + if (nargout == 2) + local_funs = local_funs(:).'; + for ifun = 1:numel(patch_indices) + indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); + end + end end end From 16c5a86ff42278b68eb242766c20c0bb300f9fc7 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 12 Apr 2018 13:58:43 +0200 Subject: [PATCH 032/366] Fixed small bug --- .../multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index e68a54e0..8d034e43 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -82,7 +82,7 @@ Cpatch = space.Cpatch{iptc}; nsh = zeros (1, msh_patch.nel); - connectivity = zeros (1, msh_patch.nel); + connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); shape_funs = zeros (msh_patch.nqn, 1, msh_patch.nel); shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, 1, msh_patch.nel); shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, 1, msh_patch.nel); From 52eb51c80246a538ac5277494bd0d8bfbef4d040 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 12 Apr 2018 15:56:21 +0200 Subject: [PATCH 033/366] Fixed bug if there are less than (p+1)^d functions in all elements --- .../@sp_multipatch_C1/sp_evaluate_element_list.m | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 8d034e43..85072cff 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -83,10 +83,10 @@ nsh = zeros (1, msh_patch.nel); connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); - shape_funs = zeros (msh_patch.nqn, 1, msh_patch.nel); - shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, 1, msh_patch.nel); - shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, 1, msh_patch.nel); - shape_fun_lapl = zeros (msh_patch.nqn, 1, msh_patch.nel); + shape_funs = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_lapl = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); for iel = 1:msh_patch.nel conn_iel = sp_patch.connectivity(:,iel); @@ -138,6 +138,11 @@ for ii = 1:numel(fields) if (isempty (sp.(fields{ii}))) sp = rmfield (sp, fields{ii}); + elseif (ii > 1) + field_size = size (sp.(fields{ii})); + inds = repmat ({':'}, 1, numel(field_size)); + inds{cat_position(ii)-1} = 1:sp.nsh_max; + sp.(fields{ii}) = sp.(fields{ii})(inds{:}); end end From a3fc62f751553d25d6de24f1fd02415702065085 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 15 May 2018 15:13:20 +0200 Subject: [PATCH 034/366] Added field in the help --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 1 + 1 file changed, 1 insertion(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 3755591f..196e7f4f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -27,6 +27,7 @@ % sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) % gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) % constructor function handle function handle to construct the same discrete space in a different msh +% Cpatch (1 x npatch cell-array) write C^1 basis functions as lin. comb. of B-splines on the patch % % METHODS % Methods that give a structure with all the functions computed in a certain subset of the mesh From 30be700c668511c734b8910d6e24df1ba608909b Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 31 Jan 2019 17:09:50 +0100 Subject: [PATCH 035/366] New version by Cesare --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 224 ++++++++++++++++-- 1 file changed, 203 insertions(+), 21 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 196e7f4f..db3d5163 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -27,7 +27,6 @@ % sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) % gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) % constructor function handle function handle to construct the same discrete space in a different msh -% Cpatch (1 x npatch cell-array) write C^1 basis functions as lin. comb. of B-splines on the patch % % METHODS % Methods that give a structure with all the functions computed in a certain subset of the mesh @@ -74,11 +73,12 @@ if (msh.ndim ~= 2 || msh.rdim ~= 2) error ('Only implemented for planar surfaces') end + - for iptc = 1:numel(geometry) - if (any (geometry(iptc).nurbs.order > 2)) - error ('For now, only bilinear patches are implemented') - end + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end knots = spaces{iptc}.knots; breaks = cellfun (@unique, knots, 'UniformOutput', false); mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); @@ -231,13 +231,146 @@ % And for val_grad, I have to change the sign for coeff2, but not for coeff1 % But everything seems to work!!! -function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) +function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) + for iref = 1:numel(interfaces) patch(1) = interfaces(iref).patch1; patch(2) = interfaces(iref).patch2; side(1) = interfaces(iref).side1; side(2) = interfaces(iref).side2; + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector + DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... + (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + +alpha0_n(1)^2+alpha0_n(2)^2; + C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + gamma=-C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) @@ -304,17 +437,9 @@ A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); end -% Absolute value of the determinant, to make it work for arbitrary orientation - geo_map_jac = msh_side_int{ii}.geo_map_jac; - alpha{ii} = abs (geopdes_det__ (geo_map_jac)); - if (side(ii) == 1 || side(ii) == 2) - numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - else - numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); - end - beta{ii} = numerator ./ denominator; +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; % RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); @@ -326,7 +451,7 @@ % RHS for the second linear system, (15) in Mario's notes rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) + if (side(ii) == 1) %paper case val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); elseif (side(ii) == 2) val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); @@ -336,7 +461,7 @@ val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); end val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel + for jj = 1:msh_side(ii).nel %paper case - check beta val_aux = val * beta{ii}(jj); rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; end @@ -350,7 +475,7 @@ val_grad = val_grad * (-1)^(side(ii)+1); rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad * (tau1 / degu)^2; + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) for jj = 1:msh_side(ii).nel val_aux = val * alpha{ii}(jj); rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; @@ -390,7 +515,64 @@ CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); end - + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} end From 2b42096dbe758a67b5a9aec4385d03ce867a3cac Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Mon, 25 May 2020 12:24:34 +0200 Subject: [PATCH 036/366] multipatch C^1 spaces added (not working yet) --- .../@sp_multipatch_C1/mp_solve_laplace_C1.m | 133 +++ .../multipatch/@sp_multipatch_C1/op_f_v_mp.m | 51 ++ .../op_gradgradu_gradgradv_mp.m | 54 ++ .../@sp_multipatch_C1/op_gradu_gradv_mp.m | 54 ++ .../op_laplaceu_laplacev_mp.m | 55 ++ .../multipatch/@sp_multipatch_C1/op_u_v_mp.m | 61 ++ .../@sp_multipatch_C1/solve_laplace.m | 139 +++ .../sp_evaluate_element_list.m | 180 ++++ .../sp_get_basis_functions.m | 41 + .../@sp_multipatch_C1/sp_get_cells.m | 52 ++ .../@sp_multipatch_C1/sp_get_neighbors.m | 41 + .../@sp_multipatch_C1/sp_h1_error.m | 54 ++ .../@sp_multipatch_C1/sp_h2_error.m | 59 ++ .../@sp_multipatch_C1/sp_l2_error.m | 48 + .../@sp_multipatch_C1/sp_multipatch_C1.m | 818 ++++++++++++++++++ .../@sp_multipatch_C1/sp_plot_solution.m | 58 ++ .../multipatch/@sp_multipatch_C1/sp_refine.m | 68 ++ .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 82 ++ .../sp_weak_drchlt_bc_laplace.m | 95 ++ .../multipatch/@sp_multipatch_C1/subsasgn.m | 4 + .../multipatch/@sp_multipatch_C1/subsref.m | 4 + 21 files changed, 2151 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m new file mode 100644 index 00000000..903b622f --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m @@ -0,0 +1,133 @@ +% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. +% +% Example to solve the diffusion problem +% +% - div ( epsilon(x) grad (u)) = f in Omega +% epsilon(x) du/dn = g on Gamma_N +% u = h on Gamma_D +% +% where the domain \Omega is formed by several patches of the form F((0,1)^n). +% +% USAGE: +% +% [geometry, msh, space, u] = +% mp_solve_laplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: array of geometry structures (see geo_load) +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% u: the computed degrees of freedom +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 2 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_laplace_C1 (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +msh = msh_multipatch (msh, boundaries); +% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); +clear sp + +% Compute and assemble the matrices +stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); +rhs = op_f_v_mp (space, msh, f); + +% Apply Neumann boundary conditions +for iref = nmnn_sides + gref = @(varargin) g(varargin{:}, iref); + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh.msh_patch{iptc}.boundary(iside); + sp_side = space.sp_patch{iptc}.boundary(iside); + rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); + rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; + end +end + +% Apply Dirichlet boundary conditions in weak form, by Nitsche's method +if (exist ('weak_drchlt_sides', 'var')) + [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, weak_drchlt_sides, h, c_diff, Cpen); + stiff_mat = stiff_mat - N_mat; + rhs = rhs + N_rhs; +end + +% Solve the linear system +u = stiff_mat \ rhs; + +end + +%!demo +%! ex_laplace_Lshaped_mp + +%!demo +%! ex_laplace_cube_mp + +%!demo +%! ex_laplace_thick_L_mp diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m new file mode 100644 index 00000000..561a3415 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m @@ -0,0 +1,51 @@ +% OP_F_V_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% +% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_v_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_v_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_v_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + +% if (~isempty (space.dofs_ornt)) +% rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); +% end + rhs = rhs + space.Cpatch{iptc}.' * rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m new file mode 100644 index 00000000..7abebba3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADGRADU_GRADGRADV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon grad grad u_j, grad grad v_i), in a multipatch domain. +% +% mat = op_gradgradu_gradgradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradgradu_gradgradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradgradu_gradgradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m new file mode 100644 index 00000000..953bba5b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADU_GRADV_MP: assemble the stiffness matrix A = [a(i,j)], a(i,j) = (epsilon grad u_j, grad v_i), in a multipatch domain. +% +% mat = op_gradu_gradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled stiffness matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradu_gradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradu_gradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m new file mode 100644 index 00000000..55ba64ac --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m @@ -0,0 +1,55 @@ +% OP_LAPLACEU_LAPLACEV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon laplace u_j, laplace v_i), in a multipatch domain. +% +% mat = op_laplaceu_laplacev_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_laplaceu_laplacev_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_laplaceu_laplacev_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m new file mode 100644 index 00000000..06151fde --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m @@ -0,0 +1,61 @@ +% OP_U_V_MP: assemble the mass matrix M = [m(i,j)], m(i,j) = (mu u_j, v_i), in a multipatch domain. +% +% mat = op_u_v_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled mass matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_u_v_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_u_v_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + +% if (~isempty (spv.dofs_ornt)) +% vs = spv.dofs_ornt{iptc}(rs)' .* vs; +% end +% if (~isempty (spu.dofs_ornt)) +% vs = vs .* spu.dofs_ornt{iptc}(cs)'; +% end + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m new file mode 100644 index 00000000..73dc7df5 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m @@ -0,0 +1,139 @@ +% SOLVE_LAPLACE: Solve a Laplace problem with a B-spline discretization (non-isoparametric approach). +% +% The function solves the diffusion problem +% +% - div ( epsilon(x) grad (u)) = f in Omega = F((0,1)^n) +% epsilon(x) du/dn = g on Gamma_N +% u = h on Gamma_D +% +% USAGE: +% +% [geometry, msh, space, u] = solve_laplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete space (see sp_scalar) +% u: the computed degrees of freedom +% +% See also EX_LAPLACE_SQUARE, EX_LAPLACE_THICK_RING for examples. +% +% Copyright (C) 2009, 2010, 2011 Carlo de Falco +% Copyright (C) 2011, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + solve_laplace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure +geometry = geo_load (geo_name); + +[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); + +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (zeta, rule); +msh = msh_cartesian (zeta, qn, qw, geometry); + +% Construct space structure +space = sp_bspline (knots, degree, msh); + +% Assemble the matrices +stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); +rhs = op_f_v_tp (space, msh, f); + +% Apply Neumann boundary conditions +for iside = nmnn_sides + if (msh.ndim > 1) +% Restrict the function handle to the specified side, in any dimension, gside = @(x,y) g(x,y,iside) + gside = @(varargin) g(varargin{:},iside); + dofs = space.boundary(iside).dofs; + rhs(dofs) = rhs(dofs) + op_f_v_tp (space.boundary(iside), msh.boundary(iside), gside); + else + if (iside == 1) + x = msh.breaks{1}(1); + else + x = msh.breaks{1}(end); + end + sp_side = space.boundary(iside); + rhs(sp_side.dofs) = rhs(sp_side.dofs) + g(x,iside); + end +end + +% Apply Dirichlet boundary conditions +u = zeros (space.ndof, 1); +[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); +u(drchlt_dofs) = u_drchlt; + +int_dofs = setdiff (1:space.ndof, drchlt_dofs); +rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; + +% Solve the linear system +u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); + +end + +%!demo +%! ex_laplace_square + +%!demo +%! ex_laplace_plate + +%!demo +%! ex_laplace_ring + +%!demo +%! ex_laplace_ring_mixed_bc + +%!demo +%! ex_laplace_cube + +%!demo +%! ex_laplace_thick_ring + +%!demo +%! ex_laplace_beltrami + +%!demo +%! ex_laplace_1d diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m new file mode 100644 index 00000000..85072cff --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -0,0 +1,180 @@ +% SP_EVALUATE_ELEMENT_LIST: compute the basis functions in a given list of elements. +% +% sp = sp_evaluate_element_list (space, msh_elems, 'option1', value1, ...) +% +% INPUTS: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh_elems: structure containing the information of quadrature or +% visualization points, for a given list of elements and patches +% (see msh_multipatch/msh_evaluate_element_list) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% hessian | false | compute shape_function_hessians (only scalars) +% laplacian | false | compute shape_function_laplacians (only scalars) +% div | false | compute shape_function_divs (only vectors) +% curl | false | compute shape_function_curls (only vectors) +% +% OUTPUT: +% +% sp: struct representing the discrete function space, with the following fields: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space +% ndof (scalar) total number of degrees of freedom +% nsh (1 x nel) number of non-vanishing functions on each element +% nsh_max (scalar) maximum number of nsh +% connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element +% shape_functions, shape_function_gradients... (see sp_evaluate_col for details) +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_evaluate_element_list (space, msh, varargin) + + is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); + + sp.npatch = space.npatch; + sp.ncomp = space.ncomp; + sp.ndof = space.ndof; + + if (isempty (msh.elem_list)), return, end + + sp.nsh_max = []; + if (is_scalar) + fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', 'shape_function_laplacians'}; + cat_position = [2, 2, 3, 4, 5, 3]; +% else +% fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', ... +% 'shape_function_laplacians', 'shape_function_divs', 'shape_function_curls'}; +% if (msh.ndim == 2 || msh.ndim == 1) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 3]; +% elseif (msh.ndim == 3) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 4]; +% end + end + for ii = 1:numel(fields) + sp.(fields{ii}) = []; + end + + for iptc = 1:space.npatch +% msh_patch = msh_evaluate_element_list (msh.msh_patch{iptc}, msh.elem_list_of_patch{iptc}); % Not working anymore + msh_patch = msh_restrict_to_patch (msh, iptc); + + sp_patch = sp_evaluate_element_list (space.sp_patch{iptc}, msh_patch, varargin{:}); + Cpatch = space.Cpatch{iptc}; + + nsh = zeros (1, msh_patch.nel); + connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); + shape_funs = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_lapl = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + + for iel = 1:msh_patch.nel + conn_iel = sp_patch.connectivity(:,iel); + [ii,jj] = find (Cpatch(conn_iel,:)); + funs = unique (jj); + nsh(iel) = numel (funs); + connectivity(1:nsh(iel),iel) = funs; + Cpatch_iel = Cpatch(conn_iel, funs); + + if (isfield (sp_patch, 'shape_functions')) + shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_gradients')) + for idim = 1:msh.rdim + shape_fun_grads(idim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_gradients(idim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + if (isfield (sp_patch, 'shape_function_laplacians')) + shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_hessians')) + for idim = 1:msh.rdim; + for jdim = 1:msh.rdim + shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + end + end + + sp.nsh = cat (2, sp.nsh, nsh); + if (msh_patch.nel > 0) + sp.connectivity = cat (2, sp.connectivity, connectivity); + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end + end + +% for ii = 1:numel(fields) +% if (isfield (sp_patch, fields{ii})) +% sp.(fields{ii}) = cat (cat_position(ii), sp.(fields{ii}), sp_patch.(fields{ii})); +% end +% end + end + sp.nsh_max = max (sp.nsh); + + for ii = 1:numel(fields) + if (isempty (sp.(fields{ii}))) + sp = rmfield (sp, fields{ii}); + elseif (ii > 1) + field_size = size (sp.(fields{ii})); + inds = repmat ({':'}, 1, numel(field_size)); + inds{cat_position(ii)-1} = 1:sp.nsh_max; + sp.(fields{ii}) = sp.(fields{ii})(inds{:}); + end + end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSH_RESTRICT_TO_PATCH: extracts the fields corresponding to the selected elements of a given patch, +% from the ones of a mesh struct, computed with msh_multipatch/msh_evaluate_element_list. +% The result is the same as calling msh_cartesian/msh_evaluate_element_list, but avoids recomputing. +% +function msh_ptc = msh_restrict_to_patch (msh, patch) + + msh_ptc.ndim = msh.ndim; + msh_ptc.rdim = msh.rdim; + msh_ptc.elem_list = msh.elem_list_of_patch{patch}(:).'; + + msh_ptc.nel = msh.nel_per_patch(patch); + msh_ptc.nel_dir = msh.nel_dir_of_patch{patch}; + msh_ptc.nqn = msh.nqn; + msh_ptc.nqn_dir = msh.nqn_dir; + + if (isempty (msh_ptc.elem_list)), return, end + + Nelem = cumsum ([0, msh.nel_per_patch]); + + global_elem_list = Nelem(patch)+1:Nelem(patch+1); + msh_ptc.quad_weights = msh.quad_weights(:,global_elem_list); + msh_ptc.geo_map = msh.geo_map(:,:,global_elem_list); + msh_ptc.geo_map_jac = msh.geo_map_jac(:,:,:,global_elem_list); + msh_ptc.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); + msh_ptc.jacdet = msh.jacdet(:,global_elem_list); + msh_ptc.element_size = msh.element_size(:,global_elem_list); + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m new file mode 100644 index 00000000..76edf5c8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m @@ -0,0 +1,41 @@ +% SP_GET_BASIS_FUNCTIONS: Compute the indices of tensor-product B-splines acting on a list of cells. +% +% fun_indices = sp_get_basis_functions (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the cells. +% +% OUTPUT: +% fun_indices: indices of the basis functions acting on the cells. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function function_indices = sp_get_basis_functions (space, msh, cell_indices) + +function_indices = []; +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [~,local_cell_indices,~] = intersect ((Nelem(iptc)+1):Nelem(iptc+1), cell_indices); + if (~isempty (local_cell_indices)) + aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); + [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); + function_indices = union (function_indices, dofs); + end +end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m new file mode 100644 index 00000000..874f4e92 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -0,0 +1,52 @@ +% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function. +% +% [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% cell_indices: indices of the cells within the support of the basis functions. +% indices_per_function: indices of the cells within the support of each basis function. +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [cell_indices, indices_per_function] = sp_get_cells (space, msh, fun_indices) + +fun_indices = fun_indices(:).'; + +indices_per_function = cell (numel (fun_indices), 1); +cell_indices = []; + +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + patch_indices = patch_indices(:).'; + [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + + cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices); + + if (nargout == 2) + local_funs = local_funs(:).'; + for ifun = 1:numel(patch_indices) + indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); + end + end + end +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m new file mode 100644 index 00000000..36a4ec2c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -0,0 +1,41 @@ +% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions +% +% neighbors_indices = sp_get_neighbors (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% neighbors_indices: indices of the functions that interact with the given ones. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function neighbors_indices = sp_get_neighbors (space, msh, fun_indices) + +neighbors_indices = []; + +for iptc = 1:space.npatch + [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); + neighbors_indices = union (neighbors_indices, global_indices); + end +end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m new file mode 100644 index 00000000..f727b7d2 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m @@ -0,0 +1,54 @@ +% SP_H1_ERROR: Evaluate the error in H^1 norm. +% +% [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% +% OUTPUT: +% +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h1(iptc), error_l2(iptc), error_h1s(iptc)] = ... + sp_h1_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m new file mode 100644 index 00000000..a40be7cb --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -0,0 +1,59 @@ +% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% hessuex: function handle to evaluate the hessian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h2(iptc), error_h1(iptc), error_l2(iptc), error_h2s(iptc), error_h1s(iptc)] = ... + sp_h2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex, hessuex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + errh2 = sqrt (sum (error_h2 .* error_h2)); + errh2s = sqrt (sum (error_h2s .* error_h2s)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m new file mode 100644 index 00000000..abbbc9ef --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -0,0 +1,48 @@ +% SP_L2_ERROR: Evaluate the error in L^2 norm. +% +% errl2 = sp_l2_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% +% OUTPUT: +% +% errl2: error in L^2 norm +% +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function errl2 = sp_l2_error (space, msh, u, uex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m new file mode 100644 index 00000000..357b368a --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -0,0 +1,818 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces) + patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; + sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_vertices +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, vertices); + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + for iptc_on_interface = 1:2 + iptc = interface(intrfc).patches(iptc_on_interface); + Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; + end + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) + +p = space.sp_patch{1}.degree(1); +k=numel(msh.msh_patch{1}.breaks{1})-2; + +all_alpha0=zeros(numel(interfaces),2); +all_alpha1=zeros(numel(interfaces),2); +all_beta0=zeros(numel(interfaces),2); +all_beta1=zeros(numel(interfaces),2); +all_t0=zeros(numel(interfaces),2); + +%Initialize the cell array of CC_vertices matrices +for ii=1:space.npatch + for jj=numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end +%Initialize the cell array of CC_edges matrices +for jj=1:numel(interfaces) + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch1), ndof_per_interface(jj)); + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch2), ndof_per_interface(jj)); +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +brk = cell (1,msh.ndim); +for j=1:space.npatch + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1}=[0 1]'; + pts{2}=[0 1]'; + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + derivatives1{j}=msh_precompute (msh_pts_der1); %rdim x ndim x n_pts{1}x n_pts{2} + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + derivatives2{j}=msh_precompute (msh_pts_der2); %rdim x ndim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) + %At this point (check) + %D_u F^j(0,0)=squeeze(derivatives{j}(:,1,1)) + %D_u F^j(0,1)=squeeze(derivatives{j}(:,1,2)) + %D_u F^j(1,0)=squeeze(derivatives{j}(:,1,3)) + %D_u F^j(1,1)=squeeze(derivatives{j}(:,1,4)) + %D_v F^j(0,0)=squeeze(derivatives{j}(:,2,1)) + %D_v F^j(0,1)=squeeze(derivatives{j}(:,2,2)) + %D_v F^j(1,0)=squeeze(derivatives{j}(:,2,3)) + %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) +end + +%Construction of CC_edges +for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; %LEFT + patch(2) = interfaces(iref).patch2; %RIGHT + side(1) = interfaces(iref).side1; %LEFT + side(2) = interfaces(iref).side2; %RIGHT + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = 1:2 % The two patches (L-R) + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector + DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma=3*C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + %Saving alphas and betas (first column=L, second column=R) + all_alpha0(iref,:)=alpha0; + all_alpha1(iref,:)=alpha1; + all_beta0(iref,:)=beta0; + all_beta1(iref,:)=beta1; + %Saving t(0) + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces(iref).ornt == -1) %this should be still the same for the multipatch + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + ind0_s{iref}=ind0; %saving the indices for later use; + ind1_s{iref}=ind1; + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is he interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +%I actually need to consider the actual parametrization to compute d, t and sigma, don't I? + +for kver=1:numel(vertices) + + ver_patches=[];%vector with indices of patches containing the vertex + ver_ind=[];%vector containing local index of vertex in the patch + sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) + for h=1:numel(vertices(kver).interfaces) + hint=vertices(kver).interfaces(h); + ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; + ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).loc_vertex)... + sides(interfaces(hint).side2,vertices(kver).loc_vertex)]; + end + ver_patches=unique(ver_patches); + ver_ind=unique(ver_ind); + + nu=numel(vertices(kver).interfaces)-1; + MM=cell(2,nu,numel(vertices)); + V=cell(nu,numel(vertices)); + E=cell(nu+1,numel(vertices)); + for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) + inter=vertices(kver).interface(im).glob_ind; %global index of the interface + patch_ind1=interfaces(vertices(kver).interface(im)).patch1; %global index of left patch of im-th interface + %patch_ind2=interfaces(vertices(kver).interface(im)).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces(vertices(kver).interfaces(im)).side1,vertices(kver).loc_vertex); %local index of vertex in left patch + %vertex_ind2=vertices(kver).interface(im).vertex2; %local index of vertex in right patch + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? + case 1 %vertex (0,0) + t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); + t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); + d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1)))... + /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); + d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1))... + +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives2{patch_ind1}(:,2,2,1)... + +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... + /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); + mix_der2(im,:)=derivatives2{patch_ind1}(:,1,2,1); + + %Pick the correct part of CC_edges_discarded{ii,iref} + if vertices(kver).loc_vertex==1 + E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + else + E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); + end +% case 2 %vertex (1,0) +% t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); +% t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); +% case 3 %vertex (1,1) +% t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,4)); +% t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,4)); +% case 4 %vertex (0,1) +% t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,2)); +% t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,2)); + end + end + %compute sigma + sigma=0; + for im=1:nu + vertex_ind=ver_ind(im); %local index of the vertex in im-th pacth + patch_ind=ver_patches(im); %global index of the im-th patch + %this works only for the standard configuration + sigma=sigma+norm([derivatives1{patch_ind}(1,1,1) derivatives1{vertices(kver).patches(im).patch_i}(2,2,1)]); + end + sigma=1/(sigma/(p*(k+1)*nu)); + + %computing matrices MM and V + for im=1:nu + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) + n2=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) + j=0; + for j1=0:2 + for j2=0:2-j1 %the following computations work in the standard case + d00=(j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im,:)'; + d20_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im,:)'; + d11_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im,:)'; + MM{1,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im+1,:)'; + d20_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im+1,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im+1,:)'; + d11_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im+1,:)'; + MM{2,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + %V_{i_m,i} + d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; + V{im,kver}=zeros(n1*n2,6); + + side1=interfaces(vertices(kver).interface(im)).side1; %side of left patch + switch side1 %only case 3 (standard) is correct + case 1 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + case 2 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + case 3 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + case 4 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + end + j=j+1; + end + end + CC_vertices{vertices(kver).patches(im).patch_i,kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; + end +end + + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m new file mode 100644 index 00000000..4175c601 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -0,0 +1,58 @@ +% SP_PLOT_SOLUTION: Plot the computed solution, given the degrees of freedom. +% +% [eu, F] = sp_plot_solution (u, space, geometry, pts, [ncuts=2]); +% [eu, F] = sp_plot_solution (u, space, geometry, [npts], [ncuts=2]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_multipatch_C1) +% geometry: an array of geometry structures (see mp_geo_load) +% pts: cell array with coordinates of points along each parametric direction +% npts: number of points along each parametric direction +% ncuts: only for volumetric domains, number of internal "cuts" in each parametric direction. +% The zero value will plot the solution on the boundary. +% +% Copyright (C) 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_plot_solution (u, space, geometry, npts, ncuts) + +if (nargin < 4) + npts = []; +end +if (nargin < 5) + ncuts = []; +end + +% if (isa (space.sp_patch{1}, 'sp_vector')) +% disp ('Warning: a different scaling is used for each patch') +% end + +hold_flag = ishold ; +for iptc = 1:space.npatch +% if (isempty (space.dofs_ornt)) + sp_plot_solution (space.Cpatch{iptc}* u, space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% else +% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% end + hold on +end + +if (~hold_flag) + hold off +end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m new file mode 100644 index 00000000..f8f87553 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -0,0 +1,68 @@ +% SP_REFINE: construct a refined space from a given one. The function only +% refines the space, the mesh must be refined separately. +% +% [sp_fine, Proj] = sp_refine (space, msh, nsub, [degree], [regularity]); +% +% The same number of subdivisions, degree and regularity is applied to every patch +% +% INPUTS: +% +% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch) +% msh: an object of the msh_multipatch class, usuallly the refined mesh (see msh_multipatch) +% nsub: number of uniform subdivisions to apply on each knot span, and for each direction +% degree: degree of the fine space, and for each direction +% regularity: regularity for the new space, and for each direction +% +% OUTPUT: +% +% sp_fine: the refined space, an object of the class sp_multipatch (see sp_multipatch) +% Proj: the coefficients relating 1D splines of the coarse and the fine spaces for each patch. +% A cell-array of size 1 x npatch, each entry containing the +% coefficients for the patch (either for scalar or vector-valued spaces). +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [sp_fine, Proj, Proj0, Proj1] = sp_refine (space, msh, nsub, degree, regularity) + + if (nargin < 4) + degree = space.sp_patch{1}.degree; + end + if (nargin < 5) + regularity = degree - 2; + end + + sp_fine = cell (1, space.npatch); + Proj = cell (1, space.npatch); + Proj0 = cell (1, space.npatch); + Proj1 = cell (1, space.npatch); + for iptc = 1:space.npatch + if (nargout > 1) + [sp_fine{iptc}, Proj{iptc}] = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); +% Refine also the spaces of degree p, regularity r+1; and degree p-1, regularity r + knots0_fine = kntrefine (space.knots0_patches{iptc}, nsub-1, degree, regularity+1); + knots1_fine = kntrefine (space.knots1_patches{iptc}, nsub-1, degree-1, regularity); + for idim = 1:msh.ndim + Proj0{iptc}{idim} = basiskntins (degree(idim), space.knots0_patches{iptc}{idim}, knots0_fine{idim}); + Proj1{iptc}{idim} = basiskntins (degree(idim)-1, space.knots1_patches{iptc}{idim}, knots1_fine{idim}); + end + else + sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); + end + end + sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, []); + + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m new file mode 100644 index 00000000..e3d71569 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -0,0 +1,82 @@ +% SP_TO_VTK: Export multipatch results to VTK format for plotting. +% +% sp_to_vtk (u, space, geometry, npts, filename, fieldnames, [option], [lambda_lame, mu_lame]) +% +% INPUT: +% +% u: vector of dof weights +% space: object representing the space of discrete functions (see sp_multipatch) +% geometry: geometry structure (see geo_load) +% npts: number of points along each parametric direction where to evaluate +% filename: name of the output file. +% fieldnames: how to name the saved variables in the vtk file +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient', +% and for vectors also 'curl', 'divergence', 'stress' +% lambda_lame: function handle to the first Lame coefficient (only needed to compute 'stress') +% mu_lame: function handle for the second Lame coefficient (only needed to compute 'stress') +% +% OUTPUT: +% +% none +% +% Copyright (C) 2010 Carlo de Falco, Rafael Vazquez +% Copyright (C) 2011, 2012, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) + + str1 = cat (2,' \n', ... +' \n', ... +' \n'); + + str2 = cat (2, ' \n'); + + str3 = cat (2, ... +'\n', ... +' \n'); + + if (length (filename) < 4 || ~strcmp (filename(end-3:end), '.pvd')) + pvd_filename = cat (2, filename, '.pvd'); + else + pvd_filename = filename; + filename = filename (1:end-4); + end + + fid = fopen (pvd_filename, 'w'); + if (fid < 0) + error ('mp_sp_to_vtk: could not open file %s', pvd_filename); + end + + fprintf (fid, str1); + ind = union (find (filename == '/', 1, 'last'), find (filename == '\', 1, 'last')) + 1; + if (isempty (ind)); ind = 1; end + for iptc = 1:space.npatch + filename_patch_without_path = cat (2, filename(ind:end), '_', num2str (iptc)); + filename_patch = cat (2, filename, '_', num2str (iptc)); + fprintf (fid, str2, iptc, filename_patch_without_path); +% if (isempty (space.dofs_ornt)) + sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + filename_patch, fieldname, varargin{:}) +% else +% sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... +% filename_patch, fieldname, varargin{:}) +% end + end + fprintf (fid, str3); + + fclose (fid); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m new file mode 100644 index 00000000..f36aa68d --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -0,0 +1,95 @@ +% SP_WEAK_DRCHLT_BC_LAPLACE: compute the matrix and right hand-side to impose +% the Dirichlet boundary conditions in weak form for Laplace (Poisson) problem. +% +% The code computes the following terms in the left hand-side +% +% - \int_{Gamma_D} mu*{du/dn v - dv/dn u + (Cpen / he) * (u v)} +% +% and in the right hand-side +% +% - \int_{Gamma_D} mu*{dv/dn g + (Cpen / he) * (v g)} +% +% with u the trial function, v the test function, he the normal characteristic length, +% and g the boundary condition to be imposed. +% +% +% [N_mat, N_rhs] = sp_weak_drchlt_bc_stokes (space, msh, refs, bnd_func, coeff, Cpen) +% +% INPUTS: +% +% space_v: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch). +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% refs: boundary sides on which the Dirichlet condition is imposed +% bnd_func: the condition to be imposed (g in the equations) +% coeff: function handle for the viscosity coefficient (mu in the equation) +% Cpen: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% N_rhs: the computed right hand-side +% +% Copyright (C) 2014 Adriano Cortes, Rafael Vazquez +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A, rhs] = sp_weak_drchlt_bc_laplace (space, msh, refs, bnd_func, coeff, Cpen, varargin) + + if (nargin < 6 || isempty (Cpen)) + Cpen = 10 * (min (space.sp_patch{1}.degree) + 1); + end + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros (space.ndof, 1); + +% Compute the matrices to impose the tangential boundary condition weakly + for iref = refs + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + + coeff_at_qnodes = coeff (x{:}); + + % Since trial and test spaces are the same, we can use B' + B = op_gradv_n_u (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + gradv_n_g = op_gradv_n_f (sp_bnd, msh_side, g_times_coeff); + + coeff_at_qnodes = coeff_at_qnodes * Cpen ./ msh_side.charlen; + C = op_u_v (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); + + A = A + space.Cpatch{iptc}.' * (B + B' - C ) * space.Cpatch{iptc}; + rhs = rhs + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); +% dofs = space.gnum{iptc}; +% A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); +% rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; + end + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m b/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m new file mode 100644 index 00000000..1c89450c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/subsasgn.m @@ -0,0 +1,4 @@ +%% override private write access of objects in this class +function obj = subsasgn (obj, S, value) +obj = builtin('subsasgn', obj, S, value); +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m b/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m new file mode 100644 index 00000000..9f7048b6 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/subsref.m @@ -0,0 +1,4 @@ +%% override private read access of object data +function value = subsref (obj, S) +value = builtin ('subsref', obj, S); +end \ No newline at end of file From 3b4957f7530242a146bd9461a5341fe52b320df3 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 29 May 2020 18:27:49 +0200 Subject: [PATCH 037/366] added function to construct structures of vertices and interfaces (including boundaries), plus test example --- .../multipatch/multipatch_bilin_geo_example.m | 12 ++ geopdes/inst/multipatch/vertices_struct.asv | 107 +++++++++++++++++ geopdes/inst/multipatch/vertices_struct.m | 109 ++++++++++++++++++ 3 files changed, 228 insertions(+) create mode 100644 geopdes/inst/multipatch/multipatch_bilin_geo_example.m create mode 100644 geopdes/inst/multipatch/vertices_struct.asv create mode 100644 geopdes/inst/multipatch/vertices_struct.m diff --git a/geopdes/inst/multipatch/multipatch_bilin_geo_example.m b/geopdes/inst/multipatch/multipatch_bilin_geo_example.m new file mode 100644 index 00000000..0baeec30 --- /dev/null +++ b/geopdes/inst/multipatch/multipatch_bilin_geo_example.m @@ -0,0 +1,12 @@ +clear all + +p1=[0 0]; p2=[1 0]; p3=[0 1]; p4=[1 1]; p5=[2,0]; p6=[2,1]; +p7=[0 -1]; p8=[1 -1]; p9=[2 -1]; +nrb(1) = nrb4surf(p2,p4,p1,p3); +nrb(2) = nrb4surf(p2,p5,p4,p6); +nrb(3) = nrb4surf(p2,p8,p5,p9); +nrb(4) = nrb4surf(p2,p1,p8,p7); +problem_data.geometry = nrb; + +[geometry, boundaries, interfaces, subdomains, boundary_interfaces] = mp_geo_load (nrb); +[interfaces_all, vertices] = vertices_struct(boundaries, interfaces); \ No newline at end of file diff --git a/geopdes/inst/multipatch/vertices_struct.asv b/geopdes/inst/multipatch/vertices_struct.asv new file mode 100644 index 00000000..cfbf1a27 --- /dev/null +++ b/geopdes/inst/multipatch/vertices_struct.asv @@ -0,0 +1,107 @@ +function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) + +%INPUT: boundaries and interfaces as given by mp_geo_load +%OUTPUT: structures containing 1) for each interfaces (included boundaries)2);for each vertex the list of interfaces +%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) + +%interfaces=interfaces_i +N_int=numel(interfaces_i); +interfaces=interfaces_i; +for h=1:numel(boundaries) + interfaces(N_int+h).patch1=boundaries(h).patches; + interfaces(N_int+h).patch2=[]; + interfaces(N_int+h).side1=boundaries(h).faces; + interfaces(N_int+h).side2=[]; +end + +%initialize vertices +ivertices=[]; + +nv=0; +for i=1:numel(interfaces) + patches_i=[interfaces(i).patch1 interfaces(i).patch2]; + sides_i=[interfaces(i).side1 interfaces(i).side2]; + for j=i+1:numel(interfaces) + patches_j=[interfaces(j).patch1 interfaces(j).patch2]; + sides_j=[interfaces(j).side1 interfaces(j).side2]; + [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); + cside_i=sides_i(cpatch_indi); + cside_j=sides_j(cpatch_indj); + if numel(cpatch)>0 %if vertex found + switch cside_i + case 1 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 2 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + case 3 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 4 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + end + end + end +end + +%vertices=ivertices; + +vertices(1)=ivertices(1); +nv=1; + +for i=2:numel(ivertices) +inter_i=ivertices(i).interfaces; +ind_i=ivertices(i).ind; +info_i=[inter_i' ind_i']; + flag_new=1; + for j=1:numel(vertices) + inter_j=vertices(j).interfaces; + ind_j=vertices(j).ind; + info_j=[inter_j' ind_j']; + if numel(intersect(info_i,info_j,'rows'))>0 + [vertices(j).interfaces,indu,indb]=unique([vertices(j).interfaces ivertices(i).interfaces]); + vertices(j).ind=[vertices(j).ind ivertices(i).ind]; + vertices(j).ind=vertices(j).ind(indu); + flag_new=0; + break + end + end + if flag_new==1 + nv=nv+1; + vertices(nv)=ivertices(i); + end +end + + +end + diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m new file mode 100644 index 00000000..2b7649b0 --- /dev/null +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -0,0 +1,109 @@ +function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) + +%INPUT: boundaries and interfaces as given by mp_geo_load +%OUTPUT: structures containing 1) for each interfaces (included boundaries) indices of the djacent patches +%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces +%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) + +%interfaces=interfaces_i +N_int=numel(interfaces_i); +interfaces=interfaces_i; +for h=1:numel(boundaries) + interfaces(N_int+h).patch1=boundaries(h).patches; + interfaces(N_int+h).patch2=[]; + interfaces(N_int+h).side1=boundaries(h).faces; + interfaces(N_int+h).side2=[]; + interfaces(N_int+h).ornt=[]; +end + +%initialize vertices +ivertices=[]; + +nv=0; +for i=1:numel(interfaces) + patches_i=[interfaces(i).patch1 interfaces(i).patch2]; + sides_i=[interfaces(i).side1 interfaces(i).side2]; + for j=i+1:numel(interfaces) + patches_j=[interfaces(j).patch1 interfaces(j).patch2]; + sides_j=[interfaces(j).side1 interfaces(j).side2]; + [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); + cside_i=sides_i(cpatch_indi); + cside_j=sides_j(cpatch_indj); + if numel(cpatch)>0 %if vertex found + switch cside_i + case 1 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 2 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + case 3 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 4 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + end + end + end +end + +%vertices=ivertices; + +vertices(1)=ivertices(1); +nv=1; + +for i=2:numel(ivertices) +inter_i=ivertices(i).interfaces; +ind_i=ivertices(i).ind; +info_i=[inter_i' ind_i']; + flag_new=1; + for j=1:numel(vertices) + inter_j=vertices(j).interfaces; + ind_j=vertices(j).ind; + info_j=[inter_j' ind_j']; + if numel(intersect(info_i,info_j,'rows'))>0 + [vertices(j).interfaces,indu,~]=unique([vertices(j).interfaces ivertices(i).interfaces]); + vertices(j).ind=[vertices(j).ind ivertices(i).ind]; + vertices(j).ind=vertices(j).ind(indu); + flag_new=0; + break + end + end + if flag_new==1 + nv=nv+1; + vertices(nv)=ivertices(i); + end +end + + +end + From 81643e917df49b29e0c63296d865bac8454cc20b Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 9 Oct 2020 16:45:23 +0200 Subject: [PATCH 038/366] Minor updates to the multipatch C^1 constructor --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 59 ++++++---- geopdes/inst/multipatch/vertices_struct.asv | 107 ------------------ 2 files changed, 40 insertions(+), 126 deletions(-) delete mode 100644 geopdes/inst/multipatch/vertices_struct.asv diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 357b368a..034befeb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -59,7 +59,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, boundaries) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') @@ -184,7 +184,7 @@ % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, vertices); + compute_coefficients (sp, msh, geometry, interfaces, boundaries); sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions @@ -279,7 +279,9 @@ % And for val_grad, I have to change the sign for coeff2, but not for coeff1 % But everything seems to work!!! -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces, vertices] = vertices_struct(boundaries, interfaces); p = space.sp_patch{1}.degree(1); k=numel(msh.msh_patch{1}.breaks{1})-2; @@ -327,6 +329,7 @@ %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) end + %Construction of CC_edges for iref = 1:numel(interfaces) patch(1) = interfaces(iref).patch1; %LEFT @@ -335,6 +338,7 @@ side(2) = interfaces(iref).side2; %RIGHT %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + if ~isempty(patch(1)) && ~isempty(patch(2)) %if it's not a boundary edge... for ii = 1:2 % The two patches (L-R) %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions brk = cell (1,msh.ndim); @@ -468,16 +472,22 @@ beta1(2)= c+d*beta1(1); %R end - + else %if it's a boundary edge, we a (canonical) choice of alphas and betas only on one side + alpha0(1)=NaN; alpha1(1)=NaN; + alpha0(2)=1; alpha1(2)=1; + beta0(1)=NaN; beta1(1)=NaN; + beta0(2)=1; beta1(2)=0; + end + %Saving alphas and betas (first column=L, second column=R) all_alpha0(iref,:)=alpha0; all_alpha1(iref,:)=alpha1; all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %Saving t(0) + all_beta1(iref,:)=beta1; % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) + if ~isempty(patch(ii)) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -624,6 +634,7 @@ %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end end %CHECKING G^1 condition @@ -712,33 +723,43 @@ V=cell(nu,numel(vertices)); E=cell(nu+1,numel(vertices)); for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) - inter=vertices(kver).interface(im).glob_ind; %global index of the interface + inter=vertices(kver).interface(im); %global index of the interface patch_ind1=interfaces(vertices(kver).interface(im)).patch1; %global index of left patch of im-th interface %patch_ind2=interfaces(vertices(kver).interface(im)).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces(vertices(kver).interfaces(im)).side1,vertices(kver).loc_vertex); %local index of vertex in left patch + vertex_ind1=sides(interfaces(vertices(kver).interfaces(im)).side1,vertices(kver).ind); %local index of vertex in left patch %vertex_ind2=vertices(kver).interface(im).vertex2; %local index of vertex in right patch + vertex_indi=vertices(kver).ind(im); %local index of vertex in interface %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? + switch vertex_indi %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? case 1 %vertex (0,0) t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)+(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1)))... /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); - d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)+(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1))... - +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... + +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)+(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives2{patch_ind1}(:,2,2,1)... - +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... + -(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); mix_der2(im,:)=derivatives2{patch_ind1}(:,1,2,1); + E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - %Pick the correct part of CC_edges_discarded{ii,iref} - if vertices(kver).loc_vertex==1 - E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - else - E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); - end + case 2 %vertex (1,0) + t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); + t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); + d0(im,:)=(squeeze(-derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(0)... + +all_beta1(inter,1)*1)*derivatives1{patch_ind1}(:,2,1)))... + /(all_alpha0(inter,1)*(0)+all_alpha0(inter,1)*1); + d0p(im,:)=((all_alpha0(inter,1)*(0)+all_alpha0(inter,1)*1)*squeeze(-derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(0)... + +all_beta1(inter,1)*1)*derivatives1{patch_ind1}(:,2,1))... + +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(-derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(0)... + +all_beta1(inter,1)*1)*derivatives2{patch_ind1}(:,2,2,1)... + +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... + /((-all_alpha0(inter,1)*0+all_alpha1(inter,1)*1)^2); + mix_der2(im,:)=-derivatives2{patch_ind1}(:,1,2,1); + E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); % case 2 %vertex (1,0) % t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); % t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); diff --git a/geopdes/inst/multipatch/vertices_struct.asv b/geopdes/inst/multipatch/vertices_struct.asv deleted file mode 100644 index cfbf1a27..00000000 --- a/geopdes/inst/multipatch/vertices_struct.asv +++ /dev/null @@ -1,107 +0,0 @@ -function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) - -%INPUT: boundaries and interfaces as given by mp_geo_load -%OUTPUT: structures containing 1) for each interfaces (included boundaries)2);for each vertex the list of interfaces -%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) - -%interfaces=interfaces_i -N_int=numel(interfaces_i); -interfaces=interfaces_i; -for h=1:numel(boundaries) - interfaces(N_int+h).patch1=boundaries(h).patches; - interfaces(N_int+h).patch2=[]; - interfaces(N_int+h).side1=boundaries(h).faces; - interfaces(N_int+h).side2=[]; -end - -%initialize vertices -ivertices=[]; - -nv=0; -for i=1:numel(interfaces) - patches_i=[interfaces(i).patch1 interfaces(i).patch2]; - sides_i=[interfaces(i).side1 interfaces(i).side2]; - for j=i+1:numel(interfaces) - patches_j=[interfaces(j).patch1 interfaces(j).patch2]; - sides_j=[interfaces(j).side1 interfaces(j).side2]; - [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); - cside_i=sides_i(cpatch_indi); - cside_j=sides_j(cpatch_indj); - if numel(cpatch)>0 %if vertex found - switch cside_i - case 1 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 2 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - case 3 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 4 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - end - end - end -end - -%vertices=ivertices; - -vertices(1)=ivertices(1); -nv=1; - -for i=2:numel(ivertices) -inter_i=ivertices(i).interfaces; -ind_i=ivertices(i).ind; -info_i=[inter_i' ind_i']; - flag_new=1; - for j=1:numel(vertices) - inter_j=vertices(j).interfaces; - ind_j=vertices(j).ind; - info_j=[inter_j' ind_j']; - if numel(intersect(info_i,info_j,'rows'))>0 - [vertices(j).interfaces,indu,indb]=unique([vertices(j).interfaces ivertices(i).interfaces]); - vertices(j).ind=[vertices(j).ind ivertices(i).ind]; - vertices(j).ind=vertices(j).ind(indu); - flag_new=0; - break - end - end - if flag_new==1 - nv=nv+1; - vertices(nv)=ivertices(i); - end -end - - -end - From 9f25279b376af6ed9ffa93281a65f52ccb0482a6 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 16 Oct 2020 17:32:43 +0200 Subject: [PATCH 039/366] Fixed indices of patches and interfaces related to each vertex, function to build vertices structure from boundaries and interfaces added --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 88 ++++++-------- .../@sp_multipatch_C1/vertices_struct.m | 108 ++++++++++++++++++ 2 files changed, 144 insertions(+), 52 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 034befeb..71643d19 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -59,7 +59,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, boundaries) +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') @@ -179,12 +179,13 @@ % ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) % CC_vertices: cell array of size npatch x numel(vertices) % The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_vertices +% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; % % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, boundaries); + compute_coefficients (sp, msh, geometry, interfaces, vertices); sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions @@ -279,9 +280,10 @@ % And for val_grad, I have to change the sign for coeff2, but not for coeff1 % But everything seems to work!!! -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) -[interfaces, vertices] = vertices_struct(boundaries, interfaces); +%ndof_per_interface: still to be computed! +%ndof_per_vertex: still to be computed! p = space.sp_patch{1}.degree(1); k=numel(msh.msh_patch{1}.breaks{1})-2; @@ -329,7 +331,6 @@ %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) end - %Construction of CC_edges for iref = 1:numel(interfaces) patch(1) = interfaces(iref).patch1; %LEFT @@ -338,7 +339,6 @@ side(2) = interfaces(iref).side2; %RIGHT %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - if ~isempty(patch(1)) && ~isempty(patch(2)) %if it's not a boundary edge... for ii = 1:2 % The two patches (L-R) %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions brk = cell (1,msh.ndim); @@ -472,22 +472,16 @@ beta1(2)= c+d*beta1(1); %R end - else %if it's a boundary edge, we a (canonical) choice of alphas and betas only on one side - alpha0(1)=NaN; alpha1(1)=NaN; - alpha0(2)=1; alpha1(2)=1; - beta0(1)=NaN; beta1(1)=NaN; - beta0(2)=1; beta1(2)=0; - end - + %Saving alphas and betas (first column=L, second column=R) all_alpha0(iref,:)=alpha0; all_alpha1(iref,:)=alpha1; all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; + all_beta1(iref,:)=beta1; + %Saving t(0) % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) - if ~isempty(patch(ii)) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -521,7 +515,7 @@ tau1 = knt(end) - knt(end-1); end -% For now I assume that the orientation is as in the paper, and we do not need any reordering +% For now we assume that the orientation is as in the paper, and we do not need any reordering %XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); % msh_side contains only the univariate parametrization of the boundary (dependence on u) % msh_side_int contains information for the bivariate parametrization (dependence on u and v) @@ -634,7 +628,6 @@ %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); - end end %CHECKING G^1 condition @@ -700,20 +693,21 @@ %We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is he interface between +%vertices(kver).interface(im) is the interface between %vertices(kver).patches(im) and vertices(kver).patches(im+1) %I actually need to consider the actual parametrization to compute d, t and sigma, don't I? for kver=1:numel(vertices) + %This has to be updated using vertices (or already done? check!) ver_patches=[];%vector with indices of patches containing the vertex ver_ind=[];%vector containing local index of vertex in the patch sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) for h=1:numel(vertices(kver).interfaces) hint=vertices(kver).interfaces(h); ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; - ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).loc_vertex)... - sides(interfaces(hint).side2,vertices(kver).loc_vertex)]; + ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... + sides(interfaces(hint).side2,vertices(kver).ind)]; end ver_patches=unique(ver_patches); ver_ind=unique(ver_ind); @@ -723,43 +717,33 @@ V=cell(nu,numel(vertices)); E=cell(nu+1,numel(vertices)); for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) - inter=vertices(kver).interface(im); %global index of the interface - patch_ind1=interfaces(vertices(kver).interface(im)).patch1; %global index of left patch of im-th interface - %patch_ind2=interfaces(vertices(kver).interface(im)).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces(vertices(kver).interfaces(im)).side1,vertices(kver).ind); %local index of vertex in left patch - %vertex_ind2=vertices(kver).interface(im).vertex2; %local index of vertex in right patch - vertex_indi=vertices(kver).ind(im); %local index of vertex in interface + inter=vertices(kver).interfaces(im); %global index of the interface + patch_ind1=interfaces(inter).patch1; %global index of left patch of im-th interface + %do we need the same for the right patch? + vertex_ind1=sides(interfaces(inter).side1,vertices(kver).ind); %local index of vertex in left patch + %do we need the same for the right patch? %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_indi %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? + switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? case 1 %vertex (0,0) t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)+(all_beta0(inter,1)*(1-0)... + d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1)))... /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); - d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)+(all_beta0(inter,1)*(1-0)... + d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1))... - +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)+(all_beta0(inter,1)*(1-0)... + +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... +all_beta1(inter,1)*0)*derivatives2{patch_ind1}(:,2,2,1)... - -(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... + +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); mix_der2(im,:)=derivatives2{patch_ind1}(:,1,2,1); - E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - case 2 %vertex (1,0) - t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); - t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - d0(im,:)=(squeeze(-derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(0)... - +all_beta1(inter,1)*1)*derivatives1{patch_ind1}(:,2,1)))... - /(all_alpha0(inter,1)*(0)+all_alpha0(inter,1)*1); - d0p(im,:)=((all_alpha0(inter,1)*(0)+all_alpha0(inter,1)*1)*squeeze(-derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(0)... - +all_beta1(inter,1)*1)*derivatives1{patch_ind1}(:,2,1))... - +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(-derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(0)... - +all_beta1(inter,1)*1)*derivatives2{patch_ind1}(:,2,2,1)... - +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... - /((-all_alpha0(inter,1)*0+all_alpha1(inter,1)*1)^2); - mix_der2(im,:)=-derivatives2{patch_ind1}(:,1,2,1); - E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); + %Pick the correct part of CC_edges_discarded{ii,iref} + if vertices(kver).loc_vertex==1 + E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + else + E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); + end % case 2 %vertex (1,0) % t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); % t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); @@ -774,18 +758,18 @@ %compute sigma sigma=0; for im=1:nu - vertex_ind=ver_ind(im); %local index of the vertex in im-th pacth + vertex_ind=ver_ind(im); %local index of the vertex in im-th patch patch_ind=ver_patches(im); %global index of the im-th patch %this works only for the standard configuration - sigma=sigma+norm([derivatives1{patch_ind}(1,1,1) derivatives1{vertices(kver).patches(im).patch_i}(2,2,1)]); + sigma=sigma+norm([derivatives1{patch_ind}(1,1,1) derivatives1{patch_ind}(2,2,1)]); end sigma=1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V for im=1:nu %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) - n2=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) + n1=space.sp_patch{patch_ind}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) + n2=space.sp_patch{patch_ind}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) j=0; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case @@ -831,7 +815,7 @@ j=j+1; end end - CC_vertices{vertices(kver).patches(im).patch_i,kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; + CC_vertices{ver_patches(im),kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m b/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m new file mode 100644 index 00000000..fa731bb7 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m @@ -0,0 +1,108 @@ +function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) + +%INPUT: boundaries and (interior) interfaces as given by mp_geo_load +%OUTPUT: structures containing 1) for each interface (included boundaries) indices of the adjacent patches +%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces +%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) + +N_int=numel(interfaces_i); +interfaces=interfaces_i; +for h=1:numel(boundaries) + interfaces(N_int+h).patch1=boundaries(h).patches; + interfaces(N_int+h).patch2=[]; + interfaces(N_int+h).side1=boundaries(h).faces; + interfaces(N_int+h).side2=[]; + interfaces(N_int+h).ornt=[]; +end + +%initialize vertices +ivertices=[]; + +nv=0; +for i=1:numel(interfaces) + patches_i=[interfaces(i).patch1 interfaces(i).patch2]; + sides_i=[interfaces(i).side1 interfaces(i).side2]; + for j=i+1:numel(interfaces) + patches_j=[interfaces(j).patch1 interfaces(j).patch2]; + sides_j=[interfaces(j).side1 interfaces(j).side2]; + [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); + cside_i=sides_i(cpatch_indi); + cside_j=sides_j(cpatch_indj); + if numel(cpatch)>0 %if vertex found + switch cside_i + case 1 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 2 + if cside_j==3 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==4 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + case 3 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 1]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 1]; + end + case 4 + if cside_j==1 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[1 2]; + elseif cside_j==2 + nv=nv+1; %increase number of vertices + ivertices(nv).interfaces=[i j]; + ivertices(nv).ind=[2 2]; + end + end + end + end +end + +%vertices=ivertices; + +vertices(1)=ivertices(1); +nv=1; + +for i=2:numel(ivertices) +inter_i=ivertices(i).interfaces; +ind_i=ivertices(i).ind; +info_i=[inter_i' ind_i']; + flag_new=1; + for j=1:numel(vertices) + inter_j=vertices(j).interfaces; + ind_j=vertices(j).ind; + info_j=[inter_j' ind_j']; + if numel(intersect(info_i,info_j,'rows'))>0 + [vertices(j).interfaces,indu,~]=unique([vertices(j).interfaces ivertices(i).interfaces]); + vertices(j).ind=[vertices(j).ind ivertices(i).ind]; + vertices(j).ind=vertices(j).ind(indu); + flag_new=0; + break + end + end + if flag_new==1 + nv=nv+1; + vertices(nv)=ivertices(i); + end +end + + +end + From fe70ebfa3ff058201ef7cef06761f829e835ac26 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Thu, 26 Nov 2020 16:26:32 +0100 Subject: [PATCH 040/366] Correct computation of t,d,sigma quantities for theconstruction of vertex functions according to the local orientation of the patch --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 183 +++++++++++------- 1 file changed, 108 insertions(+), 75 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 5a368bd1..c5673758 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -230,6 +230,7 @@ % I HAVE FINISHED MY CHANGES HERE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % XXXX No boundary for now % % Boundary construction % if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) @@ -316,18 +317,33 @@ pts{1}=[0 1]'; pts{2}=[0 1]'; msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - derivatives1{j}=msh_precompute (msh_pts_der1); %rdim x ndim x n_pts{1}x n_pts{2} + msh_der1{j}=msh_precompute (msh_pts_der1); + derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - derivatives2{j}=msh_precompute (msh_pts_der2); %rdim x ndim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) - %At this point (check) - %D_u F^j(0,0)=squeeze(derivatives{j}(:,1,1)) - %D_u F^j(0,1)=squeeze(derivatives{j}(:,1,2)) - %D_u F^j(1,0)=squeeze(derivatives{j}(:,1,3)) - %D_u F^j(1,1)=squeeze(derivatives{j}(:,1,4)) - %D_v F^j(0,0)=squeeze(derivatives{j}(:,2,1)) - %D_v F^j(0,1)=squeeze(derivatives{j}(:,2,2)) - %D_v F^j(1,0)=squeeze(derivatives{j}(:,2,3)) - %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) + msh_der2{j}=msh_precompute (msh_pts_der2); + derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + %In this case (rdim=2) + %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space + %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) + %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) + %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) + %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) + %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) + %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) + %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) + + %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space + %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) + %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) + %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) + %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) + %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) + %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) + %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) + %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) + %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) + %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) + %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) end %Construction of CC_edges @@ -365,8 +381,6 @@ end %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector @@ -378,8 +392,6 @@ else v=grev_pts{1}'; end -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; if rank(A_full)==6 @@ -699,80 +711,94 @@ %vertices(kver).interface(im) is the interface between %vertices(kver).patches(im) and vertices(kver).patches(im+1) %I actually need to consider the actual parametrization to compute d, t and sigma, don't I? +MM=cell(2,numel(vertices)); +V=cell(numel(vertices),1); +E=cell(numel(vertices),1); +%Previously: +%MM=cell(2,nu,numel(vertices)); +%V=cell(nu,numel(vertices)); +%E=cell(nu+1,numel(vertices)); +sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) for kver=1:numel(vertices) - %This has to be updated using vertices (or already done? check!) + %Everything must be updated by using interfaces_all instead of interfaces TO DO ver_patches=[];%vector with indices of patches containing the vertex ver_ind=[];%vector containing local index of vertex in the patch - sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - for h=1:numel(vertices(kver).interfaces) - hint=vertices(kver).interfaces(h); - ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; - ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... - sides(interfaces(hint).side2,vertices(kver).ind)]; - end - ver_patches=unique(ver_patches); - ver_ind=unique(ver_ind); - nu=numel(vertices(kver).interfaces)-1; - MM=cell(2,nu,numel(vertices)); - V=cell(nu,numel(vertices)); - E=cell(nu+1,numel(vertices)); + +% for h=1:numel(vertices(kver).interfaces) +% hint=vertices(kver).interfaces(h); +% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; +% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... +% sides(interfaces(hint).side2,vertices(kver).ind)]; +% end +% ver_patches=unique(ver_patches,'stable'); +% ver_ind=unique(ver_ind,'stable'); + for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) inter=vertices(kver).interfaces(im); %global index of the interface patch_ind1=interfaces(inter).patch1; %global index of left patch of im-th interface - %do we need the same for the right patch? - vertex_ind1=sides(interfaces(inter).side1,vertices(kver).ind); %local index of vertex in left patch - %do we need the same for the right patch? + patch_ind2=interfaces(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + ver_patches=[ver_patches patch_ind1 patch_ind2]; + ver_ind=[ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? + switch vertex_ind1 case 1 %vertex (0,0) - t0(im,:)=squeeze(derivatives1{patch_ind1}(:,2,1)); - t0p(im,:)=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - d0(im,:)=(squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1)))... - /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); - d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{patch_ind1}(:,1,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives1{patch_ind1}(:,2,1))... - +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{patch_ind1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives2{patch_ind1}(:,2,2,1)... - +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{patch_ind1}(:,2,1)))... - /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); - mix_der2(im,:)=derivatives2{patch_ind1}(:,1,2,1); - - %Pick the correct part of CC_edges_discarded{ii,iref} - if vertices(kver).loc_vertex==1 - E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - else - E{im,kver}=CC_edges_discarded{ii,iref}(:,[4 5 6 9 10]); - end -% case 2 %vertex (1,0) -% t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); -% t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); -% case 3 %vertex (1,1) -% t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,4)); -% t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,4)); -% case 4 %vertex (0,1) -% t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,2)); -% t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,2)); - end + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); + end + t0(im,:)=Dv_F00; + t0p(im,:)=Dvv_F00; + d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... + /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); + d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... + -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... + ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + %Pick the correct part of CC_edges_discarded %TO DO + if vertices(kver).ind(im)==1 + E{kver}{im,1}=CC_edges_discarded{ii,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + else + E{kver}{im,2}=CC_edges_discarded{ii,inter}(:,[4 5 6 9 10]); + end end + ver_patches=unique(ver_patches,'stable'); + ver_ind=unique(ver_ind,'stable'); %compute sigma sigma=0; for im=1:nu - vertex_ind=ver_ind(im); %local index of the vertex in im-th patch + %vertex_ind=ver_ind(im); %local index of the vertex in im-th patch patch_ind=ver_patches(im); %global index of the im-th patch %this works only for the standard configuration - sigma=sigma+norm([derivatives1{patch_ind}(1,1,1) derivatives1{patch_ind}(2,2,1)]); + sigma=sigma+norm([Du_F00(1) Dv_F00(2)]); end sigma=1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V for im=1:nu %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{patch_ind}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) - n2=space.sp_patch{patch_ind}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) + n1=space.sp_patch{patch_ind}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2=space.sp_patch{patch_ind}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) j=0; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case @@ -784,7 +810,7 @@ d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im,:)'; d11_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im,:)'+... [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im,:)'; - MM{1,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; %M_{i_{m+1},i} d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im+1,:)'; @@ -793,33 +819,40 @@ d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im+1,:)'; d11_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im+1,:)'+... [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im+1,:)'; - MM{2,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; - V{im,kver}=zeros(n1*n2,6); + V{kver}{im}=zeros(n1*n2,6); - side1=interfaces(vertices(kver).interface(im)).side1; %side of left patch + side1=interfaces(vertices(kver).interfaces(im)).side1; %side of left patch switch side1 %only case 3 (standard) is correct case 1 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; case 2 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; case 3 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; case 4 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; end j=j+1; end end - CC_vertices{ver_patches(im),kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; + CC_vertices{ver_patches(im),kver} = E{kver}{im}*MM{1,kver}{im} + E{kver}{im+1}*MM{2,kver}{im} + V{kver}{im}; end end + end + +%TO DO: +%- case of boundary edges +%- do modifications to handle different orientations (in basic case) +%- compute number of ndof per edge, per vertex +%- write clear algorithm for the whole construction? From 3fb993d4f6acf6e280d57f98390ceef0a6f446a5 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 2 Dec 2020 17:49:26 +0100 Subject: [PATCH 041/366] In the computation of vertex functions: numbering of interfaces/patches fixed, assembly of matrices MM and V simplified --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 74 +++++++++++-------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index c5673758..c4d694c9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -280,7 +280,10 @@ % And for val_grad, I have to change the sign for coeff2, but not for coeff1 % But everything seems to work!!! -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); %update the whole function using all_interfaces +%TO DO: for each interior vertex, the first and last interface must coincide %ndof_per_interface: still to be computed! %ndof_per_vertex: still to be computed! @@ -710,7 +713,6 @@ %We assume that the local numbering of interfaces and patches is such that %vertices(kver).interface(im) is the interface between %vertices(kver).patches(im) and vertices(kver).patches(im+1) -%I actually need to consider the actual parametrization to compute d, t and sigma, don't I? MM=cell(2,numel(vertices)); V=cell(numel(vertices),1); E=cell(numel(vertices),1); @@ -724,8 +726,9 @@ %Everything must be updated by using interfaces_all instead of interfaces TO DO ver_patches=[];%vector with indices of patches containing the vertex + ver_patches_nabla=[]; %TO CHECK WHAT THIS MUST CONTAIN EXACTLY and modify accordingly ver_ind=[];%vector containing local index of vertex in the patch - nu=numel(vertices(kver).interfaces)-1; + nu=numel(vertices(kver).interfaces); % for h=1:numel(vertices(kver).interfaces) % hint=vertices(kver).interfaces(h); @@ -736,7 +739,7 @@ % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); - for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) + for im=1:nu %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) inter=vertices(kver).interfaces(im); %global index of the interface patch_ind1=interfaces(inter).patch1; %global index of left patch of im-th interface patch_ind2=interfaces(inter).patch2; %global index of right patch of im-th interface @@ -751,21 +754,25 @@ Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); + %ver_patches_nabla=[#ind1 #ind2] case 2 %vertex (0,1) Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + %ver_patches_nabla=[#ind1 #ind2] case 3 %vertex (1,0) Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + %ver_patches_nabla=[#ind1 #ind2] case 4 %vertex (1,1) Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); + %ver_patches_nabla=[#ind1 #ind2] end t0(im,:)=Dv_F00; t0p(im,:)=Dvv_F00; @@ -774,8 +781,9 @@ d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... - ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - %Pick the correct part of CC_edges_discarded %TO DO + ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + mix_der2(im,:)=Duv_F00; + %Pick the correct part of CC_edges_discarded %TO BE FIXED if vertices(kver).ind(im)==1 E{kver}{im,1}=CC_edges_discarded{ii,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex else @@ -783,22 +791,33 @@ end end ver_patches=unique(ver_patches,'stable'); - ver_ind=unique(ver_ind,'stable'); - %compute sigma + ver_ind=unique(ver_ind,'rows','stable'); + %ver_patches_nabla=unique(ver_patches_nabla,'stable'); + + %if the number of patches coincides with the number of interfaces, + %we add one fictional interface coinciding with the first one + %(just for coding-numbering reasons) + if numel(ver_patches)==nu + t0(nu+1,:)=t0(1,:); + t0p(nu+1,:)=t0p(1,:); + d0(nu+1,:)=d0(1,:); + d0p(nu+1,:)=d0p(1,:); + E{kver}{nu,1}=E{kver}{1,1}; + E{kver}{nu,2}=E{kver}{1,2}; + end + + %computing sigma sigma=0; for im=1:nu - %vertex_ind=ver_ind(im); %local index of the vertex in im-th patch - patch_ind=ver_patches(im); %global index of the im-th patch - %this works only for the standard configuration - sigma=sigma+norm([Du_F00(1) Dv_F00(2)]); + sigma=sigma+norm(ver_patches_nabla(im)); end sigma=1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V for im=1:nu %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{patch_ind}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2=space.sp_patch{patch_ind}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) j=0; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case @@ -825,26 +844,12 @@ d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; V{kver}{im}=zeros(n1*n2,6); - - side1=interfaces(vertices(kver).interfaces(im)).side1; %side of left patch - switch side1 %only case 3 (standard) is correct - case 1 - V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - case 2 - V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - case 3 - V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - case 4 - V{im,kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - end j=j+1; end end - CC_vertices{ver_patches(im),kver} = E{kver}{im}*MM{1,kver}{im} + E{kver}{im+1}*MM{2,kver}{im} + V{kver}{im}; + CC_vertices{ver_patches(im),kver} = E{kver}{im}*MM{1,kver}{im} + E{kver}{im+1}*MM{2,kver}{im} - V{kver}{im}; end end @@ -856,3 +861,8 @@ %- do modifications to handle different orientations (in basic case) %- compute number of ndof per edge, per vertex %- write clear algorithm for the whole construction? + +%TO BE TESTED +%- number of functions +%- plots of the functions +%- continuity \ No newline at end of file From 1fdce981fbf360d10b53ec9ec1f970cc4d2ed2e1 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 4 Dec 2020 19:50:45 +0100 Subject: [PATCH 042/366] Fixes to the way edges are associated with patches and to the extraction of parts edge function matrices --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 120 +++++++++++------- 1 file changed, 74 insertions(+), 46 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index c4d694c9..48f0f8dd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -291,11 +291,11 @@ p = space.sp_patch{1}.degree(1); k=numel(msh.msh_patch{1}.breaks{1})-2; -all_alpha0=zeros(numel(interfaces),2); -all_alpha1=zeros(numel(interfaces),2); -all_beta0=zeros(numel(interfaces),2); -all_beta1=zeros(numel(interfaces),2); -all_t0=zeros(numel(interfaces),2); +all_alpha0=zeros(numel(interfaces_all),2); +all_alpha1=zeros(numel(interfaces_all),2); +all_beta0=zeros(numel(interfaces_all),2); +all_beta1=zeros(numel(interfaces_all),2); +all_t0=zeros(numel(interfaces_all),2); %Initialize the cell array of CC_vertices matrices for ii=1:space.npatch @@ -304,9 +304,9 @@ end end %Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces) - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch1), ndof_per_interface(jj)); - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch2), ndof_per_interface(jj)); +for jj=1:numel(interfaces_all) + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); end %computing for each patch all the derivatives we possibly need to compute t,d, and sigma @@ -350,11 +350,11 @@ end %Construction of CC_edges -for iref = 1:numel(interfaces) - patch(1) = interfaces(iref).patch1; %LEFT - patch(2) = interfaces(iref).patch2; %RIGHT - side(1) = interfaces(iref).side1; %LEFT - side(2) = interfaces(iref).side2; %RIGHT +for iref = 1:numel(interfaces_all) + patch(1) = interfaces_all(iref).patch1; %LEFT + patch(2) = interfaces_all(iref).patch2; %RIGHT + side(1) = interfaces_all(iref).side1; %LEFT + side(2) = interfaces_all(iref).side2; %RIGHT %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives for ii = 1:2 % The two patches (L-R) @@ -629,7 +629,7 @@ ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); end - if (ii == 2 && interfaces(iref).ornt == -1) %this should be still the same for the multipatch + if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch ind0 = fliplr (ind0); ind1 = fliplr (ind1); ind0_s{iref}=ind0; %saving the indices for later use; @@ -739,12 +739,12 @@ % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); - for im=1:nu %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) + for im=1:nu %cycle over all the interfaces containing the vertex inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch ver_patches=[ver_patches patch_ind1 patch_ind2]; ver_ind=[ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -754,26 +754,25 @@ Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); - %ver_patches_nabla=[#ind1 #ind2] case 2 %vertex (0,1) Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); - %ver_patches_nabla=[#ind1 #ind2] case 3 %vertex (1,0) Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); - %ver_patches_nabla=[#ind1 #ind2] case 4 %vertex (1,1) Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); - %ver_patches_nabla=[#ind1 #ind2] end + %Store the jacobian of F for the left patch + ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; + t0(im,:)=Dv_F00; t0p(im,:)=Dvv_F00; d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... @@ -783,16 +782,34 @@ -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; mix_der2(im,:)=Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); + end + ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + %Pick the correct part of CC_edges_discarded %TO BE FIXED if vertices(kver).ind(im)==1 - E{kver}{im,1}=CC_edges_discarded{ii,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); else - E{kver}{im,2}=CC_edges_discarded{ii,inter}(:,[4 5 6 9 10]); + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); end end - ver_patches=unique(ver_patches,'stable'); - ver_ind=unique(ver_ind,'rows','stable'); - %ver_patches_nabla=unique(ver_patches_nabla,'stable'); + [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + %ver_ind=unique(ver_ind,'rows','stable'); %if the number of patches coincides with the number of interfaces, %we add one fictional interface coinciding with the first one @@ -809,7 +826,7 @@ %computing sigma sigma=0; for im=1:nu - sigma=sigma+norm(ver_patches_nabla(im)); + sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); end sigma=1/(sigma/(p*(k+1)*nu)); @@ -818,38 +835,50 @@ %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges + im1=im_edges(1); im2=im_edges(2) j=0; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case d00=(j1==0)*(j2==0); %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im,:)'; - d20_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im,:)'; - d11_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im,:)'; + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; + d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; + d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im+1,:)'; - d20_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im+1,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im+1,:)'; - d11_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im+1,:)'; + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; + d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; + d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} - d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; + d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; V{kver}{im}=zeros(n1*n2,6); V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; j=j+1; end end - CC_vertices{ver_patches(im),kver} = E{kver}{im}*MM{1,kver}{im} + E{kver}{im+1}*MM{2,kver}{im} - V{kver}{im}; + if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 + E1=E{kver}{im1,2}; + else + E1=E{kver}{im1,1}; + end + if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 + E2=E{kver}{im2,2}; + else + E2=E{kver}{im2,1}; + end + CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; end end @@ -857,10 +886,9 @@ end %TO DO: +%- fix association patch->interface %- case of boundary edges -%- do modifications to handle different orientations (in basic case) %- compute number of ndof per edge, per vertex -%- write clear algorithm for the whole construction? %TO BE TESTED %- number of functions From 0856a1e30e0f8897d36241343d2b284eedd0aa02 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Thu, 10 Dec 2020 16:05:08 +0100 Subject: [PATCH 043/366] computation of dofs per edge and per vertex, and other small fixes (shoudl prduce output, but doesn't) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 914 ++++++++++++++++++ 1 file changed, 914 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 48f0f8dd..38d1de24 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -59,6 +59,920 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 + +% if (numel (interfaces) > 1 || msh.npatch > 2) +% error ('For now, the implementation only works for two patches') +% end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces) + patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; + sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, boundaries); + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + for iptc_on_interface = 1:2 + iptc = interface(intrfc).patches(iptc_on_interface); + Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; + end + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); + +p = space.sp_patch{1}.degree(1); +k = numel(msh.msh_patch{1}.breaks{1})-2; +n= space.sp_patch{1}.sp_univ(1).ndof; + +ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere +ndof_per_vertex=6*ones(1,numel(vertices)); + +all_alpha0=zeros(numel(interfaces_all),2); +all_alpha1=zeros(numel(interfaces_all),2); +all_beta0=zeros(numel(interfaces_all),2); +all_beta1=zeros(numel(interfaces_all),2); +all_t0=zeros(numel(interfaces_all),2); + +%Initialize the cell array of CC_vertices matrices +for ii=1:space.npatch + for jj=numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end +%Initialize the cell array of CC_edges matrices +for jj=1:numel(interfaces_all) + if isempty(interfaces_all(jj).patch1) + CC_edges{1,jj} = []; + else + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); + end + if isempty(interfaces_all(jj).patch2) + CC_edges{2,jj} = []; + else + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); + end +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +brk = cell (1,msh.ndim); +for j=1:space.npatch + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1}=[0 1]'; + pts{2}=[0 1]'; + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + msh_der1{j}=msh_precompute (msh_pts_der1); + derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + msh_der2{j}=msh_precompute (msh_pts_der2); + derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + %In this case (rdim=2) + %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space + %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) + %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) + %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) + %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) + %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) + %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) + %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) + + %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space + %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) + %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) + %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) + %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) + %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) + %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) + %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) + %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) + %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) + %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) + %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) +end + +%Construction of CC_edges +for iref = 1:numel(interfaces_all) + if ~isempty(interfaces_all(jj).patch1) + patch(1) = interfaces_all(iref).patch1; %LEFT + side(1) = interfaces_all(iref).side1; %LEFT + end + if ~isempty(interfaces_all(jj).patch2) + patch(2) = interfaces_all(iref).patch2; %RIGHT + side(2) = interfaces_all(iref).side2; %RIGHT + end + nnz_el=find(patch>0); + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = nnz_el % The two patches (L-R) + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + if nnz(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector + DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma=3*C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + %Saving alphas and betas (first column=L, second column=R) + all_alpha0(iref,:)=alpha0; + all_alpha1(iref,:)=alpha1; + all_beta0(iref,:)=beta0; + all_beta1(iref,:)=beta1; + %Saving t(0) + + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now we assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + ind0_s{iref}=ind0; %saving the indices for later use; + ind1_s{iref}=ind1; + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end + else + n0=n-k; + ndof=n0+n-k-1; + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is the interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +MM=cell(2,numel(vertices)); +V=cell(numel(vertices),1); +E=cell(numel(vertices),1); +%Previously: +%MM=cell(2,nu,numel(vertices)); +%V=cell(nu,numel(vertices)); +%E=cell(nu+1,numel(vertices)); +sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) + +for kver=1:numel(vertices) + + %Everything must be updated by using interfaces_all instead of interfaces TO DO + ver_patches=[];%vector with indices of patches containing the vertex + ver_patches_nabla={}; %cell array containing jacobians + ver_ind=[];%vector containing local index of vertex in the patch + nu=numel(vertices(kver).interfaces); + +% for h=1:numel(vertices(kver).interfaces) +% hint=vertices(kver).interfaces(h); +% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; +% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... +% sides(interfaces(hint).side2,vertices(kver).ind)]; +% end +% ver_patches=unique(ver_patches,'stable'); +% ver_ind=unique(ver_ind,'stable'); + + for im=1:nu %cycle over all the interfaces containing the vertex + inter=vertices(kver).interfaces(im); %global index of the interface + patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + ver_patches=[ver_patches patch_ind1 patch_ind2]; + ver_ind=[ver_ind vertex_ind1 vertex_ind2]; + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); + end + %Store the jacobian of F for the left patch + ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; + + t0(im,:)=Dv_F00; + t0p(im,:)=Dvv_F00; + d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... + /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); + d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... + -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... + ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + mix_der2(im,:)=Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); + end + ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + + %Pick the correct part of CC_edges_discarded %TO BE FIXED + if vertices(kver).ind(im)==1 + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); + else + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); + end + end + [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + %ver_ind=unique(ver_ind,'rows','stable'); + + %if the number of patches coincides with the number of interfaces, + %we add one fictional interface coinciding with the first one + %(just for coding-numbering reasons) + if numel(ver_patches)==nu + t0(nu+1,:)=t0(1,:); + t0p(nu+1,:)=t0p(1,:); + d0(nu+1,:)=d0(1,:); + d0p(nu+1,:)=d0p(1,:); + E{kver}{nu,1}=E{kver}{1,1}; + E{kver}{nu,2}=E{kver}{1,2}; + end + + %computing sigma + sigma=0; + for im=1:nu + sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); + end + sigma=1/(sigma/(p*(k+1)*nu)); + + %computing matrices MM and V + for im=1:nu + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges + im1=im_edges(1); im2=im_edges(2); + j=0; + for j1=0:2 + for j2=0:2-j1 %the following computations work in the standard case + d00=(j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; + d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; + d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; + MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; + d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; + d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; + MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + %V_{i_m,i} + d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; + V{kver}{im}=zeros(n1*n2,6); + V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + j=j+1; + end + end + if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 + E1=E{kver}{im1,2}; + else + E1=E{kver}{im1,1}; + end + if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 + E2=E{kver}{im2,2}; + else + E2=E{kver}{im2,1}; + end + CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; + end +end + + +end + +%TO DO: +%- case of boundary edges +%- compute number of ndof per edge, per vertex + +%TO BE TESTED +%- number of functions +%- plots of the functions +%- continuity % SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) From 1367b5e62c13a519680c445dcfe7fd957b14781b Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 11 Dec 2020 18:11:59 +0100 Subject: [PATCH 044/366] Various bugs corrected: compute_coefficients gives an output (supposedly correct for interior functions), but it does not work when used in sp_multipatch_C1 (dimension problems) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 981 +----------------- 1 file changed, 50 insertions(+), 931 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 38d1de24..fcaac0b6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -205,10 +205,12 @@ for intrfc = 1:numel(interfaces) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - for iptc_on_interface = 1:2 - iptc = interface(intrfc).patches(iptc_on_interface); - Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; - end + %for iptc_on_interface = 1:2 + iptc1 = interfaces(intrfc).patch1; + iptc2 = interfaces(intrfc).patch2; + Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; + Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; + %end end % Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point @@ -325,10 +327,10 @@ end %the following points correspond to the four vertices of the patch pts{1}=[0 1]'; - pts{2}=[0 1]'; + pts{2}=[0 1/2 1]'; msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); msh_der1{j}=msh_precompute (msh_pts_der1); - derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) + derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); msh_der2{j}=msh_precompute (msh_pts_der2); derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} @@ -358,11 +360,11 @@ %Construction of CC_edges for iref = 1:numel(interfaces_all) - if ~isempty(interfaces_all(jj).patch1) + if ~isempty(interfaces_all(iref).patch1) patch(1) = interfaces_all(iref).patch1; %LEFT side(1) = interfaces_all(iref).side1; %LEFT end - if ~isempty(interfaces_all(jj).patch2) + if ~isempty(interfaces_all(iref).patch2) patch(2) = interfaces_all(iref).patch2; %RIGHT side(2) = interfaces_all(iref).side2; %RIGHT end @@ -642,8 +644,7 @@ ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); end - - if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch + if (ii == 2 & interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch ind0 = fliplr (ind0); ind1 = fliplr (ind1); ind0_s{iref}=ind0; %saving the indices for later use; @@ -664,6 +665,9 @@ else n0=n-k; ndof=n0+n-k-1; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); +% size(CC_edges{ii,iref}) +% keyboard CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); end @@ -750,6 +754,16 @@ ver_ind=[];%vector containing local index of vertex in the patch nu=numel(vertices(kver).interfaces); + boundary_v=0; + for im=1:nu + inter=vertices(kver).interfaces(im); + if isempty(interfaces_all(inter).side1) | isempty(interfaces_all(inter).side2) + boundary_v=1; + break + end + end + if boundary_v==0 + % for h=1:numel(vertices(kver).interfaces) % hint=vertices(kver).interfaces(h); % ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; @@ -770,25 +784,25 @@ %compute t(0) and t'(0), d(0) and d'(0) switch vertex_ind1 case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1)); + Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,1)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,1)); case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2)); + Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,2)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,2)); case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,3)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,3)); + Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,3)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,3)); case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,4)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,4)); + Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,4)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,4)); end %Store the jacobian of F for the left patch ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; @@ -805,17 +819,17 @@ %We need to get the jacobian also for the right patch switch vertex_ind2 case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); end ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; @@ -855,9 +869,9 @@ %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges + im_edges=ceil(find(ind_patch_rep==im)/2); %global indices of the edges im1=im_edges(1); im2=im_edges(2); - j=0; + j=1; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case d00=(j1==0)*(j2==0); @@ -900,909 +914,14 @@ end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; end -end - - -end - -%TO DO: -%- case of boundary edges -%- compute number of ndof per edge, per vertex - -%TO BE TESTED -%- number of functions -%- plots of the functions -%- continuity % SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface - - sp.ndof_interior = 0; - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces) - patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; - sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, vertices); - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - end - - for intrfc = 1:numel(interfaces) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - for iptc_on_interface = 1:2 - iptc = interface(intrfc).patches(iptc_on_interface); - Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; - end - end - -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; - end - end - -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) - -[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); %update the whole function using all_interfaces -%TO DO: for each interior vertex, the first and last interface must coincide - -%ndof_per_interface: still to be computed! -%ndof_per_vertex: still to be computed! - -p = space.sp_patch{1}.degree(1); -k=numel(msh.msh_patch{1}.breaks{1})-2; - -all_alpha0=zeros(numel(interfaces_all),2); -all_alpha1=zeros(numel(interfaces_all),2); -all_beta0=zeros(numel(interfaces_all),2); -all_beta1=zeros(numel(interfaces_all),2); -all_t0=zeros(numel(interfaces_all),2); - -%Initialize the cell array of CC_vertices matrices -for ii=1:space.npatch - for jj=numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end -%Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces_all) - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); -end - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -brk = cell (1,msh.ndim); -for j=1:space.npatch - knots = space.sp_patch{j}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1}=[0 1]'; - pts{2}=[0 1]'; - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - msh_der1{j}=msh_precompute (msh_pts_der1); - derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - msh_der2{j}=msh_precompute (msh_pts_der2); - derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} - %In this case (rdim=2) - %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space - %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) - %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) - %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) - %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) - %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) - %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) - %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) - - %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space - %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) - %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) - %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) - %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) - %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) - %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) - %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) - %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) - %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) - %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) - %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) -end - -%Construction of CC_edges -for iref = 1:numel(interfaces_all) - patch(1) = interfaces_all(iref).patch1; %LEFT - patch(2) = interfaces_all(iref).patch2; %RIGHT - side(1) = interfaces_all(iref).side1; %LEFT - side(2) = interfaces_all(iref).side2; %RIGHT - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = 1:2 % The two patches (L-R) - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - for idim = 1:msh.ndim - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) - end - - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector - DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector - DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector - DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector - DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector - DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector - if side(2)==1 || side(2)==2 - v=grev_pts{2}'; - else - v=grev_pts{1}'; - end - A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); - gamma=3*C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R - - end - - %Saving alphas and betas (first column=L, second column=R) - all_alpha0(iref,:)=alpha0; - all_alpha1(iref,:)=alpha1; - all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %Saving t(0) - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now we assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - ind0_s{iref}=ind0; %saving the indices for later use; - ind1_s{iref}=ind1; - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); - end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - -end - - - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is the interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM=cell(2,numel(vertices)); -V=cell(numel(vertices),1); -E=cell(numel(vertices),1); -%Previously: -%MM=cell(2,nu,numel(vertices)); -%V=cell(nu,numel(vertices)); -%E=cell(nu+1,numel(vertices)); -sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - -for kver=1:numel(vertices) - - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches=[];%vector with indices of patches containing the vertex - ver_patches_nabla=[]; %TO CHECK WHAT THIS MUST CONTAIN EXACTLY and modify accordingly - ver_ind=[];%vector containing local index of vertex in the patch - nu=numel(vertices(kver).interfaces); - -% for h=1:numel(vertices(kver).interfaces) -% hint=vertices(kver).interfaces(h); -% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; -% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... -% sides(interfaces(hint).side2,vertices(kver).ind)]; -% end -% ver_patches=unique(ver_patches,'stable'); -% ver_ind=unique(ver_ind,'stable'); - - for im=1:nu %cycle over all the interfaces containing the vertex - inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch - ver_patches=[ver_patches patch_ind1 patch_ind2]; - ver_ind=[ver_ind vertex_ind1 vertex_ind2]; - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); - end - %Store the jacobian of F for the left patch - ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; - - t0(im,:)=Dv_F00; - t0p(im,:)=Dvv_F00; - d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... - /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); - d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... - -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... - ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(im,:)=Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); - end - ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; - - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if vertices(kver).ind(im)==1 - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); - else - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end - end - [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); - %ver_ind=unique(ver_ind,'rows','stable'); - - %if the number of patches coincides with the number of interfaces, - %we add one fictional interface coinciding with the first one - %(just for coding-numbering reasons) - if numel(ver_patches)==nu - t0(nu+1,:)=t0(1,:); - t0p(nu+1,:)=t0p(1,:); - d0(nu+1,:)=d0(1,:); - d0p(nu+1,:)=d0p(1,:); - E{kver}{nu,1}=E{kver}{1,1}; - E{kver}{nu,2}=E{kver}{1,2}; - end - - %computing sigma - sigma=0; - for im=1:nu - sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); - end - sigma=1/(sigma/(p*(k+1)*nu)); - - %computing matrices MM and V - for im=1:nu - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges - im1=im_edges(1); im2=im_edges(2) - j=0; - for j1=0:2 - for j2=0:2-j1 %the following computations work in the standard case - d00=(j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; - d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; - d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; - MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; - d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; - d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; - MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; - %V_{i_m,i} - d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; - V{kver}{im}=zeros(n1*n2,6); - V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - j=j+1; - end - end - if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 - E1=E{kver}{im1,2}; - else - E1=E{kver}{im1,1}; - end - if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 - E2=E{kver}{im2,2}; - else - E2=E{kver}{im2,1}; - end - CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; - end -end - - end %TO DO: -%- fix association patch->interface %- case of boundary edges -%- compute number of ndof per edge, per vertex %TO BE TESTED %- number of functions From be991fe2e01141edb0bd076b9c5a51c0380b09a8 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Tue, 19 Jan 2021 17:54:19 +0100 Subject: [PATCH 045/366] Fixed bug in sp_multipatch_C1: now output produced (for sure not correct for functions close to geometry boundaries) --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index fcaac0b6..717db5ec 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -216,7 +216,7 @@ % Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point % The information of which patches share the vertex can be computed with the help of mp_interface for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; end From 0fcd43950d9c6bfff8303a0650f7445293cd5d41 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 20 Jan 2021 18:12:50 +0100 Subject: [PATCH 046/366] sp_multipatch_C1 and compute_coefficients fixed to have the correct ndof --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 717db5ec..867db405 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -153,11 +153,12 @@ % We could store the info of interfaces per patch, as in mp_interface sp.ndof_interior = 0; + [interfaces_all, ~] = vertices_struct(boundaries, interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces) - patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; - sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; + for intrfc = 1:numel(interfaces_all) + patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; + sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; [is_interface,position] = ismember (iptc, patches); if (is_interface) sp_bnd = spaces{iptc}.boundary(sides(position)); @@ -360,6 +361,7 @@ %Construction of CC_edges for iref = 1:numel(interfaces_all) + clear patch if ~isempty(interfaces_all(iref).patch1) patch(1) = interfaces_all(iref).patch1; %LEFT side(1) = interfaces_all(iref).side1; %LEFT @@ -397,7 +399,7 @@ geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) end - if nnz(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges + if length(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector @@ -512,7 +514,6 @@ all_beta0(iref,:)=beta0; all_beta1(iref,:)=beta1; %Saving t(0) - % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) From 573d46cce86c2b1c438d49c35b9ed2746592b638 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Tue, 26 Jan 2021 16:29:04 +0100 Subject: [PATCH 047/366] Fixes to be consistent with standard patch parametrization; problems with reparametrization and numbering of functions --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 867db405..22cccf28 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -186,6 +186,7 @@ % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... compute_coefficients (sp, msh, geometry, interfaces, boundaries); +%keyboard sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions @@ -328,7 +329,7 @@ end %the following points correspond to the four vertices of the patch pts{1}=[0 1]'; - pts{2}=[0 1/2 1]'; + pts{2}=[0 1]';%pts{2}=[0 1/2 1]' msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); msh_der1{j}=msh_precompute (msh_pts_der1); derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) @@ -371,22 +372,26 @@ side(2) = interfaces_all(iref).side2; %RIGHT end nnz_el=find(patch>0); + if side(1)==3 && side(2)==1 + patch=flip(patch); + side=flip(side); + end %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives for ii = nnz_el % The two patches (L-R) %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); for idim = 1:msh.ndim - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); if (numel(grev_pts{idim}) > 1) brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; else @@ -397,21 +402,30 @@ msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); msh_side_int{ii} = msh_precompute (msh_side_int{ii}); geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% if ii==1 && (side(ii)==3 || side(ii)==4) +% disp('done1') +% geo_map_jac{ii}=flip(geo_map_jac{ii}); +% elseif ii==2 && (side(ii)==1 || side(ii)==2) +% disp('done2') +% geo_map_jac{ii}=flip(geo_map_jac{ii}); +% end end if length(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector - DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector - DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector - DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector - DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector - DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector if side(2)==1 || side(2)==2 - v=grev_pts{2}'; + v=grev_pts{2}(:); else - v=grev_pts{1}'; + v=grev_pts{1}(:); end + ngrev=numel(v); + DuFR_x=reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector + DuFR_y=reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector + DvFL_x=reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector + DvFL_y=reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector + DvFR_x=reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector + DvFR_y=reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; if rank(A_full)==6 @@ -438,6 +452,7 @@ beta2_n=sols(5); end + %keyboard %STEP 4 - Normalizing the alphas %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... % +alpha0_n(1)^2+alpha0_n(2)^2; @@ -512,11 +527,10 @@ all_alpha0(iref,:)=alpha0; all_alpha1(iref,:)=alpha1; all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %Saving t(0) + all_beta1(iref,:)=beta1; % Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) + for ii = 1:2 % The two patches (R-L) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -620,7 +634,7 @@ rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; + val_aux = val * alpha{ii}(jj)* (-1)^(ii-1); %with the multipatch settings must be multiplied by -1 for left patch; rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; end coeff2{ii} = A \ rhsc; @@ -657,7 +671,7 @@ CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 From 4258fd2490e3888099734fba9f1fb8b734053468 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Thu, 28 Jan 2021 17:41:43 +0100 Subject: [PATCH 048/366] Interior interface functions correct, interior vertex functions to be checked, boundary interface and vertex functions to be added (basic four-patches-one-vertex symmetric example) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 22cccf28..764711c4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -228,6 +228,7 @@ sp.interfaces = interfaces; sp.Cpatch = Cpatch; sp.geometry = geometry; % I store this for simplicity + %keyboard %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % I HAVE FINISHED MY CHANGES HERE @@ -372,10 +373,6 @@ side(2) = interfaces_all(iref).side2; %RIGHT end nnz_el=find(patch>0); - if side(1)==3 && side(2)==1 - patch=flip(patch); - side=flip(side); - end %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives for ii = nnz_el % The two patches (L-R) @@ -849,10 +846,10 @@ ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; %Pick the correct part of CC_edges_discarded %TO BE FIXED - if vertices(kver).ind(im)==1 + if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); - else + else %the vertex is the right/top endpoint of im-th interface E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); end @@ -884,7 +881,8 @@ %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - im_edges=ceil(find(ind_patch_rep==im)/2); %global indices of the edges + V{kver}{im}=zeros(n1*n2,6); + im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) im1=im_edges(1); im2=im_edges(2); j=1; for j1=0:2 @@ -911,23 +909,25 @@ %V_{i_m,i} d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; - V{kver}{im}=zeros(n1*n2,6); V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; j=j+1; end end - if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 + %size(V{kver}{im}) + %keyboard + if interfaces_all(vertices(kver).interfaces(im1)).patch2==ver_patches(im)%the considered patch is the second patch edge im1 E1=E{kver}{im1,2}; else E1=E{kver}{im1,1}; end - if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 + if interfaces_all(vertices(kver).interfaces(im2)).patch2==ver_patches(im)%the considered patch is the second patch of edge im2 E2=E{kver}{im2,2}; else E2=E{kver}{im2,1}; end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; + %keyboard end end @@ -939,6 +939,5 @@ %- case of boundary edges %TO BE TESTED -%- number of functions %- plots of the functions %- continuity \ No newline at end of file From 4e158cec7b91f3989620e963e41f06086a473716 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 3 Feb 2021 18:51:52 +0100 Subject: [PATCH 049/366] Unnecessary part of the code eliminated in sp_multipatch_C1 --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 764711c4..04ed97c5 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -860,14 +860,14 @@ %if the number of patches coincides with the number of interfaces, %we add one fictional interface coinciding with the first one %(just for coding-numbering reasons) - if numel(ver_patches)==nu - t0(nu+1,:)=t0(1,:); - t0p(nu+1,:)=t0p(1,:); - d0(nu+1,:)=d0(1,:); - d0p(nu+1,:)=d0p(1,:); - E{kver}{nu,1}=E{kver}{1,1}; - E{kver}{nu,2}=E{kver}{1,2}; - end +% if numel(ver_patches)==nu +% t0(nu+1,:)=t0(1,:); +% t0p(nu+1,:)=t0p(1,:); +% d0(nu+1,:)=d0(1,:); +% d0p(nu+1,:)=d0p(1,:); +% E{kver}{nu+1,1}=E{kver}{1,1}; +% E{kver}{nu+1,2}=E{kver}{1,2}; +% end %computing sigma sigma=0; From 5db82a901f3a0802a7558903a07915a04e2093b4 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Thu, 4 Feb 2021 17:53:17 +0100 Subject: [PATCH 050/366] Some bugs fixed in sp_multipatch_C1: gives (non-boundary) C1 basis functions in the basic four square patches sharing 1 vertex geometry --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 04ed97c5..f38b8eec 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -823,9 +823,9 @@ t0p(im,:)=Dvv_F00; d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); - d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... - -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... + d0p(im,:)=((-all_alpha0(inter,1)+all_alpha1(inter,1))*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... + (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; mix_der2(im,:)=Duv_F00; %We need to get the jacobian also for the right patch @@ -878,12 +878,16 @@ %computing matrices MM and V for im=1:nu + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) V{kver}{im}=zeros(n1*n2,6); im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) im1=im_edges(1); im2=im_edges(2); + if im==2 %works only if the interfaces and patches are ordered in clockwise order + im1=4; im2=1; + end j=1; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case @@ -908,9 +912,10 @@ d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; + V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + j=j+1; end end From 148d14b838f4c6ac0827cd9ba438d3dc8cb20ae7 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Mon, 22 Feb 2021 16:02:29 +0100 Subject: [PATCH 051/366] Added old two-patch class code for tests --- .../mp_solve_laplace_C1.m | 133 +++ .../@sp_multipatch_C1_twopatch/op_f_v_mp.m | 51 + .../op_gradgradu_gradgradv_mp.m | 54 + .../op_gradu_gradv_mp.m | 54 + .../op_laplaceu_laplacev_mp.m | 55 + .../@sp_multipatch_C1_twopatch/op_u_v_mp.m | 61 ++ .../solve_laplace.m | 139 +++ .../sp_evaluate_element_list.m | 180 ++++ .../sp_get_basis_functions.m | 41 + .../@sp_multipatch_C1_twopatch/sp_get_cells.m | 52 + .../sp_get_neighbors.m | 41 + .../@sp_multipatch_C1_twopatch/sp_h1_error.m | 54 + .../@sp_multipatch_C1_twopatch/sp_h2_error.m | 59 ++ .../@sp_multipatch_C1_twopatch/sp_l2_error.m | 48 + .../sp_multipatch_C1.m | 948 ++++++++++++++++++ .../sp_multipatch_C1_curve.m | 423 ++++++++ .../sp_multipatch_C1_new.m | 807 +++++++++++++++ .../sp_multipatch_C1_new2.m | 911 +++++++++++++++++ .../sp_multipatch_C1_old.m | 409 ++++++++ .../sp_multipatch_C1_twopatch.m | 592 +++++++++++ .../sp_plot_solution.m | 58 ++ .../@sp_multipatch_C1_twopatch/sp_refine.m | 68 ++ .../@sp_multipatch_C1_twopatch/sp_to_vtk.m | 82 ++ .../sp_weak_drchlt_bc_laplace.m | 95 ++ .../@sp_multipatch_C1_twopatch/subsasgn.m | 4 + .../@sp_multipatch_C1_twopatch/subsref.m | 4 + 26 files changed, 5423 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m new file mode 100644 index 00000000..903b622f --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m @@ -0,0 +1,133 @@ +% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. +% +% Example to solve the diffusion problem +% +% - div ( epsilon(x) grad (u)) = f in Omega +% epsilon(x) du/dn = g on Gamma_N +% u = h on Gamma_D +% +% where the domain \Omega is formed by several patches of the form F((0,1)^n). +% +% USAGE: +% +% [geometry, msh, space, u] = +% mp_solve_laplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: array of geometry structures (see geo_load) +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% u: the computed degrees of freedom +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 2 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_laplace_C1 (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +msh = msh_multipatch (msh, boundaries); +% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); +clear sp + +% Compute and assemble the matrices +stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); +rhs = op_f_v_mp (space, msh, f); + +% Apply Neumann boundary conditions +for iref = nmnn_sides + gref = @(varargin) g(varargin{:}, iref); + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh.msh_patch{iptc}.boundary(iside); + sp_side = space.sp_patch{iptc}.boundary(iside); + rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); + rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; + end +end + +% Apply Dirichlet boundary conditions in weak form, by Nitsche's method +if (exist ('weak_drchlt_sides', 'var')) + [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, weak_drchlt_sides, h, c_diff, Cpen); + stiff_mat = stiff_mat - N_mat; + rhs = rhs + N_rhs; +end + +% Solve the linear system +u = stiff_mat \ rhs; + +end + +%!demo +%! ex_laplace_Lshaped_mp + +%!demo +%! ex_laplace_cube_mp + +%!demo +%! ex_laplace_thick_L_mp diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m new file mode 100644 index 00000000..561a3415 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m @@ -0,0 +1,51 @@ +% OP_F_V_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% +% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_v_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_v_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_v_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + +% if (~isempty (space.dofs_ornt)) +% rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); +% end + rhs = rhs + space.Cpatch{iptc}.' * rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m new file mode 100644 index 00000000..7abebba3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADGRADU_GRADGRADV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon grad grad u_j, grad grad v_i), in a multipatch domain. +% +% mat = op_gradgradu_gradgradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradgradu_gradgradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradgradu_gradgradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m new file mode 100644 index 00000000..953bba5b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m @@ -0,0 +1,54 @@ +% OP_GRADU_GRADV_MP: assemble the stiffness matrix A = [a(i,j)], a(i,j) = (epsilon grad u_j, grad v_i), in a multipatch domain. +% +% mat = op_gradu_gradv_mp (spu, spv, msh, [epsilon], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled stiffness matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_gradu_gradv_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_gradu_gradv_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m new file mode 100644 index 00000000..55ba64ac --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m @@ -0,0 +1,55 @@ +% OP_LAPLACEU_LAPLACEV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon laplace u_j, laplace v_i), in a multipatch domain. +% +% mat = op_laplaceu_laplacev_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_laplaceu_laplacev_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_laplaceu_laplacev_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m new file mode 100644 index 00000000..06151fde --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m @@ -0,0 +1,61 @@ +% OP_U_V_MP: assemble the mass matrix M = [m(i,j)], m(i,j) = (mu u_j, v_i), in a multipatch domain. +% +% mat = op_u_v_mp (spu, spv, msh, [coeff], [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled mass matrix +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_u_v_mp (spu, spv, msh, coeff, patch_list) + + if (nargin < 5) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_u_v_mp: the number of patches does not coincide') + end + + A = sparse (spv.ndof, spu.ndof); + + for iptc = patch_list + if (nargin < 4 || isempty (coeff)) + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); + else + Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + end + + A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + +% if (~isempty (spv.dofs_ornt)) +% vs = spv.dofs_ornt{iptc}(rs)' .* vs; +% end +% if (~isempty (spu.dofs_ornt)) +% vs = vs .* spu.dofs_ornt{iptc}(cs)'; +% end + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m new file mode 100644 index 00000000..73dc7df5 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m @@ -0,0 +1,139 @@ +% SOLVE_LAPLACE: Solve a Laplace problem with a B-spline discretization (non-isoparametric approach). +% +% The function solves the diffusion problem +% +% - div ( epsilon(x) grad (u)) = f in Omega = F((0,1)^n) +% epsilon(x) du/dn = g on Gamma_N +% u = h on Gamma_D +% +% USAGE: +% +% [geometry, msh, space, u] = solve_laplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete space (see sp_scalar) +% u: the computed degrees of freedom +% +% See also EX_LAPLACE_SQUARE, EX_LAPLACE_THICK_RING for examples. +% +% Copyright (C) 2009, 2010, 2011 Carlo de Falco +% Copyright (C) 2011, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + solve_laplace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure +geometry = geo_load (geo_name); + +[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); + +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (zeta, rule); +msh = msh_cartesian (zeta, qn, qw, geometry); + +% Construct space structure +space = sp_bspline (knots, degree, msh); + +% Assemble the matrices +stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); +rhs = op_f_v_tp (space, msh, f); + +% Apply Neumann boundary conditions +for iside = nmnn_sides + if (msh.ndim > 1) +% Restrict the function handle to the specified side, in any dimension, gside = @(x,y) g(x,y,iside) + gside = @(varargin) g(varargin{:},iside); + dofs = space.boundary(iside).dofs; + rhs(dofs) = rhs(dofs) + op_f_v_tp (space.boundary(iside), msh.boundary(iside), gside); + else + if (iside == 1) + x = msh.breaks{1}(1); + else + x = msh.breaks{1}(end); + end + sp_side = space.boundary(iside); + rhs(sp_side.dofs) = rhs(sp_side.dofs) + g(x,iside); + end +end + +% Apply Dirichlet boundary conditions +u = zeros (space.ndof, 1); +[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); +u(drchlt_dofs) = u_drchlt; + +int_dofs = setdiff (1:space.ndof, drchlt_dofs); +rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; + +% Solve the linear system +u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); + +end + +%!demo +%! ex_laplace_square + +%!demo +%! ex_laplace_plate + +%!demo +%! ex_laplace_ring + +%!demo +%! ex_laplace_ring_mixed_bc + +%!demo +%! ex_laplace_cube + +%!demo +%! ex_laplace_thick_ring + +%!demo +%! ex_laplace_beltrami + +%!demo +%! ex_laplace_1d diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m new file mode 100644 index 00000000..85072cff --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m @@ -0,0 +1,180 @@ +% SP_EVALUATE_ELEMENT_LIST: compute the basis functions in a given list of elements. +% +% sp = sp_evaluate_element_list (space, msh_elems, 'option1', value1, ...) +% +% INPUTS: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh_elems: structure containing the information of quadrature or +% visualization points, for a given list of elements and patches +% (see msh_multipatch/msh_evaluate_element_list) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% hessian | false | compute shape_function_hessians (only scalars) +% laplacian | false | compute shape_function_laplacians (only scalars) +% div | false | compute shape_function_divs (only vectors) +% curl | false | compute shape_function_curls (only vectors) +% +% OUTPUT: +% +% sp: struct representing the discrete function space, with the following fields: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space +% ndof (scalar) total number of degrees of freedom +% nsh (1 x nel) number of non-vanishing functions on each element +% nsh_max (scalar) maximum number of nsh +% connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element +% shape_functions, shape_function_gradients... (see sp_evaluate_col for details) +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_evaluate_element_list (space, msh, varargin) + + is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); + + sp.npatch = space.npatch; + sp.ncomp = space.ncomp; + sp.ndof = space.ndof; + + if (isempty (msh.elem_list)), return, end + + sp.nsh_max = []; + if (is_scalar) + fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', 'shape_function_laplacians'}; + cat_position = [2, 2, 3, 4, 5, 3]; +% else +% fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', ... +% 'shape_function_laplacians', 'shape_function_divs', 'shape_function_curls'}; +% if (msh.ndim == 2 || msh.ndim == 1) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 3]; +% elseif (msh.ndim == 3) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 4]; +% end + end + for ii = 1:numel(fields) + sp.(fields{ii}) = []; + end + + for iptc = 1:space.npatch +% msh_patch = msh_evaluate_element_list (msh.msh_patch{iptc}, msh.elem_list_of_patch{iptc}); % Not working anymore + msh_patch = msh_restrict_to_patch (msh, iptc); + + sp_patch = sp_evaluate_element_list (space.sp_patch{iptc}, msh_patch, varargin{:}); + Cpatch = space.Cpatch{iptc}; + + nsh = zeros (1, msh_patch.nel); + connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); + shape_funs = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_lapl = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + + for iel = 1:msh_patch.nel + conn_iel = sp_patch.connectivity(:,iel); + [ii,jj] = find (Cpatch(conn_iel,:)); + funs = unique (jj); + nsh(iel) = numel (funs); + connectivity(1:nsh(iel),iel) = funs; + Cpatch_iel = Cpatch(conn_iel, funs); + + if (isfield (sp_patch, 'shape_functions')) + shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_gradients')) + for idim = 1:msh.rdim + shape_fun_grads(idim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_gradients(idim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + if (isfield (sp_patch, 'shape_function_laplacians')) + shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_hessians')) + for idim = 1:msh.rdim; + for jdim = 1:msh.rdim + shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + end + end + + sp.nsh = cat (2, sp.nsh, nsh); + if (msh_patch.nel > 0) + sp.connectivity = cat (2, sp.connectivity, connectivity); + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end + end + +% for ii = 1:numel(fields) +% if (isfield (sp_patch, fields{ii})) +% sp.(fields{ii}) = cat (cat_position(ii), sp.(fields{ii}), sp_patch.(fields{ii})); +% end +% end + end + sp.nsh_max = max (sp.nsh); + + for ii = 1:numel(fields) + if (isempty (sp.(fields{ii}))) + sp = rmfield (sp, fields{ii}); + elseif (ii > 1) + field_size = size (sp.(fields{ii})); + inds = repmat ({':'}, 1, numel(field_size)); + inds{cat_position(ii)-1} = 1:sp.nsh_max; + sp.(fields{ii}) = sp.(fields{ii})(inds{:}); + end + end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSH_RESTRICT_TO_PATCH: extracts the fields corresponding to the selected elements of a given patch, +% from the ones of a mesh struct, computed with msh_multipatch/msh_evaluate_element_list. +% The result is the same as calling msh_cartesian/msh_evaluate_element_list, but avoids recomputing. +% +function msh_ptc = msh_restrict_to_patch (msh, patch) + + msh_ptc.ndim = msh.ndim; + msh_ptc.rdim = msh.rdim; + msh_ptc.elem_list = msh.elem_list_of_patch{patch}(:).'; + + msh_ptc.nel = msh.nel_per_patch(patch); + msh_ptc.nel_dir = msh.nel_dir_of_patch{patch}; + msh_ptc.nqn = msh.nqn; + msh_ptc.nqn_dir = msh.nqn_dir; + + if (isempty (msh_ptc.elem_list)), return, end + + Nelem = cumsum ([0, msh.nel_per_patch]); + + global_elem_list = Nelem(patch)+1:Nelem(patch+1); + msh_ptc.quad_weights = msh.quad_weights(:,global_elem_list); + msh_ptc.geo_map = msh.geo_map(:,:,global_elem_list); + msh_ptc.geo_map_jac = msh.geo_map_jac(:,:,:,global_elem_list); + msh_ptc.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); + msh_ptc.jacdet = msh.jacdet(:,global_elem_list); + msh_ptc.element_size = msh.element_size(:,global_elem_list); + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m new file mode 100644 index 00000000..76edf5c8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m @@ -0,0 +1,41 @@ +% SP_GET_BASIS_FUNCTIONS: Compute the indices of tensor-product B-splines acting on a list of cells. +% +% fun_indices = sp_get_basis_functions (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the cells. +% +% OUTPUT: +% fun_indices: indices of the basis functions acting on the cells. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function function_indices = sp_get_basis_functions (space, msh, cell_indices) + +function_indices = []; +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [~,local_cell_indices,~] = intersect ((Nelem(iptc)+1):Nelem(iptc+1), cell_indices); + if (~isempty (local_cell_indices)) + aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); + [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); + function_indices = union (function_indices, dofs); + end +end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m new file mode 100644 index 00000000..874f4e92 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m @@ -0,0 +1,52 @@ +% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function. +% +% [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% cell_indices: indices of the cells within the support of the basis functions. +% indices_per_function: indices of the cells within the support of each basis function. +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [cell_indices, indices_per_function] = sp_get_cells (space, msh, fun_indices) + +fun_indices = fun_indices(:).'; + +indices_per_function = cell (numel (fun_indices), 1); +cell_indices = []; + +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = 1:space.npatch + [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + patch_indices = patch_indices(:).'; + [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + + cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices); + + if (nargout == 2) + local_funs = local_funs(:).'; + for ifun = 1:numel(patch_indices) + indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); + end + end + end +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m new file mode 100644 index 00000000..36a4ec2c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m @@ -0,0 +1,41 @@ +% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions +% +% neighbors_indices = sp_get_neighbors (space, msh, indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% indices: indices of the functions. +% +% OUTPUT: +% neighbors_indices: indices of the functions that interact with the given ones. +% +% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function neighbors_indices = sp_get_neighbors (space, msh, fun_indices) + +neighbors_indices = []; + +for iptc = 1:space.npatch + [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices)); + if (~isempty (patch_indices)) + aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); + [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); + neighbors_indices = union (neighbors_indices, global_indices); + end +end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m new file mode 100644 index 00000000..f727b7d2 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m @@ -0,0 +1,54 @@ +% SP_H1_ERROR: Evaluate the error in H^1 norm. +% +% [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% +% OUTPUT: +% +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h1(iptc), error_l2(iptc), error_h1s(iptc)] = ... + sp_h1_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m new file mode 100644 index 00000000..a40be7cb --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m @@ -0,0 +1,59 @@ +% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% hessuex: function handle to evaluate the hessian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h2(iptc), error_h1(iptc), error_l2(iptc), error_h2s(iptc), error_h1s(iptc)] = ... + sp_h2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex, hessuex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + errh2 = sqrt (sum (error_h2 .* error_h2)); + errh2s = sqrt (sum (error_h2s .* error_h2s)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m new file mode 100644 index 00000000..abbbc9ef --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m @@ -0,0 +1,48 @@ +% SP_L2_ERROR: Evaluate the error in L^2 norm. +% +% errl2 = sp_l2_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% +% OUTPUT: +% +% errl2: error in L^2 norm +% +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function errl2 = sp_l2_error (space, msh, u, uex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m new file mode 100644 index 00000000..f38b8eec --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m @@ -0,0 +1,948 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 + +% if (numel (interfaces) > 1 || msh.npatch > 2) +% error ('For now, the implementation only works for two patches') +% end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + [interfaces_all, ~] = vertices_struct(boundaries, interfaces); + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces_all) + patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; + sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, boundaries); +%keyboard + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + %for iptc_on_interface = 1:2 + iptc1 = interfaces(intrfc).patch1; + iptc2 = interfaces(intrfc).patch2; + Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; + Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; + %end + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + %keyboard + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); + +p = space.sp_patch{1}.degree(1); +k = numel(msh.msh_patch{1}.breaks{1})-2; +n= space.sp_patch{1}.sp_univ(1).ndof; + +ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere +ndof_per_vertex=6*ones(1,numel(vertices)); + +all_alpha0=zeros(numel(interfaces_all),2); +all_alpha1=zeros(numel(interfaces_all),2); +all_beta0=zeros(numel(interfaces_all),2); +all_beta1=zeros(numel(interfaces_all),2); +all_t0=zeros(numel(interfaces_all),2); + +%Initialize the cell array of CC_vertices matrices +for ii=1:space.npatch + for jj=numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end +%Initialize the cell array of CC_edges matrices +for jj=1:numel(interfaces_all) + if isempty(interfaces_all(jj).patch1) + CC_edges{1,jj} = []; + else + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); + end + if isempty(interfaces_all(jj).patch2) + CC_edges{2,jj} = []; + else + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); + end +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +brk = cell (1,msh.ndim); +for j=1:space.npatch + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1}=[0 1]'; + pts{2}=[0 1]';%pts{2}=[0 1/2 1]' + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + msh_der1{j}=msh_precompute (msh_pts_der1); + derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + msh_der2{j}=msh_precompute (msh_pts_der2); + derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + %In this case (rdim=2) + %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space + %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) + %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) + %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) + %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) + %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) + %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) + %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) + + %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space + %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) + %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) + %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) + %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) + %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) + %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) + %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) + %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) + %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) + %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) + %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) +end + +%Construction of CC_edges +for iref = 1:numel(interfaces_all) + clear patch + if ~isempty(interfaces_all(iref).patch1) + patch(1) = interfaces_all(iref).patch1; %LEFT + side(1) = interfaces_all(iref).side1; %LEFT + end + if ~isempty(interfaces_all(iref).patch2) + patch(2) = interfaces_all(iref).patch2; %RIGHT + side(2) = interfaces_all(iref).side2; %RIGHT + end + nnz_el=find(patch>0); + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = nnz_el % The two patches (L-R) + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + for idim = 1:msh.ndim + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% if ii==1 && (side(ii)==3 || side(ii)==4) +% disp('done1') +% geo_map_jac{ii}=flip(geo_map_jac{ii}); +% elseif ii==2 && (side(ii)==1 || side(ii)==2) +% disp('done2') +% geo_map_jac{ii}=flip(geo_map_jac{ii}); +% end + end + + if length(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + if side(2)==1 || side(2)==2 + v=grev_pts{2}(:); + else + v=grev_pts{1}(:); + end + ngrev=numel(v); + DuFR_x=reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector + DuFR_y=reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector + DvFL_x=reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector + DvFL_y=reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector + DvFR_x=reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector + DvFR_y=reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector + + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %keyboard + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma=3*C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + %Saving alphas and betas (first column=L, second column=R) + all_alpha0(iref,:)=alpha0; + all_alpha1(iref,:)=alpha1; + all_beta0(iref,:)=beta0; + all_beta1(iref,:)=beta1; + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (R-L) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now we assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj)* (-1)^(ii-1); %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + if (ii == 2 & interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + ind0_s{iref}=ind0; %saving the indices for later use; + ind1_s{iref}=ind1; + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end + else + n0=n-k; + ndof=n0+n-k-1; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); +% size(CC_edges{ii,iref}) +% keyboard + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is the interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +MM=cell(2,numel(vertices)); +V=cell(numel(vertices),1); +E=cell(numel(vertices),1); +%Previously: +%MM=cell(2,nu,numel(vertices)); +%V=cell(nu,numel(vertices)); +%E=cell(nu+1,numel(vertices)); +sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) + +for kver=1:numel(vertices) + + %Everything must be updated by using interfaces_all instead of interfaces TO DO + ver_patches=[];%vector with indices of patches containing the vertex + ver_patches_nabla={}; %cell array containing jacobians + ver_ind=[];%vector containing local index of vertex in the patch + nu=numel(vertices(kver).interfaces); + + boundary_v=0; + for im=1:nu + inter=vertices(kver).interfaces(im); + if isempty(interfaces_all(inter).side1) | isempty(interfaces_all(inter).side2) + boundary_v=1; + break + end + end + if boundary_v==0 + +% for h=1:numel(vertices(kver).interfaces) +% hint=vertices(kver).interfaces(h); +% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; +% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... +% sides(interfaces(hint).side2,vertices(kver).ind)]; +% end +% ver_patches=unique(ver_patches,'stable'); +% ver_ind=unique(ver_ind,'stable'); + + for im=1:nu %cycle over all the interfaces containing the vertex + inter=vertices(kver).interfaces(im); %global index of the interface + patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + ver_patches=[ver_patches patch_ind1 patch_ind2]; + ver_ind=[ver_ind vertex_ind1 vertex_ind2]; + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1)); + Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,1)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2)); + Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,2)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,3)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,3)); + Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,3)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,3)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,4)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,4)); + Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,4)); + Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,4)); + end + %Store the jacobian of F for the left patch + ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; + + t0(im,:)=Dv_F00; + t0p(im,:)=Dvv_F00; + d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... + /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); + d0p(im,:)=((-all_alpha0(inter,1)+all_alpha1(inter,1))*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... + (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... + ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + mix_der2(im,:)=Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); + end + ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + + %Pick the correct part of CC_edges_discarded %TO BE FIXED + if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); + else %the vertex is the right/top endpoint of im-th interface + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); + end + end + [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + %ver_ind=unique(ver_ind,'rows','stable'); + + %if the number of patches coincides with the number of interfaces, + %we add one fictional interface coinciding with the first one + %(just for coding-numbering reasons) +% if numel(ver_patches)==nu +% t0(nu+1,:)=t0(1,:); +% t0p(nu+1,:)=t0p(1,:); +% d0(nu+1,:)=d0(1,:); +% d0p(nu+1,:)=d0p(1,:); +% E{kver}{nu+1,1}=E{kver}{1,1}; +% E{kver}{nu+1,2}=E{kver}{1,2}; +% end + + %computing sigma + sigma=0; + for im=1:nu + sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); + end + sigma=1/(sigma/(p*(k+1)*nu)); + + %computing matrices MM and V + for im=1:nu + + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + V{kver}{im}=zeros(n1*n2,6); + im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) + im1=im_edges(1); im2=im_edges(2); + if im==2 %works only if the interfaces and patches are ordered in clockwise order + im1=4; im2=1; + end + j=1; + for j1=0:2 + for j2=0:2-j1 %the following computations work in the standard case + d00=(j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; + d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; + d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; + MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; + d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; + d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; + MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + %V_{i_m,i} + d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; + V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + + j=j+1; + end + end + %size(V{kver}{im}) + %keyboard + if interfaces_all(vertices(kver).interfaces(im1)).patch2==ver_patches(im)%the considered patch is the second patch edge im1 + E1=E{kver}{im1,2}; + else + E1=E{kver}{im1,1}; + end + if interfaces_all(vertices(kver).interfaces(im2)).patch2==ver_patches(im)%the considered patch is the second patch of edge im2 + E2=E{kver}{im2,2}; + else + E2=E{kver}{im2,1}; + end + CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; + %keyboard + end + end + +end + +end + +%TO DO: +%- case of boundary edges + +%TO BE TESTED +%- plots of the functions +%- continuity \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m new file mode 100644 index 00000000..975c8377 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m @@ -0,0 +1,423 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') %da scommentare! +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + sp.ndof_interior = 0; +% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 + sides = [interfaces(1).side1, interfaces(1).side2]; + for iptc = 1:sp.npatch +% This should be a loop on the interfaces to which the patch belongs + sp_bnd = spaces{iptc}.boundary(sides(iptc)); + interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + + [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + + sp.ndof_interface = ndof; % The number of functions in V^2 + sp.ndof = sp.ndof_interior + sp.ndof_interface; + + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + + global_indices = (sp.ndof_interior+1):sp.ndof; + Cpatch{iptc}(:,global_indices) = CC{iptc}; + end + + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) + + for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; + patch(2) = interfaces(iref).patch2; + side(1) = interfaces(iref).side1; + side(2) = interfaces(iref).side2; + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +% Absolute value of the determinant, to make it work for arbitrary orientation -> IMPORTANT! +% geo_map_jac = msh_side_int{ii}.geo_map_jac; %da scommentare! +% alpha{ii} = abs (geopdes_det__ (geo_map_jac)); +% if (side(ii) == 1 || side(ii) == 2) +% numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); +% denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); +% else +% numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); +% denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); +% end +% beta{ii} = numerator ./ denominator; + if ii==1 + alpha{ii}=113*(41 + 18*grev_pts{2}')/6544; + %-113*(41 + 18*tt{2})/6544; + beta{ii}=6622447/4826200 - (249660873*grev_pts{2}')/98937100; + %6622447/4826200 - (249660873*tt{2})/98937100; + elseif ii==2 + alpha{ii}=339*(17 + 8*grev_pts{2}')/6544; + %339*(17 + 8*tt{2})/6544; + beta{ii}=-225776957/197874200 + (54357979*grev_pts{2}')/24734275; + %-225776957/197874200 + (54357979*tt{2})/24734275; + end +% alpha{ii}(:) +% beta{ii}(:) +% pause + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel + val_aux = val * beta{ii}(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad * (tau1 / degu); + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj); + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces(iref).ornt == -1) + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; + CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); + end + + + end + + +%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% +% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R +% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) +% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) +% and the jacobian (jacdet) at the Greville points. The last index +% indicates the Greville point. +% sp_grev(ii) is a structure with the value of the basis functions +% (.shape_functions) at the Greville points. The last index indicates the Greville point. +% The previous one indicates the basis functions that are non-null on the +% element. This also includes functions from the interior. +% The number of the non-vanishing basis functions is in connectivity + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m new file mode 100644 index 00000000..2cce7ea5 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m @@ -0,0 +1,807 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces) + patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; + sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_vertices +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, vertices); + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + for iptc_on_interface = 1:2 + iptc = interface(intrfc).patches(iptc_on_interface); + Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; + end + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) + +p = space.sp_patch{1}.degree(1); +k=numel(msh.msh_patch{1}.breaks{1})-2; + +all_alpha0=zeros(numel(interfaces),2); +all_alpha1=zeros(numel(interfaces),2); +all_beta0=zeros(numel(interfaces),2); +all_beta1=zeros(numel(interfaces),2); +all_t0=zeros(numel(interfaces),2); + +%Initialize the cell array of CC_vertices matrices +for ii=1:space.npatch + for jj=numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end +%Initialize the cell array of CC_edges matrices +for jj=1:numel(interfaces) + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch1), ndof_per_interface(jj)); + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch2), ndof_per_interface(jj)); +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +brk = cell (1,msh.ndim); +for j=1:space.npatch + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1}=[0 1]'; + pts{2}=[0 1]'; + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + derivatives1{j}=msh_precompute (msh_pts_der1); %rdim x ndim x n_pts{1}x n_pts{2} + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + derivatives2{j}=msh_precompute (msh_pts_der2); %rdim x ndim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) + %At this point (check) + %D_u F^j(0,0)=squeeze(derivatives{j}(:,1,1)) + %D_u F^j(0,1)=squeeze(derivatives{j}(:,1,2)) + %D_u F^j(1,0)=squeeze(derivatives{j}(:,1,3)) + %D_u F^j(1,1)=squeeze(derivatives{j}(:,1,4)) + %D_v F^j(0,0)=squeeze(derivatives{j}(:,2,1)) + %D_v F^j(0,1)=squeeze(derivatives{j}(:,2,2)) + %D_v F^j(1,0)=squeeze(derivatives{j}(:,2,3)) + %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) +end + +%Construction of CC_edges +for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; %LEFT + patch(2) = interfaces(iref).patch2; %RIGHT + side(1) = interfaces(iref).side1; %LEFT + side(2) = interfaces(iref).side2; %RIGHT + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = 1:2 % The two patches (L-R) + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector + DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma=3*C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + %Saving alphas and betas (first column=L, second column=R) + all_alpha0(iref,:)=alpha0; + all_alpha1(iref,:)=alpha1; + all_beta0(iref,:)=beta0; + all_beta1(iref,:)=beta1; + %Saving t(0) + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces(iref).ornt == -1) %this should be still the same for the multipatch + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + ind0_s{iref}=ind0; %saving the indices for later use; + ind1_s{iref}=ind1; + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is he interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +%I actually need to consider the actual parametrization to compute d, t and sigma, don't I? + +for kver=1:numel(vertices) + nu=numel(vertices(kver).patches); + MM=cell(2,nu,numel(vertices)); + V=cell(nu,numel(vertices)); + E=cell(nu+1,numel(vertices)); + for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) + inter=vertices(kver).interface(im).glob_ind; %global index of the interface + patch_ind1=vertices(kver).interface(im).patch_i1; %global index of left patch of im-th interface + patch_ind2=vertices(kver).interface(im).patch_i2; %global index of right patch of im-th interface + vertex_ind1=vertices(kver).interface(im).vertex1; %local index of vertex in left patch + vertex_ind2=vertices(kver).interface(im).vertex2; %local index of vertex in right patch + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? + case 1 %vertex (0,0) + t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)); + t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,1)); + d0(im,:)=(squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)))... + /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); + d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,1,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1))... + +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... + +all_beta1(inter,1)*0)*derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,1)... + +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)))... + /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); + mix_der2(im,:)=derivatives2{vertices(kver).interface(im).patch_i1}(:,1,2,1); + E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + case 2 %vertex (1,0) + t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); + t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); + case 3 %vertex (1,1) + t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,4)); + t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,4)); + case 4 %vertex (0,1) + t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,2)); + t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,2)); + end + end + %compute sigma + sigma=0; + for im=1:nu + vertex_ind=vertices(kver).patches(im).vertex; %local index of the vertex in im-th pacth + patch_ind=vertices(kver).patches(im).patch_i; %global index of the im-th patch + switch vertex_ind + case 1 %vertex (0,0) + sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,1) derivatives1{vertices(kver).patches(im).patch_i}(2,2,1)]); + case 2 %vertex (1,0) + sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,3) derivatives1{vertices(kver).patches(im).patch_i}(2,2,3)]); + case 3 %vertex (1,1) + sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,4) derivatives1{vertices(kver).patches(im).patch_i}(2,2,4)]); + case 4 %vertex (0,1) + sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,2) derivatives1{vertices(kver).patches(im).patch_i}(2,2,2)]); + end + end + sigma=1/(sigma/(p*(k+1)*nu)); + + %computing matrices MM and V + for im=1:nu + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) + n2=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) + j=0; + for j1=0:2 + for j2=0:2-j1 + d00=(j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im,:)'; + d20_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im,:)'; + d11_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im,:)'; + MM{1,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im+1,:)'; + d20_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im+1,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im+1,:)'; + d11_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im+1,:)'; + MM{2,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + %V_{i_m,i} + d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; + V{im,kver}=zeros(n1*n2,6); + + side1=interfaces(vertices(kver).interface(im).patch_i1).side1; %side of left patch + switch side1 + case 1 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %correct that some of these are the already computed ds? + case 2 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + case 3 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + case 4 + V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + end + j=j+1; + end + end + CC_vertices{vertices(kver).patches(im).patch_i,kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; + end +end + + +%end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m new file mode 100644 index 00000000..7d095540 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m @@ -0,0 +1,911 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces) + patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; + sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, vertices); + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + for iptc_on_interface = 1:2 + iptc = interface(intrfc).patches(iptc_on_interface); + Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; + end + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); + +p = space.sp_patch{1}.degree(1); +k = numel(msh.msh_patch{1}.breaks{1})-2; +n= space.sp_patch{1}.sp_univ{1}.ndof; + +ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere +ndof_per_vertex=6*ones(1,numel(vertices)); + +all_alpha0=zeros(numel(interfaces_all),2); +all_alpha1=zeros(numel(interfaces_all),2); +all_beta0=zeros(numel(interfaces_all),2); +all_beta1=zeros(numel(interfaces_all),2); +all_t0=zeros(numel(interfaces_all),2); + +%Initialize the cell array of CC_vertices matrices +for ii=1:space.npatch + for jj=numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end +%Initialize the cell array of CC_edges matrices +for jj=1:numel(interfaces_all) + if isempty(interfaces_all(jj).patch1) + CC_edges{1,jj} = []; + else + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); + end + if isempty(interfaces_all(jj).patch2) + CC_edges{2,jj} = []; + else + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); + end +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +brk = cell (1,msh.ndim); +for j=1:space.npatch + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1}=[0 1]'; + pts{2}=[0 1]'; + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + msh_der1{j}=msh_precompute (msh_pts_der1); + derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + msh_der2{j}=msh_precompute (msh_pts_der2); + derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + %In this case (rdim=2) + %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space + %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) + %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) + %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) + %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) + %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) + %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) + %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) + + %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space + %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) + %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) + %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) + %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) + %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) + %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) + %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) + %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) + %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) + %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) + %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) +end + +%Construction of CC_edges +for iref = 1:numel(interfaces_all) + if ~isempty(interfaces_all(jj).patch1) + patch(1) = interfaces_all(iref).patch1; %LEFT + side(1) = interfaces_all(iref).side1; %LEFT + end + if ~isempty(interfaces_all(jj).patch2) + patch(2) = interfaces_all(iref).patch2; %RIGHT + side(2) = interfaces_all(iref).side2; %RIGHT + end + nnz_el=find(patch>0); + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = nnz_el % The two patches (L-R) + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + if nnz(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector + DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma=3*C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + %Saving alphas and betas (first column=L, second column=R) + all_alpha0(iref,:)=alpha0; + all_alpha1(iref,:)=alpha1; + all_beta0(iref,:)=beta0; + all_beta1(iref,:)=beta1; + %Saving t(0) + + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now we assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + ind0_s{iref}=ind0; %saving the indices for later use; + ind1_s{iref}=ind1; + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + end + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is the interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +MM=cell(2,numel(vertices)); +V=cell(numel(vertices),1); +E=cell(numel(vertices),1); +%Previously: +%MM=cell(2,nu,numel(vertices)); +%V=cell(nu,numel(vertices)); +%E=cell(nu+1,numel(vertices)); +sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) + +for kver=1:numel(vertices) + + %Everything must be updated by using interfaces_all instead of interfaces TO DO + ver_patches=[];%vector with indices of patches containing the vertex + ver_patches_nabla={}; %cell array containing jacobians + ver_ind=[];%vector containing local index of vertex in the patch + nu=numel(vertices(kver).interfaces); + +% for h=1:numel(vertices(kver).interfaces) +% hint=vertices(kver).interfaces(h); +% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; +% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... +% sides(interfaces(hint).side2,vertices(kver).ind)]; +% end +% ver_patches=unique(ver_patches,'stable'); +% ver_ind=unique(ver_ind,'stable'); + + for im=1:nu %cycle over all the interfaces containing the vertex + inter=vertices(kver).interfaces(im); %global index of the interface + patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + ver_patches=[ver_patches patch_ind1 patch_ind2]; + ver_ind=[ver_ind vertex_ind1 vertex_ind2]; + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); + Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); + Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); + Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); + end + %Store the jacobian of F for the left patch + ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; + + t0(im,:)=Dv_F00; + t0p(im,:)=Dvv_F00; + d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... + /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); + d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... + -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... + ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + mix_der2(im,:)=Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); + case 2 %vertex (0,1) + Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); + case 3 %vertex (1,0) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); + Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); + case 4 %vertex (1,1) + Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); + Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); + end + ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + + %Pick the correct part of CC_edges_discarded %TO BE FIXED + if vertices(kver).ind(im)==1 + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); + else + E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); + E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); + end + end + [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + %ver_ind=unique(ver_ind,'rows','stable'); + + %if the number of patches coincides with the number of interfaces, + %we add one fictional interface coinciding with the first one + %(just for coding-numbering reasons) + if numel(ver_patches)==nu + t0(nu+1,:)=t0(1,:); + t0p(nu+1,:)=t0p(1,:); + d0(nu+1,:)=d0(1,:); + d0p(nu+1,:)=d0p(1,:); + E{kver}{nu,1}=E{kver}{1,1}; + E{kver}{nu,2}=E{kver}{1,2}; + end + + %computing sigma + sigma=0; + for im=1:nu + sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); + end + sigma=1/(sigma/(p*(k+1)*nu)); + + %computing matrices MM and V + for im=1:nu + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges + im1=im_edges(1); im2=im_edges(2); + j=0; + for j1=0:2 + for j2=0:2-j1 %the following computations work in the standard case + d00=(j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; + d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; + d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; + d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; + MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} + d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; + d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; + d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; + d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; + MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + %V_{i_m,i} + d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; + V{kver}{im}=zeros(n1*n2,6); + V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + j=j+1; + end + end + if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 + E1=E{kver}{im1,2}; + else + E1=E{kver}{im1,1}; + end + if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 + E2=E{kver}{im2,2}; + else + E2=E{kver}{im2,1}; + end + CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; + end +end + + +end + +%TO DO: +%- case of boundary edges +%- compute number of ndof per edge, per vertex + +%TO BE TESTED +%- number of functions +%- plots of the functions +%- continuity \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m new file mode 100644 index 00000000..fb4aee5c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m @@ -0,0 +1,409 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + for iptc = 1:numel(geometry) + if (any (geometry(iptc).nurbs.order > 2)) + error ('For now, only bilinear patches are implemented') + end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + sp.ndof_interior = 0; +% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 + sides = [interfaces(1).side1, interfaces(1).side2]; + for iptc = 1:sp.npatch +% This should be a loop on the interfaces to which the patch belongs + sp_bnd = spaces{iptc}.boundary(sides(iptc)); + interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + + [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + + sp.ndof_interface = ndof; % The number of functions in V^2 + sp.ndof = sp.ndof_interior + sp.ndof_interface; + + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + + global_indices = (sp.ndof_interior+1):sp.ndof; + Cpatch{iptc}(:,global_indices) = CC{iptc}; + end + + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) + + for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; + patch(2) = interfaces(iref).patch2; + side(1) = interfaces(iref).side1; + side(2) = interfaces(iref).side2; + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +% Absolute value of the determinant, to make it work for arbitrary orientation + geo_map_jac = msh_side_int{ii}.geo_map_jac; + alpha{ii} = abs (geopdes_det__ (geo_map_jac)); + if (side(ii) == 1 || side(ii) == 2) + numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + else + numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); + denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); + end + beta{ii} = numerator ./ denominator; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel + val_aux = val * beta{ii}(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj); + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces(iref).ornt == -1) + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; + CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); + end + + + end + + +%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% +% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R +% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) +% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) +% and the jacobian (jacdet) at the Greville points. The last index +% indicates the Greville point. +% sp_grev(ii) is a structure with the value of the basis functions +% (.shape_functions) at the Greville points. The last index indicates the Greville point. +% The previous one indicates the basis functions that are non-null on the +% element. This also includes functions from the interior. +% The number of the non-vanishing basis functions is in connectivity + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m new file mode 100644 index 00000000..f0bc345b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m @@ -0,0 +1,592 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1_twopatch (spaces, msh, geometry, interfaces, boundary_interfaces) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 +% XXX FOR NOW ONLY FOR TWO PATCHES + +if (numel (interfaces) > 1 || msh.npatch > 2) + error ('For now, the implementation only works for two patches') +end + + sp.ndof_interior = 0; +% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 + sides = [interfaces(1).side1, interfaces(1).side2]; + for iptc = 1:sp.npatch +% This should be a loop on the interfaces to which the patch belongs + sp_bnd = spaces{iptc}.boundary(sides(iptc)); + interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + + [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + + sp.ndof_interface = ndof; % The number of functions in V^2 + sp.ndof = sp.ndof_interior + sp.ndof_interface; + + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + + global_indices = (sp.ndof_interior+1):sp.ndof; + Cpatch{iptc}(:,global_indices) = CC{iptc}; + end + + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + +% XXXX No boundary for now +% % Boundary construction +% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) +% sp_bnd = cell (msh.boundary.npatch, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); +% end +% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); +% +% dofs = zeros (sp.boundary.ndof, 1); +% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); +% for iptc = 1:msh.boundary.npatch +% patch_number = msh.boundary.patch_numbers(iptc); +% side_number = msh.boundary.side_numbers(iptc); +% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% if (~isempty (sp.boundary.dofs_ornt)) +% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... +% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); +% end +% end +% sp.boundary.dofs = dofs; +% sp.boundary.boundary_orientation = boundary_orientation; +% +% else +% sp.boundary = []; +% end +% +% sp.dofs = []; +% sp.boundary_orientation = []; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1_twopatch'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) + + + for iref = 1:numel(interfaces) + patch(1) = interfaces(iref).patch1; + patch(2) = interfaces(iref).patch2; + side(1) = interfaces(iref).side1; + side(2) = interfaces(iref).side2; + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + for idim = 1:msh.ndim + %Greville points for G^1 conditions system + geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; + p1=geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; + p2=geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1}=aveknt(aug_geo_knot1,p1+1); + grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector + DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector + DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector + DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector + DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector + DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector + if side(2)==1 || side(2)==2 + v=grev_pts{2}'; + else + v=grev_pts{1}'; + end + A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... + (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; + if rank(A_full)==6 + A=A_full(:,2:end); + b=-A_full(:,1); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=sols(1); %R + alpha0_n(1)=sols(2); %L + alpha1_n(1)=sols(3); %L + beta0_n=sols(4); + beta1_n=sols(5); + beta2_n=sols(6); + else + A=A_full(:,3:end); + b=-sum(A_full(:,1:2),2); + sols=A\b; + alpha0_n(2)=1; %R + alpha1_n(2)=1; %R + alpha0_n(1)=sols(1); %L + alpha1_n(1)=sols(2); %L + beta0_n=sols(3); + beta1_n=sols(4); + beta2_n=sols(5); + end + + %STEP 4 - Normalizing the alphas + C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + +alpha0_n(1)^2+alpha0_n(2)^2; + C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + gamma=-C2/(2*C1); + alpha0(2)=alpha0_n(2)*gamma; %R + alpha1(2)=alpha1_n(2)*gamma; %R + alpha0(1)=alpha0_n(1)*gamma; %L + alpha1(1)=alpha1_n(1)*gamma; %L + bbeta0=beta0_n*gamma; + bbeta1=beta1_n*gamma; + bbeta2=beta2_n*gamma; + + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0=alpha0(1); %alpha_L(0) + alpha_L_1=alpha1(1); %alpha_L(1) + alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_R_0=alpha0(2); %alpha_L(0) + alpha_R_1=alpha1(2); %alpha_L(1) + alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0=bbeta0; %beta(0) + beta_1=bbeta2; %beta(1) + beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + + if rank(M)==3 + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a=quant2; b=quant1; + c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; + e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; + C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; + beta0(1)=-C2/(2*C1); %L + beta1(1)=a+b*beta0(1); %L + beta0(2)=c+d*beta0(1); %R + beta1(2)=e+f*beta0(1); %R + + else + + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b=[-b*c-2*a*b; -a*d-2*c*d]; + sol=M2\M2b; + beta0(1)= sol(1); %L + beta1(1)= sol(2); %L + beta0(2)= a+b*beta0(1); %R + beta1(2)= c+d*beta1(1); %R + + end + + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (L-R) + brk = cell (1,msh.ndim); + knots = space.sp_patch{patch(ii)}.knots; + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = space.sp_patch{patch(1)}.degree(ind1); + knots0 = space.knots0_patches{patch(ii)}{ind1}; + knots1 = space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + if (numel(grev_pts{idim}) > 1) + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + else + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + end + msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + ind2 = ceil (side(ii)/2); + degu = space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); + else + tau1 = knt(end) - knt(end-1); + end + +% For now I assume that the orientation is as in the paper, and we do not need any reordering +%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_grev contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); + msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (side(ii) == 2) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + elseif (side(ii) == 4) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = val * beta{ii}(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu); %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj); + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof) only works for the two patch case, for now + ndof = sp0_struct.ndof + sp1_struct.ndof; + CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); + + ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 2) + ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + elseif (side(ii) == 4) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + if (ii == 2 && interfaces(iref).ornt == -1) + ind0 = fliplr (ind0); + ind1 = fliplr (ind1); + coeff0{2} = flipud (fliplr (coeff0{2})); + coeff1{2} = flipud (fliplr (coeff1{2})); + coeff2{2} = flipud (fliplr (coeff2{2})); + end + + CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; + CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); + end + +%CHECKING G^1 condition +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% for ii = 1:2 % The two patches (L-R) +% brk = cell (1,msh.ndim); +% knots = space.sp_patch{patch(ii)}.knots; +% for idim = 1:msh.ndim +% %Greville points for G^1 conditions system +% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; +% p1=geometry(patch(ii)).nurbs.order(1); +% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; +% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; +% p2=geometry(patch(ii)).nurbs.order(2); +% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; +% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); +% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); +% if (numel(grev_pts{idim}) > 1) +% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; +% else +% brk{idim} = [knots{idim}(1) knots{idim}(end)]; +% end +% end +% +% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); +% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); +% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); +% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% end +% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; +% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation +% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; +% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; +% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector +% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector +% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector +% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector +% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector +% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector +%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta +% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x +% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y +% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... +% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; +% alpha{1} +% alpha{2} +% beta{1} +% beta{2} +% bbeta +% alpha0 +% alpha1 +% beta0 +% beta1 +%pause +% grev_pts{1} +% grev_pts{2} + + end + + +%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% +% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R +% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) +% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) +% and the jacobian (jacdet) at the Greville points. The last index +% indicates the Greville point. +% sp_grev(ii) is a structure with the value of the basis functions +% (.shape_functions) at the Greville points. The last index indicates the Greville point. +% The previous one indicates the basis functions that are non-null on the +% element. This also includes functions from the interior. +% The number of the non-vanishing basis functions is in connectivity + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m new file mode 100644 index 00000000..4175c601 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m @@ -0,0 +1,58 @@ +% SP_PLOT_SOLUTION: Plot the computed solution, given the degrees of freedom. +% +% [eu, F] = sp_plot_solution (u, space, geometry, pts, [ncuts=2]); +% [eu, F] = sp_plot_solution (u, space, geometry, [npts], [ncuts=2]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_multipatch_C1) +% geometry: an array of geometry structures (see mp_geo_load) +% pts: cell array with coordinates of points along each parametric direction +% npts: number of points along each parametric direction +% ncuts: only for volumetric domains, number of internal "cuts" in each parametric direction. +% The zero value will plot the solution on the boundary. +% +% Copyright (C) 2016, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_plot_solution (u, space, geometry, npts, ncuts) + +if (nargin < 4) + npts = []; +end +if (nargin < 5) + ncuts = []; +end + +% if (isa (space.sp_patch{1}, 'sp_vector')) +% disp ('Warning: a different scaling is used for each patch') +% end + +hold_flag = ishold ; +for iptc = 1:space.npatch +% if (isempty (space.dofs_ornt)) + sp_plot_solution (space.Cpatch{iptc}* u, space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% else +% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% end + hold on +end + +if (~hold_flag) + hold off +end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m new file mode 100644 index 00000000..f8f87553 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m @@ -0,0 +1,68 @@ +% SP_REFINE: construct a refined space from a given one. The function only +% refines the space, the mesh must be refined separately. +% +% [sp_fine, Proj] = sp_refine (space, msh, nsub, [degree], [regularity]); +% +% The same number of subdivisions, degree and regularity is applied to every patch +% +% INPUTS: +% +% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch) +% msh: an object of the msh_multipatch class, usuallly the refined mesh (see msh_multipatch) +% nsub: number of uniform subdivisions to apply on each knot span, and for each direction +% degree: degree of the fine space, and for each direction +% regularity: regularity for the new space, and for each direction +% +% OUTPUT: +% +% sp_fine: the refined space, an object of the class sp_multipatch (see sp_multipatch) +% Proj: the coefficients relating 1D splines of the coarse and the fine spaces for each patch. +% A cell-array of size 1 x npatch, each entry containing the +% coefficients for the patch (either for scalar or vector-valued spaces). +% +% Copyright (C) 2015, 2016 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [sp_fine, Proj, Proj0, Proj1] = sp_refine (space, msh, nsub, degree, regularity) + + if (nargin < 4) + degree = space.sp_patch{1}.degree; + end + if (nargin < 5) + regularity = degree - 2; + end + + sp_fine = cell (1, space.npatch); + Proj = cell (1, space.npatch); + Proj0 = cell (1, space.npatch); + Proj1 = cell (1, space.npatch); + for iptc = 1:space.npatch + if (nargout > 1) + [sp_fine{iptc}, Proj{iptc}] = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); +% Refine also the spaces of degree p, regularity r+1; and degree p-1, regularity r + knots0_fine = kntrefine (space.knots0_patches{iptc}, nsub-1, degree, regularity+1); + knots1_fine = kntrefine (space.knots1_patches{iptc}, nsub-1, degree-1, regularity); + for idim = 1:msh.ndim + Proj0{iptc}{idim} = basiskntins (degree(idim), space.knots0_patches{iptc}{idim}, knots0_fine{idim}); + Proj1{iptc}{idim} = basiskntins (degree(idim)-1, space.knots1_patches{iptc}{idim}, knots1_fine{idim}); + end + else + sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); + end + end + sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, []); + + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m new file mode 100644 index 00000000..e3d71569 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m @@ -0,0 +1,82 @@ +% SP_TO_VTK: Export multipatch results to VTK format for plotting. +% +% sp_to_vtk (u, space, geometry, npts, filename, fieldnames, [option], [lambda_lame, mu_lame]) +% +% INPUT: +% +% u: vector of dof weights +% space: object representing the space of discrete functions (see sp_multipatch) +% geometry: geometry structure (see geo_load) +% npts: number of points along each parametric direction where to evaluate +% filename: name of the output file. +% fieldnames: how to name the saved variables in the vtk file +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient', +% and for vectors also 'curl', 'divergence', 'stress' +% lambda_lame: function handle to the first Lame coefficient (only needed to compute 'stress') +% mu_lame: function handle for the second Lame coefficient (only needed to compute 'stress') +% +% OUTPUT: +% +% none +% +% Copyright (C) 2010 Carlo de Falco, Rafael Vazquez +% Copyright (C) 2011, 2012, 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) + + str1 = cat (2,' \n', ... +' \n', ... +' \n'); + + str2 = cat (2, ' \n'); + + str3 = cat (2, ... +'\n', ... +' \n'); + + if (length (filename) < 4 || ~strcmp (filename(end-3:end), '.pvd')) + pvd_filename = cat (2, filename, '.pvd'); + else + pvd_filename = filename; + filename = filename (1:end-4); + end + + fid = fopen (pvd_filename, 'w'); + if (fid < 0) + error ('mp_sp_to_vtk: could not open file %s', pvd_filename); + end + + fprintf (fid, str1); + ind = union (find (filename == '/', 1, 'last'), find (filename == '\', 1, 'last')) + 1; + if (isempty (ind)); ind = 1; end + for iptc = 1:space.npatch + filename_patch_without_path = cat (2, filename(ind:end), '_', num2str (iptc)); + filename_patch = cat (2, filename, '_', num2str (iptc)); + fprintf (fid, str2, iptc, filename_patch_without_path); +% if (isempty (space.dofs_ornt)) + sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + filename_patch, fieldname, varargin{:}) +% else +% sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... +% filename_patch, fieldname, varargin{:}) +% end + end + fprintf (fid, str3); + + fclose (fid); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m new file mode 100644 index 00000000..f36aa68d --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m @@ -0,0 +1,95 @@ +% SP_WEAK_DRCHLT_BC_LAPLACE: compute the matrix and right hand-side to impose +% the Dirichlet boundary conditions in weak form for Laplace (Poisson) problem. +% +% The code computes the following terms in the left hand-side +% +% - \int_{Gamma_D} mu*{du/dn v - dv/dn u + (Cpen / he) * (u v)} +% +% and in the right hand-side +% +% - \int_{Gamma_D} mu*{dv/dn g + (Cpen / he) * (v g)} +% +% with u the trial function, v the test function, he the normal characteristic length, +% and g the boundary condition to be imposed. +% +% +% [N_mat, N_rhs] = sp_weak_drchlt_bc_stokes (space, msh, refs, bnd_func, coeff, Cpen) +% +% INPUTS: +% +% space_v: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch). +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% refs: boundary sides on which the Dirichlet condition is imposed +% bnd_func: the condition to be imposed (g in the equations) +% coeff: function handle for the viscosity coefficient (mu in the equation) +% Cpen: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% N_rhs: the computed right hand-side +% +% Copyright (C) 2014 Adriano Cortes, Rafael Vazquez +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A, rhs] = sp_weak_drchlt_bc_laplace (space, msh, refs, bnd_func, coeff, Cpen, varargin) + + if (nargin < 6 || isempty (Cpen)) + Cpen = 10 * (min (space.sp_patch{1}.degree) + 1); + end + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros (space.ndof, 1); + +% Compute the matrices to impose the tangential boundary condition weakly + for iref = refs + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + + coeff_at_qnodes = coeff (x{:}); + + % Since trial and test spaces are the same, we can use B' + B = op_gradv_n_u (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + gradv_n_g = op_gradv_n_f (sp_bnd, msh_side, g_times_coeff); + + coeff_at_qnodes = coeff_at_qnodes * Cpen ./ msh_side.charlen; + C = op_u_v (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); + + g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; + g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); + + A = A + space.Cpatch{iptc}.' * (B + B' - C ) * space.Cpatch{iptc}; + rhs = rhs + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); +% dofs = space.gnum{iptc}; +% A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); +% rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; + end + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m new file mode 100644 index 00000000..1c89450c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m @@ -0,0 +1,4 @@ +%% override private write access of objects in this class +function obj = subsasgn (obj, S, value) +obj = builtin('subsasgn', obj, S, value); +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m new file mode 100644 index 00000000..9f7048b6 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m @@ -0,0 +1,4 @@ +%% override private read access of object data +function value = subsref (obj, S) +value = builtin ('subsref', obj, S); +end \ No newline at end of file From b9964224ec0d485cdde8c6fbbb4722d20ff09acd Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 26 Feb 2021 19:35:31 +0100 Subject: [PATCH 052/366] Fixed some bugs in the computation of gluing data, but still not C^1 edge and vertex functions --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f38b8eec..f708e890 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -469,29 +469,29 @@ %STEP 5 - Computing the betas %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + alpha_L_0=alpha0(2); %alpha_L(0) + alpha_L_1=alpha1(2); %alpha_L(1) + alpha_L_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + alpha_R_0=alpha0(1); %alpha_L(0) + alpha_R_1=alpha1(1); %alpha_L(1) + alpha_R_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) beta_0=bbeta0; %beta(0) beta_1=bbeta2; %beta(1) beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; + M=[alpha_L_0 0 alpha_R_0 0; 0 alpha_L_1 0 alpha_R_1; alpha_L_12/2 alpha_L_12/2 alpha_R_12/2 alpha_R_12/2]; if rank(M)==3 %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant1=(-alpha_R_12/2+(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/(-(alpha_R_1*alpha_L_12)/(2*alpha_L_1)+alpha_R_12/2); quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; + c=beta_0/alpha_L_0; d=-alpha_R_0/alpha_L_0; + e=(beta_1-alpha_R_1*quant2)/alpha_L_1; f=-alpha_R_1*quant1/alpha_L_1; %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; @@ -505,8 +505,8 @@ %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; + a=beta_0/alpha_L_0; b=-alpha_R_0/alpha_L_0; + c=beta_1/alpha_L_1; d=-alpha_R_1/alpha_L_1; %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R %The resuting system is @@ -527,7 +527,8 @@ all_beta1(iref,:)=beta1; % Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (R-L) + for ii = 1:2 % The two patches (L-R) + ii_ab=3-ii; %this will be used to access the correct alphas and betas brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -592,8 +593,8 @@ end %alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; + alpha{ii}=abs(alpha0(ii_ab)*(1-grev_pts{2}')+alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii}=beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; % RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); @@ -629,9 +630,9 @@ val_grad = val_grad * (-1)^(side(ii)+1); rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii-1); %with the multipatch settings must be multiplied by -1 for left patch; + val_aux = val * alpha{ii}(jj)* (-1)^(ii); %with the multipatch settings must be multiplied by -1 for left patch; rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; end coeff2{ii} = A \ rhsc; From 9f84381a4f704810cb806dbf48199e98a0c35a01 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 3 Mar 2021 16:55:10 +0100 Subject: [PATCH 053/366] interior edge functions working --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f708e890..55347634 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -486,20 +486,20 @@ %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L quant1=(-alpha_R_12/2+(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/(-(alpha_R_1*alpha_L_12)/(2*alpha_L_1)+alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); + quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/(-(alpha_R_1*alpha_L_12)/(2*alpha_L_1)+alpha_R_12/2); %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=-alpha_R_0/alpha_L_0; - e=(beta_1-alpha_R_1*quant2)/alpha_L_1; f=-alpha_R_1*quant1/alpha_L_1; + a=quant2; b=quant1; %? + c=beta_0/alpha_L_0; d=-alpha_R_0/alpha_L_0; %this is ok + e=(beta_1-alpha_R_1*quant2)/alpha_L_1; f=-alpha_R_1*quant1/alpha_L_1; %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R + beta0(2)=-C2/(2*C1); %L + beta1(2)=a+b*beta0(2); %L + beta0(1)=c+d*beta0(2); %R + beta1(1)=e+f*beta0(2); %R else @@ -513,10 +513,10 @@ M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; M2b=[-b*c-2*a*b; -a*d-2*c*d]; sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R + beta0(2)= sol(1); %L + beta1(2)= sol(2); %L + beta0(1)= a+b*beta0(2); %R + beta1(1)= c+d*beta1(2); %R end @@ -525,6 +525,8 @@ all_alpha1(iref,:)=alpha1; all_beta0(iref,:)=beta0; all_beta1(iref,:)=beta1; + %keyboard + % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) @@ -594,7 +596,8 @@ %alphas and betas alpha{ii}=abs(alpha0(ii_ab)*(1-grev_pts{2}')+alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; + beta{ii}=beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; + %keyboard looks like alpha must be inverted, but betas mustn't % RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); From 666cdba9e03e4d15cacf95cc1df3b256f32322de Mon Sep 17 00:00:00 2001 From: cesare Date: Wed, 10 Mar 2021 08:51:52 +0100 Subject: [PATCH 054/366] A few changes to follow more closely the procedure and notation of the paper draft --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 55347634..1ba1cad4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -788,13 +788,13 @@ % end % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); - +% 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) for im=1:nu %cycle over all the interfaces containing the vertex inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + patch_ind2=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind1=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind2=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind1=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch ver_patches=[ver_patches patch_ind1 patch_ind2]; ver_ind=[ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -831,23 +831,28 @@ (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(im,:)=Duv_F00; + mix_der2(2*im-1,:)=Duv_F00; %We need to get the jacobian also for the right patch switch vertex_ind2 case 1 %vertex (0,0) Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); + Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,1)); case 2 %vertex (0,1) Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); + Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,2)); case 3 %vertex (1,0) Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); + Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,3)); case 4 %vertex (1,1) Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); + Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,4)); end ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + mix_der2(2*im,:)=Duv_F00; %Pick the correct part of CC_edges_discarded %TO BE FIXED if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface @@ -859,8 +864,12 @@ end end [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + mix_der2_n=mix_der2(ind_patch_sigma,:); %ver_ind=unique(ver_ind,'rows','stable'); + %ind_patch_sigma contains the positions of the elements of ver_patches + %originally (each of them is present twice, the first one is considered) + %if the number of patches coincides with the number of interfaces, %we add one fictional interface coinciding with the first one %(just for coding-numbering reasons) @@ -881,16 +890,16 @@ sigma=1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V - for im=1:nu + for im=1:nu %cycle over the patches containing the vertex %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) V{kver}{im}=zeros(n1*n2,6); - im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) + im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) im1=im_edges(1); im2=im_edges(2); - if im==2 %works only if the interfaces and patches are ordered in clockwise order - im1=4; im2=1; + if im~=1 %works only if the interfaces and patches are ordered in clockwise order + temp=im1; im1=im2; im2=temp; %this is done to have always the interface to the right of the patch in im1 end j=1; for j1=0:2 @@ -916,10 +925,10 @@ d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2_n(im,:)'; + V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - + %keyboard j=j+1; end end @@ -936,7 +945,6 @@ E2=E{kver}{im2,1}; end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; - %keyboard end end From d43cc2e069a704ed3e88d78d9cdaf043da9c3ce8 Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 26 Mar 2021 08:56:54 +0100 Subject: [PATCH 055/366] small modificiations to have the same indexing of edges and patches as in the draft of the paper --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 55347634..c9dc8fbb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -307,6 +307,7 @@ CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); end end +%keyboard %Initialize the cell array of CC_edges matrices for jj=1:numel(interfaces_all) if isempty(interfaces_all(jj).patch1) @@ -788,13 +789,13 @@ % end % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); - +% 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) for im=1:nu %cycle over all the interfaces containing the vertex inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + patch_ind2=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind1=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind2=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind1=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch ver_patches=[ver_patches patch_ind1 patch_ind2]; ver_ind=[ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -831,23 +832,28 @@ (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(im,:)=Duv_F00; + mix_der2(2*im-1,:)=Duv_F00; %We need to get the jacobian also for the right patch switch vertex_ind2 case 1 %vertex (0,0) Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); + Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,1)); case 2 %vertex (0,1) Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); + Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,2)); case 3 %vertex (1,0) Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); + Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,3)); case 4 %vertex (1,1) Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); + Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,4)); end ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; + mix_der2(2*im,:)=Duv_F00; %Pick the correct part of CC_edges_discarded %TO BE FIXED if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface @@ -859,8 +865,12 @@ end end [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); + mix_der2_n=mix_der2(ind_patch_sigma,:); %ver_ind=unique(ver_ind,'rows','stable'); + %ind_patch_sigma contains the positions of the elements of ver_patches + %originally (each of them is present twice, the first one is considered) + %if the number of patches coincides with the number of interfaces, %we add one fictional interface coinciding with the first one %(just for coding-numbering reasons) @@ -881,16 +891,16 @@ sigma=1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V - for im=1:nu + for im=1:nu %cycle over the patches containing the vertex %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) V{kver}{im}=zeros(n1*n2,6); - im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) + im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) im1=im_edges(1); im2=im_edges(2); - if im==2 %works only if the interfaces and patches are ordered in clockwise order - im1=4; im2=1; + if im~=1 %works only if the interfaces and patches are ordered in clockwise order + temp=im1; im1=im2; im2=temp; %this is done to have always the interface to the right of the patch in im1 end j=1; for j1=0:2 @@ -916,10 +926,10 @@ d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... + [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2_n(im,:)'; + V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - + %keyboard j=j+1; end end @@ -936,7 +946,6 @@ E2=E{kver}{im2,1}; end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; - %keyboard end end From e47efcd2418c1173d8ee3fa5ce4f86c312070964 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 26 Mar 2021 12:05:08 +0100 Subject: [PATCH 056/366] Changed indices for orientation. Simplified computation of Kronecker deltas --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index c9dc8fbb..e5b7ecb3 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -792,10 +792,10 @@ % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) for im=1:nu %cycle over all the interfaces containing the vertex inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind2=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind1=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind2=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind1=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch ver_patches=[ver_patches patch_ind1 patch_ind2]; ver_ind=[ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -905,28 +905,30 @@ j=1; for j1=0:2 for j2=0:2-j1 %the following computations work in the standard case + mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; + vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; d00=(j1==0)*(j2==0); %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; - d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; - d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; + d10_a=vec_detlas*t0(im1,:)'; + d20_a=t0(im1,:)*mat_deltas*t0(im1,:)'+... + vec_deltas*t0p(im1,:)'; + d01_a=vec_deltas*d0(im1,:)'; + d11_a=t0(im1,:)*mat_deltas*d0(im1,:)'+... + vec_deltas*d0p(im1,:)'; MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; - d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; - d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; + d10_b=vec_deltas*t0(im2,:)'; + d20_b=t0(im2,:)*mat_deltas*t0(im2,:)'+... + vec_deltas*t0p(im2,:)'; + d01_b=vec_deltas*d0(im2,:)'; + d11_b=t0(im2,:)*mat_deltas*d0(im2,:)'+... + vec_deltas*d0p(im2,:)'; MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; %V_{i_m,i} - d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2_n(im,:)'; + d11_c=t0(im1,:)*mat_deltas*t0(im2,:)'+... + vec_deltas*mix_der2_n(im,:)'; V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %keyboard From 348d482cdc018ecf1cac0e9425514c6ae8540ef9 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 26 Mar 2021 12:11:37 +0100 Subject: [PATCH 057/366] Fixed bug --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index e5b7ecb3..01897e7b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -909,7 +909,7 @@ vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; d00=(j1==0)*(j2==0); %M_{i_{m-1},i} - d10_a=vec_detlas*t0(im1,:)'; + d10_a=vec_deltas*t0(im1,:)'; d20_a=t0(im1,:)*mat_deltas*t0(im1,:)'+... vec_deltas*t0p(im1,:)'; d01_a=vec_deltas*d0(im1,:)'; From df17d681f9b6d1c0958da68303f077ae14e486cd Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Mon, 29 Mar 2021 18:19:16 +0200 Subject: [PATCH 058/366] computation of d (d0) and its derivative corrected --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 01897e7b..2a7be584 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -826,12 +826,12 @@ t0(im,:)=Dv_F00; t0p(im,:)=Dvv_F00; - d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... - /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); - d0p(im,:)=((-all_alpha0(inter,1)+all_alpha1(inter,1))*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... - (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... - ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + d0(im,:)=(Du_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dv_F00)... + /(all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0); + d0p(im,:)=((-all_alpha0(inter,2)+all_alpha1(inter,2))*(Du_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dv_F00)+... + (all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)*(Duv_F00+... + (-all_beta0(inter,2)+all_beta1(inter,2))*Dv_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dvv_F00... + ))/(all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)^2; mix_der2(2*im-1,:)=Duv_F00; %We need to get the jacobian also for the right patch switch vertex_ind2 @@ -889,7 +889,6 @@ sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); end sigma=1/(sigma/(p*(k+1)*nu)); - %computing matrices MM and V for im=1:nu %cycle over the patches containing the vertex @@ -931,7 +930,7 @@ vec_deltas*mix_der2_n(im,:)'; V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - %keyboard + keyboard j=j+1; end end From 76e01659126c8541c6978e3a9325f68120dcb20e Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Mon, 29 Mar 2021 18:30:54 +0200 Subject: [PATCH 059/366] fixed bug --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 2a7be584..01263ef0 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -930,7 +930,7 @@ vec_deltas*mix_der2_n(im,:)'; V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - keyboard + %keyboard j=j+1; end end From 3852b339f07556a515cf1ea6201005d2e67d442a Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 31 Mar 2021 16:53:11 +0200 Subject: [PATCH 060/366] reordering of left-right interfaces indices for a patch when computing vertex functions --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 01263ef0..46f65a3f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -898,7 +898,7 @@ V{kver}{im}=zeros(n1*n2,6); im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) im1=im_edges(1); im2=im_edges(2); - if im~=1 %works only if the interfaces and patches are ordered in clockwise order + if im==1 %works only if the interfaces and patches are ordered in clockwise order temp=im1; im1=im2; im2=temp; %this is done to have always the interface to the right of the patch in im1 end j=1; @@ -947,6 +947,9 @@ E2=E{kver}{im2,1}; end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; + boundary_dofs_right=[1 9 17 25 33 41 49 57]; %for debug + boundary_dofs_left=1:8; %for debug + %keyboard end end From 4b1445d09646e06d85328404a3ec7a01fedd3b0f Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Wed, 7 Apr 2021 10:05:45 +0200 Subject: [PATCH 061/366] Fixed some elements of matrices MM for the case r=p-2 --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 46f65a3f..40351d42 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -291,6 +291,9 @@ p = space.sp_patch{1}.degree(1); k = numel(msh.msh_patch{1}.breaks{1})-2; n= space.sp_patch{1}.sp_univ(1).ndof; +breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); +mult=histc(space.sp_patch{1}.knots{1},breaks_m{1}); +reg=p-max(mult(2:end-1)); ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere ndof_per_vertex=6*ones(1,numel(vertices)); @@ -914,17 +917,25 @@ d01_a=vec_deltas*d0(im1,:)'; d11_a=t0(im1,:)*mat_deltas*d0(im1,:)'+... vec_deltas*d0p(im1,:)'; - MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + %M_{i_{m+1},i} d10_b=vec_deltas*t0(im2,:)'; d20_b=t0(im2,:)*mat_deltas*t0(im2,:)'+... vec_deltas*t0p(im2,:)'; d01_b=vec_deltas*d0(im2,:)'; d11_b=t0(im2,:)*mat_deltas*d0(im2,:)'+... - vec_deltas*d0p(im2,:)'; - MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + vec_deltas*d0p(im2,:)'; + if reg Date: Wed, 7 Apr 2021 17:31:54 +0200 Subject: [PATCH 062/366] Another fix of some elements of matrices MM (all cases) --- .../inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 40351d42..79ba0676 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -927,14 +927,14 @@ vec_deltas*d0p(im2,:)'; if reg Date: Wed, 7 Apr 2021 19:01:44 +0200 Subject: [PATCH 063/366] Compuite gluing data in a separate function (in the same file) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 263 +++++++++--------- 1 file changed, 135 insertions(+), 128 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 79ba0676..41f38847 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -412,125 +412,14 @@ % end end - if length(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - if side(2)==1 || side(2)==2 - v=grev_pts{2}(:); - else - v=grev_pts{1}(:); - end - ngrev=numel(v); - DuFR_x=reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector - DuFR_y=reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector - DvFL_x=reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector - DvFL_y=reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector - DvFR_x=reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector - DvFR_y=reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector - - A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %keyboard - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); - gamma=3*C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - + if (length(patch)==2) %as it is placed now, this check computes the matrices corresponding only to interior edges + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(2); %alpha_L(0) - alpha_L_1=alpha1(2); %alpha_L(1) - alpha_L_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - alpha_R_0=alpha0(1); %alpha_L(0) - alpha_R_1=alpha1(1); %alpha_L(1) - alpha_R_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 alpha_R_0 0; 0 alpha_L_1 0 alpha_R_1; alpha_L_12/2 alpha_L_12/2 alpha_R_12/2 alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(-alpha_R_12/2+(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/(-(alpha_R_1*alpha_L_12)/(2*alpha_L_1)+alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/(-(alpha_R_1*alpha_L_12)/(2*alpha_L_1)+alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; %? - c=beta_0/alpha_L_0; d=-alpha_R_0/alpha_L_0; %this is ok - e=(beta_1-alpha_R_1*quant2)/alpha_L_1; f=-alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(2)=-C2/(2*C1); %L - beta1(2)=a+b*beta0(2); %L - beta0(1)=c+d*beta0(2); %R - beta1(1)=e+f*beta0(2); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=-alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=-alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(2)= sol(1); %L - beta1(2)= sol(2); %L - beta0(1)= a+b*beta0(2); %R - beta1(1)= c+d*beta1(2); %R - - end - %Saving alphas and betas (first column=L, second column=R) - all_alpha0(iref,:)=alpha0; - all_alpha1(iref,:)=alpha1; - all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %keyboard - + all_alpha0(iref,:) = alpha0; + all_alpha1(iref,:) = alpha1; + all_beta0(iref,:) = beta0; + all_beta1(iref,:) = beta1; % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) @@ -599,8 +488,8 @@ end %alphas and betas - alpha{ii}=abs(alpha0(ii_ab)*(1-grev_pts{2}')+alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; + alpha{ii} = abs(alpha0(ii_ab)*(1-grev_pts{2}')+alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii} = beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; %keyboard looks like alpha must be inverted, but betas mustn't % RHS for the first linear system, (14) in Mario's notes @@ -667,8 +556,8 @@ if (ii == 2 & interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch ind0 = fliplr (ind0); ind1 = fliplr (ind1); - ind0_s{iref}=ind0; %saving the indices for later use; - ind1_s{iref}=ind1; + ind0_s{iref} = ind0; %saving the indices for later use; + ind1_s{iref} = ind1; coeff0{2} = flipud (fliplr (coeff0{2})); coeff1{2} = flipud (fliplr (coeff1{2})); coeff2{2} = flipud (fliplr (coeff2{2})); @@ -682,14 +571,14 @@ CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); end - else - n0=n-k; - ndof=n0+n-k-1; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); + else + n0=n-k; + ndof=n0+n-k-1; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); % size(CC_edges{ii,iref}) % keyboard - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); end %CHECKING G^1 condition @@ -970,9 +859,127 @@ end +function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + if (side(2)==1 || side(2)==2) + v = grev_pts{2}(:); + else + v = grev_pts{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector + DuFR_y = reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector + DvFL_x = reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector + DvFL_y = reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector + DvFR_x = reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector + DvFR_y = reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(2) = 1; %R + alpha1_n(2) = sols(1); %R + alpha0_n(1) = sols(2); %L + alpha1_n(1) = sols(3); %L + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(2) = 1; %R + alpha1_n(2) = 1; %R + alpha0_n(1) = sols(1); %L + alpha1_n(1) = sols(2); %L + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end + + %keyboard + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1 = alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; + C2 = alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + gamma = 3*C2/(2*C1); + alpha0(2) = alpha0_n(2)*gamma; %R + alpha1(2) = alpha1_n(2)*gamma; %R + alpha0(1) = alpha0_n(1)*gamma; %L + alpha1(1) = alpha1_n(1)*gamma; %L + bbeta0 = beta0_n*gamma; + bbeta1 = beta1_n*gamma; + bbeta2 = beta2_n*gamma; + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_L_0 = alpha0(2); %alpha_L(0) + alpha_L_1 = alpha1(2); %alpha_L(1) + alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + alpha_R_0 = alpha0(1); %alpha_L(0) + alpha_R_1 = alpha1(1); %alpha_L(1) + alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + beta_0 = bbeta0; %beta(0) + beta_1 = bbeta2; %beta(1) + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M = [alpha_L_0 0 alpha_R_0 0; ... + 0 alpha_L_1 0 alpha_R_1; ... + alpha_L_12/2 alpha_L_12/2 alpha_R_12/2 alpha_R_12/2]; + + if (rank(M)==3) + + %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L + quant1 = (-alpha_R_12/2 + (alpha_R_0*alpha_L_12)/(2*alpha_L_0)) / ... + (-(alpha_R_1*alpha_L_12)/(2*alpha_L_1) + alpha_R_12/2); + quant2 = (beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0) - (beta_1*alpha_L_12)/(2*alpha_L_1)) / ... + (-(alpha_R_1*alpha_L_12)/(2*alpha_L_1) + alpha_R_12/2); + + %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + a = quant2; b = quant1; + c = beta_0/alpha_L_0; d = -alpha_R_0/alpha_L_0; + e = (beta_1-alpha_R_1*quant2)/alpha_L_1; f = -alpha_R_1*quant1/alpha_L_1; + + %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; + C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; + beta0(2) = -C2/(2*C1); %L + beta1(2) = a + b*beta0(2); %L + beta0(1) = c + d*beta0(2); %R + beta1(1) = e + f*beta0(2); %R + + else + %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a = beta_0/alpha_L_0; b = -alpha_R_0/alpha_L_0; + c = beta_1/alpha_L_1; d = -alpha_R_1/alpha_L_1; + + %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %The resuting system is + M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b = [-b*c-2*a*b; -a*d-2*c*d]; + sol = M2\M2b; + beta0(2)= sol(1); %L + beta1(2)= sol(2); %L + beta0(1)= a + b*beta0(2); %R + beta1(1)= c + d*beta1(2); %R + end + +end + %TO DO: %- case of boundary edges %TO BE TESTED %- plots of the functions -%- continuity \ No newline at end of file +%- continuity + + From dd0cf31a5dc4e3dfca050205f5f73a5e9bbb227a Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:11:48 +0200 Subject: [PATCH 064/366] Estetica --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 41f38847..bc4eb2c7 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -290,57 +290,57 @@ p = space.sp_patch{1}.degree(1); k = numel(msh.msh_patch{1}.breaks{1})-2; -n= space.sp_patch{1}.sp_univ(1).ndof; +n = space.sp_patch{1}.sp_univ(1).ndof; breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); -mult=histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg=p-max(mult(2:end-1)); +mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); +reg = p-max(mult(2:end-1)); -ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere -ndof_per_vertex=6*ones(1,numel(vertices)); +ndof_per_interface = (2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere +ndof_per_vertex = 6*ones(1,numel(vertices)); -all_alpha0=zeros(numel(interfaces_all),2); -all_alpha1=zeros(numel(interfaces_all),2); -all_beta0=zeros(numel(interfaces_all),2); -all_beta1=zeros(numel(interfaces_all),2); -all_t0=zeros(numel(interfaces_all),2); +all_alpha0 = zeros(numel(interfaces_all),2); +all_alpha1 = zeros(numel(interfaces_all),2); +all_beta0 = zeros(numel(interfaces_all),2); +all_beta1 = zeros(numel(interfaces_all),2); +all_t0 = zeros(numel(interfaces_all),2); %Initialize the cell array of CC_vertices matrices -for ii=1:space.npatch - for jj=numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end +for ii = 1:space.npatch + for jj = 1:numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end end -%keyboard + %Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces_all) - if isempty(interfaces_all(jj).patch1) - CC_edges{1,jj} = []; - else - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); - end - if isempty(interfaces_all(jj).patch2) - CC_edges{2,jj} = []; - else - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); - end +for jj = 1:numel(interfaces_all) + if (isempty(interfaces_all(jj).patch1)) + CC_edges{1,jj} = []; + else + CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); + end + if (isempty(interfaces_all(jj).patch2)) + CC_edges{2,jj} = []; + else + CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); + end end %computing for each patch all the derivatives we possibly need to compute t,d, and sigma brk = cell (1,msh.ndim); for j=1:space.npatch - knots = space.sp_patch{j}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1}=[0 1]'; - pts{2}=[0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - msh_der1{j}=msh_precompute (msh_pts_der1); - derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - msh_der2{j}=msh_precompute (msh_pts_der2); - derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + knots = space.sp_patch{j}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1} = [0 1]'; + pts{2} = [0 1]';%pts{2}=[0 1/2 1]' + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); + msh_der1{j} = msh_precompute (msh_pts_der1); + derivatives1{j} = msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); + msh_der2{j} = msh_precompute (msh_pts_der2); + derivatives2{j} = msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} %In this case (rdim=2) %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) From 4068a4baedf45a0f40fd2c2bdd3cf29031d01acf Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:18:50 +0200 Subject: [PATCH 065/366] Some cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index bc4eb2c7..edbc2971 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -327,20 +327,18 @@ %computing for each patch all the derivatives we possibly need to compute t,d, and sigma brk = cell (1,msh.ndim); -for j=1:space.npatch - knots = space.sp_patch{j}.knots; +for iptc = 1:space.npatch + knots = space.sp_patch{iptc}.knots; for idim = 1:msh.ndim brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? end %the following points correspond to the four vertices of the patch pts{1} = [0 1]'; pts{2} = [0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - msh_der1{j} = msh_precompute (msh_pts_der1); - derivatives1{j} = msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - msh_der2{j} = msh_precompute (msh_pts_der2); - derivatives2{j} = msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives1{j} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives2{j} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} %In this case (rdim=2) %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) From 90c22e920b73c38535650756651d301da22866dd Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:22:49 +0200 Subject: [PATCH 066/366] Cleaning and fixed bug from previous commit --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index edbc2971..680da9d7 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -337,8 +337,8 @@ pts{2} = [0 1]';%pts{2}=[0 1/2 1]' msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); msh_der = msh_precompute (msh_pts_der1); - derivatives1{j} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives2{j} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} + derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} %In this case (rdim=2) %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) @@ -365,31 +365,31 @@ %Construction of CC_edges for iref = 1:numel(interfaces_all) - clear patch - if ~isempty(interfaces_all(iref).patch1) - patch(1) = interfaces_all(iref).patch1; %LEFT - side(1) = interfaces_all(iref).side1; %LEFT - end - if ~isempty(interfaces_all(iref).patch2) - patch(2) = interfaces_all(iref).patch2; %RIGHT - side(2) = interfaces_all(iref).side2; %RIGHT - end - nnz_el=find(patch>0); + clear patch + if (~isempty(interfaces_all(iref).patch1)) + patch(1) = interfaces_all(iref).patch1; %LEFT + side(1) = interfaces_all(iref).side1; %LEFT + end + if (~isempty(interfaces_all(iref).patch2)) + patch(2) = interfaces_all(iref).patch2; %RIGHT + side(2) = interfaces_all(iref).side2; %RIGHT + end + nnz_el = find(patch>0); %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = nnz_el % The two patches (L-R) %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + for ii = nnz_el % The two patches (L-R) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); + geo_knot_v1 = geometry(patch(ii)).nurbs.knots{1}; + p1 = geometry(patch(ii)).nurbs.order(1); + aug_geo_knot1 = [geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; + geo_knot_v2 = geometry(patch(ii)).nurbs.knots{2}; + p2 = geometry(patch(ii)).nurbs.order(2); + aug_geo_knot2 = [geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; + grev_pts{1} = aveknt(aug_geo_knot1,p1+1); + grev_pts{2} = aveknt(aug_geo_knot2,p2+1); for idim = 1:msh.ndim if (numel(grev_pts{idim}) > 1) brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; From 5bf33efb160c766f7fa454cb3c4d8ef2cb1869b4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:54:35 +0200 Subject: [PATCH 067/366] Remove useless check --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 680da9d7..9cd2a9dd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -391,16 +391,12 @@ grev_pts{1} = aveknt(aug_geo_knot1,p1+1); grev_pts{2} = aveknt(aug_geo_knot2,p2+1); for idim = 1:msh.ndim - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; end msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_interior = msh_precompute (msh_side_interior); + geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) % if ii==1 && (side(ii)==3 || side(ii)==4) % disp('done1') % geo_map_jac{ii}=flip(geo_map_jac{ii}); From 9745bf4f352c16b37031fdd5b5e09766676440ec Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:57:57 +0200 Subject: [PATCH 068/366] Remove another unused check --- .../inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 9cd2a9dd..83653b65 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -417,7 +417,7 @@ % Compute the Greville points, and the auxiliary mesh and space objects for ii = 1:2 % The two patches (L-R) - ii_ab=3-ii; %this will be used to access the correct alphas and betas + ii_ab = 3-ii; %this will be used to access the correct alphas and betas brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -433,11 +433,7 @@ for idim = 1:msh.ndim grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; end msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); From 45e369e108cc65003b4ac23c944caa63a7a6d74f Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 09:58:42 +0200 Subject: [PATCH 069/366] Use real patch number --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 83653b65..5f01a24e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -427,7 +427,7 @@ ind2 = ceil (side(ii)/2); ind1 = setdiff (1:msh.ndim, ind2); - degree = space.sp_patch{patch(1)}.degree(ind1); + degree = space.sp_patch{patch(ii)}.degree(ind1); knots0 = space.knots0_patches{patch(ii)}{ind1}; knots1 = space.knots1_patches{patch(ii)}{ind1}; for idim = 1:msh.ndim From 594528f37dcff85d56c9517f6b080540b5927105 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 10:14:27 +0200 Subject: [PATCH 070/366] Removed unused msh_side_int. Other minor things --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 5f01a24e..bca743c9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -453,9 +453,9 @@ % msh_side_int contains information for the bivariate parametrization (dependence on u and v) % sp_grev contains the value and derivatives of the basis functions, at the Greville points msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_interior); +% msh_side_int{ii} = msh_precompute (msh_side_interior); % sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element % The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) @@ -477,10 +477,10 @@ A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); end -%alphas and betas - alpha{ii} = abs(alpha0(ii_ab)*(1-grev_pts{2}')+alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii} = beta0(ii_ab)*(1-grev_pts{2}')+beta1(ii_ab)*grev_pts{2}'; - %keyboard looks like alpha must be inverted, but betas mustn't +%alphas and betas % ORIENTATION ISSUE + alpha{ii} = abs (alpha0(ii_ab)*(1-grev_pts{2}') + alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii} = beta0(ii_ab)*(1-grev_pts{2}') + beta1(ii_ab)*grev_pts{2}'; + %looks like alpha must be inverted, but betas mustn't % RHS for the first linear system, (14) in Mario's notes rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); @@ -543,7 +543,7 @@ ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); end - if (ii == 2 & interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch + if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch ind0 = fliplr (ind0); ind1 = fliplr (ind1); ind0_s{iref} = ind0; %saving the indices for later use; From d7de761aaf5d978608a818fb2d1fd32d27d492c1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 10:23:50 +0200 Subject: [PATCH 071/366] Change name: ndof -> ndof_edge --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index bca743c9..e35ed8bb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -525,9 +525,9 @@ coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse % Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); +% The numbering (ndof_edge) only works for the two patch case, for now + ndof_edge = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; if (side(ii) == 1) @@ -555,20 +555,18 @@ CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof_edge) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof_edge-2]); end else - n0=n-k; - ndof=n0+n-k-1; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); -% size(CC_edges{ii,iref}) -% keyboard - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); + n0 = n-k; + ndof_edge = n0+n-k-1; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); + CC_edges_discarded{ii,iref} = CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 + CC_edges{ii,iref} = CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof_edge-2]); end %CHECKING G^1 condition From f618aec8401168d91eb1baf4d7120772bbcc358e Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 10:37:59 +0200 Subject: [PATCH 072/366] Cleaning. Comment currently unused code --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index e35ed8bb..d7643b06 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -634,32 +634,32 @@ %We assume that the local numbering of interfaces and patches is such that %vertices(kver).interface(im) is the interface between %vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM=cell(2,numel(vertices)); -V=cell(numel(vertices),1); -E=cell(numel(vertices),1); +MM = cell(2,numel(vertices)); +V = cell(numel(vertices),1); +E = cell(numel(vertices),1); %Previously: %MM=cell(2,nu,numel(vertices)); %V=cell(nu,numel(vertices)); %E=cell(nu+1,numel(vertices)); -sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) +sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) -for kver=1:numel(vertices) +for kver = 1:numel(vertices) - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches=[];%vector with indices of patches containing the vertex - ver_patches_nabla={}; %cell array containing jacobians - ver_ind=[];%vector containing local index of vertex in the patch - nu=numel(vertices(kver).interfaces); + %Everything must be updated by using interfaces_all instead of interfaces TO DO + ver_patches = []; %vector with indices of patches containing the vertex + ver_patches_nabla = {}; %cell array containing jacobians + ver_ind = []; %vector containing local index of vertex in the patch + nu = numel(vertices(kver).interfaces); - boundary_v=0; - for im=1:nu - inter=vertices(kver).interfaces(im); - if isempty(interfaces_all(inter).side1) | isempty(interfaces_all(inter).side2) - boundary_v=1; - break - end + boundary_vertex = 0; + for im = 1:nu + inter = vertices(kver).interfaces(im); + if (isempty(interfaces_all(inter).side1) || isempty(interfaces_all(inter).side2)) + boundary_vertex = 1; + break end - if boundary_v==0 + end + if (~boundary_vertex) % for h=1:numel(vertices(kver).interfaces) % hint=vertices(kver).interfaces(h); @@ -670,37 +670,37 @@ % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) - for im=1:nu %cycle over all the interfaces containing the vertex - inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch - ver_patches=[ver_patches patch_ind1 patch_ind2]; - ver_ind=[ver_ind vertex_ind1 vertex_ind2]; + for im = 1:nu %cycle over all the interfaces containing the vertex + inter = vertices(kver).interfaces(im); %global index of the interface + patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of im-th interface + patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of im-th interface + vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch + vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + ver_patches = [ver_patches patch_ind1 patch_ind2]; + ver_ind = [ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1)); - Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,1)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2)); - Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,2)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,3)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,3)); - Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,3)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,3)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,4)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,4)); - Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,4)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,4)); - end + switch vertex_ind1 + case 1 %vertex (0,0) + Du_F00 = derivatives1{patch_ind1}(:,1,1); + Dv_F00 = derivatives1{patch_ind1}(:,2,1); + Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); + Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); +% case 2 %vertex (0,1) +% Du_F00 = derivatives1{patch_ind1}(:,1,2); +% Dv_F00 = -derivatives1{patch_ind1}(:,2,2); +% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,2); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,2); +% case 3 %vertex (1,0) +% Du_F00 = -derivatives1{patch_ind1}(:,1,3); +% Dv_F00 = derivatives1{patch_ind1}(:,2,3); +% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,3); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,3); +% case 4 %vertex (1,1) +% Du_F00 = -derivatives1{patch_ind1}(:,1,4); +% Dv_F00 = -derivatives1{patch_ind1}(:,2,4); +% Duv_F00 = derivatives2{patch_ind1}(:,1,2,4); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); + end %Store the jacobian of F for the left patch ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; @@ -841,7 +841,7 @@ %corner_4dofs=[1 2 9 10]; %keyboard end - end + end end From aad774525380d86539f40f8bd26f9a06ec91942a Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 10:44:06 +0200 Subject: [PATCH 073/366] Cleaning. Improve readability. Comment currently unused code --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d7643b06..4fa1bad4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -702,36 +702,37 @@ % Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); end %Store the jacobian of F for the left patch - ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; + ver_patches_nabla{2*im-1} = [Du_F00 Dv_F00]; - t0(im,:)=Dv_F00; - t0p(im,:)=Dvv_F00; - d0(im,:)=(Du_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dv_F00)... - /(all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0); - d0p(im,:)=((-all_alpha0(inter,2)+all_alpha1(inter,2))*(Du_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dv_F00)+... - (all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)*(Duv_F00+... - (-all_beta0(inter,2)+all_beta1(inter,2))*Dv_F00+(all_beta0(inter,2)*(1-0)+all_beta1(inter,2)*0)*Dvv_F00... - ))/(all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)^2; - mix_der2(2*im-1,:)=Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); - Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); - Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); - Duv_F00=-squeeze(derivatives2{patch_ind2}(:,1,2,3)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); - Duv_F00=squeeze(derivatives2{patch_ind2}(:,1,2,4)); - end + t0(im,:) = Dv_F00; + t0p(im,:) = Dvv_F00; + d0(im,:) = (Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) / ... + (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0); + d0p(im,:) = ((-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... + (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0) * ... + (Duv_F00 + (-all_beta0(inter,2) + all_beta1(inter,2))*Dv_F00 + ... + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dvv_F00)) / ... + (all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)^2; + mix_der2(2*im-1,:) = Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00 = derivatives1{patch_ind2}(:,1,1); + Dv_F00 = derivatives1{patch_ind2}(:,2,1); + Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); +% case 2 %vertex (0,1) +% Du_F00 = derivatives1{patch_ind2}(:,1,2); +% Dv_F00 = -derivatives1{patch_ind2}(:,2,2); +% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,2); +% case 3 %vertex (1,0) +% Du_F00 = -derivatives1{patch_ind2}(:,1,3); +% Dv_F00 = derivatives1{patch_ind2}(:,2,3); +% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,3); +% case 4 %vertex (1,1) +% Du_F00 = -derivatives1{patch_ind2}(:,1,4); +% Dv_F00 = -derivatives1{patch_ind2}(:,2,4); +% Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); + end ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; mix_der2(2*im,:)=Duv_F00; From 1cb3db22a4eaaa2261d48ec8d230f6bf3cf3488c Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 11:01:31 +0200 Subject: [PATCH 074/366] Some more cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 156 ++++++++---------- 1 file changed, 73 insertions(+), 83 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 4fa1bad4..6409861d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -733,20 +733,20 @@ % Dv_F00 = -derivatives1{patch_ind2}(:,2,4); % Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); end - ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; - mix_der2(2*im,:)=Duv_F00; + ver_patches_nabla{2*im} = [Du_F00 Dv_F00]; + mix_der2(2*im,:) = Duv_F00; - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); - else %the vertex is the right/top endpoint of im-th interface - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end + %Pick the correct part of CC_edges_discarded %TO BE FIXED + if (vertices(kver).ind(im) == 1) %the vertex is the left/bottom endpoint of im-th interface + E{kver}{im,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{im,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); +% else %the vertex is the right/top endpoint of im-th interface +% E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); +% E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); + end end - [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); - mix_der2_n=mix_der2(ind_patch_sigma,:); + [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); + mix_der2_n = mix_der2(ind_patch_sigma,:); %ver_ind=unique(ver_ind,'rows','stable'); %ind_patch_sigma contains the positions of the elements of ver_patches @@ -765,82 +765,74 @@ % end %computing sigma - sigma=0; - for im=1:nu - sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); + sigma = 0; + for im = 1:nu + sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); end - sigma=1/(sigma/(p*(k+1)*nu)); + sigma = 1/(sigma/(p*(k+1)*nu)); %computing matrices MM and V - for im=1:nu %cycle over the patches containing the vertex + for im = 1:nu %cycle over the patches containing the vertex %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - V{kver}{im}=zeros(n1*n2,6); - im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) - im1=im_edges(1); im2=im_edges(2); - if im==1 %works only if the interfaces and patches are ordered in clockwise order - temp=im1; im1=im2; im2=temp; %this is done to have always the interface to the right of the patch in im1 - end - j=1; - for j1=0:2 - for j2=0:2-j1 %the following computations work in the standard case - mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; - vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; - d00=(j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a=vec_deltas*t0(im1,:)'; - d20_a=t0(im1,:)*mat_deltas*t0(im1,:)'+... - vec_deltas*t0p(im1,:)'; - d01_a=vec_deltas*d0(im1,:)'; - d11_a=t0(im1,:)*mat_deltas*d0(im1,:)'+... - vec_deltas*d0p(im1,:)'; - - %M_{i_{m+1},i} - d10_b=vec_deltas*t0(im2,:)'; - d20_b=t0(im2,:)*mat_deltas*t0(im2,:)'+... - vec_deltas*t0p(im2,:)'; - d01_b=vec_deltas*d0(im2,:)'; - d11_b=t0(im2,:)*mat_deltas*d0(im2,:)'+... - vec_deltas*d0p(im2,:)'; - if reg Date: Thu, 8 Apr 2021 11:18:52 +0200 Subject: [PATCH 075/366] Replace variable name --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 6409861d..7740c400 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -764,7 +764,7 @@ % E{kver}{nu+1,2}=E{kver}{1,2}; % end - %computing sigma + %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices sigma = 0; for im = 1:nu sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); @@ -782,7 +782,7 @@ if (im == 1) %works only if the interfaces and patches are ordered in clockwise order temp = im1; im1 = im2; im2 = temp; %this is done to have always the interface to the right of the patch in im1 end - jj = 1; + jfun = 1; for j1 = 0:2 for j2 = 0:2-j1 %the following computations work in the standard case mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; @@ -800,19 +800,19 @@ d01_b = vec_deltas*d0(im2,:)'; d11_b = t0(im2,:)*mat_deltas*d0(im2,:)' + vec_deltas*d0p(im2,:)'; if (reg < p-2) - MM{1,kver}{im}(:,jj) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... + MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - MM{2,kver}{im}(:,jj) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; else - MM{1,kver}{im}(:,jj) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... + MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - MM{2,kver}{im}(:,jj) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... + MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; end %V_{i_m,i} d11_c = t0(im1,:)*mat_deltas*t0(im2,:)' + vec_deltas*mix_der2_n(im,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],jj) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... + V{kver}{im}([1, 2, n2+1, n2+2],jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %keyboard jj = jj+1; From d7e3828a7ce468bc6c387a1f1ce3617fbac8019c Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 11:56:49 +0200 Subject: [PATCH 076/366] Fixed my stupid bug --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 7740c400..abaac813 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -815,19 +815,19 @@ V{kver}{im}([1, 2, n2+1, n2+2],jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %keyboard - jj = jj+1; + jfun = jfun+1; end end % Check which patch of the edge function we are considering if (interfaces_all(vertices(kver).interfaces(im1)).patch2 == ver_patches(im))%the considered patch is the second patch edge im1 - E1=E{kver}{im1,2}; + E1 = E{kver}{im1,2}; else - E1=E{kver}{im1,1}; + E1 = E{kver}{im1,1}; end if (interfaces_all(vertices(kver).interfaces(im2)).patch2 == ver_patches(im))%the considered patch is the second patch of edge im2 - E2=E{kver}{im2,2}; + E2 = E{kver}{im2,2}; else - E2=E{kver}{im2,1}; + E2 = E{kver}{im2,1}; end CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im}; %csi2=[1 9 17 25 33 41 49 57]; From 911aa4caef3a7a6346c82bccd785132a3862a248 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 12:57:09 +0200 Subject: [PATCH 077/366] Some cleaning to make debugging easier. No changes --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index abaac813..b904ffc5 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -782,6 +782,8 @@ if (im == 1) %works only if the interfaces and patches are ordered in clockwise order temp = im1; im1 = im2; im2 = temp; %this is done to have always the interface to the right of the patch in im1 end + + corner_4dofs = [1 2 n2+1 n2+2]; jfun = 1; for j1 = 0:2 for j2 = 0:2-j1 %the following computations work in the standard case @@ -800,20 +802,36 @@ d01_b = vec_deltas*d0(im2,:)'; d11_b = t0(im2,:)*mat_deltas*d0(im2,:)' + vec_deltas*d0p(im2,:)'; if (reg < p-2) - MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... +% MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... +% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; +% MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... +% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... + MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; else - MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... - -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... - -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; +% MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... +% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; +% MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... +% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + MM1(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(p*(k+1)), ... + d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... + -d01_a/(p*(k+1)), ... + -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + MM2(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(p*(k+1)), ... + d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... + -d01_b/(p*(k+1)), ... + -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; end %V_{i_m,i} d11_c = t0(im1,:)*mat_deltas*t0(im2,:)' + vec_deltas*mix_der2_n(im,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+d10_b/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + V{kver}{im}(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(p*(k+1)), ... + d00+d10_b/(p*(k+1)),... + d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %keyboard jfun = jfun+1; end @@ -829,10 +847,10 @@ else E2 = E{kver}{im2,1}; end - CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im}; +% CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im}; + CC_vertices{ver_patches(im),kver} = E1*MM1 + E2*MM2 - V{kver}{im}; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; - %corner_4dofs=[1 2 9 10]; end end From 91a8ab9399c558f7718231da014ff4914c8fdd30 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 17:12:58 +0200 Subject: [PATCH 078/366] Changed some variable names, to distinguish edges and patches --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 140 +++++++++--------- 1 file changed, 72 insertions(+), 68 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index b904ffc5..0b4a6d73 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -649,10 +649,10 @@ ver_patches = []; %vector with indices of patches containing the vertex ver_patches_nabla = {}; %cell array containing jacobians ver_ind = []; %vector containing local index of vertex in the patch - nu = numel(vertices(kver).interfaces); + ninterfaces_ver = numel(vertices(kver).interfaces); boundary_vertex = 0; - for im = 1:nu + for im = 1:ninterfaces_ver inter = vertices(kver).interfaces(im); if (isempty(interfaces_all(inter).side1) || isempty(interfaces_all(inter).side2)) boundary_vertex = 1; @@ -670,12 +670,12 @@ % ver_patches=unique(ver_patches,'stable'); % ver_ind=unique(ver_ind,'stable'); % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) - for im = 1:nu %cycle over all the interfaces containing the vertex - inter = vertices(kver).interfaces(im); %global index of the interface - patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch + for iedge = 1:ninterfaces_ver %cycle over all the interfaces containing the vertex + inter = vertices(kver).interfaces(iedge); %global index of the interface + patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface + patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface + vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch + vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch ver_patches = [ver_patches patch_ind1 patch_ind2]; ver_ind = [ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -702,18 +702,18 @@ % Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); end %Store the jacobian of F for the left patch - ver_patches_nabla{2*im-1} = [Du_F00 Dv_F00]; - - t0(im,:) = Dv_F00; - t0p(im,:) = Dvv_F00; - d0(im,:) = (Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) / ... + ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; + + t0(iedge,:) = Dv_F00; + t0p(iedge,:) = Dvv_F00; + d0(iedge,:) = (Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) / ... (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0); - d0p(im,:) = ((-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... + d0p(iedge,:) = ((-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0) * ... (Duv_F00 + (-all_beta0(inter,2) + all_beta1(inter,2))*Dv_F00 + ... (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dvv_F00)) / ... (all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)^2; - mix_der2(2*im-1,:) = Duv_F00; + mix_der2(2*iedge-1,:) = Duv_F00; %We need to get the jacobian also for the right patch switch vertex_ind2 case 1 %vertex (0,0) @@ -733,17 +733,17 @@ % Dv_F00 = -derivatives1{patch_ind2}(:,2,4); % Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); end - ver_patches_nabla{2*im} = [Du_F00 Dv_F00]; - mix_der2(2*im,:) = Duv_F00; + ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; + mix_der2(2*iedge,:) = Duv_F00; %Pick the correct part of CC_edges_discarded %TO BE FIXED - if (vertices(kver).ind(im) == 1) %the vertex is the left/bottom endpoint of im-th interface - E{kver}{im,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{im,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); + if (vertices(kver).ind(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface + E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); % else %the vertex is the right/top endpoint of im-th interface % E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); % E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end + end end [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); mix_der2_n = mix_der2(ind_patch_sigma,:); @@ -755,33 +755,34 @@ %if the number of patches coincides with the number of interfaces, %we add one fictional interface coinciding with the first one %(just for coding-numbering reasons) -% if numel(ver_patches)==nu -% t0(nu+1,:)=t0(1,:); -% t0p(nu+1,:)=t0p(1,:); -% d0(nu+1,:)=d0(1,:); -% d0p(nu+1,:)=d0p(1,:); -% E{kver}{nu+1,1}=E{kver}{1,1}; -% E{kver}{nu+1,2}=E{kver}{1,2}; +% if numel(ver_patches)==ninterfaces_ver +% t0(ninterfaces_ver+1,:)=t0(1,:); +% t0p(ninterfaces_ver+1,:)=t0p(1,:); +% d0(ninterfaces_ver+1,:)=d0(1,:); +% d0p(ninterfaces_ver+1,:)=d0p(1,:); +% E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; +% E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; % end %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices sigma = 0; - for im = 1:nu + for im = 1:ninterfaces_ver % FIX: is this the number of interfaces? sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); end - sigma = 1/(sigma/(p*(k+1)*nu)); + sigma = 1/(sigma/(p*(k+1)*ninterfaces_ver)); %computing matrices MM and V - for im = 1:nu %cycle over the patches containing the vertex + for ipatch = 1:ninterfaces_ver %FIX: cycle over the patches containing the vertex %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1 = space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2 = space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - V{kver}{im} = zeros(n1*n2,6); - im_edges = ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) - im1 = im_edges(1); im2 = im_edges(2); - if (im == 1) %works only if the interfaces and patches are ordered in clockwise order - temp = im1; im1 = im2; im2 = temp; %this is done to have always the interface to the right of the patch in im1 + n1 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) +% V{kver}{im} = zeros(n1*n2,6); + VV = zeros(n1*n2,6); + im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) + if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order + im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 end + iedge1 = im_edges(1); iedge2 = im_edges(2); corner_4dofs = [1 2 n2+1 n2+2]; jfun = 1; @@ -791,30 +792,30 @@ vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; d00 = (j1==0)*(j2==0); %M_{i_{m-1},i} - d10_a = vec_deltas*t0(im1,:)'; - d20_a = t0(im1,:)*mat_deltas*t0(im1,:)' + vec_deltas*t0p(im1,:)'; - d01_a = vec_deltas*d0(im1,:)'; - d11_a = t0(im1,:)*mat_deltas*d0(im1,:)' + vec_deltas*d0p(im1,:)'; + d10_a = vec_deltas*t0(iedge1,:)'; + d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; + d01_a = vec_deltas*d0(iedge1,:)'; + d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; %M_{i_{m+1},i} - d10_b = vec_deltas*t0(im2,:)'; - d20_b = t0(im2,:)*mat_deltas*t0(im2,:)' + vec_deltas*t0p(im2,:)'; - d01_b = vec_deltas*d0(im2,:)'; - d11_b = t0(im2,:)*mat_deltas*d0(im2,:)' + vec_deltas*d0p(im2,:)'; + d10_b = vec_deltas*t0(iedge2,:)'; + d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; + d01_b = vec_deltas*d0(iedge2,:)'; + d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; if (reg < p-2) -% MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... -% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; -% MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... -% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; +% MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... +% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; +% MM{2,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... +% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; else -% MM{1,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... -% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; -% MM{2,kver}{im}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... -% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; +% MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... +% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; +% MM{2,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... +% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; MM1(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(p*(k+1)), ... d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... @@ -827,28 +828,31 @@ -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; end %V_{i_m,i} - d11_c = t0(im1,:)*mat_deltas*t0(im2,:)' + vec_deltas*mix_der2_n(im,:)'; - V{kver}{im}(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(p*(k+1)), ... - d00+d10_b/(p*(k+1)),... - d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - %keyboard + d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; +% V{kver}{ipatch}(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_a/(p*(k+1)), ... +% d00+d10_b/(p*(k+1)),... +% d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(p*(k+1)), ... + d00+d10_b/(p*(k+1)),... + d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; jfun = jfun+1; end end % Check which patch of the edge function we are considering - if (interfaces_all(vertices(kver).interfaces(im1)).patch2 == ver_patches(im))%the considered patch is the second patch edge im1 - E1 = E{kver}{im1,2}; + if (interfaces_all(vertices(kver).interfaces(iedge1)).patch2 == ver_patches(ipatch))%the considered patch is the second patch edge iedge1 + E1 = E{kver}{iedge1,2}; else - E1 = E{kver}{im1,1}; + E1 = E{kver}{iedge1,1}; end - if (interfaces_all(vertices(kver).interfaces(im2)).patch2 == ver_patches(im))%the considered patch is the second patch of edge im2 - E2 = E{kver}{im2,2}; + if (interfaces_all(vertices(kver).interfaces(iedge2)).patch2 == ver_patches(ipatch))%the considered patch is the second patch of edge iedge2 + E2 = E{kver}{iedge2,2}; else - E2 = E{kver}{im2,1}; + E2 = E{kver}{iedge2,1}; end -% CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im}; - CC_vertices{ver_patches(im),kver} = E1*MM1 + E2*MM2 - V{kver}{im}; +% CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; + CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; end From 6c1a4f8353e5853e9a604e4ec00933c21da4ca03 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 17:15:35 +0200 Subject: [PATCH 079/366] Initialize MM1 and MM2 --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 1 + 1 file changed, 1 insertion(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 0b4a6d73..9b9882f6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -777,6 +777,7 @@ n1 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) n2 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) % V{kver}{im} = zeros(n1*n2,6); + MM1 = zeros(5,6); MM2 = zeros(5,6); VV = zeros(n1*n2,6); im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order From 243d57d3aa468bf31993ca04a9a586da26d19ecb Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Apr 2021 18:50:58 +0200 Subject: [PATCH 080/366] Reduced number of points --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 9b9882f6..e06cfdff 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -379,19 +379,13 @@ %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions for ii = nnz_el % The two patches (L-R) + % Points for G^1 conditions system brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - %Greville points for G^1 conditions system - geo_knot_v1 = geometry(patch(ii)).nurbs.knots{1}; - p1 = geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1 = [geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2 = geometry(patch(ii)).nurbs.knots{2}; - p2 = geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2 = [geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1} = aveknt(aug_geo_knot1,p1+1); - grev_pts{2} = aveknt(aug_geo_knot2,p2+1); + knt = geometry(patch(ii)).nurbs.knots; + order = geometry(patch(ii)).nurbs.order; for idim = 1:msh.ndim - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; + brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; end msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); From aef1827bd5f537897f2242f6349b832d23ec074b Mon Sep 17 00:00:00 2001 From: cesare bracco Date: Fri, 9 Apr 2021 11:42:48 +0200 Subject: [PATCH 081/366] New fix on the vertex functions matrices MM1 and MM2 --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index e06cfdff..d614ad33 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -803,9 +803,9 @@ % MM{2,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... % -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; else % MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... % -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; @@ -814,13 +814,13 @@ MM1(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(p*(k+1)), ... d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... - -d01_a/(p*(k+1)), ... - -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + d01_a/(p*(k+1)), ... + d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; MM2(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_b/(p*(k+1)), ... d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... - -d01_b/(p*(k+1)), ... - -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + d01_b/(p*(k+1)), ... + d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; end %V_{i_m,i} d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; From 1820855ac2adf46de9cdce254fc6d5bd8111b164 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 9 Apr 2021 18:19:13 +0200 Subject: [PATCH 082/366] Added comment --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index e06cfdff..b3c9f9fd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -887,7 +887,7 @@ beta1_n = sols(5); beta2_n = sols(6); else - A = A_full(:,3:end); + A = A_full(:,3:end); % FIX: not a square matrix b = -sum(A_full(:,1:2),2); sols = A\b; alpha0_n(2) = 1; %R From 16b258905a71081da9d1f55d4b5ad66eec8a6062 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 14 Apr 2021 15:49:10 +0200 Subject: [PATCH 083/366] Changed coefficients of V matrix (not 100% sure it is correct) --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f8706e8e..24c19180 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -829,8 +829,8 @@ % d00+d10_b/(p*(k+1)),... % d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(p*(k+1)), ... - d00+d10_b/(p*(k+1)),... + d00+d10_b/(p*(k+1)), ... + d00+d10_a/(p*(k+1)),... d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; jfun = jfun+1; end From fa68dc860d33aedd725c4c675eb9729f09aaef40 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 14 Apr 2021 18:28:20 +0200 Subject: [PATCH 084/366] Heuristic changes that made it work for the regular case, not for the general one. --- .../inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 24c19180..8cfe969c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -829,8 +829,8 @@ % d00+d10_b/(p*(k+1)),... % d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(p*(k+1)), ... - d00+d10_a/(p*(k+1)),... + d00+d10_a/(p*(k+1)), ... + d00+d10_b/(p*(k+1)),... d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; jfun = jfun+1; end @@ -846,8 +846,11 @@ else E2 = E{kver}{iedge2,1}; end + XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); + XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; + CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; end From 7eab27abaa43c18206f06553b955bca76666c4c4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 16 Apr 2021 15:43:44 +0200 Subject: [PATCH 085/366] Edge functions as in Mario's code (change of sign). --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 8cfe969c..eea587a9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -512,7 +512,7 @@ rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii); %with the multipatch settings must be multiplied by -1 for left patch; + val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; end coeff2{ii} = A \ rhsc; @@ -829,8 +829,8 @@ % d00+d10_b/(p*(k+1)),... % d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(p*(k+1)), ... - d00+d10_b/(p*(k+1)),... + d00+d10_b/(p*(k+1)), ... + d00+d10_a/(p*(k+1)),... d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; jfun = jfun+1; end @@ -847,10 +847,10 @@ E2 = E{kver}{iedge2,1}; end XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); - XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); +% % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; - CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; +% % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; end From 03f95a6e47231065d4dd39f47cc799098e439305 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 16 Apr 2021 17:29:40 +0200 Subject: [PATCH 086/366] Working code. We have to understand why --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index eea587a9..4099e21a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -761,7 +761,7 @@ %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices sigma = 0; for im = 1:ninterfaces_ver % FIX: is this the number of interfaces? - sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); + sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); end sigma = 1/(sigma/(p*(k+1)*ninterfaces_ver)); %computing matrices MM and V @@ -790,13 +790,13 @@ d10_a = vec_deltas*t0(iedge1,:)'; d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; d01_a = vec_deltas*d0(iedge1,:)'; - d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; + d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + 0*vec_deltas*d0p(iedge1,:)'; %M_{i_{m+1},i} d10_b = vec_deltas*t0(iedge2,:)'; d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; d01_b = vec_deltas*d0(iedge2,:)'; - d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; + d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + 0*vec_deltas*d0p(iedge2,:)'; if (reg < p-2) % MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... % -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; @@ -829,8 +829,8 @@ % d00+d10_b/(p*(k+1)),... % d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(p*(k+1)), ... - d00+d10_a/(p*(k+1)),... + d00+d10_a/(p*(k+1)), ... + d00+d10_b/(p*(k+1)),... d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; jfun = jfun+1; end @@ -853,6 +853,9 @@ % % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; + M1aux{ipatch} = E1 * MM1; + M2aux{ipatch} = E2 * MM2; + Vaux{ipatch} = VV; end end From c9226e6bb3464ff99a78d85c8f55f24a6bad3dcd Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 16 Apr 2021 18:32:13 +0200 Subject: [PATCH 087/366] Fixed sign of the derivative. d0p seems correct now --- .../inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 4099e21a..b5f01332 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -702,7 +702,7 @@ t0p(iedge,:) = Dvv_F00; d0(iedge,:) = (Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) / ... (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0); - d0p(iedge,:) = ((-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... + d0p(iedge,:) = (-(-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0) * ... (Duv_F00 + (-all_beta0(inter,2) + all_beta1(inter,2))*Dv_F00 + ... (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dvv_F00)) / ... @@ -790,13 +790,13 @@ d10_a = vec_deltas*t0(iedge1,:)'; d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; d01_a = vec_deltas*d0(iedge1,:)'; - d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + 0*vec_deltas*d0p(iedge1,:)'; + d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; %M_{i_{m+1},i} d10_b = vec_deltas*t0(iedge2,:)'; d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; d01_b = vec_deltas*d0(iedge2,:)'; - d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + 0*vec_deltas*d0p(iedge2,:)'; + d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; if (reg < p-2) % MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... % -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; From 1f2c6b405fe032551eb4c1d8ff59c856868f7707 Mon Sep 17 00:00:00 2001 From: cesare Date: Tue, 27 Apr 2021 13:09:05 +0200 Subject: [PATCH 088/366] in sp_multipatch_C1, matrices alpha0, alpha1, beta0, beta1 modified such that columns 1 and 2 contain gluing data for patch i0 (R) and patch i1 (L) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 109 +++++++++--------- 1 file changed, 54 insertions(+), 55 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index b5f01332..ce8dff3e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -403,15 +403,14 @@ if (length(patch)==2) %as it is placed now, this check computes the matrices corresponding only to interior edges [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); - %Saving alphas and betas (first column=L, second column=R) + %Saving alphas and betas (first column=R, second column=L) all_alpha0(iref,:) = alpha0; all_alpha1(iref,:) = alpha1; all_beta0(iref,:) = beta0; all_beta1(iref,:) = beta1; % Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - ii_ab = 3-ii; %this will be used to access the correct alphas and betas + for ii = 1:2 % The two patches (R-L) brk = cell (1,msh.ndim); knots = space.sp_patch{patch(ii)}.knots; @@ -472,8 +471,8 @@ end %alphas and betas % ORIENTATION ISSUE - alpha{ii} = abs (alpha0(ii_ab)*(1-grev_pts{2}') + alpha1(ii_ab)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii} = beta0(ii_ab)*(1-grev_pts{2}') + beta1(ii_ab)*grev_pts{2}'; + alpha{ii} = abs (alpha0(ii)*(1-grev_pts{2}') + alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation + beta{ii} = beta0(ii)*(1-grev_pts{2}') + beta1(ii)*grev_pts{2}'; %looks like alpha must be inverted, but betas mustn't % RHS for the first linear system, (14) in Mario's notes @@ -700,13 +699,13 @@ t0(iedge,:) = Dv_F00; t0p(iedge,:) = Dvv_F00; - d0(iedge,:) = (Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) / ... - (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0); - d0p(iedge,:) = (-(-all_alpha0(inter,2) + all_alpha1(inter,2))*(Du_F00 + (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dv_F00) +... - (all_alpha0(inter,2)*(1-0) + all_alpha1(inter,2)*0) * ... - (Duv_F00 + (-all_beta0(inter,2) + all_beta1(inter,2))*Dv_F00 + ... - (all_beta0(inter,2)*(1-0) + all_beta1(inter,2)*0)*Dvv_F00)) / ... - (all_alpha0(inter,2)*(1-0)+all_alpha1(inter,2)*0)^2; + d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... + (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); + d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... + (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... + (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; mix_der2(2*iedge-1,:) = Duv_F00; %We need to get the jacobian also for the right patch switch vertex_ind2 @@ -885,10 +884,10 @@ A = A_full(:,2:end); b = -A_full(:,1); sols = A\b; - alpha0_n(2) = 1; %R - alpha1_n(2) = sols(1); %R - alpha0_n(1) = sols(2); %L - alpha1_n(1) = sols(3); %L + alpha0_n(1) = 1; %R + alpha1_n(1) = sols(1); %R + alpha0_n(2) = sols(2); %L + alpha1_n(2) = sols(3); %L beta0_n = sols(4); beta1_n = sols(5); beta2_n = sols(6); @@ -896,10 +895,10 @@ A = A_full(:,3:end); % FIX: not a square matrix b = -sum(A_full(:,1:2),2); sols = A\b; - alpha0_n(2) = 1; %R - alpha1_n(2) = 1; %R - alpha0_n(1) = sols(1); %L - alpha1_n(1) = sols(2); %L + alpha0_n(1) = 1; %R + alpha1_n(1) = 1; %R + alpha0_n(2) = sols(1); %L + alpha1_n(2) = sols(2); %L beta0_n = sols(3); beta1_n = sols(4); beta2_n = sols(5); @@ -911,72 +910,72 @@ % +alpha0_n(1)^2+alpha0_n(2)^2; %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); %gamma=-C2/(2*C1); - C1 = alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2 = alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); + C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; + C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); gamma = 3*C2/(2*C1); - alpha0(2) = alpha0_n(2)*gamma; %R - alpha1(2) = alpha1_n(2)*gamma; %R - alpha0(1) = alpha0_n(1)*gamma; %L - alpha1(1) = alpha1_n(1)*gamma; %L + alpha0(1) = alpha0_n(1)*gamma; %R + alpha1(1) = alpha1_n(1)*gamma; %R + alpha0(2) = alpha0_n(2)*gamma; %L + alpha1(2) = alpha1_n(2)*gamma; %L bbeta0 = beta0_n*gamma; bbeta1 = beta1_n*gamma; bbeta2 = beta2_n*gamma; %STEP 5 - Computing the betas %alphas and beta evaluated at 0,1,1/2 + alpha_R_0 = alpha0(1); %alpha_R(0) + alpha_R_1 = alpha1(1); %alpha_R(1) + alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_R(1/2) alpha_L_0 = alpha0(2); %alpha_L(0) alpha_L_1 = alpha1(2); %alpha_L(1) - alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - alpha_R_0 = alpha0(1); %alpha_L(0) - alpha_R_1 = alpha1(1); %alpha_L(1) - alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_L(1/2) + alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) beta_0 = bbeta0; %beta(0) beta_1 = bbeta2; %beta(1) beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M = [alpha_L_0 0 alpha_R_0 0; ... - 0 alpha_L_1 0 alpha_R_1; ... - alpha_L_12/2 alpha_L_12/2 alpha_R_12/2 alpha_R_12/2]; + M = [alpha_R_0 0 alpha_L_0 0; ... + 0 alpha_R_1 0 alpha_L_1; ... + alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; if (rank(M)==3) - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1 = (-alpha_R_12/2 + (alpha_R_0*alpha_L_12)/(2*alpha_L_0)) / ... - (-(alpha_R_1*alpha_L_12)/(2*alpha_L_1) + alpha_R_12/2); - quant2 = (beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0) - (beta_1*alpha_L_12)/(2*alpha_L_1)) / ... - (-(alpha_R_1*alpha_L_12)/(2*alpha_L_1) + alpha_R_12/2); + %Computing beta1_R, beta0_L, beta1_L in terms of beta0_R + quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where + %beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where a = quant2; b = quant1; - c = beta_0/alpha_L_0; d = -alpha_R_0/alpha_L_0; - e = (beta_1-alpha_R_1*quant2)/alpha_L_1; f = -alpha_R_1*quant1/alpha_L_1; + c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; + e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R + %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; - beta0(2) = -C2/(2*C1); %L - beta1(2) = a + b*beta0(2); %L - beta0(1) = c + d*beta0(2); %R - beta1(1) = e + f*beta0(2); %R + beta0(1) = -C2/(2*C1); %R + beta1(1) = a + b*beta0(1); %R + beta0(2) = c + d*beta0(1); %L + beta1(2) = e + f*beta0(1); %L else - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: + %Computing beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a = beta_0/alpha_L_0; b = -alpha_R_0/alpha_L_0; - c = beta_1/alpha_L_1; d = -alpha_R_1/alpha_L_1; + a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; + c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R + %We determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L %The resuting system is M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; M2b = [-b*c-2*a*b; -a*d-2*c*d]; sol = M2\M2b; - beta0(2)= sol(1); %L - beta1(2)= sol(2); %L - beta0(1)= a + b*beta0(2); %R - beta1(1)= c + d*beta1(2); %R + beta0(1)= sol(1); %R + beta1(1)= sol(2); %R + beta0(2)= a + b*beta0(1); %L + beta1(2)= c + d*beta1(1); %L end - + end %TO DO: From 93ebb46f298f5572fd1771f529996d99590952ca Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 5 May 2021 15:06:55 +0200 Subject: [PATCH 089/366] Removed boundary part --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index ce8dff3e..eb6d3444 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -235,38 +235,6 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); function spaux = patches_constructor (spaces, MSH) for ipatch = 1:MSH.npatch From e3d35bff47814cf13afc4b404dd9da3365d68263 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 5 May 2021 15:11:54 +0200 Subject: [PATCH 090/366] Removed unused lines --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index eb6d3444..31b751fb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -765,19 +765,11 @@ d01_b = vec_deltas*d0(iedge2,:)'; d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; if (reg < p-2) -% MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... -% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; -% MM{2,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... -% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; else -% MM{1,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... -% -d01_a/(p*(k+1)), -d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; -% MM{2,kver}{ipatch}(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... -% -d01_b/(p*(k+1)), -d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; MM1(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(p*(k+1)), ... d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... @@ -791,10 +783,6 @@ end %V_{i_m,i} d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; -% V{kver}{ipatch}(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_a/(p*(k+1)), ... -% d00+d10_b/(p*(k+1)),... -% d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(p*(k+1)), ... d00+d10_b/(p*(k+1)),... @@ -820,9 +808,9 @@ % % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; - M1aux{ipatch} = E1 * MM1; - M2aux{ipatch} = E2 * MM2; - Vaux{ipatch} = VV; +% M1aux{ipatch} = E1 * MM1; +% M2aux{ipatch} = E2 * MM2; +% Vaux{ipatch} = VV; end end From 3a39d861a7aec70be66b10091f37673f1b0416f7 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 May 2021 19:04:29 +0200 Subject: [PATCH 091/366] Adding new file for reorientation. --- .../sp_multipatch_C1_reorientation.m | 978 ++++++++++++++++++ 1 file changed, 978 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m new file mode 100644 index 00000000..ca960469 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m @@ -0,0 +1,978 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% BETA VERSION. For now, it will only work with two patches +% +% sp = sp_multipatch_C1 (spaces, msh, interfaces) +%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% +% INPUTS: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% interfaces: information of connectivity between patches (see mp_geo_load) +% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) +%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% interior_dofs_per_patch +% ndof_interior +% ndof_interface +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) +% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + + if (msh.ndim ~= 2 || msh.rdim ~= 2) + error ('Only implemented for planar surfaces') + end + + + for iptc = 1:numel(geometry) +% if (any (geometry(iptc).nurbs.order > 2)) +% error ('For now, only bilinear patches are implemented') +% end + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Assuming that the starting space has degree p and regularity r, +% r <= p-2, we compute the knot vectors of the auxiliary spaces: +% knots0: degree p, regularity r+1. +% knots1: degree p-1, regularity r. + + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom +% We need to give a global numbering to the C^1 basis functions +% We start numbering those away from the interface (V^1) patch by patch +% And then generate the numbering for the functions close to the interface (V^2) + +% Compute the local indices of the functions in V^1 +% and sum them up to get the whole space V^1 + +% if (numel (interfaces) > 1 || msh.npatch > 2) +% error ('For now, the implementation only works for two patches') +% end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE CHANGED STARTING FROM HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% We could store the info of interfaces per patch, as in mp_interface + + sp.ndof_interior = 0; + [interfaces_all, ~] = vertices_struct(boundaries, interfaces); + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces_all) + patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; + sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + +% EXPECTED OUTPUT FROM compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of +% size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; +% + +% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + compute_coefficients (sp, msh, geometry, interfaces, boundaries); +%keyboard + + sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions + sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Computation of the coefficients for basis change +% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof +% The coefficients for basis change have been stored in CC_* + + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + +% Boundary edges are missing + for intrfc = 1:numel(interfaces) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + iptc1 = interfaces(intrfc).patch1; + iptc2 = interfaces(intrfc).patch2; + Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; + Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; + end + +% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point +% The information of which patches share the vertex can be computed with the help of mp_interface + for ivrt = 1%:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) + Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + end + end + +% sp.patches_on_vertex = patches_on_vertex; TO BE DONE + sp.interfaces = interfaces; + sp.Cpatch = Cpatch; + sp.geometry = geometry; % I store this for simplicity + %keyboard + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% I HAVE FINISHED MY CHANGES HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); + +end + + +% There are some issues related to the orientation. +% I am taking the absolute value of alpha +% And for val_grad, I have to change the sign for coeff2, but not for coeff1 +% But everything seems to work!!! + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) + +[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); + +pp = space.sp_patch{1}.degree(1); +kk = numel(msh.msh_patch{1}.breaks{1})-2; +nn = space.sp_patch{1}.sp_univ(1).ndof; +breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); +mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); +reg = pp-max(mult(2:end-1)); + +% ndof_per_interface = (2*nn-2*kk-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere +ndof_per_vertex = 6*ones(1,numel(vertices)); + +all_alpha0 = zeros(numel(interfaces_all),2); +all_alpha1 = zeros(numel(interfaces_all),2); +all_beta0 = zeros(numel(interfaces_all),2); +all_beta1 = zeros(numel(interfaces_all),2); +all_t0 = zeros(numel(interfaces_all),2); + +%Initialize the cell array of CC_vertices matrices +for ii = 1:space.npatch + for jj = 1:numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); + end +end + +%computing for each patch all the derivatives we possibly need to compute t,d, and sigma +% FIX: this would be done inside the vertex loop, after reorientation +brk = cell (1,msh.ndim); +for iptc = 1:space.npatch + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1} = [0 1]'; + pts{2} = [0 1]';%pts{2}=[0 1/2 1]' + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} +end + +%Construction of CC_edges +for iref = 1%:numel(interfaces_all) +% Create an auxiliary geometry with reorientation +% FIX: Probably not valid for boundary edges + [geo_local, interface_local, operations] = reorientation_edge (interfaces_all(iref), geometry); + +% FIX: only necessary for boundary edges. Reorientation makes the others as in the paper + clear patch + if (~isempty(interface_local.patch1)) + original_patch(1) = interfaces_all(iref).patch1; + patch(1) = interface_local.patch1; %LEFT + side(1) = interface_local.side1; %LEFT + end + if (~isempty(interface_local.patch2)) + original_patch(2) = interfaces_all(iref).patch2; + patch(2) = interface_local.patch2; %RIGHT + side(2) = interface_local.side2; %RIGHT + end + nnz_el = find(patch>0); + + %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives + %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions + for ii = nnz_el % The two patches (L-R) + % Points for G^1 conditions system + brk = cell (1,msh.ndim); + knt = geo_local(ii).nurbs.knots; + order = geo_local(ii).nurbs.order; + for idim = 1:msh.ndim + grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; + brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); + msh_side_interior = msh_precompute (msh_side_interior); + geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) + end + + if (length(patch)==2) %as it is placed now, this check computes the matrices corresponding only to interior edges + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); + + %Saving alphas and betas (first column=R, second column=L) + % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION + all_alpha0(iref,:) = alpha0; + all_alpha1(iref,:) = alpha1; + all_beta0(iref,:) = beta0; + all_beta1(iref,:) = beta1; + +% Compute the Greville points, and the auxiliary mesh and space objects + for ii = 1:2 % The two patches (R-L) + brk = cell (1,msh.ndim); + knots = knot_vector_reorientation (space.sp_patch{original_patch(ii)}.knots, operations(ii,:)); + knots0 = knot_vector_reorientation (space.knots0_patches{original_patch(ii)}, operations(ii,:)); + knots1 = knot_vector_reorientation (space.knots1_patches{original_patch(ii)}, operations(ii,:)); + degrees = degree_reorientation (space.sp_patch{original_patch(ii)}.degree, operations(ii,3)); + +% The knot vectors for the N0 and N1 basis functions, as in Mario's notation +% Only univariate knot vectors are computed +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); + knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; + knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (knots{ind2}); + if (mod (side(ii), 2) == 1) + tau1 = knt(2) - knt(1); +% else +% tau1 = knt(end) - knt(end-1); + end + +% For now we assume that the orientation is as in the paper, and we do not need any reordering +% msh_side contains only the univariate parametrization of the boundary (dependence on u) +% msh_side_int contains information for the bivariate parametrization (dependence on u and v) +% sp_aux contains the value and derivatives of the basis functions, at the Greville points + msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); +% sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_interior); + sp_aux = sp_bspline (knots, degrees, msh_side_interior); + +% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% The univariate space for the basis functions N^{p,r} on the interface +% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) + ind = [2 2 1 1]; + knotsn = knots{ind(side(ii))}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems, (14)-(16) in Mario's notes + A = sparse (msh_side(ii).nel, msh_side(ii).nel); + for jj = 1:msh_side(ii).nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha{ii} = abs (alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'); %we have to take the absolute value to make it work for any orientation + beta{ii} = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; + %looks like alpha must be inverted, but betas mustn't + +% RHS for the first linear system, (14) in Mario's notes + rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); + for jj = 1:msh_side(ii).nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0{ii} = A \ rhss; + coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the second linear system, (15) in Mario's notes + rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); + if (side(ii) == 1) %paper case, ii = 1 + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); +% elseif (side(ii) == 2) +% val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); + elseif (side(ii) == 3) % The other paper case, ii = 2 + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); +% elseif (side(ii) == 4) +% val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side(ii).nel %paper case - check beta + val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1{ii} = A \ rhsb; + coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse + +% RHS for the third linear system, (16) in Mario's notes +% We need this change of sign to make it work for general orientation. +% I don't understand why we don't need it in the previous system. + val_grad = val_grad * (-1)^(side(ii)+1); + + rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side(ii).nel + val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2{ii} = A \ rhsc; + coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis +% The numbering (ndof_edge) only works for the two patch case, for now + ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; + ndof_dir_original = space.sp_patch{original_patch(ii)}.ndof_dir; + if (side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); +% elseif (side(ii) == 2) +% ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); +% ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); + elseif (side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); +% elseif (side(ii) == 4) +% ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); +% ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); + end + + ndof_edge = sp0_struct.ndof + sp1_struct.ndof; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); + + CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; + CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof_edge) = coeff2{ii}; %...and derivative basis functions (associated to iref-th interface) + + %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded + CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 + CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof_edge-2]); + +% My (longer) version to better understand the indexing + trace_functions = 4:sp0_struct.ndof-3; + deriv_functions = 3:sp1_struct.ndof-2; + ndof_trace = sp0_struct.ndof - 6; + ndof_deriv = sp1_struct.ndof - 4; + discarded_trace_functions = [1:3, sp0_struct.ndof-2:sp0_struct.ndof]; + discarded_deriv_functions = [1 2 sp1_struct.ndof-1 sp1_struct.ndof]; + + indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); + ind0_ornt = indices_reoriented(ind0); + ind1_ornt = indices_reoriented(ind1); + +% Active functions + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_trace + ndof_deriv); + CC_edges{ii,iref}(ind0_ornt,1:ndof_trace) = coeff0{ii}(:,trace_functions); %coefficients of trace basis functions... + CC_edges{ii,iref}(ind1_ornt,1:ndof_trace) = coeff1{ii}(:,trace_functions); + CC_edges{ii,iref}(ind1_ornt,ndof_trace+(1:ndof_deriv)) = coeff2{ii}(:,deriv_functions); %...and derivative basis functions (associated to iref-th interface) +% Inactive functions, used to compute vertex functions + CC_edges_discarded{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), 10); + CC_edges_discarded{ii,iref}(ind0,1:6) = coeff0{ii}(:,discarded_trace_functions); + CC_edges_discarded{ii,iref}(ind1,1:6) = coeff1{ii}(:,discarded_trace_functions); + CC_edges_discarded{ii,iref}(ind1,7:10) = coeff2{ii}(:,discarded_deriv_functions); + + ndof_per_interface(iref) = ndof_trace + ndof_deriv; + end + else + n0 = nn-kk; + ndof_edge = n0+nn-kk-1; + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); + CC_edges_discarded{ii,iref} = CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 + CC_edges{ii,iref} = CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof_edge-2]); + end +end + + + +%We assume that the local numbering of interfaces and patches is such that +%vertices(kver).interface(im) is the interface between +%vertices(kver).patches(im) and vertices(kver).patches(im+1) +MM = cell(2,numel(vertices)); +V = cell(numel(vertices),1); +E = cell(numel(vertices),1); +%Previously: +%MM=cell(2,nu,numel(vertices)); +%V=cell(nu,numel(vertices)); +%E=cell(nu+1,numel(vertices)); +sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) + +for kver = 1:numel(vertices) + + %Everything must be updated by using interfaces_all instead of interfaces TO DO + ver_patches = []; %vector with indices of patches containing the vertex + ver_patches_nabla = {}; %cell array containing jacobians + ver_ind = []; %vector containing local index of vertex in the patch + ninterfaces_ver = numel(vertices(kver).interfaces); + + boundary_vertex = 0; + for im = 1:ninterfaces_ver + inter = vertices(kver).interfaces(im); + if (isempty(interfaces_all(inter).side1) || isempty(interfaces_all(inter).side2)) + boundary_vertex = 1; + break + end + end + if (~boundary_vertex) + +% for h=1:numel(vertices(kver).interfaces) +% hint=vertices(kver).interfaces(h); +% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; +% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... +% sides(interfaces(hint).side2,vertices(kver).ind)]; +% end +% ver_patches=unique(ver_patches,'stable'); +% ver_ind=unique(ver_ind,'stable'); +% 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) + for iedge = 1:ninterfaces_ver %cycle over all the interfaces containing the vertex + inter = vertices(kver).interfaces(iedge); %global index of the interface + patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface + patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface + vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch + vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch + ver_patches = [ver_patches patch_ind1 patch_ind2]; + ver_ind = [ver_ind vertex_ind1 vertex_ind2]; + %compute t(0) and t'(0), d(0) and d'(0) + switch vertex_ind1 + case 1 %vertex (0,0) + Du_F00 = derivatives1{patch_ind1}(:,1,1); + Dv_F00 = derivatives1{patch_ind1}(:,2,1); + Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); + Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); +% case 2 %vertex (0,1) +% Du_F00 = derivatives1{patch_ind1}(:,1,2); +% Dv_F00 = -derivatives1{patch_ind1}(:,2,2); +% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,2); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,2); +% case 3 %vertex (1,0) +% Du_F00 = -derivatives1{patch_ind1}(:,1,3); +% Dv_F00 = derivatives1{patch_ind1}(:,2,3); +% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,3); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,3); +% case 4 %vertex (1,1) +% Du_F00 = -derivatives1{patch_ind1}(:,1,4); +% Dv_F00 = -derivatives1{patch_ind1}(:,2,4); +% Duv_F00 = derivatives2{patch_ind1}(:,1,2,4); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); + end + %Store the jacobian of F for the left patch + ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; + + t0(iedge,:) = Dv_F00; + t0p(iedge,:) = Dvv_F00; + d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... + (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); + d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... + (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... + (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... + (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; + mix_der2(2*iedge-1,:) = Duv_F00; + %We need to get the jacobian also for the right patch + switch vertex_ind2 + case 1 %vertex (0,0) + Du_F00 = derivatives1{patch_ind2}(:,1,1); + Dv_F00 = derivatives1{patch_ind2}(:,2,1); + Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); +% case 2 %vertex (0,1) +% Du_F00 = derivatives1{patch_ind2}(:,1,2); +% Dv_F00 = -derivatives1{patch_ind2}(:,2,2); +% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,2); +% case 3 %vertex (1,0) +% Du_F00 = -derivatives1{patch_ind2}(:,1,3); +% Dv_F00 = derivatives1{patch_ind2}(:,2,3); +% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,3); +% case 4 %vertex (1,1) +% Du_F00 = -derivatives1{patch_ind2}(:,1,4); +% Dv_F00 = -derivatives1{patch_ind2}(:,2,4); +% Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); + end + ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; + mix_der2(2*iedge,:) = Duv_F00; + + %Pick the correct part of CC_edges_discarded %TO BE FIXED + if (vertices(kver).ind(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface + E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex + E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); +% else %the vertex is the right/top endpoint of im-th interface +% E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); +% E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); + end + end + [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); + mix_der2_n = mix_der2(ind_patch_sigma,:); + %ver_ind=unique(ver_ind,'rows','stable'); + + %ind_patch_sigma contains the positions of the elements of ver_patches + %originally (each of them is present twice, the first one is considered) + + %if the number of patches coincides with the number of interfaces, + %we add one fictional interface coinciding with the first one + %(just for coding-numbering reasons) +% if numel(ver_patches)==ninterfaces_ver +% t0(ninterfaces_ver+1,:)=t0(1,:); +% t0p(ninterfaces_ver+1,:)=t0p(1,:); +% d0(ninterfaces_ver+1,:)=d0(1,:); +% d0p(ninterfaces_ver+1,:)=d0p(1,:); +% E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; +% E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; +% end + + %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices + sigma = 0; + for im = 1:ninterfaces_ver % FIX: is this the number of interfaces? + sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); + end + sigma = 1/(sigma/(pp*(kk+1)*ninterfaces_ver)); + %computing matrices MM and V + for ipatch = 1:ninterfaces_ver %FIX: cycle over the patches containing the vertex + + %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) + n1 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) +% V{kver}{im} = zeros(n1*n2,6); + MM1 = zeros(5,6); MM2 = zeros(5,6); + VV = zeros(n1*n2,6); + im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) + if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order + im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 + end + iedge1 = im_edges(1); iedge2 = im_edges(2); + + corner_4dofs = [1 2 n2+1 n2+2]; + jfun = 1; + for j1 = 0:2 + for j2 = 0:2-j1 %the following computations work in the standard case + mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; + vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; + d00 = (j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a = vec_deltas*t0(iedge1,:)'; + d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; + d01_a = vec_deltas*d0(iedge1,:)'; + d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; + + %M_{i_{m+1},i} + d10_b = vec_deltas*t0(iedge2,:)'; + d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; + d01_b = vec_deltas*d0(iedge2,:)'; + d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; + if (reg < pp-2) + MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(pp*(kk+1)), d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2),... + d01_a/(pp*(kk+1)), d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)]'; + MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(pp*(kk+1)), d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2),... + d01_b/(pp*(kk+1)), d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)]'; + else + MM1(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2),... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)]'; + MM2(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(pp*(kk+1)), ... + d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2),... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)]'; + end + %V_{i_m,i} + d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; + VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+d10_b/(pp*(kk+1)),... + d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; + jfun = jfun+1; + end + end + % Check which patch of the edge function we are considering + if (interfaces_all(vertices(kver).interfaces(iedge1)).patch2 == ver_patches(ipatch))%the considered patch is the second patch edge iedge1 + E1 = E{kver}{iedge1,2}; + else + E1 = E{kver}{iedge1,1}; + end + if (interfaces_all(vertices(kver).interfaces(iedge2)).patch2 == ver_patches(ipatch))%the considered patch is the second patch of edge iedge2 + E2 = E{kver}{iedge2,2}; + else + E2 = E{kver}{iedge2,1}; + end + XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); +% % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); +% CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; + CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; +% % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; + %csi2=[1 9 17 25 33 41 49 57]; + %csi1=1:8; +% M1aux{ipatch} = E1 * MM1; +% M2aux{ipatch} = E2 * MM2; +% Vaux{ipatch} = VV; + end + end + +end + +end + +function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) + + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + if (side(2)==1 || side(2)==2) + v = grev_pts{2}(:); + else + v = grev_pts{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector + DuFR_y = reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector + DvFL_x = reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector + DvFL_y = reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector + DvFR_x = reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector + DvFR_y = reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(1) = 1; %R + alpha1_n(1) = sols(1); %R + alpha0_n(2) = sols(2); %L + alpha1_n(2) = sols(3); %L + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); % FIX: not a square matrix + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(1) = 1; %R + alpha1_n(1) = 1; %R + alpha0_n(2) = sols(1); %L + alpha1_n(2) = sols(2); %L + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end + + %keyboard + %STEP 4 - Normalizing the alphas + %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... + % +alpha0_n(1)^2+alpha0_n(2)^2; + %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); + %gamma=-C2/(2*C1); + C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; + C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); + gamma = 3*C2/(2*C1); + alpha0(1) = alpha0_n(1)*gamma; %R + alpha1(1) = alpha1_n(1)*gamma; %R + alpha0(2) = alpha0_n(2)*gamma; %L + alpha1(2) = alpha1_n(2)*gamma; %L + bbeta0 = beta0_n*gamma; + bbeta1 = beta1_n*gamma; + bbeta2 = beta2_n*gamma; + + %STEP 5 - Computing the betas + %alphas and beta evaluated at 0,1,1/2 + alpha_R_0 = alpha0(1); %alpha_R(0) + alpha_R_1 = alpha1(1); %alpha_R(1) + alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_R(1/2) + alpha_L_0 = alpha0(2); %alpha_L(0) + alpha_L_1 = alpha1(2); %alpha_L(1) + alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) + beta_0 = bbeta0; %beta(0) + beta_1 = bbeta2; %beta(1) + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + + %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + M = [alpha_R_0 0 alpha_L_0 0; ... + 0 alpha_R_1 0 alpha_L_1; ... + alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; + + if (rank(M)==3) + + %Computing beta1_R, beta0_L, beta1_L in terms of beta0_R + quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + + %beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where + a = quant2; b = quant1; + c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; + e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; + + %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L + C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; + C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; + beta0(1) = -C2/(2*C1); %R + beta1(1) = a + b*beta0(1); %R + beta0(2) = c + d*beta0(1); %L + beta1(2) = e + f*beta0(1); %L + + else + %Computing beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: + %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; + c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; + + %We determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L + %The resuting system is + M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b = [-b*c-2*a*b; -a*d-2*c*d]; + sol = M2\M2b; + beta0(1)= sol(1); %R + beta1(1)= sol(2); %R + beta0(2)= a + b*beta0(1); %L + beta1(2)= c + d*beta1(1); %L + end + +end + +%TO DO: +%- case of boundary edges + +%TO BE TESTED +%- plots of the functions +%- continuity +function [geo_reoriented, local_interface, operations] = reorientation_edge (interface, geometry) + patches = [interface.patch1 interface.patch2]; + nrb_patches = [geometry(patches).nurbs]; + sides = [interface.side1 interface.side2]; +% Change orientation of first patch + [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(1) == 2) + if (jacdet < 0) + operations(1,:) = [1 0 0]; + else + operations(1,:) = [1 1 0]; + end + elseif (sides(1) == 3) + if (jacdet < 0) + operations(1,:) = [0 0 1]; + else + operations(1,:) = [1 0 1]; + end + elseif (sides(1) == 4) + if (jacdet < 0) + operations(1,:) = [1 1 1]; + else + operations(1,:) = [0 1 1]; + end + elseif (sides(1) == 1) + if (jacdet < 0) + operations(1,:) = [0 1 0]; + else + operations(1,:) = [0 0 0]; + end + end + +% Change orientation of second patch + [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(2) == 1) + if (jacdet < 0) + operations(2,:) = [0 0 1]; + else + operations(2,:) = [0 1 1]; + end + elseif (sides(2) == 2) + if (jacdet < 0) + operations(2,:) = [1 1 1]; + else + operations(2,:) = [1 0 1]; + end + elseif (sides(2) == 3) + if (jacdet < 0) + operations(2,:) = [1 0 0]; + else + operations(2,:) = [0 0 0]; + end + elseif (sides(2) == 4) + if (jacdet < 0) + operations(2,:) = [0 1 0]; + else + operations(2,:) = [1 1 0]; + end + end + + for ii = 1:2 + if (operations(ii,1)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); + end + if (operations(ii,2)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 2); + end + if (operations(ii,3)) + nrb_patches(ii) = nrbtransp (nrb_patches(ii)); + end + end + + [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); + + if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) + error('The reorientation is wrong') + end +end + +function knots = knot_vector_reorientation (knots, operations) + if (operations(1)) + knots{1} = sort (1 - knots{1}); + end + if (operations(2)) + knots{2} = sort (1-knots{2}); + end + if (operations(3)) + knots([2 1]) = knots([1 2]); + end +end + +function degree = degree_reorientation (degree, transposition) + if (transposition) + degree = degree([2 1]); + end +end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(3)) + indices = indices.'; + end + if (operations(2)) + indices = flipud (indices); + end + if (operations(1)) + indices = fliplr (indices); + end + +end \ No newline at end of file From 6b402af12eb24179f5923d0c88cbf4a4c5857e3e Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 7 May 2021 12:08:55 +0200 Subject: [PATCH 092/366] Working for any orientation, with non-uniform knot vector --- .../@sp_multipatch_C1/sp_multipatch_C1_reorientation.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m index ca960469..6d482e23 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m @@ -965,14 +965,14 @@ function indices = indices_reorientation (ndof_dir, operations) ndof = prod (ndof_dir); indices = reshape (1:ndof, ndof_dir); - if (operations(3)) - indices = indices.'; - end - if (operations(2)) + if (operations(1)) indices = flipud (indices); end - if (operations(1)) + if (operations(2)) indices = fliplr (indices); end + if (operations(3)) + indices = indices.'; + end end \ No newline at end of file From 14b28851619a1cd9db6c6155756d2cb3b3c2b65f Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 7 May 2021 16:01:06 +0200 Subject: [PATCH 093/366] A lot of cleaning, and fixed minor things. --- .../sp_multipatch_C1_reorientation.m | 439 ++++++++---------- 1 file changed, 189 insertions(+), 250 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m index 6d482e23..1136441d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m @@ -153,7 +153,7 @@ % We could store the info of interfaces per patch, as in mp_interface sp.ndof_interior = 0; - [interfaces_all, ~] = vertices_struct(boundaries, interfaces); + [interfaces_all, vertices] = vertices_struct(boundaries, interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) @@ -185,7 +185,7 @@ % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, boundaries); + compute_coefficients (sp, msh, geometry, interfaces_all, vertices); %keyboard sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions @@ -205,13 +205,12 @@ speye (numel (sp.interior_dofs_per_patch{iptc})); end -% Boundary edges are missing - for intrfc = 1:numel(interfaces) + for intrfc = 1:numel(interfaces_all) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - iptc1 = interfaces(intrfc).patch1; - iptc2 = interfaces(intrfc).patch2; - Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; - Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; + patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; + for iptc = 1:numel(patches) + Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; + end end % Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point @@ -246,37 +245,34 @@ end -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) +%Initialize output variables with correct size +ndof_per_interface = zeros (1, numel(interfaces_all)); +ndof_per_vertex = 6*ones(1,numel(vertices)); -[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); +CC_edges = cell (2, numel (interfaces_all)); +CC_edges_discarded = cell (2, numel (interfaces_all)); +CC_vertices = cell (space.npatch, numel(vertices)); +for ii = 1:space.npatch + for jj = 1:numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), 6); + end +end pp = space.sp_patch{1}.degree(1); kk = numel(msh.msh_patch{1}.breaks{1})-2; -nn = space.sp_patch{1}.sp_univ(1).ndof; +% nn = space.sp_patch{1}.sp_univ(1).ndof; breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg = pp-max(mult(2:end-1)); +reg = pp - max(mult(2:end-1)); -% ndof_per_interface = (2*nn-2*kk-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere -ndof_per_vertex = 6*ones(1,numel(vertices)); all_alpha0 = zeros(numel(interfaces_all),2); all_alpha1 = zeros(numel(interfaces_all),2); all_beta0 = zeros(numel(interfaces_all),2); all_beta1 = zeros(numel(interfaces_all),2); -all_t0 = zeros(numel(interfaces_all),2); -%Initialize the cell array of CC_vertices matrices -for ii = 1:space.npatch - for jj = 1:numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end %computing for each patch all the derivatives we possibly need to compute t,d, and sigma % FIX: this would be done inside the vertex loop, after reorientation @@ -296,30 +292,19 @@ end %Construction of CC_edges -for iref = 1%:numel(interfaces_all) -% Create an auxiliary geometry with reorientation -% FIX: Probably not valid for boundary edges - [geo_local, interface_local, operations] = reorientation_edge (interfaces_all(iref), geometry); +for iref = 1:numel(interfaces_all) +% Auxiliary geometry with orientation as in the paper + [geo_local, operations] = reorientation_edge (interfaces_all(iref), geometry); -% FIX: only necessary for boundary edges. Reorientation makes the others as in the paper - clear patch - if (~isempty(interface_local.patch1)) - original_patch(1) = interfaces_all(iref).patch1; - patch(1) = interface_local.patch1; %LEFT - side(1) = interface_local.side1; %LEFT - end - if (~isempty(interface_local.patch2)) - original_patch(2) = interfaces_all(iref).patch2; - patch(2) = interface_local.patch2; %RIGHT - side(2) = interface_local.side2; %RIGHT - end - nnz_el = find(patch>0); - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - for ii = nnz_el % The two patches (L-R) - % Points for G^1 conditions system - brk = cell (1,msh.ndim); + original_patch = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; + patch = [1 2]; side = [1 3]; + npatches_on_edge = numel (original_patch); + +% Compute gluing data + geo_map_jac = cell (npatches_on_edge, 1); + for ii = 1:npatches_on_edge + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); knt = geo_local(ii).nurbs.knots; order = geo_local(ii).nurbs.order; for idim = 1:msh.ndim @@ -332,184 +317,132 @@ geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) end - if (length(patch)==2) %as it is placed now, this check computes the matrices corresponding only to interior edges - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); - + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); + clear geo_map_jac msh_grev msh_side_interior grev_pts + %Saving alphas and betas (first column=R, second column=L) % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION - all_alpha0(iref,:) = alpha0; - all_alpha1(iref,:) = alpha1; - all_beta0(iref,:) = beta0; - all_beta1(iref,:) = beta1; + all_alpha0(iref,:) = alpha0; + all_alpha1(iref,:) = alpha1; + all_beta0(iref,:) = beta0; + all_beta1(iref,:) = beta1; -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (R-L) - brk = cell (1,msh.ndim); - knots = knot_vector_reorientation (space.sp_patch{original_patch(ii)}.knots, operations(ii,:)); - knots0 = knot_vector_reorientation (space.knots0_patches{original_patch(ii)}, operations(ii,:)); - knots1 = knot_vector_reorientation (space.knots1_patches{original_patch(ii)}, operations(ii,:)); - degrees = degree_reorientation (space.sp_patch{original_patch(ii)}.degree, operations(ii,3)); - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed +% Compute the Greville points, and the auxiliary mesh and space objects for +% functions with reduced degree or increased regularity + for ii = 1:npatches_on_edge %% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); - knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; - knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + ind2 = ceil (side(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); + degrees = degree_reorientation (space.sp_patch{original_patch(ii)}.degree, operations(ii,3)); + degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); + + knots = knot_vector_reorientation (space.sp_patch{original_patch(ii)}.knots, operations(ii,:)); + knots0 = knot_vector_reorientation (space.knots0_patches{original_patch(ii)}, operations(ii,:)); + knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; + knots1 = knot_vector_reorientation (space.knots1_patches{original_patch(ii)}, operations(ii,:)); + knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); % Degree and first length in the direction normal to the interface - degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); -% else -% tau1 = knt(end) - knt(end-1); - end + degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (knots{ind2}); + tau1 = knt(2) - knt(1); -% For now we assume that the orientation is as in the paper, and we do not need any reordering -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) % sp_aux contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); -% sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_interior); - sp_aux = sp_bspline (knots, degrees, msh_side_interior); - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + msh_side = msh_eval_boundary_side (msh_grev, side(ii)); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); + sp_aux = sp_bspline (knots, degrees, msh_side_interior); + +% Univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) and N^{p,r} on the interface + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); + + knotsn = knots{ind1}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); % Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end + A = sparse (msh_side.nel, msh_side.nel); + for jj = 1:msh_side.nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end %alphas and betas - alpha{ii} = abs (alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'); %we have to take the absolute value to make it work for any orientation - beta{ii} = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; - %looks like alpha must be inverted, but betas mustn't - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case, ii = 1 - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); -% elseif (side(ii) == 2) -% val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) % The other paper case, ii = 2 - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); -% elseif (side(ii) == 4) -% val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof_edge) only works for the two patch case, for now - ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; - ndof_dir_original = space.sp_patch{original_patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); -% elseif (side(ii) == 2) -% ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); -% ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); -% elseif (side(ii) == 4) -% ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); -% ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end + alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; + beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; - ndof_edge = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); - - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof_edge) = coeff2{ii}; %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof_edge-2]); +% RHS and solution of the linear systems, (14)-(16) in Mario's notes + rhss = sparse (msh_side.nel, sp0_struct.ndof); + for jj = 1:msh_side.nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0 = A \ rhss; + coeff0(abs(coeff0) < 1e-12) = 0; % Make more sparse + + rhsb = sparse (msh_side.nel, sp0_struct.ndof); + if (ii == 1) % paper case, (side(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (ii == 2) %The other paper case, (side(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side.nel + val_aux = -val * beta(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1 = A \ rhsb; + coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse -% My (longer) version to better understand the indexing - trace_functions = 4:sp0_struct.ndof-3; - deriv_functions = 3:sp1_struct.ndof-2; - ndof_trace = sp0_struct.ndof - 6; - ndof_deriv = sp1_struct.ndof - 4; - discarded_trace_functions = [1:3, sp0_struct.ndof-2:sp0_struct.ndof]; - discarded_deriv_functions = [1 2 sp1_struct.ndof-1 sp1_struct.ndof]; - - indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); - ind0_ornt = indices_reoriented(ind0); - ind1_ornt = indices_reoriented(ind1); - -% Active functions - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_trace + ndof_deriv); - CC_edges{ii,iref}(ind0_ornt,1:ndof_trace) = coeff0{ii}(:,trace_functions); %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1_ornt,1:ndof_trace) = coeff1{ii}(:,trace_functions); - CC_edges{ii,iref}(ind1_ornt,ndof_trace+(1:ndof_deriv)) = coeff2{ii}(:,deriv_functions); %...and derivative basis functions (associated to iref-th interface) -% Inactive functions, used to compute vertex functions - CC_edges_discarded{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), 10); - CC_edges_discarded{ii,iref}(ind0,1:6) = coeff0{ii}(:,discarded_trace_functions); - CC_edges_discarded{ii,iref}(ind1,1:6) = coeff1{ii}(:,discarded_trace_functions); - CC_edges_discarded{ii,iref}(ind1,7:10) = coeff2{ii}(:,discarded_deriv_functions); + rhsc = sparse (msh_side.nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side.nel + val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2 = A \ rhsc; + coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse - ndof_per_interface(iref) = ndof_trace + ndof_deriv; +% Pass the coefficients to the tensor product basis + ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; + ndof_dir_original = space.sp_patch{original_patch(ii)}.ndof_dir; + if (ii == 1) %(side(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (ii == 2) %(side(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); end - else - n0 = nn-kk; - ndof_edge = n0+nn-kk-1; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); - CC_edges_discarded{ii,iref} = CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 - CC_edges{ii,iref} = CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof_edge-2]); + indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); + ind0_ornt = indices_reoriented(ind0); + ind1_ornt = indices_reoriented(ind1); + +% Store the coefficients in CC_edges, and compute the number of functions + ndof_edge = sp0_struct.ndof + sp1_struct.ndof; + trace_functions = 4:sp0_struct.ndof-3; + deriv_functions = sp0_struct.ndof + (3:sp1_struct.ndof-2); + active_functions = union (trace_functions, deriv_functions); + discarded_functions = setdiff (1:ndof_edge, active_functions); + + CC = sparse (space.ndof_per_patch(original_patch(ii)), ndof_edge); + CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; + CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; + CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; + + ndof_per_interface(iref) = numel(active_functions); + CC_edges{ii,iref} = sparse (space.ndof_per_patch(original_patch(ii)), ndof_per_interface(iref)); + CC_edges{ii,iref} = CC(:,active_functions); + CC_edges_discarded{ii,iref} = CC(:,discarded_functions); end end @@ -743,6 +676,15 @@ function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) + if (numel (geo_map_jac) == 1) +% FIX: alpha1 and beta1 do not exist. They should be empty, but give an error in all_alpha + alpha0 = [1 1]; + alpha1 = [0 0]; + beta0 = [0 0]; + beta1 = [0 0]; + return + end + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); @@ -857,13 +799,7 @@ end -%TO DO: -%- case of boundary edges - -%TO BE TESTED -%- plots of the functions -%- continuity -function [geo_reoriented, local_interface, operations] = reorientation_edge (interface, geometry) +function [geo_reoriented, operations] = reorientation_edge (interface, geometry) patches = [interface.patch1 interface.patch2]; nrb_patches = [geometry(patches).nurbs]; sides = [interface.side1 interface.side2]; @@ -896,36 +832,38 @@ end end -% Change orientation of second patch - [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - if (sides(2) == 1) - if (jacdet < 0) - operations(2,:) = [0 0 1]; - else - operations(2,:) = [0 1 1]; - end - elseif (sides(2) == 2) - if (jacdet < 0) - operations(2,:) = [1 1 1]; - else - operations(2,:) = [1 0 1]; - end - elseif (sides(2) == 3) - if (jacdet < 0) - operations(2,:) = [1 0 0]; - else - operations(2,:) = [0 0 0]; - end - elseif (sides(2) == 4) - if (jacdet < 0) - operations(2,:) = [0 1 0]; - else - operations(2,:) = [1 1 0]; +% Change orientation of second patch, only for inner edges + if (numel(nrb_patches) == 2) + [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(2) == 1) + if (jacdet < 0) + operations(2,:) = [0 0 1]; + else + operations(2,:) = [0 1 1]; + end + elseif (sides(2) == 2) + if (jacdet < 0) + operations(2,:) = [1 1 1]; + else + operations(2,:) = [1 0 1]; + end + elseif (sides(2) == 3) + if (jacdet < 0) + operations(2,:) = [1 0 0]; + else + operations(2,:) = [0 0 0]; + end + elseif (sides(2) == 4) + if (jacdet < 0) + operations(2,:) = [0 1 0]; + else + operations(2,:) = [1 1 0]; + end end end - for ii = 1:2 + for ii = 1:numel(nrb_patches) if (operations(ii,1)) nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); end @@ -938,9 +876,11 @@ end [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); - - if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) - error('The reorientation is wrong') +% FIX: this check can be removed once everything is working + if (numel (nrb_patches) == 2) + if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) + error('The reorientation is wrong') + end end end @@ -973,6 +913,5 @@ end if (operations(3)) indices = indices.'; - end - -end \ No newline at end of file + end +end From 3ca54ff2a05e108464383b0969149a1afd95eb25 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 7 May 2021 17:50:45 +0200 Subject: [PATCH 094/366] Some more cleaning --- .../sp_multipatch_C1_reorientation.m | 119 +++++++----------- 1 file changed, 47 insertions(+), 72 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m index 1136441d..4850fec1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m @@ -153,7 +153,7 @@ % We could store the info of interfaces per patch, as in mp_interface sp.ndof_interior = 0; - [interfaces_all, vertices] = vertices_struct(boundaries, interfaces); + [interfaces_all, vertices] = vertices_struct (boundaries, interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) @@ -273,29 +273,11 @@ all_beta0 = zeros(numel(interfaces_all),2); all_beta1 = zeros(numel(interfaces_all),2); - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -% FIX: this would be done inside the vertex loop, after reorientation -brk = cell (1,msh.ndim); -for iptc = 1:space.npatch - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1} = [0 1]'; - pts{2} = [0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); - msh_der = msh_precompute (msh_pts_der1); - derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} -end - -%Construction of CC_edges +%Computation of CC_edges for iref = 1:numel(interfaces_all) % Auxiliary geometry with orientation as in the paper [geo_local, operations] = reorientation_edge (interfaces_all(iref), geometry); - + original_patch = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; patch = [1 2]; side = [1 3]; npatches_on_edge = numel (original_patch); @@ -316,29 +298,29 @@ msh_side_interior = msh_precompute (msh_side_interior); geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) end - + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); clear geo_map_jac msh_grev msh_side_interior grev_pts - + %Saving alphas and betas (first column=R, second column=L) % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION all_alpha0(iref,:) = alpha0; all_alpha1(iref,:) = alpha1; all_beta0(iref,:) = beta0; all_beta1(iref,:) = beta1; - + % Compute the Greville points, and the auxiliary mesh and space objects for % functions with reduced degree or increased regularity for ii = 1:npatches_on_edge %% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] ind2 = ceil (side(ii)/2); ind1 = setdiff (1:msh.ndim, ind2); - + brk = cell (1,msh.ndim); grev_pts = cell (1, msh.ndim); degrees = degree_reorientation (space.sp_patch{original_patch(ii)}.degree, operations(ii,3)); degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); - + knots = knot_vector_reorientation (space.sp_patch{original_patch(ii)}.knots, operations(ii,:)); knots0 = knot_vector_reorientation (space.knots0_patches{original_patch(ii)}, operations(ii,:)); knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; @@ -403,16 +385,16 @@ rhsb = rhsb + rhss; coeff1 = A \ rhsb; coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse - + rhsc = sparse (msh_side.nel, sp1_struct.ndof); val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) for jj = 1:msh_side.nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; + val_aux = val * alpha(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; end coeff2 = A \ rhsc; coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse - + % Pass the coefficients to the tensor product basis ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; ndof_dir_original = space.sp_patch{original_patch(ii)}.ndof_dir; @@ -438,7 +420,7 @@ CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; - + ndof_per_interface(iref) = numel(active_functions); CC_edges{ii,iref} = sparse (space.ndof_per_patch(original_patch(ii)), ndof_per_interface(iref)); CC_edges{ii,iref} = CC(:,active_functions); @@ -447,6 +429,24 @@ end +% Computation of CC_vertices +% Compute for each patch all the derivatives we possibly need to compute t,d, and sigma +% FIX: this would be done inside the vertex loop, after reorientation +brk = cell (1,msh.ndim); +for iptc = 1:space.npatch + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1} = [0 1]'; + pts{2} = [0 1]';%pts{2}=[0 1/2 1]' + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} +end + %We assume that the local numbering of interfaces and patches is such that %vertices(kver).interface(im) is the interface between @@ -454,14 +454,9 @@ MM = cell(2,numel(vertices)); V = cell(numel(vertices),1); E = cell(numel(vertices),1); -%Previously: -%MM=cell(2,nu,numel(vertices)); -%V=cell(nu,numel(vertices)); -%E=cell(nu+1,numel(vertices)); sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) for kver = 1:numel(vertices) - %Everything must be updated by using interfaces_all instead of interfaces TO DO ver_patches = []; %vector with indices of patches containing the vertex ver_patches_nabla = {}; %cell array containing jacobians @@ -502,21 +497,6 @@ Dv_F00 = derivatives1{patch_ind1}(:,2,1); Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); -% case 2 %vertex (0,1) -% Du_F00 = derivatives1{patch_ind1}(:,1,2); -% Dv_F00 = -derivatives1{patch_ind1}(:,2,2); -% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,2); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,2); -% case 3 %vertex (1,0) -% Du_F00 = -derivatives1{patch_ind1}(:,1,3); -% Dv_F00 = derivatives1{patch_ind1}(:,2,3); -% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,3); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,3); -% case 4 %vertex (1,1) -% Du_F00 = -derivatives1{patch_ind1}(:,1,4); -% Dv_F00 = -derivatives1{patch_ind1}(:,2,4); -% Duv_F00 = derivatives2{patch_ind1}(:,1,2,4); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); end %Store the jacobian of F for the left patch ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; @@ -537,18 +517,6 @@ Du_F00 = derivatives1{patch_ind2}(:,1,1); Dv_F00 = derivatives1{patch_ind2}(:,2,1); Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); -% case 2 %vertex (0,1) -% Du_F00 = derivatives1{patch_ind2}(:,1,2); -% Dv_F00 = -derivatives1{patch_ind2}(:,2,2); -% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,2); -% case 3 %vertex (1,0) -% Du_F00 = -derivatives1{patch_ind2}(:,1,3); -% Dv_F00 = derivatives1{patch_ind2}(:,2,3); -% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,3); -% case 4 %vertex (1,1) -% Du_F00 = -derivatives1{patch_ind2}(:,1,4); -% Dv_F00 = -derivatives1{patch_ind2}(:,2,4); -% Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); end ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; mix_der2(2*iedge,:) = Duv_F00; @@ -621,27 +589,33 @@ d01_b = vec_deltas*d0(iedge2,:)'; d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; if (reg < pp-2) - MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(pp*(kk+1)), d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2),... - d01_a/(pp*(kk+1)), d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)]'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(pp*(kk+1)), d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2),... - d01_b/(pp*(kk+1)), d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)]'; + MM1(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; + MM2(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(pp*(kk+1)), ... + d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; else MM1(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(pp*(kk+1)), ... - d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2),... + d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)]'; + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; MM2(:,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_b/(pp*(kk+1)), ... - d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2),... + d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)]'; + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; end %V_{i_m,i} d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... d00+d10_a/(pp*(kk+1)), ... - d00+d10_b/(pp*(kk+1)),... + d00+d10_b/(pp*(kk+1)), ... d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; jfun = jfun+1; end @@ -657,7 +631,7 @@ else E2 = E{kver}{iedge2,1}; end - XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); +% % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); % % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; @@ -799,6 +773,7 @@ end +% Functions to deal with general orientation of the patches function [geo_reoriented, operations] = reorientation_edge (interface, geometry) patches = [interface.patch1 interface.patch2]; nrb_patches = [geometry(patches).nurbs]; From 1aee00f66b152c2f1faca033c1e081b83854afd6 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 7 May 2021 17:51:12 +0200 Subject: [PATCH 095/366] And more cleaning --- geopdes/inst/multipatch/vertices_struct.m | 152 +++++++++------------- 1 file changed, 65 insertions(+), 87 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 2b7649b0..efaaac3a 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -5,105 +5,83 @@ %and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces %containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) -%interfaces=interfaces_i -N_int=numel(interfaces_i); -interfaces=interfaces_i; -for h=1:numel(boundaries) - interfaces(N_int+h).patch1=boundaries(h).patches; - interfaces(N_int+h).patch2=[]; - interfaces(N_int+h).side1=boundaries(h).faces; - interfaces(N_int+h).side2=[]; - interfaces(N_int+h).ornt=[]; +N_int = numel (interfaces_i); +interfaces = interfaces_i; +for hh = 1:numel(boundaries) + interfaces(N_int+hh).patch1 = boundaries(hh).patches; + interfaces(N_int+hh).side1 = boundaries(hh).faces; end %initialize vertices ivertices=[]; -nv=0; -for i=1:numel(interfaces) - patches_i=[interfaces(i).patch1 interfaces(i).patch2]; - sides_i=[interfaces(i).side1 interfaces(i).side2]; - for j=i+1:numel(interfaces) - patches_j=[interfaces(j).patch1 interfaces(j).patch2]; - sides_j=[interfaces(j).side1 interfaces(j).side2]; - [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); - cside_i=sides_i(cpatch_indi); - cside_j=sides_j(cpatch_indj); - if numel(cpatch)>0 %if vertex found - switch cside_i - case 1 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 2 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - case 3 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 4 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - end - end +% Find all vertices as intersection of two edges +nv = 0; +for ii = 1:numel(interfaces) + patches_i = [interfaces(ii).patch1 interfaces(ii).patch2]; + sides_i = [interfaces(ii).side1 interfaces(ii).side2]; + for jj = ii+1:numel(interfaces) + patches_j = [interfaces(jj).patch1 interfaces(jj).patch2]; + sides_j = [interfaces(jj).side1 interfaces(jj).side2]; + [cpatch, cpatch_indi, cpatch_indj] = intersect (patches_i, patches_j); + cside_i = sides_i(cpatch_indi); + cside_j = sides_j(cpatch_indj); + + if (numel(cpatch) > 0) % possible vertex found + flag = false; + if (cside_i == 1 && cside_j == 3) + inds = [1 1]; flag = true; + elseif (cside_i == 1 && cside_j == 4) + inds = [2 1]; flag = true; + elseif (cside_i == 2 && cside_j==3) + inds = [1 2]; flag = true; + elseif (cside_i == 2 && cside_j==4) + inds = [2 2]; flag = true; + elseif (cside_i == 3 && cside_j == 1) + inds = [1 1]; flag = true; + elseif (cside_i == 3 && cside_j == 2) + inds = [2 1]; flag = true; + elseif (cside_i == 4 && cside_j == 1) + inds = [1 2]; flag = true; + elseif (cside_i == 4 && cside_j==2) + inds = [2 2]; flag = true; + end + if (flag) + nv = nv+1; %increase number of vertices + ivertices(nv).interfaces = [ii jj]; + ivertices(nv).ind = inds; + end end + end end %vertices=ivertices; -vertices(1)=ivertices(1); -nv=1; +% Remove redundant vertices +vertices(1) = ivertices(1); +nvert = 1; -for i=2:numel(ivertices) -inter_i=ivertices(i).interfaces; -ind_i=ivertices(i).ind; -info_i=[inter_i' ind_i']; - flag_new=1; - for j=1:numel(vertices) - inter_j=vertices(j).interfaces; - ind_j=vertices(j).ind; - info_j=[inter_j' ind_j']; - if numel(intersect(info_i,info_j,'rows'))>0 - [vertices(j).interfaces,indu,~]=unique([vertices(j).interfaces ivertices(i).interfaces]); - vertices(j).ind=[vertices(j).ind ivertices(i).ind]; - vertices(j).ind=vertices(j).ind(indu); - flag_new=0; - break - end - end - if flag_new==1 - nv=nv+1; - vertices(nv)=ivertices(i); +for ii = 2:numel(ivertices) + inter_i = ivertices(ii).interfaces; + ind_i = ivertices(ii).ind; + info_i = [inter_i' ind_i']; + flag_new = 1; + for jj = 1:numel(vertices) + inter_j = vertices(jj).interfaces; + ind_j = vertices(jj).ind; + info_j = [inter_j' ind_j']; + if (numel(intersect(info_i,info_j,'rows')) > 0) + [vertices(jj).interfaces,indu,~] = unique([vertices(jj).interfaces ivertices(ii).interfaces]); + vertices(jj).ind = [vertices(jj).ind ivertices(ii).ind]; + vertices(jj).ind = vertices(jj).ind(indu); + flag_new = 0; + break end + end + if (flag_new) + nvert = nvert + 1; + vertices(nvert) = ivertices(ii); + end end - end - From 41a73a50231d360e944015e251f5da8a55134843 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 May 2021 08:59:03 +0200 Subject: [PATCH 096/366] New file for computing the vertices structure. First working version --- .../inst/multipatch/vertices_struct_rafa.m | 357 ++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 geopdes/inst/multipatch/vertices_struct_rafa.m diff --git a/geopdes/inst/multipatch/vertices_struct_rafa.m b/geopdes/inst/multipatch/vertices_struct_rafa.m new file mode 100644 index 00000000..f1b562c3 --- /dev/null +++ b/geopdes/inst/multipatch/vertices_struct_rafa.m @@ -0,0 +1,357 @@ +%INPUT: boundaries and interfaces as given by mp_geo_load +%OUTPUT: structures containing 1) for each interfaces (included boundaries) indices of the djacent patches +%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces +%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) + +function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i, geometry, boundary_interfaces) + +for iptc = 1:numel(geometry) + msh{iptc} = msh_cartesian ({[0 1] [0 1]}, {0.5 0.5}, {1 1}, geometry(iptc), 'der2', false); + space{iptc} = sp_bspline ({[0 0 1 1] [0 0 1 1]}, [1 1], msh{iptc}); + scalar_spaces{1} = sp_bspline ({[0 1] [0 0 1 1]}, [0 1], msh{iptc}); + scalar_spaces{2} = sp_bspline ({[0 0 1 1] [0 1]}, [1 0], msh{iptc}); + sp_curl{iptc} = sp_vector (scalar_spaces, msh{iptc}, 'curl-preserving'); +end +msh = msh_multipatch (msh, boundaries); +space = sp_multipatch (space, msh, interfaces_i, boundary_interfaces); +sp_curl = sp_multipatch (sp_curl, msh, interfaces_i, boundary_interfaces); + +N_int = numel (interfaces_i); +interfaces = interfaces_i; +interfaces_bnd = interfaces_i; +for hh = 1:numel(boundaries) + interfaces(N_int+hh).patch1 = boundaries(hh).patches; + interfaces(N_int+hh).side1 = boundaries(hh).faces; + interfaces_bnd(N_int+hh).patch1 = boundaries(hh).patches; + interfaces_bnd(N_int+hh).side1 = boundaries(hh).faces; + interfaces_bnd(N_int+hh).patch2 = 0; + interfaces_bnd(N_int+hh).side2 = 0; +end + +% Find the operations for reorientation +for ii = 1:numel(interfaces) + interfaces(ii).operations = reorientation_edge (interfaces(ii), geometry); +end + +% Correspondence between interfaces and edges of the space +% FIX: relative orientation (space <--> interfaces) is missing +int2sp = zeros (sp_curl.ndof, 1); +side2dof = [3 4 1 2]; dof2side = side2dof; +for ii = 1:numel(interfaces) + patch1 = interfaces(ii).patch1; + side1 = interfaces(ii).side1; + int2sp(ii) = sp_curl.gnum{patch1}(side2dof(side1)); +end +[~,sp2int] = ismember(1:sp_curl.ndof, int2sp); + +% Incidence matrices +C = sparse (sp_curl.ndof, space.ndof); +C_local = [1 0 1 0; -1 0 0 1; 0 1 -1 0; 0 -1 0 -1].'; +for iptc = 1:space.npatch + C(sp_curl.gnum{iptc},space.gnum{iptc}) = spdiags(sp_curl.dofs_ornt{iptc}(:),0,4,4) * C_local; +end + +vertices = struct('edges', [], 'patches', [], 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); +% Inner and boundary vertex are done in a different way +% For inner vertices, I set the patch with lowest number as the first one +boundary_vertices = space.boundary.dofs(:).'; +inner_vertices = setdiff (1:space.ndof, boundary_vertices); +for ivert = inner_vertices + sp_edges = find(C(:,ivert)); + edges = sp2int(sp_edges); + patches_aux = [interfaces(edges).patch1; interfaces(edges).patch2]; + sides_aux = [interfaces(edges).side1; interfaces(edges).side2]; + patches = unique (patches_aux(:)).'; + position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); + valence = numel(patches); + gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); + gnum_curl = gnum_curl(:,dof2side); + + patch_reorientation = zeros (valence, 3); + for iptc = 1:valence + patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); + end + +% Determine the first edge and patch to reorder the patches and edges + current_patch = 1; + reornt = patch_reorientation(1,:); + if (all (reornt == [0 0 0]) || all (reornt == [1 0 0])) + side = 3; + elseif (all (reornt == [0 1 0]) || all (reornt == [1 1 0])) + side = 4; + elseif (all (reornt == [0 0 1]) || all (reornt == [0 1 1])) + side = 1; + else + side = 2; + end + + indices = find (patches_aux == patches(current_patch)); + edge_aux = find (sides_aux(indices) == side); + [~,current_edge] = ind2sub([2,numel(edges)], indices(edge_aux)); + +% Starting from first edge and patch, reorder the other patches and edges +% reordering_edges and reordering_patches are local indices + reordering_patches = current_patch; + reordering_edges = current_edge; + nn = 1; + while (nn < valence) + [~,edges_on_patch] = find (patches_aux == patches(current_patch)); + next_edge = setdiff (edges_on_patch, current_edge); + [patches_on_edge,~] = find (gnum_curl == edges(next_edge)); + next_patch = setdiff (patches_on_edge, current_patch); + + nn = nn + 1; + reordering_edges(nn) = next_edge; + reordering_patches(nn) = next_patch; + current_patch = next_patch; + current_edge = next_edge; + end + edges = edges(reordering_edges); + patches = patches(reordering_patches); + +% Check the orientation of each edge compared to the one in interfaces + edge_orientation = 2*([interfaces(edges).patch2] == patches) - 1; + + vertices(ivert).edges = edges; + vertices(ivert).patches = patches; + vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); + vertices(ivert).edge_orientation = edge_orientation; + vertices(ivert).boundary_vertex = false; +end + +for ivert = boundary_vertices + sp_edges = find(C(:,ivert)); + edges = sp2int(sp_edges); + patches_aux = [interfaces_bnd(edges).patch1; interfaces_bnd(edges).patch2]; + sides_aux = [interfaces_bnd(edges).side1; interfaces_bnd(edges).side2]; + patches = setdiff (unique (patches_aux(:)).', 0); + position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); + valence = numel(patches); + gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); + gnum_curl = gnum_curl(:,dof2side); + + patch_reorientation = zeros (valence, 3); + for iptc = 1:valence + patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); + end + +% Determine the first edge and patch to reorder the patches and edges +% This part uses local indexing of edges and patches + [~,~,bnd_edges] = intersect (sp2int(sp_curl.boundary.dofs), edges); + if (numel (bnd_edges) ~=2) + error ('The number of boundary edges near a vertex should be equal to two') + end + for ii = 1:2 + [bnd_patches(ii), bnd_sides(ii)] = find (gnum_curl == edges(bnd_edges(ii))); + end + + reornt = patch_reorientation(bnd_patches(1),:); + if ((bnd_sides(1) == 3 && (all (reornt == [0 0 0]) || all (reornt == [1 0 0]))) ... + || (bnd_sides(1) == 4 && (all (reornt == [0 1 0]) || all (reornt == [1 1 0]))) ... + || (bnd_sides(1) == 1 && (all (reornt == [0 0 1]) || all (reornt == [0 1 1]))) ... + || (bnd_sides(1) == 2 && (all (reornt == [1 0 1]) || all (reornt == [1 1 1])))) + current_edge = bnd_edges(1); + current_patch = bnd_patches(1); + last_edge = bnd_edges(2); + else + current_edge = bnd_edges(2); + current_patch = bnd_patches(end); + last_edge = bnd_edges(1); + end + +% Starting from first edge and patch, reorder the other patches and edges +% reordering_edges and reordering_patches are local indices + reordering_patches = current_patch; + reordering_edges = current_edge; + reordering_edges(valence+1) = last_edge; + nn = 1; + while (nn < valence) + [~,edges_on_patch] = find (patches_aux == patches(current_patch)); + next_edge = setdiff (edges_on_patch, current_edge); + [patches_on_edge,~] = find (gnum_curl == edges(next_edge)); + next_patch = setdiff (patches_on_edge, current_patch); + + nn = nn + 1; + reordering_edges(nn) = next_edge; + reordering_patches(nn) = next_patch; + current_patch = next_patch; + current_edge = next_edge; + end + edges = edges(reordering_edges); + patches = patches(reordering_patches); + +% Check the orientation of each edge compared to the one in interfaces + edge_orientation = 2*([interfaces_bnd(edges).patch2] == [patches 0]) - 1; + + vertices(ivert).edges = edges; + vertices(ivert).patches = patches; + vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); + vertices(ivert).edge_orientation = edge_orientation; + vertices(ivert).boundary_vertex = true; +end + + + + +%initialize vertices +ivertices=[]; + +% Find all vertices as intersection of two edges +nv = 0; +for ii = 1:numel(interfaces) + patches_i = [interfaces(ii).patch1 interfaces(ii).patch2]; + sides_i = [interfaces(ii).side1 interfaces(ii).side2]; + for jj = ii+1:numel(interfaces) + patches_j = [interfaces(jj).patch1 interfaces(jj).patch2]; + sides_j = [interfaces(jj).side1 interfaces(jj).side2]; + [cpatch, cpatch_indi, cpatch_indj] = intersect (patches_i, patches_j); + cside_i = sides_i(cpatch_indi); + cside_j = sides_j(cpatch_indj); + + if (numel(cpatch) > 0) % possible vertex found + flag = false; + if (cside_i == 1 && cside_j == 3) + inds = [1 1]; flag = true; + elseif (cside_i == 1 && cside_j == 4) + inds = [2 1]; flag = true; + elseif (cside_i == 2 && cside_j==3) + inds = [1 2]; flag = true; + elseif (cside_i == 2 && cside_j==4) + inds = [2 2]; flag = true; + elseif (cside_i == 3 && cside_j == 1) + inds = [1 1]; flag = true; + elseif (cside_i == 3 && cside_j == 2) + inds = [2 1]; flag = true; + elseif (cside_i == 4 && cside_j == 1) + inds = [1 2]; flag = true; + elseif (cside_i == 4 && cside_j==2) + inds = [2 2]; flag = true; + end + if (flag) + nv = nv+1; %increase number of vertices + ivertices(nv).interfaces = [ii jj]; + ivertices(nv).ind = inds; + end + end + end +end + +%vertices=ivertices; + +% Remove redundant vertices +vertices(1) = ivertices(1); +nvert = 1; + +for ii = 2:numel(ivertices) + inter_i = ivertices(ii).interfaces; + ind_i = ivertices(ii).ind; + info_i = [inter_i' ind_i']; + flag_new = 1; + for jj = 1:numel(vertices) + inter_j = vertices(jj).interfaces; + ind_j = vertices(jj).ind; + info_j = [inter_j' ind_j']; + if (numel(intersect(info_i,info_j,'rows')) > 0) + [vertices(jj).interfaces,indu,~] = unique([vertices(jj).interfaces ivertices(ii).interfaces]); + vertices(jj).ind = [vertices(jj).ind ivertices(ii).ind]; + vertices(jj).ind = vertices(jj).ind(indu); + flag_new = 0; + break + end + end + if (flag_new) + nvert = nvert + 1; + vertices(nvert) = ivertices(ii); + end +end + +end + +function operations = reorientation_edge (interface, geometry) + patches = [interface.patch1 interface.patch2]; + nrb_patches = [geometry(patches).nurbs]; + sides = [interface.side1 interface.side2]; +% Change orientation of first patch + [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(1) == 2) + if (jacdet < 0) + operations(1,:) = [1 0 0]; + else + operations(1,:) = [1 1 0]; + end + elseif (sides(1) == 3) + if (jacdet < 0) + operations(1,:) = [0 0 1]; + else + operations(1,:) = [1 0 1]; + end + elseif (sides(1) == 4) + if (jacdet < 0) + operations(1,:) = [1 1 1]; + else + operations(1,:) = [0 1 1]; + end + elseif (sides(1) == 1) + if (jacdet < 0) + operations(1,:) = [0 1 0]; + else + operations(1,:) = [0 0 0]; + end + end + +% Change orientation of second patch, only for inner edges + if (numel(nrb_patches) == 2) + [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(2) == 1) + if (jacdet < 0) + operations(2,:) = [0 0 1]; + else + operations(2,:) = [0 1 1]; + end + elseif (sides(2) == 2) + if (jacdet < 0) + operations(2,:) = [1 1 1]; + else + operations(2,:) = [1 0 1]; + end + elseif (sides(2) == 3) + if (jacdet < 0) + operations(2,:) = [1 0 0]; + else + operations(2,:) = [0 0 0]; + end + elseif (sides(2) == 4) + if (jacdet < 0) + operations(2,:) = [0 1 0]; + else + operations(2,:) = [1 1 0]; + end + end + end +end + + +function operations = reorientation_vertex (position, nrb) + + operations = zeros (1,3); + switch position + case 2 + operations(1) = 1; + nrb = nrbreverse (nrb, 1); + case 3 + operations(2) = 1; + nrb = nrbreverse (nrb, 2); + case 4 + operations(1:2) = [1 1]; + nrb = nrbreverse (nrb, [1 2]); + end + [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + + if (jacdet < 0) + operations(3) = 1; + end + +end \ No newline at end of file From 8c6aea279206b0d8963108ee7d46f93ca1cff43b Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 May 2021 08:59:44 +0200 Subject: [PATCH 097/366] Added msgid to warning --- geopdes/inst/multipatch/mp_geo_load.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/mp_geo_load.m b/geopdes/inst/multipatch/mp_geo_load.m index d74eecf6..feb2b5ac 100644 --- a/geopdes/inst/multipatch/mp_geo_load.m +++ b/geopdes/inst/multipatch/mp_geo_load.m @@ -135,7 +135,7 @@ for iptc = 1:numel(in) geometry(iptc) = geo_load (in(iptc)); end - warning ('Automatically generating the interface and boundary information with nrbmultipatch') + warning ('geopdes:nrbmultipatch','Automatically generating the interface and boundary information with nrbmultipatch') [interfaces, boundaries] = nrbmultipatch (in); subdomains(1).name = 'SUBDOMAIN 1'; subdomains(1).patches = 1:numel(in); From df73e3eb24b8735416ec2b7567b67621dbadcbbd Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 May 2021 09:01:27 +0200 Subject: [PATCH 098/366] Remove old parts of the code --- .../inst/multipatch/vertices_struct_rafa.m | 75 ------------------- 1 file changed, 75 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct_rafa.m b/geopdes/inst/multipatch/vertices_struct_rafa.m index f1b562c3..b84a09c7 100644 --- a/geopdes/inst/multipatch/vertices_struct_rafa.m +++ b/geopdes/inst/multipatch/vertices_struct_rafa.m @@ -190,81 +190,6 @@ vertices(ivert).boundary_vertex = true; end - - - -%initialize vertices -ivertices=[]; - -% Find all vertices as intersection of two edges -nv = 0; -for ii = 1:numel(interfaces) - patches_i = [interfaces(ii).patch1 interfaces(ii).patch2]; - sides_i = [interfaces(ii).side1 interfaces(ii).side2]; - for jj = ii+1:numel(interfaces) - patches_j = [interfaces(jj).patch1 interfaces(jj).patch2]; - sides_j = [interfaces(jj).side1 interfaces(jj).side2]; - [cpatch, cpatch_indi, cpatch_indj] = intersect (patches_i, patches_j); - cside_i = sides_i(cpatch_indi); - cside_j = sides_j(cpatch_indj); - - if (numel(cpatch) > 0) % possible vertex found - flag = false; - if (cside_i == 1 && cside_j == 3) - inds = [1 1]; flag = true; - elseif (cside_i == 1 && cside_j == 4) - inds = [2 1]; flag = true; - elseif (cside_i == 2 && cside_j==3) - inds = [1 2]; flag = true; - elseif (cside_i == 2 && cside_j==4) - inds = [2 2]; flag = true; - elseif (cside_i == 3 && cside_j == 1) - inds = [1 1]; flag = true; - elseif (cside_i == 3 && cside_j == 2) - inds = [2 1]; flag = true; - elseif (cside_i == 4 && cside_j == 1) - inds = [1 2]; flag = true; - elseif (cside_i == 4 && cside_j==2) - inds = [2 2]; flag = true; - end - if (flag) - nv = nv+1; %increase number of vertices - ivertices(nv).interfaces = [ii jj]; - ivertices(nv).ind = inds; - end - end - end -end - -%vertices=ivertices; - -% Remove redundant vertices -vertices(1) = ivertices(1); -nvert = 1; - -for ii = 2:numel(ivertices) - inter_i = ivertices(ii).interfaces; - ind_i = ivertices(ii).ind; - info_i = [inter_i' ind_i']; - flag_new = 1; - for jj = 1:numel(vertices) - inter_j = vertices(jj).interfaces; - ind_j = vertices(jj).ind; - info_j = [inter_j' ind_j']; - if (numel(intersect(info_i,info_j,'rows')) > 0) - [vertices(jj).interfaces,indu,~] = unique([vertices(jj).interfaces ivertices(ii).interfaces]); - vertices(jj).ind = [vertices(jj).ind ivertices(ii).ind]; - vertices(jj).ind = vertices(jj).ind(indu); - flag_new = 0; - break - end - end - if (flag_new) - nvert = nvert + 1; - vertices(nvert) = ivertices(ii); - end -end - end function operations = reorientation_edge (interface, geometry) From 98fc35c24c0984980d9045cba174196bd635c22e Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 May 2021 10:50:18 +0200 Subject: [PATCH 099/366] Added valence information --- .../inst/multipatch/vertices_struct_rafa.m | 163 ++++++++---------- 1 file changed, 70 insertions(+), 93 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct_rafa.m b/geopdes/inst/multipatch/vertices_struct_rafa.m index b84a09c7..2a41ee9e 100644 --- a/geopdes/inst/multipatch/vertices_struct_rafa.m +++ b/geopdes/inst/multipatch/vertices_struct_rafa.m @@ -34,7 +34,6 @@ end % Correspondence between interfaces and edges of the space -% FIX: relative orientation (space <--> interfaces) is missing int2sp = zeros (sp_curl.ndof, 1); side2dof = [3 4 1 2]; dof2side = side2dof; for ii = 1:numel(interfaces) @@ -51,82 +50,20 @@ C(sp_curl.gnum{iptc},space.gnum{iptc}) = spdiags(sp_curl.dofs_ornt{iptc}(:),0,4,4) * C_local; end -vertices = struct('edges', [], 'patches', [], 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); +vertices = struct('valence_p', [], 'valence_e', [], 'edges', [], 'patches', [], ... + 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); % Inner and boundary vertex are done in a different way % For inner vertices, I set the patch with lowest number as the first one boundary_vertices = space.boundary.dofs(:).'; -inner_vertices = setdiff (1:space.ndof, boundary_vertices); -for ivert = inner_vertices - sp_edges = find(C(:,ivert)); - edges = sp2int(sp_edges); - patches_aux = [interfaces(edges).patch1; interfaces(edges).patch2]; - sides_aux = [interfaces(edges).side1; interfaces(edges).side2]; - patches = unique (patches_aux(:)).'; - position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); - valence = numel(patches); - gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); - gnum_curl = gnum_curl(:,dof2side); - - patch_reorientation = zeros (valence, 3); - for iptc = 1:valence - patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); - end - -% Determine the first edge and patch to reorder the patches and edges - current_patch = 1; - reornt = patch_reorientation(1,:); - if (all (reornt == [0 0 0]) || all (reornt == [1 0 0])) - side = 3; - elseif (all (reornt == [0 1 0]) || all (reornt == [1 1 0])) - side = 4; - elseif (all (reornt == [0 0 1]) || all (reornt == [0 1 1])) - side = 1; - else - side = 2; - end - - indices = find (patches_aux == patches(current_patch)); - edge_aux = find (sides_aux(indices) == side); - [~,current_edge] = ind2sub([2,numel(edges)], indices(edge_aux)); - -% Starting from first edge and patch, reorder the other patches and edges -% reordering_edges and reordering_patches are local indices - reordering_patches = current_patch; - reordering_edges = current_edge; - nn = 1; - while (nn < valence) - [~,edges_on_patch] = find (patches_aux == patches(current_patch)); - next_edge = setdiff (edges_on_patch, current_edge); - [patches_on_edge,~] = find (gnum_curl == edges(next_edge)); - next_patch = setdiff (patches_on_edge, current_patch); - - nn = nn + 1; - reordering_edges(nn) = next_edge; - reordering_patches(nn) = next_patch; - current_patch = next_patch; - current_edge = next_edge; - end - edges = edges(reordering_edges); - patches = patches(reordering_patches); - -% Check the orientation of each edge compared to the one in interfaces - edge_orientation = 2*([interfaces(edges).patch2] == patches) - 1; - - vertices(ivert).edges = edges; - vertices(ivert).patches = patches; - vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); - vertices(ivert).edge_orientation = edge_orientation; - vertices(ivert).boundary_vertex = false; -end - -for ivert = boundary_vertices +for ivert = 1:space.ndof + boundary_vertex = ismember (ivert, boundary_vertices); sp_edges = find(C(:,ivert)); edges = sp2int(sp_edges); patches_aux = [interfaces_bnd(edges).patch1; interfaces_bnd(edges).patch2]; sides_aux = [interfaces_bnd(edges).side1; interfaces_bnd(edges).side2]; patches = setdiff (unique (patches_aux(:)).', 0); position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); - valence = numel(patches); + valence = numel (patches); gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); gnum_curl = gnum_curl(:,dof2side); @@ -136,34 +73,23 @@ end % Determine the first edge and patch to reorder the patches and edges -% This part uses local indexing of edges and patches - [~,~,bnd_edges] = intersect (sp2int(sp_curl.boundary.dofs), edges); - if (numel (bnd_edges) ~=2) - error ('The number of boundary edges near a vertex should be equal to two') - end - for ii = 1:2 - [bnd_patches(ii), bnd_sides(ii)] = find (gnum_curl == edges(bnd_edges(ii))); - end - - reornt = patch_reorientation(bnd_patches(1),:); - if ((bnd_sides(1) == 3 && (all (reornt == [0 0 0]) || all (reornt == [1 0 0]))) ... - || (bnd_sides(1) == 4 && (all (reornt == [0 1 0]) || all (reornt == [1 1 0]))) ... - || (bnd_sides(1) == 1 && (all (reornt == [0 0 1]) || all (reornt == [0 1 1]))) ... - || (bnd_sides(1) == 2 && (all (reornt == [1 0 1]) || all (reornt == [1 1 1])))) - current_edge = bnd_edges(1); - current_patch = bnd_patches(1); - last_edge = bnd_edges(2); + if (boundary_vertex) + [current_edge, current_patch, last_edge] = ... + find_first_edge_and_patch_boundary (edges, patch_reorientation, sp_curl.boundary.dofs, gnum_curl, sp2int); + reordering_edges = zeros (1, valence+1); + reordering_edges(valence+1) = last_edge; + reordering_patches = zeros (1, valence); else - current_edge = bnd_edges(2); - current_patch = bnd_patches(end); - last_edge = bnd_edges(1); + [current_edge, current_patch] = ... + find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation); + reordering_edges = zeros (1, valence); + reordering_patches = zeros (1, valence); end % Starting from first edge and patch, reorder the other patches and edges % reordering_edges and reordering_patches are local indices - reordering_patches = current_patch; - reordering_edges = current_edge; - reordering_edges(valence+1) = last_edge; + reordering_patches(1) = current_patch; + reordering_edges(1) = current_edge; nn = 1; while (nn < valence) [~,edges_on_patch] = find (patches_aux == patches(current_patch)); @@ -181,13 +107,19 @@ patches = patches(reordering_patches); % Check the orientation of each edge compared to the one in interfaces - edge_orientation = 2*([interfaces_bnd(edges).patch2] == [patches 0]) - 1; + if (boundary_vertex) + edge_orientation = 2*([interfaces_bnd(edges).patch2] == [patches 0]) - 1; + else + edge_orientation = 2*([interfaces(edges).patch2] == patches) - 1; + end + vertices(ivert).valence_p = valence; + vertices(ivert).valence_e = numel(edges); vertices(ivert).edges = edges; vertices(ivert).patches = patches; vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); vertices(ivert).edge_orientation = edge_orientation; - vertices(ivert).boundary_vertex = true; + vertices(ivert).boundary_vertex = boundary_vertex; end end @@ -279,4 +211,49 @@ operations(3) = 1; end +end + +% Determine the first edge and patch to reorder the patches and edges +% These two functions use local numbering +function [first_edge, first_patch] = find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation) + first_patch = 1; + reornt = patch_reorientation(1,:); + if (all (reornt == [0 0 0]) || all (reornt == [1 0 0])) + side = 3; + elseif (all (reornt == [0 1 0]) || all (reornt == [1 1 0])) + side = 4; + elseif (all (reornt == [0 0 1]) || all (reornt == [0 1 1])) + side = 1; + else + side = 2; + end + + indices = find (patches_aux == patches(first_patch)); + edge_aux = find (sides_aux(indices) == side); + [~,first_edge] = ind2sub([2,numel(edges)], indices(edge_aux)); +end + +function [first_edge, first_patch, last_edge] = ... + find_first_edge_and_patch_boundary (edges, patch_reorientation, curl_bnd_dofs, gnum_curl, sp2int) + [~,~,bnd_edges] = intersect (sp2int(curl_bnd_dofs), edges); + if (numel (bnd_edges) ~=2) + error ('The number of boundary edges near a vertex should be equal to two') + end + for ii = 1:2 + [bnd_patches(ii), bnd_sides(ii)] = find (gnum_curl == edges(bnd_edges(ii))); + end + + reornt = patch_reorientation(bnd_patches(1),:); + if ((bnd_sides(1) == 3 && (all (reornt == [0 0 0]) || all (reornt == [1 0 0]))) ... + || (bnd_sides(1) == 4 && (all (reornt == [0 1 0]) || all (reornt == [1 1 0]))) ... + || (bnd_sides(1) == 1 && (all (reornt == [0 0 1]) || all (reornt == [0 1 1]))) ... + || (bnd_sides(1) == 2 && (all (reornt == [1 0 1]) || all (reornt == [1 1 1])))) + first_edge = bnd_edges(1); + first_patch = bnd_patches(1); + last_edge = bnd_edges(2); + else + first_edge = bnd_edges(2); + first_patch = bnd_patches(end); + last_edge = bnd_edges(1); + end end \ No newline at end of file From 5cc41bdc6203eca8fa2ed4664bd22c85d0911f60 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 May 2021 18:26:10 +0200 Subject: [PATCH 100/366] Cleaned edge functions. Working on vertex functions --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 720 ++++++++---------- 1 file changed, 314 insertions(+), 406 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 31b751fb..d4580166 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -59,7 +59,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries, boundary_interfaces) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') @@ -153,7 +153,7 @@ % We could store the info of interfaces per patch, as in mp_interface sp.ndof_interior = 0; - [interfaces_all, ~] = vertices_struct(boundaries, interfaces); + [interfaces_all, vertices] = vertices_struct_rafa (boundaries, interfaces, geometry, boundary_interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) @@ -185,7 +185,7 @@ % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, boundaries); + compute_coefficients (sp, msh, geometry, interfaces_all, vertices); %keyboard sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions @@ -204,15 +204,13 @@ Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... speye (numel (sp.interior_dofs_per_patch{iptc})); end - - for intrfc = 1:numel(interfaces) + + for intrfc = 1:numel(interfaces_all) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - %for iptc_on_interface = 1:2 - iptc1 = interfaces(intrfc).patch1; - iptc2 = interfaces(intrfc).patch2; - Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; - Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; - %end + patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; + for iptc = 1:numel(patches) + Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; + end end % Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point @@ -247,350 +245,208 @@ end -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) +%Initialize output variables with correct size +ndof_per_interface = zeros (1, numel(interfaces_all)); +ndof_per_vertex = 6*ones(1,numel(vertices)); -[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); +CC_edges = cell (2, numel (interfaces_all)); +CC_edges_discarded = cell (2, numel (interfaces_all)); +CC_vertices = cell (space.npatch, numel(vertices)); +for ii = 1:space.npatch + for jj = 1:numel(vertices) + CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), 6); + end +end -p = space.sp_patch{1}.degree(1); -k = numel(msh.msh_patch{1}.breaks{1})-2; -n = space.sp_patch{1}.sp_univ(1).ndof; +pp = space.sp_patch{1}.degree(1); +kk = numel(msh.msh_patch{1}.breaks{1})-2; +% nn = space.sp_patch{1}.sp_univ(1).ndof; breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg = p-max(mult(2:end-1)); +reg = pp - max(mult(2:end-1)); -ndof_per_interface = (2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere -ndof_per_vertex = 6*ones(1,numel(vertices)); all_alpha0 = zeros(numel(interfaces_all),2); all_alpha1 = zeros(numel(interfaces_all),2); all_beta0 = zeros(numel(interfaces_all),2); all_beta1 = zeros(numel(interfaces_all),2); -all_t0 = zeros(numel(interfaces_all),2); - -%Initialize the cell array of CC_vertices matrices -for ii = 1:space.npatch - for jj = 1:numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end - -%Initialize the cell array of CC_edges matrices -for jj = 1:numel(interfaces_all) - if (isempty(interfaces_all(jj).patch1)) - CC_edges{1,jj} = []; - else - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); - end - if (isempty(interfaces_all(jj).patch2)) - CC_edges{2,jj} = []; - else - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); - end -end - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -brk = cell (1,msh.ndim); -for iptc = 1:space.npatch - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1} = [0 1]'; - pts{2} = [0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); - msh_der = msh_precompute (msh_pts_der1); - derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} - %In this case (rdim=2) - %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space - %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) - %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) - %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) - %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) - %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) - %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) - %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) - - %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space - %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) - %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) - %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) - %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) - %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) - %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) - %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) - %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) - %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) - %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) - %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) -end -%Construction of CC_edges +%Computation of CC_edges for iref = 1:numel(interfaces_all) - clear patch - if (~isempty(interfaces_all(iref).patch1)) - patch(1) = interfaces_all(iref).patch1; %LEFT - side(1) = interfaces_all(iref).side1; %LEFT - end - if (~isempty(interfaces_all(iref).patch2)) - patch(2) = interfaces_all(iref).patch2; %RIGHT - side(2) = interfaces_all(iref).side2; %RIGHT - end - nnz_el = find(patch>0); - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - for ii = nnz_el % The two patches (L-R) - % Points for G^1 conditions system - brk = cell (1,msh.ndim); - knt = geometry(patch(ii)).nurbs.knots; - order = geometry(patch(ii)).nurbs.order; + patches = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; + npatches_on_edge = numel (patches); + operations = interfaces_all(iref).operations; +% Auxiliary geometry with orientation as in the paper + geo_local = reorientation_patches (operations, geometry(patches)); + sides = [1 3]; + +% Compute gluing data + geo_map_jac = cell (npatches_on_edge, 1); + for ii = 1:npatches_on_edge + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); + knt = geo_local(ii).nurbs.knots; + order = geo_local(ii).nurbs.order; for idim = 1:msh.ndim grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); msh_side_interior = msh_precompute (msh_side_interior); geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% if ii==1 && (side(ii)==3 || side(ii)==4) -% disp('done1') -% geo_map_jac{ii}=flip(geo_map_jac{ii}); -% elseif ii==2 && (side(ii)==1 || side(ii)==2) -% disp('done2') -% geo_map_jac{ii}=flip(geo_map_jac{ii}); -% end end - - if (length(patch)==2) %as it is placed now, this check computes the matrices corresponding only to interior edges - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); + + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); + clear geo_map_jac msh_grev msh_side_interior grev_pts %Saving alphas and betas (first column=R, second column=L) - all_alpha0(iref,:) = alpha0; - all_alpha1(iref,:) = alpha1; - all_beta0(iref,:) = beta0; - all_beta1(iref,:) = beta1; - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (R-L) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed + % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION + all_alpha0(iref,:) = alpha0; + all_alpha1(iref,:) = alpha1; + all_beta0(iref,:) = beta0; + all_beta1(iref,:) = beta1; + +% Compute the Greville points, and the auxiliary mesh and space objects for +% functions with reduced degree or increased regularity + for ii = 1:npatches_on_edge %% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(ii)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); + ind2 = ceil (sides(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); + degrees = degree_reorientation (space.sp_patch{patches(ii)}.degree, operations(ii,3)); + degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); + + knots = knot_vector_reorientation (space.sp_patch{patches(ii)}.knots, operations(ii,:)); + knots0 = knot_vector_reorientation (space.knots0_patches{patches(ii)}, operations(ii,:)); + knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; + knots1 = knot_vector_reorientation (space.knots1_patches{patches(ii)}, operations(ii,:)); + knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); % Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end + degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); + knt = unique (knots{ind2}); + tau1 = knt(2) - knt(1); + +% sp_aux contains the value and derivatives of the basis functions, at the Greville points + msh_side = msh_eval_boundary_side (msh_grev, sides(ii)); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); + sp_aux = sp_bspline (knots, degrees, msh_side_interior); -% For now we assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_interior); -% msh_side_int{ii} = msh_precompute (msh_side_interior); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); +% Univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) and N^{p,r} on the interface + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(sides(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(sides(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); + + knotsn = knots{ind1}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(sides(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); % Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end + A = sparse (msh_side.nel, msh_side.nel); + for jj = 1:msh_side.nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end -%alphas and betas % ORIENTATION ISSUE - alpha{ii} = abs (alpha0(ii)*(1-grev_pts{2}') + alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii} = beta0(ii)*(1-grev_pts{2}') + beta1(ii)*grev_pts{2}'; - %looks like alpha must be inverted, but betas mustn't +%alphas and betas + alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; + beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof_edge) only works for the two patch case, for now - ndof_edge = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - ind0_s{iref} = ind0; %saving the indices for later use; - ind1_s{iref} = ind1; - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end +% RHS and solution of the linear systems, (14)-(16) in Mario's notes + rhss = sparse (msh_side.nel, sp0_struct.ndof); + for jj = 1:msh_side.nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0 = A \ rhss; + coeff0(abs(coeff0) < 1e-12) = 0; % Make more sparse + + rhsb = sparse (msh_side.nel, sp0_struct.ndof); + if (ii == 1) % paper case, (sides(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (ii == 2) %The other paper case, (sides(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side.nel + val_aux = -val * beta(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1 = A \ rhsb; + coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse + + rhsc = sparse (msh_side.nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + for jj = 1:msh_side.nel + val_aux = val * alpha(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2 = A \ rhsc; + coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof_edge) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof_edge-2]); +% Pass the coefficients to the tensor product basis + ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; + ndof_dir_original = space.sp_patch{patches(ii)}.ndof_dir; + if (ii == 1) %(sides(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (ii == 2) %(sides(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); end - else - n0 = n-k; - ndof_edge = n0+n-k-1; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof_edge); - CC_edges_discarded{ii,iref} = CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof_edge-1 ndof_edge]); %dimension: n^2 x 10 - CC_edges{ii,iref} = CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof_edge-2]); + indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); + ind0_ornt = indices_reoriented(ind0); + ind1_ornt = indices_reoriented(ind1); + +% Store the coefficients in CC_edges, and compute the number of functions + ndof_edge = sp0_struct.ndof + sp1_struct.ndof; + trace_functions = 4:sp0_struct.ndof-3; + deriv_functions = sp0_struct.ndof + (3:sp1_struct.ndof-2); + active_functions = union (trace_functions, deriv_functions); + discarded_functions = setdiff (1:ndof_edge, active_functions); + + CC = sparse (space.ndof_per_patch(patches(ii)), ndof_edge); + CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; + CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; + CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; + + ndof_per_interface(iref) = numel(active_functions); + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patches(ii)), ndof_per_interface(iref)); + CC_edges{ii,iref} = CC(:,active_functions); + CC_edges_discarded{ii,iref} = CC(:,discarded_functions); end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - end +% Computation of CC_vertices +% Compute for each patch all the derivatives we possibly need to compute t,d, and sigma +% FIX: this would be done inside the vertex loop, after reorientation +brk = cell (1,msh.ndim); +for iptc = 1:space.npatch + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? + end + %the following points correspond to the four vertices of the patch + pts{1} = [0 1]'; + pts{2} = [0 1]';%pts{2}=[0 1/2 1]' + msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} +end + %We assume that the local numbering of interfaces and patches is such that %vertices(kver).interface(im) is the interface between @@ -598,45 +454,60 @@ MM = cell(2,numel(vertices)); V = cell(numel(vertices),1); E = cell(numel(vertices),1); -%Previously: -%MM=cell(2,nu,numel(vertices)); -%V=cell(nu,numel(vertices)); -%E=cell(nu+1,numel(vertices)); sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) for kver = 1:numel(vertices) - +% if (vertices(kver).boundary_vertex) +% continue +% end + edges = vertices(kver).edges; + patches = vertices(kver).patches; + valence_e = vertices(kver).valence_e; + valence_p = vertices(kver).valence_p; + operations = vertices(kver).patch_reorientation; + + geo_local = reorientation_patches (operations, geometry(patches)); + +% ver_patches = []; %FIX: remove +% for iedge = 1:valence_e %cycle over all the interfaces containing the vertex +% inter = vertices(kver).edges(iedge); %global index of the interface +% patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface +% patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface +% % vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch +% % vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch +% vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation +% ver_patches = [ver_patches patch_ind1 patch_ind2]; +% ver_ind = [ver_ind vertex_ind1 vertex_ind2]; +% %compute t(0) and t'(0), d(0) and d'(0) +% +% % These must be computed here +% Du_F00 = derivatives1{patch_ind1}(:,1,1); +% Dv_F00 = derivatives1{patch_ind1}(:,2,1); +% Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); +% end +% end +end + +for kver = 1:numel(vertices) %Everything must be updated by using interfaces_all instead of interfaces TO DO ver_patches = []; %vector with indices of patches containing the vertex ver_patches_nabla = {}; %cell array containing jacobians ver_ind = []; %vector containing local index of vertex in the patch - ninterfaces_ver = numel(vertices(kver).interfaces); + valence_e = vertices(kver).valence_e; + valence_p = vertices(kver).valence_p; + patches = vertices(kver).patches; - boundary_vertex = 0; - for im = 1:ninterfaces_ver - inter = vertices(kver).interfaces(im); - if (isempty(interfaces_all(inter).side1) || isempty(interfaces_all(inter).side2)) - boundary_vertex = 1; - break - end - end - if (~boundary_vertex) + if (~vertices(kver).boundary_vertex) -% for h=1:numel(vertices(kver).interfaces) -% hint=vertices(kver).interfaces(h); -% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; -% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... -% sides(interfaces(hint).side2,vertices(kver).ind)]; -% end -% ver_patches=unique(ver_patches,'stable'); -% ver_ind=unique(ver_ind,'stable'); % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) - for iedge = 1:ninterfaces_ver %cycle over all the interfaces containing the vertex - inter = vertices(kver).interfaces(iedge); %global index of the interface + for iedge = 1:valence_e %cycle over all the interfaces containing the vertex + inter = vertices(kver).edges(iedge); %global index of the interface patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface - vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch - vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch +% vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch +% vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch + vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation ver_patches = [ver_patches patch_ind1 patch_ind2]; ver_ind = [ver_ind vertex_ind1 vertex_ind2]; %compute t(0) and t'(0), d(0) and d'(0) @@ -646,21 +517,6 @@ Dv_F00 = derivatives1{patch_ind1}(:,2,1); Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); -% case 2 %vertex (0,1) -% Du_F00 = derivatives1{patch_ind1}(:,1,2); -% Dv_F00 = -derivatives1{patch_ind1}(:,2,2); -% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,2); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,2); -% case 3 %vertex (1,0) -% Du_F00 = -derivatives1{patch_ind1}(:,1,3); -% Dv_F00 = derivatives1{patch_ind1}(:,2,3); -% Duv_F00 = -derivatives2{patch_ind1}(:,1,2,3); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,3); -% case 4 %vertex (1,1) -% Du_F00 = -derivatives1{patch_ind1}(:,1,4); -% Dv_F00 = -derivatives1{patch_ind1}(:,2,4); -% Duv_F00 = derivatives2{patch_ind1}(:,1,2,4); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,4); end %Store the jacobian of F for the left patch ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; @@ -681,24 +537,12 @@ Du_F00 = derivatives1{patch_ind2}(:,1,1); Dv_F00 = derivatives1{patch_ind2}(:,2,1); Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); -% case 2 %vertex (0,1) -% Du_F00 = derivatives1{patch_ind2}(:,1,2); -% Dv_F00 = -derivatives1{patch_ind2}(:,2,2); -% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,2); -% case 3 %vertex (1,0) -% Du_F00 = -derivatives1{patch_ind2}(:,1,3); -% Dv_F00 = derivatives1{patch_ind2}(:,2,3); -% Duv_F00 = -derivatives2{patch_ind2}(:,1,2,3); -% case 4 %vertex (1,1) -% Du_F00 = -derivatives1{patch_ind2}(:,1,4); -% Dv_F00 = -derivatives1{patch_ind2}(:,2,4); -% Duv_F00 = derivatives2{patch_ind2}(:,1,2,4); end ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; mix_der2(2*iedge,:) = Duv_F00; %Pick the correct part of CC_edges_discarded %TO BE FIXED - if (vertices(kver).ind(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface + if (vertices(kver).edge_orientation(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); % else %the vertex is the right/top endpoint of im-th interface @@ -727,16 +571,16 @@ %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices sigma = 0; - for im = 1:ninterfaces_ver % FIX: is this the number of interfaces? + for im = 1:valence_p % FIX: is this the number of interfaces? sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); end - sigma = 1/(sigma/(p*(k+1)*ninterfaces_ver)); + sigma = 1/(sigma/(pp*(kk+1)*valence_p)); %computing matrices MM and V - for ipatch = 1:ninterfaces_ver %FIX: cycle over the patches containing the vertex + for ipatch = 1:valence_p %FIX: cycle over the patches containing the vertex %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) + n1 = space.sp_patch{patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) + n2 = space.sp_patch{patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) % V{kver}{im} = zeros(n1*n2,6); MM1 = zeros(5,6); MM2 = zeros(5,6); VV = zeros(n1*n2,6); @@ -745,7 +589,7 @@ im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 end iedge1 = im_edges(1); iedge2 = im_edges(2); - + corner_4dofs = [1 2 n2+1 n2+2]; jfun = 1; for j1 = 0:2 @@ -764,47 +608,53 @@ d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; d01_b = vec_deltas*d0(iedge2,:)'; d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; - if (reg < p-2) - MM1(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + if (reg < pp-2) + MM1(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; + MM2(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(pp*(kk+1)), ... + d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; else MM1(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(p*(k+1)), ... - d00+3*d10_a/(p*(k+1))+2*d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), ... - d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; + d00+d10_a/(pp*(kk+1)), ... + d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; MM2(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(p*(k+1)), ... - d00+3*d10_b/(p*(k+1))+2*d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), ... - d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; + d00+d10_b/(pp*(kk+1)), ... + d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; end %V_{i_m,i} d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(p*(k+1)), ... - d00+d10_b/(p*(k+1)),... - d00+(d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; + d00+d10_a/(pp*(kk+1)), ... + d00+d10_b/(pp*(kk+1)), ... + d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; jfun = jfun+1; end end % Check which patch of the edge function we are considering - if (interfaces_all(vertices(kver).interfaces(iedge1)).patch2 == ver_patches(ipatch))%the considered patch is the second patch edge iedge1 + if (interfaces_all(vertices(kver).edges(iedge1)).patch2 == patches(ipatch))%the considered patch is the second patch edge iedge1 E1 = E{kver}{iedge1,2}; else E1 = E{kver}{iedge1,1}; end - if (interfaces_all(vertices(kver).interfaces(iedge2)).patch2 == ver_patches(ipatch))%the considered patch is the second patch of edge iedge2 + if (interfaces_all(vertices(kver).edges(iedge2)).patch2 == patches(ipatch))%the considered patch is the second patch of edge iedge2 E2 = E{kver}{iedge2,2}; else E2 = E{kver}{iedge2,1}; end - XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); +% % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); % % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; - CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; + CC_vertices{patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; % % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; %csi2=[1 9 17 25 33 41 49 57]; %csi1=1:8; @@ -820,6 +670,15 @@ function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) + if (numel (geo_map_jac) == 1) +% FIX: alpha1 and beta1 do not exist. They should be empty, but give an error in all_alpha + alpha0 = [1 1]; + alpha1 = [0 0]; + beta0 = [0 0]; + beta1 = [0 0]; + return + end + %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); @@ -934,9 +793,58 @@ end -%TO DO: -%- case of boundary edges +% Functions to deal with general orientation of the patches +function geo_reoriented = reorientation_patches (operations, geometry) + nrb_patches = [geometry.nurbs]; + for ii = 1:numel(nrb_patches) + if (operations(ii,1)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); + end + if (operations(ii,2)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 2); + end + if (operations(ii,3)) + nrb_patches(ii) = nrbtransp (nrb_patches(ii)); + end + end + + [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); +% FIX: this check can be removed once everything is working + if (numel (nrb_patches) == 2) + if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) + error('The reorientation is wrong') + end + end +end + +function knots = knot_vector_reorientation (knots, operations) + if (operations(1)) + knots{1} = sort (1 - knots{1}); + end + if (operations(2)) + knots{2} = sort (1-knots{2}); + end + if (operations(3)) + knots([2 1]) = knots([1 2]); + end +end + +function degree = degree_reorientation (degree, transposition) + if (transposition) + degree = degree([2 1]); + end +end -%TO BE TESTED -%- plots of the functions -%- continuity +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end From 8263d3cbd00876c86edffdf00ab490d05dafbfb8 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 19 May 2021 18:55:24 +0200 Subject: [PATCH 101/366] It seems to work with any orientation (uniform knot vectors) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 533 +++++++++++------- 1 file changed, 326 insertions(+), 207 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d4580166..7eb4962c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -190,6 +190,8 @@ sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions +%%% FIX : only for one interior vertex +% sp.ndof_vertices = ndof_per_vertex(1); % Total number of vertex functions sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; % Computation of the coefficients for basis change @@ -215,8 +217,13 @@ % Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point % The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) + for ivrt = 1:numel(vertices) +% %%% FIX : only for one interior vertex +% if (vertices(ivrt).boundary_vertex) +% continue +% end global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); +% global_indices = sp.ndof_interior + sp.ndof_edges + (1:ndof_per_vertex(ivrt)); for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; end @@ -429,25 +436,6 @@ end -% Computation of CC_vertices -% Compute for each patch all the derivatives we possibly need to compute t,d, and sigma -% FIX: this would be done inside the vertex loop, after reorientation -brk = cell (1,msh.ndim); -for iptc = 1:space.npatch - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1} = [0 1]'; - pts{2} = [0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); - msh_der = msh_precompute (msh_pts_der1); - derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} -end - - %We assume that the local numbering of interfaces and patches is such that %vertices(kver).interface(im) is the interface between %vertices(kver).patches(im) and vertices(kver).patches(im+1) @@ -465,207 +453,338 @@ valence_e = vertices(kver).valence_e; valence_p = vertices(kver).valence_p; operations = vertices(kver).patch_reorientation; + edge_orientation = vertices(kver).edge_orientation; geo_local = reorientation_patches (operations, geometry(patches)); -% ver_patches = []; %FIX: remove -% for iedge = 1:valence_e %cycle over all the interfaces containing the vertex -% inter = vertices(kver).edges(iedge); %global index of the interface -% patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface -% patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface -% % vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch -% % vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch -% vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation -% ver_patches = [ver_patches patch_ind1 patch_ind2]; -% ver_ind = [ver_ind vertex_ind1 vertex_ind2]; -% %compute t(0) and t'(0), d(0) and d'(0) -% -% % These must be computed here -% Du_F00 = derivatives1{patch_ind1}(:,1,1); -% Dv_F00 = derivatives1{patch_ind1}(:,2,1); -% Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); -% end -% end -end - -for kver = 1:numel(vertices) - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches = []; %vector with indices of patches containing the vertex - ver_patches_nabla = {}; %cell array containing jacobians - ver_ind = []; %vector containing local index of vertex in the patch - valence_e = vertices(kver).valence_e; - valence_p = vertices(kver).valence_p; - patches = vertices(kver).patches; - - if (~vertices(kver).boundary_vertex) +% Precompute the derivatives and compute sigma + sigma = 0; + for iptc = 1:valence_p + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; + end + msh_pts_der1 = msh_cartesian (brk, {0 0}, [], geo_local(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives_new1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives_new2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} -% 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) - for iedge = 1:valence_e %cycle over all the interfaces containing the vertex - inter = vertices(kver).edges(iedge); %global index of the interface - patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface - patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface -% vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch -% vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch - vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation - ver_patches = [ver_patches patch_ind1 patch_ind2]; - ver_ind = [ver_ind vertex_ind1 vertex_ind2]; - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00 = derivatives1{patch_ind1}(:,1,1); - Dv_F00 = derivatives1{patch_ind1}(:,2,1); - Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); - Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); - end - %Store the jacobian of F for the left patch - ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; - - t0(iedge,:) = Dv_F00; - t0p(iedge,:) = Dvv_F00; - d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... - (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); - d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... - (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... - (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... - (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(2*iedge-1,:) = Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00 = derivatives1{patch_ind2}(:,1,1); - Dv_F00 = derivatives1{patch_ind2}(:,2,1); - Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); - end - ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; - mix_der2(2*iedge,:) = Duv_F00; - - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if (vertices(kver).edge_orientation(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface - E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); -% else %the vertex is the right/top endpoint of im-th interface -% E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); -% E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end + sigma = sigma + norm (derivatives_new1{iptc},2); % FIX: choose which norm + end + sigma = pp*(kk+1)*valence_p/sigma; + + for ipatch = 1:valence_p + prev_edge = ipatch; + next_edge = mod(ipatch, valence_e) + 1; + +% Compute gluing data, and edge functions from CC_edges_discarded + if (edge_orientation(prev_edge) == 1) + alpha_prev = all_alpha0(edges(prev_edge),2); + beta_prev = all_beta0(edges(prev_edge),2); + alpha_der_prev = -all_alpha0(edges(prev_edge),2) + all_alpha1(edges(prev_edge),2); + beta_der_prev = -all_beta0(edges(prev_edge),2) + all_beta1(edges(prev_edge),2); + E_prev = CC_edges_discarded{2,edges(prev_edge)}(:,[1 2 3 7 8]); + else + alpha_prev = all_alpha1(edges(prev_edge),1); + beta_prev = -all_beta1(edges(prev_edge),1); + alpha_der_prev = all_alpha0(edges(prev_edge),1) - all_alpha1(edges(prev_edge),1); + beta_der_prev = -all_beta0(edges(prev_edge),1) + all_beta1(edges(prev_edge),1); + E_prev = CC_edges_discarded{1,edges(prev_edge)}(:,[6 5 4 10 9]); + E_prev(:,[4 5]) = -E_prev(:,[4 5]); + end + if (edge_orientation(next_edge) == 1) + alpha_next = all_alpha0(edges(next_edge),1); + beta_next = all_beta0(edges(next_edge),1); + alpha_der_next = -all_alpha0(edges(next_edge),1) + all_alpha1(edges(next_edge),1); + beta_der_next = -all_beta0(edges(next_edge),1) + all_beta1(edges(next_edge),1); + E_next = CC_edges_discarded{1,edges(next_edge)}(:,[1 2 3 7 8]); + else + alpha_next = all_alpha1(edges(next_edge),2); + beta_next = -all_beta1(edges(next_edge),2); + alpha_der_next = all_alpha0(edges(next_edge),2) - all_alpha1(edges(next_edge),2); + beta_der_next = -all_beta0(edges(next_edge),2) + all_beta1(edges(next_edge),2); + E_next = CC_edges_discarded{2,edges(next_edge)}(:,[6 5 4 10 9]); + E_next(:,[4 5]) = -E_next(:,[4 5]); end - [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); - mix_der2_n = mix_der2(ind_patch_sigma,:); - %ver_ind=unique(ver_ind,'rows','stable'); - %ind_patch_sigma contains the positions of the elements of ver_patches - %originally (each of them is present twice, the first one is considered) + Du_F = derivatives_new1{ipatch}(:,1); + Dv_F = derivatives_new1{ipatch}(:,2); + Duu_F = derivatives_new2{ipatch}(:,1,1); + Duv_F = derivatives_new2{ipatch}(:,1,2); + Dvv_F = derivatives_new2{ipatch}(:,2,2); - %if the number of patches coincides with the number of interfaces, - %we add one fictional interface coinciding with the first one - %(just for coding-numbering reasons) -% if numel(ver_patches)==ninterfaces_ver -% t0(ninterfaces_ver+1,:)=t0(1,:); -% t0p(ninterfaces_ver+1,:)=t0p(1,:); -% d0(ninterfaces_ver+1,:)=d0(1,:); -% d0p(ninterfaces_ver+1,:)=d0p(1,:); -% E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; -% E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; -% end +% Edge information + t0_prev = Du_F; + t0_next = Dv_F; + t0p_prev = Duu_F; + t0p_next = Dvv_F; + + d0_prev = -(Dv_F + beta_prev * Du_F) / alpha_prev; + d0_next = (Du_F + beta_next * Dv_F) / alpha_next; + d0p_prev = ( alpha_der_prev * (Dv_F + beta_prev*Du_F) - ... + alpha_prev * (Duv_F + beta_der_prev*Du_F + beta_prev*Duu_F)) / alpha_prev^2; + d0p_next = (-alpha_der_next * (Du_F + beta_next*Dv_F) + ... + alpha_next * (Duv_F + beta_der_next*Dv_F + beta_next*Dvv_F)) / alpha_next^2; + +% Compute M and V matrices + ndof = space.sp_patch{patches(ipatch)}.ndof; + M_prev = sparse (5,6); M_next = sparse (5,6); + VV = sparse (ndof,6); - %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices - sigma = 0; - for im = 1:valence_p % FIX: is this the number of interfaces? - sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); - end - sigma = 1/(sigma/(pp*(kk+1)*valence_p)); - %computing matrices MM and V - for ipatch = 1:valence_p %FIX: cycle over the patches containing the vertex - - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1 = space.sp_patch{patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2 = space.sp_patch{patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) -% V{kver}{im} = zeros(n1*n2,6); - MM1 = zeros(5,6); MM2 = zeros(5,6); - VV = zeros(n1*n2,6); - im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) - if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order - im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 - end - iedge1 = im_edges(1); iedge2 = im_edges(2); - - corner_4dofs = [1 2 n2+1 n2+2]; - jfun = 1; - for j1 = 0:2 - for j2 = 0:2-j1 %the following computations work in the standard case - mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; - vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; - d00 = (j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a = vec_deltas*t0(iedge1,:)'; - d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; - d01_a = vec_deltas*d0(iedge1,:)'; - d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; - - %M_{i_{m+1},i} - d10_b = vec_deltas*t0(iedge2,:)'; - d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; - d01_b = vec_deltas*d0(iedge2,:)'; - d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; - if (reg < pp-2) - MM1(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; - else - MM1(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; - end - %V_{i_m,i} - d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; - VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+d10_b/(pp*(kk+1)), ... - d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; - jfun = jfun+1; + ndof_dir = space.sp_patch{patches(ipatch)}.ndof_dir; + all_indices = indices_reorientation (ndof_dir, operations(ipatch,:)); + corner_4dofs = all_indices(1:2,1:2); + jfun = 1; + for j1 = 0:2 + for j2 = 0:2-j1 + mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; + vec_deltas = [(j1==1)*(j2==0); (j1==0)*(j2==1)]; + d00 = (j1==0)*(j2==0); + %M_{i_{m-1},i} + d10_a = vec_deltas.'*t0_prev; + d20_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; + d01_a = vec_deltas.'*d0_prev; + d11_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; + + %M_{i_{m+1},i} + d10_b = vec_deltas.'*t0_next; + d20_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; + d01_b = vec_deltas.'*d0_next; + d11_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; + if (reg < pp-2) + M_prev(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(pp*(kk+1)), ... + d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; + else + M_prev(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... + d01_a/(pp*(kk+1)), ... + d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_b/(pp*(kk+1)), ... + d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... + d01_b/(pp*(kk+1)), ... + d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; end + %V_{i_m,i} + d11_c = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; + VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... + d00+d10_a/(pp*(kk+1)), ... + d00+d10_b/(pp*(kk+1)), ... + d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; + jfun = jfun+1; end - % Check which patch of the edge function we are considering - if (interfaces_all(vertices(kver).edges(iedge1)).patch2 == patches(ipatch))%the considered patch is the second patch edge iedge1 - E1 = E{kver}{iedge1,2}; - else - E1 = E{kver}{iedge1,1}; - end - if (interfaces_all(vertices(kver).edges(iedge2)).patch2 == patches(ipatch))%the considered patch is the second patch of edge iedge2 - E2 = E{kver}{iedge2,2}; - else - E2 = E{kver}{iedge2,1}; - end -% % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); -% % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); -% CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; - CC_vertices{patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; -% % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; - %csi2=[1 9 17 25 33 41 49 57]; - %csi1=1:8; -% M1aux{ipatch} = E1 * MM1; -% M2aux{ipatch} = E2 * MM2; -% Vaux{ipatch} = VV; end + + CC_vertices{patches(ipatch),kver} = E_prev*M_prev + E_next*M_next - VV; end end + +% % Computation of CC_vertices +% % Compute for each patch all the derivatives we possibly need to compute t,d, and sigma +% % FIX: this would be done inside the vertex loop, after reorientation +% brk = cell (1,msh.ndim); +% for iptc = 1:space.npatch +% knots = space.sp_patch{iptc}.knots; +% for idim = 1:msh.ndim +% brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? +% end +% %the following points correspond to the four vertices of the patch +% pts{1} = [0 1]'; +% pts{2} = [0 1]';%pts{2}=[0 1/2 1]' +% msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); +% msh_der = msh_precompute (msh_pts_der1); +% derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) +% derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} +% end +% +% for kver = 1:numel(vertices) +% %Everything must be updated by using interfaces_all instead of interfaces TO DO +% ver_patches = []; %vector with indices of patches containing the vertex +% ver_patches_nabla = {}; %cell array containing jacobians +% ver_ind = []; %vector containing local index of vertex in the patch +% valence_e = vertices(kver).valence_e; +% valence_p = vertices(kver).valence_p; +% patches = vertices(kver).patches; +% +% if (~vertices(kver).boundary_vertex) +% +% % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) +% for iedge = 1:valence_e %cycle over all the interfaces containing the vertex +% inter = vertices(kver).edges(iedge); %global index of the interface +% patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface +% patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface +% % vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch +% % vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch +% vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation +% ver_patches = [ver_patches patch_ind1 patch_ind2]; +% ver_ind = [ver_ind vertex_ind1 vertex_ind2]; +% %compute t(0) and t'(0), d(0) and d'(0) +% switch vertex_ind1 +% case 1 %vertex (0,0) +% Du_F00 = derivatives1{patch_ind1}(:,1,1); +% Dv_F00 = derivatives1{patch_ind1}(:,2,1); +% Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); +% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); +% end +% %Store the jacobian of F for the left patch +% ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; +% +% t0(iedge,:) = Dv_F00; +% t0p(iedge,:) = Dvv_F00; +% d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... +% (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); +% d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... +% (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... +% (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... +% (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... +% (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; +% mix_der2(2*iedge-1,:) = Duv_F00; +% %We need to get the jacobian also for the right patch +% switch vertex_ind2 +% case 1 %vertex (0,0) +% Du_F00 = derivatives1{patch_ind2}(:,1,1); +% Dv_F00 = derivatives1{patch_ind2}(:,2,1); +% Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); +% end +% ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; +% mix_der2(2*iedge,:) = Duv_F00; +% +% %Pick the correct part of CC_edges_discarded %TO BE FIXED +% if (vertices(kver).edge_orientation(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface +% E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex +% E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); +% % else %the vertex is the right/top endpoint of im-th interface +% % E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); +% % E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); +% end +% end +% [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); +% mix_der2_n = mix_der2(ind_patch_sigma,:); +% %ver_ind=unique(ver_ind,'rows','stable'); +% +% %ind_patch_sigma contains the positions of the elements of ver_patches +% %originally (each of them is present twice, the first one is considered) +% +% %if the number of patches coincides with the number of interfaces, +% %we add one fictional interface coinciding with the first one +% %(just for coding-numbering reasons) +% % if numel(ver_patches)==ninterfaces_ver +% % t0(ninterfaces_ver+1,:)=t0(1,:); +% % t0p(ninterfaces_ver+1,:)=t0p(1,:); +% % d0(ninterfaces_ver+1,:)=d0(1,:); +% % d0p(ninterfaces_ver+1,:)=d0p(1,:); +% % E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; +% % E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; +% % end +% +% %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices +% sigma = 0; +% for im = 1:valence_p % FIX: is this the number of interfaces? +% sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); +% end +% sigma = 1/(sigma/(pp*(kk+1)*valence_p)); +% %computing matrices MM and V +% for ipatch = 1:valence_p %FIX: cycle over the patches containing the vertex +% +% %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) +% n1 = space.sp_patch{patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) +% n2 = space.sp_patch{patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) +% % V{kver}{im} = zeros(n1*n2,6); +% MM1 = zeros(5,6); MM2 = zeros(5,6); +% VV = zeros(n1*n2,6); +% im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) +% if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order +% im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 +% end +% iedge1 = im_edges(1); iedge2 = im_edges(2); +% +% corner_4dofs = [1 2 n2+1 n2+2]; +% jfun = 1; +% for j1 = 0:2 +% for j2 = 0:2-j1 %the following computations work in the standard case +% mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; +% vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; +% d00 = (j1==0)*(j2==0); +% %M_{i_{m-1},i} +% d10_a = vec_deltas*t0(iedge1,:)'; +% d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; +% d01_a = vec_deltas*d0(iedge1,:)'; +% d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; +% +% %M_{i_{m+1},i} +% d10_b = vec_deltas*t0(iedge2,:)'; +% d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; +% d01_b = vec_deltas*d0(iedge2,:)'; +% d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; +% if (reg < pp-2) +% MM1(:,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_a/(pp*(kk+1)), ... +% d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... +% d01_a/(pp*(kk+1)), ... +% d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; +% MM2(:,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_b/(pp*(kk+1)), ... +% d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... +% d01_b/(pp*(kk+1)), ... +% d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; +% else +% MM1(:,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_a/(pp*(kk+1)), ... +% d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... +% d01_a/(pp*(kk+1)), ... +% d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; +% MM2(:,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_b/(pp*(kk+1)), ... +% d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... +% d01_b/(pp*(kk+1)), ... +% d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; +% end +% %V_{i_m,i} +% d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; +% VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... +% d00+d10_a/(pp*(kk+1)), ... +% d00+d10_b/(pp*(kk+1)), ... +% d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; +% jfun = jfun+1; +% end +% end +% % Check which patch of the edge function we are considering +% if (interfaces_all(vertices(kver).edges(iedge1)).patch2 == patches(ipatch))%the considered patch is the second patch edge iedge1 +% E1 = E{kver}{iedge1,2}; +% else +% E1 = E{kver}{iedge1,1}; +% end +% if (interfaces_all(vertices(kver).edges(iedge2)).patch2 == patches(ipatch))%the considered patch is the second patch of edge iedge2 +% E2 = E{kver}{iedge2,2}; +% else +% E2 = E{kver}{iedge2,1}; +% end +% % % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); +% % % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); +% % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; +% CC_vertices{patches(ipatch),1} = E1*MM1 + E2*MM2 - VV; +% % % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; +% %csi2=[1 9 17 25 33 41 49 57]; +% %csi1=1:8; +% % M1aux{ipatch} = E1 * MM1; +% % M2aux{ipatch} = E2 * MM2; +% % Vaux{ipatch} = VV; +% end +% end +% +% end + end function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) @@ -673,7 +792,7 @@ if (numel (geo_map_jac) == 1) % FIX: alpha1 and beta1 do not exist. They should be empty, but give an error in all_alpha alpha0 = [1 1]; - alpha1 = [0 0]; + alpha1 = [1 1]; beta0 = [0 0]; beta1 = [0 0]; return From c40ed5d3baa6c9d8879ed1ee1b860adf416077bb Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 16:09:23 +0200 Subject: [PATCH 102/366] Some cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 285 ++---------------- 1 file changed, 24 insertions(+), 261 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 7eb4962c..14545781 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -44,7 +44,8 @@ % sp_get_cells: compute the cells on which a list of functions do not vanish % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015-2021 Rafael Vazquez +% Copyright (C) 2019-2021 Cesare Bracco % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -74,12 +75,8 @@ if (msh.ndim ~= 2 || msh.rdim ~= 2) error ('Only implemented for planar surfaces') end - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end + for iptc = 1:numel(geometry) knots = spaces{iptc}.knots; breaks = cellfun (@unique, knots, 'UniformOutput', false); mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); @@ -92,7 +89,6 @@ end end end - sp.ncomp = spaces{1}.ncomp; sp.transform = spaces{1}.transform; @@ -113,11 +109,7 @@ sp.ndof_per_patch = [aux.ndof]; sp.sp_patch = spaces; -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - +% Knot vectors of auxiliary spaces knots0 = cell (sp.npatch, 1); knots1 = knots0; for iptc = 1:sp.npatch knots = spaces{iptc}.knots; @@ -141,16 +133,8 @@ % Compute the local indices of the functions in V^1 % and sum them up to get the whole space V^1 -% if (numel (interfaces) > 1 || msh.npatch > 2) -% error ('For now, the implementation only works for two patches') -% end -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface sp.ndof_interior = 0; [interfaces_all, vertices] = vertices_struct_rafa (boundaries, interfaces, geometry, boundary_interfaces); @@ -186,12 +170,10 @@ % [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); -%keyboard - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions -%%% FIX : only for one interior vertex -% sp.ndof_vertices = ndof_per_vertex(1); % Total number of vertex functions + +% Total number of functions, and of functions of each type + sp.ndof_edges = sum(ndof_per_interface); + sp.ndof_vertices = sum (ndof_per_vertex); sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; % Computation of the coefficients for basis change @@ -215,31 +197,17 @@ end end -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface for ivrt = 1:numel(vertices) -% %%% FIX : only for one interior vertex -% if (vertices(ivrt).boundary_vertex) -% continue -% end global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); -% global_indices = sp.ndof_interior + sp.ndof_edges + (1:ndof_per_vertex(ivrt)); for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; end end -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE sp.interfaces = interfaces; sp.Cpatch = Cpatch; sp.geometry = geometry; % I store this for simplicity - %keyboard -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); function spaux = patches_constructor (spaces, MSH) for ipatch = 1:MSH.npatch @@ -247,8 +215,7 @@ end end - sp = class (sp, 'sp_multipatch_C1'); - + sp = class (sp, 'sp_multipatch_C1'); end @@ -274,7 +241,6 @@ mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); reg = pp - max(mult(2:end-1)); - all_alpha0 = zeros(numel(interfaces_all),2); all_alpha1 = zeros(numel(interfaces_all),2); all_beta0 = zeros(numel(interfaces_all),2); @@ -309,8 +275,7 @@ [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); clear geo_map_jac msh_grev msh_side_interior grev_pts - %Saving alphas and betas (first column=R, second column=L) - % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION + %Saving alphas and betas (first column=i_0, second column=i_1) all_alpha0(iref,:) = alpha0; all_alpha1(iref,:) = alpha1; all_beta0(iref,:) = beta0; @@ -326,13 +291,13 @@ brk = cell (1,msh.ndim); grev_pts = cell (1, msh.ndim); degrees = degree_reorientation (space.sp_patch{patches(ii)}.degree, operations(ii,3)); - degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); + degree = degrees(ind1); knots = knot_vector_reorientation (space.sp_patch{patches(ii)}.knots, operations(ii,:)); knots0 = knot_vector_reorientation (space.knots0_patches{patches(ii)}, operations(ii,:)); - knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; + knots0 = knots0{ind1}; knots1 = knot_vector_reorientation (space.knots1_patches{patches(ii)}, operations(ii,:)); - knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; + knots1 = knots1{ind1}; for idim = 1:msh.ndim grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); grev_pts{idim} = grev_pts{idim}(:)'; @@ -341,7 +306,7 @@ msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); % Degree and first length in the direction normal to the interface - degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); + degu = degrees(ind2); knt = unique (knots{ind2}); tau1 = knt(2) - knt(1); @@ -360,7 +325,7 @@ spn = sp_bspline (knotsn, degree, msh_grev.boundary(sides(ii))); spn_struct = sp_precompute_param (spn, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); -% Matrix for the linear systems, (14)-(16) in Mario's notes +% Matrix for the linear systems A = sparse (msh_side.nel, msh_side.nel); for jj = 1:msh_side.nel A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); @@ -394,9 +359,9 @@ coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse rhsc = sparse (msh_side.nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) + val = val_grad* (tau1 / degu); for jj = 1:msh_side.nel - val_aux = val * alpha(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; + val_aux = val * alpha(jj)* (-1)^(ii+1); rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; end coeff2 = A \ rhsc; @@ -445,9 +410,6 @@ sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) for kver = 1:numel(vertices) -% if (vertices(kver).boundary_vertex) -% continue -% end edges = vertices(kver).edges; patches = vertices(kver).patches; valence_e = vertices(kver).valence_e; @@ -583,208 +545,10 @@ jfun = jfun+1; end end - CC_vertices{patches(ipatch),kver} = E_prev*M_prev + E_next*M_next - VV; end - end - -% % Computation of CC_vertices -% % Compute for each patch all the derivatives we possibly need to compute t,d, and sigma -% % FIX: this would be done inside the vertex loop, after reorientation -% brk = cell (1,msh.ndim); -% for iptc = 1:space.npatch -% knots = space.sp_patch{iptc}.knots; -% for idim = 1:msh.ndim -% brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? -% end -% %the following points correspond to the four vertices of the patch -% pts{1} = [0 1]'; -% pts{2} = [0 1]';%pts{2}=[0 1/2 1]' -% msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); -% msh_der = msh_precompute (msh_pts_der1); -% derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) -% derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} -% end -% -% for kver = 1:numel(vertices) -% %Everything must be updated by using interfaces_all instead of interfaces TO DO -% ver_patches = []; %vector with indices of patches containing the vertex -% ver_patches_nabla = {}; %cell array containing jacobians -% ver_ind = []; %vector containing local index of vertex in the patch -% valence_e = vertices(kver).valence_e; -% valence_p = vertices(kver).valence_p; -% patches = vertices(kver).patches; -% -% if (~vertices(kver).boundary_vertex) -% -% % 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) -% for iedge = 1:valence_e %cycle over all the interfaces containing the vertex -% inter = vertices(kver).edges(iedge); %global index of the interface -% patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface -% patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface -% % vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch -% % vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch -% vertex_ind1 = 1; vertex_ind2 = 1; % FIX: This must depend on the orientation -% ver_patches = [ver_patches patch_ind1 patch_ind2]; -% ver_ind = [ver_ind vertex_ind1 vertex_ind2]; -% %compute t(0) and t'(0), d(0) and d'(0) -% switch vertex_ind1 -% case 1 %vertex (0,0) -% Du_F00 = derivatives1{patch_ind1}(:,1,1); -% Dv_F00 = derivatives1{patch_ind1}(:,2,1); -% Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); -% Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); -% end -% %Store the jacobian of F for the left patch -% ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; -% -% t0(iedge,:) = Dv_F00; -% t0p(iedge,:) = Dvv_F00; -% d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... -% (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); -% d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... -% (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... -% (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... -% (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... -% (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; -% mix_der2(2*iedge-1,:) = Duv_F00; -% %We need to get the jacobian also for the right patch -% switch vertex_ind2 -% case 1 %vertex (0,0) -% Du_F00 = derivatives1{patch_ind2}(:,1,1); -% Dv_F00 = derivatives1{patch_ind2}(:,2,1); -% Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); -% end -% ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; -% mix_der2(2*iedge,:) = Duv_F00; -% -% %Pick the correct part of CC_edges_discarded %TO BE FIXED -% if (vertices(kver).edge_orientation(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface -% E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex -% E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); -% % else %the vertex is the right/top endpoint of im-th interface -% % E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); -% % E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); -% end -% end -% [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); -% mix_der2_n = mix_der2(ind_patch_sigma,:); -% %ver_ind=unique(ver_ind,'rows','stable'); -% -% %ind_patch_sigma contains the positions of the elements of ver_patches -% %originally (each of them is present twice, the first one is considered) -% -% %if the number of patches coincides with the number of interfaces, -% %we add one fictional interface coinciding with the first one -% %(just for coding-numbering reasons) -% % if numel(ver_patches)==ninterfaces_ver -% % t0(ninterfaces_ver+1,:)=t0(1,:); -% % t0p(ninterfaces_ver+1,:)=t0p(1,:); -% % d0(ninterfaces_ver+1,:)=d0(1,:); -% % d0p(ninterfaces_ver+1,:)=d0p(1,:); -% % E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; -% % E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; -% % end -% -% %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices -% sigma = 0; -% for im = 1:valence_p % FIX: is this the number of interfaces? -% sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); -% end -% sigma = 1/(sigma/(pp*(kk+1)*valence_p)); -% %computing matrices MM and V -% for ipatch = 1:valence_p %FIX: cycle over the patches containing the vertex -% -% %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) -% n1 = space.sp_patch{patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) -% n2 = space.sp_patch{patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) -% % V{kver}{im} = zeros(n1*n2,6); -% MM1 = zeros(5,6); MM2 = zeros(5,6); -% VV = zeros(n1*n2,6); -% im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) -% if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order -% im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 -% end -% iedge1 = im_edges(1); iedge2 = im_edges(2); -% -% corner_4dofs = [1 2 n2+1 n2+2]; -% jfun = 1; -% for j1 = 0:2 -% for j2 = 0:2-j1 %the following computations work in the standard case -% mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; -% vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; -% d00 = (j1==0)*(j2==0); -% %M_{i_{m-1},i} -% d10_a = vec_deltas*t0(iedge1,:)'; -% d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; -% d01_a = vec_deltas*d0(iedge1,:)'; -% d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; -% -% %M_{i_{m+1},i} -% d10_b = vec_deltas*t0(iedge2,:)'; -% d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; -% d01_b = vec_deltas*d0(iedge2,:)'; -% d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; -% if (reg < pp-2) -% MM1(:,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_a/(pp*(kk+1)), ... -% d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... -% d01_a/(pp*(kk+1)), ... -% d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; -% MM2(:,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_b/(pp*(kk+1)), ... -% d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... -% d01_b/(pp*(kk+1)), ... -% d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; -% else -% MM1(:,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_a/(pp*(kk+1)), ... -% d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... -% d01_a/(pp*(kk+1)), ... -% d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; -% MM2(:,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_b/(pp*(kk+1)), ... -% d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... -% d01_b/(pp*(kk+1)), ... -% d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; -% end -% %V_{i_m,i} -% d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; -% VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... -% d00+d10_a/(pp*(kk+1)), ... -% d00+d10_b/(pp*(kk+1)), ... -% d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; -% jfun = jfun+1; -% end -% end -% % Check which patch of the edge function we are considering -% if (interfaces_all(vertices(kver).edges(iedge1)).patch2 == patches(ipatch))%the considered patch is the second patch edge iedge1 -% E1 = E{kver}{iedge1,2}; -% else -% E1 = E{kver}{iedge1,1}; -% end -% if (interfaces_all(vertices(kver).edges(iedge2)).patch2 == patches(ipatch))%the considered patch is the second patch of edge iedge2 -% E2 = E{kver}{iedge2,2}; -% else -% E2 = E{kver}{iedge2,1}; -% end -% % % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); -% % % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); -% % CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; -% CC_vertices{patches(ipatch),1} = E1*MM1 + E2*MM2 - VV; -% % % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; -% %csi2=[1 9 17 25 33 41 49 57]; -% %csi1=1:8; -% % M1aux{ipatch} = E1 * MM1; -% % M2aux{ipatch} = E2 * MM2; -% % Vaux{ipatch} = VV; -% end -% end -% -% end - end function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) @@ -838,7 +602,6 @@ beta2_n = sols(5); end - %keyboard %STEP 4 - Normalizing the alphas %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... % +alpha0_n(1)^2+alpha0_n(2)^2; @@ -927,13 +690,13 @@ end end - [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); -% FIX: this check can be removed once everything is working - if (numel (nrb_patches) == 2) - if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) - error('The reorientation is wrong') - end - end + geo_reoriented = mp_geo_load (nrb_patches); +% [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); +% if (numel (nrb_patches) == 2) +% if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) +% error('The reorientation is wrong') +% end +% end end function knots = knot_vector_reorientation (knots, operations) From 873adc5ed6005f111b9f22b21647bcd362dade00 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 17:55:02 +0200 Subject: [PATCH 103/366] Some more cleaning and help --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 90 +++++++++---------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 14545781..f79a87fc 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -1,33 +1,35 @@ % SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity % -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) +% sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries, boundary_interfaces) % % INPUTS: % -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) +% spaces: cell-array of space objects, one for each patch (see sp_scalar) % msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% geometry: geometry struct (see mp_geo_load) % interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% boundaries: information about the boundary of the domain (see mp_geo_load) +% boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) % % OUTPUT: % % sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: % -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% ndof_interior (scalar) total number of interior degrees of freedom +% ndof_edges (scalar) total number of edge degrees of freedom +% ndof_vertices (scalar) total number of vertex degrees of freedom +% interior_dofs_per_patch (1 x npatch cell-array) local number of interior functions on each patch +% dofs_on_edge (1 x nedges cell-array) global numbering of edge functions on each edge +% dofs_on_vertex (1 x nvertices cell-array) global numbering of the six functions on each vertex +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar) +% Cpatch (1 x npatch cell-array) coefficients of the linear combination of basis functions as standard B-splines, +% on each patch. The matrix Cpatch{iptc} has size ndof_per_patch(iptc) x ndof +% constructor function handle function handle to construct the same discrete space in a different msh % % METHODS % Methods that give a structure with all the functions computed in a certain subset of the mesh @@ -133,9 +135,6 @@ % Compute the local indices of the functions in V^1 % and sum them up to get the whole space V^1 - - - sp.ndof_interior = 0; [interfaces_all, vertices] = vertices_struct_rafa (boundaries, interfaces, geometry, boundary_interfaces); for iptc = 1:sp.npatch @@ -152,34 +151,19 @@ sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); end + +% Compute coefficients to express the basis functions as combinations of B-splines +% See the function compute_coefficients below for details. -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); % Total number of functions, and of functions of each type - sp.ndof_edges = sum(ndof_per_interface); + sp.ndof_edges = sum (ndof_per_interface); sp.ndof_vertices = sum (ndof_per_vertex); sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - + +% Store the coefficients for matrix change in Cpatch Cpatch = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); for iptc = 1:sp.npatch @@ -189,24 +173,31 @@ speye (numel (sp.interior_dofs_per_patch{iptc})); end + sp.dofs_on_edge = cell (1, numel(interfaces_all)); for intrfc = 1:numel(interfaces_all) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + sp.dofs_on_edge{intrfc} = global_indices; patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; for iptc = 1:numel(patches) Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; end end + sp.dofs_on_vertex = cell (1, numel(vertices)); for ivrt = 1:numel(vertices) global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + sp.dofs_on_vertex{ivrt} = global_indices; for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; end end - sp.interfaces = interfaces; sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity + +% I store this for simplicity + sp.interfaces = interfaces_all; + sp.vertices = vertices; + sp.geometry = geometry; sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); function spaux = patches_constructor (spaces, MSH) @@ -220,6 +211,16 @@ function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) +% OUTPUT from compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices). Even if the value is always six. +% CC_vertices: cell array of size npatch x numel(vertices) +% The matrix CC_vertices{ii,jj} has size sp.ndof_per_patch(patch) x ndof_per_vertex{jj} +% with patch being the index of the ii-th patch containing vertex jj; %Initialize output variables with correct size ndof_per_interface = zeros (1, numel(interfaces_all)); @@ -236,7 +237,6 @@ pp = space.sp_patch{1}.degree(1); kk = numel(msh.msh_patch{1}.breaks{1})-2; -% nn = space.sp_patch{1}.sp_univ(1).ndof; breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); reg = pp - max(mult(2:end-1)); From fe48fcdebcad9584669e32a7ef1b84480bda07ef Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 17:58:51 +0200 Subject: [PATCH 104/366] Renamed my function as old Cesare's one --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 18 +- .../@sp_multipatch_C1/vertices_struct.m | 108 ------- geopdes/inst/multipatch/vertices_struct.m | 296 ++++++++++++++---- .../inst/multipatch/vertices_struct_rafa.m | 259 --------------- 4 files changed, 239 insertions(+), 442 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m delete mode 100644 geopdes/inst/multipatch/vertices_struct_rafa.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f79a87fc..e77d0e4c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -127,16 +127,11 @@ sp.knots0_patches = knots0; sp.knots1_patches = knots1; -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 - +% Computation of the number of degrees of freedom, and the coefficients to +% express them as linear combinations of B-splines. +% See the function compute_coefficients below for details. sp.ndof_interior = 0; - [interfaces_all, vertices] = vertices_struct_rafa (boundaries, interfaces, geometry, boundary_interfaces); + [interfaces_all, vertices] = vertices_struct (boundaries, interfaces, geometry, boundary_interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) @@ -148,12 +143,9 @@ interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); end end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices + sp.interior_dofs_per_patch{iptc} = interior_dofs; sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); end - -% Compute coefficients to express the basis functions as combinations of B-splines -% See the function compute_coefficients below for details. [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m b/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m deleted file mode 100644 index fa731bb7..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/vertices_struct.m +++ /dev/null @@ -1,108 +0,0 @@ -function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) - -%INPUT: boundaries and (interior) interfaces as given by mp_geo_load -%OUTPUT: structures containing 1) for each interface (included boundaries) indices of the adjacent patches -%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces -%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) - -N_int=numel(interfaces_i); -interfaces=interfaces_i; -for h=1:numel(boundaries) - interfaces(N_int+h).patch1=boundaries(h).patches; - interfaces(N_int+h).patch2=[]; - interfaces(N_int+h).side1=boundaries(h).faces; - interfaces(N_int+h).side2=[]; - interfaces(N_int+h).ornt=[]; -end - -%initialize vertices -ivertices=[]; - -nv=0; -for i=1:numel(interfaces) - patches_i=[interfaces(i).patch1 interfaces(i).patch2]; - sides_i=[interfaces(i).side1 interfaces(i).side2]; - for j=i+1:numel(interfaces) - patches_j=[interfaces(j).patch1 interfaces(j).patch2]; - sides_j=[interfaces(j).side1 interfaces(j).side2]; - [cpatch,cpatch_indi,cpatch_indj] = intersect(patches_i,patches_j); - cside_i=sides_i(cpatch_indi); - cside_j=sides_j(cpatch_indj); - if numel(cpatch)>0 %if vertex found - switch cside_i - case 1 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 2 - if cside_j==3 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==4 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - case 3 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 1]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 1]; - end - case 4 - if cside_j==1 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[1 2]; - elseif cside_j==2 - nv=nv+1; %increase number of vertices - ivertices(nv).interfaces=[i j]; - ivertices(nv).ind=[2 2]; - end - end - end - end -end - -%vertices=ivertices; - -vertices(1)=ivertices(1); -nv=1; - -for i=2:numel(ivertices) -inter_i=ivertices(i).interfaces; -ind_i=ivertices(i).ind; -info_i=[inter_i' ind_i']; - flag_new=1; - for j=1:numel(vertices) - inter_j=vertices(j).interfaces; - ind_j=vertices(j).ind; - info_j=[inter_j' ind_j']; - if numel(intersect(info_i,info_j,'rows'))>0 - [vertices(j).interfaces,indu,~]=unique([vertices(j).interfaces ivertices(i).interfaces]); - vertices(j).ind=[vertices(j).ind ivertices(i).ind]; - vertices(j).ind=vertices(j).ind(indu); - flag_new=0; - break - end - end - if flag_new==1 - nv=nv+1; - vertices(nv)=ivertices(i); - end -end - - -end - diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index efaaac3a..2a41ee9e 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -1,87 +1,259 @@ -function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i) - %INPUT: boundaries and interfaces as given by mp_geo_load %OUTPUT: structures containing 1) for each interfaces (included boundaries) indices of the djacent patches %and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces %containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) +function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i, geometry, boundary_interfaces) + +for iptc = 1:numel(geometry) + msh{iptc} = msh_cartesian ({[0 1] [0 1]}, {0.5 0.5}, {1 1}, geometry(iptc), 'der2', false); + space{iptc} = sp_bspline ({[0 0 1 1] [0 0 1 1]}, [1 1], msh{iptc}); + scalar_spaces{1} = sp_bspline ({[0 1] [0 0 1 1]}, [0 1], msh{iptc}); + scalar_spaces{2} = sp_bspline ({[0 0 1 1] [0 1]}, [1 0], msh{iptc}); + sp_curl{iptc} = sp_vector (scalar_spaces, msh{iptc}, 'curl-preserving'); +end +msh = msh_multipatch (msh, boundaries); +space = sp_multipatch (space, msh, interfaces_i, boundary_interfaces); +sp_curl = sp_multipatch (sp_curl, msh, interfaces_i, boundary_interfaces); + N_int = numel (interfaces_i); interfaces = interfaces_i; +interfaces_bnd = interfaces_i; for hh = 1:numel(boundaries) interfaces(N_int+hh).patch1 = boundaries(hh).patches; interfaces(N_int+hh).side1 = boundaries(hh).faces; + interfaces_bnd(N_int+hh).patch1 = boundaries(hh).patches; + interfaces_bnd(N_int+hh).side1 = boundaries(hh).faces; + interfaces_bnd(N_int+hh).patch2 = 0; + interfaces_bnd(N_int+hh).side2 = 0; end -%initialize vertices -ivertices=[]; +% Find the operations for reorientation +for ii = 1:numel(interfaces) + interfaces(ii).operations = reorientation_edge (interfaces(ii), geometry); +end -% Find all vertices as intersection of two edges -nv = 0; +% Correspondence between interfaces and edges of the space +int2sp = zeros (sp_curl.ndof, 1); +side2dof = [3 4 1 2]; dof2side = side2dof; for ii = 1:numel(interfaces) - patches_i = [interfaces(ii).patch1 interfaces(ii).patch2]; - sides_i = [interfaces(ii).side1 interfaces(ii).side2]; - for jj = ii+1:numel(interfaces) - patches_j = [interfaces(jj).patch1 interfaces(jj).patch2]; - sides_j = [interfaces(jj).side1 interfaces(jj).side2]; - [cpatch, cpatch_indi, cpatch_indj] = intersect (patches_i, patches_j); - cside_i = sides_i(cpatch_indi); - cside_j = sides_j(cpatch_indj); + patch1 = interfaces(ii).patch1; + side1 = interfaces(ii).side1; + int2sp(ii) = sp_curl.gnum{patch1}(side2dof(side1)); +end +[~,sp2int] = ismember(1:sp_curl.ndof, int2sp); + +% Incidence matrices +C = sparse (sp_curl.ndof, space.ndof); +C_local = [1 0 1 0; -1 0 0 1; 0 1 -1 0; 0 -1 0 -1].'; +for iptc = 1:space.npatch + C(sp_curl.gnum{iptc},space.gnum{iptc}) = spdiags(sp_curl.dofs_ornt{iptc}(:),0,4,4) * C_local; +end + +vertices = struct('valence_p', [], 'valence_e', [], 'edges', [], 'patches', [], ... + 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); +% Inner and boundary vertex are done in a different way +% For inner vertices, I set the patch with lowest number as the first one +boundary_vertices = space.boundary.dofs(:).'; +for ivert = 1:space.ndof + boundary_vertex = ismember (ivert, boundary_vertices); + sp_edges = find(C(:,ivert)); + edges = sp2int(sp_edges); + patches_aux = [interfaces_bnd(edges).patch1; interfaces_bnd(edges).patch2]; + sides_aux = [interfaces_bnd(edges).side1; interfaces_bnd(edges).side2]; + patches = setdiff (unique (patches_aux(:)).', 0); + position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); + valence = numel (patches); + gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); + gnum_curl = gnum_curl(:,dof2side); + + patch_reorientation = zeros (valence, 3); + for iptc = 1:valence + patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); + end + +% Determine the first edge and patch to reorder the patches and edges + if (boundary_vertex) + [current_edge, current_patch, last_edge] = ... + find_first_edge_and_patch_boundary (edges, patch_reorientation, sp_curl.boundary.dofs, gnum_curl, sp2int); + reordering_edges = zeros (1, valence+1); + reordering_edges(valence+1) = last_edge; + reordering_patches = zeros (1, valence); + else + [current_edge, current_patch] = ... + find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation); + reordering_edges = zeros (1, valence); + reordering_patches = zeros (1, valence); + end + +% Starting from first edge and patch, reorder the other patches and edges +% reordering_edges and reordering_patches are local indices + reordering_patches(1) = current_patch; + reordering_edges(1) = current_edge; + nn = 1; + while (nn < valence) + [~,edges_on_patch] = find (patches_aux == patches(current_patch)); + next_edge = setdiff (edges_on_patch, current_edge); + [patches_on_edge,~] = find (gnum_curl == edges(next_edge)); + next_patch = setdiff (patches_on_edge, current_patch); - if (numel(cpatch) > 0) % possible vertex found - flag = false; - if (cside_i == 1 && cside_j == 3) - inds = [1 1]; flag = true; - elseif (cside_i == 1 && cside_j == 4) - inds = [2 1]; flag = true; - elseif (cside_i == 2 && cside_j==3) - inds = [1 2]; flag = true; - elseif (cside_i == 2 && cside_j==4) - inds = [2 2]; flag = true; - elseif (cside_i == 3 && cside_j == 1) - inds = [1 1]; flag = true; - elseif (cside_i == 3 && cside_j == 2) - inds = [2 1]; flag = true; - elseif (cside_i == 4 && cside_j == 1) - inds = [1 2]; flag = true; - elseif (cside_i == 4 && cside_j==2) - inds = [2 2]; flag = true; + nn = nn + 1; + reordering_edges(nn) = next_edge; + reordering_patches(nn) = next_patch; + current_patch = next_patch; + current_edge = next_edge; + end + edges = edges(reordering_edges); + patches = patches(reordering_patches); + +% Check the orientation of each edge compared to the one in interfaces + if (boundary_vertex) + edge_orientation = 2*([interfaces_bnd(edges).patch2] == [patches 0]) - 1; + else + edge_orientation = 2*([interfaces(edges).patch2] == patches) - 1; + end + + vertices(ivert).valence_p = valence; + vertices(ivert).valence_e = numel(edges); + vertices(ivert).edges = edges; + vertices(ivert).patches = patches; + vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); + vertices(ivert).edge_orientation = edge_orientation; + vertices(ivert).boundary_vertex = boundary_vertex; +end + +end + +function operations = reorientation_edge (interface, geometry) + patches = [interface.patch1 interface.patch2]; + nrb_patches = [geometry(patches).nurbs]; + sides = [interface.side1 interface.side2]; +% Change orientation of first patch + [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(1) == 2) + if (jacdet < 0) + operations(1,:) = [1 0 0]; + else + operations(1,:) = [1 1 0]; + end + elseif (sides(1) == 3) + if (jacdet < 0) + operations(1,:) = [0 0 1]; + else + operations(1,:) = [1 0 1]; + end + elseif (sides(1) == 4) + if (jacdet < 0) + operations(1,:) = [1 1 1]; + else + operations(1,:) = [0 1 1]; + end + elseif (sides(1) == 1) + if (jacdet < 0) + operations(1,:) = [0 1 0]; + else + operations(1,:) = [0 0 0]; + end + end + +% Change orientation of second patch, only for inner edges + if (numel(nrb_patches) == 2) + [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + if (sides(2) == 1) + if (jacdet < 0) + operations(2,:) = [0 0 1]; + else + operations(2,:) = [0 1 1]; + end + elseif (sides(2) == 2) + if (jacdet < 0) + operations(2,:) = [1 1 1]; + else + operations(2,:) = [1 0 1]; + end + elseif (sides(2) == 3) + if (jacdet < 0) + operations(2,:) = [1 0 0]; + else + operations(2,:) = [0 0 0]; end - if (flag) - nv = nv+1; %increase number of vertices - ivertices(nv).interfaces = [ii jj]; - ivertices(nv).ind = inds; + elseif (sides(2) == 4) + if (jacdet < 0) + operations(2,:) = [0 1 0]; + else + operations(2,:) = [1 1 0]; end end end end -%vertices=ivertices; - -% Remove redundant vertices -vertices(1) = ivertices(1); -nvert = 1; - -for ii = 2:numel(ivertices) - inter_i = ivertices(ii).interfaces; - ind_i = ivertices(ii).ind; - info_i = [inter_i' ind_i']; - flag_new = 1; - for jj = 1:numel(vertices) - inter_j = vertices(jj).interfaces; - ind_j = vertices(jj).ind; - info_j = [inter_j' ind_j']; - if (numel(intersect(info_i,info_j,'rows')) > 0) - [vertices(jj).interfaces,indu,~] = unique([vertices(jj).interfaces ivertices(ii).interfaces]); - vertices(jj).ind = [vertices(jj).ind ivertices(ii).ind]; - vertices(jj).ind = vertices(jj).ind(indu); - flag_new = 0; - break - end + +function operations = reorientation_vertex (position, nrb) + + operations = zeros (1,3); + switch position + case 2 + operations(1) = 1; + nrb = nrbreverse (nrb, 1); + case 3 + operations(2) = 1; + nrb = nrbreverse (nrb, 2); + case 4 + operations(1:2) = [1 1]; + nrb = nrbreverse (nrb, [1 2]); + end + [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); + jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + + if (jacdet < 0) + operations(3) = 1; end - if (flag_new) - nvert = nvert + 1; - vertices(nvert) = ivertices(ii); + +end + +% Determine the first edge and patch to reorder the patches and edges +% These two functions use local numbering +function [first_edge, first_patch] = find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation) + first_patch = 1; + reornt = patch_reorientation(1,:); + if (all (reornt == [0 0 0]) || all (reornt == [1 0 0])) + side = 3; + elseif (all (reornt == [0 1 0]) || all (reornt == [1 1 0])) + side = 4; + elseif (all (reornt == [0 0 1]) || all (reornt == [0 1 1])) + side = 1; + else + side = 2; end -end + indices = find (patches_aux == patches(first_patch)); + edge_aux = find (sides_aux(indices) == side); + [~,first_edge] = ind2sub([2,numel(edges)], indices(edge_aux)); end + +function [first_edge, first_patch, last_edge] = ... + find_first_edge_and_patch_boundary (edges, patch_reorientation, curl_bnd_dofs, gnum_curl, sp2int) + [~,~,bnd_edges] = intersect (sp2int(curl_bnd_dofs), edges); + if (numel (bnd_edges) ~=2) + error ('The number of boundary edges near a vertex should be equal to two') + end + for ii = 1:2 + [bnd_patches(ii), bnd_sides(ii)] = find (gnum_curl == edges(bnd_edges(ii))); + end + + reornt = patch_reorientation(bnd_patches(1),:); + if ((bnd_sides(1) == 3 && (all (reornt == [0 0 0]) || all (reornt == [1 0 0]))) ... + || (bnd_sides(1) == 4 && (all (reornt == [0 1 0]) || all (reornt == [1 1 0]))) ... + || (bnd_sides(1) == 1 && (all (reornt == [0 0 1]) || all (reornt == [0 1 1]))) ... + || (bnd_sides(1) == 2 && (all (reornt == [1 0 1]) || all (reornt == [1 1 1])))) + first_edge = bnd_edges(1); + first_patch = bnd_patches(1); + last_edge = bnd_edges(2); + else + first_edge = bnd_edges(2); + first_patch = bnd_patches(end); + last_edge = bnd_edges(1); + end +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/vertices_struct_rafa.m b/geopdes/inst/multipatch/vertices_struct_rafa.m deleted file mode 100644 index 2a41ee9e..00000000 --- a/geopdes/inst/multipatch/vertices_struct_rafa.m +++ /dev/null @@ -1,259 +0,0 @@ -%INPUT: boundaries and interfaces as given by mp_geo_load -%OUTPUT: structures containing 1) for each interfaces (included boundaries) indices of the djacent patches -%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces -%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) - -function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i, geometry, boundary_interfaces) - -for iptc = 1:numel(geometry) - msh{iptc} = msh_cartesian ({[0 1] [0 1]}, {0.5 0.5}, {1 1}, geometry(iptc), 'der2', false); - space{iptc} = sp_bspline ({[0 0 1 1] [0 0 1 1]}, [1 1], msh{iptc}); - scalar_spaces{1} = sp_bspline ({[0 1] [0 0 1 1]}, [0 1], msh{iptc}); - scalar_spaces{2} = sp_bspline ({[0 0 1 1] [0 1]}, [1 0], msh{iptc}); - sp_curl{iptc} = sp_vector (scalar_spaces, msh{iptc}, 'curl-preserving'); -end -msh = msh_multipatch (msh, boundaries); -space = sp_multipatch (space, msh, interfaces_i, boundary_interfaces); -sp_curl = sp_multipatch (sp_curl, msh, interfaces_i, boundary_interfaces); - -N_int = numel (interfaces_i); -interfaces = interfaces_i; -interfaces_bnd = interfaces_i; -for hh = 1:numel(boundaries) - interfaces(N_int+hh).patch1 = boundaries(hh).patches; - interfaces(N_int+hh).side1 = boundaries(hh).faces; - interfaces_bnd(N_int+hh).patch1 = boundaries(hh).patches; - interfaces_bnd(N_int+hh).side1 = boundaries(hh).faces; - interfaces_bnd(N_int+hh).patch2 = 0; - interfaces_bnd(N_int+hh).side2 = 0; -end - -% Find the operations for reorientation -for ii = 1:numel(interfaces) - interfaces(ii).operations = reorientation_edge (interfaces(ii), geometry); -end - -% Correspondence between interfaces and edges of the space -int2sp = zeros (sp_curl.ndof, 1); -side2dof = [3 4 1 2]; dof2side = side2dof; -for ii = 1:numel(interfaces) - patch1 = interfaces(ii).patch1; - side1 = interfaces(ii).side1; - int2sp(ii) = sp_curl.gnum{patch1}(side2dof(side1)); -end -[~,sp2int] = ismember(1:sp_curl.ndof, int2sp); - -% Incidence matrices -C = sparse (sp_curl.ndof, space.ndof); -C_local = [1 0 1 0; -1 0 0 1; 0 1 -1 0; 0 -1 0 -1].'; -for iptc = 1:space.npatch - C(sp_curl.gnum{iptc},space.gnum{iptc}) = spdiags(sp_curl.dofs_ornt{iptc}(:),0,4,4) * C_local; -end - -vertices = struct('valence_p', [], 'valence_e', [], 'edges', [], 'patches', [], ... - 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); -% Inner and boundary vertex are done in a different way -% For inner vertices, I set the patch with lowest number as the first one -boundary_vertices = space.boundary.dofs(:).'; -for ivert = 1:space.ndof - boundary_vertex = ismember (ivert, boundary_vertices); - sp_edges = find(C(:,ivert)); - edges = sp2int(sp_edges); - patches_aux = [interfaces_bnd(edges).patch1; interfaces_bnd(edges).patch2]; - sides_aux = [interfaces_bnd(edges).side1; interfaces_bnd(edges).side2]; - patches = setdiff (unique (patches_aux(:)).', 0); - position = cellfun (@(gnum) find(gnum==ivert), space.gnum(patches)); - valence = numel (patches); - gnum_curl = sp2int(cell2mat (sp_curl.gnum(patches))); - gnum_curl = gnum_curl(:,dof2side); - - patch_reorientation = zeros (valence, 3); - for iptc = 1:valence - patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); - end - -% Determine the first edge and patch to reorder the patches and edges - if (boundary_vertex) - [current_edge, current_patch, last_edge] = ... - find_first_edge_and_patch_boundary (edges, patch_reorientation, sp_curl.boundary.dofs, gnum_curl, sp2int); - reordering_edges = zeros (1, valence+1); - reordering_edges(valence+1) = last_edge; - reordering_patches = zeros (1, valence); - else - [current_edge, current_patch] = ... - find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation); - reordering_edges = zeros (1, valence); - reordering_patches = zeros (1, valence); - end - -% Starting from first edge and patch, reorder the other patches and edges -% reordering_edges and reordering_patches are local indices - reordering_patches(1) = current_patch; - reordering_edges(1) = current_edge; - nn = 1; - while (nn < valence) - [~,edges_on_patch] = find (patches_aux == patches(current_patch)); - next_edge = setdiff (edges_on_patch, current_edge); - [patches_on_edge,~] = find (gnum_curl == edges(next_edge)); - next_patch = setdiff (patches_on_edge, current_patch); - - nn = nn + 1; - reordering_edges(nn) = next_edge; - reordering_patches(nn) = next_patch; - current_patch = next_patch; - current_edge = next_edge; - end - edges = edges(reordering_edges); - patches = patches(reordering_patches); - -% Check the orientation of each edge compared to the one in interfaces - if (boundary_vertex) - edge_orientation = 2*([interfaces_bnd(edges).patch2] == [patches 0]) - 1; - else - edge_orientation = 2*([interfaces(edges).patch2] == patches) - 1; - end - - vertices(ivert).valence_p = valence; - vertices(ivert).valence_e = numel(edges); - vertices(ivert).edges = edges; - vertices(ivert).patches = patches; - vertices(ivert).patch_reorientation = patch_reorientation(reordering_patches,:); - vertices(ivert).edge_orientation = edge_orientation; - vertices(ivert).boundary_vertex = boundary_vertex; -end - -end - -function operations = reorientation_edge (interface, geometry) - patches = [interface.patch1 interface.patch2]; - nrb_patches = [geometry(patches).nurbs]; - sides = [interface.side1 interface.side2]; -% Change orientation of first patch - [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - if (sides(1) == 2) - if (jacdet < 0) - operations(1,:) = [1 0 0]; - else - operations(1,:) = [1 1 0]; - end - elseif (sides(1) == 3) - if (jacdet < 0) - operations(1,:) = [0 0 1]; - else - operations(1,:) = [1 0 1]; - end - elseif (sides(1) == 4) - if (jacdet < 0) - operations(1,:) = [1 1 1]; - else - operations(1,:) = [0 1 1]; - end - elseif (sides(1) == 1) - if (jacdet < 0) - operations(1,:) = [0 1 0]; - else - operations(1,:) = [0 0 0]; - end - end - -% Change orientation of second patch, only for inner edges - if (numel(nrb_patches) == 2) - [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - if (sides(2) == 1) - if (jacdet < 0) - operations(2,:) = [0 0 1]; - else - operations(2,:) = [0 1 1]; - end - elseif (sides(2) == 2) - if (jacdet < 0) - operations(2,:) = [1 1 1]; - else - operations(2,:) = [1 0 1]; - end - elseif (sides(2) == 3) - if (jacdet < 0) - operations(2,:) = [1 0 0]; - else - operations(2,:) = [0 0 0]; - end - elseif (sides(2) == 4) - if (jacdet < 0) - operations(2,:) = [0 1 0]; - else - operations(2,:) = [1 1 0]; - end - end - end -end - - -function operations = reorientation_vertex (position, nrb) - - operations = zeros (1,3); - switch position - case 2 - operations(1) = 1; - nrb = nrbreverse (nrb, 1); - case 3 - operations(2) = 1; - nrb = nrbreverse (nrb, 2); - case 4 - operations(1:2) = [1 1]; - nrb = nrbreverse (nrb, [1 2]); - end - [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - - if (jacdet < 0) - operations(3) = 1; - end - -end - -% Determine the first edge and patch to reorder the patches and edges -% These two functions use local numbering -function [first_edge, first_patch] = find_first_edge_and_patch_interior (patches, edges, patches_aux, sides_aux, patch_reorientation) - first_patch = 1; - reornt = patch_reorientation(1,:); - if (all (reornt == [0 0 0]) || all (reornt == [1 0 0])) - side = 3; - elseif (all (reornt == [0 1 0]) || all (reornt == [1 1 0])) - side = 4; - elseif (all (reornt == [0 0 1]) || all (reornt == [0 1 1])) - side = 1; - else - side = 2; - end - - indices = find (patches_aux == patches(first_patch)); - edge_aux = find (sides_aux(indices) == side); - [~,first_edge] = ind2sub([2,numel(edges)], indices(edge_aux)); -end - -function [first_edge, first_patch, last_edge] = ... - find_first_edge_and_patch_boundary (edges, patch_reorientation, curl_bnd_dofs, gnum_curl, sp2int) - [~,~,bnd_edges] = intersect (sp2int(curl_bnd_dofs), edges); - if (numel (bnd_edges) ~=2) - error ('The number of boundary edges near a vertex should be equal to two') - end - for ii = 1:2 - [bnd_patches(ii), bnd_sides(ii)] = find (gnum_curl == edges(bnd_edges(ii))); - end - - reornt = patch_reorientation(bnd_patches(1),:); - if ((bnd_sides(1) == 3 && (all (reornt == [0 0 0]) || all (reornt == [1 0 0]))) ... - || (bnd_sides(1) == 4 && (all (reornt == [0 1 0]) || all (reornt == [1 1 0]))) ... - || (bnd_sides(1) == 1 && (all (reornt == [0 0 1]) || all (reornt == [0 1 1]))) ... - || (bnd_sides(1) == 2 && (all (reornt == [1 0 1]) || all (reornt == [1 1 1])))) - first_edge = bnd_edges(1); - first_patch = bnd_patches(1); - last_edge = bnd_edges(2); - else - first_edge = bnd_edges(2); - first_patch = bnd_patches(end); - last_edge = bnd_edges(1); - end -end \ No newline at end of file From d1d000ba536762ef50bb0964aa712defd354cde0 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:07:51 +0200 Subject: [PATCH 105/366] More cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- geopdes/inst/multipatch/vertices_struct.m | 46 +++++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index e77d0e4c..adcfe471 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -2,7 +2,7 @@ % % sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries, boundary_interfaces) % -% INPUTS: +% INPUT: % % spaces: cell-array of space objects, one for each patch (see sp_scalar) % msh: mesh object that defines the multipatch mesh (see msh_multipatch) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 2a41ee9e..4e8130e1 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -1,9 +1,45 @@ -%INPUT: boundaries and interfaces as given by mp_geo_load -%OUTPUT: structures containing 1) for each interfaces (included boundaries) indices of the djacent patches -%and corresponding incides of sides in the patches; 2)for each vertex the list of interfaces -%containing it and the corresponding index of the point in the interface (1=left/bottom, 2=right/top) +% VERTICES_STRUCT: Compute interfaces and vertices struct, necessary to build the basis +% +% [edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces) +% +% INPUT: +% +% geometry: geometry struct (see mp_geo_load) +% interfaces: information of connectivity between patches (see mp_geo_load) +% boundaries: information about the boundary of the domain (see mp_geo_load) +% boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% +% OUTPUT: +% +% interfaces: struct array similar to interfaces, but it also contains boundary edges +% vertices: struct array. For each vertex it contains: +% - valence_p: number of patches touching the vertex +% - valence_e: number of edges touching the vertex +% - edges: global numbering of the edges +% - patches: global numbering of the patches +% - patch_reorientation: operations necessary to orient the patch as +% in the standard configuration (reverse x, reverse y, transpose) +% - edge_orientation: orientation of the edge in interfaces with +% respect to the standard configuration in the vertex +% - boundary_vertex: true if the vertex is a boundary vertex +% +% Copyright (C) 2019-2021 Rafael Vazquez +% Copyright (C) 2019-2021 Cesare Bracco +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. -function [interfaces, vertices] = vertices_struct(boundaries, interfaces_i, geometry, boundary_interfaces) +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [interfaces, vertices] = vertices_struct (geometry, interfaces_i, boundaries, boundary_interfaces) for iptc = 1:numel(geometry) msh{iptc} = msh_cartesian ({[0 1] [0 1]}, {0.5 0.5}, {1 1}, geometry(iptc), 'der2', false); From 680462ed588ca7d0bd3c5f035c05a4c8f46bfbc1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:10:48 +0200 Subject: [PATCH 106/366] Fixed bug (reorder input variables) --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index adcfe471..1181b00a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -131,7 +131,7 @@ % express them as linear combinations of B-splines. % See the function compute_coefficients below for details. sp.ndof_interior = 0; - [interfaces_all, vertices] = vertices_struct (boundaries, interfaces, geometry, boundary_interfaces); + [interfaces_all, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) From 3d60e8cbe93527d1fb12508e16aef115f2f67832 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:36:15 +0200 Subject: [PATCH 107/366] Moved vertices_struct outside the constructor --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 21 +- .../sp_multipatch_C1_reorientation.m | 892 ------------------ 2 files changed, 10 insertions(+), 903 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 1181b00a..46f54a74 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -1,15 +1,14 @@ % SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity % -% sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries, boundary_interfaces) +% sp = sp_multipatch_C1 (spaces, msh, geometry, edges, vertices) % % INPUT: % -% spaces: cell-array of space objects, one for each patch (see sp_scalar) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% geometry: geometry struct (see mp_geo_load) -% interfaces: information of connectivity between patches (see mp_geo_load) -% boundaries: information about the boundary of the domain (see mp_geo_load) -% boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) +% spaces: cell-array of space objects, one for each patch (see sp_scalar) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% geometry: geometry struct (see mp_geo_load) +% edges: struct array similar to interfaces (see vertices_struct) +% vertices: struct array with vertex information (see vertices_struct) % % OUTPUT: % @@ -40,6 +39,7 @@ % sp_h1_error: compute the error in H1 norm % sp_h2_error: compute the error in H2 norm % sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% sp_plot_solution: plot the solution in Matlab % % Methods for basic connectivity operations % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements @@ -62,7 +62,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries, boundary_interfaces) +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces_all, vertices) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) error ('All the spaces in the array should be of the same class') @@ -106,7 +106,7 @@ error ('C1 continuity is only implemented for splines, not for NURBS') end end - + sp.ndof = 0; sp.ndof_per_patch = [aux.ndof]; sp.sp_patch = spaces; @@ -131,7 +131,6 @@ % express them as linear combinations of B-splines. % See the function compute_coefficients below for details. sp.ndof_interior = 0; - [interfaces_all, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); for iptc = 1:sp.npatch interior_dofs = 1:spaces{iptc}.ndof; for intrfc = 1:numel(interfaces_all) @@ -191,7 +190,7 @@ sp.vertices = vertices; sp.geometry = geometry; - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces_all, vertices); function spaux = patches_constructor (spaces, MSH) for ipatch = 1:MSH.npatch spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m deleted file mode 100644 index 4850fec1..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1_reorientation.m +++ /dev/null @@ -1,892 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 - -% if (numel (interfaces) > 1 || msh.npatch > 2) -% error ('For now, the implementation only works for two patches') -% end - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface - - sp.ndof_interior = 0; - [interfaces_all, vertices] = vertices_struct (boundaries, interfaces); - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces_all) - patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; - sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces_all, vertices); -%keyboard - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - end - - for intrfc = 1:numel(interfaces_all) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; - for iptc = 1:numel(patches) - Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; - end - end - -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; - end - end - -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - %keyboard - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) - -%Initialize output variables with correct size -ndof_per_interface = zeros (1, numel(interfaces_all)); -ndof_per_vertex = 6*ones(1,numel(vertices)); - -CC_edges = cell (2, numel (interfaces_all)); -CC_edges_discarded = cell (2, numel (interfaces_all)); -CC_vertices = cell (space.npatch, numel(vertices)); -for ii = 1:space.npatch - for jj = 1:numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), 6); - end -end - -pp = space.sp_patch{1}.degree(1); -kk = numel(msh.msh_patch{1}.breaks{1})-2; -% nn = space.sp_patch{1}.sp_univ(1).ndof; -breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); -mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg = pp - max(mult(2:end-1)); - - -all_alpha0 = zeros(numel(interfaces_all),2); -all_alpha1 = zeros(numel(interfaces_all),2); -all_beta0 = zeros(numel(interfaces_all),2); -all_beta1 = zeros(numel(interfaces_all),2); - -%Computation of CC_edges -for iref = 1:numel(interfaces_all) -% Auxiliary geometry with orientation as in the paper - [geo_local, operations] = reorientation_edge (interfaces_all(iref), geometry); - - original_patch = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; - patch = [1 2]; side = [1 3]; - npatches_on_edge = numel (original_patch); - -% Compute gluing data - geo_map_jac = cell (npatches_on_edge, 1); - for ii = 1:npatches_on_edge - brk = cell (1,msh.ndim); - grev_pts = cell (1, msh.ndim); - knt = geo_local(ii).nurbs.knots; - order = geo_local(ii).nurbs.order; - for idim = 1:msh.ndim - grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; - brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_interior = msh_precompute (msh_side_interior); - geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) - end - - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side); - clear geo_map_jac msh_grev msh_side_interior grev_pts - - %Saving alphas and betas (first column=R, second column=L) - % FIX: THIS HAS TO BE RECOMPUTED AFTER REORIENTATION - all_alpha0(iref,:) = alpha0; - all_alpha1(iref,:) = alpha1; - all_beta0(iref,:) = beta0; - all_beta1(iref,:) = beta1; - -% Compute the Greville points, and the auxiliary mesh and space objects for -% functions with reduced degree or increased regularity - for ii = 1:npatches_on_edge -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - brk = cell (1,msh.ndim); - grev_pts = cell (1, msh.ndim); - degrees = degree_reorientation (space.sp_patch{original_patch(ii)}.degree, operations(ii,3)); - degree = degrees(ind1); %space.sp_patch{patch(ii)}.degree(ind1); - - knots = knot_vector_reorientation (space.sp_patch{original_patch(ii)}.knots, operations(ii,:)); - knots0 = knot_vector_reorientation (space.knots0_patches{original_patch(ii)}, operations(ii,:)); - knots0 = knots0{ind1}; %space.knots0_patches{patch(ii)}{ind1}; - knots1 = knot_vector_reorientation (space.knots1_patches{original_patch(ii)}, operations(ii,:)); - knots1 = knots1{ind1}; %space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - degu = degrees(ind2); %space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (knots{ind2}); - tau1 = knt(2) - knt(1); - -% sp_aux contains the value and derivatives of the basis functions, at the Greville points - msh_side = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = sp_bspline (knots, degrees, msh_side_interior); - -% Univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) and N^{p,r} on the interface - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - - knotsn = knots{ind1}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side.nel, msh_side.nel); - for jj = 1:msh_side.nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; - beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; - -% RHS and solution of the linear systems, (14)-(16) in Mario's notes - rhss = sparse (msh_side.nel, sp0_struct.ndof); - for jj = 1:msh_side.nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0 = A \ rhss; - coeff0(abs(coeff0) < 1e-12) = 0; % Make more sparse - - rhsb = sparse (msh_side.nel, sp0_struct.ndof); - if (ii == 1) % paper case, (side(ii) == 1) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (ii == 2) %The other paper case, (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side.nel - val_aux = -val * beta(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1 = A \ rhsb; - coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse - - rhsc = sparse (msh_side.nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); %^2 removed %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side.nel - val_aux = val * alpha(jj)* (-1)^(ii+1); %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2 = A \ rhsc; - coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis - ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; - ndof_dir_original = space.sp_patch{original_patch(ii)}.ndof_dir; - if (ii == 1) %(side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (ii == 2) %(side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - end - indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); - ind0_ornt = indices_reoriented(ind0); - ind1_ornt = indices_reoriented(ind1); - -% Store the coefficients in CC_edges, and compute the number of functions - ndof_edge = sp0_struct.ndof + sp1_struct.ndof; - trace_functions = 4:sp0_struct.ndof-3; - deriv_functions = sp0_struct.ndof + (3:sp1_struct.ndof-2); - active_functions = union (trace_functions, deriv_functions); - discarded_functions = setdiff (1:ndof_edge, active_functions); - - CC = sparse (space.ndof_per_patch(original_patch(ii)), ndof_edge); - CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; - CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; - CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; - - ndof_per_interface(iref) = numel(active_functions); - CC_edges{ii,iref} = sparse (space.ndof_per_patch(original_patch(ii)), ndof_per_interface(iref)); - CC_edges{ii,iref} = CC(:,active_functions); - CC_edges_discarded{ii,iref} = CC(:,discarded_functions); - end -end - - -% Computation of CC_vertices -% Compute for each patch all the derivatives we possibly need to compute t,d, and sigma -% FIX: this would be done inside the vertex loop, after reorientation -brk = cell (1,msh.ndim); -for iptc = 1:space.npatch - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1} = [0 1]'; - pts{2} = [0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(iptc),'boundary', true, 'der2', true); - msh_der = msh_precompute (msh_pts_der1); - derivatives1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} -end - - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is the interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM = cell(2,numel(vertices)); -V = cell(numel(vertices),1); -E = cell(numel(vertices),1); -sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - -for kver = 1:numel(vertices) - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches = []; %vector with indices of patches containing the vertex - ver_patches_nabla = {}; %cell array containing jacobians - ver_ind = []; %vector containing local index of vertex in the patch - ninterfaces_ver = numel(vertices(kver).interfaces); - - boundary_vertex = 0; - for im = 1:ninterfaces_ver - inter = vertices(kver).interfaces(im); - if (isempty(interfaces_all(inter).side1) || isempty(interfaces_all(inter).side2)) - boundary_vertex = 1; - break - end - end - if (~boundary_vertex) - -% for h=1:numel(vertices(kver).interfaces) -% hint=vertices(kver).interfaces(h); -% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; -% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... -% sides(interfaces(hint).side2,vertices(kver).ind)]; -% end -% ver_patches=unique(ver_patches,'stable'); -% ver_ind=unique(ver_ind,'stable'); -% 1=RIGHT PATCH 2=LEFT PATCH (true also for alphas and betas, but not for CC_edges and CC_edges_discarded) - for iedge = 1:ninterfaces_ver %cycle over all the interfaces containing the vertex - inter = vertices(kver).interfaces(iedge); %global index of the interface - patch_ind1 = interfaces_all(inter).patch1; %global index of left patch of iedge-th interface - patch_ind2 = interfaces_all(inter).patch2; %global index of right patch of iedge-th interface - vertex_ind1 = sides(interfaces_all(inter).side1,vertices(kver).ind(iedge)); %local index of vertex in left patch - vertex_ind2 = sides(interfaces_all(inter).side2,vertices(kver).ind(iedge)); %local index of vertex in right patch - ver_patches = [ver_patches patch_ind1 patch_ind2]; - ver_ind = [ver_ind vertex_ind1 vertex_ind2]; - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00 = derivatives1{patch_ind1}(:,1,1); - Dv_F00 = derivatives1{patch_ind1}(:,2,1); - Duv_F00 = derivatives2{patch_ind1}(:,1,2,1); - Dvv_F00 = derivatives2{patch_ind1}(:,2,2,1); - end - %Store the jacobian of F for the left patch - ver_patches_nabla{2*iedge-1} = [Du_F00 Dv_F00]; - - t0(iedge,:) = Dv_F00; - t0p(iedge,:) = Dvv_F00; - d0(iedge,:) = (Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) / ... - (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0); - d0p(iedge,:) = (-(-all_alpha0(inter,1) + all_alpha1(inter,1))*(Du_F00 + (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dv_F00) +... - (all_alpha0(inter,1)*(1-0) + all_alpha1(inter,1)*0) * ... - (Duv_F00 + (-all_beta0(inter,1) + all_beta1(inter,1))*Dv_F00 + ... - (all_beta0(inter,1)*(1-0) + all_beta1(inter,1)*0)*Dvv_F00)) / ... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(2*iedge-1,:) = Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00 = derivatives1{patch_ind2}(:,1,1); - Dv_F00 = derivatives1{patch_ind2}(:,2,1); - Duv_F00 = derivatives2{patch_ind2}(:,1,2,1); - end - ver_patches_nabla{2*iedge} = [Du_F00 Dv_F00]; - mix_der2(2*iedge,:) = Duv_F00; - - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if (vertices(kver).ind(iedge) == 1) %the vertex is the left/bottom endpoint of im-th interface - E{kver}{iedge,1} = CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{iedge,2} = CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); -% else %the vertex is the right/top endpoint of im-th interface -% E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); -% E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end - end - [ver_patches, ind_patch_sigma, ind_patch_rep] = unique (ver_patches, 'stable'); - mix_der2_n = mix_der2(ind_patch_sigma,:); - %ver_ind=unique(ver_ind,'rows','stable'); - - %ind_patch_sigma contains the positions of the elements of ver_patches - %originally (each of them is present twice, the first one is considered) - - %if the number of patches coincides with the number of interfaces, - %we add one fictional interface coinciding with the first one - %(just for coding-numbering reasons) -% if numel(ver_patches)==ninterfaces_ver -% t0(ninterfaces_ver+1,:)=t0(1,:); -% t0p(ninterfaces_ver+1,:)=t0p(1,:); -% d0(ninterfaces_ver+1,:)=d0(1,:); -% d0p(ninterfaces_ver+1,:)=d0p(1,:); -% E{kver}{ninterfaces_ver+1,1}=E{kver}{1,1}; -% E{kver}{ninterfaces_ver+1,2}=E{kver}{1,2}; -% end - - %computing sigma % FIX: ver_patches_nabla needs to be changed for multiple vertices - sigma = 0; - for im = 1:ninterfaces_ver % FIX: is this the number of interfaces? - sigma = sigma + norm(ver_patches_nabla{ind_patch_sigma(im)},2); - end - sigma = 1/(sigma/(pp*(kk+1)*ninterfaces_ver)); - %computing matrices MM and V - for ipatch = 1:ninterfaces_ver %FIX: cycle over the patches containing the vertex - - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2 = space.sp_patch{ver_patches(ipatch)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) -% V{kver}{im} = zeros(n1*n2,6); - MM1 = zeros(5,6); MM2 = zeros(5,6); - VV = zeros(n1*n2,6); - im_edges = ceil(find(ind_patch_rep==ipatch)/2); %indices of the edges containing the vertex (in the list of edges containing the vertex) - if (ipatch == 1) %works only if the interfaces and patches are ordered in clockwise order - im_edges = flip (im_edges); %this is done to have always the interface to the right of the patch in iedge1 - end - iedge1 = im_edges(1); iedge2 = im_edges(2); - - corner_4dofs = [1 2 n2+1 n2+2]; - jfun = 1; - for j1 = 0:2 - for j2 = 0:2-j1 %the following computations work in the standard case - mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; - vec_deltas = [(j1==1)*(j2==0), (j1==0)*(j2==1)]; - d00 = (j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a = vec_deltas*t0(iedge1,:)'; - d20_a = t0(iedge1,:)*mat_deltas*t0(iedge1,:)' + vec_deltas*t0p(iedge1,:)'; - d01_a = vec_deltas*d0(iedge1,:)'; - d11_a = t0(iedge1,:)*mat_deltas*d0(iedge1,:)' + vec_deltas*d0p(iedge1,:)'; - - %M_{i_{m+1},i} - d10_b = vec_deltas*t0(iedge2,:)'; - d20_b = t0(iedge2,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*t0p(iedge2,:)'; - d01_b = vec_deltas*d0(iedge2,:)'; - d11_b = t0(iedge2,:)*mat_deltas*d0(iedge2,:)' + vec_deltas*d0p(iedge2,:)'; - if (reg < pp-2) - MM1(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; - else - MM1(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - MM2(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; - end - %V_{i_m,i} - d11_c = t0(iedge1,:)*mat_deltas*t0(iedge2,:)' + vec_deltas*mix_der2_n(ipatch,:)'; - VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+d10_b/(pp*(kk+1)), ... - d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; - jfun = jfun+1; - end - end - % Check which patch of the edge function we are considering - if (interfaces_all(vertices(kver).interfaces(iedge1)).patch2 == ver_patches(ipatch))%the considered patch is the second patch edge iedge1 - E1 = E{kver}{iedge1,2}; - else - E1 = E{kver}{iedge1,1}; - end - if (interfaces_all(vertices(kver).interfaces(iedge2)).patch2 == ver_patches(ipatch))%the considered patch is the second patch of edge iedge2 - E2 = E{kver}{iedge2,2}; - else - E2 = E{kver}{iedge2,1}; - end -% % XX1 = E1; XX1(:,4) = -XX1(:,4); XX1(:,5) = -XX1(:,5); -% % XX2 = E2; XX2(:,4) = -XX2(:,4); XX2(:,5) = -XX2(:,5); -% CC_vertices{ver_patches(ipatch),kver} = E1*MM{1,kver}{ipatch} + E2*MM{2,kver}{ipatch} - V{kver}{ipatch}; - CC_vertices{ver_patches(ipatch),kver} = E1*MM1 + E2*MM2 - VV; -% % CC_vertices{ver_patches(ipatch),kver} = XX1*MM1 + XX2*MM2 - VV; - %csi2=[1 9 17 25 33 41 49 57]; - %csi1=1:8; -% M1aux{ipatch} = E1 * MM1; -% M2aux{ipatch} = E2 * MM2; -% Vaux{ipatch} = VV; - end - end - -end - -end - -function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) - - if (numel (geo_map_jac) == 1) -% FIX: alpha1 and beta1 do not exist. They should be empty, but give an error in all_alpha - alpha0 = [1 1]; - alpha1 = [0 0]; - beta0 = [0 0]; - beta1 = [0 0]; - return - end - - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - if (side(2)==1 || side(2)==2) - v = grev_pts{2}(:); - else - v = grev_pts{1}(:); - end - ngrev = numel(v); - DuFR_x = reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector - DuFR_y = reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector - DvFL_x = reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector - DvFL_y = reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector - DvFR_x = reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector - DvFR_y = reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector - - A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if (rank(A_full)==6) - A = A_full(:,2:end); - b = -A_full(:,1); - sols = A\b; - alpha0_n(1) = 1; %R - alpha1_n(1) = sols(1); %R - alpha0_n(2) = sols(2); %L - alpha1_n(2) = sols(3); %L - beta0_n = sols(4); - beta1_n = sols(5); - beta2_n = sols(6); - else - A = A_full(:,3:end); % FIX: not a square matrix - b = -sum(A_full(:,1:2),2); - sols = A\b; - alpha0_n(1) = 1; %R - alpha1_n(1) = 1; %R - alpha0_n(2) = sols(1); %L - alpha1_n(2) = sols(2); %L - beta0_n = sols(3); - beta1_n = sols(4); - beta2_n = sols(5); - end - - %keyboard - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; - C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); - gamma = 3*C2/(2*C1); - alpha0(1) = alpha0_n(1)*gamma; %R - alpha1(1) = alpha1_n(1)*gamma; %R - alpha0(2) = alpha0_n(2)*gamma; %L - alpha1(2) = alpha1_n(2)*gamma; %L - bbeta0 = beta0_n*gamma; - bbeta1 = beta1_n*gamma; - bbeta2 = beta2_n*gamma; - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_R_0 = alpha0(1); %alpha_R(0) - alpha_R_1 = alpha1(1); %alpha_R(1) - alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_R(1/2) - alpha_L_0 = alpha0(2); %alpha_L(0) - alpha_L_1 = alpha1(2); %alpha_L(1) - alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0 = bbeta0; %beta(0) - beta_1 = bbeta2; %beta(1) - beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M = [alpha_R_0 0 alpha_L_0 0; ... - 0 alpha_R_1 0 alpha_L_1; ... - alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; - - if (rank(M)==3) - - %Computing beta1_R, beta0_L, beta1_L in terms of beta0_R - quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - - %beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where - a = quant2; b = quant1; - c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; - e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; - - %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L - C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; - C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; - beta0(1) = -C2/(2*C1); %R - beta1(1) = a + b*beta0(1); %R - beta0(2) = c + d*beta0(1); %L - beta1(2) = e + f*beta0(1); %L - - else - %Computing beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; - c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; - - %We determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L - %The resuting system is - M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b = [-b*c-2*a*b; -a*d-2*c*d]; - sol = M2\M2b; - beta0(1)= sol(1); %R - beta1(1)= sol(2); %R - beta0(2)= a + b*beta0(1); %L - beta1(2)= c + d*beta1(1); %L - end - -end - -% Functions to deal with general orientation of the patches -function [geo_reoriented, operations] = reorientation_edge (interface, geometry) - patches = [interface.patch1 interface.patch2]; - nrb_patches = [geometry(patches).nurbs]; - sides = [interface.side1 interface.side2]; -% Change orientation of first patch - [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - if (sides(1) == 2) - if (jacdet < 0) - operations(1,:) = [1 0 0]; - else - operations(1,:) = [1 1 0]; - end - elseif (sides(1) == 3) - if (jacdet < 0) - operations(1,:) = [0 0 1]; - else - operations(1,:) = [1 0 1]; - end - elseif (sides(1) == 4) - if (jacdet < 0) - operations(1,:) = [1 1 1]; - else - operations(1,:) = [0 1 1]; - end - elseif (sides(1) == 1) - if (jacdet < 0) - operations(1,:) = [0 1 0]; - else - operations(1,:) = [0 0 0]; - end - end - -% Change orientation of second patch, only for inner edges - if (numel(nrb_patches) == 2) - [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - if (sides(2) == 1) - if (jacdet < 0) - operations(2,:) = [0 0 1]; - else - operations(2,:) = [0 1 1]; - end - elseif (sides(2) == 2) - if (jacdet < 0) - operations(2,:) = [1 1 1]; - else - operations(2,:) = [1 0 1]; - end - elseif (sides(2) == 3) - if (jacdet < 0) - operations(2,:) = [1 0 0]; - else - operations(2,:) = [0 0 0]; - end - elseif (sides(2) == 4) - if (jacdet < 0) - operations(2,:) = [0 1 0]; - else - operations(2,:) = [1 1 0]; - end - end - end - - for ii = 1:numel(nrb_patches) - if (operations(ii,1)) - nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); - end - if (operations(ii,2)) - nrb_patches(ii) = nrbreverse (nrb_patches(ii), 2); - end - if (operations(ii,3)) - nrb_patches(ii) = nrbtransp (nrb_patches(ii)); - end - end - - [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); -% FIX: this check can be removed once everything is working - if (numel (nrb_patches) == 2) - if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) - error('The reorientation is wrong') - end - end -end - -function knots = knot_vector_reorientation (knots, operations) - if (operations(1)) - knots{1} = sort (1 - knots{1}); - end - if (operations(2)) - knots{2} = sort (1-knots{2}); - end - if (operations(3)) - knots([2 1]) = knots([1 2]); - end -end - -function degree = degree_reorientation (degree, transposition) - if (transposition) - degree = degree([2 1]); - end -end - -function indices = indices_reorientation (ndof_dir, operations) - ndof = prod (ndof_dir); - indices = reshape (1:ndof, ndof_dir); - if (operations(1)) - indices = flipud (indices); - end - if (operations(2)) - indices = fliplr (indices); - end - if (operations(3)) - indices = indices.'; - end -end From 0d36116c17a0d193dfff354e69ad3f1529fab99d Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:45:12 +0200 Subject: [PATCH 108/366] Working version of sp_refine --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m index f8f87553..d4b7d666 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -62,7 +62,6 @@ sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); end end - sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, []); - + sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, space.vertices); end \ No newline at end of file From fa3d70b839ee3565000e43afb91d08af9b072756 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:50:26 +0200 Subject: [PATCH 109/366] Added function to the help --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 46f54a74..26171523 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -46,6 +46,9 @@ % sp_get_cells: compute the cells on which a list of functions do not vanish % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one % +% Other methods +% sp_refine: generate a refined space, and subdivision matrices for the univariate spaces +% % Copyright (C) 2015-2021 Rafael Vazquez % Copyright (C) 2019-2021 Cesare Bracco % From 2624be3d3c76124957c72e1884851fc823fceb01 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 20 May 2021 18:57:52 +0200 Subject: [PATCH 110/366] Rename the coefficients as in the draft, and more cleaning. --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 78 +++++++++---------- 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 26171523..91b8cd04 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -394,15 +394,7 @@ end end - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is the interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM = cell(2,numel(vertices)); -V = cell(numel(vertices),1); -E = cell(numel(vertices),1); -sides = [1 4; 2 3; 1 2; 4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - +% Computation of CC_vertices for kver = 1:numel(vertices) edges = vertices(kver).edges; patches = vertices(kver).patches; @@ -495,47 +487,47 @@ for j2 = 0:2-j1 mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; vec_deltas = [(j1==1)*(j2==0); (j1==0)*(j2==1)]; - d00 = (j1==0)*(j2==0); + c0 = (j1==0)*(j2==0); %M_{i_{m-1},i} - d10_a = vec_deltas.'*t0_prev; - d20_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; - d01_a = vec_deltas.'*d0_prev; - d11_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; + c1_a = vec_deltas.'*t0_prev; + c2_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; + d0_a = vec_deltas.'*d0_prev; + d1_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; %M_{i_{m+1},i} - d10_b = vec_deltas.'*t0_next; - d20_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; - d01_b = vec_deltas.'*d0_next; - d11_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; + c1_b = vec_deltas.'*t0_next; + c2_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; + d0_b = vec_deltas.'*d0_next; + d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; if (reg < pp-2) - M_prev(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+2*d10_a/(pp*(kk+1))+d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+2*d10_b/(pp*(kk+1))+d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; + M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+2*c1_a/(pp*(kk+1))+c2_a/(pp*(pp-1)*(kk+1)^2), ... + d0_a/(pp*(kk+1)), ... + d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_b/(pp*(kk+1)), ... + c0+2*c1_b/(pp*(kk+1))+c2_b/(pp*(pp-1)*(kk+1)^2), ... + d0_b/(pp*(kk+1)), ... + d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; else - M_prev(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+3*d10_a/(pp*(kk+1))+2*d20_a/(pp*(pp-1)*(kk+1)^2), ... - d01_a/(pp*(kk+1)), ... - d01_a/(pp*(kk+1))+d11_a/(pp*(pp-1)*(kk+1)^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_b/(pp*(kk+1)), ... - d00+3*d10_b/(pp*(kk+1))+2*d20_b/(pp*(pp-1)*(kk+1)^2), ... - d01_b/(pp*(kk+1)), ... - d01_b/(pp*(kk+1))+d11_b/(pp*(pp-1)*(kk+1)^2)].'; + M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+3*c1_a/(pp*(kk+1))+2*c2_a/(pp*(pp-1)*(kk+1)^2), ... + d0_a/(pp*(kk+1)), ... + d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_b/(pp*(kk+1)), ... + c0+3*c1_b/(pp*(kk+1))+2*c2_b/(pp*(pp-1)*(kk+1)^2), ... + d0_b/(pp*(kk+1)), ... + d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; end %V_{i_m,i} - d11_c = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; - VV(corner_4dofs,jfun) = sigma^(j1+j2)*[d00, ... - d00+d10_a/(pp*(kk+1)), ... - d00+d10_b/(pp*(kk+1)), ... - d00+(d10_a+d10_b+d11_c/(pp*(kk+1)))/(pp*(kk+1))]'; + e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; + VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+c1_b/(pp*(kk+1)), ... + c0+(c1_a+c1_b+e11/(pp*(kk+1)))/(pp*(kk+1))]'; jfun = jfun+1; end end From ed6662f70f86c365095ab3413a717e7eed3ce8ac Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 21 May 2021 10:07:09 +0200 Subject: [PATCH 111/366] CC_vertices is only defined for patches around the vertex --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 91b8cd04..c194794f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -181,8 +181,9 @@ for ivrt = 1:numel(vertices) global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); sp.dofs_on_vertex{ivrt} = global_indices; - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; + for iptc = 1:vertices(ivrt).valence_p + patch = vertices(ivrt).patches(iptc); + Cpatch{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; end end @@ -212,9 +213,10 @@ % sp.ndof_per_patch(patch) x ndof_per_interface(jj) % with patch = interfaces(jj).patches(ii); % ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices). Even if the value is always six. -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; +% CC_vertices: cell array of size 1 x numel(vertices), each entry containin another +% cell-array of size 1 x vertices(ii).valence_p (local number of patches) +% The matrix CC_vertices{jj}{ii} has size sp.ndof_per_patch(patch) x ndof_per_vertex(ii) +% with patch = vertices(jj).patches(ii). %Initialize output variables with correct size ndof_per_interface = zeros (1, numel(interfaces_all)); @@ -222,11 +224,9 @@ CC_edges = cell (2, numel (interfaces_all)); CC_edges_discarded = cell (2, numel (interfaces_all)); -CC_vertices = cell (space.npatch, numel(vertices)); -for ii = 1:space.npatch - for jj = 1:numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), 6); - end +CC_vertices = cell (1, numel(vertices)); +for jj = 1:numel(vertices) + CC_vertices{jj} = cell (1,numel(vertices(jj).valence_p)); end pp = space.sp_patch{1}.degree(1); @@ -531,7 +531,7 @@ jfun = jfun+1; end end - CC_vertices{patches(ipatch),kver} = E_prev*M_prev + E_next*M_next - VV; + CC_vertices{kver}{ipatch} = E_prev*M_prev + E_next*M_next - VV; end end From f7474a30256a0c86aa015476b33e3df0c791a739 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 21 May 2021 10:25:32 +0200 Subject: [PATCH 112/366] Some cleaning in the function for gluing data --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 101 +++++++++--------- 1 file changed, 49 insertions(+), 52 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index c194794f..0674bbac 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -538,9 +538,13 @@ end function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) +% OUTPUT from gluing data +% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. +% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring +% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). +% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. if (numel (geo_map_jac) == 1) -% FIX: alpha1 and beta1 do not exist. They should be empty, but give an error in all_alpha alpha0 = [1 1]; alpha1 = [1 1]; beta0 = [0 0]; @@ -548,19 +552,19 @@ return end - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! + % Assemble and solve G^1 conditions system if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); else v = grev_pts{1}(:); end ngrev = numel(v); - DuFR_x = reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector - DuFR_y = reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector - DvFL_x = reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector - DvFL_y = reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector - DvFR_x = reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector - DvFR_y = reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector + DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; @@ -568,10 +572,10 @@ A = A_full(:,2:end); b = -A_full(:,1); sols = A\b; - alpha0_n(1) = 1; %R - alpha1_n(1) = sols(1); %R - alpha0_n(2) = sols(2); %L - alpha1_n(2) = sols(3); %L + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); beta0_n = sols(4); beta1_n = sols(5); beta2_n = sols(6); @@ -579,57 +583,51 @@ A = A_full(:,3:end); % FIX: not a square matrix b = -sum(A_full(:,1:2),2); sols = A\b; - alpha0_n(1) = 1; %R - alpha1_n(1) = 1; %R - alpha0_n(2) = sols(1); %L - alpha1_n(2) = sols(2); %L + alpha0_n(1) = 1; + alpha1_n(1) = 1; + alpha0_n(2) = sols(1); + alpha1_n(2) = sols(2); beta0_n = sols(3); beta1_n = sols(4); beta2_n = sols(5); end - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); + % Normalize the alphas C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); gamma = 3*C2/(2*C1); - alpha0(1) = alpha0_n(1)*gamma; %R - alpha1(1) = alpha1_n(1)*gamma; %R - alpha0(2) = alpha0_n(2)*gamma; %L - alpha1(2) = alpha1_n(2)*gamma; %L + alpha0(1) = alpha0_n(1)*gamma; + alpha1(1) = alpha1_n(1)*gamma; + alpha0(2) = alpha0_n(2)*gamma; + alpha1(2) = alpha1_n(2)*gamma; bbeta0 = beta0_n*gamma; bbeta1 = beta1_n*gamma; bbeta2 = beta2_n*gamma; - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_R_0 = alpha0(1); %alpha_R(0) - alpha_R_1 = alpha1(1); %alpha_R(1) - alpha_R_12 = (alpha0(1)+alpha1(1))/2; %alpha_R(1/2) - alpha_L_0 = alpha0(2); %alpha_L(0) - alpha_L_1 = alpha1(2); %alpha_L(1) - alpha_L_12 = (alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0 = bbeta0; %beta(0) - beta_1 = bbeta2; %beta(1) - beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) + % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. + alpha_R_0 = alpha0(1); + alpha_R_1 = alpha1(1); + alpha_R_12 = (alpha0(1)+alpha1(1))/2; + alpha_L_0 = alpha0(2); + alpha_L_1 = alpha1(2); + alpha_L_12 = (alpha0(2)+alpha1(2))/2; + beta_0 = bbeta0; + beta_1 = bbeta2; + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta + % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta M = [alpha_R_0 0 alpha_L_0 0; ... 0 alpha_R_1 0 alpha_L_1; ... alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; if (rank(M)==3) - - %Computing beta1_R, beta0_L, beta1_L in terms of beta0_R + % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - %beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where + % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where a = quant2; b = quant1; c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; @@ -637,26 +635,25 @@ %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; - beta0(1) = -C2/(2*C1); %R - beta1(1) = a + b*beta0(1); %R - beta0(2) = c + d*beta0(1); %L - beta1(2) = e + f*beta0(1); %L + beta0(1) = -C2/(2*C1); + beta1(1) = a + b*beta0(1); + beta0(2) = c + d*beta0(1); + beta1(2) = e + f*beta0(1); else - %Computing beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: + % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; - %We determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L - %The resuting system is + % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; M2b = [-b*c-2*a*b; -a*d-2*c*d]; sol = M2\M2b; - beta0(1)= sol(1); %R - beta1(1)= sol(2); %R - beta0(2)= a + b*beta0(1); %L - beta1(2)= c + d*beta1(1); %L + beta0(1)= sol(1); + beta1(1)= sol(2); + beta0(2)= a + b*beta0(1); + beta1(2)= c + d*beta1(1); end end From f43ba121e8f96dfa6d26b344c1eaf1d58a317a97 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 21 May 2021 10:35:52 +0200 Subject: [PATCH 113/366] Another simplification --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 41 ++++++++----------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 0674bbac..f0a72a16 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -395,6 +395,13 @@ end % Computation of CC_vertices +% Auxiliary constants to deal with different regularity cases in the M matrices +if (reg < pp-2) + const1 = 2; const2 = 1; +else + const1 = 3; const2 = 2; +end + for kver = 1:numel(vertices) edges = vertices(kver).edges; patches = vertices(kver).patches; @@ -499,29 +506,17 @@ c2_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; d0_b = vec_deltas.'*d0_next; d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; - if (reg < pp-2) - M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+2*c1_a/(pp*(kk+1))+c2_a/(pp*(pp-1)*(kk+1)^2), ... - d0_a/(pp*(kk+1)), ... - d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_b/(pp*(kk+1)), ... - c0+2*c1_b/(pp*(kk+1))+c2_b/(pp*(pp-1)*(kk+1)^2), ... - d0_b/(pp*(kk+1)), ... - d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; - else - M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+3*c1_a/(pp*(kk+1))+2*c2_a/(pp*(pp-1)*(kk+1)^2), ... - d0_a/(pp*(kk+1)), ... - d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_b/(pp*(kk+1)), ... - c0+3*c1_b/(pp*(kk+1))+2*c2_b/(pp*(pp-1)*(kk+1)^2), ... - d0_b/(pp*(kk+1)), ... - d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; - end + + M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+const1*c1_a/(pp*(kk+1))+const2*c2_a/(pp*(pp-1)*(kk+1)^2), ... + d0_a/(pp*(kk+1)), ... + d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_b/(pp*(kk+1)), ... + c0+const1*c1_b/(pp*(kk+1))+const2*c2_b/(pp*(pp-1)*(kk+1)^2), ... + d0_b/(pp*(kk+1)), ... + d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; %V_{i_m,i} e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... From 190c5906acecb233053fa02a37e8ffd01e81e7dc Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 21 May 2021 14:06:15 +0200 Subject: [PATCH 114/366] Replace 2-norm by infinity-norm --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f0a72a16..55dbe816 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -424,7 +424,7 @@ derivatives_new1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) derivatives_new2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} - sigma = sigma + norm (derivatives_new1{iptc},2); % FIX: choose which norm + sigma = sigma + norm (derivatives_new1{iptc}, Inf); end sigma = pp*(kk+1)*valence_p/sigma; From d0f6b1d3a2df2d32e6f6578789402b1874e8fcb3 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 30 Jun 2021 11:45:32 +0200 Subject: [PATCH 115/366] Fixed small bug: use the knot vector from the space, not from the msh. --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 55dbe816..d3babbed 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -230,8 +230,8 @@ end pp = space.sp_patch{1}.degree(1); -kk = numel(msh.msh_patch{1}.breaks{1})-2; breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); +kk = numel(breaks_m{1}) - 2; mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); reg = pp - max(mult(2:end-1)); From e59ca1a261ae426ff3e6934fbff161438dbcf5bc Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 30 Jun 2021 15:23:43 +0200 Subject: [PATCH 116/366] Functions for finding elements near vertices --- .../@msh_multipatch/msh_cells_near_vertex.m | 56 +++++++++++++++++++ .../sp_get_vertex_neighbors.m | 46 +++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m diff --git a/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m new file mode 100644 index 00000000..629f50c6 --- /dev/null +++ b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m @@ -0,0 +1,56 @@ +% MSH_CELLS_NEAR_VERTEX: Identify the elements adjacent to given vertices +% +% elems_near_vertex = msh_cells_near_vertex (msh, vertices) +% +% INPUT: +% +% msh: multipatch mesh object (see msh_multipatch) +% vertices: struct containing the vertex information (see vertices_struct) +% +% OUTPUT: +% +% elems_near_vertex: for each vertex in the input, list of elements +% adjacent to the vertex (cell-array, to allow different valences). +% +% Copyright (C) 2021 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function elems_adj_to_vertex = msh_cells_near_vertex (msh, vertices) + +nvert = numel (vertices); +elems_adj_to_vertex = cell (nvert, 1); +shifting_index = cumsum ([0 msh.nel_per_patch]); + +for ivert = 1:nvert + elems = []; + patches = vertices(ivert).patches; + patch_ornt = vertices(ivert).patch_reorientation; + for iptc = 1:numel(patches) + patch = patches(iptc); + nel_dir = msh.msh_patch{patch}.nel_dir; + indx = 1; indy = 1; + if (patch_ornt(iptc,1)) + indx = nel_dir(1); + end + if (patch_ornt(iptc,2)) + indy = nel_dir(2); + end + new_elem = shifting_index(patch) + sub2ind (nel_dir, indx, indy); + elems = [elems, new_elem]; + end + elems_adj_to_vertex{ivert} = elems; +end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m new file mode 100644 index 00000000..a27e8ec8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -0,0 +1,46 @@ +% SP_GET_VERTEX_NEIGHBORS: Compute the indices of elements in the support +% of vertex functions, separated by patches +% +% cell_indices = sp_get_vertex_neighbors (space, msh, vertex_index, patch_indices) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% vertex_index: indices of the vertex for which to compute the cells. +% patch_indices: local indices (w.r.t. vertex) for the patches on which to +% compute the cells. +% +% OUTPUT: +% cell_indices: indices of the functions that interact with the given ones. +% +% Copyright (C) 2021 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function cell_indices = sp_get_vertex_neighbors (space, msh, vertex_index, patch_indices) + +if (nargin < 4) + patch_indices = 1:space.vertices(vertex_index).valence_p; +end +cell_indices = cell (numel(patch_indices), 1); + +Nelem = cumsum ([0 msh.nel_per_patch]); +for iptc = patch_indices + patch = space.vertices(vertex_index).patches(iptc); + [bsp_indices, ~] = find (space.Cpatch{patch}(:,space.dofs_on_vertex{vertex_index})); + [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); + cell_indices{iptc} = Nelem(patch) + aux_cell_indices; +end + +end \ No newline at end of file From 9a5ab08ddfa513fb92bca0aabf144eb83346f554 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Jul 2021 15:23:18 +0200 Subject: [PATCH 117/366] Use the correct class name --- geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m index f8f87553..0c799cfc 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m @@ -62,7 +62,7 @@ sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); end end - sp_fine = sp_multipatch_C1 (sp_fine, msh, space.geometry, space.interfaces, []); + sp_fine = sp_multipatch_C1_twopatch (sp_fine, msh, space.geometry, space.interfaces, []); end \ No newline at end of file From 4314cad883245da0bd103a127f758d9c8e69e4ea Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Jul 2021 16:16:43 +0200 Subject: [PATCH 118/366] Fix error when the number of functions per element is not constant --- .../@sp_multipatch_C1/sp_evaluate_element_list.m | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 85072cff..226298ba 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -109,7 +109,7 @@ shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; end if (isfield (sp_patch, 'shape_function_hessians')) - for idim = 1:msh.rdim; + for idim = 1:msh.rdim for jdim = 1:msh.rdim shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; @@ -118,8 +118,22 @@ end end + nsh_max = max(sp.nsh); nsh_max_patch = max(nsh); sp.nsh = cat (2, sp.nsh, nsh); if (msh_patch.nel > 0) + if (nsh_max > nsh_max_patch) + connectivity(nsh_max_patch+1:nsh_max,:) = 0; + if (isfield (sp_patch, 'shape_functions')); shape_funs(:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_gradients')); shape_fun_grads(:,:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_hessians')); shape_fun_hess(:,:,:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_laplacians')); shape_fun_lapl(:,nsh_max_patch+1:nsh_max,:) = 0; end + elseif (nsh_max_patch > nsh_max) + sp.connectivity(nsh_max+1:nsh_max_patch,:) = 0; + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions(:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients(:,:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians(:,:,:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians(:,nsh_max+1:nsh_max_patch,:) = 0; end + end sp.connectivity = cat (2, sp.connectivity, connectivity); if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end From 80186ac8865a99dc40213515a7990e130e3785dd Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Jul 2021 18:57:30 +0200 Subject: [PATCH 119/366] Output in row vector, and second output for msh_cells_near_vertex --- .../multipatch/@msh_multipatch/msh_cells_near_vertex.m | 7 +++++-- .../multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m index 629f50c6..96381c55 100644 --- a/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m +++ b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m @@ -1,6 +1,6 @@ % MSH_CELLS_NEAR_VERTEX: Identify the elements adjacent to given vertices % -% elems_near_vertex = msh_cells_near_vertex (msh, vertices) +% [all_adjacent_elemens, elems_near_vertex] = msh_cells_near_vertex (msh, vertices) % % INPUT: % @@ -9,6 +9,7 @@ % % OUTPUT: % +% all_adjacent_elements: elements adjacents to any of the input vertices. % elems_near_vertex: for each vertex in the input, list of elements % adjacent to the vertex (cell-array, to allow different valences). % @@ -27,12 +28,13 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function elems_adj_to_vertex = msh_cells_near_vertex (msh, vertices) +function [all_adj_elems, elems_adj_to_vertex] = msh_cells_near_vertex (msh, vertices) nvert = numel (vertices); elems_adj_to_vertex = cell (nvert, 1); shifting_index = cumsum ([0 msh.nel_per_patch]); +all_adj_elems = []; for ivert = 1:nvert elems = []; patches = vertices(ivert).patches; @@ -51,6 +53,7 @@ elems = [elems, new_elem]; end elems_adj_to_vertex{ivert} = elems; + all_adj_elems = union (all_adj_elems, elems); end end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index a27e8ec8..2ed8b10d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -36,11 +36,11 @@ cell_indices = cell (numel(patch_indices), 1); Nelem = cumsum ([0 msh.nel_per_patch]); -for iptc = patch_indices - patch = space.vertices(vertex_index).patches(iptc); +for iptc = 1:numel(patch_indices) + patch = space.vertices(vertex_index).patches(patch_indices(iptc)); [bsp_indices, ~] = find (space.Cpatch{patch}(:,space.dofs_on_vertex{vertex_index})); [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); - cell_indices{iptc} = Nelem(patch) + aux_cell_indices; + cell_indices{iptc} = Nelem(patch) + aux_cell_indices(:).'; end end \ No newline at end of file From 577958f331bbf0e2b109e73e96a5c8f7d1328f17 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 22 Sep 2021 10:33:36 +0200 Subject: [PATCH 120/366] To use new version of the constructor --- geopdes/inst/multipatch/mp_solve_laplace_C1.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index 90bfe344..5d6b6ef8 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -88,9 +88,10 @@ sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); end +[edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); msh = msh_multipatch (msh, boundaries); % space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); -space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); clear sp % Compute and assemble the matrices From 5e402a72a18116bda17b24c466e26ff69b1f5744 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 22 Sep 2021 16:36:37 +0200 Subject: [PATCH 121/366] Fixed bug --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m index a40be7cb..6aac47e2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -35,7 +35,7 @@ % along with Octave; see the file COPYING. If not, see % . -function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex) +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex, hessuex) if (space.npatch ~= msh.npatch) error ('The number of patches does not coincide') From 59db48848f77d33be286a9ff808a7c3ae679ea1b Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 22 Sep 2021 16:37:02 +0200 Subject: [PATCH 122/366] First version of Dirichlet boundary conditions. To be fixed --- .../sp_bilaplacian_drchlt_C1.m | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m new file mode 100644 index 00000000..a3bd889b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -0,0 +1,61 @@ +function [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) + +% refs should be the whole boundary, for now +M = spalloc (space.ndof, space.ndof, space.ndof); +rhs = zeros (space.ndof, 1); + +M2 = spalloc (space.ndof, space.ndof, space.ndof); +rhs2 = zeros (space.ndof, 1); + +drchlt_dofs = []; +drchlt_dofs2 = []; + +boundaries = msh.boundaries; +for iref = refs + href = @(varargin) h(varargin{:}, iref); + for bnd_side = 1:boundaries(iref).nsides + iptc_bnd = sum([boundaries(1:iref-1).nsides]) + bnd_side; + iptc = boundaries(iref).patches(bnd_side); + iside = boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd_struct = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + + [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); + [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); + + drchlt_dofs = union (drchlt_dofs, icol); + drchlt_dofs2 = union (drchlt_dofs2, jcol); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coeff_at_qnodes = ones (size(x{1})); + dudn_at_qnodes = dudn (x{:},iref); + + M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); + + M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + + end +end + +u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); + +uu = sparse (space.ndof, 1); +uu(drchlt_dofs) = u_drchlt; + +drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); +rhs2 = rhs2 - M2 * uu; +u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); + +uu(drchlt_dofs2) = u_drchlt2; + +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +u_drchlt = uu(drchlt_dofs); + +end \ No newline at end of file From 0b7a146f34f2560c760fe4f837c0e9d984c75d06 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 22 Sep 2021 16:37:38 +0200 Subject: [PATCH 123/366] Solver for the bilaplacian --- .../inst/multipatch/mp_solve_bilaplace_C1.m | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 geopdes/inst/multipatch/mp_solve_bilaplace_C1.m diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m new file mode 100644 index 00000000..a447ae6e --- /dev/null +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -0,0 +1,104 @@ +% MP_SOLVE_BILAPLACE: solve the bilaplacian problem in a multipatch geometry. +% +% USAGE: +% +% [geometry, msh, space, u] = +% mp_solve_bilaplace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - c_diff: diffusion coefficient (epsilon in the equation) +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% - h: function for Dirichlet boundary condition +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: array of geometry structures (see geo_load) +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% u: the computed degrees of freedom +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 2 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_laplace_C1 (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +[edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); +msh = msh_multipatch (msh, boundaries); +% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); +clear sp + +% Compute and assemble the matrices +stiff_mat = op_gradgradu_gradgradv_mp (space, space, msh, c_diff); +rhs = op_f_v_mp (space, msh, f); + + +u = zeros (space.ndof, 1); +[u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); +u(drchlt_dofs) = u_drchlt; + +int_dofs = setdiff (1:space.ndof, drchlt_dofs); +rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; %zeros(length(int_dofs),1)-(abs(stiff_mat(int_dofs, drchlt_dofs))>1e-14)*ones(length(drchlt_dofs),1);%rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; + +% Solve the linear system +u(int_dofs) = stiff_mat(int_dofs,int_dofs) \ rhs(int_dofs); + +end From 21bf86e14d204c0df1767589b2df46a885c67d99 Mon Sep 17 00:00:00 2001 From: cebsare Date: Tue, 26 Oct 2021 15:35:13 +0200 Subject: [PATCH 124/366] Constructor modified to add to output structure contaning the matrices employed to express vertex functions as standard B-splines --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d3babbed..ff8af5a2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -149,9 +149,12 @@ sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); end - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); +%Sigmas, K and V matrices used in the construction of vertex functions + sp.vertex_function_matrices=v_fun_matrices; + % Total number of functions, and of functions of each type sp.ndof_edges = sum (ndof_per_interface); sp.ndof_vertices = sum (ndof_per_vertex); @@ -205,7 +208,7 @@ end -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) % OUTPUT from compute_coefficients % ndof_per_interface: number of edge functions on each interface, array of size 1 x numel(interfaces); % CC_edges: cell array of size 2 x numel(interfaces), the two corresponds @@ -218,6 +221,9 @@ % The matrix CC_vertices{jj}{ii} has size sp.ndof_per_patch(patch) x ndof_per_vertex(ii) % with patch = vertices(jj).patches(ii). +% Initialize cell array containing sigma, K and V matrices for each vertex +v_fun_matrices=cell(2, numel(vertices)); + %Initialize output variables with correct size ndof_per_interface = zeros (1, numel(interfaces_all)); ndof_per_vertex = 6*ones(1,numel(vertices)); @@ -410,6 +416,9 @@ operations = vertices(kver).patch_reorientation; edge_orientation = vertices(kver).edge_orientation; + %Initializing the cell-array containing, for vertex kver, K and V matrices + KV_matrices=cell(1,valence_p); + geo_local = reorientation_patches (operations, geometry(patches)); % Precompute the derivatives and compute sigma @@ -427,6 +436,8 @@ sigma = sigma + norm (derivatives_new1{iptc}, Inf); end sigma = pp*(kk+1)*valence_p/sigma; + %Storing sigma for output + v_fun_matrices{1,kver}=sigma; for ipatch = 1:valence_p prev_edge = ipatch; @@ -527,7 +538,12 @@ end end CC_vertices{kver}{ipatch} = E_prev*M_prev + E_next*M_next - VV; + %Storing the matrices for output + KV_matrices{ipatch}.K_prev=M_prev; + KV_matrices{ipatch}.K_next=M_next; + KV_matrices{ipatch}.V=VV; end + v_fun_matrices{2,kver}=KV_matrices; end end From f9635e8e447c3aa1c7471164e2caa92b0dadd021 Mon Sep 17 00:00:00 2001 From: cesare Date: Tue, 16 Nov 2021 17:27:54 +0100 Subject: [PATCH 125/366] sp_multipatch_C1 modified to compute gluing data for surfaces, still not computing vertex functions for surfaces --- .../@sp_multipatch_C1/sp_multipatch_C1.asv | 902 ++++++++++++++++++ .../@sp_multipatch_C1/sp_multipatch_C1.m | 195 +++- 2 files changed, 1089 insertions(+), 8 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv new file mode 100644 index 00000000..058470c3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv @@ -0,0 +1,902 @@ +% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity +% +% sp = sp_multipatch_C1 (spaces, msh, geometry, edges, vertices) +% +% INPUT: +% +% spaces: cell-array of space objects, one for each patch (see sp_scalar) +% msh: mesh object that defines the multipatch mesh (see msh_multipatch) +% geometry: geometry struct (see mp_geo_load) +% edges: struct array similar to interfaces (see vertices_struct) +% vertices: struct array with vertex information (see vertices_struct) +% +% OUTPUT: +% +% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space (always equal to one) +% ndof (scalar) total number of degrees of freedom after gluing patches together +% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% ndof_interior (scalar) total number of interior degrees of freedom +% ndof_edges (scalar) total number of edge degrees of freedom +% ndof_vertices (scalar) total number of vertex degrees of freedom +% interior_dofs_per_patch (1 x npatch cell-array) local number of interior functions on each patch +% dofs_on_edge (1 x nedges cell-array) global numbering of edge functions on each edge +% dofs_on_vertex (1 x nvertices cell-array) global numbering of the six functions on each vertex +% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar) +% Cpatch (1 x npatch cell-array) coefficients of the linear combination of basis functions as standard B-splines, +% on each patch. The matrix Cpatch{iptc} has size ndof_per_patch(iptc) x ndof +% constructor function handle function handle to construct the same discrete space in a different msh +% +% METHODS +% Methods that give a structure with all the functions computed in a certain subset of the mesh +% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements +% +% Methods for post-processing, that require a computed vector of degrees of freedom +% sp_l2_error: compute the error in L2 norm +% sp_h1_error: compute the error in H1 norm +% sp_h2_error: compute the error in H2 norm +% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch +% sp_plot_solution: plot the solution in Matlab +% +% Methods for basic connectivity operations +% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements +% sp_get_cells: compute the cells on which a list of functions do not vanish +% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% +% Other methods +% sp_refine: generate a refined space, and subdivision matrices for the univariate spaces +% +% Copyright (C) 2015-2021 Rafael Vazquez +% Copyright (C) 2019-2021 Cesare Bracco +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces_all, vertices) + + if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) + error ('All the spaces in the array should be of the same class') + end + aux = struct ([spaces{:}]); + + sp.npatch = numel (spaces); + if (sp.npatch ~= msh.npatch) + error ('The list of spaces does not correspond to the mesh') + end + +% if (msh.ndim ~= 2 || msh.rdim ~= 2) +% error ('Only implemented for planar surfaces') +% end + + for iptc = 1:numel(geometry) + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); + if (any ([mult{:}] < 2)) + error ('The regularity should be at most degree minus two') + end + for idim = 1:2 + if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) + error ('The regularity should not be lower than one') + end + end + end + + sp.ncomp = spaces{1}.ncomp; + sp.transform = spaces{1}.transform; + + if (~all ([aux.ncomp] == 1)) + error ('The number of components should be the same for all the spaces, and equal to one') + end + for iptc = 1:sp.npatch + if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) + error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') + end + if (~strcmpi (spaces{iptc}.space_type, 'spline')) + error ('C1 continuity is only implemented for splines, not for NURBS') + end + end + + sp.ndof = 0; + sp.ndof_per_patch = [aux.ndof]; + sp.sp_patch = spaces; + +% Knot vectors of auxiliary spaces + knots0 = cell (sp.npatch, 1); knots1 = knots0; + for iptc = 1:sp.npatch + knots = spaces{iptc}.knots; + breaks = cellfun (@unique, knots, 'UniformOutput', false); + for idim = 1:msh.ndim + mult = histc (knots{idim}, breaks{idim}); + mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; + mult1{idim} = mult - 1; + end + knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); + knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); + end + sp.knots0_patches = knots0; + sp.knots1_patches = knots1; + +% Computation of the number of degrees of freedom, and the coefficients to +% express them as linear combinations of B-splines. +% See the function compute_coefficients below for details. + sp.ndof_interior = 0; + for iptc = 1:sp.npatch + interior_dofs = 1:spaces{iptc}.ndof; + for intrfc = 1:numel(interfaces_all) + patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; + sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; + [is_interface,position] = ismember (iptc, patches); + if (is_interface) + sp_bnd = spaces{iptc}.boundary(sides(position)); + interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); + end + end + sp.interior_dofs_per_patch{iptc} = interior_dofs; + sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + end + + [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... + compute_coefficients (sp, msh, geometry, interfaces_all, vertices); + +%Sigmas, K and V matrices used in the construction of vertex functions + sp.vertex_function_matrices=v_fun_matrices; + +% Total number of functions, and of functions of each type + sp.ndof_edges = sum (ndof_per_interface); + sp.ndof_vertices = sum (ndof_per_vertex); + sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; + +% Store the coefficients for matrix change in Cpatch + Cpatch = cell (sp.npatch, 1); + numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + for iptc = 1:sp.npatch + Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); + Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + speye (numel (sp.interior_dofs_per_patch{iptc})); + end + + sp.dofs_on_edge = cell (1, numel(interfaces_all)); + for intrfc = 1:numel(interfaces_all) + global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + sp.dofs_on_edge{intrfc} = global_indices; + patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; + for iptc = 1:numel(patches) + Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; + end + end + + sp.dofs_on_vertex = cell (1, numel(vertices)); + for ivrt = 1:numel(vertices) + global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + sp.dofs_on_vertex{ivrt} = global_indices; + for iptc = 1:vertices(ivrt).valence_p + patch = vertices(ivrt).patches(iptc); + Cpatch{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; + end + end + + sp.Cpatch = Cpatch; + +% I store this for simplicity + sp.interfaces = interfaces_all; + sp.vertices = vertices; + sp.geometry = geometry; + + sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces_all, vertices); + function spaux = patches_constructor (spaces, MSH) + for ipatch = 1:MSH.npatch + spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); + end + end + + sp = class (sp, 'sp_multipatch_C1'); +end + + +function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) +% OUTPUT from compute_coefficients +% ndof_per_interface: number of edge functions on each interface, array of size 1 x numel(interfaces); +% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds +% to the two patches on the interface. The matrix CC_edges{ii,jj} has size +% sp.ndof_per_patch(patch) x ndof_per_interface(jj) +% with patch = interfaces(jj).patches(ii); +% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices). Even if the value is always six. +% CC_vertices: cell array of size 1 x numel(vertices), each entry containin another +% cell-array of size 1 x vertices(ii).valence_p (local number of patches) +% The matrix CC_vertices{jj}{ii} has size sp.ndof_per_patch(patch) x ndof_per_vertex(ii) +% with patch = vertices(jj).patches(ii). + +% Initialize cell array containing sigma, K and V matrices for each vertex +v_fun_matrices=cell(2, numel(vertices)); + +%Initialize output variables with correct size +ndof_per_interface = zeros (1, numel(interfaces_all)); +ndof_per_vertex = 6*ones(1,numel(vertices)); + +CC_edges = cell (2, numel (interfaces_all)); +CC_edges_discarded = cell (2, numel (interfaces_all)); +CC_vertices = cell (1, numel(vertices)); +for jj = 1:numel(vertices) + CC_vertices{jj} = cell (1,vertices(jj).valence_p); + for kk=1:vertices(jj).valence_p + CC_vertices{jj}{kk}=zeros(space.sp_patch{kk}.ndof,6); + end +end + +pp = space.sp_patch{1}.degree(1); +breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); +kk = numel(breaks_m{1}) - 2; +mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); +reg = pp - max(mult(2:end-1)); + +all_alpha0 = zeros(numel(interfaces_all),2); +all_alpha1 = zeros(numel(interfaces_all),2); +all_beta0 = zeros(numel(interfaces_all),2); +all_beta1 = zeros(numel(interfaces_all),2); + +%Computation of CC_edges +for iref = 1:numel(interfaces_all) + patches = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; + npatches_on_edge = numel (patches); + operations = interfaces_all(iref).operations; +% Auxiliary geometry with orientation as in the paper + geo_local = reorientation_patches (operations, geometry(patches)); + sides = [1 3]; + +% Compute gluing data + geo_map_jac = cell (npatches_on_edge, 1); + for ii = 1:npatches_on_edge + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); + knt = geo_local(ii).nurbs.knots; + order = geo_local(ii).nurbs.order; + for idim = 1:msh.ndim + grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; + brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); + msh_side_interior = msh_precompute (msh_side_interior); + geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% if msh.ndim+1==msh.rdim +% geo_map_jac_reduced{ii}=geo_map_jac{ii}(:,:,:,[1 end]); +% DuFR_z = reshape (geo_map_jac_reduced{1}(3,1,:,:), ngrev, 1); +% DvFL_z = reshape (geo_map_jac_reduced{2}(3,2,:,:), ngrev, 1); +% DvFR_z = reshape (geo_map_jac_reduced{1}(3,2,:,:), ngrev, 1); +% end + end + +% if msh.ndim+1~=msh.rdim || planar_surf + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); +% else +% grev_pts_reduced{1}=grev_pts{1}([1 end]); +% grev_pts_reduced{2}=grev_pts{2}([1 end]); +% [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); +% end + clear geo_map_jac msh_grev msh_side_interior grev_pts + %clear geo_map_jac geo_map_jac_reduced msh_grev msh_side_interior grev_pts + + %Saving alphas and betas (first column=i_0, second column=i_1) + all_alpha0(iref,:) = alpha0; + all_alpha1(iref,:) = alpha1; + all_beta0(iref,:) = beta0; + all_beta1(iref,:) = beta1; + +% Compute the Greville points, and the auxiliary mesh and space objects for +% functions with reduced degree or increased regularity + for ii = 1:npatches_on_edge +%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] + ind2 = ceil (sides(ii)/2); + ind1 = setdiff (1:msh.ndim, ind2); + + brk = cell (1,msh.ndim); + grev_pts = cell (1, msh.ndim); + degrees = degree_reorientation (space.sp_patch{patches(ii)}.degree, operations(ii,3)); + degree = degrees(ind1); + + knots = knot_vector_reorientation (space.sp_patch{patches(ii)}.knots, operations(ii,:)); + knots0 = knot_vector_reorientation (space.knots0_patches{patches(ii)}, operations(ii,:)); + knots0 = knots0{ind1}; + knots1 = knot_vector_reorientation (space.knots1_patches{patches(ii)}, operations(ii,:)); + knots1 = knots1{ind1}; + for idim = 1:msh.ndim + grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); + grev_pts{idim} = grev_pts{idim}(:)'; + brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; + end + msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); + +% Degree and first length in the direction normal to the interface + degu = degrees(ind2); + knt = unique (knots{ind2}); + tau1 = knt(2) - knt(1); + +% sp_aux contains the value and derivatives of the basis functions, at the Greville points + msh_side = msh_eval_boundary_side (msh_grev, sides(ii)); + msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); + sp_aux = sp_bspline (knots, degrees, msh_side_interior); + +% Univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) and N^{p,r} on the interface + sp0 = sp_bspline (knots0, degree, msh_grev.boundary(sides(ii))); + sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(sides(ii))); + sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); + sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); + + knotsn = knots{ind1}; + spn = sp_bspline (knotsn, degree, msh_grev.boundary(sides(ii))); + spn_struct = sp_precompute_param (spn, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); + +% Matrix for the linear systems + A = sparse (msh_side.nel, msh_side.nel); + for jj = 1:msh_side.nel + A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); + end + +%alphas and betas + alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; + beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; + +% RHS and solution of the linear systems, (14)-(16) in Mario's notes + rhss = sparse (msh_side.nel, sp0_struct.ndof); + for jj = 1:msh_side.nel + rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); + end + coeff0 = A \ rhss; + coeff0(abs(coeff0) < 1e-12) = 0; % Make more sparse + + rhsb = sparse (msh_side.nel, sp0_struct.ndof); + if (ii == 1) % paper case, (sides(ii) == 1) + val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); + elseif (ii == 2) %The other paper case, (sides(ii) == 3) + val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); + end + val = val_grad * (tau1 / degu)^2; + for jj = 1:msh_side.nel + val_aux = -val * beta(jj); + rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; + end + rhsb = rhsb + rhss; + coeff1 = A \ rhsb; + coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse + + rhsc = sparse (msh_side.nel, sp1_struct.ndof); + val = val_grad* (tau1 / degu); + for jj = 1:msh_side.nel + val_aux = val * alpha(jj)* (-1)^(ii+1); + rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; + end + coeff2 = A \ rhsc; + coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse + +% Pass the coefficients to the tensor product basis + ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; + ndof_dir_original = space.sp_patch{patches(ii)}.ndof_dir; + if (ii == 1) %(sides(ii) == 1) + ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); + ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); + elseif (ii == 2) %(sides(ii) == 3) + ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); + ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); + end + indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); + ind0_ornt = indices_reoriented(ind0); + ind1_ornt = indices_reoriented(ind1); + +% Store the coefficients in CC_edges, and compute the number of functions + ndof_edge = sp0_struct.ndof + sp1_struct.ndof; + trace_functions = 4:sp0_struct.ndof-3; + deriv_functions = sp0_struct.ndof + (3:sp1_struct.ndof-2); + active_functions = union (trace_functions, deriv_functions); + discarded_functions = setdiff (1:ndof_edge, active_functions); + + CC = sparse (space.ndof_per_patch(patches(ii)), ndof_edge); + CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; + CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; + CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; + + ndof_per_interface(iref) = numel(active_functions); + CC_edges{ii,iref} = sparse (space.ndof_per_patch(patches(ii)), ndof_per_interface(iref)); + CC_edges{ii,iref} = CC(:,active_functions); + CC_edges_discarded{ii,iref} = CC(:,discarded_functions); + end +end + +if msh.ndim+1~=msh.rdim +% Computation of CC_vertices +% Auxiliary constants to deal with different regularity cases in the M matrices +if (reg < pp-2) + const1 = 2; const2 = 1; +else + const1 = 3; const2 = 2; +end + +for kver = 1:numel(vertices) + edges = vertices(kver).edges; + patches = vertices(kver).patches; + valence_e = vertices(kver).valence_e; + valence_p = vertices(kver).valence_p; + operations = vertices(kver).patch_reorientation; + edge_orientation = vertices(kver).edge_orientation; + + %Initializing the cell-array containing, for vertex kver, K and V matrices + KV_matrices=cell(1,valence_p); + + geo_local = reorientation_patches (operations, geometry(patches)); + +% Precompute the derivatives and compute sigma + sigma = 0; + for iptc = 1:valence_p + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; + end + msh_pts_der1 = msh_cartesian (brk, {0 0}, [], geo_local(iptc),'boundary', true, 'der2', true); + msh_der = msh_precompute (msh_pts_der1); + derivatives_new1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives_new2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} + + sigma = sigma + norm (derivatives_new1{iptc}, Inf); + end + sigma = pp*(kk+1)*valence_p/sigma; + %Storing sigma for output + v_fun_matrices{1,kver}=sigma; + + for ipatch = 1:valence_p + prev_edge = ipatch; + next_edge = mod(ipatch, valence_e) + 1; + +% Compute gluing data, and edge functions from CC_edges_discarded + if (edge_orientation(prev_edge) == 1) + alpha_prev = all_alpha0(edges(prev_edge),2); + beta_prev = all_beta0(edges(prev_edge),2); + alpha_der_prev = -all_alpha0(edges(prev_edge),2) + all_alpha1(edges(prev_edge),2); + beta_der_prev = -all_beta0(edges(prev_edge),2) + all_beta1(edges(prev_edge),2); + E_prev = CC_edges_discarded{2,edges(prev_edge)}(:,[1 2 3 7 8]); + else + alpha_prev = all_alpha1(edges(prev_edge),1); + beta_prev = -all_beta1(edges(prev_edge),1); + alpha_der_prev = all_alpha0(edges(prev_edge),1) - all_alpha1(edges(prev_edge),1); + beta_der_prev = -all_beta0(edges(prev_edge),1) + all_beta1(edges(prev_edge),1); + E_prev = CC_edges_discarded{1,edges(prev_edge)}(:,[6 5 4 10 9]); + E_prev(:,[4 5]) = -E_prev(:,[4 5]); + end + if (edge_orientation(next_edge) == 1) + alpha_next = all_alpha0(edges(next_edge),1); + beta_next = all_beta0(edges(next_edge),1); + alpha_der_next = -all_alpha0(edges(next_edge),1) + all_alpha1(edges(next_edge),1); + beta_der_next = -all_beta0(edges(next_edge),1) + all_beta1(edges(next_edge),1); + E_next = CC_edges_discarded{1,edges(next_edge)}(:,[1 2 3 7 8]); + else + alpha_next = all_alpha1(edges(next_edge),2); + beta_next = -all_beta1(edges(next_edge),2); + alpha_der_next = all_alpha0(edges(next_edge),2) - all_alpha1(edges(next_edge),2); + beta_der_next = -all_beta0(edges(next_edge),2) + all_beta1(edges(next_edge),2); + E_next = CC_edges_discarded{2,edges(next_edge)}(:,[6 5 4 10 9]); + E_next(:,[4 5]) = -E_next(:,[4 5]); + end + + Du_F = derivatives_new1{ipatch}(:,1); + Dv_F = derivatives_new1{ipatch}(:,2); + Duu_F = derivatives_new2{ipatch}(:,1,1); + Duv_F = derivatives_new2{ipatch}(:,1,2); + Dvv_F = derivatives_new2{ipatch}(:,2,2); + +% Edge information + t0_prev = Du_F; + t0_next = Dv_F; + t0p_prev = Duu_F; + t0p_next = Dvv_F; + + d0_prev = -(Dv_F + beta_prev * Du_F) / alpha_prev; + d0_next = (Du_F + beta_next * Dv_F) / alpha_next; + d0p_prev = ( alpha_der_prev * (Dv_F + beta_prev*Du_F) - ... + alpha_prev * (Duv_F + beta_der_prev*Du_F + beta_prev*Duu_F)) / alpha_prev^2; + d0p_next = (-alpha_der_next * (Du_F + beta_next*Dv_F) + ... + alpha_next * (Duv_F + beta_der_next*Dv_F + beta_next*Dvv_F)) / alpha_next^2; + +% Compute M and V matrices + ndof = space.sp_patch{patches(ipatch)}.ndof; + M_prev = sparse (5,6); M_next = sparse (5,6); + VV = sparse (ndof,6); + + ndof_dir = space.sp_patch{patches(ipatch)}.ndof_dir; + all_indices = indices_reorientation (ndof_dir, operations(ipatch,:)); + corner_4dofs = all_indices(1:2,1:2); + jfun = 1; + for j1 = 0:2 + for j2 = 0:2-j1 + mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; + vec_deltas = [(j1==1)*(j2==0); (j1==0)*(j2==1)]; + c0 = (j1==0)*(j2==0); + %M_{i_{m-1},i} + c1_a = vec_deltas.'*t0_prev; + c2_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; + d0_a = vec_deltas.'*d0_prev; + d1_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; + + %M_{i_{m+1},i} + c1_b = vec_deltas.'*t0_next; + c2_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; + d0_b = vec_deltas.'*d0_next; + d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; + + M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+const1*c1_a/(pp*(kk+1))+const2*c2_a/(pp*(pp-1)*(kk+1)^2), ... + d0_a/(pp*(kk+1)), ... + d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; + M_next(:,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_b/(pp*(kk+1)), ... + c0+const1*c1_b/(pp*(kk+1))+const2*c2_b/(pp*(pp-1)*(kk+1)^2), ... + d0_b/(pp*(kk+1)), ... + d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; + %V_{i_m,i} + e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; + VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... + c0+c1_a/(pp*(kk+1)), ... + c0+c1_b/(pp*(kk+1)), ... + c0+(c1_a+c1_b+e11/(pp*(kk+1)))/(pp*(kk+1))]'; + jfun = jfun+1; + end + end + CC_vertices{kver}{ipatch} = E_prev*M_prev + E_next*M_next - VV; + %Storing the matrices for output + KV_matrices{ipatch}.K_prev=M_prev; + KV_matrices{ipatch}.K_next=M_next; + KV_matrices{ipatch}.V=VV; + end + v_fun_matrices{2,kver}=KV_matrices; +end +end + +end + +function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) +% OUTPUT from gluing data +% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. +% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring +% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). + +% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. + if (numel (geo_map_jac) == 1) + alpha0 = [1 1]; + alpha1 = [1 1]; + beta0 = [0 0]; + beta1 = [0 0]; + return + end + + if size(geo_map_jac{1},1)==3 + grev_pts_red{1}=grev_pts{1}([1 end]); + grev_pts_red{2}=grev_pts{2}([1 end]); + for ii=1:length(geo_map_jac) + geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); + end + if (side(2)==1 || side(2)==2) + v = grev_pts_red{2}(:); + else + v = grev_pts_red{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); + DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); + DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); + DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; + (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; + rank_A=rank(A_full); + end + + if rank_A<5 || + % Assemble and solve G^1 conditions system + if (side(2)==1 || side(2)==2) + v = grev_pts{2}(:); + else + v = grev_pts{1}(:); + end + ngrev = numel(v); + + DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); % FIX: not a square matrix + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = 1; + alpha0_n(2) = sols(1); + alpha1_n(2) = sols(2); + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end + + % Normalize the alphas + C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; + C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); + gamma = 3*C2/(2*C1); + alpha0(1) = alpha0_n(1)*gamma; + alpha1(1) = alpha1_n(1)*gamma; + alpha0(2) = alpha0_n(2)*gamma; + alpha1(2) = alpha1_n(2)*gamma; + bbeta0 = beta0_n*gamma; + bbeta1 = beta1_n*gamma; + bbeta2 = beta2_n*gamma; + + % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. + alpha_R_0 = alpha0(1); + alpha_R_1 = alpha1(1); + alpha_R_12 = (alpha0(1)+alpha1(1))/2; + alpha_L_0 = alpha0(2); + alpha_L_1 = alpha1(2); + alpha_L_12 = (alpha0(2)+alpha1(2))/2; + beta_0 = bbeta0; + beta_1 = bbeta2; + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; + + % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta + M = [alpha_R_0 0 alpha_L_0 0; ... + 0 alpha_R_1 0 alpha_L_1; ... + alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; + + if (rank(M)==3) + % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R + quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + + % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where + a = quant2; b = quant1; + c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; + e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; + + %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L + C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; + C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; + beta0(1) = -C2/(2*C1); + beta1(1) = a + b*beta0(1); + beta0(2) = c + d*beta0(1); + beta1(2) = e + f*beta0(1); + + else + % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: + % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; + c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; + + % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L + M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b = [-b*c-2*a*b; -a*d-2*c*d]; + sol = M2\M2b; + beta0(1)= sol(1); + beta1(1)= sol(2); + beta0(2)= a + b*beta0(1); + beta1(2)= c + d*beta1(1); + end + +end + + +function [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, side) +% OUTPUT from gluing data +% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. +% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring +% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). + +% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. + if (numel (geo_map_jac) == 1) + alpha0 = [1 1]; + alpha1 = [1 1]; + beta0 = [0 0]; + beta1 = [0 0]; + return + end + + % Assemble and solve G^1 conditions system + if (side(2)==1 || side(2)==2) + v = grev_pts{2}(:); + else + v = grev_pts{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); + DuFR_z = reshape (geo_map_jac{1}(3,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); + DvFL_z = reshape (geo_map_jac{2}(3,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); + DvFR_z = reshape (geo_map_jac{1}(3,2,:,:), ngrev, 1); + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; + (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; + + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); % FIX: not a square matrix + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = 1; + alpha0_n(2) = sols(1); + alpha1_n(2) = sols(2); + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end + + % Normalize the alphas + C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; + C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); + gamma = 3*C2/(2*C1); + alpha0(1) = alpha0_n(1)*gamma; + alpha1(1) = alpha1_n(1)*gamma; + alpha0(2) = alpha0_n(2)*gamma; + alpha1(2) = alpha1_n(2)*gamma; + bbeta0 = beta0_n*gamma; + bbeta1 = beta1_n*gamma; + bbeta2 = beta2_n*gamma; + + % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. + alpha_R_0 = alpha0(1); + alpha_R_1 = alpha1(1); + alpha_R_12 = (alpha0(1)+alpha1(1))/2; + alpha_L_0 = alpha0(2); + alpha_L_1 = alpha1(2); + alpha_L_12 = (alpha0(2)+alpha1(2))/2; + beta_0 = bbeta0; + beta_1 = bbeta2; + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; + + % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta + M = [alpha_R_0 0 alpha_L_0 0; ... + 0 alpha_R_1 0 alpha_L_1; ... + alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; + + if (rank(M)==3) + % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R + quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + + % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where + a = quant2; b = quant1; + c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; + e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; + + %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L + C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; + C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; + beta0(1) = -C2/(2*C1); + beta1(1) = a + b*beta0(1); + beta0(2) = c + d*beta0(1); + beta1(2) = e + f*beta0(1); + + else + % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: + % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; + c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; + + % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L + M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b = [-b*c-2*a*b; -a*d-2*c*d]; + sol = M2\M2b; + beta0(1)= sol(1); + beta1(1)= sol(2); + beta0(2)= a + b*beta0(1); + beta1(2)= c + d*beta1(1); + end + +end + + +% Functions to deal with general orientation of the patches +function geo_reoriented = reorientation_patches (operations, geometry) + nrb_patches = [geometry.nurbs]; + for ii = 1:numel(nrb_patches) + if (operations(ii,1)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); + end + if (operations(ii,2)) + nrb_patches(ii) = nrbreverse (nrb_patches(ii), 2); + end + if (operations(ii,3)) + nrb_patches(ii) = nrbtransp (nrb_patches(ii)); + end + end + + geo_reoriented = mp_geo_load (nrb_patches); +% [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); +% if (numel (nrb_patches) == 2) +% if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) +% error('The reorientation is wrong') +% end +% end +end + +function knots = knot_vector_reorientation (knots, operations) + if (operations(1)) + knots{1} = sort (1 - knots{1}); + end + if (operations(2)) + knots{2} = sort (1-knots{2}); + end + if (operations(3)) + knots([2 1]) = knots([1 2]); + end +end + +function degree = degree_reorientation (degree, transposition) + if (transposition) + degree = degree([2 1]); + end +end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index ff8af5a2..00addbd9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -77,9 +77,9 @@ error ('The list of spaces does not correspond to the mesh') end - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end +% if (msh.ndim ~= 2 || msh.rdim ~= 2) +% error ('Only implemented for planar surfaces') +% end for iptc = 1:numel(geometry) knots = spaces{iptc}.knots; @@ -232,7 +232,10 @@ CC_edges_discarded = cell (2, numel (interfaces_all)); CC_vertices = cell (1, numel(vertices)); for jj = 1:numel(vertices) - CC_vertices{jj} = cell (1,numel(vertices(jj).valence_p)); + CC_vertices{jj} = cell (1,vertices(jj).valence_p); + for kk=1:vertices(jj).valence_p + CC_vertices{jj}{kk}=zeros(space.sp_patch{kk}.ndof,6); + end end pp = space.sp_patch{1}.degree(1); @@ -270,10 +273,23 @@ msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); msh_side_interior = msh_precompute (msh_side_interior); geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) +% if msh.ndim+1==msh.rdim +% geo_map_jac_reduced{ii}=geo_map_jac{ii}(:,:,:,[1 end]); +% DuFR_z = reshape (geo_map_jac_reduced{1}(3,1,:,:), ngrev, 1); +% DvFL_z = reshape (geo_map_jac_reduced{2}(3,2,:,:), ngrev, 1); +% DvFR_z = reshape (geo_map_jac_reduced{1}(3,2,:,:), ngrev, 1); +% end end - - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); - clear geo_map_jac msh_grev msh_side_interior grev_pts + +% if msh.ndim+1~=msh.rdim || planar_surf + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides) +% else +% grev_pts_reduced{1}=grev_pts{1}([1 end]); +% grev_pts_reduced{2}=grev_pts{2}([1 end]); +% [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); +% end + clear geo_map_jac msh_grev msh_side_interior grev_pts + %clear geo_map_jac geo_map_jac_reduced msh_grev msh_side_interior grev_pts %Saving alphas and betas (first column=i_0, second column=i_1) all_alpha0(iref,:) = alpha0; @@ -400,6 +416,7 @@ end end +if msh.ndim+1~=msh.rdim % Computation of CC_vertices % Auxiliary constants to deal with different regularity cases in the M matrices if (reg < pp-2) @@ -545,6 +562,7 @@ end v_fun_matrices{2,kver}=KV_matrices; end +end end @@ -562,7 +580,37 @@ beta1 = [0 0]; return end - + + rank_A=6; + if size(geo_map_jac{1},1)==3 + grev_pts_red{1}=grev_pts{1}([1 end]); + grev_pts_red{2}=grev_pts{2}([1 end]); + for ii=1:length(geo_map_jac) + geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); + end + if (side(2)==1 || side(2)==2) + v = grev_pts_red{2}(:); + else + v = grev_pts_red{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); + DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); + DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); + DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; + (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; + rank_A=rank(A_full); + end + + if rank_A<5 || size(geo_map_jac{1},1)<3 % Assemble and solve G^1 conditions system if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); @@ -570,6 +618,7 @@ v = grev_pts{1}(:); end ngrev = numel(v); + DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); @@ -579,6 +628,8 @@ A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + end + if (rank(A_full)==6) A = A_full(:,2:end); b = -A_full(:,1); @@ -669,6 +720,134 @@ end + +function [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, side) +% OUTPUT from gluing data +% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. +% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring +% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). + +% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. + if (numel (geo_map_jac) == 1) + alpha0 = [1 1]; + alpha1 = [1 1]; + beta0 = [0 0]; + beta1 = [0 0]; + return + end + + % Assemble and solve G^1 conditions system + if (side(2)==1 || side(2)==2) + v = grev_pts{2}(:); + else + v = grev_pts{1}(:); + end + ngrev = numel(v); + DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); + DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); + DuFR_z = reshape (geo_map_jac{1}(3,1,:,:), ngrev, 1); + DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); + DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); + DvFL_z = reshape (geo_map_jac{2}(3,2,:,:), ngrev, 1); + DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); + DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); + DvFR_z = reshape (geo_map_jac{1}(3,2,:,:), ngrev, 1); + + A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; + (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; + + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); % FIX: not a square matrix + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = 1; + alpha0_n(2) = sols(1); + alpha1_n(2) = sols(2); + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end + + % Normalize the alphas + C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; + C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); + gamma = 3*C2/(2*C1); + alpha0(1) = alpha0_n(1)*gamma; + alpha1(1) = alpha1_n(1)*gamma; + alpha0(2) = alpha0_n(2)*gamma; + alpha1(2) = alpha1_n(2)*gamma; + bbeta0 = beta0_n*gamma; + bbeta1 = beta1_n*gamma; + bbeta2 = beta2_n*gamma; + + % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. + alpha_R_0 = alpha0(1); + alpha_R_1 = alpha1(1); + alpha_R_12 = (alpha0(1)+alpha1(1))/2; + alpha_L_0 = alpha0(2); + alpha_L_1 = alpha1(2); + alpha_L_12 = (alpha0(2)+alpha1(2))/2; + beta_0 = bbeta0; + beta_1 = bbeta2; + beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; + + % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta + M = [alpha_R_0 0 alpha_L_0 0; ... + 0 alpha_R_1 0 alpha_L_1; ... + alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; + + if (rank(M)==3) + % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R + quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... + (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); + + % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where + a = quant2; b = quant1; + c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; + e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; + + %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L + C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; + C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; + beta0(1) = -C2/(2*C1); + beta1(1) = a + b*beta0(1); + beta0(2) = c + d*beta0(1); + beta1(2) = e + f*beta0(1); + + else + % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: + % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where + a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; + c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; + + % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L + M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; + M2b = [-b*c-2*a*b; -a*d-2*c*d]; + sol = M2\M2b; + beta0(1)= sol(1); + beta1(1)= sol(2); + beta0(2)= a + b*beta0(1); + beta1(2)= c + d*beta1(1); + end + +end + + % Functions to deal with general orientation of the patches function geo_reoriented = reorientation_patches (operations, geometry) nrb_patches = [geometry.nurbs]; From 498eb25a4a5b7115023972c4c246a612601160af Mon Sep 17 00:00:00 2001 From: cesare Date: Wed, 17 Nov 2021 10:58:36 +0100 Subject: [PATCH 126/366] sp_multipatch_C1 modified to prepare computation of vertex functions for non-planar geometries --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 00addbd9..667ecc55 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -282,7 +282,7 @@ end % if msh.ndim+1~=msh.rdim || planar_surf - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides) + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); % else % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); @@ -437,6 +437,9 @@ KV_matrices=cell(1,valence_p); geo_local = reorientation_patches (operations, geometry(patches)); + %Here we need to further modify geo_local by rotating the parametrization + %of the patches, that is, for each ip in patches, rotate the control points + %geometry(ip).nurbs.coefs (4 x (number of control points in dir 1) x (number of control points in dir 2) matrix) % Precompute the derivatives and compute sigma sigma = 0; @@ -456,6 +459,15 @@ %Storing sigma for output v_fun_matrices{1,kver}=sigma; + %Tangent vectors + Du_F = derivatives_new1{ipatch}(:,1); + Dv_F = derivatives_new1{ipatch}(:,2); + normal=cross(Du_F,Dv_F); + unit_normal=normal/norm(normal); + r=cross(unit_normal,[0 0 1]'); + cos_theta=[0 0 1]*unit_normal; + sin_theta=norm(r); + for ipatch = 1:valence_p prev_edge = ipatch; next_edge = mod(ipatch, valence_e) + 1; From 4d6974c8ef3306f7bbd4de4c6074a1d6c1937feb Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Wed, 17 Nov 2021 13:36:02 +0100 Subject: [PATCH 127/366] Fixed vertex basis computation for surfaces --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 667ecc55..6abaad5c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -416,7 +416,6 @@ end end -if msh.ndim+1~=msh.rdim % Computation of CC_vertices % Auxiliary constants to deal with different regularity cases in the M matrices if (reg < pp-2) @@ -459,18 +458,55 @@ %Storing sigma for output v_fun_matrices{1,kver}=sigma; - %Tangent vectors - Du_F = derivatives_new1{ipatch}(:,1); - Dv_F = derivatives_new1{ipatch}(:,2); - normal=cross(Du_F,Dv_F); - unit_normal=normal/norm(normal); - r=cross(unit_normal,[0 0 1]'); - cos_theta=[0 0 1]*unit_normal; - sin_theta=norm(r); + if msh.ndim+1==msh.rdim + %Tangent vectors + Du_F = derivatives_new1{1}(:,1); + Dv_F = derivatives_new1{1}(:,2); + %Normal vector + normal=cross(Du_F,Dv_F); + unit_normal=normal/norm(normal); + %Vector orthogonal to n and z along which the geometry is rotated + %(rotation axis) + r=cross(unit_normal,[0 0 1]'); + %Angle between n and z + cos_th=[0 0 1]*unit_normal; + sin_th=norm(r); + %Rotation matrix + R=[cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... + r(1)*r(2)*(1-cos_th)+r(3)*sin_th,cos_th + r(2)^2*(1-cos_th),r(2)*r(3)*(1-cos_th)-r(1)*sin_th;... + r(1)*r(3)*(1-cos_th)-r(2)*sin_th,r(3)*r(2)*(1-cos_th)+r(1)*sin_th,cos_th + r(3)^2*(1-cos_th)]; + + for ipatch = 1:valence_p + + coeff_hom=geo_local(ipatch).nurbs.coefs; + coeff_w=coeff_hom(4,:,:); + coeff_eu=coeff_hom(1:3,:,:)./(repmat(coeff_w,3,1,1)); %Euclidean coefficients + rot_coeff=ones(4,size(coeff_eu,2),size(coeff_eu,3)); + for k=1:size(coeff_eu,3) + rot_coeff(1:3,:,k)=R*(coeff_eu(:,:,k)-coeff_eu(:,1,1))+coeff_eu(:,1,1); + end + rot_nrb(ipatch)=geometry(patches(ipatch)).nurbs; + rot_nrb(ipatch).coefs=rot_coeff; + end + + rot_geo = mp_geo_load(rot_nrb); + + for iptc = 1:valence_p + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; + end + rot_msh_pts_der1 = msh_cartesian (brk, {0 0}, [], rot_geo(iptc),'boundary', true, 'der2', true); + rot_msh_der = msh_precompute (rot_msh_pts_der1); + derivatives_new1{iptc} = rot_msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives_new2{iptc} = rot_msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} + end + end for ipatch = 1:valence_p - prev_edge = ipatch; - next_edge = mod(ipatch, valence_e) + 1; + + prev_edge = ipatch; + next_edge = mod(ipatch, valence_e) + 1; % Compute gluing data, and edge functions from CC_edges_discarded if (edge_orientation(prev_edge) == 1) @@ -502,11 +538,11 @@ E_next(:,[4 5]) = -E_next(:,[4 5]); end - Du_F = derivatives_new1{ipatch}(:,1); - Dv_F = derivatives_new1{ipatch}(:,2); - Duu_F = derivatives_new2{ipatch}(:,1,1); - Duv_F = derivatives_new2{ipatch}(:,1,2); - Dvv_F = derivatives_new2{ipatch}(:,2,2); + Du_F = derivatives_new1{ipatch}(1:2,1); + Dv_F = derivatives_new1{ipatch}(1:2,2); + Duu_F = derivatives_new2{ipatch}(1:2,1,1) + Duv_F = derivatives_new2{ipatch}(1:2,1,2) + Dvv_F = derivatives_new2{ipatch}(1:2,2,2) % Edge information t0_prev = Du_F; @@ -574,7 +610,7 @@ end v_fun_matrices{2,kver}=KV_matrices; end -end + end From 4ce8d504bb92a61e80d8559c854362aeec45f72c Mon Sep 17 00:00:00 2001 From: cesare Date: Thu, 18 Nov 2021 09:49:12 +0100 Subject: [PATCH 128/366] sp_multipatch_C1 modified simplifying the solution of the linear system coming form the G^1condition (in the computation of gluing data) --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 152 +++++++++++------- 1 file changed, 91 insertions(+), 61 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 6abaad5c..1a310f5d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -540,9 +540,9 @@ Du_F = derivatives_new1{ipatch}(1:2,1); Dv_F = derivatives_new1{ipatch}(1:2,2); - Duu_F = derivatives_new2{ipatch}(1:2,1,1) - Duv_F = derivatives_new2{ipatch}(1:2,1,2) - Dvv_F = derivatives_new2{ipatch}(1:2,2,2) + Duu_F = derivatives_new2{ipatch}(1:2,1,1); + Duv_F = derivatives_new2{ipatch}(1:2,1,2); + Dvv_F = derivatives_new2{ipatch}(1:2,2,2); % Edge information t0_prev = Du_F; @@ -629,78 +629,108 @@ return end - rank_A=6; - if size(geo_map_jac{1},1)==3 - grev_pts_red{1}=grev_pts{1}([1 end]); - grev_pts_red{2}=grev_pts{2}([1 end]); - for ii=1:length(geo_map_jac) - geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); - end - if (side(2)==1 || side(2)==2) - v = grev_pts_red{2}(:); - else - v = grev_pts_red{1}(:); - end - ngrev = numel(v); - DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); - DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); - DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); - DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); - DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); - DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); - DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); - DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); - DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); - - A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; - (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; - rank_A=rank(A_full); - end +% rank_A=6; +% if size(geo_map_jac{1},1)==3 +% grev_pts_red{1}=grev_pts{1}([1 end]); +% grev_pts_red{2}=grev_pts{2}([1 end]); +% for ii=1:length(geo_map_jac) +% geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); +% end +% if (side(2)==1 || side(2)==2) +% v = grev_pts_red{2}(:); +% else +% v = grev_pts_red{1}(:); +% end +% ngrev = numel(v); +% DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); +% DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); +% DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); +% DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); +% DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); +% DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); +% DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); +% DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); +% DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); +% +% A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... +% (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; +% (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; +% rank_A=rank(A_full); +% end +% +% if rank_A<5 || size(geo_map_jac{1},1)<3 +% % Assemble and solve G^1 conditions system +% if (side(2)==1 || side(2)==2) +% v = grev_pts{2}(:); +% else +% v = grev_pts{1}(:); +% end +% ngrev = numel(v); +% +% DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); +% DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); +% DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); +% DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); +% DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); +% DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); +% +% A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... +% (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; +% end +% if (rank(A_full)==6) +% A = A_full(:,2:end); +% b = -A_full(:,1); +% sols = A\b; +% alpha0_n(1) = 1; +% alpha1_n(1) = sols(1); +% alpha0_n(2) = sols(2); +% alpha1_n(2) = sols(3); +% beta0_n = sols(4); +% beta1_n = sols(5); +% beta2_n = sols(6); +% else +% A = A_full(:,3:end); % FIX: not a square matrix +% b = -sum(A_full(:,1:2),2); +% sols = A\b; +% alpha0_n(1) = 1; +% alpha1_n(1) = 1; +% alpha0_n(2) = sols(1); +% alpha1_n(2) = sols(2); +% beta0_n = sols(3); +% beta1_n = sols(4); +% beta2_n = sols(5); +% end - if rank_A<5 || size(geo_map_jac{1},1)<3 - % Assemble and solve G^1 conditions system if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); else v = grev_pts{1}(:); end ngrev = numel(v); - DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); + DuFR_z = reshape (geo_map_jac{1}(3,1,:,:), ngrev, 1); DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); + DvFL_z = reshape (geo_map_jac{2}(3,2,:,:), ngrev, 1); DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); + DvFR_z = reshape (geo_map_jac{1}(3,2,:,:), ngrev, 1); A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - end - - if (rank(A_full)==6) - A = A_full(:,2:end); - b = -A_full(:,1); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = sols(1); - alpha0_n(2) = sols(2); - alpha1_n(2) = sols(3); - beta0_n = sols(4); - beta1_n = sols(5); - beta2_n = sols(6); - else - A = A_full(:,3:end); % FIX: not a square matrix - b = -sum(A_full(:,1:2),2); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = 1; - alpha0_n(2) = sols(1); - alpha1_n(2) = sols(2); - beta0_n = sols(3); - beta1_n = sols(4); - beta2_n = sols(5); - end + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; + (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; + + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; %we arbitrarily set the first unknown to 1 to avoid the null solution + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); % Normalize the alphas C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; @@ -729,7 +759,7 @@ M = [alpha_R_0 0 alpha_L_0 0; ... 0 alpha_R_1 0 alpha_L_1; ... alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; - + if (rank(M)==3) % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... From cd1dff64c40d66bf6f9e620fa78ef2b9512005d9 Mon Sep 17 00:00:00 2001 From: cesare Date: Mon, 29 Nov 2021 11:53:13 +0100 Subject: [PATCH 129/366] matrix_basis_change_new__ fully running but giving not correct results for the refinement of vertex functions --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index ff8af5a2..f0822beb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -542,6 +542,8 @@ KV_matrices{ipatch}.K_prev=M_prev; KV_matrices{ipatch}.K_next=M_next; KV_matrices{ipatch}.V=VV; + KV_matrices{ipatch}.E_prev=E_prev; + KV_matrices{ipatch}.E_next=E_next; end v_fun_matrices{2,kver}=KV_matrices; end From 48d2592cae63a46890699a6c22cc3ee46ae966f4 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 2 Dec 2021 11:41:54 +0100 Subject: [PATCH 130/366] Modified the usage of gd computing function in file --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 1a310f5d..72100945 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -282,7 +282,7 @@ end % if msh.ndim+1~=msh.rdim || planar_surf - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); + [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); % else % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); From fee74dd20d2dd414b45f21f003077b3e2ed0b01e Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 6 Dec 2021 17:41:40 +0100 Subject: [PATCH 131/366] Added new variable, for simplicity --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index f0822beb..c599a43d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -163,11 +163,13 @@ % Store the coefficients for matrix change in Cpatch Cpatch = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); + speye (numel (sp.interior_dofs_per_patch{iptc})); + sp.dofs_on_patch{iptc} = shift_index_patch(iptc)+1:shift_index_patch(iptc+1); end sp.dofs_on_edge = cell (1, numel(interfaces_all)); From 70dd8c7e1b0499656281089fc780f72887c608fc Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 Jan 2022 12:19:33 +0100 Subject: [PATCH 132/366] Check for closed surfaces --- geopdes/inst/multipatch/vertices_struct.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 4e8130e1..b45edbb1 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -90,7 +90,11 @@ 'patch_reorientation', [], 'edge_orientation', [], 'boundary_vertex', []); % Inner and boundary vertex are done in a different way % For inner vertices, I set the patch with lowest number as the first one -boundary_vertices = space.boundary.dofs(:).'; +if (isempty (space.boundary)) + boundary_vertices = []; +else + boundary_vertices = space.boundary.dofs(:).'; +end for ivert = 1:space.ndof boundary_vertex = ismember (ivert, boundary_vertices); sp_edges = find(C(:,ivert)); From c69639389f1974308dae6fa5d8233d085979f001 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 Jan 2022 19:08:27 +0100 Subject: [PATCH 133/366] Use the first fundamental form for 3D surfaces --- geopdes/inst/multipatch/vertices_struct.m | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index b45edbb1..1b43c709 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -169,8 +169,10 @@ nrb_patches = [geometry(patches).nurbs]; sides = [interface.side1 interface.side2]; % Change orientation of first patch - [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + jac = geometry(patches(1)).map_der({rand(1),rand(1)}); + jacdet = geopdes_det__ (jac); +% [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1), rand(1)}); +% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1) if (sides(1) == 2) if (jacdet < 0) operations(1,:) = [1 0 0]; @@ -199,8 +201,10 @@ % Change orientation of second patch, only for inner edges if (numel(nrb_patches) == 2) - [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + jac = geometry(patches(2)).map_der({rand(1),rand(1)}); + jacdet = geopdes_det__ (jac); +% [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); +% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); if (sides(2) == 1) if (jacdet < 0) operations(2,:) = [0 0 1]; @@ -245,7 +249,10 @@ nrb = nrbreverse (nrb, [1 2]); end [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); - jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); +% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + jac_as_I_want = jac{1}; + jac_as_I_want(:,2) = jac{2}; + jacdet = geopdes_det__ (jac_as_I_want); if (jacdet < 0) operations(3) = 1; From c99cc9f0214489acb046007511f33510dcbf7852 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 3 Feb 2022 19:25:08 +0100 Subject: [PATCH 134/366] Working version for oriented surfaces --- geopdes/inst/multipatch/vertices_struct.m | 76 ++++++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 1b43c709..34d54d43 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -64,9 +64,18 @@ interfaces_bnd(N_int+hh).side2 = 0; end -% Find the operations for reorientation -for ii = 1:numel(interfaces) - interfaces(ii).operations = reorientation_edge (interfaces(ii), geometry); +% Find the operations for reparametrization +if (msh.ndim == 2 && msh.rdim == 2) + for ii = 1:numel(interfaces) + interfaces(ii).operations = reorientation_edge_planar (interfaces(ii), geometry); + end +elseif (msh.ndim == 2 && msh.rdim == 3) + % In the case of 3D surfaces, check that all patches have the same orientation as the surface + check_orientation (geometry, interfaces) + + for ii = 1:numel(interfaces) + interfaces(ii).operations = reorientation_edge_3dsurface (interfaces(ii), geometry); + end end % Correspondence between interfaces and edges of the space @@ -164,15 +173,35 @@ end -function operations = reorientation_edge (interface, geometry) + +function check_orientation (geometry, interfaces) + Nint = find ([interfaces.patch2]); Nint = Nint(end); + + coords_on_side = {0 0.5; 1 0.5; 0.5 0; 0.5 1}; %4 rows for the sides, 2 columns for the coordinates + + for iedge = 1:Nint + patches = [interfaces(iedge).patch1 interfaces(iedge).patch2]; + nrb_patches = [geometry(patches).nurbs]; + sides = [interfaces(iedge).side1 interfaces(iedge).side2]; + jac_side1 = geometry(patches(1)).map_der(coords_on_side(sides(1),:)); + jac_side2 = geometry(patches(2)).map_der(coords_on_side(sides(2),:)); + normal1 = cross (jac_side1(:,1), jac_side1(:,2)); normal1 = normal1 / norm(normal1); + normal2 = cross (jac_side2(:,1), jac_side2(:,2)); normal2 = normal2 / norm(normal2); + if (max (abs (normal1 - normal2)) > 1e-13) + mssg = sprintf('The patches at interface %d do not follow a global orientation. The involved patches are patch %d (side %d), and patch %d (side %d)', iedge, patches(1), sides(1), patches(2), sides(2)); + error (mssg); + end + end +end + + +function operations = reorientation_edge_planar (interface, geometry) patches = [interface.patch1 interface.patch2]; nrb_patches = [geometry(patches).nurbs]; sides = [interface.side1 interface.side2]; % Change orientation of first patch jac = geometry(patches(1)).map_der({rand(1),rand(1)}); jacdet = geopdes_det__ (jac); -% [~,jac] = nrbdeval (nrb_patches(1), nrbderiv(nrb_patches(1)), {rand(1), rand(1)}); -% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1) if (sides(1) == 2) if (jacdet < 0) operations(1,:) = [1 0 0]; @@ -203,8 +232,6 @@ if (numel(nrb_patches) == 2) jac = geometry(patches(2)).map_der({rand(1),rand(1)}); jacdet = geopdes_det__ (jac); -% [~,jac] = nrbdeval (nrb_patches(2), nrbderiv(nrb_patches(2)), {rand(1) rand(1)}); -% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); if (sides(2) == 1) if (jacdet < 0) operations(2,:) = [0 0 1]; @@ -233,6 +260,37 @@ end end +function operations = reorientation_edge_3dsurface (interface, geometry) + patches = [interface.patch1 interface.patch2]; + nrb_patches = [geometry(patches).nurbs]; + sides = [interface.side1 interface.side2]; +% Change orientation of first patch + if (sides(1) == 2) + operations(1,:) = [1 1 0]; + elseif (sides(1) == 3) + operations(1,:) = [1 0 1]; + elseif (sides(1) == 4) + operations(1,:) = [0 1 1]; + elseif (sides(1) == 1) + operations(1,:) = [0 0 0]; + end + +% Change orientation of second patch, only for inner edges + if (numel(nrb_patches) == 2) + jac = geometry(patches(2)).map_der({rand(1),rand(1)}); + jacdet = geopdes_det__ (jac); + if (sides(2) == 1) + operations(2,:) = [0 1 1]; + elseif (sides(2) == 2) + operations(2,:) = [1 0 1]; + elseif (sides(2) == 3) + operations(2,:) = [0 0 0]; + elseif (sides(2) == 4) + operations(2,:) = [1 1 0]; + end + end +end + function operations = reorientation_vertex (position, nrb) @@ -303,4 +361,4 @@ first_patch = bnd_patches(end); last_edge = bnd_edges(1); end -end \ No newline at end of file +end From 6390a2d170405db5913ec6a7effb078ee15be579 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 10 Feb 2022 10:27:30 +0100 Subject: [PATCH 135/366] Fixed bug for 3D surfaces --- geopdes/inst/multipatch/vertices_struct.m | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 34d54d43..06af8d43 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -23,7 +23,7 @@ % respect to the standard configuration in the vertex % - boundary_vertex: true if the vertex is a boundary vertex % -% Copyright (C) 2019-2021 Rafael Vazquez +% Copyright (C) 2019-2022 Rafael Vazquez % Copyright (C) 2019-2021 Cesare Bracco % % This program is free software: you can redistribute it and/or modify @@ -118,7 +118,7 @@ patch_reorientation = zeros (valence, 3); for iptc = 1:valence - patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs); + patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs, msh.rdim); end % Determine the first edge and patch to reorder the patches and edges @@ -292,7 +292,7 @@ function check_orientation (geometry, interfaces) end -function operations = reorientation_vertex (position, nrb) +function operations = reorientation_vertex (position, nrb, rdim) operations = zeros (1,3); switch position @@ -306,14 +306,18 @@ function check_orientation (geometry, interfaces) operations(1:2) = [1 1]; nrb = nrbreverse (nrb, [1 2]); end - [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); -% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - jac_as_I_want = jac{1}; - jac_as_I_want(:,2) = jac{2}; - jacdet = geopdes_det__ (jac_as_I_want); - if (jacdet < 0) - operations(3) = 1; + if (rdim == 2) + [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); +% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); + jacdet = geopdes_det__ (cell2mat(jac)); + if (jacdet < 0) + operations(3) = 1; + end + elseif (rdim == 3) + if (sum(operations) == 1) + operations(3) = 1; + end end end From d787ebbe425d8c86295eac9938e0336d482838f4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 10 Feb 2022 10:36:13 +0100 Subject: [PATCH 136/366] Removed unused operation --- geopdes/inst/multipatch/vertices_struct.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 06af8d43..af14f038 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -277,8 +277,6 @@ function check_orientation (geometry, interfaces) % Change orientation of second patch, only for inner edges if (numel(nrb_patches) == 2) - jac = geometry(patches(2)).map_der({rand(1),rand(1)}); - jacdet = geopdes_det__ (jac); if (sides(2) == 1) operations(2,:) = [0 1 1]; elseif (sides(2) == 2) From e54c3f33759fe2d8cb59394527d1fbb5cc15821e Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 11 Feb 2022 17:06:45 +0100 Subject: [PATCH 137/366] Remove unefficient use of speye --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index c599a43d..021e6475 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -165,10 +165,14 @@ numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); +% Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); + rows = sp.interior_dofs_per_patch{iptc}; + cols = global_indices; + vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); + Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), sp.ndof); +% Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... +% speye (numel (sp.interior_dofs_per_patch{iptc})); sp.dofs_on_patch{iptc} = shift_index_patch(iptc)+1:shift_index_patch(iptc+1); end From 950f66b373c7f4df84b3e59f91a7fed96b9ff90c Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 11 Feb 2022 17:09:31 +0100 Subject: [PATCH 138/366] Ignore asv files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ceba4418..86d3e265 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ *.log *.out *.swp +*.asv From 17180448437f7f724eaa82142d432a7da9d69e21 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Mon, 14 Feb 2022 15:09:36 +0100 Subject: [PATCH 139/366] Small changes --- .../inst/examples/base/ex_two_patches_C1.m | 126 ++++++++++++++---- .../@sp_multipatch_C1/sp_multipatch_C1.m | 117 ++++------------ 2 files changed, 130 insertions(+), 113 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index a4f06fad..7f525610 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -1,50 +1,130 @@ % EX_LAPLACE_LSHAPED_MP: solve the Poisson problem in the multipatch L-shaped domain with a B-spline discretization. - +clear all +close all % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file % nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); % nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); -p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; -nrb(1) = nrb4surf (p2, p1, p4, p3); +% p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; +% nrb(1) = nrb4surf (p2, p1, p4, p3); +% +% p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; +% nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; +% problem_data.geo_name = nrb; + +%Two patch flat planar +% coefs_1(:,1,:)=[0.125 -0.125 0;0.8 0.4 0]; +% coefs_1(:,2,:)=[-0.75 0.5 0;0.0 1.0 0]; +% +% coefs_2(:,1,:)=[0.125 -0.125 0;-0.1 -0.9 0]; +% coefs_2(:,2,:)=[0.8 0.4 0;0.87 -0.5 0]; +% +% knots{1} = [0 0 1 1]; +% knots{2} = [0 0 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; + +%Three patches flat +% coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; +% coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; +% +% coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; +% coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; +% coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; +% +% coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; +% coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; +% coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% nrb(3)=butterf3; +% problem_data.geo_name = nrb; + +% 3 patch surf +coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; + +coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; -p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; -nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; +coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; problem_data.geo_name = nrb; + % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = []; problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; % Physical parameters -problem_data.c_diff = @(x, y) ones(size(x)); +problem_data.c_diff = @(x, y, z) ones(size(x)); -% Source and boundary terms -problem_data.f = @(x, y) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); -problem_data.g = @(x, y, ind) test_Lshaped_mp_g_nmnn (x, y, ind); -problem_data.h = @(x, y, ind) exp(x) .* sin (x.*y); +% % Source and boundary terms +% problem_data.f = @(x, y, z) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); +% problem_data.g = @(x, y, z, ind) test_Lshaped_mp_g_nmnn (x, y, ind); +% problem_data.h = @(x, y, z, ind) exp(x) .* sin (x.*y); -% Exact solution (optional) -problem_data.uex = @(x, y) exp(x) .* sin (x.*y); -problem_data.graduex = @(x, y) cat (1, ... - reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... - reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); +% % Exact solution (optional) +% problem_data.uex = @(x, y, z) exp(x) .* sin (x.*y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... +% reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); - -problem_data.f = @(x, y) zeros (size(x)); -problem_data.h = @(x, y, ind) exp(y) .* sin (x); -problem_data.uex = @(x, y) exp (y) .* sin (x); -problem_data.graduex = @(x, y) cat (1, ... + +%Surf +problem_data.f = @(x, y, z) zeros (size(x)); +problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); +problem_data.uex = @(x, y, z) exp (y) .* sin (x); +problem_data.graduex = @(x, y, z) cat (1, ... reshape (exp(y).*cos(x), [1, size(x)]), ... - reshape (exp(y).*sin(x), [1, size(x)])); + reshape (exp(y).*sin(x), [1, size(x)]), ... + zeros([1, size(x)])); + +% problem_data.f = @(x, y) zeros (size(x)); +% problem_data.h = @(x, y, ind) exp(y) .* sin (x); +% problem_data.uex = @(x, y) exp (y) .* sin (x); +% problem_data.graduex = @(x, y) cat (1, ... +% reshape (exp(y).*cos(x), [1, size(x)]), ... +% reshape (exp(y).*sin(x), [1, size(x)])); + % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [8 8]; % Number of subdivisions +method_data.nsub = [16 16]; % Number of subdivisions method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); @@ -55,7 +135,7 @@ % % EXPORT TO PARAVIEW % output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; % -vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; +vtk_pts = {linspace(0, 1, 50), linspace(0, 1, 50)}; % fprintf ('The result is saved in the file %s.pvd \n \n', output_file); % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 72100945..a9e23b22 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -628,79 +628,8 @@ beta1 = [0 0]; return end - -% rank_A=6; -% if size(geo_map_jac{1},1)==3 -% grev_pts_red{1}=grev_pts{1}([1 end]); -% grev_pts_red{2}=grev_pts{2}([1 end]); -% for ii=1:length(geo_map_jac) -% geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); -% end -% if (side(2)==1 || side(2)==2) -% v = grev_pts_red{2}(:); -% else -% v = grev_pts_red{1}(:); -% end -% ngrev = numel(v); -% DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); -% DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); -% DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); -% DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); -% DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); -% DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); -% DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); -% DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); -% DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); -% -% A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... -% (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; -% (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; -% rank_A=rank(A_full); -% end -% -% if rank_A<5 || size(geo_map_jac{1},1)<3 -% % Assemble and solve G^1 conditions system -% if (side(2)==1 || side(2)==2) -% v = grev_pts{2}(:); -% else -% v = grev_pts{1}(:); -% end -% ngrev = numel(v); -% -% DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); -% DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); -% DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); -% DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); -% DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); -% DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); -% -% A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... -% (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; -% end -% if (rank(A_full)==6) -% A = A_full(:,2:end); -% b = -A_full(:,1); -% sols = A\b; -% alpha0_n(1) = 1; -% alpha1_n(1) = sols(1); -% alpha0_n(2) = sols(2); -% alpha1_n(2) = sols(3); -% beta0_n = sols(4); -% beta1_n = sols(5); -% beta2_n = sols(6); -% else -% A = A_full(:,3:end); % FIX: not a square matrix -% b = -sum(A_full(:,1:2),2); -% sols = A\b; -% alpha0_n(1) = 1; -% alpha1_n(1) = 1; -% alpha0_n(2) = sols(1); -% alpha1_n(2) = sols(2); -% beta0_n = sols(3); -% beta1_n = sols(4); -% beta2_n = sols(5); -% end - + + % Assemble and solve G^1 conditions system if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); else @@ -709,28 +638,36 @@ ngrev = numel(v); DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); - DuFR_z = reshape (geo_map_jac{1}(3,1,:,:), ngrev, 1); DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); - DvFL_z = reshape (geo_map_jac{2}(3,2,:,:), ngrev, 1); DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); - DvFR_z = reshape (geo_map_jac{1}(3,2,:,:), ngrev, 1); A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; - (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; - - A = A_full(:,2:end); - b = -A_full(:,1); - sols = A\b; %we arbitrarily set the first unknown to 1 to avoid the null solution - alpha0_n(1) = 1; - alpha1_n(1) = sols(1); - alpha0_n(2) = sols(2); - alpha1_n(2) = sols(3); - beta0_n = sols(4); - beta1_n = sols(5); - beta2_n = sols(6); + (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; + if (rank(A_full)==6) + A = A_full(:,2:end); + b = -A_full(:,1); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = sols(1); + alpha0_n(2) = sols(2); + alpha1_n(2) = sols(3); + beta0_n = sols(4); + beta1_n = sols(5); + beta2_n = sols(6); + else + A = A_full(:,3:end); % FIX: not a square matrix + b = -sum(A_full(:,1:2),2); + sols = A\b; + alpha0_n(1) = 1; + alpha1_n(1) = 1; + alpha0_n(2) = sols(1); + alpha1_n(2) = sols(2); + beta0_n = sols(3); + beta1_n = sols(4); + beta2_n = sols(5); + end % Normalize the alphas C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; @@ -759,7 +696,7 @@ M = [alpha_R_0 0 alpha_L_0 0; ... 0 alpha_R_1 0 alpha_L_1; ... alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; - + if (rank(M)==3) % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... From 2201b657eb8a1ed85b197fcf862d2953dee6850a Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 15 Feb 2022 10:39:49 +0100 Subject: [PATCH 140/366] Change function name and update the help --- geopdes/inst/multipatch/mp_solve_bilaplace_C1.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index a447ae6e..2a8c6ffe 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -1,9 +1,9 @@ -% MP_SOLVE_BILAPLACE: solve the bilaplacian problem in a multipatch geometry. +% MP_SOLVE_BILAPLACE_C1: solve the bilaplacian problem in a multipatch geometry. % % USAGE: % % [geometry, msh, space, u] = -% mp_solve_bilaplace (problem_data, method_data) +% mp_solve_bilaplace_C1 (problem_data, method_data) % % INPUT: % @@ -11,9 +11,9 @@ % - geo_name: name of the file containing the geometry % - nmnn_sides: sides with Neumann boundary condition (may be empty) % - drchlt_sides: sides with Dirichlet boundary condition -% - c_diff: diffusion coefficient (epsilon in the equation) +% - c_diff: diffusion coefficient % - f: source term -% - g: function for Neumann condition (if nmnn_sides is not empty) +% - g: function for Neumann condition % - h: function for Dirichlet boundary condition % % method_data : a structure with discretization data. Its fields are: @@ -25,13 +25,13 @@ % % OUTPUT: % -% geometry: array of geometry structures (see geo_load) +% geometry: array of geometry structures (see mp_geo_load) % msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) -% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch_C1) % u: the computed degrees of freedom % % Copyright (C) 2009, 2010 Carlo de Falco -% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez +% Copyright (C) 2010--2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -47,7 +47,7 @@ % along with this program. If not, see . function [geometry, msh, space, u] = ... - mp_solve_laplace_C1 (problem_data, method_data) + mp_solve_bilaplace_C1 (problem_data, method_data) % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); From 7c692e1e5811f6f7c37062bc725f8bb6ad63dafa Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Tue, 15 Feb 2022 11:41:38 +0100 Subject: [PATCH 141/366] Tests --- .../inst/examples/base/ex_two_patches_C1.m | 101 ++++++++++++++---- .../@sp_multipatch_C1/sp_multipatch_C1.m | 6 +- 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index 7f525610..faef0578 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -1,6 +1,7 @@ % EX_LAPLACE_LSHAPED_MP: solve the Poisson problem in the multipatch L-shaped domain with a B-spline discretization. clear all close all + % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file @@ -57,18 +58,55 @@ % nrb(3)=butterf3; % problem_data.geo_name = nrb; -% 3 patch surf -coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; -coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; -coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% % 3 patch surf +% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% +% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +% +% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +% problem_data.geo_name = nrb; + + +%5 patch surf +coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; +coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; +coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; -coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; -coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; -coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; +coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; +coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; -coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; -coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; -coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; +coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; +coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; + +coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; +coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; +coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; + +coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; +coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; +coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; knots{1} = [0 0 0 1 1 1]; knots{2} = [0 0 0 1 1 1]; @@ -76,17 +114,21 @@ butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); nrb(1)=butterf1; nrb(2)=butterf2; nrb(3)=butterf3; +nrb(4)=butterf4; +nrb(5)=butterf5; problem_data.geo_name = nrb; % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = []; -problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8 9 10]; % Physical parameters problem_data.c_diff = @(x, y, z) ones(size(x)); @@ -104,13 +146,36 @@ %Surf -problem_data.f = @(x, y, z) zeros (size(x)); -problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); -problem_data.uex = @(x, y, z) exp (y) .* sin (x); +% problem_data.f = @(x, y, z) zeros(size(x)); +% problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); +% problem_data.uex = @(x, y, z) exp (y) .* sin (x); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (exp(y).*cos(x), [1, size(x)]), ... +% reshape (exp(y).*sin(x), [1, size(x)]), ... +% zeros([1, size(x)])); + + +% problem_data.f = @(x, y, z) -(1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-4 * cos(9 * x) .* ( (65 + 392 * x.^4 + 422 * y.^2 + 648 * y.^4 + ... +% 2 * x.^2 .* (179 + 520 * y.^2) ) .* cos(1 - 7 * y) + 28 * y .* (1 + 2 * x.^2 + 2 * y.^2) .* sin(1 - 7 * y) ) + ... +% 144 * x .* sin(9 * x) .* ( (1 + 2 * x.^2 + 2 * y.^2) .* cos(1 - 7 * y) + 7 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* sin(1 - 7 * y) ) ); +% problem_data.h = @(x, y, z, ind) cos(9*x) .* cos(1 - 7*y); +% problem_data.uex = @(x, y, z) cos(9*x) .* cos(1 - 7*y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (-( (2 * (9 * (1 + 4 * y.^2) .* cos(1 - 7 * y) .* sin(9 * x) + 28 * x .* y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2)), [1, size(x)]), ... +% reshape ((72 * x .* y .* cos(1 - 7 * y) .* sin(9 * x) + 14 * (1 + 4 * x.^2) .* cos(9 * x) .* sin(1 - 7 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... +% reshape((4 * (9 * x .* cos(1 - 7 * y) .* sin(9 * x) - 7 * y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); + + + +problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); +problem_data.h = @(x, y, z, ind) z; +problem_data.uex = @(x, y, z) z; problem_data.graduex = @(x, y, z) cat (1, ... - reshape (exp(y).*cos(x), [1, size(x)]), ... - reshape (exp(y).*sin(x), [1, size(x)]), ... - zeros([1, size(x)])); + reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); + + % problem_data.f = @(x, y) zeros (size(x)); % problem_data.h = @(x, y, ind) exp(y) .* sin (x); @@ -124,7 +189,7 @@ clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [16 16]; % Number of subdivisions +method_data.nsub = [8 8]; % Number of subdivisions method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index a9e23b22..f59b2aa2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -281,9 +281,11 @@ % end end -% if msh.ndim+1~=msh.rdim || planar_surf + if msh.ndim+1 == msh.rdim [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); -% else + else + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); + end % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); % [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); From c4173b23e10a0fbd23823aca3e22199cb5bc8e3f Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Tue, 15 Feb 2022 13:52:16 +0100 Subject: [PATCH 142/366] Split planar and surf code --- .../inst/examples/base/ex_surf_laplace_C1.m | 211 ++++++++++++++++++ .../inst/examples/base/ex_two_patches_C1.m | 156 +------------ 2 files changed, 218 insertions(+), 149 deletions(-) create mode 100644 geopdes/inst/examples/base/ex_surf_laplace_C1.m diff --git a/geopdes/inst/examples/base/ex_surf_laplace_C1.m b/geopdes/inst/examples/base/ex_surf_laplace_C1.m new file mode 100644 index 00000000..0e843dec --- /dev/null +++ b/geopdes/inst/examples/base/ex_surf_laplace_C1.m @@ -0,0 +1,211 @@ +% EX_LAPLACE_LSHAPED_MP: solve the Poisson problem in the multipatch L-shaped domain with a B-spline discretization. +clear all +close all + +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +% nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); +% nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); + +% p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; +% nrb(1) = nrb4surf (p2, p1, p4, p3); +% +% p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; +% nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; +% problem_data.geo_name = nrb; + +%Two patch flat planar +% coefs_1(:,1,:)=[0.125 -0.125 0;0.8 0.4 0]; +% coefs_1(:,2,:)=[-0.75 0.5 0;0.0 1.0 0]; +% +% coefs_2(:,1,:)=[0.125 -0.125 0;-0.1 -0.9 0]; +% coefs_2(:,2,:)=[0.8 0.4 0;0.87 -0.5 0]; +% +% knots{1} = [0 0 1 1]; +% knots{2} = [0 0 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; + +%Three patches flat +% coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; +% coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; +% +% coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; +% coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; +% coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; +% +% coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; +% coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; +% coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% nrb(3)=butterf3; +% problem_data.geo_name = nrb; + +% % 3 patch surf +% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% +% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +% +% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +% problem_data.geo_name = nrb; + + +%5 patch surf +coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; +coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; +coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; + +coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; +coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; +coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; + +coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; +coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; +coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; + +coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; +coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; +coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; + +coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; +coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; +coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +nrb(4)=butterf4; +nrb(5)=butterf5; +problem_data.geo_name = nrb; + + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = []; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8 9 10]; + +% Physical parameters +problem_data.c_diff = @(x, y, z) ones(size(x)); + +% % Source and boundary terms +% problem_data.f = @(x, y, z) exp(x).*((x.^2 + y.^2 - 1).*sin(x.*y) - 2*y.*cos(x.*y)); +% problem_data.g = @(x, y, z, ind) test_Lshaped_mp_g_nmnn (x, y, ind); +% problem_data.h = @(x, y, z, ind) exp(x) .* sin (x.*y); + +% % Exact solution (optional) +% problem_data.uex = @(x, y, z) exp(x) .* sin (x.*y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... +% reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); + + +%Surf +% problem_data.f = @(x, y, z) zeros(size(x)); +% problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); +% problem_data.uex = @(x, y, z) exp (y) .* sin (x); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (exp(y).*cos(x), [1, size(x)]), ... +% reshape (exp(y).*sin(x), [1, size(x)]), ... +% zeros([1, size(x)])); + + +% problem_data.f = @(x, y, z) -(1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-4 * cos(9 * x) .* ( (65 + 392 * x.^4 + 422 * y.^2 + 648 * y.^4 + ... +% 2 * x.^2 .* (179 + 520 * y.^2) ) .* cos(1 - 7 * y) + 28 * y .* (1 + 2 * x.^2 + 2 * y.^2) .* sin(1 - 7 * y) ) + ... +% 144 * x .* sin(9 * x) .* ( (1 + 2 * x.^2 + 2 * y.^2) .* cos(1 - 7 * y) + 7 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* sin(1 - 7 * y) ) ); +% problem_data.h = @(x, y, z, ind) cos(9*x) .* cos(1 - 7*y); +% problem_data.uex = @(x, y, z) cos(9*x) .* cos(1 - 7*y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (-( (2 * (9 * (1 + 4 * y.^2) .* cos(1 - 7 * y) .* sin(9 * x) + 28 * x .* y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2)), [1, size(x)]), ... +% reshape ((72 * x .* y .* cos(1 - 7 * y) .* sin(9 * x) + 14 * (1 + 4 * x.^2) .* cos(9 * x) .* sin(1 - 7 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... +% reshape((4 * (9 * x .* cos(1 - 7 * y) .* sin(9 * x) - 7 * y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); + + + +problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); +problem_data.h = @(x, y, z, ind) z; +problem_data.uex = @(x, y, z) z; +problem_data.graduex = @(x, y, z) cat (1, ... + reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); + + + +% problem_data.f = @(x, y) zeros (size(x)); +% problem_data.h = @(x, y, ind) exp(y) .* sin (x); +% problem_data.uex = @(x, y) exp (y) .* sin (x); +% problem_data.graduex = @(x, y) cat (1, ... +% reshape (exp(y).*cos(x), [1, size(x)]), ... +% reshape (exp(y).*sin(x), [1, size(x)])); + + +% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +method_data.degree = [3 3]; % Degree of the splines +method_data.regularity = [1 1]; % Regularity of the splines +method_data.nsub = [8 8]; % Number of subdivisions +method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); + +% 3) CALL TO THE SOLVER +[geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); + +% % 4) POST-PROCESSING +% % EXPORT TO PARAVIEW +% output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; +% +vtk_pts = {linspace(0, 1, 50), linspace(0, 1, 50)}; +% fprintf ('The result is saved in the file %s.pvd \n \n', output_file); +% sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') +% +figure +sp_plot_solution (u, space, geometry, vtk_pts) + +% COMPARISON WITH THE EXACT SOLUTION +[error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) diff --git a/geopdes/inst/examples/base/ex_two_patches_C1.m b/geopdes/inst/examples/base/ex_two_patches_C1.m index faef0578..ee546a93 100644 --- a/geopdes/inst/examples/base/ex_two_patches_C1.m +++ b/geopdes/inst/examples/base/ex_two_patches_C1.m @@ -5,126 +5,16 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file -% nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); -% nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); +nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); +nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); -% p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; -% nrb(1) = nrb4surf (p2, p1, p4, p3); -% -% p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; -% nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; -% problem_data.geo_name = nrb; - -%Two patch flat planar -% coefs_1(:,1,:)=[0.125 -0.125 0;0.8 0.4 0]; -% coefs_1(:,2,:)=[-0.75 0.5 0;0.0 1.0 0]; -% -% coefs_2(:,1,:)=[0.125 -0.125 0;-0.1 -0.9 0]; -% coefs_2(:,2,:)=[0.8 0.4 0;0.87 -0.5 0]; -% -% knots{1} = [0 0 1 1]; -% knots{2} = [0 0 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; - -%Three patches flat -% coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; -% coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; -% coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; -% -% coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; -% coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; -% coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; -% -% coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; -% coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; -% coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% nrb(3)=butterf3; -% problem_data.geo_name = nrb; - -% % 3 patch surf -% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; -% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; -% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; -% -% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; -% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; -% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; -% -% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; -% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; -% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); -% problem_data.geo_name = nrb; +p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; +nrb(1) = nrb4surf (p2, p1, p4, p3); - -%5 patch surf -coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; -coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; -coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; - -coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; -coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; -coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; - -coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; -coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; -coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; - -coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; -coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; -coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; - -coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; -coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; -coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -nrb(4)=butterf4; -nrb(5)=butterf5; +p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; +nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; problem_data.geo_name = nrb; - % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = []; @@ -143,39 +33,7 @@ % problem_data.graduex = @(x, y, z) cat (1, ... % reshape (exp(x).*(sin(x.*y) + y.*cos(x.*y)), [1, size(x)]), ... % reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); - - -%Surf -% problem_data.f = @(x, y, z) zeros(size(x)); -% problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); -% problem_data.uex = @(x, y, z) exp (y) .* sin (x); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (exp(y).*cos(x), [1, size(x)]), ... -% reshape (exp(y).*sin(x), [1, size(x)]), ... -% zeros([1, size(x)])); - - -% problem_data.f = @(x, y, z) -(1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-4 * cos(9 * x) .* ( (65 + 392 * x.^4 + 422 * y.^2 + 648 * y.^4 + ... -% 2 * x.^2 .* (179 + 520 * y.^2) ) .* cos(1 - 7 * y) + 28 * y .* (1 + 2 * x.^2 + 2 * y.^2) .* sin(1 - 7 * y) ) + ... -% 144 * x .* sin(9 * x) .* ( (1 + 2 * x.^2 + 2 * y.^2) .* cos(1 - 7 * y) + 7 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* sin(1 - 7 * y) ) ); -% problem_data.h = @(x, y, z, ind) cos(9*x) .* cos(1 - 7*y); -% problem_data.uex = @(x, y, z) cos(9*x) .* cos(1 - 7*y); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (-( (2 * (9 * (1 + 4 * y.^2) .* cos(1 - 7 * y) .* sin(9 * x) + 28 * x .* y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2)), [1, size(x)]), ... -% reshape ((72 * x .* y .* cos(1 - 7 * y) .* sin(9 * x) + 14 * (1 + 4 * x.^2) .* cos(9 * x) .* sin(1 - 7 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... -% reshape((4 * (9 * x .* cos(1 - 7 * y) .* sin(9 * x) - 7 * y .* cos(9 * x) .* sin(1 - 7 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); - - - -problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); -problem_data.h = @(x, y, z, ind) z; -problem_data.uex = @(x, y, z) z; -problem_data.graduex = @(x, y, z) cat (1, ... - reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); - - + % problem_data.f = @(x, y) zeros (size(x)); % problem_data.h = @(x, y, ind) exp(y) .* sin (x); From dc366c49190ba09b9e7ae3d705cbd8a3dd85d5cc Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Tue, 15 Feb 2022 14:00:25 +0100 Subject: [PATCH 143/366] Small test --- .../inst/examples/base/ex_surf_laplace_C1.m | 164 +++++++++--------- 1 file changed, 78 insertions(+), 86 deletions(-) diff --git a/geopdes/inst/examples/base/ex_surf_laplace_C1.m b/geopdes/inst/examples/base/ex_surf_laplace_C1.m index 0e843dec..5af7c75d 100644 --- a/geopdes/inst/examples/base/ex_surf_laplace_C1.m +++ b/geopdes/inst/examples/base/ex_surf_laplace_C1.m @@ -4,16 +4,6 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data -% Physical domain, defined as NURBS map given in a text file -% nrb(1) = nrb4surf ([0 0], [-1 0], [0 1], [-1 1]); -% nrb(2) = nrb4surf ([0 0], [1 0], [0 1], [1 1]); - -% p1 = [-4 -1/2]; p2 = [0 0]; p3 = [-10/3 16/5]; p4 = [0 3]; -% nrb(1) = nrb4surf (p2, p1, p4, p3); -% -% p1 = [0 0]; p2 = [8/3 -2/5]; p3 = [0 3]; p4 = [10/3 23/7]; -% nrb(2) = nrb4surf (p1, p2, p3, p4); problem_data.geo_id = 1; -% problem_data.geo_name = nrb; %Two patch flat planar % coefs_1(:,1,:)=[0.125 -0.125 0;0.8 0.4 0]; @@ -30,33 +20,35 @@ % % nrb(1)=butterf1; % nrb(2)=butterf2; +% problem_data.geo_name = nrb; + %Three patches flat -% coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; -% coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; -% coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; -% -% coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; -% coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; -% coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; -% -% coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; -% coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; -% coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% nrb(3)=butterf3; -% problem_data.geo_name = nrb; +coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; +coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; +coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; + +coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; +coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; +coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; + +coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; +coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; +coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +% nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +nrb(3)=butterf3; +problem_data.geo_name = nrb; % % 3 patch surf % coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; @@ -88,47 +80,47 @@ %5 patch surf -coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; -coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; -coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; - -coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; -coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; -coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; - -coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; -coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; -coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; - -coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; -coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; -coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; - -coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; -coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; -coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -nrb(4)=butterf4; -nrb(5)=butterf5; -problem_data.geo_name = nrb; +% coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; +% coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; +% coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; +% +% coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; +% coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; +% coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; +% +% coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; +% coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; +% coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; +% +% coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; +% coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; +% coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; +% +% coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; +% coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; +% coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% nrb(4)=butterf4; +% nrb(5)=butterf5; +% problem_data.geo_name = nrb; % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = []; -problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8 9 10]; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; % Physical parameters problem_data.c_diff = @(x, y, z) ones(size(x)); @@ -145,14 +137,14 @@ % reshape (exp(x).*x.*cos(x.*y), [1, size(x)])); -%Surf -% problem_data.f = @(x, y, z) zeros(size(x)); -% problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); -% problem_data.uex = @(x, y, z) exp (y) .* sin (x); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (exp(y).*cos(x), [1, size(x)]), ... -% reshape (exp(y).*sin(x), [1, size(x)]), ... -% zeros([1, size(x)])); +% Surf +problem_data.f = @(x, y, z) zeros(size(x)); +problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); +problem_data.uex = @(x, y, z) exp (y) .* sin (x); +problem_data.graduex = @(x, y, z) cat (1, ... + reshape (exp(y).*cos(x), [1, size(x)]), ... + reshape (exp(y).*sin(x), [1, size(x)]), ... + zeros([1, size(x)])); % problem_data.f = @(x, y, z) -(1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-4 * cos(9 * x) .* ( (65 + 392 * x.^4 + 422 * y.^2 + 648 * y.^4 + ... @@ -167,13 +159,13 @@ -problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); -problem_data.h = @(x, y, z, ind) z; -problem_data.uex = @(x, y, z) z; -problem_data.graduex = @(x, y, z) cat (1, ... - reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); +% problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); +% problem_data.h = @(x, y, z, ind) z; +% problem_data.uex = @(x, y, z) z; +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... +% reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... +% reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); From 8f6149bf1fe03823215f2684ce1f314d42c0e25b Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 24 Feb 2022 15:28:42 +0100 Subject: [PATCH 144/366] Removed unused line --- .../inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 1 - 1 file changed, 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index a3bd889b..7e542c52 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -14,7 +14,6 @@ for iref = refs href = @(varargin) h(varargin{:}, iref); for bnd_side = 1:boundaries(iref).nsides - iptc_bnd = sum([boundaries(1:iref-1).nsides]) + bnd_side; iptc = boundaries(iref).patches(bnd_side); iside = boundaries(iref).faces(bnd_side); From baecd81e8df51b3088db4c230b2fc1ec800ac7cb Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 24 Feb 2022 15:29:39 +0100 Subject: [PATCH 145/366] Possibility to use the exact solution as data in a simpler way --- .../sp_bilaplacian_drchlt_C1_exact.m | 60 +++++++++++++++++++ .../inst/multipatch/mp_solve_bilaplace_C1.m | 8 ++- 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m new file mode 100644 index 00000000..0532c8e8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -0,0 +1,60 @@ +function [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) + +% refs should be the whole boundary, for now +M = spalloc (space.ndof, space.ndof, space.ndof); +rhs = zeros (space.ndof, 1); + +M2 = spalloc (space.ndof, space.ndof, space.ndof); +rhs2 = zeros (space.ndof, 1); + +drchlt_dofs = []; +drchlt_dofs2 = []; + +boundaries = msh.boundaries; +for iref = refs +% href = @(varargin) h(varargin{:}, iref); + for bnd_side = 1:boundaries(iref).nsides + iptc = boundaries(iref).patches(bnd_side); + iside = boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd_struct = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + + [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); + [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); + + drchlt_dofs = union (drchlt_dofs, icol); + drchlt_dofs2 = union (drchlt_dofs2, jcol); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coeff_at_qnodes = ones (size(x{1})); + dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel); + + M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); + + M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + + end +end + +u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); + +uu = sparse (space.ndof, 1); +uu(drchlt_dofs) = u_drchlt; + +drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); +rhs2 = rhs2 - M2 * uu; +u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); + +uu(drchlt_dofs2) = u_drchlt2; + +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +u_drchlt = uu(drchlt_dofs); + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 2a8c6ffe..45c84cd0 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -90,9 +90,13 @@ stiff_mat = op_gradgradu_gradgradv_mp (space, space, msh, c_diff); rhs = op_f_v_mp (space, msh, f); - +% Apply boundary conditions u = zeros (space.ndof, 1); -[u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); +if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) + [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); +else + [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); +end u(drchlt_dofs) = u_drchlt; int_dofs = setdiff (1:space.ndof, drchlt_dofs); From 72d3410bf2246f45e54fd3dc0b17d56f4a113af2 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 24 Feb 2022 16:31:25 +0100 Subject: [PATCH 146/366] Added small modifications and start testing biharmonic over surfaces --- .../base/ex_bilaplacian_Lshape_5patch.m | 154 ++++++++++++++++++ .../inst/examples/base/ex_surf_laplace_C1.m | 145 ++++++++++------- 2 files changed, 239 insertions(+), 60 deletions(-) create mode 100644 geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m new file mode 100644 index 00000000..9a6eafac --- /dev/null +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -0,0 +1,154 @@ +close all +clear all +warning ('off','geopdes:nrbmultipatch') + +% PHYSICAL DATA OF THE PROBLEM +% 5 patches (L-shape) +% p1=[0 0]; p2=[1 0]; p3=[1 1]; p4=[-1/3 1/3]; p5=[0 -1]; p6=[-2/3 -1/3]; p7=[-1 -1]; p8=[-2/3 1/3]; p9=[-1 1]; +% nrb(1) = nrb4surf(p1,p2,p4,p3); +% nrb(2) = nrb4surf(p1,p5,p6,p7); +% nrb(3) = nrb4surf(p6,p7,p8,p9); +% nrb(4) = nrb4surf(p1,p6,p4,p8); +% nrb(5) = nrb4surf(p8,p9,p4,p3); +% +% problem_data.geo_name = nrb; + +% % 3 patch surf +% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% +% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +% +% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +% problem_data.geo_name = nrb; + +%5 patch surf +coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; +coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; +coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; + +coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; +coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; +coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; + +coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; +coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; +coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; + +coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; +coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; +coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; + +coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; +coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; +coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +nrb(4)=butterf4; +nrb(5)=butterf5; +problem_data.geo_name = nrb; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = [1 2 3 4 5 6 7 8 9 10]; +problem_data.drchlt_sides = []; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8 9 10]; + +% Physical parameters +problem_data.c_diff = @(x, y, z) ones(size(x)); +% Source and boundary terms +C = 1; +p=-1; +% Bilaplacian +% problem_data.f = @(x,y,z) bilaplacian_rhs_Lshape2(x,y); +% % problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); +% problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); +% problem_data.h = @(x, y, z, ind) solution_bilaplacian_Lshape (x, y); + +% problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); +% problem_data.g = @(x, y, z, ind) (2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2); +% problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); +% problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape ((-3*(1 + 4*y.^2).*cos(y).*sin(3*x) + 4*x.*y.*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... +% reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... +% reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); + +problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); +problem_data.h = @(x, y, z, ind) z; +problem_data.g = @(x, y, z, ind) z; +problem_data.uex = @(x, y, z) z; +problem_data.graduex = @(x, y, z) cat (1, ... + reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... + reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); + +% Exact solution (optional) +problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); +% problem_data.graduex = @(x, y, z) solution_bilaplacian_Lshape_grad (x, y); +% problem_data.hessuex = @(x, y, z) solution_bilaplacian_Lshape_hessian (x, y); + +% CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) +clear method_data +method_data.degree = [3 3]; % Degree of the splines +method_data.regularity = [1 1]; % Regularity of the splines +method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); +method_data.space_type = 'standard'; % 'simplified' (only children functions) or 'standard' (full basis) + +% SOLVE AND DISPLAY RESULTS +plot_data.print_info = true; +plot_data.plot_hmesh = false; +plot_data.plot_discrete_sol = false; + +[geometry, hmsh, hspace, u] = mp_solve_bilaplace_C1 (problem_data, method_data); +if (isfield (problem_data, 'hessuex')) + [err_h2, err_h1, err_l2, err_h2s, err_h1s] = sp_h2_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex); + if (plot_data.print_info) + fprintf('Error in H2 seminorm = %g\n', err_h2s); + end +end + +% EXPORT VTK FILE +subplot(1,2,1) +npts = [51 51]; +sp_plot_solution (u, hspace, geometry, npts); shading interp +vtk_pts = {linspace(0,1,npts(1)), linspace(0,1,npts(2))}; +subplot(1,2,2) +for iptc = 1:hmsh.npatch + F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); + X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); + surf(X, Y, problem_data.uex(X,Y)); + hold on; shading interp +end +warning ('on','geopdes:nrbmultipatch') diff --git a/geopdes/inst/examples/base/ex_surf_laplace_C1.m b/geopdes/inst/examples/base/ex_surf_laplace_C1.m index 5af7c75d..00df5ab0 100644 --- a/geopdes/inst/examples/base/ex_surf_laplace_C1.m +++ b/geopdes/inst/examples/base/ex_surf_laplace_C1.m @@ -24,44 +24,17 @@ %Three patches flat -coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; -coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; -coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; - -coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; -coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; -coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; - -coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; -coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; -coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -% nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -nrb(3)=butterf3; -problem_data.geo_name = nrb; - -% % 3 patch surf -% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; -% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; -% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% coefs_1(:,3,:)=[0.125 -0.125 1; 0.4625 0.1375 1; 0.8 0.4 1]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1; 0.04375 0.44375 1; 0.4 0.7 1]; +% coefs_1(:,1,:)=[-0.75 0.5 1;-0.375 0.75 1; 0.0 1.0 1]; % -% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; -% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; -% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +% coefs_2(:,3,:)=[0.125 -0.125 1; 0.0125 -0.5125 1; -0.1 -0.9 1]; +% coefs_2(:,2,:)=[0.4625 0.1375 1;0.42375 -0.28125 1; 0.385 -0.7 1]; +% coefs_2(:,1,:)=[0.8 0.4 1; 0.835 -0.05 1;0.87 -0.5 1]; % -% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; -% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; -% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +% coefs_3(:,3,:)=[0.125 -0.125 1; -0.3125 0.1875 1; -0.75 0.5 1]; +% coefs_3(:,2,:)=[0.0125 -0.5125 1; -0.39875 -0.25625 1;-0.81 0.0 1]; +% coefs_3(:,1,:)=[-0.1 -0.9 1; -0.485 -0.7 1; -0.87 -0.5 1]; % % knots{1} = [0 0 0 1 1 1]; % knots{2} = [0 0 0 1 1 1]; @@ -72,12 +45,39 @@ % % nrb(1)=butterf1; % nrb(2)=butterf2; -% nrb(3)=butterf3; % % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); % % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +% nrb(3)=butterf3; % problem_data.geo_name = nrb; +% % 3 patch surf +coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; + +coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; + +coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +% nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +problem_data.geo_name = nrb; + %5 patch surf % coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; @@ -138,13 +138,13 @@ % Surf -problem_data.f = @(x, y, z) zeros(size(x)); -problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); -problem_data.uex = @(x, y, z) exp (y) .* sin (x); -problem_data.graduex = @(x, y, z) cat (1, ... - reshape (exp(y).*cos(x), [1, size(x)]), ... - reshape (exp(y).*sin(x), [1, size(x)]), ... - zeros([1, size(x)])); +% problem_data.f = @(x, y, z) zeros(size(x)); +% problem_data.h = @(x, y, z, ind) exp(y) .* sin (x); +% problem_data.uex = @(x, y, z) exp (y) .* sin (x); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (exp(y).*cos(x), [1, size(x)]), ... +% reshape (exp(y).*sin(x), [1, size(x)]), ... +% zeros([1, size(x)])); % problem_data.f = @(x, y, z) -(1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-4 * cos(9 * x) .* ( (65 + 392 * x.^4 + 422 * y.^2 + 648 * y.^4 + ... @@ -168,7 +168,15 @@ % reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); - +problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); +problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); +problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); +problem_data.graduex = @(x, y, z) cat (1, ... + reshape ((-3*(1 + 4*y.^2).*cos(y).*sin(3*x) + 4*x.*y.*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... + reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... + reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); + + % problem_data.f = @(x, y) zeros (size(x)); % problem_data.h = @(x, y, ind) exp(y) .* sin (x); % problem_data.uex = @(x, y) exp (y) .* sin (x); @@ -179,25 +187,42 @@ % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data -method_data.degree = [3 3]; % Degree of the splines +method_data.degree = [5 5]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [8 8]; % Number of subdivisions + method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); -% 3) CALL TO THE SOLVER -[geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); +h=[]; + +for i= 1:4 + fprintf ('Loop %d \n', i); + method_data.nsub = [2^(i+1) 2^(i+1)] ; % Number of subdivisions + % 3) CALL TO THE SOLVER + [geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); + + h = [h 1/sqrt(msh.nel_per_patch(1))] + % % 4) POST-PROCESSING + % % EXPORT TO PARAVIEW + % output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; + % + vtk_pts = {linspace(0, 1, 50), linspace(0, 1, 50)}; + % fprintf ('The result is saved in the file %s.pvd \n \n', output_file); + % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') + % + + % COMPARISON WITH THE EXACT SOLUTION + [error_h1(i), error_l2(i)] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) +end -% % 4) POST-PROCESSING -% % EXPORT TO PARAVIEW -% output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; -% -vtk_pts = {linspace(0, 1, 50), linspace(0, 1, 50)}; -% fprintf ('The result is saved in the file %s.pvd \n \n', output_file); -% sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') -% figure sp_plot_solution (u, space, geometry, vtk_pts) -% COMPARISON WITH THE EXACT SOLUTION -[error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) +figure +loglog(h, error_l2,'-o') +hold on +loglog(h, error_h1,'-*') +loglog(h, 0.0001*h.^6,'-x') +loglog(h, 0.001*h.^5,'-x') +legend("L^2 error", "H^1 error", "h^6", "h^5",'Location','southeast'); + From 9a078363a488b63994e6620df6c3b8ca7862a7f6 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 2 Mar 2022 19:17:32 +0100 Subject: [PATCH 147/366] Changed the way to impose boundary conditions, with a single projection --- .../sp_bilaplacian_drchlt_C1.m | 28 +++++++++++-------- .../sp_bilaplacian_drchlt_C1_exact.m | 28 +++++++++++-------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 7e542c52..1527f842 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -43,18 +43,22 @@ end end -u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); - -uu = sparse (space.ndof, 1); -uu(drchlt_dofs) = u_drchlt; - -drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); -rhs2 = rhs2 - M2 * uu; -u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); - -uu(drchlt_dofs2) = u_drchlt2; +% u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); +% +% uu = sparse (space.ndof, 1); +% uu(drchlt_dofs) = u_drchlt; +% +% drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); +% rhs2 = rhs2 - M2 * uu; +% u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); +% +% uu(drchlt_dofs2) = u_drchlt2; +% +% drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +% u_drchlt = uu(drchlt_dofs); drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); -u_drchlt = uu(drchlt_dofs); +u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... + (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); -end \ No newline at end of file +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 0532c8e8..8f4f0325 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -43,18 +43,22 @@ end end -u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); - -uu = sparse (space.ndof, 1); -uu(drchlt_dofs) = u_drchlt; - -drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); -rhs2 = rhs2 - M2 * uu; -u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); - -uu(drchlt_dofs2) = u_drchlt2; +% u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); +% +% uu = sparse (space.ndof, 1); +% uu(drchlt_dofs) = u_drchlt; +% +% drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); +% rhs2 = rhs2 - M2 * uu; +% u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); +% +% uu(drchlt_dofs2) = u_drchlt2; +% +% drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +% u_drchlt = uu(drchlt_dofs); drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); -u_drchlt = uu(drchlt_dofs); +u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... + (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); -end \ No newline at end of file +end From 6058c027842eaae5c6bac427834b5cc6af22e43e Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 3 Mar 2022 10:14:54 +0100 Subject: [PATCH 148/366] Test Biharmonic --- .../base/ex_bilaplacian_Lshape_5patch.m | 198 ++++++++++++------ .../sp_bilaplacian_drchlt_C1_exact.m | 1 + 2 files changed, 135 insertions(+), 64 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index 9a6eafac..1f9a8d7e 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -4,15 +4,48 @@ % PHYSICAL DATA OF THE PROBLEM % 5 patches (L-shape) -% p1=[0 0]; p2=[1 0]; p3=[1 1]; p4=[-1/3 1/3]; p5=[0 -1]; p6=[-2/3 -1/3]; p7=[-1 -1]; p8=[-2/3 1/3]; p9=[-1 1]; +% p1=[0 0 1]; p2=[1 0 1]; p3=[1 1 1]; p4=[-1/3 1/3 1]; p5=[0 -1 1]; p6=[-2/3 -1/3 1]; p7=[-1 -1 1]; p8=[-2/3 1/3 1]; p9=[-1 1 1]; % nrb(1) = nrb4surf(p1,p2,p4,p3); -% nrb(2) = nrb4surf(p1,p5,p6,p7); -% nrb(3) = nrb4surf(p6,p7,p8,p9); -% nrb(4) = nrb4surf(p1,p6,p4,p8); -% nrb(5) = nrb4surf(p8,p9,p4,p3); +% nrb(2) = nrb4surf(p5,p1,p7,p6); +% nrb(3) = nrb4surf(p7,p6,p9,p8); +% nrb(4) = nrb4surf(p6,p1,p8,p4); +% nrb(5) = nrb4surf(p8,p4,p9,p3); % % problem_data.geo_name = nrb; +coefs_1(:,1,:)=[0 0 1; 1 0 1]; +coefs_1(:,2,:)=[-1/3 1/3 1; 1 1 1]; + +coefs_2(:,1,:)=[-1 -1 1; 0 -1 1]; +coefs_2(:,2,:)=[-2/3 -1/3 1; 0 0 1]; + +coefs_3(:,1,:)=[-1 -1 1; -2/3 -1/3 1]; +coefs_3(:,2,:)=[-1 1 1; -2/3 1/3 1]; + +coefs_4(:,1,:)=[-2/3 -1/3 1; 0 0 1]; +coefs_4(:,2,:)=[-2/3 1/3 1; -1/3 1/3 1]; + +coefs_5(:,1,:)=[-2/3 1/3 1; -1/3 1/3 1]; +coefs_5(:,2,:)=[-1 1 1; 1 1 1]; + + +knots{1} = [0 0 1 1]; +knots{2} = [0 0 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +nrb(4)=butterf4; +nrb(5)=butterf5; + +problem_data.geo_name = nrb; + % % 3 patch surf % coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; % coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; @@ -42,46 +75,46 @@ % problem_data.geo_name = nrb; %5 patch surf -coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; -coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; -coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; - -coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; -coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; -coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; - -coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; -coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; -coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; - -coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; -coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; -coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; - -coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; -coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; -coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -nrb(4)=butterf4; -nrb(5)=butterf5; -problem_data.geo_name = nrb; +% coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; +% coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; +% coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; +% +% coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; +% coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; +% coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; +% +% coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; +% coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; +% coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; +% +% coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; +% coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; +% coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; +% +% coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; +% coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; +% coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% nrb(4)=butterf4; +% nrb(5)=butterf5; +% problem_data.geo_name = nrb; % Type of boundary conditions for each side of the domain -problem_data.nmnn_sides = [1 2 3 4 5 6 7 8 9 10]; -problem_data.drchlt_sides = []; -problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8 9 10]; +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [1 2 3 4 5 6]; +problem_data.weak_drchlt_sides = []; % Physical parameters problem_data.c_diff = @(x, y, z) ones(size(x)); @@ -94,8 +127,13 @@ % problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); % problem_data.h = @(x, y, z, ind) solution_bilaplacian_Lshape (x, y); +problem_data.f = @(x,y,z) sin(x); +% problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); +% problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); +problem_data.h = @(x, y, z, ind) sin(x); + % problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); -% problem_data.g = @(x, y, z, ind) (2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2); +% problem_data.g = @(x, y, z, ind) 1; % problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); % problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); % problem_data.graduex = @(x, y, z) cat (1, ... @@ -103,25 +141,32 @@ % reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... % reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); -problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); -problem_data.h = @(x, y, z, ind) z; -problem_data.g = @(x, y, z, ind) z; -problem_data.uex = @(x, y, z) z; -problem_data.graduex = @(x, y, z) cat (1, ... - reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... - reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); +% problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); +% problem_data.h = @(x, y, z, ind) z; +% problem_data.g = @(x, y, z, ind) 1; +% problem_data.uex = @(x, y, z) z; +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... +% reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... +% reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); % Exact solution (optional) -problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); +% problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); % problem_data.graduex = @(x, y, z) solution_bilaplacian_Lshape_grad (x, y); % problem_data.hessuex = @(x, y, z) solution_bilaplacian_Lshape_hessian (x, y); +problem_data.uex = @(x, y, z) sin(x); +problem_data.graduex = @(x, y, z) cat (1, ... + reshape (cos(x), [1, size(x)]), ... + reshape (zeros(size(x)), [1, size(x)]), ... + reshape ( zeros(size(x)), [1, size(x)])); +problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); + % CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +% method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule method_data.Cpen = 10 * (min(method_data.degree) + 1); method_data.space_type = 'standard'; % 'simplified' (only children functions) or 'standard' (full basis) @@ -131,24 +176,49 @@ plot_data.plot_hmesh = false; plot_data.plot_discrete_sol = false; -[geometry, hmsh, hspace, u] = mp_solve_bilaplace_C1 (problem_data, method_data); -if (isfield (problem_data, 'hessuex')) - [err_h2, err_h1, err_l2, err_h2s, err_h1s] = sp_h2_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex); - if (plot_data.print_info) - fprintf('Error in H2 seminorm = %g\n', err_h2s); +h=[]; + +for i= 1:2 + fprintf ('Loop %d \n', i); + method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions + % 3) CALL TO THE SOLVER + + [geometry, hmsh, hspace, u] = mp_solve_bilaplace_C1 (problem_data, method_data); + + h = [h 1/sqrt(hmsh.nel_per_patch(1))]; + + if (isfield (problem_data, 'hessuex')) + [err_h2(i), err_h1(i), err_l2(i), err_h2s(i), err_h1s(i)] = sp_h2_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex); + if (plot_data.print_info) + fprintf('Error in L2 seminorm = %g\n', err_l2(i)); + fprintf('Error in H1 seminorm = %g\n', err_h1(i)); + fprintf('Error in H2 seminorm = %g\n', err_h2(i)); + end end -end +end + % EXPORT VTK FILE subplot(1,2,1) -npts = [51 51]; +npts = [10 10]; sp_plot_solution (u, hspace, geometry, npts); shading interp vtk_pts = {linspace(0,1,npts(1)), linspace(0,1,npts(2))}; subplot(1,2,2) for iptc = 1:hmsh.npatch F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); - X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); - surf(X, Y, problem_data.uex(X,Y)); - hold on; shading interp + X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); Z = reshape (F(3,:), npts); + surf(X, Y, Z, problem_data.uex(X,Y, Z)); + hold on; + shading interp end warning ('on','geopdes:nrbmultipatch') + +figure +loglog(h, err_l2,'-o') +hold on +loglog(h, err_h1s,'-o') +loglog(h, err_h2,'-o') +loglog(h, 100*h.^4,'-x') +loglog(h, 1000*h.^3,'-x') +loglog(h, 10000*h.^2,'-x') +legend("L^2 error", "H^1 error", "H^2 seminorm", "h^4", "h^3", "h^2",'Location','southeast'); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 0532c8e8..45cc1127 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -32,6 +32,7 @@ x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); end coeff_at_qnodes = ones (size(x{1})); + dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel); M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; From e7633a3a7dffd2641836ac0b41585bd4484c9848 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 6 Apr 2022 11:43:50 +0200 Subject: [PATCH 149/366] Comments to implement boundary conditions --- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 1527f842..e5dfa052 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -58,6 +58,15 @@ % u_drchlt = uu(drchlt_dofs); drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); + + +% SET M = M + M2 +% LOOP ON VERTICES +% RESTRICT TO 6x6 matrix and analyze +% If null space is not empty: +% 1) Remove one basis function from drchlt_dofs +% 2) Get the coefficients of the internal functions (will be given as an output) + u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); From 5e5eabc3cbae04f63273ba4b1fe2e1e9e6d486b2 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 18 Apr 2022 13:56:51 +0200 Subject: [PATCH 150/366] Fixed bug for surfaces on the 2D space --- geopdes/inst/multipatch/vertices_struct.m | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index af14f038..0c8f2650 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -118,7 +118,7 @@ patch_reorientation = zeros (valence, 3); for iptc = 1:valence - patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc)).nurbs, msh.rdim); + patch_reorientation(iptc,1:3) = reorientation_vertex (position(iptc), geometry(patches(iptc))); end % Determine the first edge and patch to reorder the patches and edges @@ -290,29 +290,25 @@ function check_orientation (geometry, interfaces) end -function operations = reorientation_vertex (position, nrb, rdim) +function operations = reorientation_vertex (position, geom_patch) operations = zeros (1,3); switch position case 2 operations(1) = 1; - nrb = nrbreverse (nrb, 1); case 3 operations(2) = 1; - nrb = nrbreverse (nrb, 2); case 4 operations(1:2) = [1 1]; - nrb = nrbreverse (nrb, [1 2]); end - if (rdim == 2) - [~,jac] = nrbdeval (nrb, nrbderiv(nrb), {rand(1) rand(1)}); -% jacdet = jac{1}(1) * jac{2}(2) - jac{1}(2) * jac{2}(1); - jacdet = geopdes_det__ (cell2mat(jac)); - if (jacdet < 0) + if (geom_patch.rdim == 2) + jac = geom_patch.map_der({rand(1),rand(1)}); + jacdet = geopdes_det__ (jac); + if ((jacdet > 0 && sum(operations) == 1) || (jacdet < 0 && sum(operations) ~= 1)) operations(3) = 1; end - elseif (rdim == 3) + elseif (geom_patch.rdim == 3) if (sum(operations) == 1) operations(3) = 1; end From 9f282eb4118b9a0659af65629506905f018b010a Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Tue, 19 Apr 2022 10:51:07 +0200 Subject: [PATCH 151/366] Added biharmonic for surfaces --- .../base/ex_bilaplacian_Lshape_5patch.m | 362 +++++++++++++++--- .../inst/examples/base/ex_laplace_beltrami.m | 143 +++++-- .../inst/examples/base/ex_surf_laplace_C1.m | 152 ++++++-- .../@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 60 +++ .../@sp_multipatch_C1/sp_l2_lap_error.m | 48 +++ .../@sp_multipatch_C1/sp_multipatch_C1.asv | 119 +++--- .../@sp_multipatch_C1/sp_multipatch_C1.m | 8 +- .../inst/multipatch/mp_solve_bilaplace_C1.m | 9 +- geopdes/inst/solve/solve_laplace.m | 3 + .../space/@sp_scalar/sp_h2_equiv_lap_error.m | 68 ++++ geopdes/inst/space/@sp_scalar/sp_l2_error.m | 2 +- geopdes/inst/space/sp_h2_equiv_lap_error.m | 66 ++++ geopdes/inst/space/sp_l2_lap_error.m | 52 +++ 13 files changed, 922 insertions(+), 170 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m create mode 100644 geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m create mode 100644 geopdes/inst/space/sp_h2_equiv_lap_error.m create mode 100644 geopdes/inst/space/sp_l2_lap_error.m diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index 1f9a8d7e..6e3d027b 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -13,40 +13,40 @@ % % problem_data.geo_name = nrb; -coefs_1(:,1,:)=[0 0 1; 1 0 1]; -coefs_1(:,2,:)=[-1/3 1/3 1; 1 1 1]; - -coefs_2(:,1,:)=[-1 -1 1; 0 -1 1]; -coefs_2(:,2,:)=[-2/3 -1/3 1; 0 0 1]; - -coefs_3(:,1,:)=[-1 -1 1; -2/3 -1/3 1]; -coefs_3(:,2,:)=[-1 1 1; -2/3 1/3 1]; - -coefs_4(:,1,:)=[-2/3 -1/3 1; 0 0 1]; -coefs_4(:,2,:)=[-2/3 1/3 1; -1/3 1/3 1]; - -coefs_5(:,1,:)=[-2/3 1/3 1; -1/3 1/3 1]; -coefs_5(:,2,:)=[-1 1 1; 1 1 1]; - - -knots{1} = [0 0 1 1]; -knots{2} = [0 0 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -nrb(4)=butterf4; -nrb(5)=butterf5; - -problem_data.geo_name = nrb; +% coefs_1(:,1,:)=[0 0 1; 1 0 1]; +% coefs_1(:,2,:)=[-1/3 1/3 1; 1 1 1]; +% +% coefs_2(:,1,:)=[-1 -1 1; 0 -1 1]; +% coefs_2(:,2,:)=[-2/3 -1/3 1; 0 0 1]; +% +% coefs_3(:,1,:)=[-1 -1 1; -2/3 -1/3 1]; +% coefs_3(:,2,:)=[-1 1 1; -2/3 1/3 1]; +% +% coefs_4(:,1,:)=[-2/3 -1/3 1; 0 0 1]; +% coefs_4(:,2,:)=[-2/3 1/3 1; -1/3 1/3 1]; +% +% coefs_5(:,1,:)=[-2/3 1/3 1; -1/3 1/3 1]; +% coefs_5(:,2,:)=[-1 1 1; 1 1 1]; +% +% +% knots{1} = [0 0 1 1]; +% knots{2} = [0 0 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% nrb(4)=butterf4; +% nrb(5)=butterf5; +% +% problem_data.geo_name = nrb; -% % 3 patch surf +% % 3 patch surf parabolic % coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; % coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; % coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; @@ -74,7 +74,7 @@ % % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); % problem_data.geo_name = nrb; -%5 patch surf +% 5 patch surf parabolic % coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; % coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; % coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; @@ -111,6 +111,145 @@ % nrb(5)=butterf5; % problem_data.geo_name = nrb; + +% % 4 patch surf hyperbolic smooth boundary +% coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; +% coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; +% coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; +% +% coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; +% coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; +% coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; +% +% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; +% coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; +% coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; +% +% coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; +% coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; +% coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% nrb(4)=butterf4; +% problem_data.geo_name = nrb; + +% 4 patch surf hyperbolic non smooth boundary +% coefs_1(:,1,:)=[-1.2 -1.0 0.44; -0.65 -1.1 -1.08; -0.1 -1.2 -1.43]; +% coefs_1(:,2,:)=[-1.3 -0.6 1.48; -0.625 -0.575 -0.12; 0.05 -0.55 0.1]; +% coefs_1(:,3,:)=[-1.4 -0.2 1.92; -0.6 -0.05 -0.26; 0.2 0.1 0.03]; +% +% coefs_2(:,1,:)=[-0.1 -1.2 -1.43; 0.45 -1.1 -1.3; 1.0 -1.0 0.0]; +% coefs_2(:,2,:)=[0.05 -0.55 0.1; 0.625 -0.625 -0.16; 1.2 -0.7 1.0]; +% coefs_2(:,3,:)=[0.2 0.1 0.03; 0.8 -0.15 0.32; 1.4 -0.4 1.8]; +% +% coefs_3(:,1,:)=[0.2 0.1 0.03; 0.8 -0.15 0.32; 1.4 -0.4 1.8]; +% coefs_3(:,2,:)=[0.1 0.75 -0.14; 0.65 0.475 0.34; 1.2 0.2 1.72]; +% coefs_3(:,3,:)=[0.0 1.4 -1.96; 0.5 1.1 -1.12; 1.0 0.8 0.36]; +% +% coefs_4(:,1,:)=[-1.4 -0.2 1.92; -0.6 -0.05 -0.26; 0.2 0.1 0.03]; +% coefs_4(:,2,:)=[-1.2 0.2 1.52; -0.55 0.475 0.01; 0.1 0.75 -0.14]; +% coefs_4(:,3,:)=[-1.0 0.6 0.64; -0.5 1.0 -0.84; 0.0 1.4 -1.96]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% nrb(4)=butterf4; +% problem_data.geo_name = nrb; + +% 3 patch surf hyperbolic non smooth boundary +% coefs_1(:,1,:)=[-0.75 -0.5 0.3125; -0.5416666666666666 -0.75 -0.25; -0.3333333333333333 -1.0 -0.8888888888888888]; +% coefs_1(:,2,:)=[-0.625 0.0 0.625; -0.38333333333333336 -0.275 0.28958333333333336; -0.14166666666666666 -0.55 -0.11666666666666667]; +% coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.025; 0.05 -0.1 -0.0075]; +% +% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 -0.8888888888888888; 0.3333333333333333 -0.875 -1.0833333333333333; 1.0 -0.75 0.4375]; +% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 -0.11666666666666667; 0.5125 -0.4625 -0.23472222222222222; 1.1666666666666667 -0.375 1.3333333333333333]; +% coefs_2(:,3,:)=[0.05 -0.1 -0.0075; 0.6916666666666667 -0.05 0.06666666666666667; 1.3333333333333333 0.0 1.7777777777777777]; +% +% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.6916666666666667 -0.05 0.06666666666666667; 1.3333333333333333 0.0 1.7777777777777777]; +% coefs_3(:,2,:)=[-0.225 0.2 0.025; 0.3458333333333333 0.2875 -0.2833333333333333; 0.9166666666666666 0.375 0.6666666666666666]; +% coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 -0.625; 0.5 0.75 -0.3125]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% problem_data.geo_name = nrb; + +% % 3 patch surf hyperbolic non smooth boundary flat +% coefs_1(:,1,:)=[-0.75 -0.5 1.0; -0.5416666666666666 -0.75 1.0; -0.3333333333333333 -1.0 1.0]; +% coefs_1(:,2,:)=[-0.625 0.0 1.0; -0.38333333333333336 -0.275 1.0; -0.14166666666666666 -0.55 1.0]; +% coefs_1(:,3,:)=[-0.5 0.5 1.0; -0.225 0.2 1.0; 0.05 -0.1 1.0]; +% +% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 1.0; 0.3333333333333333 -0.875 1.0; 1.0 -0.75 1.0]; +% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 1.0; 0.5125 -0.4625 1.0; 1.1666666666666667 -0.375 1.0]; +% coefs_2(:,3,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; +% +% coefs_3(:,1,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; +% coefs_3(:,2,:)=[-0.225 0.2 1.0; 0.3458333333333333 0.2875 1.0; 0.9166666666666666 0.375 1.0]; +% coefs_3(:,3,:)=[-0.5 0.5 1.0; 0.0 0.625 1.0; 0.5 0.75 1.0]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% problem_data.geo_name = nrb; + + +% 3 patch surf hyperbolic non smooth boundary flat 2D +coefs_1(:,1,:)=[-0.75 -0.5 0.0; -0.5416666666666666 -0.75 0.0; -0.3333333333333333 -1.0 0.0]; +coefs_1(:,2,:)=[-0.625 0.0 0.0; -0.38333333333333336 -0.275 0.0; -0.14166666666666666 -0.55 0.0]; +coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.0; 0.05 -0.1 0.0]; + +coefs_2(:,1,:)=[-0.3333333333333333 -1.0 0.0; 0.3333333333333333 -0.875 0.0; 1.0 -0.75 0.0]; +coefs_2(:,2,:)=[-0.14166666666666666 -0.55 0.0; 0.5125 -0.4625 0.0; 1.1666666666666667 -0.375 0.0]; +coefs_2(:,3,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; + +coefs_3(:,1,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; +coefs_3(:,2,:)=[-0.225 0.2 0.0; 0.3458333333333333 0.2875 0.0; 0.9166666666666666 0.375 0.0]; +coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 0.0; 0.5 0.75 0.0]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +% nrb(3)=butterf3; +problem_data.geo_name = nrb; + % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = [1 2 3 4 5 6]; @@ -119,19 +258,43 @@ % Physical parameters problem_data.c_diff = @(x, y, z) ones(size(x)); % Source and boundary terms -C = 1; -p=-1; +% C = 1; +% p=-1; % Bilaplacian % problem_data.f = @(x,y,z) bilaplacian_rhs_Lshape2(x,y); % % problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); -% problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); +% % problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); % problem_data.h = @(x, y, z, ind) solution_bilaplacian_Lshape (x, y); +% +% % Exact solution (optional) +% problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); +% problem_data.graduex = @(x, y, z) solution_bilaplacian_Lshape_grad (x, y); +% problem_data.hessuex = @(x, y, z) solution_bilaplacian_Lshape_hessian (x, y); -problem_data.f = @(x,y,z) sin(x); -% problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); -% problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); -problem_data.h = @(x, y, z, ind) sin(x); +% Cos(5x) Cos(5y) parabolic +% problem_data.f = @(x,y,z) (1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^5) ) * 40 .* (8 * x .* sin(5 * x) .* (-4 * (16 + 151 * x.^2 + 681 * x.^4 + 1408 * x.^6 + 1200 * x.^8 + ... +% 4 * (19 + 153 * x.^2 + 456 * x.^4 + 600 * x.^6) .* y.^2 - 3 * (23 + 192 * x.^2) .* y.^4 - 32 * (31 + 75 * x.^2) .* y.^6 - 1200 * y.^8) .* cos(5 * y) + ... +% 5 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* (63 + 354 * x.^2 + 912 * x.^4 + 800 * x.^6 + 6 * (59 + 304 * x.^2 + 400 * x.^4) .* y.^2 + ... +% 48 * (19 + 50 * x.^2) .* y.^4 + 800 * y.^6) .* sin(5 * y) ) + cos(5 * x) .* (5 * (1 + 4 * x.^2 + 4 * y.^2) .* (37 + 276 * y.^2 + ... +% 4 * (400 * x.^8 + 8 * x.^6 .* (77 + 400 * y.^2) + y.^4 .* (333 + 616 * y.^2 + 400 * y.^4) + ... +% x.^4 .* (333 + 2648 * y.^2 + 5600 * y.^4) + x.^2 .* (69 + 766 * y.^2 + 2648 * y.^4 + 3200 * y.^6) ) ) .* cos(5 * y) - ... +% 32 * y .* (16 - 1200 * x.^8 + 151 * y.^2 + 681 * y.^4 - 32 * x.^6 .* (31 + 75 * y.^2) + 16 * y.^6 .* (88 + 75 * y.^2) - ... +% 3 * x.^4 .* (23 + 192 * y.^2) + 4 * x.^2 .* (19 + 153 * y.^2 + 456 * y.^4 + 600 * y.^6) ) .* sin(5 * y))); +% % problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); +% % problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); +% problem_data.h = @(x, y, z, ind) 2 * cos(5 * x) .* cos(5 * y); +% +% problem_data.uex = @(x, y, z) 2 * cos(5 * x) .* cos(5 * y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape ((-10 * (1 + 4 * y.^2) .* cos(5 * y) .* sin(5 * x) + 40 * x .* y .* cos(5 * x) .* sin(5 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... +% reshape ((40 * x .* y .* cos(5 * y) .* sin(5 * x) - 10 * (1 + 4 * x.^2) .* cos(5 * x) .* sin(5 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... +% reshape ((20 * (x .* cos(5 * y) .* sin(5 * x) + y .* cos(5 * x) .* sin(5 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); +% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% problem_data.lapuex = @(x, y, z) (1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-20 * (1 + 2 * x.^2 + 2 * y.^2) .* cos(5 * x) .* (5 * (1 + 4 * x.^2 + 4 * y.^2) .* cos(5 * y) - ... +% 4 * y .* sin(5 * y) ) + 80 * x .* sin(5 * x) .* ( (1 + 2 * x.^2 + 2 * y.^2) .* cos(5 * y) - 5 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* sin(5 * y) ) ); + +% Cos(3x) Cos(y) % problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); % problem_data.g = @(x, y, z, ind) 1; % problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); @@ -141,26 +304,73 @@ % reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... % reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); -% problem_data.f = @(x, y, z) ( (4 * (1 + 2 * x.^2 + 2 * y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^2); + +% z parabolic +% % problem_data.f = @(x, y, z) -((32 .* (-3 + 24 * x.^4 + 22 * y.^2 + 24 * y.^4 + x.^2 .* (22 + 48 *y.^2) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^5); +% problem_data.f = @(x, y, z) z; +% % problem_data.g = @(x, y, z, ind) z; % problem_data.h = @(x, y, z, ind) z; -% problem_data.g = @(x, y, z, ind) 1; % problem_data.uex = @(x, y, z) z; % problem_data.graduex = @(x, y, z) cat (1, ... % reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... % reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... % reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); +% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% problem_data.lapuex = @(x, y, z) -((4*(1 + 2*x.^2 + 2*y.^2))./(1 + 4*x.^2 + 4*y.^2).^2); + +% z hyperbolic +% % problem_data.f = @(x, y, z) z; +% problem_data.f = @(x, y, z) (64 * (x - y) .* (x + y) .* (13 + 64 *x.^4 + 12 *y.^2 + 64 *y.^4 + x.^2 .*(12 - 768 *y.^2)))./(1 + 4 *x.^2 + 4 *y.^2).^5; +% % problem_data.g = @(x, y, z, ind) z; +% problem_data.h = @(x, y, z, ind) z; +% problem_data.uex = @(x, y, z) z; +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... +% reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... +% reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); +% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% problem_data.lapuex = @(x, y, z) -((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); -% Exact solution (optional) -% problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); -% problem_data.graduex = @(x, y, z) solution_bilaplacian_Lshape_grad (x, y); -% problem_data.hessuex = @(x, y, z) solution_bilaplacian_Lshape_hessian (x, y); -problem_data.uex = @(x, y, z) sin(x); -problem_data.graduex = @(x, y, z) cat (1, ... - reshape (cos(x), [1, size(x)]), ... - reshape (zeros(size(x)), [1, size(x)]), ... - reshape ( zeros(size(x)), [1, size(x)])); -problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% z planar 3d +% % problem_data.f = @(x, y, z) z;-((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2) +% problem_data.f = @(x, y, z) zeros(size(x)); +% % problem_data.g = @(x, y, z, ind) z; +% problem_data.h = @(x, y, z, ind) z; +% problem_data.uex = @(x, y, z) z; +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (zeros(size(x)), [1, size(x)]), ... +% reshape (zeros(size(x)), [1, size(x)]), ... +% reshape (ones(size(x)), [1, size(x)])); +% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% problem_data.lapuex = @(x, y, z) zeros(size(x)); + +% 3D problem +% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +% problem_data.f = @(x,y,z) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); +% problem_data.g = @(x, y, z, ind) zeros(size(x)); +% problem_data.h = @(x, y, z, ind) exp(-C*normax2(x,y)); +% +% % Exact solution (optional) +% problem_data.uex =@(x,y,z) exp(-C*normax2(x,y)); +% problem_data.graduex = @(x,y,z) -2*C*cat (1, ... +% reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... +% reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)]), ... +% reshape (zeros(size(x)), [1, size(x)]) ); + +% 2D +C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); +% problem_data.g = @(x, y, ind) zeros(size(x)); +problem_data.h = @(x, y, ind) exp(-C*normax2(x,y)); + +% Exact solution (optional) +problem_data.uex =@(x,y) exp(-C*normax2(x,y)); +problem_data.graduex = @(x,y) -2*C*cat (1, ... + reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... + reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); % CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) clear method_data @@ -178,7 +388,7 @@ h=[]; -for i= 1:2 +for i= 1:3 fprintf ('Loop %d \n', i); method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions % 3) CALL TO THE SOLVER @@ -186,7 +396,8 @@ [geometry, hmsh, hspace, u] = mp_solve_bilaplace_C1 (problem_data, method_data); h = [h 1/sqrt(hmsh.nel_per_patch(1))]; - + fprintf ('h %g \n', h(i)); + if (isfield (problem_data, 'hessuex')) [err_h2(i), err_h1(i), err_l2(i), err_h2s(i), err_h1s(i)] = sp_h2_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex); if (plot_data.print_info) @@ -194,10 +405,25 @@ fprintf('Error in H1 seminorm = %g\n', err_h1(i)); fprintf('Error in H2 seminorm = %g\n', err_h2(i)); end + elseif (isfield (problem_data, 'lapuex')) + [err_h2(i), err_h1(i), err_l2(i), err_h2s(i), err_h1s(i)] = sp_h2_equiv_lap_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.lapuex); + if (plot_data.print_info) + fprintf('Error in L2 seminorm = %g\n', err_l2(i)); + fprintf('Error in H1 seminorm = %g\n', err_h1s(i)); + fprintf('Error in H2 seminorm = %g\n', err_h2s(i)); + end end + + [err_h1(i), err_l2(i), err_h1s(i)] = sp_h1_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex); + if (plot_data.print_info) + fprintf('Error in L2 seminorm = %g\n', err_l2(i)); + fprintf('Error in H1 seminorm = %g\n', err_h1(i)); + end end + + % EXPORT VTK FILE subplot(1,2,1) npts = [10 10]; @@ -206,19 +432,33 @@ subplot(1,2,2) for iptc = 1:hmsh.npatch F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); - X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); Z = reshape (F(3,:), npts); - surf(X, Y, Z, problem_data.uex(X,Y, Z)); + X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); +% Z = reshape (F(3,:), npts); + surf(X, Y, problem_data.uex(X,Y)); hold on; shading interp end warning ('on','geopdes:nrbmultipatch') + +% figure +% for iptc = 1:hmsh.npatch +% F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); +% X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); Z = reshape (F(3,:), npts); +% +% eu = sp_eval (hspace.Cpatch{iptc}*u, hspace.sp_patch{iptc}, geometry(iptc), vtk_pts); +% surf(X, Y, Z, problem_data.uex(X,Y, Z)-eu); +% hold on; +% shading interp +% end + + figure loglog(h, err_l2,'-o') hold on loglog(h, err_h1s,'-o') -loglog(h, err_h2,'-o') +% loglog(h, err_h2s,'-o') loglog(h, 100*h.^4,'-x') -loglog(h, 1000*h.^3,'-x') -loglog(h, 10000*h.^2,'-x') -legend("L^2 error", "H^1 error", "H^2 seminorm", "h^4", "h^3", "h^2",'Location','southeast'); +loglog(h, 100*h.^3,'-x') +loglog(h, 10*h.^2,'-x') +legend("L^2 error", "H^1 error", "h^4", "h^3", "h^2",'Location','southeast'); diff --git a/geopdes/inst/examples/base/ex_laplace_beltrami.m b/geopdes/inst/examples/base/ex_laplace_beltrami.m index a92a2be1..4857f562 100644 --- a/geopdes/inst/examples/base/ex_laplace_beltrami.m +++ b/geopdes/inst/examples/base/ex_laplace_beltrami.m @@ -3,7 +3,53 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS structure from the NURBS toolbox -problem_data.geo_name = 'geo_roof.txt'; +% problem_data.geo_name = 'geo_roof.txt'; + +% % 4 patch surf hyperbolic smooth boundary +% coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; +% coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; +% coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; +% +% coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; +% coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; +% coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; +% +% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; +% coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; +% coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; +% +% coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; +% coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; +% coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% % nrb(2)=butterf2; +% % nrb(3)=butterf3; +% % nrb(4)=butterf4; +% problem_data.geo_name = nrb; + + +% % 1 patch surf hyperbolic smooth boundary +coefs_1(:,1,:)=[-0.5 -0.5 0.0; 0.0 -0.5 -0.5; 0.5 -0.5 0.0]; +coefs_1(:,2,:)=[-0.5 0.0 0.5; 0.0 0.0 0.0; 0.5 0.0 0.5]; +coefs_1(:,3,:)=[-0.5 0.5 0.0; 0.0 0.5 -0.5; 0.5 0.5 0.0]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); + +nrb(1)=butterf1; +problem_data.geo_name = nrb; + % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; @@ -12,32 +58,58 @@ % Physical parameters problem_data.c_diff = @(x, y, z) ones(size(x)); -% Source and boundary terms -alp = 5; bet = 1; L = 1; -g1 = @(x,y) (1-cos(atan(x./y))).*(1-sin(atan(x./y))); -g2 = @(x,y) cos(atan(x./y)) + sin(atan(x./y)) - 4*cos(atan(x./y)).*sin(atan(x./y)); -gz = @(z) sin(pi*alp/L*z); -dg1 = @(x,y) sin(atan(y./x)).*(1-sin(atan(y./x))) - cos(atan(y./x)).*(1-cos(atan(y./x))); - -problem_data.f = @(x, y, z) bet*((alp*pi/L)^2 * g1(x,y) - g2(x,y)).*gz(z); -problem_data.h = @(x, y, z, ind) bet * g1(x,y).*gz(z); - -% Exact solution (optional) -problem_data.uex = @(x, y, z) bet * g1(x,y).*gz(z); +% % Source and boundary terms +% alp = 5; bet = 1; L = 1; +% g1 = @(x,y) (1-cos(atan(x./y))).*(1-sin(atan(x./y))); +% g2 = @(x,y) cos(atan(x./y)) + sin(atan(x./y)) - 4*cos(atan(x./y)).*sin(atan(x./y)); +% gz = @(z) sin(pi*alp/L*z); +% dg1 = @(x,y) sin(atan(y./x)).*(1-sin(atan(y./x))) - cos(atan(y./x)).*(1-cos(atan(y./x))); +% +% problem_data.f = @(x, y, z) bet*((alp*pi/L)^2 * g1(x,y) - g2(x,y)).*gz(z); +% problem_data.h = @(x, y, z, ind) bet * g1(x,y).*gz(z); +% +% % Exact solution (optional) +% problem_data.uex = @(x, y, z) bet * g1(x,y).*gz(z); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape (-1./sqrt(x.^2+y.^2).*sin(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... +% reshape ( 1./sqrt(x.^2+y.^2).*cos(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... +% reshape ( alp*pi/L * cos(alp*pi/L*z) .* bet .* g1(x,y), [1, size(x)])); + +% % z hyperbolic +% problem_data.f = @(x, y, z) z; +problem_data.f = @(x, y, z) ((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); +% problem_data.g = @(x, y, z, ind) z; +problem_data.h = @(x, y, z, ind) z; +problem_data.uex = @(x, y, z) z; problem_data.graduex = @(x, y, z) cat (1, ... - reshape (-1./sqrt(x.^2+y.^2).*sin(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... - reshape ( 1./sqrt(x.^2+y.^2).*cos(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... - reshape ( alp*pi/L * cos(alp*pi/L*z) .* bet .* g1(x,y), [1, size(x)])); + reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... + reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... + reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); +% problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +% problem_data.lapuex = @(x, y, z) -((8*(x.^2 - y.^2))./(1 + 4*x.^2 + 4*y.^2).^2); + % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data method_data.degree = [3 3]; % Degree of the splines -method_data.regularity = [2 2]; % Regularity of the splines -method_data.nsub = [9 9]; % Number of subdivisions +method_data.regularity = [1 1]; % Regularity of the splines +% method_data.nsub = [9 9]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule -% 3) CALL TO THE SOLVER +h=[]; + +for i= 1:4 + fprintf ('Loop %d \n', i); + method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions + % 3) CALL TO THE SOLVER + + % 3) CALL TO THE SOLVER [geometry, msh, space, u] = solve_laplace (problem_data, method_data); + + h = [h 1/sqrt(msh.nel(1))]; +% Display errors of the computed solution in the L2 and H1 norm +[error_h1(i), error_l2(i)] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) +end % 4) POST-PROCESSING % 4.1) EXPORT TO PARAVIEW @@ -51,17 +123,38 @@ % 4.2) PLOT IN MATLAB. COMPARISON WITH THE EXACT SOLUTION [eu, F] = sp_eval (u, space, geometry, vtk_pts); -[X, Y, Z] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:)), squeeze(F(3,:,:))); +[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); subplot (1,2,1) -surf (X, Y, Z, eu) +surf (X, Y, eu) title ('Numerical solution'), axis tight subplot (1,2,2) -surf (X, Y, Z, problem_data.uex (X,Y,Z)) +surf (X, Y, problem_data.uex (X,Y)) title ('Exact solution'), axis tight -% Display errors of the computed solution in the L2 and H1 norm -[error_h1, error_l2] = ... - sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) + +figure +loglog(h, error_l2,'-o') +hold on +loglog(h, error_h1,'-o') +loglog(h, 100*h.^4,'-x') +loglog(h, 100*h.^3,'-x') +loglog(h, 10*h.^2,'-x') +legend("L^2 error", "H^1 error", "h^4", "h^3", "h^2",'Location','southeast'); + + +% figure +% npts = [20 20]; +% [eu, F] = sp_eval(u, space, geometry, vtk_pts, 'gradient'); +% % F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); +% X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); Z = reshape (F(3,:), npts); +% gradex = problem_data.graduex(X,Y,Z); +% subplot (1,2,1) +% surf(X, Y, Z, squeeze(gradex(3,:,:))); +% shading interp +% subplot (1,2,2) +% surf(X, Y, Z, squeeze(eu(3,:,:))); +% shading interp + %!demo %! ex_laplace_beltrami diff --git a/geopdes/inst/examples/base/ex_surf_laplace_C1.m b/geopdes/inst/examples/base/ex_surf_laplace_C1.m index 00df5ab0..697e74c8 100644 --- a/geopdes/inst/examples/base/ex_surf_laplace_C1.m +++ b/geopdes/inst/examples/base/ex_surf_laplace_C1.m @@ -1,6 +1,7 @@ % EX_LAPLACE_LSHAPED_MP: solve the Poisson problem in the multipatch L-shaped domain with a B-spline discretization. clear all close all +clc % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data @@ -51,32 +52,32 @@ % problem_data.geo_name = nrb; % % 3 patch surf -coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; -coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; -coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; - -coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; -coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; -coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; - -coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; -coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; -coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -% nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); -problem_data.geo_name = nrb; +% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; +% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; +% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; +% +% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; +% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; +% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; +% +% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; +% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; +% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); +% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); +% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); +% problem_data.geo_name = nrb; %5 patch surf @@ -117,6 +118,58 @@ % problem_data.geo_name = nrb; +% 3 patch surf hyperbolic non smooth boundary flat 2D +coefs_1(:,1,:)=[-0.75 -0.5 0.0; -0.5416666666666666 -0.75 0.0; -0.3333333333333333 -1.0 0.0]; +coefs_1(:,2,:)=[-0.625 0.0 0.0; -0.38333333333333336 -0.275 0.0; -0.14166666666666666 -0.55 0.0]; +coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.0; 0.05 -0.1 0.0]; + +coefs_2(:,1,:)=[-0.3333333333333333 -1.0 0.0; 0.3333333333333333 -0.875 0.0; 1.0 -0.75 0.0]; +coefs_2(:,2,:)=[-0.14166666666666666 -0.55 0.0; 0.5125 -0.4625 0.0; 1.1666666666666667 -0.375 0.0]; +coefs_2(:,3,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; + +coefs_3(:,1,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; +coefs_3(:,2,:)=[-0.225 0.2 0.0; 0.3458333333333333 0.2875 0.0; 0.9166666666666666 0.375 0.0]; +coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 0.0; 0.5 0.75 0.0]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +problem_data.geo_name = nrb; + + +% % 3 patch surf hyperbolic non smooth boundary flat +% coefs_1(:,1,:)=[-0.75 -0.5 1.0; -0.5416666666666666 -0.75 1.0; -0.3333333333333333 -1.0 1.0]; +% coefs_1(:,2,:)=[-0.625 0.0 1.0; -0.38333333333333336 -0.275 1.0; -0.14166666666666666 -0.55 1.0]; +% coefs_1(:,3,:)=[-0.5 0.5 1.0; -0.225 0.2 1.0; 0.05 -0.1 1.0]; +% +% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 1.0; 0.3333333333333333 -0.875 1.0; 1.0 -0.75 1.0]; +% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 1.0; 0.5125 -0.4625 1.0; 1.1666666666666667 -0.375 1.0]; +% coefs_2(:,3,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; +% +% coefs_3(:,1,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; +% coefs_3(:,2,:)=[-0.225 0.2 1.0; 0.3458333333333333 0.2875 1.0; 0.9166666666666666 0.375 1.0]; +% coefs_3(:,3,:)=[-0.5 0.5 1.0; 0.0 0.625 1.0; 0.5 0.75 1.0]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; +% nrb(3)=butterf3; +% problem_data.geo_name = nrb; + + % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = []; @@ -168,13 +221,13 @@ % reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); -problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); -problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); -problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); -problem_data.graduex = @(x, y, z) cat (1, ... - reshape ((-3*(1 + 4*y.^2).*cos(y).*sin(3*x) + 4*x.*y.*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... - reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... - reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); +% problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); +% problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); +% problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); +% problem_data.graduex = @(x, y, z) cat (1, ... +% reshape ((-3*(1 + 4*y.^2).*cos(y).*sin(3*x) + 4*x.*y.*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... +% reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... +% reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); % problem_data.f = @(x, y) zeros (size(x)); @@ -185,9 +238,38 @@ % reshape (exp(y).*sin(x), [1, size(x)])); +% 2D +C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); +% problem_data.g = @(x, y, ind) zeros(size(x)); +problem_data.h = @(x, y, ind) exp(-C*normax2(x,y)); + +% Exact solution (optional) +problem_data.uex =@(x,y) exp(-C*normax2(x,y)); +problem_data.graduex = @(x,y) -2*C*cat (1, ... + reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... + reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); + + +% 3D problem +% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +% problem_data.f = @(x,y,z) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); +% problem_data.g = @(x, y, z, ind) zeros(size(x)); +% problem_data.h = @(x, y, z, ind) exp(-C*normax2(x,y)); +% +% % Exact solution (optional) +% problem_data.uex =@(x,y,z) exp(-C*normax2(x,y)); +% problem_data.graduex = @(x,y,z) -2*C*cat (1, ... +% reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... +% reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)]), ... +% reshape (zeros(size(x)), [1, size(x)]) ); + + % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data -method_data.degree = [5 5]; % Degree of the splines +method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule @@ -195,7 +277,7 @@ h=[]; -for i= 1:4 +for i= 1:1 fprintf ('Loop %d \n', i); method_data.nsub = [2^(i+1) 2^(i+1)] ; % Number of subdivisions % 3) CALL TO THE SOLVER diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m new file mode 100644 index 00000000..c272655e --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -0,0 +1,60 @@ +% SP_H2_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, lapuex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% lapuex: function handle to evaluate the laplacian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2015, 2017 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_equiv_lap_error (space, msh, u, uex, graduex, lapuex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + [error_h2(iptc), error_h1(iptc), error_l2(iptc), error_h2s_lap(iptc), error_h1s(iptc)] = ... + sp_h2_equiv_lap_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex, lapuex); + + end + errl2 = sqrt (sum (error_l2 .* error_l2)); + errh1 = sqrt (sum (error_h1 .* error_h1)); + errh1s = sqrt (sum (error_h1s .* error_h1s)); + errh2 = sqrt (sum (error_h2 .* error_h2)); + errh2s = sqrt (sum (error_h2s_lap .* error_h2s_lap)); + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m new file mode 100644 index 00000000..0e108798 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m @@ -0,0 +1,48 @@ +% SP_L2_ERROR: Evaluate the error in L^2 norm. +% +% errl2 = sp_l2_error (space, msh, u, uex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% +% OUTPUT: +% +% errl2: error in L^2 norm +% +% Copyright (C) 2015 Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function errl2_lap = sp_l2_lap_error (space, msh, u, lapuex) + + if (space.npatch ~= msh.npatch) + error ('The number of patches does not coincide') + end + + for iptc = 1:msh.npatch +% if (isempty (space.dofs_ornt)) + u_ptc = space.Cpatch{iptc} * u; +% else +% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; +% end + error_l2_lap(iptc) = sp_l2_lap_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, lapuex); + end + errl2_lap = sqrt (sum (error_l2_lap .* error_l2_lap)); + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv index 058470c3..7d035f39 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv @@ -163,11 +163,17 @@ function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces_all, vertices) % Store the coefficients for matrix change in Cpatch Cpatch = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); + shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); +% Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); + rows = sp.interior_dofs_per_patch{iptc}; + cols = global_indices; + vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); + Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), sp.ndof); +% Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... +% speye (numel (sp.interior_dofs_per_patch{iptc})); + sp.dofs_on_patch{iptc} = shift_index_patch(iptc)+1:shift_index_patch(iptc+1); end sp.dofs_on_edge = cell (1, numel(interfaces_all)); @@ -281,9 +287,12 @@ for iref = 1:numel(interfaces_all) % end end -% if msh.ndim+1~=msh.rdim || planar_surf + if msh.ndim + 1 == msh.rdim + [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); + else + disp(' [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); -% else + end % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); % [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); @@ -416,7 +425,6 @@ for iref = 1:numel(interfaces_all) end end -if msh.ndim+1~=msh.rdim % Computation of CC_vertices % Auxiliary constants to deal with different regularity cases in the M matrices if (reg < pp-2) @@ -437,6 +445,9 @@ for kver = 1:numel(vertices) KV_matrices=cell(1,valence_p); geo_local = reorientation_patches (operations, geometry(patches)); + %Here we need to further modify geo_local by rotating the parametrization + %of the patches, that is, for each ip in patches, rotate the control points + %geometry(ip).nurbs.coefs (4 x (number of control points in dir 1) x (number of control points in dir 2) matrix) % Precompute the derivatives and compute sigma sigma = 0; @@ -456,9 +467,55 @@ for kver = 1:numel(vertices) %Storing sigma for output v_fun_matrices{1,kver}=sigma; + if msh.ndim+1==msh.rdim + %Tangent vectors + Du_F = derivatives_new1{1}(:,1); + Dv_F = derivatives_new1{1}(:,2); + %Normal vector + normal=cross(Du_F,Dv_F); + unit_normal=normal/norm(normal); + %Vector orthogonal to n and z along which the geometry is rotated + %(rotation axis) + r=cross(unit_normal,[0 0 1]'); + %Angle between n and z + cos_th=[0 0 1]*unit_normal; + sin_th=norm(r); + %Rotation matrix + R=[cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... + r(1)*r(2)*(1-cos_th)+r(3)*sin_th,cos_th + r(2)^2*(1-cos_th),r(2)*r(3)*(1-cos_th)-r(1)*sin_th;... + r(1)*r(3)*(1-cos_th)-r(2)*sin_th,r(3)*r(2)*(1-cos_th)+r(1)*sin_th,cos_th + r(3)^2*(1-cos_th)]; + + for ipatch = 1:valence_p + + coeff_hom=geo_local(ipatch).nurbs.coefs; + coeff_w=coeff_hom(4,:,:); + coeff_eu=coeff_hom(1:3,:,:)./(repmat(coeff_w,3,1,1)); %Euclidean coefficients + rot_coeff=ones(4,size(coeff_eu,2),size(coeff_eu,3)); + for k=1:size(coeff_eu,3) + rot_coeff(1:3,:,k)=R*(coeff_eu(:,:,k)-coeff_eu(:,1,1))+coeff_eu(:,1,1); + end + rot_nrb(ipatch)=geometry(patches(ipatch)).nurbs; + rot_nrb(ipatch).coefs=rot_coeff; + end + + rot_geo = mp_geo_load(rot_nrb); + + for iptc = 1:valence_p + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim}=[knots{idim}(1) knots{idim}(end)]; + end + rot_msh_pts_der1 = msh_cartesian (brk, {0 0}, [], rot_geo(iptc),'boundary', true, 'der2', true); + rot_msh_der = msh_precompute (rot_msh_pts_der1); + derivatives_new1{iptc} = rot_msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives_new2{iptc} = rot_msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} + end + end + for ipatch = 1:valence_p - prev_edge = ipatch; - next_edge = mod(ipatch, valence_e) + 1; + + prev_edge = ipatch; + next_edge = mod(ipatch, valence_e) + 1; % Compute gluing data, and edge functions from CC_edges_discarded if (edge_orientation(prev_edge) == 1) @@ -490,11 +547,11 @@ for kver = 1:numel(vertices) E_next(:,[4 5]) = -E_next(:,[4 5]); end - Du_F = derivatives_new1{ipatch}(:,1); - Dv_F = derivatives_new1{ipatch}(:,2); - Duu_F = derivatives_new2{ipatch}(:,1,1); - Duv_F = derivatives_new2{ipatch}(:,1,2); - Dvv_F = derivatives_new2{ipatch}(:,2,2); + Du_F = derivatives_new1{ipatch}(1:2,1); + Dv_F = derivatives_new1{ipatch}(1:2,2); + Duu_F = derivatives_new2{ipatch}(1:2,1,1); + Duv_F = derivatives_new2{ipatch}(1:2,1,2); + Dvv_F = derivatives_new2{ipatch}(1:2,2,2); % Edge information t0_prev = Du_F; @@ -559,10 +616,12 @@ for kver = 1:numel(vertices) KV_matrices{ipatch}.K_prev=M_prev; KV_matrices{ipatch}.K_next=M_next; KV_matrices{ipatch}.V=VV; + KV_matrices{ipatch}.E_prev=E_prev; + KV_matrices{ipatch}.E_next=E_next; end v_fun_matrices{2,kver}=KV_matrices; end -end + end @@ -580,36 +639,7 @@ function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev beta1 = [0 0]; return end - - if size(geo_map_jac{1},1)==3 - grev_pts_red{1}=grev_pts{1}([1 end]); - grev_pts_red{2}=grev_pts{2}([1 end]); - for ii=1:length(geo_map_jac) - geo_map_jac_red{ii}=geo_map_jac{ii}(:,:,:,[1 end]); - end - if (side(2)==1 || side(2)==2) - v = grev_pts_red{2}(:); - else - v = grev_pts_red{1}(:); - end - ngrev = numel(v); - DuFR_x = reshape (geo_map_jac_red{1}(1,1,:,:), ngrev, 1); - DuFR_y = reshape (geo_map_jac_red{1}(2,1,:,:), ngrev, 1); - DuFR_z = reshape (geo_map_jac_red{1}(3,1,:,:), ngrev, 1); - DvFL_x = reshape (geo_map_jac_red{2}(1,2,:,:), ngrev, 1); - DvFL_y = reshape (geo_map_jac_red{2}(2,2,:,:), ngrev, 1); - DvFL_z = reshape (geo_map_jac_red{2}(3,2,:,:), ngrev, 1); - DvFR_x = reshape (geo_map_jac_red{1}(1,2,:,:), ngrev, 1); - DvFR_y = reshape (geo_map_jac_red{1}(2,2,:,:), ngrev, 1); - DvFR_z = reshape (geo_map_jac_red{1}(3,2,:,:), ngrev, 1); - - A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; - (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; - rank_A=rank(A_full); - end - - if rank_A<5 || + % Assemble and solve G^1 conditions system if (side(2)==1 || side(2)==2) v = grev_pts{2}(:); @@ -617,7 +647,6 @@ function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev v = grev_pts{1}(:); end ngrev = numel(v); - DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d99d8552..9098af48 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -286,12 +286,14 @@ % DvFR_z = reshape (geo_map_jac_reduced{1}(3,2,:,:), ngrev, 1); % end end - - if msh.ndim+1 == msh.rdim + + if msh.ndim + 1 == msh.rdim [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); else + disp('Planar GD'); [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); end + keyboard % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); % [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); @@ -467,6 +469,8 @@ v_fun_matrices{1,kver}=sigma; if msh.ndim+1==msh.rdim + + disp('Surf code'); %Tangent vectors Du_F = derivatives_new1{1}(:,1); Dv_F = derivatives_new1{1}(:,2); diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 45c84cd0..f8f25c8a 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -87,9 +87,16 @@ clear sp % Compute and assemble the matrices -stiff_mat = op_gradgradu_gradgradv_mp (space, space, msh, c_diff); +% GradGrad operator +% stiff_mat = op_gradgradu_gradgradv_mp (space, space, msh, c_diff); + +% Laplacian operator (For biharmonic problem) +stiff_mat = op_laplaceu_laplacev_mp (space, space, msh, c_diff); rhs = op_f_v_mp (space, msh, f); +% stiff_mat = op_u_v_mp (space, space, msh, c_diff); +% rhs = op_f_v_mp (space, msh, f); + % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 87844923..6ce3dc14 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -83,6 +83,9 @@ stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); rhs = op_f_v_tp (space, msh, f); +% stiff_mat = op_u_v_tp (space, space, msh, c_diff); +% rhs = op_f_v_tp (space, msh, f); + % Apply Neumann boundary conditions for iside = nmnn_sides if (msh.ndim > 1) diff --git a/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m b/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m new file mode 100644 index 00000000..a8dc9bb3 --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m @@ -0,0 +1,68 @@ +% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% hessuex: function handle to evaluate the hessian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm +% errh1s: error in H^1 seminorm +% +% Copyright (C) 2010 Carlo de Falco +% Copyright (C) 2011, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016 Viacheslav Balobanov +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_equiv_lap_error (sp, msh, u, uex, graduex, lapuex) + + if (numel(u) ~= sp.ndof) + error ('Wrong size of the vector of degrees of freedom') + end + + errl2 = 0; + errh1s = 0; + errh2s = 0; + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (sp, msh_col, 'gradient', true, 'laplacian', true); + + [~, ~, err_l2, err_h2s, err_h1s] = sp_h2_equiv_lap_error (sp_col, msh_col, u, uex, graduex, lapuex); + + errh2s = errh2s + err_h2s.^2; + errh1s = errh1s + err_h1s.^2; + errl2 = errl2 + err_l2.^2; + end + + errh2 = sqrt (errl2 + errh1s + errh2s); + errh1 = sqrt (errl2 + errh1s); + errl2 = sqrt (errl2); + + errh2s = sqrt (errh2s); + errh1s = sqrt (errh1s); + +end \ No newline at end of file diff --git a/geopdes/inst/space/@sp_scalar/sp_l2_error.m b/geopdes/inst/space/@sp_scalar/sp_l2_error.m index ed128a6c..4d2383e7 100644 --- a/geopdes/inst/space/@sp_scalar/sp_l2_error.m +++ b/geopdes/inst/space/@sp_scalar/sp_l2_error.m @@ -40,7 +40,7 @@ for iel = 1:msh.nel_dir(1) msh_col = msh_evaluate_col (msh, iel); - sp_col = sp_evaluate_col (space, msh_col, 'value', true, 'gradient', false); + sp_col = sp_evaluate_col (space, msh_col, 'value', true, 'gradient', false, 'laplacian', true); errl2 = errl2 + (sp_l2_error (sp_col, msh_col, u, uex)).^2; end diff --git a/geopdes/inst/space/sp_h2_equiv_lap_error.m b/geopdes/inst/space/sp_h2_equiv_lap_error.m new file mode 100644 index 00000000..1068b9de --- /dev/null +++ b/geopdes/inst/space/sp_h2_equiv_lap_error.m @@ -0,0 +1,66 @@ +% SP_H2_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. +% +% [errh2, errh1, errl2, errh2s, errh1s, errh2_elem, errh1_elem, errl2_elem, errh2s_elem, errh1s_elem] = sp_h2_error (sp, msh, u, uex, graduex, lapuex) +% +% INPUT: +% +% space: structure representing the space of discrete functions (see sp_scalar/sp_evaluate_col) +% msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% graduex: function handle to evaluate the gradient of the exact solution +% lapuex: function handle to evaluate the laplacian of the exact solution +% +% OUTPUT: +% +% errh2: error in H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm +% errh2s: error in H^2 seminorm (involving only second dervatives) +% errh1s: error in H^1 seminorm +% errh2_elem: error in H^2 norm, for each single element +% errh1_elem: error in H^1 norm, for each single element +% errl2_elem: error in L^2 norm, for each single element +% errh2s_elem: error in H^2 seminorm, for each single element +% errh1s_elem: error in H^1 seminorm, for each single element +% +% Copyright (C) 2010 Carlo de Falco +% Copyright (C) 2011, 2016 Rafael Vazquez +% Copyright (C) 2015, 2016 Viacheslav Balobanov +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errh2, errh1, errl2, errh2s, errh1s, errh2_elem, errh1_elem, errl2_elem, errh2s_elem, errh1s_elem] = ... + sp_h2_equiv_lap_error (sp, msh, u, uex, graduex, lapuex) + + lap_valu = sp_eval_msh (u, sp, msh, 'laplacian'); + lap_valu = reshape (lap_valu, sp.ncomp, msh.nqn, msh.nel); + + for idir = 1:msh.rdim + x{idir} = reshape (msh.geo_map(idir,:,:), msh.nqn*msh.nel, 1); + end + lap_valex = reshape (feval (lapuex, x{:}), sp.ncomp, msh.nqn, msh.nel); + + w = msh.quad_weights .* msh.jacdet; + + [errh1, errl2, errh1s, errh1_elem, errl2_elem, errh1s_elem] = sp_h1_error (sp, msh, u, uex, graduex); + + errh2s_elem = sum (reshape (sum ((lap_valu - lap_valex).^2, 1), [msh.nqn, msh.nel]) .*w); + errh2s = sqrt (sum (errh2s_elem)); + + errh2 = sqrt (errh1^2 + errh2s^2); + errh2_elem = sqrt (errh1_elem.^2 + errh2s_elem); + +end \ No newline at end of file diff --git a/geopdes/inst/space/sp_l2_lap_error.m b/geopdes/inst/space/sp_l2_lap_error.m new file mode 100644 index 00000000..bf903778 --- /dev/null +++ b/geopdes/inst/space/sp_l2_lap_error.m @@ -0,0 +1,52 @@ +% SP_L2_ERROR: Evaluate the error in L^2 norm. +% +% [errl2, errl2_elem] = sp_l2_error (space, msh, u, uex); +% +% INPUT: +% +% space: structure representing the space of discrete functions (see sp_scalar/sp_evaluate_col) +% msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution +% +% OUTPUT: +% +% errl2: error in L^2 norm +% errl2_elem: error in L^2 norm, for each single element +% +% Copyright (C) 2010 Carlo de Falco +% Copyright (C) 2011 Rafael Vazquez +% Copyright (C) 2015 Eduardo M. Garau, Rafael Vazquez +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation; either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with Octave; see the file COPYING. If not, see +% . + +function [errl2lap, errl2lap_elem] = sp_l2_lap_error (sp, msh, u, lapuex) + + lap_valu = sp_eval_msh (u, sp, msh, 'laplacian'); + lap_valu = reshape (lap_valu, sp.ncomp, msh.nqn, msh.nel); + + for idir = 1:msh.rdim + x{idir} = reshape (msh.geo_map(idir,:,:), msh.nqn*msh.nel, 1); + end + lap_valex = reshape (feval (lapuex, x{:}), sp.ncomp, msh.nqn, msh.nel); + + w = msh.quad_weights .* msh.jacdet; + + errl2lap_elem = sum (reshape (sum ((lap_valu - lap_valex).^2, 1), [msh.nqn, msh.nel]) .* w); + + errl2lap = sqrt (sum (errl2lap_elem)); + errl2lap_elem = sqrt (errl2lap_elem); + +end \ No newline at end of file From 7950ec7511ec16cd75d7ac57767288fb9fbfb0e4 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 28 Apr 2022 11:05:24 +0200 Subject: [PATCH 152/366] Added kernel computation in bdy condition files --- .../base/ex_bilaplacian_Lshape_5patch.m | 176 ++-- .../sp_bilaplacian_drchlt_C1.m | 34 +- .../sp_bilaplacian_drchlt_C1_exact.m | 32 +- .../@sp_multipatch_C1/sp_multipatch_C1.asv | 931 ------------------ .../@sp_multipatch_C1/sp_multipatch_C1.m | 1 - .../inst/multipatch/mp_solve_bilaplace_C1.m | 7 +- 6 files changed, 160 insertions(+), 1021 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index 6e3d027b..9ff4a6d2 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -113,35 +113,35 @@ % % 4 patch surf hyperbolic smooth boundary -% coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; -% coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; -% coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; -% -% coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; -% coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; -% coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; -% -% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; -% coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; -% coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; -% -% coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; -% coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; -% coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% nrb(4)=butterf4; -% problem_data.geo_name = nrb; +coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; +coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; +coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; + +coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; +coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; +coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; + +coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; +coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; +coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; + +coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; +coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; +coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; + +knots{1} = [0 0 0 1 1 1]; +knots{2} = [0 0 0 1 1 1]; + +butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); + +nrb(1)=butterf1; +nrb(2)=butterf2; +nrb(3)=butterf3; +nrb(4)=butterf4; +problem_data.geo_name = nrb; % 4 patch surf hyperbolic non smooth boundary % coefs_1(:,1,:)=[-1.2 -1.0 0.44; -0.65 -1.1 -1.08; -0.1 -1.2 -1.43]; @@ -226,33 +226,33 @@ % 3 patch surf hyperbolic non smooth boundary flat 2D -coefs_1(:,1,:)=[-0.75 -0.5 0.0; -0.5416666666666666 -0.75 0.0; -0.3333333333333333 -1.0 0.0]; -coefs_1(:,2,:)=[-0.625 0.0 0.0; -0.38333333333333336 -0.275 0.0; -0.14166666666666666 -0.55 0.0]; -coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.0; 0.05 -0.1 0.0]; - -coefs_2(:,1,:)=[-0.3333333333333333 -1.0 0.0; 0.3333333333333333 -0.875 0.0; 1.0 -0.75 0.0]; -coefs_2(:,2,:)=[-0.14166666666666666 -0.55 0.0; 0.5125 -0.4625 0.0; 1.1666666666666667 -0.375 0.0]; -coefs_2(:,3,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; - -coefs_3(:,1,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; -coefs_3(:,2,:)=[-0.225 0.2 0.0; 0.3458333333333333 0.2875 0.0; 0.9166666666666666 0.375 0.0]; -coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 0.0; 0.5 0.75 0.0]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; +% coefs_1(:,1,:)=[-0.75 -0.5 0.0; -0.5416666666666666 -0.75 0.0; -0.3333333333333333 -1.0 0.0]; +% coefs_1(:,2,:)=[-0.625 0.0 0.0; -0.38333333333333336 -0.275 0.0; -0.14166666666666666 -0.55 0.0]; +% coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.0; 0.05 -0.1 0.0]; +% +% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 0.0; 0.3333333333333333 -0.875 0.0; 1.0 -0.75 0.0]; +% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 0.0; 0.5125 -0.4625 0.0; 1.1666666666666667 -0.375 0.0]; +% coefs_2(:,3,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; +% +% coefs_3(:,1,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; +% coefs_3(:,2,:)=[-0.225 0.2 0.0; 0.3458333333333333 0.2875 0.0; 0.9166666666666666 0.375 0.0]; +% coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 0.0; 0.5 0.75 0.0]; +% +% knots{1} = [0 0 0 1 1 1]; +% knots{2} = [0 0 0 1 1 1]; +% +% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); +% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); +% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); +% +% nrb(1)=butterf1; +% nrb(2)=butterf2; % nrb(3)=butterf3; -problem_data.geo_name = nrb; +% problem_data.geo_name = nrb; % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; -problem_data.drchlt_sides = [1 2 3 4 5 6]; +problem_data.drchlt_sides = [1 2 3 4 5 6 7 8]; problem_data.weak_drchlt_sides = []; % Physical parameters @@ -319,17 +319,17 @@ % problem_data.lapuex = @(x, y, z) -((4*(1 + 2*x.^2 + 2*y.^2))./(1 + 4*x.^2 + 4*y.^2).^2); % z hyperbolic -% % problem_data.f = @(x, y, z) z; -% problem_data.f = @(x, y, z) (64 * (x - y) .* (x + y) .* (13 + 64 *x.^4 + 12 *y.^2 + 64 *y.^4 + x.^2 .*(12 - 768 *y.^2)))./(1 + 4 *x.^2 + 4 *y.^2).^5; -% % problem_data.g = @(x, y, z, ind) z; -% problem_data.h = @(x, y, z, ind) z; -% problem_data.uex = @(x, y, z) z; -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... -% reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... -% reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); -% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -% problem_data.lapuex = @(x, y, z) -((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); +% problem_data.f = @(x, y, z) z; +problem_data.f = @(x, y, z) (64 * (x - y) .* (x + y) .* (13 + 64 *x.^4 + 12 *y.^2 + 64 *y.^4 + x.^2 .*(12 - 768 *y.^2)))./(1 + 4 *x.^2 + 4 *y.^2).^5; +% problem_data.g = @(x, y, z, ind) z; +problem_data.h = @(x, y, z, ind) z; +problem_data.uex = @(x, y, z) z; +problem_data.graduex = @(x, y, z) cat (1, ... + reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... + reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... + reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); +% problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); +problem_data.lapuex = @(x, y, z) -((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); % z planar 3d @@ -359,18 +359,32 @@ % reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)]), ... % reshape (zeros(size(x)), [1, size(x)]) ); +% % 2D +% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +% problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); +% % problem_data.g = @(x, y, ind) zeros(size(x)); +% problem_data.h = @(x, y, ind) exp(-C*normax2(x,y)); +% +% % Exact solution (optional) +% problem_data.uex =@(x,y) exp(-C*normax2(x,y)); +% problem_data.graduex = @(x,y) -2*C*cat (1, ... +% reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... +% reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); + + % 2D -C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; -normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); -problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); -% problem_data.g = @(x, y, ind) zeros(size(x)); -problem_data.h = @(x, y, ind) exp(-C*normax2(x,y)); - -% Exact solution (optional) -problem_data.uex =@(x,y) exp(-C*normax2(x,y)); -problem_data.graduex = @(x,y) -2*C*cat (1, ... - reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... - reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); +% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); +% problem_data.f = @(x,y) 256*cos(4*x); +% % problem_data.g = @(x, y, ind) zeros(size(x)); +% problem_data.h = @(x, y, ind) cos(4*x); +% +% % Exact solution (optional) +% problem_data.uex =@(x,y) cos(4*x); +% problem_data.graduex = @(x,y) cat (1, ... +% reshape (-4*sin(4*x), [1, size(x)]), ... +% reshape (zeros(size(x)), [1, size(x)])); % CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) clear method_data @@ -413,12 +427,6 @@ fprintf('Error in H2 seminorm = %g\n', err_h2s(i)); end end - - [err_h1(i), err_l2(i), err_h1s(i)] = sp_h1_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex); - if (plot_data.print_info) - fprintf('Error in L2 seminorm = %g\n', err_l2(i)); - fprintf('Error in H1 seminorm = %g\n', err_h1(i)); - end end @@ -433,8 +441,8 @@ for iptc = 1:hmsh.npatch F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); -% Z = reshape (F(3,:), npts); - surf(X, Y, problem_data.uex(X,Y)); + Z = reshape (F(3,:), npts); + surf(X, Y, Z, problem_data.uex(X,Y,Z)); hold on; shading interp end @@ -457,8 +465,8 @@ loglog(h, err_l2,'-o') hold on loglog(h, err_h1s,'-o') -% loglog(h, err_h2s,'-o') +loglog(h, err_h2s,'-o') loglog(h, 100*h.^4,'-x') loglog(h, 100*h.^3,'-x') loglog(h, 10*h.^2,'-x') -legend("L^2 error", "H^1 error", "h^4", "h^3", "h^2",'Location','southeast'); +legend("L^2 error", "H^1 error", "H^2 error", "h^4", "h^3", "h^2",'Location','southeast'); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index e5dfa052..85b201d4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) +function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -57,7 +57,35 @@ % drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); % u_drchlt = uu(drchlt_dofs); -drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +% Kernel computation for separating verrtex boundary functions + +% Insert a h-dependent parameter in front of M2 +M_bdy = M + M2; +dofs_to_remove = []; +add_int_dofs = {}; +count_vert = 0; + + for iv = 1 : numel(space.vertices) + % Loop just over Dirichlet boundary vertices + if space.vertices(iv).boundary_vertex + M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if ~isempty(ker) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; + add_int_dofs{count_vert, 1} = iv; + add_int_dofs{count_vert, 2} = ker; + add_int_dofs{count_vert, 3} = ind; + + end + % Pick up the basis function with the max coeff abs val in the ker + % Use the other as bdy functions + % Check the global index of the removed function, remove it + % from dirichlet dofs and add the function in the kernel into + % the internal part (it should go in the output) + end + end % SET M = M + M2 @@ -66,6 +94,8 @@ % If null space is not empty: % 1) Remove one basis function from drchlt_dofs % 2) Get the coefficients of the internal functions (will be given as an output) +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index a443defa..7440732b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -58,7 +58,37 @@ % drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); % u_drchlt = uu(drchlt_dofs); + +% Insert a h-dependent parameter in front of M2 +M_bdy = M + M2; +dofs_to_remove = []; +add_int_dofs = {}; +count_vert = 0; + + for iv = 1 : numel(space.vertices) + % Loop just over Dirichlet boundary vertices + if space.vertices(iv).boundary_vertex + M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if ~isempty(ker) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; + add_int_dofs{count_vert, 1} = iv; + add_int_dofs{count_vert, 2} = ker; + add_int_dofs{count_vert, 3} = ind; + end + % Pick up the basis function with the max coeff abs val in the ker + % Use the other as bdy functions + % Check the global index of the removed function, remove it + % from dirichlet dofs and add the function in the kernel into + % the internal part (it should go in the output) + end + end + drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); + u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv deleted file mode 100644 index 7d035f39..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.asv +++ /dev/null @@ -1,931 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% sp = sp_multipatch_C1 (spaces, msh, geometry, edges, vertices) -% -% INPUT: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% geometry: geometry struct (see mp_geo_load) -% edges: struct array similar to interfaces (see vertices_struct) -% vertices: struct array with vertex information (see vertices_struct) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% ndof_interior (scalar) total number of interior degrees of freedom -% ndof_edges (scalar) total number of edge degrees of freedom -% ndof_vertices (scalar) total number of vertex degrees of freedom -% interior_dofs_per_patch (1 x npatch cell-array) local number of interior functions on each patch -% dofs_on_edge (1 x nedges cell-array) global numbering of edge functions on each edge -% dofs_on_vertex (1 x nvertices cell-array) global numbering of the six functions on each vertex -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar) -% Cpatch (1 x npatch cell-array) coefficients of the linear combination of basis functions as standard B-splines, -% on each patch. The matrix Cpatch{iptc} has size ndof_per_patch(iptc) x ndof -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% sp_plot_solution: plot the solution in Matlab -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Other methods -% sp_refine: generate a refined space, and subdivision matrices for the univariate spaces -% -% Copyright (C) 2015-2021 Rafael Vazquez -% Copyright (C) 2019-2021 Cesare Bracco -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces_all, vertices) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - -% if (msh.ndim ~= 2 || msh.rdim ~= 2) -% error ('Only implemented for planar surfaces') -% end - - for iptc = 1:numel(geometry) - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Knot vectors of auxiliary spaces - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom, and the coefficients to -% express them as linear combinations of B-splines. -% See the function compute_coefficients below for details. - sp.ndof_interior = 0; - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces_all) - patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; - sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... - compute_coefficients (sp, msh, geometry, interfaces_all, vertices); - -%Sigmas, K and V matrices used in the construction of vertex functions - sp.vertex_function_matrices=v_fun_matrices; - -% Total number of functions, and of functions of each type - sp.ndof_edges = sum (ndof_per_interface); - sp.ndof_vertices = sum (ndof_per_vertex); - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Store the coefficients for matrix change in Cpatch - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - shift_index_patch = cumsum ([0 numel_interior_dofs]); - for iptc = 1:sp.npatch -% Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - rows = sp.interior_dofs_per_patch{iptc}; - cols = global_indices; - vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); - Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), sp.ndof); -% Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... -% speye (numel (sp.interior_dofs_per_patch{iptc})); - sp.dofs_on_patch{iptc} = shift_index_patch(iptc)+1:shift_index_patch(iptc+1); - end - - sp.dofs_on_edge = cell (1, numel(interfaces_all)); - for intrfc = 1:numel(interfaces_all) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - sp.dofs_on_edge{intrfc} = global_indices; - patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; - for iptc = 1:numel(patches) - Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; - end - end - - sp.dofs_on_vertex = cell (1, numel(vertices)); - for ivrt = 1:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); - sp.dofs_on_vertex{ivrt} = global_indices; - for iptc = 1:vertices(ivrt).valence_p - patch = vertices(ivrt).patches(iptc); - Cpatch{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; - end - end - - sp.Cpatch = Cpatch; - -% I store this for simplicity - sp.interfaces = interfaces_all; - sp.vertices = vertices; - sp.geometry = geometry; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces_all, vertices); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); -end - - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = compute_coefficients (space, msh, geometry, interfaces_all, vertices) -% OUTPUT from compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices). Even if the value is always six. -% CC_vertices: cell array of size 1 x numel(vertices), each entry containin another -% cell-array of size 1 x vertices(ii).valence_p (local number of patches) -% The matrix CC_vertices{jj}{ii} has size sp.ndof_per_patch(patch) x ndof_per_vertex(ii) -% with patch = vertices(jj).patches(ii). - -% Initialize cell array containing sigma, K and V matrices for each vertex -v_fun_matrices=cell(2, numel(vertices)); - -%Initialize output variables with correct size -ndof_per_interface = zeros (1, numel(interfaces_all)); -ndof_per_vertex = 6*ones(1,numel(vertices)); - -CC_edges = cell (2, numel (interfaces_all)); -CC_edges_discarded = cell (2, numel (interfaces_all)); -CC_vertices = cell (1, numel(vertices)); -for jj = 1:numel(vertices) - CC_vertices{jj} = cell (1,vertices(jj).valence_p); - for kk=1:vertices(jj).valence_p - CC_vertices{jj}{kk}=zeros(space.sp_patch{kk}.ndof,6); - end -end - -pp = space.sp_patch{1}.degree(1); -breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); -kk = numel(breaks_m{1}) - 2; -mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg = pp - max(mult(2:end-1)); - -all_alpha0 = zeros(numel(interfaces_all),2); -all_alpha1 = zeros(numel(interfaces_all),2); -all_beta0 = zeros(numel(interfaces_all),2); -all_beta1 = zeros(numel(interfaces_all),2); - -%Computation of CC_edges -for iref = 1:numel(interfaces_all) - patches = [interfaces_all(iref).patch1 interfaces_all(iref).patch2]; - npatches_on_edge = numel (patches); - operations = interfaces_all(iref).operations; -% Auxiliary geometry with orientation as in the paper - geo_local = reorientation_patches (operations, geometry(patches)); - sides = [1 3]; - -% Compute gluing data - geo_map_jac = cell (npatches_on_edge, 1); - for ii = 1:npatches_on_edge - brk = cell (1,msh.ndim); - grev_pts = cell (1, msh.ndim); - knt = geo_local(ii).nurbs.knots; - order = geo_local(ii).nurbs.order; - for idim = 1:msh.ndim - grev_pts{idim} = [knt{idim}(order(idim)) (knt{idim}(order(idim))+knt{idim}(end-order(idim)+1))/2 knt{idim}(end-order(idim)+1)]; - brk{idim} = [knt{idim}(order(idim)), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knt{idim}(end-order(idim)+1)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); - msh_side_interior = msh_precompute (msh_side_interior); - geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% if msh.ndim+1==msh.rdim -% geo_map_jac_reduced{ii}=geo_map_jac{ii}(:,:,:,[1 end]); -% DuFR_z = reshape (geo_map_jac_reduced{1}(3,1,:,:), ngrev, 1); -% DvFL_z = reshape (geo_map_jac_reduced{2}(3,2,:,:), ngrev, 1); -% DvFR_z = reshape (geo_map_jac_reduced{1}(3,2,:,:), ngrev, 1); -% end - end - - if msh.ndim + 1 == msh.rdim - [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); - else - disp(' - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); - end -% grev_pts_reduced{1}=grev_pts{1}([1 end]); -% grev_pts_reduced{2}=grev_pts{2}([1 end]); -% [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); -% end - clear geo_map_jac msh_grev msh_side_interior grev_pts - %clear geo_map_jac geo_map_jac_reduced msh_grev msh_side_interior grev_pts - - %Saving alphas and betas (first column=i_0, second column=i_1) - all_alpha0(iref,:) = alpha0; - all_alpha1(iref,:) = alpha1; - all_beta0(iref,:) = beta0; - all_beta1(iref,:) = beta1; - -% Compute the Greville points, and the auxiliary mesh and space objects for -% functions with reduced degree or increased regularity - for ii = 1:npatches_on_edge -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (sides(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - brk = cell (1,msh.ndim); - grev_pts = cell (1, msh.ndim); - degrees = degree_reorientation (space.sp_patch{patches(ii)}.degree, operations(ii,3)); - degree = degrees(ind1); - - knots = knot_vector_reorientation (space.sp_patch{patches(ii)}.knots, operations(ii,:)); - knots0 = knot_vector_reorientation (space.knots0_patches{patches(ii)}, operations(ii,:)); - knots0 = knots0{ind1}; - knots1 = knot_vector_reorientation (space.knots1_patches{patches(ii)}, operations(ii,:)); - knots1 = knots1{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, degrees(idim)+1);%space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - end - msh_grev = msh_cartesian (brk, grev_pts, [], geo_local(ii), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - degu = degrees(ind2); - knt = unique (knots{ind2}); - tau1 = knt(2) - knt(1); - -% sp_aux contains the value and derivatives of the basis functions, at the Greville points - msh_side = msh_eval_boundary_side (msh_grev, sides(ii)); - msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); - sp_aux = sp_bspline (knots, degrees, msh_side_interior); - -% Univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) and N^{p,r} on the interface - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(sides(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(sides(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); - - knotsn = knots{ind1}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(sides(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(sides(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems - A = sparse (msh_side.nel, msh_side.nel); - for jj = 1:msh_side.nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; - beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; - -% RHS and solution of the linear systems, (14)-(16) in Mario's notes - rhss = sparse (msh_side.nel, sp0_struct.ndof); - for jj = 1:msh_side.nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0 = A \ rhss; - coeff0(abs(coeff0) < 1e-12) = 0; % Make more sparse - - rhsb = sparse (msh_side.nel, sp0_struct.ndof); - if (ii == 1) % paper case, (sides(ii) == 1) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (ii == 2) %The other paper case, (sides(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side.nel - val_aux = -val * beta(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1 = A \ rhsb; - coeff1(abs(coeff1) < 1e-12) = 0; % Make more sparse - - rhsc = sparse (msh_side.nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); - for jj = 1:msh_side.nel - val_aux = val * alpha(jj)* (-1)^(ii+1); - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2 = A \ rhsc; - coeff2(abs(coeff2) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis - ndof_dir = sp_aux.ndof_dir; %space.sp_patch{patch(ii)}.ndof_dir; - ndof_dir_original = space.sp_patch{patches(ii)}.ndof_dir; - if (ii == 1) %(sides(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (ii == 2) %(sides(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - end - indices_reoriented = indices_reorientation (ndof_dir_original, operations(ii,:)); - ind0_ornt = indices_reoriented(ind0); - ind1_ornt = indices_reoriented(ind1); - -% Store the coefficients in CC_edges, and compute the number of functions - ndof_edge = sp0_struct.ndof + sp1_struct.ndof; - trace_functions = 4:sp0_struct.ndof-3; - deriv_functions = sp0_struct.ndof + (3:sp1_struct.ndof-2); - active_functions = union (trace_functions, deriv_functions); - discarded_functions = setdiff (1:ndof_edge, active_functions); - - CC = sparse (space.ndof_per_patch(patches(ii)), ndof_edge); - CC(ind0_ornt,1:sp0_struct.ndof) = coeff0; - CC(ind1_ornt,1:sp0_struct.ndof) = coeff1; - CC(ind1_ornt,sp0_struct.ndof+(1:sp1_struct.ndof)) = coeff2; - - ndof_per_interface(iref) = numel(active_functions); - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patches(ii)), ndof_per_interface(iref)); - CC_edges{ii,iref} = CC(:,active_functions); - CC_edges_discarded{ii,iref} = CC(:,discarded_functions); - end -end - -% Computation of CC_vertices -% Auxiliary constants to deal with different regularity cases in the M matrices -if (reg < pp-2) - const1 = 2; const2 = 1; -else - const1 = 3; const2 = 2; -end - -for kver = 1:numel(vertices) - edges = vertices(kver).edges; - patches = vertices(kver).patches; - valence_e = vertices(kver).valence_e; - valence_p = vertices(kver).valence_p; - operations = vertices(kver).patch_reorientation; - edge_orientation = vertices(kver).edge_orientation; - - %Initializing the cell-array containing, for vertex kver, K and V matrices - KV_matrices=cell(1,valence_p); - - geo_local = reorientation_patches (operations, geometry(patches)); - %Here we need to further modify geo_local by rotating the parametrization - %of the patches, that is, for each ip in patches, rotate the control points - %geometry(ip).nurbs.coefs (4 x (number of control points in dir 1) x (number of control points in dir 2) matrix) - -% Precompute the derivatives and compute sigma - sigma = 0; - for iptc = 1:valence_p - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; - end - msh_pts_der1 = msh_cartesian (brk, {0 0}, [], geo_local(iptc),'boundary', true, 'der2', true); - msh_der = msh_precompute (msh_pts_der1); - derivatives_new1{iptc} = msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives_new2{iptc} = msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} - - sigma = sigma + norm (derivatives_new1{iptc}, Inf); - end - sigma = pp*(kk+1)*valence_p/sigma; - %Storing sigma for output - v_fun_matrices{1,kver}=sigma; - - if msh.ndim+1==msh.rdim - %Tangent vectors - Du_F = derivatives_new1{1}(:,1); - Dv_F = derivatives_new1{1}(:,2); - %Normal vector - normal=cross(Du_F,Dv_F); - unit_normal=normal/norm(normal); - %Vector orthogonal to n and z along which the geometry is rotated - %(rotation axis) - r=cross(unit_normal,[0 0 1]'); - %Angle between n and z - cos_th=[0 0 1]*unit_normal; - sin_th=norm(r); - %Rotation matrix - R=[cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... - r(1)*r(2)*(1-cos_th)+r(3)*sin_th,cos_th + r(2)^2*(1-cos_th),r(2)*r(3)*(1-cos_th)-r(1)*sin_th;... - r(1)*r(3)*(1-cos_th)-r(2)*sin_th,r(3)*r(2)*(1-cos_th)+r(1)*sin_th,cos_th + r(3)^2*(1-cos_th)]; - - for ipatch = 1:valence_p - - coeff_hom=geo_local(ipatch).nurbs.coefs; - coeff_w=coeff_hom(4,:,:); - coeff_eu=coeff_hom(1:3,:,:)./(repmat(coeff_w,3,1,1)); %Euclidean coefficients - rot_coeff=ones(4,size(coeff_eu,2),size(coeff_eu,3)); - for k=1:size(coeff_eu,3) - rot_coeff(1:3,:,k)=R*(coeff_eu(:,:,k)-coeff_eu(:,1,1))+coeff_eu(:,1,1); - end - rot_nrb(ipatch)=geometry(patches(ipatch)).nurbs; - rot_nrb(ipatch).coefs=rot_coeff; - end - - rot_geo = mp_geo_load(rot_nrb); - - for iptc = 1:valence_p - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; - end - rot_msh_pts_der1 = msh_cartesian (brk, {0 0}, [], rot_geo(iptc),'boundary', true, 'der2', true); - rot_msh_der = msh_precompute (rot_msh_pts_der1); - derivatives_new1{iptc} = rot_msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives_new2{iptc} = rot_msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} - end - end - - for ipatch = 1:valence_p - - prev_edge = ipatch; - next_edge = mod(ipatch, valence_e) + 1; - -% Compute gluing data, and edge functions from CC_edges_discarded - if (edge_orientation(prev_edge) == 1) - alpha_prev = all_alpha0(edges(prev_edge),2); - beta_prev = all_beta0(edges(prev_edge),2); - alpha_der_prev = -all_alpha0(edges(prev_edge),2) + all_alpha1(edges(prev_edge),2); - beta_der_prev = -all_beta0(edges(prev_edge),2) + all_beta1(edges(prev_edge),2); - E_prev = CC_edges_discarded{2,edges(prev_edge)}(:,[1 2 3 7 8]); - else - alpha_prev = all_alpha1(edges(prev_edge),1); - beta_prev = -all_beta1(edges(prev_edge),1); - alpha_der_prev = all_alpha0(edges(prev_edge),1) - all_alpha1(edges(prev_edge),1); - beta_der_prev = -all_beta0(edges(prev_edge),1) + all_beta1(edges(prev_edge),1); - E_prev = CC_edges_discarded{1,edges(prev_edge)}(:,[6 5 4 10 9]); - E_prev(:,[4 5]) = -E_prev(:,[4 5]); - end - if (edge_orientation(next_edge) == 1) - alpha_next = all_alpha0(edges(next_edge),1); - beta_next = all_beta0(edges(next_edge),1); - alpha_der_next = -all_alpha0(edges(next_edge),1) + all_alpha1(edges(next_edge),1); - beta_der_next = -all_beta0(edges(next_edge),1) + all_beta1(edges(next_edge),1); - E_next = CC_edges_discarded{1,edges(next_edge)}(:,[1 2 3 7 8]); - else - alpha_next = all_alpha1(edges(next_edge),2); - beta_next = -all_beta1(edges(next_edge),2); - alpha_der_next = all_alpha0(edges(next_edge),2) - all_alpha1(edges(next_edge),2); - beta_der_next = -all_beta0(edges(next_edge),2) + all_beta1(edges(next_edge),2); - E_next = CC_edges_discarded{2,edges(next_edge)}(:,[6 5 4 10 9]); - E_next(:,[4 5]) = -E_next(:,[4 5]); - end - - Du_F = derivatives_new1{ipatch}(1:2,1); - Dv_F = derivatives_new1{ipatch}(1:2,2); - Duu_F = derivatives_new2{ipatch}(1:2,1,1); - Duv_F = derivatives_new2{ipatch}(1:2,1,2); - Dvv_F = derivatives_new2{ipatch}(1:2,2,2); - -% Edge information - t0_prev = Du_F; - t0_next = Dv_F; - t0p_prev = Duu_F; - t0p_next = Dvv_F; - - d0_prev = -(Dv_F + beta_prev * Du_F) / alpha_prev; - d0_next = (Du_F + beta_next * Dv_F) / alpha_next; - d0p_prev = ( alpha_der_prev * (Dv_F + beta_prev*Du_F) - ... - alpha_prev * (Duv_F + beta_der_prev*Du_F + beta_prev*Duu_F)) / alpha_prev^2; - d0p_next = (-alpha_der_next * (Du_F + beta_next*Dv_F) + ... - alpha_next * (Duv_F + beta_der_next*Dv_F + beta_next*Dvv_F)) / alpha_next^2; - -% Compute M and V matrices - ndof = space.sp_patch{patches(ipatch)}.ndof; - M_prev = sparse (5,6); M_next = sparse (5,6); - VV = sparse (ndof,6); - - ndof_dir = space.sp_patch{patches(ipatch)}.ndof_dir; - all_indices = indices_reorientation (ndof_dir, operations(ipatch,:)); - corner_4dofs = all_indices(1:2,1:2); - jfun = 1; - for j1 = 0:2 - for j2 = 0:2-j1 - mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; - vec_deltas = [(j1==1)*(j2==0); (j1==0)*(j2==1)]; - c0 = (j1==0)*(j2==0); - %M_{i_{m-1},i} - c1_a = vec_deltas.'*t0_prev; - c2_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; - d0_a = vec_deltas.'*d0_prev; - d1_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; - - %M_{i_{m+1},i} - c1_b = vec_deltas.'*t0_next; - c2_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; - d0_b = vec_deltas.'*d0_next; - d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; - - M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+const1*c1_a/(pp*(kk+1))+const2*c2_a/(pp*(pp-1)*(kk+1)^2), ... - d0_a/(pp*(kk+1)), ... - d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_b/(pp*(kk+1)), ... - c0+const1*c1_b/(pp*(kk+1))+const2*c2_b/(pp*(pp-1)*(kk+1)^2), ... - d0_b/(pp*(kk+1)), ... - d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; - %V_{i_m,i} - e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; - VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+c1_b/(pp*(kk+1)), ... - c0+(c1_a+c1_b+e11/(pp*(kk+1)))/(pp*(kk+1))]'; - jfun = jfun+1; - end - end - CC_vertices{kver}{ipatch} = E_prev*M_prev + E_next*M_next - VV; - %Storing the matrices for output - KV_matrices{ipatch}.K_prev=M_prev; - KV_matrices{ipatch}.K_next=M_next; - KV_matrices{ipatch}.V=VV; - KV_matrices{ipatch}.E_prev=E_prev; - KV_matrices{ipatch}.E_next=E_next; - end - v_fun_matrices{2,kver}=KV_matrices; -end - - -end - -function [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, side) -% OUTPUT from gluing data -% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. -% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring -% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). - -% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. - if (numel (geo_map_jac) == 1) - alpha0 = [1 1]; - alpha1 = [1 1]; - beta0 = [0 0]; - beta1 = [0 0]; - return - end - - % Assemble and solve G^1 conditions system - if (side(2)==1 || side(2)==2) - v = grev_pts{2}(:); - else - v = grev_pts{1}(:); - end - ngrev = numel(v); - DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); - DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); - DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); - DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); - DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); - DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); - - A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if (rank(A_full)==6) - A = A_full(:,2:end); - b = -A_full(:,1); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = sols(1); - alpha0_n(2) = sols(2); - alpha1_n(2) = sols(3); - beta0_n = sols(4); - beta1_n = sols(5); - beta2_n = sols(6); - else - A = A_full(:,3:end); % FIX: not a square matrix - b = -sum(A_full(:,1:2),2); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = 1; - alpha0_n(2) = sols(1); - alpha1_n(2) = sols(2); - beta0_n = sols(3); - beta1_n = sols(4); - beta2_n = sols(5); - end - - % Normalize the alphas - C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; - C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); - gamma = 3*C2/(2*C1); - alpha0(1) = alpha0_n(1)*gamma; - alpha1(1) = alpha1_n(1)*gamma; - alpha0(2) = alpha0_n(2)*gamma; - alpha1(2) = alpha1_n(2)*gamma; - bbeta0 = beta0_n*gamma; - bbeta1 = beta1_n*gamma; - bbeta2 = beta2_n*gamma; - - % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. - alpha_R_0 = alpha0(1); - alpha_R_1 = alpha1(1); - alpha_R_12 = (alpha0(1)+alpha1(1))/2; - alpha_L_0 = alpha0(2); - alpha_L_1 = alpha1(2); - alpha_L_12 = (alpha0(2)+alpha1(2))/2; - beta_0 = bbeta0; - beta_1 = bbeta2; - beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; - - % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta - M = [alpha_R_0 0 alpha_L_0 0; ... - 0 alpha_R_1 0 alpha_L_1; ... - alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; - - if (rank(M)==3) - % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R - quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - - % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where - a = quant2; b = quant1; - c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; - e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; - - %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L - C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; - C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; - beta0(1) = -C2/(2*C1); - beta1(1) = a + b*beta0(1); - beta0(2) = c + d*beta0(1); - beta1(2) = e + f*beta0(1); - - else - % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: - % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; - c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; - - % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L - M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b = [-b*c-2*a*b; -a*d-2*c*d]; - sol = M2\M2b; - beta0(1)= sol(1); - beta1(1)= sol(2); - beta0(2)= a + b*beta0(1); - beta1(2)= c + d*beta1(1); - end - -end - - -function [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, side) -% OUTPUT from gluing data -% The gluing data are computed as alpha = alpha0*(1-t) + alpha1*t. -% The two components of alpha0, alpha1, beta0, beta1 refer to the neighboring -% patches: first or second ((i,0) and (i,1) in the draft, L and R in old notation). - -% For boundary edges we set alpha=1 and beta=0. For simplicity, we store an inexistent second patch. - if (numel (geo_map_jac) == 1) - alpha0 = [1 1]; - alpha1 = [1 1]; - beta0 = [0 0]; - beta1 = [0 0]; - return - end - - % Assemble and solve G^1 conditions system - if (side(2)==1 || side(2)==2) - v = grev_pts{2}(:); - else - v = grev_pts{1}(:); - end - ngrev = numel(v); - DuFR_x = reshape (geo_map_jac{1}(1,1,:,:), ngrev, 1); - DuFR_y = reshape (geo_map_jac{1}(2,1,:,:), ngrev, 1); - DuFR_z = reshape (geo_map_jac{1}(3,1,:,:), ngrev, 1); - DvFL_x = reshape (geo_map_jac{2}(1,2,:,:), ngrev, 1); - DvFL_y = reshape (geo_map_jac{2}(2,2,:,:), ngrev, 1); - DvFL_z = reshape (geo_map_jac{2}(3,2,:,:), ngrev, 1); - DvFR_x = reshape (geo_map_jac{1}(1,2,:,:), ngrev, 1); - DvFR_y = reshape (geo_map_jac{1}(2,2,:,:), ngrev, 1); - DvFR_z = reshape (geo_map_jac{1}(3,2,:,:), ngrev, 1); - - A_full = [(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y; - (1-v).*DvFL_z v.*DvFL_z (1-v).*DuFR_z v.*DuFR_z (1-v).^2.*DvFR_z 2*(1-v).*v.*DvFR_z v.^2.*DvFR_z]; - - if (rank(A_full)==6) - A = A_full(:,2:end); - b = -A_full(:,1); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = sols(1); - alpha0_n(2) = sols(2); - alpha1_n(2) = sols(3); - beta0_n = sols(4); - beta1_n = sols(5); - beta2_n = sols(6); - else - A = A_full(:,3:end); % FIX: not a square matrix - b = -sum(A_full(:,1:2),2); - sols = A\b; - alpha0_n(1) = 1; - alpha1_n(1) = 1; - alpha0_n(2) = sols(1); - alpha1_n(2) = sols(2); - beta0_n = sols(3); - beta1_n = sols(4); - beta2_n = sols(5); - end - - % Normalize the alphas - C1 = alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2+alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2; - C2 = alpha0_n(2)+alpha1_n(2)+alpha0_n(1)+alpha1_n(1); - gamma = 3*C2/(2*C1); - alpha0(1) = alpha0_n(1)*gamma; - alpha1(1) = alpha1_n(1)*gamma; - alpha0(2) = alpha0_n(2)*gamma; - alpha1(2) = alpha1_n(2)*gamma; - bbeta0 = beta0_n*gamma; - bbeta1 = beta1_n*gamma; - bbeta2 = beta2_n*gamma; - - % Compute the betas, evaluating alphas and betas at 0, 1/2, 1. - alpha_R_0 = alpha0(1); - alpha_R_1 = alpha1(1); - alpha_R_12 = (alpha0(1)+alpha1(1))/2; - alpha_L_0 = alpha0(2); - alpha_L_1 = alpha1(2); - alpha_L_12 = (alpha0(2)+alpha1(2))/2; - beta_0 = bbeta0; - beta_1 = bbeta2; - beta_12 = (bbeta0+bbeta2)/4+bbeta1/2; - - % Compute the matrix of the system considering the relationship between beta^(i,0), beta^(i,1) and beta - M = [alpha_R_0 0 alpha_L_0 0; ... - 0 alpha_R_1 0 alpha_L_1; ... - alpha_R_12/2 alpha_R_12/2 alpha_L_12/2 alpha_L_12/2]; - - if (rank(M)==3) - % Compute beta1_R, beta0_L, beta1_L in terms of beta0_R - quant1 = (-alpha_L_12/2 + (alpha_L_0*alpha_R_12)/(2*alpha_R_0)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - quant2 = (beta_12-(beta_0*alpha_R_12)/(2*alpha_R_0) - (beta_1*alpha_R_12)/(2*alpha_R_1)) / ... - (-(alpha_L_1*alpha_R_12)/(2*alpha_R_1) + alpha_L_12/2); - - % beta1_R=a+b*beta0_R, beta0_L=c+d*beta0_R, beta1_L=e+f*beta0_R, where - a = quant2; b = quant1; - c = beta_0/alpha_R_0; d = -alpha_L_0/alpha_R_0; - e = (beta_1-alpha_L_1*quant2)/alpha_R_1; f = -alpha_L_1*quant1/alpha_R_1; - - %We determine beta0_R by minimizing the sum of the norms of beta_R and beta_L - C1 = ((b-1)^2)/3 + (b-1) + ((f-d)^2)/3 + (f-d)*d + d^2 + 1; - C2 = 2*a*(b-1)/3 + a + 2*(e-c)*(f-d)/3 + (e-c)*d + (f-d)*c + 2*c*d; - beta0(1) = -C2/(2*C1); - beta1(1) = a + b*beta0(1); - beta0(2) = c + d*beta0(1); - beta1(2) = e + f*beta0(1); - - else - % Compute beta0_L in terms of beta0_R and beta1_L in terms of beta1_R: - % beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a = beta_0/alpha_R_0; b = -alpha_L_0/alpha_R_0; - c = beta_1/alpha_R_1; d = -alpha_L_1/alpha_R_1; - - % Determine beta0_R and beta_1_R by minimizing the sum of the norms of beta_R and beta_L - M2 = [2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b = [-b*c-2*a*b; -a*d-2*c*d]; - sol = M2\M2b; - beta0(1)= sol(1); - beta1(1)= sol(2); - beta0(2)= a + b*beta0(1); - beta1(2)= c + d*beta1(1); - end - -end - - -% Functions to deal with general orientation of the patches -function geo_reoriented = reorientation_patches (operations, geometry) - nrb_patches = [geometry.nurbs]; - for ii = 1:numel(nrb_patches) - if (operations(ii,1)) - nrb_patches(ii) = nrbreverse (nrb_patches(ii), 1); - end - if (operations(ii,2)) - nrb_patches(ii) = nrbreverse (nrb_patches(ii), 2); - end - if (operations(ii,3)) - nrb_patches(ii) = nrbtransp (nrb_patches(ii)); - end - end - - geo_reoriented = mp_geo_load (nrb_patches); -% [geo_reoriented, ~, local_interface] = mp_geo_load (nrb_patches); -% if (numel (nrb_patches) == 2) -% if (local_interface.side1 ~= 1 || local_interface.side2 ~= 3 || local_interface.ornt ~= 1) -% error('The reorientation is wrong') -% end -% end -end - -function knots = knot_vector_reorientation (knots, operations) - if (operations(1)) - knots{1} = sort (1 - knots{1}); - end - if (operations(2)) - knots{2} = sort (1-knots{2}); - end - if (operations(3)) - knots([2 1]) = knots([1 2]); - end -end - -function degree = degree_reorientation (degree, transposition) - if (transposition) - degree = degree([2 1]); - end -end - -function indices = indices_reorientation (ndof_dir, operations) - ndof = prod (ndof_dir); - indices = reshape (1:ndof, ndof_dir); - if (operations(1)) - indices = flipud (indices); - end - if (operations(2)) - indices = fliplr (indices); - end - if (operations(3)) - indices = indices.'; - end -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 9098af48..156eb34b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -293,7 +293,6 @@ disp('Planar GD'); [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); end - keyboard % grev_pts_reduced{1}=grev_pts{1}([1 end]); % grev_pts_reduced{2}=grev_pts{2}([1 end]); % [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index f8f25c8a..9bab56ba 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -94,18 +94,21 @@ stiff_mat = op_laplaceu_laplacev_mp (space, space, msh, c_diff); rhs = op_f_v_mp (space, msh, f); +% L2 approximation % stiff_mat = op_u_v_mp (space, space, msh, c_diff); % rhs = op_f_v_mp (space, msh, f); % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) - [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); + [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); else - [u_drchlt, drchlt_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); + [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); end u(drchlt_dofs) = u_drchlt; + + int_dofs = setdiff (1:space.ndof, drchlt_dofs); rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; %zeros(length(int_dofs),1)-(abs(stiff_mat(int_dofs, drchlt_dofs))>1e-14)*ones(length(drchlt_dofs),1);%rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; From ffae93aa7dc65c52e9ab7c936d4fb1d5e7995820 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Wed, 4 May 2022 17:05:17 +0200 Subject: [PATCH 153/366] Added kernel computation for bdy vertex basis functions --- .../base/ex_bilaplacian_Lshape_5patch.m | 2 +- .../sp_bilaplacian_drchlt_C1_exact.m | 2 +- .../inst/multipatch/mp_solve_bilaplace_C1.m | 54 +++++++++++++++++-- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index 9ff4a6d2..f17cc766 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -402,7 +402,7 @@ h=[]; -for i= 1:3 +for i= 1:1 fprintf ('Loop %d \n', i); method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions % 3) CALL TO THE SOLVER diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 7440732b..e1e195c4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -72,7 +72,7 @@ ker = null(full(M_ker)); if ~isempty(ker) count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); + [max_val, ind] = max(abs(ker)); dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; add_int_dofs{count_vert, 1} = iv; add_int_dofs{count_vert, 2} = ker; diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 9bab56ba..be2bde80 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -108,11 +108,59 @@ u(drchlt_dofs) = u_drchlt; - int_dofs = setdiff (1:space.ndof, drchlt_dofs); -rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; %zeros(length(int_dofs),1)-(abs(stiff_mat(int_dofs, drchlt_dofs))>1e-14)*ones(length(drchlt_dofs),1);%rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; + +add_mat = []; +add_rhs = []; +add_rb = []; +add_dofs = []; +s_vec = zeros(size(add_int_dofs, 1), size(add_int_dofs, 1)); +B_change = speye(space.ndof); + +for bv = 1 : size(add_int_dofs, 1) +% space.dofs_on_vertex{add_int_dofs{bv, 1}} +% b_change = eye(6); +% b_change(:, add_int_dofs{bv, 3}) = add_int_dofs{bv, 2}; % To transform from the new basis to the old one +% B_change([space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3}) ] + + B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}) = eye(6); + B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})) = add_int_dofs{bv, 2}; + + add_mat = [add_mat; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, int_dofs) ]; + add_rhs = [add_rhs; add_int_dofs{bv, 2}.' * rhs(space.dofs_on_vertex{add_int_dofs{bv, 1}})]; + add_rb = [add_rb; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, drchlt_dofs) * u_drchlt]; + add_dofs = [add_dofs space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})]; + + for bv_1 = 1 : size(add_int_dofs, 1) + s_vec(bv, bv_1) = add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv_1, 1}}) * add_int_dofs{bv_1, 2}; + end + + +end + +A = [stiff_mat(int_dofs, int_dofs) add_mat'; ... + add_mat s_vec ]; + +r = [rhs(int_dofs); ... + add_rhs ]; + +rb = [ stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; ... + add_rb ]; + +% rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; %zeros(length(int_dofs),1)-(abs(stiff_mat(int_dofs, drchlt_dofs))>1e-14)*ones(length(drchlt_dofs),1);%rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; % Solve the linear system -u(int_dofs) = stiff_mat(int_dofs,int_dofs) \ rhs(int_dofs); +% u(int_dofs) = stiff_mat(int_dofs,int_dofs) \ rhs(int_dofs); +% size(u) + +int_dofs_new = [int_dofs add_dofs]; + +u_newBasis(int_dofs_new) = A \ (r - rb); +u_newBasis(drchlt_dofs) = u_drchlt; + +% u(int_dofs) = u_int_dofs_newBasis(1:numel(int_dofs)); +% u([add_dofs drchlt_dofs]) = B_change * u_newBasis([ drchlt_dofs]); + +u = B_change * u_newBasis'; end From 134810b0f5d77d1862d68542a94f3632691686d2 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 5 May 2022 11:25:21 +0200 Subject: [PATCH 154/366] Fixed kernel computation for smooth boundary --- .../inst/examples/base/ex_bilaplacian_Lshape_5patch.m | 9 +++++---- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 2 +- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 4 ++-- geopdes/inst/multipatch/mp_solve_bilaplace_C1.m | 7 ++++--- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index f17cc766..67ae9dbe 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -1,5 +1,6 @@ close all clear all +clc warning ('off','geopdes:nrbmultipatch') % PHYSICAL DATA OF THE PROBLEM @@ -402,7 +403,7 @@ h=[]; -for i= 1:1 +for i= 1:3 fprintf ('Loop %d \n', i); method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions % 3) CALL TO THE SOLVER @@ -466,7 +467,7 @@ hold on loglog(h, err_h1s,'-o') loglog(h, err_h2s,'-o') -loglog(h, 100*h.^4,'-x') -loglog(h, 100*h.^3,'-x') -loglog(h, 10*h.^2,'-x') +loglog(h, 0.001*h.^4,'-x') +loglog(h, 0.01*h.^3,'-x') +loglog(h, 0.1*h.^2,'-x') legend("L^2 error", "H^1 error", "H^2 error", "h^4", "h^3", "h^2",'Location','southeast'); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 85b201d4..4a9e093e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) +function [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index e1e195c4..db9136c6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -86,7 +86,7 @@ end end -drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index be2bde80..497b6414 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -101,14 +101,15 @@ % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) - [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); + [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); else - [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); + [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); end u(drchlt_dofs) = u_drchlt; int_dofs = setdiff (1:space.ndof, drchlt_dofs); +int_dofs = setdiff (int_dofs, dofs_to_remove); add_mat = []; add_rhs = []; @@ -139,7 +140,7 @@ end A = [stiff_mat(int_dofs, int_dofs) add_mat'; ... - add_mat s_vec ]; + add_mat s_vec ]; r = [rhs(int_dofs); ... add_rhs ]; From 0491255fe0348f3cc63de0f0183f3642acd69608 Mon Sep 17 00:00:00 2001 From: cesare Date: Wed, 11 May 2022 12:50:01 +0200 Subject: [PATCH 155/366] cleaned the code in multipatch mp_solve_bilaplace_C1, removed 1 output from sp_bilaplacian_drchlt_C1 and sp_bilaplacian_drchlt_C1_exact --- .../sp_bilaplacian_drchlt_C1.m | 2 +- .../sp_bilaplacian_drchlt_C1_exact.m | 2 +- .../inst/multipatch/mp_solve_bilaplace_C1.m | 45 +++++++++---------- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 4a9e093e..85b201d4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) +function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index db9136c6..0cff1905 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 497b6414..ad3ac5a3 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -101,67 +101,64 @@ % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) - [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); + [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); else - [u_drchlt, drchlt_dofs, add_int_dofs, dofs_to_remove] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); + [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); end u(drchlt_dofs) = u_drchlt; int_dofs = setdiff (1:space.ndof, drchlt_dofs); -int_dofs = setdiff (int_dofs, dofs_to_remove); +add_dofs = []; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs +for bv = 1 : size(add_int_dofs, 1) + add_dofs = [add_dofs space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})]; +end +%By subtracting add_dofs (later they will be added again), int_dofs contain ony the "original" interior dofs +int_dofs = setdiff (int_dofs, add_dofs); +%We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking +%into account the dirichlet conditions), and the basis change matrix (we will need it +%to go from the basis with kernel vectors obtained when examnining the dirichlet conditions +%to the usual basis) add_mat = []; add_rhs = []; add_rb = []; -add_dofs = []; s_vec = zeros(size(add_int_dofs, 1), size(add_int_dofs, 1)); -B_change = speye(space.ndof); +B_change = speye(space.ndof); %basis change matrix for bv = 1 : size(add_int_dofs, 1) -% space.dofs_on_vertex{add_int_dofs{bv, 1}} -% b_change = eye(6); -% b_change(:, add_int_dofs{bv, 3}) = add_int_dofs{bv, 2}; % To transform from the new basis to the old one -% B_change([space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3}) ] - B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}) = eye(6); B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})) = add_int_dofs{bv, 2}; add_mat = [add_mat; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, int_dofs) ]; add_rhs = [add_rhs; add_int_dofs{bv, 2}.' * rhs(space.dofs_on_vertex{add_int_dofs{bv, 1}})]; add_rb = [add_rb; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, drchlt_dofs) * u_drchlt]; - add_dofs = [add_dofs space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})]; for bv_1 = 1 : size(add_int_dofs, 1) s_vec(bv, bv_1) = add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv_1, 1}}) * add_int_dofs{bv_1, 2}; - end - - + end end +%Stiffness matrix (including additional "interior" dofs) A = [stiff_mat(int_dofs, int_dofs) add_mat'; ... add_mat s_vec ]; - + +%Right-hand side (including additional "interior" dofs)... r = [rhs(int_dofs); ... add_rhs ]; +%...and its correction rb = [ stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; ... add_rb ]; -% rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; %zeros(length(int_dofs),1)-(abs(stiff_mat(int_dofs, drchlt_dofs))>1e-14)*ones(length(drchlt_dofs),1);%rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; - -% Solve the linear system -% u(int_dofs) = stiff_mat(int_dofs,int_dofs) \ rhs(int_dofs); -% size(u) - +%"interior" dofs = "original" interior dofs + the discared "boundary" vertex dofs int_dofs_new = [int_dofs add_dofs]; +%Solving the system u_newBasis(int_dofs_new) = A \ (r - rb); u_newBasis(drchlt_dofs) = u_drchlt; -% u(int_dofs) = u_int_dofs_newBasis(1:numel(int_dofs)); -% u([add_dofs drchlt_dofs]) = B_change * u_newBasis([ drchlt_dofs]); - +%Switching to the usual basis u = B_change * u_newBasis'; end From d0146ac29d699d47b0da7c63164f38156c42e670 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Thu, 12 May 2022 17:44:32 +0200 Subject: [PATCH 156/366] Restored the status of files after tests --- .../inst/examples/base/ex_laplace_beltrami.m | 121 +++--------------- geopdes/inst/solve/solve_laplace.m | 3 - geopdes/inst/space/@sp_scalar/sp_l2_error.m | 2 +- 3 files changed, 22 insertions(+), 104 deletions(-) diff --git a/geopdes/inst/examples/base/ex_laplace_beltrami.m b/geopdes/inst/examples/base/ex_laplace_beltrami.m index 4857f562..bb3346fa 100644 --- a/geopdes/inst/examples/base/ex_laplace_beltrami.m +++ b/geopdes/inst/examples/base/ex_laplace_beltrami.m @@ -3,53 +3,7 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS structure from the NURBS toolbox -% problem_data.geo_name = 'geo_roof.txt'; - -% % 4 patch surf hyperbolic smooth boundary -% coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; -% coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; -% coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; -% -% coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; -% coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; -% coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; -% -% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; -% coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; -% coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; -% -% coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; -% coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; -% coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% % nrb(2)=butterf2; -% % nrb(3)=butterf3; -% % nrb(4)=butterf4; -% problem_data.geo_name = nrb; - - -% % 1 patch surf hyperbolic smooth boundary -coefs_1(:,1,:)=[-0.5 -0.5 0.0; 0.0 -0.5 -0.5; 0.5 -0.5 0.0]; -coefs_1(:,2,:)=[-0.5 0.0 0.5; 0.0 0.0 0.0; 0.5 0.0 0.5]; -coefs_1(:,3,:)=[-0.5 0.5 0.0; 0.0 0.5 -0.5; 0.5 0.5 0.0]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); - -nrb(1)=butterf1; -problem_data.geo_name = nrb; - +problem_data.geo_name = 'geo_roof.txt'; % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; @@ -59,57 +13,35 @@ problem_data.c_diff = @(x, y, z) ones(size(x)); % % Source and boundary terms -% alp = 5; bet = 1; L = 1; -% g1 = @(x,y) (1-cos(atan(x./y))).*(1-sin(atan(x./y))); -% g2 = @(x,y) cos(atan(x./y)) + sin(atan(x./y)) - 4*cos(atan(x./y)).*sin(atan(x./y)); -% gz = @(z) sin(pi*alp/L*z); -% dg1 = @(x,y) sin(atan(y./x)).*(1-sin(atan(y./x))) - cos(atan(y./x)).*(1-cos(atan(y./x))); -% -% problem_data.f = @(x, y, z) bet*((alp*pi/L)^2 * g1(x,y) - g2(x,y)).*gz(z); -% problem_data.h = @(x, y, z, ind) bet * g1(x,y).*gz(z); -% -% % Exact solution (optional) -% problem_data.uex = @(x, y, z) bet * g1(x,y).*gz(z); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (-1./sqrt(x.^2+y.^2).*sin(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... -% reshape ( 1./sqrt(x.^2+y.^2).*cos(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... -% reshape ( alp*pi/L * cos(alp*pi/L*z) .* bet .* g1(x,y), [1, size(x)])); - -% % z hyperbolic -% problem_data.f = @(x, y, z) z; -problem_data.f = @(x, y, z) ((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); -% problem_data.g = @(x, y, z, ind) z; -problem_data.h = @(x, y, z, ind) z; -problem_data.uex = @(x, y, z) z; +alp = 5; bet = 1; L = 1; +g1 = @(x,y) (1-cos(atan(x./y))).*(1-sin(atan(x./y))); +g2 = @(x,y) cos(atan(x./y)) + sin(atan(x./y)) - 4*cos(atan(x./y)).*sin(atan(x./y)); +gz = @(z) sin(pi*alp/L*z); +dg1 = @(x,y) sin(atan(y./x)).*(1-sin(atan(y./x))) - cos(atan(y./x)).*(1-cos(atan(y./x))); + +problem_data.f = @(x, y, z) bet*((alp*pi/L)^2 * g1(x,y) - g2(x,y)).*gz(z); +problem_data.h = @(x, y, z, ind) bet * g1(x,y).*gz(z); + +% Exact solution (optional) +problem_data.uex = @(x, y, z) bet * g1(x,y).*gz(z); problem_data.graduex = @(x, y, z) cat (1, ... - reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... - reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... - reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); -% problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -% problem_data.lapuex = @(x, y, z) -((8*(x.^2 - y.^2))./(1 + 4*x.^2 + 4*y.^2).^2); + reshape (-1./sqrt(x.^2+y.^2).*sin(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... + reshape ( 1./sqrt(x.^2+y.^2).*cos(atan(y./x))*bet.*gz(z).*dg1(x,y), [1, size(x)]), ... + reshape ( alp*pi/L * cos(alp*pi/L*z) .* bet .* g1(x,y), [1, size(x)])); % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data method_data.degree = [3 3]; % Degree of the splines method_data.regularity = [1 1]; % Regularity of the splines -% method_data.nsub = [9 9]; % Number of subdivisions +method_data.nsub = [9 9]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule -h=[]; - -for i= 1:4 - fprintf ('Loop %d \n', i); - method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions - % 3) CALL TO THE SOLVER - - % 3) CALL TO THE SOLVER +% 3) CALL TO THE SOLVER [geometry, msh, space, u] = solve_laplace (problem_data, method_data); - h = [h 1/sqrt(msh.nel(1))]; % Display errors of the computed solution in the L2 and H1 norm -[error_h1(i), error_l2(i)] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) -end +[error_h1, error_l2] = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) % 4) POST-PROCESSING % 4.1) EXPORT TO PARAVIEW @@ -123,25 +55,14 @@ % 4.2) PLOT IN MATLAB. COMPARISON WITH THE EXACT SOLUTION [eu, F] = sp_eval (u, space, geometry, vtk_pts); -[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +[X, Y, Z] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:)), squeeze(F(3,:,:))); subplot (1,2,1) -surf (X, Y, eu) +surf (X, Y, Z, eu) title ('Numerical solution'), axis tight subplot (1,2,2) -surf (X, Y, problem_data.uex (X,Y)) +surf (X, Y, Z, problem_data.uex (X,Y,Z)) title ('Exact solution'), axis tight - -figure -loglog(h, error_l2,'-o') -hold on -loglog(h, error_h1,'-o') -loglog(h, 100*h.^4,'-x') -loglog(h, 100*h.^3,'-x') -loglog(h, 10*h.^2,'-x') -legend("L^2 error", "H^1 error", "h^4", "h^3", "h^2",'Location','southeast'); - - % figure % npts = [20 20]; % [eu, F] = sp_eval(u, space, geometry, vtk_pts, 'gradient'); diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 6ce3dc14..87844923 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -83,9 +83,6 @@ stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); rhs = op_f_v_tp (space, msh, f); -% stiff_mat = op_u_v_tp (space, space, msh, c_diff); -% rhs = op_f_v_tp (space, msh, f); - % Apply Neumann boundary conditions for iside = nmnn_sides if (msh.ndim > 1) diff --git a/geopdes/inst/space/@sp_scalar/sp_l2_error.m b/geopdes/inst/space/@sp_scalar/sp_l2_error.m index 4d2383e7..ed128a6c 100644 --- a/geopdes/inst/space/@sp_scalar/sp_l2_error.m +++ b/geopdes/inst/space/@sp_scalar/sp_l2_error.m @@ -40,7 +40,7 @@ for iel = 1:msh.nel_dir(1) msh_col = msh_evaluate_col (msh, iel); - sp_col = sp_evaluate_col (space, msh_col, 'value', true, 'gradient', false, 'laplacian', true); + sp_col = sp_evaluate_col (space, msh_col, 'value', true, 'gradient', false); errl2 = errl2 + (sp_l2_error (sp_col, msh_col, u, uex)).^2; end From cf224815500b3ba676ed63b831fa4735709970bd Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 13 May 2022 15:32:59 +0200 Subject: [PATCH 157/366] Some cleaning for Dirichlet conditions. Still unfinished. --- .../sp_bilaplacian_drchlt_C1.m | 72 ++++-------- .../sp_bilaplacian_drchlt_C1_exact.m | 63 ++++------- .../@sp_multipatch_C1/sp_multipatch_C1.m | 104 ++++++++---------- .../inst/multipatch/mp_solve_bilaplace_C1.m | 42 +++---- geopdes/inst/multipatch/vertices_struct.m | 16 ++- 5 files changed, 112 insertions(+), 185 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 85b201d4..1c7499d9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -32,72 +32,40 @@ x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); end coeff_at_qnodes = ones (size(x{1})); - dudn_at_qnodes = dudn (x{:},iref); + dudn_at_qnodes = dudn (x{:},iref) .* msh_side.charlen; M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); - M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end -% u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); -% -% uu = sparse (space.ndof, 1); -% uu(drchlt_dofs) = u_drchlt; -% -% drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); -% rhs2 = rhs2 - M2 * uu; -% u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); -% -% uu(drchlt_dofs2) = u_drchlt2; -% -% drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); -% u_drchlt = uu(drchlt_dofs); - % Kernel computation for separating verrtex boundary functions -% Insert a h-dependent parameter in front of M2 -M_bdy = M + M2; -dofs_to_remove = []; -add_int_dofs = {}; -count_vert = 0; - - for iv = 1 : numel(space.vertices) - % Loop just over Dirichlet boundary vertices - if space.vertices(iv).boundary_vertex - M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if ~isempty(ker) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; - add_int_dofs{count_vert, 1} = iv; - add_int_dofs{count_vert, 2} = ker; - add_int_dofs{count_vert, 3} = ind; - - end - % Pick up the basis function with the max coeff abs val in the ker - % Use the other as bdy functions - % Check the global index of the removed function, remove it - % from dirichlet dofs and add the function in the kernel into - % the internal part (it should go in the output) - end +% Check the kernel of vertex functions on Dirichlet boundary vertices +% Pick up the basis function with the max. abs. coeff in the kernel, +% remove it from drchlt_dofs, and add the function in the kernel into the +% internal part (it goes in the output) +for iv = 1 : numel(space.vertices) + % TODO: Loop just over Dirichlet boundary vertices + if (space.vertices(iv).boundary_vertex) + M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; + add_int_dofs(count_vert) = struct('vertex_number', iv, 'function_index', ind, 'kernel_coeffs', ker); end + end +end - -% SET M = M + M2 -% LOOP ON VERTICES -% RESTRICT TO 6x6 matrix and analyze -% If null space is not empty: -% 1) Remove one basis function from drchlt_dofs -% 2) Get the coefficients of the internal functions (will be given as an output) -drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); -u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... - (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); +u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 0cff1905..7dc5e0b1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -32,64 +32,43 @@ x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); end coeff_at_qnodes = ones (size(x{1})); - - dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel); + dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel) .* msh_side.charlen; M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); - M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end -% u_drchlt = M(drchlt_dofs, drchlt_dofs) \ rhs(drchlt_dofs, 1); -% -% uu = sparse (space.ndof, 1); -% uu(drchlt_dofs) = u_drchlt; -% -% drchlt_dofs2 = setdiff (drchlt_dofs2, drchlt_dofs); -% rhs2 = rhs2 - M2 * uu; -% u_drchlt2 = M2(drchlt_dofs2, drchlt_dofs2) \ rhs2(drchlt_dofs2); -% -% uu(drchlt_dofs2) = u_drchlt2; -% -% drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); -% u_drchlt = uu(drchlt_dofs); - - -% Insert a h-dependent parameter in front of M2 -M_bdy = M + M2; +M_bdry = M + M2; dofs_to_remove = []; -add_int_dofs = {}; count_vert = 0; +add_int_dofs = struct ('vertex_number', [], 'function_index', [], 'kernel_coeffs', []); - for iv = 1 : numel(space.vertices) - % Loop just over Dirichlet boundary vertices - if space.vertices(iv).boundary_vertex - M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if ~isempty(ker) - count_vert = count_vert + 1; - [max_val, ind] = max(abs(ker)); - dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; - add_int_dofs{count_vert, 1} = iv; - add_int_dofs{count_vert, 2} = ker; - add_int_dofs{count_vert, 3} = ind; - end - % Pick up the basis function with the max coeff abs val in the ker - % Use the other as bdy functions - % Check the global index of the removed function, remove it - % from dirichlet dofs and add the function in the kernel into - % the internal part (it should go in the output) - end +% Check the kernel of vertex functions on Dirichlet boundary vertices +% Pick up the basis function with the max. abs. coeff in the kernel, +% remove it from drchlt_dofs, and add the function in the kernel into the +% internal part (it goes in the output) +for iv = 1 : numel(space.vertices) + % TODO: Loop just over Dirichlet boundary vertices + if (space.vertices(iv).boundary_vertex) + M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; + add_int_dofs(count_vert) = struct('vertex_number', iv, 'function_index', ind, 'kernel_coeffs', ker); end + end +end drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); -u_drchlt = (M(drchlt_dofs,drchlt_dofs) + M2(drchlt_dofs, drchlt_dofs)) \ ... - (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); +u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 156eb34b..cd95636f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -49,8 +49,9 @@ % Other methods % sp_refine: generate a refined space, and subdivision matrices for the univariate spaces % -% Copyright (C) 2015-2021 Rafael Vazquez -% Copyright (C) 2019-2021 Cesare Bracco +% Copyright (C) 2015-2022 Rafael Vazquez +% Copyright (C) 2019-2022 Cesare Bracco +% Copyright (C) 2022 Andrea Farahat % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -77,10 +78,6 @@ error ('The list of spaces does not correspond to the mesh') end -% if (msh.ndim ~= 2 || msh.rdim ~= 2) -% error ('Only implemented for planar surfaces') -% end - for iptc = 1:numel(geometry) knots = spaces{iptc}.knots; breaks = cellfun (@unique, knots, 'UniformOutput', false); @@ -198,7 +195,7 @@ sp.Cpatch = Cpatch; -% I store this for simplicity +% Store information about the geometry, for simplicity sp.interfaces = interfaces_all; sp.vertices = vertices; sp.geometry = geometry; @@ -279,26 +276,14 @@ msh_side_interior = msh_boundary_side_from_interior (msh_grev, sides(ii)); msh_side_interior = msh_precompute (msh_side_interior); geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% if msh.ndim+1==msh.rdim -% geo_map_jac_reduced{ii}=geo_map_jac{ii}(:,:,:,[1 end]); -% DuFR_z = reshape (geo_map_jac_reduced{1}(3,1,:,:), ngrev, 1); -% DvFL_z = reshape (geo_map_jac_reduced{2}(3,2,:,:), ngrev, 1); -% DvFR_z = reshape (geo_map_jac_reduced{1}(3,2,:,:), ngrev, 1); -% end end if msh.ndim + 1 == msh.rdim [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); else - disp('Planar GD'); [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); end -% grev_pts_reduced{1}=grev_pts{1}([1 end]); -% grev_pts_reduced{2}=grev_pts{2}([1 end]); -% [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac_reduced, grev_pts_reduced, sides); -% end - clear geo_map_jac msh_grev msh_side_interior grev_pts - %clear geo_map_jac geo_map_jac_reduced msh_grev msh_side_interior grev_pts + clear geo_map_jac msh_grev msh_side_interior grev_pts %Saving alphas and betas (first column=i_0, second column=i_1) all_alpha0(iref,:) = alpha0; @@ -469,55 +454,52 @@ if msh.ndim+1==msh.rdim - disp('Surf code'); - %Tangent vectors - Du_F = derivatives_new1{1}(:,1); - Dv_F = derivatives_new1{1}(:,2); - %Normal vector - normal=cross(Du_F,Dv_F); - unit_normal=normal/norm(normal); - %Vector orthogonal to n and z along which the geometry is rotated - %(rotation axis) - r=cross(unit_normal,[0 0 1]'); - %Angle between n and z - cos_th=[0 0 1]*unit_normal; - sin_th=norm(r); - %Rotation matrix - R=[cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... + disp('Surf code'); + %Tangent vectors + Du_F = derivatives_new1{1}(:,1); + Dv_F = derivatives_new1{1}(:,2); + %Normal vector + normal = cross(Du_F,Dv_F); + unit_normal = normal/norm(normal); + %Vector orthogonal to n and z along which the geometry is rotated (rotation axis) + r = cross(unit_normal,[0 0 1]'); + %Angle between n and z + cos_th = [0 0 1]*unit_normal; + sin_th = norm(r); + %Rotation matrix + R = [cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... r(1)*r(2)*(1-cos_th)+r(3)*sin_th,cos_th + r(2)^2*(1-cos_th),r(2)*r(3)*(1-cos_th)-r(1)*sin_th;... r(1)*r(3)*(1-cos_th)-r(2)*sin_th,r(3)*r(2)*(1-cos_th)+r(1)*sin_th,cos_th + r(3)^2*(1-cos_th)]; - for ipatch = 1:valence_p - - coeff_hom=geo_local(ipatch).nurbs.coefs; - coeff_w=coeff_hom(4,:,:); - coeff_eu=coeff_hom(1:3,:,:)./(repmat(coeff_w,3,1,1)); %Euclidean coefficients - rot_coeff=ones(4,size(coeff_eu,2),size(coeff_eu,3)); - for k=1:size(coeff_eu,3) - rot_coeff(1:3,:,k)=R*(coeff_eu(:,:,k)-coeff_eu(:,1,1))+coeff_eu(:,1,1); - end - rot_nrb(ipatch)=geometry(patches(ipatch)).nurbs; - rot_nrb(ipatch).coefs=rot_coeff; - end + for ipatch = 1:valence_p + coeff_hom = geo_local(ipatch).nurbs.coefs; + coeff_w = coeff_hom(4,:,:); + coeff_eu = coeff_hom(1:3,:,:)./(repmat(coeff_w,3,1,1)); %Euclidean coefficients + rot_coeff = ones(4,size(coeff_eu,2),size(coeff_eu,3)); + for k = 1:size(coeff_eu,3) + rot_coeff(1:3,:,k) = R*(coeff_eu(:,:,k)-coeff_eu(:,1,1))+coeff_eu(:,1,1); + end + rot_nrb(ipatch) = geometry(patches(ipatch)).nurbs; + rot_nrb(ipatch).coefs = rot_coeff; + end - rot_geo = mp_geo_load(rot_nrb); + rot_geo = mp_geo_load(rot_nrb); - for iptc = 1:valence_p - knots = space.sp_patch{iptc}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; - end - rot_msh_pts_der1 = msh_cartesian (brk, {0 0}, [], rot_geo(iptc),'boundary', true, 'der2', true); - rot_msh_der = msh_precompute (rot_msh_pts_der1); - derivatives_new1{iptc} = rot_msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - derivatives_new2{iptc} = rot_msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} - end + for iptc = 1:valence_p + knots = space.sp_patch{iptc}.knots; + for idim = 1:msh.ndim + brk{idim} = [knots{idim}(1) knots{idim}(end)]; + end + rot_msh_pts_der1 = msh_cartesian (brk, {0 0}, [], rot_geo(iptc),'boundary', true, 'der2', true); + rot_msh_der = msh_precompute (rot_msh_pts_der1); + derivatives_new1{iptc} = rot_msh_der.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) + derivatives_new2{iptc} = rot_msh_der.geo_map_der2; %rdim x ndim x ndim x n_pts{1} x n_pts{2} + end end for ipatch = 1:valence_p - - prev_edge = ipatch; - next_edge = mod(ipatch, valence_e) + 1; + prev_edge = ipatch; + next_edge = mod(ipatch, valence_e) + 1; % Compute gluing data, and edge functions from CC_edges_discarded if (edge_orientation(prev_edge) == 1) diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index ad3ac5a3..deedd089 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -87,17 +87,9 @@ clear sp % Compute and assemble the matrices -% GradGrad operator -% stiff_mat = op_gradgradu_gradgradv_mp (space, space, msh, c_diff); - -% Laplacian operator (For biharmonic problem) stiff_mat = op_laplaceu_laplacev_mp (space, space, msh, c_diff); rhs = op_f_v_mp (space, msh, f); -% L2 approximation -% stiff_mat = op_u_v_mp (space, space, msh, c_diff); -% rhs = op_f_v_mp (space, msh, f); - % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) @@ -107,36 +99,38 @@ end u(drchlt_dofs) = u_drchlt; - int_dofs = setdiff (1:space.ndof, drchlt_dofs); add_dofs = []; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs -for bv = 1 : size(add_int_dofs, 1) - add_dofs = [add_dofs space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})]; +for bv = 1 : numel(add_int_dofs) + vertex_number = add_int_dofs(bv).vertex_number; + add_dofs = [add_dofs space.dofs_on_vertex{vertex_number}(add_int_dofs(bv).function_index)]; end %By subtracting add_dofs (later they will be added again), int_dofs contain ony the "original" interior dofs int_dofs = setdiff (int_dofs, add_dofs); %We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking -%into account the dirichlet conditions), and the basis change matrix (we will need it +%into account the Dirichlet conditions), and the basis change matrix (we will need it %to go from the basis with kernel vectors obtained when examnining the dirichlet conditions %to the usual basis) add_mat = []; add_rhs = []; add_rb = []; -s_vec = zeros(size(add_int_dofs, 1), size(add_int_dofs, 1)); +s_vec = numel(size(add_int_dofs, 1), size(add_int_dofs, 1)); B_change = speye(space.ndof); %basis change matrix -for bv = 1 : size(add_int_dofs, 1) - B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}) = eye(6); - B_change(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv, 1}}(add_int_dofs{bv, 3})) = add_int_dofs{bv, 2}; - - add_mat = [add_mat; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, int_dofs) ]; - add_rhs = [add_rhs; add_int_dofs{bv, 2}.' * rhs(space.dofs_on_vertex{add_int_dofs{bv, 1}})]; - add_rb = [add_rb; add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, drchlt_dofs) * u_drchlt]; - - for bv_1 = 1 : size(add_int_dofs, 1) - s_vec(bv, bv_1) = add_int_dofs{bv, 2}.' * stiff_mat(space.dofs_on_vertex{add_int_dofs{bv, 1}}, space.dofs_on_vertex{add_int_dofs{bv_1, 1}}) * add_int_dofs{bv_1, 2}; - end +for bv = 1 : numel(add_int_dofs) + vertex_number = add_int_dofs(bv).vertex_number; + dofs_on_vertex = space.dofs_on_vertex{vertex_number}; + kernel_coeffs = add_int_dofs(bv).kernel_coeffs; + B_change(dofs_on_vertex, dofs_on_vertex(add_int_dofs(bv).function_index)) = kernel_coeffs; + + add_mat = [add_mat; kernel_coeffs.' * stiff_mat(dofs_on_vertex, int_dofs) ]; + add_rhs = [add_rhs; kernel_coeffs.' * rhs(dofs_on_vertex)]; + add_rb = [add_rb; kernel_coeffs.' * stiff_mat(dofs_on_vertex, drchlt_dofs) * u_drchlt]; + + for bv_1 = 1 : numel(add_int_dofs) + s_vec(bv, bv_1) = kernel_coeffs.' * stiff_mat(dofs_on_vertex, space.dofs_on_vertex{add_int_dofs(bv_1).vertex_number}) * add_int_dofs(bv_1).kernel_coeffs; + end end %Stiffness matrix (including additional "interior" dofs) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 0c8f2650..520718d9 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -55,13 +55,17 @@ N_int = numel (interfaces_i); interfaces = interfaces_i; interfaces_bnd = interfaces_i; +icont = 0; for hh = 1:numel(boundaries) - interfaces(N_int+hh).patch1 = boundaries(hh).patches; - interfaces(N_int+hh).side1 = boundaries(hh).faces; - interfaces_bnd(N_int+hh).patch1 = boundaries(hh).patches; - interfaces_bnd(N_int+hh).side1 = boundaries(hh).faces; - interfaces_bnd(N_int+hh).patch2 = 0; - interfaces_bnd(N_int+hh).side2 = 0; + for jj = 1:numel(boundaries(hh).patches) + icont = icont + 1; + interfaces(N_int+icont).patch1 = boundaries(hh).patches(jj); + interfaces(N_int+icont).side1 = boundaries(hh).faces(jj); + interfaces_bnd(N_int+icont).patch1 = boundaries(hh).patches(jj); + interfaces_bnd(N_int+icont).side1 = boundaries(hh).faces(jj); + interfaces_bnd(N_int+icont).patch2 = 0; + interfaces_bnd(N_int+icont).side2 = 0; + end end % Find the operations for reparametrization From de56f3a57c8088a8514da90e29942662e7e71ce3 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 13 May 2022 15:41:39 +0200 Subject: [PATCH 158/366] Fixed a couple of bugs --- .../multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 5 ++++- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 1c7499d9..d0af5b19 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -43,7 +43,10 @@ end end -% Kernel computation for separating verrtex boundary functions +M_bdry = M + M2; +add_int_dofs = []; +dofs_to_remove = []; +count_vert = 0; % Check the kernel of vertex functions on Dirichlet boundary vertices % Pick up the basis function with the max. abs. coeff in the kernel, diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 7dc5e0b1..f5d0f874 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -44,9 +44,9 @@ end M_bdry = M + M2; +add_int_dofs = []; dofs_to_remove = []; count_vert = 0; -add_int_dofs = struct ('vertex_number', [], 'function_index', [], 'kernel_coeffs', []); % Check the kernel of vertex functions on Dirichlet boundary vertices % Pick up the basis function with the max. abs. coeff in the kernel, From c5dbefbf481c5d70d382cb424ac7334efb889671 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 13 May 2022 15:50:34 +0200 Subject: [PATCH 159/366] Fixed bug for empty add_int_dofs --- .../multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 5 ++++- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 5 ++++- geopdes/inst/multipatch/mp_solve_bilaplace_C1.m | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index d0af5b19..0964a2e2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -44,7 +44,6 @@ end M_bdry = M + M2; -add_int_dofs = []; dofs_to_remove = []; count_vert = 0; @@ -71,4 +70,8 @@ u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); +if (count_vert == 0) + add_int_dofs = []; +end + end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index f5d0f874..cf704edb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -44,7 +44,6 @@ end M_bdry = M + M2; -add_int_dofs = []; dofs_to_remove = []; count_vert = 0; @@ -71,4 +70,8 @@ u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); +if (count_vert == 0) + add_int_dofs = []; +end + end diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index deedd089..2669cc25 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -115,7 +115,7 @@ add_mat = []; add_rhs = []; add_rb = []; -s_vec = numel(size(add_int_dofs, 1), size(add_int_dofs, 1)); +s_vec = zeros(numel(add_int_dofs), numel(add_int_dofs)); B_change = speye(space.ndof); %basis change matrix for bv = 1 : numel(add_int_dofs) From ce9dc8660aa7d3cf109a9ca624ab93d90bb209ee Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 13 May 2022 17:55:32 +0200 Subject: [PATCH 160/366] New working version. Still modifying it. --- .../inst/multipatch/mp_solve_bilaplace_C1.m | 42 ++++++------------- 1 file changed, 12 insertions(+), 30 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 2669cc25..8fb14fb0 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -105,54 +105,36 @@ vertex_number = add_int_dofs(bv).vertex_number; add_dofs = [add_dofs space.dofs_on_vertex{vertex_number}(add_int_dofs(bv).function_index)]; end -%By subtracting add_dofs (later they will be added again), int_dofs contain ony the "original" interior dofs -int_dofs = setdiff (int_dofs, add_dofs); %We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking %into account the Dirichlet conditions), and the basis change matrix (we will need it %to go from the basis with kernel vectors obtained when examnining the dirichlet conditions %to the usual basis) -add_mat = []; -add_rhs = []; -add_rb = []; -s_vec = zeros(numel(add_int_dofs), numel(add_int_dofs)); B_change = speye(space.ndof); %basis change matrix +B_change_local = sparse (6*numel(add_dofs), numel(add_dofs)); %basis change matrix +vertex_dofs = []; for bv = 1 : numel(add_int_dofs) vertex_number = add_int_dofs(bv).vertex_number; dofs_on_vertex = space.dofs_on_vertex{vertex_number}; kernel_coeffs = add_int_dofs(bv).kernel_coeffs; B_change(dofs_on_vertex, dofs_on_vertex(add_int_dofs(bv).function_index)) = kernel_coeffs; + row_inds = (bv-1)*6 + (1:6); + B_change_local(row_inds, bv) = kernel_coeffs; - add_mat = [add_mat; kernel_coeffs.' * stiff_mat(dofs_on_vertex, int_dofs) ]; - add_rhs = [add_rhs; kernel_coeffs.' * rhs(dofs_on_vertex)]; - add_rb = [add_rb; kernel_coeffs.' * stiff_mat(dofs_on_vertex, drchlt_dofs) * u_drchlt]; - - for bv_1 = 1 : numel(add_int_dofs) - s_vec(bv, bv_1) = kernel_coeffs.' * stiff_mat(dofs_on_vertex, space.dofs_on_vertex{add_int_dofs(bv_1).vertex_number}) * add_int_dofs(bv_1).kernel_coeffs; - end + vertex_dofs = union (vertex_dofs, dofs_on_vertex); end -%Stiffness matrix (including additional "interior" dofs) -A = [stiff_mat(int_dofs, int_dofs) add_mat'; ... - add_mat s_vec ]; - -%Right-hand side (including additional "interior" dofs)... -r = [rhs(int_dofs); ... - add_rhs ]; - -%...and its correction -rb = [ stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; ... - add_rb ]; +stiff_mat(:,add_dofs) = stiff_mat(:,vertex_dofs) * B_change_local; +stiff_mat(add_dofs,:) = B_change_local.' * stiff_mat(vertex_dofs,:); +rhs(add_dofs) = B_change_local.' * rhs(vertex_dofs); -%"interior" dofs = "original" interior dofs + the discared "boundary" vertex dofs -int_dofs_new = [int_dofs add_dofs]; +rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; -%Solving the system -u_newBasis(int_dofs_new) = A \ (r - rb); -u_newBasis(drchlt_dofs) = u_drchlt; +% Solve the linear system +u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); %Switching to the usual basis -u = B_change * u_newBasis'; +u = B_change * u; end From 17d5ba784ace2a4e2fcbf630878437316478fb14 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 13 May 2022 18:41:23 +0200 Subject: [PATCH 161/366] More cleaning. MISSING: use of local matrix, and loop on Dirichlet --- .../sp_bilaplacian_drchlt_C1.m | 23 ++++++++----- .../sp_bilaplacian_drchlt_C1_exact.m | 23 ++++++++----- .../inst/multipatch/mp_solve_bilaplace_C1.m | 33 +++++-------------- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 0964a2e2..0f576359 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) +function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -45,33 +45,40 @@ M_bdry = M + M2; dofs_to_remove = []; +vertices_numbers = []; +row_indices = []; count_vert = 0; % Check the kernel of vertex functions on Dirichlet boundary vertices % Pick up the basis function with the max. abs. coeff in the kernel, % remove it from drchlt_dofs, and add the function in the kernel into the % internal part (it goes in the output) +B_change_local = []; for iv = 1 : numel(space.vertices) % TODO: Loop just over Dirichlet boundary vertices if (space.vertices(iv).boundary_vertex) - M_ker = M_bdy(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); ker = null(full(M_ker)); if (~isempty(ker)) count_vert = count_vert + 1; [~, ind] = max(abs(ker)); - dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; - add_int_dofs(count_vert) = struct('vertex_number', iv, 'function_index', ind, 'kernel_coeffs', ker); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; end end end +kernel_info = struct ('vertices_numbers', vertices_numbers, 'all_vertex_dofs', row_indices, 'quasi_interior_dofs', dofs_to_remove, 'B_change_local', sparse(B_change_local)); + drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); -if (count_vert == 0) - add_int_dofs = []; -end - end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index cf704edb..94c4db08 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -45,12 +45,15 @@ M_bdry = M + M2; dofs_to_remove = []; +vertices_numbers = []; +row_indices = []; count_vert = 0; % Check the kernel of vertex functions on Dirichlet boundary vertices % Pick up the basis function with the max. abs. coeff in the kernel, % remove it from drchlt_dofs, and add the function in the kernel into the % internal part (it goes in the output) +B_change_local = []; for iv = 1 : numel(space.vertices) % TODO: Loop just over Dirichlet boundary vertices if (space.vertices(iv).boundary_vertex) @@ -59,19 +62,23 @@ if (~isempty(ker)) count_vert = count_vert + 1; [~, ind] = max(abs(ker)); - dofs_to_remove = [dofs_to_remove space.dofs_on_vertex{iv}(ind)]; - add_int_dofs(count_vert) = struct('vertex_number', iv, 'function_index', ind, 'kernel_coeffs', ker); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; end end end -drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +kernel_info = struct ('vertices_numbers', vertices_numbers, 'all_vertex_dofs', row_indices, 'quasi_interior_dofs', dofs_to_remove, 'B_change_local', sparse(B_change_local)); + +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); -if (count_vert == 0) - add_int_dofs = []; -end - end diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 8fb14fb0..8dcf9d53 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -93,41 +93,26 @@ % Apply boundary conditions u = zeros (space.ndof, 1); if (isfield(problem_data, 'graduex') && isfield(problem_data, 'uex')) - [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); + [u_drchlt, drchlt_dofs, kernel_dofs] = sp_bilaplacian_drchlt_C1_exact (space, msh, drchlt_sides, uex, graduex); else - [u_drchlt, drchlt_dofs, add_int_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); + [u_drchlt, drchlt_dofs, kernel_dofs] = sp_bilaplacian_drchlt_C1 (space, msh, drchlt_sides, h, g); end u(drchlt_dofs) = u_drchlt; int_dofs = setdiff (1:space.ndof, drchlt_dofs); -add_dofs = []; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs -for bv = 1 : numel(add_int_dofs) - vertex_number = add_int_dofs(bv).vertex_number; - add_dofs = [add_dofs space.dofs_on_vertex{vertex_number}(add_int_dofs(bv).function_index)]; -end +add_dofs = kernel_dofs.quasi_interior_dofs; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs %We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking %into account the Dirichlet conditions), and the basis change matrix (we will need it %to go from the basis with kernel vectors obtained when examnining the dirichlet conditions %to the usual basis) -B_change = speye(space.ndof); %basis change matrix -B_change_local = sparse (6*numel(add_dofs), numel(add_dofs)); %basis change matrix -vertex_dofs = []; - -for bv = 1 : numel(add_int_dofs) - vertex_number = add_int_dofs(bv).vertex_number; - dofs_on_vertex = space.dofs_on_vertex{vertex_number}; - kernel_coeffs = add_int_dofs(bv).kernel_coeffs; - B_change(dofs_on_vertex, dofs_on_vertex(add_int_dofs(bv).function_index)) = kernel_coeffs; - row_inds = (bv-1)*6 + (1:6); - B_change_local(row_inds, bv) = kernel_coeffs; - - vertex_dofs = union (vertex_dofs, dofs_on_vertex); -end +vertex_dofs = kernel_dofs.all_vertex_dofs; +B_change = speye (space.ndof); %basis change matrix +B_change(kernel_dofs.all_vertex_dofs,kernel_dofs.quasi_interior_dofs) = kernel_dofs.B_change_local; -stiff_mat(:,add_dofs) = stiff_mat(:,vertex_dofs) * B_change_local; -stiff_mat(add_dofs,:) = B_change_local.' * stiff_mat(vertex_dofs,:); -rhs(add_dofs) = B_change_local.' * rhs(vertex_dofs); +stiff_mat(:,add_dofs) = stiff_mat(:,vertex_dofs) * kernel_dofs.B_change_local; +stiff_mat(add_dofs,:) = kernel_dofs.B_change_local.' * stiff_mat(vertex_dofs,:); +rhs(add_dofs) = kernel_dofs.B_change_local.' * rhs(vertex_dofs); rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; From e656c3d87dbd99d0e37e67340950d90d3c6527b6 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Tue, 31 May 2022 17:01:23 +0200 Subject: [PATCH 162/366] Fiexed loop over dirichlet boundaries and using local matrix for vertex basis transformation --- .../base/ex_bilaplacian_Lshape_5patch.m | 10 ++--- .../sp_bilaplacian_drchlt_C1.m | 37 +++++++++++-------- .../sp_bilaplacian_drchlt_C1_exact.m | 37 +++++++++++-------- .../inst/multipatch/mp_solve_bilaplace_C1.m | 12 ++++-- 4 files changed, 55 insertions(+), 41 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m index 67ae9dbe..3d1d1f82 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m @@ -1,6 +1,6 @@ close all clear all -clc +% clc warning ('off','geopdes:nrbmultipatch') % PHYSICAL DATA OF THE PROBLEM @@ -334,7 +334,7 @@ % z planar 3d -% % problem_data.f = @(x, y, z) z;-((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2) +% problem_data.f = @(x, y, z) z;-((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2) % problem_data.f = @(x, y, z) zeros(size(x)); % % problem_data.g = @(x, y, z, ind) z; % problem_data.h = @(x, y, z, ind) z; @@ -347,7 +347,7 @@ % problem_data.lapuex = @(x, y, z) zeros(size(x)); % 3D problem -% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; +C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; % normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); % problem_data.f = @(x,y,z) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); % problem_data.g = @(x, y, z, ind) zeros(size(x)); @@ -360,7 +360,7 @@ % reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)]), ... % reshape (zeros(size(x)), [1, size(x)]) ); -% % 2D +% % 2D with coefficients % C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; % normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); % problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); @@ -374,7 +374,7 @@ % reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); -% 2D +% 2D cos % C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; % normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); % problem_data.f = @(x,y) 256*cos(4*x); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 0f576359..dcecf46b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -54,23 +54,28 @@ % remove it from drchlt_dofs, and add the function in the kernel into the % internal part (it goes in the output) B_change_local = []; +n_boundaries = numel(msh.boundaries); % number of boundary edges +global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges + for iv = 1 : numel(space.vertices) - % TODO: Loop just over Dirichlet boundary vertices - if (space.vertices(iv).boundary_vertex) - M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end + % Loop just over Dirichlet boundary vertices + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + end + end end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 94c4db08..2cad0528 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -54,23 +54,28 @@ % remove it from drchlt_dofs, and add the function in the kernel into the % internal part (it goes in the output) B_change_local = []; +n_boundaries = numel(msh.boundaries); % number of boundary edges +global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges + for iv = 1 : numel(space.vertices) - % TODO: Loop just over Dirichlet boundary vertices - if (space.vertices(iv).boundary_vertex) - M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end + % Loop just over Dirichlet boundary vertices + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + end + end end end diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 8dcf9d53..674bfc59 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -107,8 +107,8 @@ %to go from the basis with kernel vectors obtained when examnining the dirichlet conditions %to the usual basis) vertex_dofs = kernel_dofs.all_vertex_dofs; -B_change = speye (space.ndof); %basis change matrix -B_change(kernel_dofs.all_vertex_dofs,kernel_dofs.quasi_interior_dofs) = kernel_dofs.B_change_local; +% B_change = speye (space.ndof); %basis change matrix +% B_change(kernel_dofs.all_vertex_dofs,kernel_dofs.quasi_interior_dofs) = kernel_dofs.B_change_local; stiff_mat(:,add_dofs) = stiff_mat(:,vertex_dofs) * kernel_dofs.B_change_local; stiff_mat(add_dofs,:) = kernel_dofs.B_change_local.' * stiff_mat(vertex_dofs,:); @@ -119,7 +119,11 @@ % Solve the linear system u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); -%Switching to the usual basis -u = B_change * u; +% Switching to the usual basis using the local matrix for the vertex dofs +u_old = u(setdiff(kernel_dofs.all_vertex_dofs, add_dofs)); % Coefficients of the vertex functions that were already in the old basis +u(kernel_dofs.all_vertex_dofs) = kernel_dofs.B_change_local * u(kernel_dofs.quasi_interior_dofs); +u(setdiff(kernel_dofs.all_vertex_dofs, add_dofs)) = u(setdiff(kernel_dofs.all_vertex_dofs, add_dofs)) + u_old; + +% u = B_change * u; end From 6e3e155121a0fe9bedbae153d04cbc7eb63f84d2 Mon Sep 17 00:00:00 2001 From: Andrea Farahat Date: Mon, 13 Jun 2022 16:02:13 +0200 Subject: [PATCH 163/366] Added small stuffs/comments to the vertex boundary computations --- .../sp_bilaplacian_drchlt_C1.m | 66 ++++++++++++++----- .../sp_bilaplacian_drchlt_C1_exact.m | 64 +++++++++++++----- .../inst/multipatch/mp_solve_bilaplace_C1.m | 8 +-- 3 files changed, 101 insertions(+), 37 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index dcecf46b..83ce7c8e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -58,32 +58,64 @@ global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges for iv = 1 : numel(space.vertices) + if numel(space.vertices(iv).patches)>1 % Loop just over Dirichlet boundary vertices - if ~isempty(intersect(global_refs, space.vertices(iv).edges)) - if (space.vertices(iv).boundary_vertex) - M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + + Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 space.sp_patch{patches(1)}.ndof_dir(1)+2 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + + M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... + space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + +% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + end + end end end end kernel_info = struct ('vertices_numbers', vertices_numbers, 'all_vertex_dofs', row_indices, 'quasi_interior_dofs', dofs_to_remove, 'B_change_local', sparse(B_change_local)); -drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); +drchlt_dofs = union (drchlt_dofs, drchlt_dofs2); drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 2cad0528..e7f58c2f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -58,23 +58,41 @@ global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges for iv = 1 : numel(space.vertices) + if numel(space.vertices(iv).patches)>1 % Loop just over Dirichlet boundary vertices - if ~isempty(intersect(global_refs, space.vertices(iv).edges)) - if (space.vertices(iv).boundary_vertex) - M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + + Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 space.sp_patch{patches(1)}.ndof_dir(1)+2 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + + M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... + space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + +% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + end + end end end end @@ -87,3 +105,17 @@ u_drchlt = M_bdry(drchlt_dofs,drchlt_dofs) \ (rhs(drchlt_dofs) + rhs2(drchlt_dofs)); end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 674bfc59..53410e0e 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -102,10 +102,10 @@ int_dofs = setdiff (1:space.ndof, drchlt_dofs); add_dofs = kernel_dofs.quasi_interior_dofs; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs -%We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking -%into account the Dirichlet conditions), and the basis change matrix (we will need it -%to go from the basis with kernel vectors obtained when examnining the dirichlet conditions -%to the usual basis) +% We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking +% into account the Dirichlet conditions), and the basis change matrix (we will need it +% to go from the basis with kernel vectors obtained when examnining the dirichlet conditions +% to the usual basis) vertex_dofs = kernel_dofs.all_vertex_dofs; % B_change = speye (space.ndof); %basis change matrix % B_change(kernel_dofs.all_vertex_dofs,kernel_dofs.quasi_interior_dofs) = kernel_dofs.B_change_local; From e549d54d573b54de913097310ff361154e324d90 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 15 Jun 2022 10:01:42 +0200 Subject: [PATCH 164/366] Fixed bug for non-NURBS geometries (reshape) --- .../msh/@msh_cartesian/msh_evaluate_element_list.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m b/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m index 31fb131b..8b5e83f5 100644 --- a/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m +++ b/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m @@ -106,15 +106,15 @@ msh_col.geo_map_der2 = zeros (msh.rdim, msh.ndim, msh.ndim, msh.nqn, msh_col.nel); [F, jac, hess] = cellfun (@(x) feval (msh.map_der2, x), qqn, 'UniformOutput', false); for iel = 1:numel(elem_list) - msh_col.geo_map(:,:,iel) = F{iel}; - msh_col.geo_map_jac(:,:,:,iel) = jac{iel}; - msh_col.geo_map_der2(:,:,:,:,iel) = hess{iel}; + msh_col.geo_map(:,:,iel) = reshape (F{iel}, msh.rdim, msh.nqn); + msh_col.geo_map_jac(:,:,:,iel) = reshape (jac{iel}, msh.rdim, msh.ndim, msh.nqn); + msh_col.geo_map_der2(:,:,:,:,iel) = reshape (hess{iel}, msh.rdim, msh.ndim, msh.ndim, msh.nqn); end else [F, jac] = cellfun (@(x) feval (msh.map_der, x), qqn, 'UniformOutput', false); for iel = 1:numel(elem_list) - msh_col.geo_map(:,:,iel) = F{iel}; - msh_col.geo_map_jac(:,:,:,iel) = jac{iel}; + msh_col.geo_map(:,:,iel) = reshape (F{iel}, msh.rdim, msh.nqn); + msh_col.geo_map_jac(:,:,:,iel) = reshape (jac{iel}, msh.rdim, msh.ndim, msh.nqn); end end From f4b71c5269a67f1a0575e17ec934066caf8cea0a Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 5 Sep 2022 11:16:33 +0200 Subject: [PATCH 165/366] Solver for KL shells using a scalar space, single patch. --- .../solve_kirchhoff_love_shell_scalarspace.m | 111 +++++++++++ .../inst/space/@sp_scalar/op_KL_shells_tp.m | 71 +++++++ .../inst/space/@sp_scalar/op_f_v_tp_vector.m | 54 ++++++ .../inst/space/@sp_scalar/sp_eval_vector.m | 182 ++++++++++++++++++ geopdes/inst/space/@sp_scalar/sp_to_vtk.m | 6 +- geopdes/inst/space/sp_scalar2vector.m | 134 +++++++++++++ geopdes/inst/space/sp_scalar2vector_param.m | 96 +++++++++ 7 files changed, 653 insertions(+), 1 deletion(-) create mode 100644 geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m create mode 100644 geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m create mode 100644 geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m create mode 100644 geopdes/inst/space/@sp_scalar/sp_eval_vector.m create mode 100644 geopdes/inst/space/sp_scalar2vector.m create mode 100644 geopdes/inst/space/sp_scalar2vector_param.m diff --git a/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m new file mode 100644 index 00000000..3426f696 --- /dev/null +++ b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m @@ -0,0 +1,111 @@ +% SOLVE_KIRCHHOFF_LOVE_SHELL: Solve the Kirchhoff-Love shell model in a NURBS domain. +% It uses an object space of type sp_scalar, instead of sp_vector. +% +% USAGE: +% +% [geometry, msh, space, u] = solve_kirchhoff_love_shell (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - drchlt_sides: sides with Dirichlet boundary condition +% - drchlt_components: cell-array, the components that are set to zero for each drchlt_side +% - E_coeff: function handle for Young's modulus +% - nu_coeff: function handle for Poisson's ratio +% - thickness: scalar value, thickness of the shell +% - f: source term, distributed load +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree (>=2) of the spline functions. +% - regularity: continuity (>=1) of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete basis functions (see sp_scalar) +% u: the computed degrees of freedom +% +% NOTE: only homogeneous Dirichlet conditions implemented so far +% +% See also EX_KL_SHELL_SCORDELIS_LO_ROOF for an example. +% +% Copyright (C) 2017-2019 Pablo Antolin, Luca Coradello, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = solve_kirchhoff_love_shell_scalarspace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +if (any(degree <= 1) || any(regularity == 0)) + error ('The degree must be at least two, and the regularity at least C^1') +end + +geometry = geo_load (geo_name); +degelev = max (degree - (geometry.nurbs.order-1), 0); +nurbs = nrbdegelev (geometry.nurbs, degelev); +[rknots, ~, nknots] = kntrefine (nurbs.knots, nsub-1, nurbs.order-1, regularity); + +nurbs = nrbkntins (nurbs, nknots); +geometry = geo_load (nurbs); + +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (geometry.nurbs.knots, rule); +msh = msh_cartesian (geometry.nurbs.knots, qn, qw, geometry); + +% Construct space structure +space = sp_nurbs (geometry.nurbs, msh); + +% Assemble the stiffness matrix and right-hand side +K = op_KL_shells_tp (space, space, msh, E_coeff, nu_coeff, thickness); +rhs = op_f_v_tp_vector (space, msh, f); + +% Apply boundary conditions +drchlt_dofs = []; +for iside = 1:numel(drchlt_sides) + side = drchlt_sides(iside); + if (~exist('drchlt_components','var')) + components = 1:3; + else + components = drchlt_components{iside}; + end + scalar_dofs = space.boundary(side).dofs; + for icomp = components + drchlt_dofs = union (drchlt_dofs, (icomp-1)*space.ndof + scalar_dofs); + end +end + +ndof = msh.rdim * space.ndof; +u = zeros (ndof, 1); +int_dofs = setdiff (1:ndof, drchlt_dofs); +%rhs(int_dofs) = rhs(int_dofs) - K(int_dofs, drchlt_dofs)*u(drchlt_dofs); + +% Solve the linear system +u(int_dofs) = K(int_dofs, int_dofs) \ rhs(int_dofs); + +end diff --git a/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m b/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m new file mode 100644 index 00000000..7deec3ca --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m @@ -0,0 +1,71 @@ +% OP_KL_SHELLS_TP: assemble the Kirchhoff-Love shell stiffness matrix, exploiting the tensor product structure. +% +% mat = op_KL_shells_tp (spu, spv, msh, E_coeff, nu_coeff, t_coeff); +% [rows, cols, values] = op_KL_shells_tp (spu, spv, msh, E_coeff, nu_coeff, t_coeff); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_vector) +% spv: object representing the space of test functions (see sp_vector) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% E_coeff: function handle to compute the Young's modulus +% nu_coeff: function handle to compute the Poisson's ratio +% t_coeff: thickness of the shell, scalar value + +% OUTPUT: +% +% mat: assembled stiffness matrix +% rows: row indices of the nonzero entries +% cols: column indices of the nonzero entries +% values: values of the nonzero entries +% +% Copyright (C) 2018, 2019 Pablo Antolin, Luca Coradello +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function varargout = op_KL_shells_tp (space_u, space_v, msh, E_coeff, nu_coeff, t_coeff) + + A = spalloc (msh.rdim*space_v.ndof, msh.rdim*space_u.ndof, 3*msh.rdim*space_u.ndof); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col_u = sp_evaluate_col_param (space_u, msh_col, 'value', true, 'gradient', true, 'hessian', true); + sp_col_v = sp_evaluate_col_param (space_v, msh_col, 'value', true, 'gradient', true, 'hessian', true); + sp_col_u = sp_scalar2vector_param (sp_col_u, msh_col, 'value', true, 'gradient', true, 'hessian', true); + sp_col_v = sp_scalar2vector_param (sp_col_v, msh_col, 'value', true, 'gradient', true, 'hessian', true); + + if (nargin == 6) + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + E_coeffs = E_coeff (x{:}); + nu_coeffs = nu_coeff (x{:}); + else + error ('geopdes:op_KL_shells_tp: invalid input') + end + + A = A + op_KL_shells (sp_col_u, sp_col_v, msh_col, E_coeffs, nu_coeffs, t_coeff); + end + + if (nargout == 1) + varargout{1} = A; + elseif (nargout == 3) + [rows, cols, vals] = find (A); + varargout{1} = rows; + varargout{2} = cols; + varargout{3} = vals; + end + +end diff --git a/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m b/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m new file mode 100644 index 00000000..3725f868 --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m @@ -0,0 +1,54 @@ +% OP_F_V_TP_VECTOR: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), +% where f is a vector-valued, and the basis functions in each component belong to the same scalar space. +% +% rhs = op_f_v_tp_vector (spv, msh, coeff); +% +% INPUT: +% +% spv: object representing the function space (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% coeff: function handle to compute the vector-valued source function +% +% OUTPUT: +% +% rhs: assembled right-hand side, of size space.ndof*msh.rdim +% +% Copyright (C) 2011, 2017, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_v_tp_vector (space, msh, coeff) + + for idim = 1:msh.ndim + size1 = size (space.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + + rhs = zeros (msh.rdim * space.ndof, 1); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col); + sp_col = sp_scalar2vector (sp_col, msh_col, 'value', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + rhs = rhs + op_f_v (sp_col, msh_col, coeff (x{:})); + end + +end diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_vector.m b/geopdes/inst/space/@sp_scalar/sp_eval_vector.m new file mode 100644 index 00000000..13bfcf32 --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_eval_vector.m @@ -0,0 +1,182 @@ +% SP_EVAL_VECTOR: Compute the value or the derivatives of a function, given by its degrees of freedom, at a given set of points. +% It uses a scalar-valued space, with a vector of degrees of freedom of length rdim*space.ndof +% +% [eu, F] = sp_eval_vector (u, space, geometry, pts, [option], [lambda_lame, mu_lame]); +% [eu, F] = sp_eval_vector (u, space, geometry, npts, [option], [lambda_lame, mu_lame]); +% +% INPUT: +% +% u: vector of dof weights (of length rdim*space.ndof) +% space: object defining the discrete space (see sp_scalar) +% geometry: geometry structure (see geo_load) +% pts: cell array with coordinates of points along each parametric direction +% npts: number of points along each parametric direction +% option: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient', 'curl', 'divergence' and 'stress' +% lambda_lame: function handle to the first Lame coefficient (only needed to compute 'stress') +% mu_lame: function handle for the second Lame coefficient (only needed to compute 'stress') +% +% OUTPUT: +% +% eu: cell-array with the fields evaluated at the given points +% F: grid points in the physical domain, that is, the mapped points +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2011, 2012, 2014, 2015, 2018, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [eu, F] = sp_eval_vector (u, space, geometry, npts, options, lambda_lame, mu_lame) + +% if (numel (u) ~= space.ndof) +% error ('The number of degrees of freedom of the vector and the space do not match') +% end + + if (nargin < 5) + options = {'value'}; + lambda_lame = []; + mu_lame = []; + elseif (nargin < 7) + lambda_lame = []; + mu_lame = []; + end + if (~iscell (options)) + options = {options}; + end + nopts = numel (options); + + ndim = numel (space.knots); + + endpoints = zeros (2, ndim); + if (isfield (geometry, 'nurbs')) + nurbs = geometry.nurbs; + if (ndim == 1) + nurbs.knots = {nurbs.knots}; + end + for idim=1:ndim + endpoints(:,idim) = nurbs.knots{idim}([nurbs.order(idim), end-nurbs.order(idim)+1]); + end + clear nurbs + elseif (isfield (struct(space), 'knots')) + degree = space.degree; + for idim=1:ndim + endpoints(:,idim) = space.knots{idim}([degree(idim)+1, end-degree(idim)]); + end + else + endpoints(2,:) = 1; + end + + if (iscell (npts)) + pts = npts; + npts = cellfun (@numel, pts); + elseif (isvector (npts)) + if (numel (npts) == 1) + npts = npts * ones (1,ndim); + end + for idim = 1:ndim + pts{idim} = linspace (endpoints(1,idim), endpoints(2,idim), npts(idim)); + end + end + + for jj = 1:ndim + pts{jj} = pts{jj}(:)'; + if (numel (pts{jj}) > 1) + brk{jj} = [endpoints(1,jj), pts{jj}(1:end-1) + diff(pts{jj})/2, endpoints(2,jj)]; + else + brk{jj} = endpoints(:,jj).'; + end + end + + msh = msh_cartesian (brk, pts, [], geometry, 'boundary', false); + sp = space.constructor (msh); + + + value = false; grad = false; laplacian = false; + curl = false; divergence = false; + + ncomp = msh.rdim; + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = zeros (ncomp, msh.nqn, msh.nel); + eunum{iopt} = {1:ncomp, 1:msh.nqn}; + eusize{iopt} = [ncomp, npts]; + value = true; + + case 'gradient' + eu{iopt} = zeros (ncomp, msh.rdim, msh.nqn, msh.nel); + eunum{iopt} = {1:ncomp, 1:msh.rdim, 1:msh.nqn}; + eusize{iopt} = [ncomp, msh.rdim, npts]; + grad = true; + +% case 'laplacian' +% eu{iopt} = zeros (ncomp, msh.nqn, msh.nel); +% eunum{iopt} = {1:ncomp, 1:msh.nqn}; +% eusize{iopt} = [ncomp, npts]; +% laplacian = true; +% + case 'curl' + if (msh.ndim == 2 && msh.rdim == 2) + eu{iopt} = zeros (msh.nqn, msh.nel); + eunum{iopt} = {1:msh.nqn}; + eusize{iopt} = npts; + elseif (msh.ndim == 3 && msh.rdim == 3) + eu{iopt} = zeros (msh.rdim, msh.nqn, msh.nel); + eunum{iopt} = {1:msh.rdim, 1:msh.nqn}; + eusize{iopt} = [msh.rdim, npts]; + end + curl = true; + + case 'divergence' + eu{iopt} = zeros (msh.nqn, msh.nel); + eunum{iopt} = {1:msh.nqn}; + eusize{iopt} = npts; + divergence = true; + + case 'stress' + if (nargin < 6) + error ('sp_eval_msh: Lame coefficients missing') + end + eu{iopt} = zeros (ncomp, msh.rdim, msh.nqn, msh.nel); + eunum{iopt} = {1:ncomp, 1:msh.rdim, 1:msh.nqn}; + eusize{iopt} = [ncomp, msh.rdim, npts]; + grad = true; divergence = true; + end + end + + F = zeros (msh.rdim, msh.nqn, msh.nel); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (sp, msh_col, 'value', value, 'gradient', grad); +% 'laplacian', laplacian, 'hessian', hessian); + sp_col = sp_scalar2vector (sp_col, msh_col, 'value', value, 'gradient', grad, 'divergence', divergence, 'curl', curl); + + eu_aux = sp_eval_msh (u, sp_col, msh_col, options); + + F(:,:,msh_col.elem_list) = msh_col.geo_map; + for iopt = 1:nopts + eu{iopt}(eunum{iopt}{:},msh_col.elem_list) = eu_aux{iopt}; + end + end + + F = reshape (F, [msh.rdim, npts]); + for iopt = 1:nopts + eu{iopt} = reshape (eu{iopt}, [eusize{iopt}, 1]); % The extra 1 makes things work also in 1D + end + + if (nopts == 1) + eu = eu{1}; + end +end diff --git a/geopdes/inst/space/@sp_scalar/sp_to_vtk.m b/geopdes/inst/space/@sp_scalar/sp_to_vtk.m index 3ff3d12d..371fb0d2 100644 --- a/geopdes/inst/space/@sp_scalar/sp_to_vtk.m +++ b/geopdes/inst/space/@sp_scalar/sp_to_vtk.m @@ -40,7 +40,11 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) - [eu, F] = sp_eval (u, space, geometry, npts, varargin{:}); + if (numel(u) == space.ndof) + [eu, F] = sp_eval (u, space, geometry, npts, varargin{:}); + elseif (numel(u) == geometry.rdim * space.ndof) + [eu, F] = sp_eval_vector (u, space, geometry, npts, varargin{:}); + end msh_to_vtk (F, eu, filename, fieldname); diff --git a/geopdes/inst/space/sp_scalar2vector.m b/geopdes/inst/space/sp_scalar2vector.m new file mode 100644 index 00000000..8334fb3b --- /dev/null +++ b/geopdes/inst/space/sp_scalar2vector.m @@ -0,0 +1,134 @@ +% SP_SCALAR2VECTOR: from a scalar space struct, compute a vector-valued +% space struct, with the same basis functions on each component. +% +% space_vec = sp_scalar2vector (space, msh, 'option1', value1, ...); +% +% INPUT: +% +% space: struct defining the scalar discrete space (see for instance sp_scalar/sp_evaluate_col) +% msh: struct defining the mesh (see for instance msh_cartesian/msh_evaluate_col) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% curl | false | compute shape_function_curls +% divergence | false | compute shape_function_divs +% hessian | false | compute shape_function_hessians +% +% OUTPUT: +% +% space_vec: struct defining the vector-valued discrete space, with +% ndof = space.ndof*msh.rdim. +% +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function space_vec = sp_scalar2vector (space, msh, varargin) + +value = true; +gradient = false; +divergence = false; +curl = false; +hessian = false; + if (~isempty (varargin)) + if (~rem (length (varargin), 2) == 0) + error ('sp_scalar2vector: options must be passed in the [option, value] format'); + end + for ii=1:2:length(varargin)-1 + if (strcmpi (varargin {ii}, 'value')) + value = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'gradient')) + gradient = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'curl')) + curl = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'divergence')) + divergence = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'hessian')) + hessian = varargin {ii+1}; + else + warning ('Ignoring unknown option %s', varargin {ii}); + end + end + end + + ncomp = msh.rdim; + space_vec.nsh_max = ncomp * space.nsh_max; + space_vec.nsh = ncomp * space.nsh; + space_vec.ndof = ncomp * space.ndof; + space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + space_vec.ncomp = ncomp; + + space_vec.connectivity = []; + for icomp = 1:ncomp + space_vec.connectivity = [space_vec.connectivity; space.connectivity+(icomp-1)*space.ndof]; + end + + if (value) + space_vec.shape_functions = zeros (ncomp, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_functions(icomp,:,fun_inds,:) = space.shape_functions; + end + end + + if (gradient) + space_vec.shape_function_gradients = zeros (ncomp, msh.rdim, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_gradients(icomp,:,:,fun_inds,:) = space.shape_function_gradients; + end + end + + if (divergence) + space_vec.shape_function_divs = zeros (msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_divs(:,fun_inds,:) = space.shape_function_gradients(icomp,:,:,:); + end + end + + if (curl) + if (ncomp == 3) + space_vec.shape_function_curls = zeros (msh.rdim, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + iplone = mod (icomp, ncomp) + 1; + ipltwo = mod (icomp+1, ncomp) + 1; + + space_vec.shape_function_curls(iplone,:,fun_inds,:) = space.shape_function_gradients(ipltwo,:,:,:); + space_vec.shape_function_curls(ipltwo,:,fun_inds,:) = -space.shape_function_gradients(iplone,:,:,:); + end + elseif (ncomp == 2) + space_vec.shape_function_curls = zeros (msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + iplone = mod (icomp, ncomp) + 1; + + space_vec.shape_function_curls(:,fun_inds,:) = (-1)^icomp * space.shape_function_gradients(iplone,:,:,:); + end + end + end + + if (hessian) + space_vec.shape_function_hessians = zeros (ncomp, msh.rdim, msh.rdim, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_hessians(icomp,:,:,:,fun_inds,:) = space.shape_function_hessians; + end + end + +end diff --git a/geopdes/inst/space/sp_scalar2vector_param.m b/geopdes/inst/space/sp_scalar2vector_param.m new file mode 100644 index 00000000..3abc8ce1 --- /dev/null +++ b/geopdes/inst/space/sp_scalar2vector_param.m @@ -0,0 +1,96 @@ +% SP_SCALAR2VECTOR_PARAM: from a scalar space struct, compute a vector-valued +% space struct, with the same basis functions on each component of the parametric domain. +% +% space_vec = sp_scalar2vector_param (space, msh, 'option1', value1, ...); +% +% INPUT: +% +% space: struct defining the scalar discrete space (see for instance sp_scalar/sp_evaluate_col) +% msh: struct defining the mesh (see for instance msh_cartesian/msh_evaluate_col) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% hessian | false | compute shape_function_hessians +% +% OUTPUT: +% +% space_vec: struct defining the vector-valued discrete space, with +% ndof = space.ndof*msh.ndim. +% +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function space_vec = sp_scalar2vector_param (space, msh, varargin) + +value = true; +gradient = false; +hessian = false; + if (~isempty (varargin)) + if (~rem (length (varargin), 2) == 0) + error ('sp_scalar2vector: options must be passed in the [option, value] format'); + end + for ii=1:2:length(varargin)-1 + if (strcmpi (varargin {ii}, 'value')) + value = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'gradient')) + gradient = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'hessian')) + hessian = varargin {ii+1}; + else + warning ('Ignoring unknown option %s', varargin {ii}); + end + end + end + + ncomp = msh.rdim; + space_vec.nsh_max = ncomp * space.nsh_max; + space_vec.nsh = ncomp * space.nsh; + space_vec.ndof = ncomp * space.ndof; + space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + space_vec.ncomp = ncomp; + + space_vec.connectivity = []; + for icomp = 1:ncomp + space_vec.connectivity = [space_vec.connectivity; space.connectivity+(icomp-1)*space.ndof]; + end + + if (value) + space_vec.shape_functions = zeros (ncomp, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_functions(icomp,:,fun_inds,:) = space.shape_functions; + end + end + + if (gradient) + space_vec.shape_function_gradients = zeros (ncomp, msh.ndim, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_gradients(icomp,:,:,fun_inds,:) = space.shape_function_gradients; + end + end + + if (hessian) + space_vec.shape_function_hessians = zeros (ncomp, msh.ndim, msh.ndim, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_hessians(icomp,:,:,:,fun_inds,:) = space.shape_function_hessians; + end + end + +end From fd2630556739c59e39daf05dec47c057899ea985 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 5 Sep 2022 15:49:56 +0200 Subject: [PATCH 166/366] Some small changes and a bug to plot the stress --- geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m | 5 +++-- geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m | 4 ++-- geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m | 2 +- geopdes/inst/space/@sp_scalar/sp_eval_vector.m | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m index 3426f696..af941a43 100644 --- a/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m +++ b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m @@ -1,9 +1,9 @@ -% SOLVE_KIRCHHOFF_LOVE_SHELL: Solve the Kirchhoff-Love shell model in a NURBS domain. +% SOLVE_KIRCHHOFF_LOVE_SHELL_SCALARSPACE: Solve the Kirchhoff-Love shell model in a NURBS domain. % It uses an object space of type sp_scalar, instead of sp_vector. % % USAGE: % -% [geometry, msh, space, u] = solve_kirchhoff_love_shell (problem_data, method_data) +% [geometry, msh, space, u] = solve_kirchhoff_love_shell_scalarspace (problem_data, method_data) % % INPUT: % @@ -35,6 +35,7 @@ % See also EX_KL_SHELL_SCORDELIS_LO_ROOF for an example. % % Copyright (C) 2017-2019 Pablo Antolin, Luca Coradello, Rafael Vazquez +% Copyright (C) 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by diff --git a/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m b/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m index 7deec3ca..6e0a30f5 100644 --- a/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m +++ b/geopdes/inst/space/@sp_scalar/op_KL_shells_tp.m @@ -5,8 +5,8 @@ % % INPUT: % -% spu: object representing the space of trial functions (see sp_vector) -% spv: object representing the space of test functions (see sp_vector) +% spu: object representing the space of trial functions (see sp_scalar) +% spv: object representing the space of test functions (see sp_scalar) % msh: object defining the domain partition and the quadrature rule (see msh_cartesian) % E_coeff: function handle to compute the Young's modulus % nu_coeff: function handle to compute the Poisson's ratio diff --git a/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m b/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m index 3725f868..1801f878 100644 --- a/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m +++ b/geopdes/inst/space/@sp_scalar/op_f_v_tp_vector.m @@ -1,5 +1,5 @@ % OP_F_V_TP_VECTOR: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), -% where f is a vector-valued, and the basis functions in each component belong to the same scalar space. +% where f is vector-valued, and the basis functions in each component belong to the same scalar space. % % rhs = op_f_v_tp_vector (spv, msh, coeff); % diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_vector.m b/geopdes/inst/space/@sp_scalar/sp_eval_vector.m index 13bfcf32..5746718f 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval_vector.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval_vector.m @@ -163,7 +163,8 @@ % 'laplacian', laplacian, 'hessian', hessian); sp_col = sp_scalar2vector (sp_col, msh_col, 'value', value, 'gradient', grad, 'divergence', divergence, 'curl', curl); - eu_aux = sp_eval_msh (u, sp_col, msh_col, options); + eu_aux = sp_eval_msh (u, sp_col, msh_col, options, lambda_lame, mu_lame); +% eu_aux = sp_eval_msh (u, sp_col, msh_col, options); F(:,:,msh_col.elem_list) = msh_col.geo_map; for iopt = 1:nopts From b7f0ac440136076bd761b1d824720a382959cc47 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 27 Sep 2022 10:59:52 +0200 Subject: [PATCH 167/366] Fixed bug for single patch domain --- geopdes/inst/multipatch/vertices_struct.m | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index 520718d9..be470b53 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -61,6 +61,9 @@ icont = icont + 1; interfaces(N_int+icont).patch1 = boundaries(hh).patches(jj); interfaces(N_int+icont).side1 = boundaries(hh).faces(jj); + interfaces(N_int+icont).patch2 = []; + interfaces(N_int+icont).side2 = []; + interfaces(N_int+icont).ornt = []; interfaces_bnd(N_int+icont).patch1 = boundaries(hh).patches(jj); interfaces_bnd(N_int+icont).side1 = boundaries(hh).faces(jj); interfaces_bnd(N_int+icont).patch2 = 0; @@ -179,7 +182,12 @@ function check_orientation (geometry, interfaces) - Nint = find ([interfaces.patch2]); Nint = Nint(end); + Nint = find ([interfaces.patch2]); + if (~isempty (Nint)) + Nint = Nint(end); + else + Nint = 0; + end coords_on_side = {0 0.5; 1 0.5; 0.5 0; 0.5 1}; %4 rows for the sides, 2 columns for the coordinates From 9509727a58a3751930e02a24866144a66007d04b Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 30 Sep 2022 13:09:57 +0200 Subject: [PATCH 168/366] Modifications for vector fields on scalar spaces --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m | 8 ++++++++ geopdes/inst/space/sp_scalar2vector_param.m | 11 +++++++++++ 2 files changed, 19 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index e3d71569..af9bef13 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -67,6 +67,8 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) filename_patch_without_path = cat (2, filename(ind:end), '_', num2str (iptc)); filename_patch = cat (2, filename, '_', num2str (iptc)); fprintf (fid, str2, iptc, filename_patch_without_path); + + if (numel(u) == space.ndof) % if (isempty (space.dofs_ornt)) sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) @@ -74,6 +76,12 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) % sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... % filename_patch, fieldname, varargin{:}) % end + elseif (numel(u) == space.ndof*geometry(iptc).rdim) + Cpatch_repmat = repmat (space.Cpatch(iptc), 1, geometry(iptc).rdim); + Cpatch_vector = blkdiag (Cpatch_repmat{:}); + sp_to_vtk (Cpatch_vector * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + filename_patch, fieldname, varargin{:}) + end end fprintf (fid, str3); diff --git a/geopdes/inst/space/sp_scalar2vector_param.m b/geopdes/inst/space/sp_scalar2vector_param.m index 3abc8ce1..882ce5e9 100644 --- a/geopdes/inst/space/sp_scalar2vector_param.m +++ b/geopdes/inst/space/sp_scalar2vector_param.m @@ -40,6 +40,7 @@ value = true; gradient = false; hessian = false; +divergence = false; if (~isempty (varargin)) if (~rem (length (varargin), 2) == 0) error ('sp_scalar2vector: options must be passed in the [option, value] format'); @@ -49,6 +50,8 @@ value = varargin {ii+1}; elseif (strcmpi (varargin {ii}, 'gradient')) gradient = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'divergence')) + divergence = varargin {ii+1}; elseif (strcmpi (varargin {ii}, 'hessian')) hessian = varargin {ii+1}; else @@ -84,6 +87,14 @@ space_vec.shape_function_gradients(icomp,:,:,fun_inds,:) = space.shape_function_gradients; end end + + if (divergence) + space_vec.shape_function_divs = zeros (msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_divs(:,fun_inds,:) = space.shape_function_gradients (icomp,:,:,:); + end + end if (hessian) space_vec.shape_function_hessians = zeros (ncomp, msh.ndim, msh.ndim, msh.nqn, space_vec.nsh_max, msh.nel); From f69834ef545d4632a9182f5e2c707086351e2da0 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 28 May 2020 14:24:38 +0200 Subject: [PATCH 169/366] Keep the warning as it was before entering the function --- geopdes/inst/geometry/geo_load.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/geometry/geo_load.m b/geopdes/inst/geometry/geo_load.m index 4d703bf3..243099dd 100644 --- a/geopdes/inst/geometry/geo_load.m +++ b/geopdes/inst/geometry/geo_load.m @@ -87,6 +87,7 @@ end geometry.rdim = rdim; + wrn_struct = warning ('query', 'nrbderiv:SecondDerivative'); warning ('off', 'nrbderiv:SecondDerivative') [deriv, deriv2] = nrbderiv (geometry.nurbs); geometry.dnurbs = deriv; @@ -109,7 +110,9 @@ geometry.boundary(ibnd).map_der2 = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 2, rdim); end end - warning ('on', 'nrbderiv:SecondDerivative') + if (strcmpi (wrn_struct.state, 'on')) + warning ('on', 'nrbderiv:SecondDerivative') + end else for ibnd = 1:6 % This loop should be until 2*ndim, but ndim is not known geometry.boundary(ibnd).map = @(PTS) boundary_map (geometry.map, ibnd, PTS); From 6de9b0bef6b40b2fb7f341e4ce02013e8704d095 Mon Sep 17 00:00:00 2001 From: Carlo de Falco Date: Wed, 3 Jun 2020 23:03:18 +0200 Subject: [PATCH 170/366] allow complex coefficients --- geopdes/src/op_f_v.cc | 93 ++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/geopdes/src/op_f_v.cc b/geopdes/src/op_f_v.cc index 553ed945..013bfcde 100644 --- a/geopdes/src/op_f_v.cc +++ b/geopdes/src/op_f_v.cc @@ -19,44 +19,21 @@ #include "geopdes.h" -DEFUN_DLD(op_f_v, args, nargout,"\n\ -OP_F_V: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i). \n\ -\n\ - mat = op_f_v (spv, msh, coeff); \n\ -\n\ -INPUT:\n\ -\n\ - spv: structure representing the function space (see sp_scalar/sp_evaluate_col) \n\ - msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) \n\ - coeff: source function evaluated at the quadrature points \n\ -\n\ -OUTPUT:\n\ -\n\ - mat: assembled right-hand side \n\ -") +template +void op_f_v_worker (const geopdes_mesh &msh, const geopdes_space &sp, + const ARRAY &coeff, NUMBER *matptr) { - - octave_value_list retval; - - if (nargout != 1 || args.length () != 3) - print_usage (); - - geopdes_mesh msh (args(1).scalar_map_value ()); - geopdes_space sp (args(0).scalar_map_value (), msh); - const octave_idx_type nel = msh.nel (), ncomp = sp.ncomp (), - nqn = msh.nqn (), nsh = sp.nsh_max (); - - double jacdet_weights[nqn]; - - dim_vector idx (ncomp, nqn, nel); - Array coeff = args(2).array_value ().reshape (idx); + const octave_idx_type + nel = msh.nel (), + ncomp = sp.ncomp (), + nqn = msh.nqn (), + nsh = sp.nsh_max (); double shp[nsh][nqn][ncomp]; octave_idx_type conn[nsh]; - ColumnVector mat (sp.ndof (), 0.0); - double *matptr = mat.fortran_vec (); - + double jacdet_weights[nqn]; + octave_idx_type iel, inode, idof, icmp; for (iel=0; iel < nel; iel++) @@ -74,7 +51,7 @@ OUTPUT:\n\ if (msh.weights (inode, iel) > 0.0) { - double s = 0.0; + NUMBER s = 0.0; for (icmp = 0; icmp < ncomp; icmp++) s += shp[idof][inode][icmp] * coeff (icmp, inode, iel); @@ -87,9 +64,53 @@ OUTPUT:\n\ { warning_with_id ("geopdes:zero_measure_element", "op_f_v: element %lld has 0 area (or volume)", static_cast (iel)); } - - retval(0) = octave_value (mat); +} + +DEFUN_DLD(op_f_v, args, nargout,"\n\ +OP_F_V: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i). \n\ +\n\ + mat = op_f_v (spv, msh, coeff); \n\ +\n\ +INPUT:\n\ +\n\ + spv: structure representing the function space (see sp_scalar/sp_evaluate_col) \n\ + msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) \n\ + coeff: source function evaluated at the quadrature points \n\ +\n\ +OUTPUT:\n\ +\n\ + mat: assembled right-hand side \n\ +") +{ + + octave_value_list retval; + + if (nargout != 1 || args.length () != 3) + print_usage (); + + geopdes_mesh msh (args(1).scalar_map_value ()); + geopdes_space sp (args(0).scalar_map_value (), msh); + dim_vector idx (sp.ncomp (), msh.nqn (), msh.nel ()); + + if (args(2).iscomplex ()) + { + Array coeff = args(2).complex_array_value ().reshape (idx); + ComplexColumnVector mat (sp.ndof (), 0.0); + Complex *matptr = mat.fortran_vec (); + op_f_v_worker (msh, sp, coeff, matptr); + retval(0) = octave_value (mat); + } + else + { + Array coeff = args(2).array_value ().reshape (idx); + ColumnVector mat (sp.ndof (), 0.0); + double *matptr = mat.fortran_vec (); + op_f_v_worker (msh, sp, coeff, matptr); + retval(0) = octave_value (mat); + } + + return retval; } From 2abe522f7720b292775a40bcde3c12a509b80778 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 14 Jul 2020 02:02:40 +0200 Subject: [PATCH 171/366] Added periodic functionalities to scalar spaces --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 97 +++++++++++++++-------- geopdes/inst/space/sp_bspline.m | 19 +++-- geopdes/inst/space/sp_bspline_1d_param.m | 24 +++++- geopdes/inst/utils/kntunclamp.m | 89 +++++++++++++++++++++ 4 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 geopdes/inst/utils/kntunclamp.m diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 33bb8eb5..5b0aea6a 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -73,8 +73,14 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_scalar (knots, degree, weights, msh, transform) +function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_directions,regularity) + if (nargin < 7) + regularity = degree-1; + end + if (nargin < 6) + periodic_directions = []; + end if (nargin == 4) transform = 'grad-preserving'; end @@ -93,14 +99,27 @@ if (numel (knots) ~= msh.ndim) error ('The dimension of the mesh and the space do not correspond to each other') end - + + if numel(periodic_directions) > 0 + knots = kntunclamp(knots, degree, regularity, periodic_directions); + end + + sp.knots = knots; sp.degree = degree; sp.weights = weights; + nodes = msh.qn; for idim = 1:msh.ndim - sp.sp_univ(idim) = sp_bspline_1d_param (knots{idim}, degree(idim), nodes{idim}, 'gradient', true, 'hessian', true); + if (regularity(idim) >= degree(idim)) + regularity(idim) = degree(idim)-1; + end + sp.sp_univ(idim) = sp_bspline_1d_param (knots{idim}, degree(idim), nodes{idim},... + 'gradient', true, 'hessian', true,... + 'periodic',ismember(idim,periodic_directions),... + 'regularity',regularity(idim)); + end sp.nsh_dir = [sp.sp_univ.nsh_max]; @@ -121,45 +140,51 @@ %% ind2 = [1 1 2 2 3 3] in 3D, %ind2 = [1 1 2 2] in 2D ind2 = ceil (iside/2); ind = setdiff (1:msh.ndim, ind2); + + if (~ismember(ind2,periodic_directions)) + if (~isempty (msh.boundary)) + if (strcmpi (sp.space_type, 'spline')) + weights = []; + elseif (strcmpi (sp.space_type, 'nurbs')) + indices = arrayfun (@(x) 1:x, sp.ndof_dir, 'UniformOutput', false); + if (rem (iside, 2) == 0) + indices{ind2} = sp.ndof_dir(ind2); + else + indices{ind2} = 1; + end + weights = squeeze (sp.weights(indices{:})); + end + sp.boundary(iside) = sp_scalar (sp.knots(ind), sp.degree(ind), weights, msh.boundary(iside)); + end + + bnd_ndof_dir = sp.ndof_dir(ind); + bnd_ndof = prod (bnd_ndof_dir); + [ind_univ{ind}] = ind2sub (bnd_ndof_dir, 1:bnd_ndof); + if (rem (iside, 2) == 0) + ind_univ{ind2} = sp.ndof_dir(ind2) * ones (1, bnd_ndof); + else + ind_univ{ind2} = ones (1, bnd_ndof); + end + sp.boundary(iside).dofs = sub2ind (sp.ndof_dir, ind_univ{:}); + sp.boundary(iside).ndof = numel (sp.boundary(iside).dofs); - if (~isempty (msh.boundary)) - if (strcmpi (sp.space_type, 'spline')) - weights = []; - elseif (strcmpi (sp.space_type, 'nurbs')) - indices = arrayfun (@(x) 1:x, sp.ndof_dir, 'UniformOutput', false); + if (sp.ndof_dir(ind2) > 1) if (rem (iside, 2) == 0) - indices{ind2} = sp.ndof_dir(ind2); + ind_univ{ind2} = (sp.ndof_dir(ind2) - 1) * ones (1, bnd_ndof); else - indices{ind2} = 1; + ind_univ{ind2} = 2 * ones (1, bnd_ndof); end - weights = squeeze (sp.weights(indices{:})); + sp.boundary(iside).adjacent_dofs = sub2ind (sp.ndof_dir, ind_univ{:}); end - sp.boundary(iside) = sp_scalar (sp.knots(ind), sp.degree(ind), weights, msh.boundary(iside)); - end - bnd_ndof_dir = sp.ndof_dir(ind); - bnd_ndof = prod (bnd_ndof_dir); - [ind_univ{ind}] = ind2sub (bnd_ndof_dir, 1:bnd_ndof); - if (rem (iside, 2) == 0) - ind_univ{ind2} = sp.ndof_dir(ind2) * ones (1, bnd_ndof); else - ind_univ{ind2} = ones (1, bnd_ndof); + sp.boundary(iside).ndof = 0; + sp.boundary(iside).dofs = []; + sp.boundary(iside).adjacent_dofs = []; end - sp.boundary(iside).dofs = sub2ind (sp.ndof_dir, ind_univ{:}); - sp.boundary(iside).ndof = numel (sp.boundary(iside).dofs); - - if (sp.ndof_dir(ind2) > 1) - if (rem (iside, 2) == 0) - ind_univ{ind2} = (sp.ndof_dir(ind2) - 1) * ones (1, bnd_ndof); - else - ind_univ{ind2} = 2 * ones (1, bnd_ndof); - end - sp.boundary(iside).adjacent_dofs = sub2ind (sp.ndof_dir, ind_univ{:}); - end - end - elseif (msh.ndim == 1) + elseif (msh.ndim == 1 && numel(periodic_directions) == 0 ) sp.boundary(1).dofs = 1; sp.boundary(2).dofs = sp.ndof; if (sp.ndof > 1) @@ -177,8 +202,12 @@ sp.adjacent_dofs = []; sp.transform = transform; - - sp.constructor = @(MSH) sp_scalar (sp.knots, sp.degree, sp.weights, MSH, sp.transform); + + sp.periodic_directions = periodic_directions; + sp.regularity = regularity; + + sp.constructor = @(MSH) sp_scalar (sp.knots, sp.degree, sp.weights, MSH, sp.transform,... + sp.periodic_directions,sp.regularity); sp = class (sp, 'sp_scalar'); end diff --git a/geopdes/inst/space/sp_bspline.m b/geopdes/inst/space/sp_bspline.m index 78c3a63e..5dbf2775 100644 --- a/geopdes/inst/space/sp_bspline.m +++ b/geopdes/inst/space/sp_bspline.m @@ -29,12 +29,19 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_bspline (knots, degree, msh, transform) +function sp = sp_bspline (knots, degree, msh, transform, periodic_directions,regularity) -if (nargin == 3) - transform = 'grad-preserving'; -end + if (nargin < 6) + regularity = degree-1; + end + + if (nargin < 5) + periodic_directions = []; + end + if (nargin == 3) + transform = 'grad-preserving'; + end -sp = sp_scalar (knots, degree, [], msh, transform); + sp = sp_scalar (knots, degree, [], msh, transform, periodic_directions, regularity); -end \ No newline at end of file +end diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 7b1922f7..e4fbadf0 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -42,6 +42,9 @@ gradient = true; hessian = false; +periodic = false; +regularity = degree-1; + if (~isempty (varargin)) if (~rem (length (varargin), 2) == 0) error ('sp_bspline_1d_param: options must be passed in the [option, value] format'); @@ -51,6 +54,10 @@ gradient = varargin {ii+1}; elseif (strcmpi (varargin {ii}, 'hessian')) hessian = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'periodic')) + periodic = varargin{ii+1}; + elseif (strcmpi (varargin {ii}, 'regularity')) + regularity = varargin{ii+1}; else error ('sp_bspline_1d_param: unknown option %s', varargin {ii}); end @@ -99,12 +106,26 @@ supp = cell (ndof, 1); for ii = 1:ndof - [dummy, supp{ii}] = find (connectivity == ii); + [~, supp{ii}] = find (connectivity == ii); end shape_functions = reshape (ders(:, 1, :), nqn, nel, []); shape_functions = permute (shape_functions, [1, 3, 2]); +if (periodic) + n_extra_dofs = regularity+1; + + ndof = ndof-n_extra_dofs; + nsh = repmat(nsh_max,1,size(connectivity,2)); + + connectivity = mod(connectivity-1,ndof)+1; + + for k = 1:n_extra_dofs + supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; + supp(end) = []; % deletes cell-array element! + end +end + sp = struct ('nsh_max', nsh_max, 'nsh', nsh, 'ndof', ndof, ... 'connectivity', connectivity, ... 'shape_functions', shape_functions, ... @@ -123,6 +144,7 @@ sp.('shape_function_hessians') = shape_function_hessians; end + end diff --git a/geopdes/inst/utils/kntunclamp.m b/geopdes/inst/utils/kntunclamp.m new file mode 100644 index 00000000..5e0dae54 --- /dev/null +++ b/geopdes/inst/utils/kntunclamp.m @@ -0,0 +1,89 @@ +function uknt = kntunclamp (knt, deg, k, dim) +% KNTUNCLAMP: Compute the unclamped knot vector starting from an open one. +% +% Calling Sequence: +% +% uknt = kntunclamp (knt, deg, k) +% uknt = kntunclamp (knt, deg, k, dim) +% +% INPUT: +% +% knt : open knot vector: see kntrefine +% deg : polynomial degree of the spline space +% k : continuity for the unclamping (from 0 up to p-1) +% dim : dimension in which to unclamp (all by default). +% +% OUTPUT: +% +% uknt: unclamped knot vector, see nrbmak +% +% Description: +% +% Unclamps directly the open knot vector. See nrbunclamp +% for further information. +% +% Copyright (C) 2013, 2014 Rafael Vazquez +% Copyright (C) 2020, Bernard Kapidani +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + + if (~iscell (knt)) + knt = {knt}; + end + uknt = knt; + + ndim = numel (knt); + if (nargin < 4) + dim = 1:ndim; + end + + +% if (iscell (knt)) + if (numel(k) < ndim) + k = [k(:).', k(end) * ones(1, ndim-numel(k))]; + end + + assert (numel(deg) == ndim, 'degrees and knots must have the same size'); + for idim = dim + + U = knt{idim}; + + p = deg(idim); + n = numel(U) - p - 1; + m = n + p + 1; + kk = k(idim); + + if (kk >= p) + warning ('Taking the maximum k allowed, degree - 1') + kk = p - 1; + end + + % Unclamp at left end + for ii=0:kk + U(kk-ii+1) = U(kk-ii+2) - (U(n+1-ii) - U(n-ii)); + end + + % Unclamp at right end + for ii=0:kk + U(m-kk+ii) = U(m-kk+ii-1) + U(p+ii+1+1) - U(p+ii+1); + end + +% defect = p - kk - 1; + uknt{idim} = U; + + end + +end + + From 29f4ccc702d46b389bb13e143f8147d682ec180c Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 14 Jul 2020 12:28:59 +0200 Subject: [PATCH 172/366] Regularity is not needed anymore as an input for periodic scalar spaces --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 36 ++++++++++------------- geopdes/inst/space/sp_bspline.m | 13 ++++---- geopdes/inst/space/sp_bspline_1d_param.m | 7 +++-- geopdes/inst/utils/kntunclamp.m | 1 - 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 5b0aea6a..135714b4 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -1,15 +1,17 @@ % SP_SCALAR: Constructor of the class of scalar tensor-product spaces (B-Splines or NURBS). % -% sp = sp_scalar (knots, degree, weights, msh, [transform]) +% sp = sp_scalar (knots, degree, weights, msh, [transform, periodic_directions]) % % INPUTS: % -% knots: open knot vector (cell array of size [1, ndim]) -% degree: spline polynomial degree (vector of size [1, ndim]) -% weights: weights associated to the basis functions. For B-splines it should be empty -% msh: msh object that defines the quadrature rule (see msh_cartesian) -% transform: string with the transformation to the physical domain, one of -% 'grad-preserving' (default) and 'integral-preserving', for N-forms. +% knots: open knot vector (cell array of size [1, ndim]) +% degree: spline polynomial degree (vector of size [1, ndim]) +% weights: weights associated to the basis functions. For B-splines it should be empty +% msh: msh object that defines the quadrature rule (see msh_cartesian) +% transform: string with the transformation to the physical domain, one of +% 'grad-preserving' (default) and 'integral-preserving', for N-forms +% periodic_directions: Cartesian directions in which the space should be made periodic +% % % OUTPUT: % @@ -73,11 +75,8 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_directions,regularity) +function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_directions) - if (nargin < 7) - regularity = degree-1; - end if (nargin < 6) periodic_directions = []; end @@ -100,9 +99,9 @@ error ('The dimension of the mesh and the space do not correspond to each other') end - if numel(periodic_directions) > 0 - knots = kntunclamp(knots, degree, regularity, periodic_directions); - end +% % % if (numel(periodic_directions) > 0) +% % % knots = kntunclamp(knots, degree, regularity, periodic_directions); +% % % end sp.knots = knots; @@ -112,13 +111,9 @@ nodes = msh.qn; for idim = 1:msh.ndim - if (regularity(idim) >= degree(idim)) - regularity(idim) = degree(idim)-1; - end sp.sp_univ(idim) = sp_bspline_1d_param (knots{idim}, degree(idim), nodes{idim},... 'gradient', true, 'hessian', true,... - 'periodic',ismember(idim,periodic_directions),... - 'regularity',regularity(idim)); + 'periodic',ismember(idim,periodic_directions)); end @@ -204,10 +199,9 @@ sp.transform = transform; sp.periodic_directions = periodic_directions; - sp.regularity = regularity; sp.constructor = @(MSH) sp_scalar (sp.knots, sp.degree, sp.weights, MSH, sp.transform,... - sp.periodic_directions,sp.regularity); + sp.periodic_directions); sp = class (sp, 'sp_scalar'); end diff --git a/geopdes/inst/space/sp_bspline.m b/geopdes/inst/space/sp_bspline.m index 5dbf2775..bed62078 100644 --- a/geopdes/inst/space/sp_bspline.m +++ b/geopdes/inst/space/sp_bspline.m @@ -1,6 +1,6 @@ % SP_BSPLINE: Constructor of the class of tensor-product spaces of B-Splines. % -% sp = sp_bspline (knots, degree, msh, [transform]) +% sp = sp_bspline (knots, degree, msh, [transform, periodic_directions]) % % INPUTS: % @@ -29,19 +29,20 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_bspline (knots, degree, msh, transform, periodic_directions,regularity) +function sp = sp_bspline (knots, degree, msh, transform, periodic_directions) - if (nargin < 6) - regularity = degree-1; - end +% % % if (nargin < 6) +% % % regularity = degree-1; +% % % end if (nargin < 5) periodic_directions = []; end + if (nargin == 3) transform = 'grad-preserving'; end - sp = sp_scalar (knots, degree, [], msh, transform, periodic_directions, regularity); + sp = sp_scalar (knots, degree, [], msh, transform, periodic_directions); end diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index e4fbadf0..3b0067fb 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -16,6 +16,7 @@ % ------------+-----------------+----------------------------------- % gradient | true | compute shape_function_gradients % hessian | false | compute shape_function_hessians +% periodic | false | make space connectivity periodic % % OUTPUT: % @@ -43,7 +44,6 @@ gradient = true; hessian = false; periodic = false; -regularity = degree-1; if (~isempty (varargin)) if (~rem (length (varargin), 2) == 0) @@ -56,8 +56,6 @@ hessian = varargin {ii+1}; elseif (strcmpi (varargin {ii}, 'periodic')) periodic = varargin{ii+1}; - elseif (strcmpi (varargin {ii}, 'regularity')) - regularity = varargin{ii+1}; else error ('sp_bspline_1d_param: unknown option %s', varargin {ii}); end @@ -113,6 +111,9 @@ shape_functions = permute (shape_functions, [1, 3, 2]); if (periodic) + + uniknots = unique(knots); + regularity = degree-nnz(uniknots(degree+1) == knots); n_extra_dofs = regularity+1; ndof = ndof-n_extra_dofs; diff --git a/geopdes/inst/utils/kntunclamp.m b/geopdes/inst/utils/kntunclamp.m index 5e0dae54..10ee3d1c 100644 --- a/geopdes/inst/utils/kntunclamp.m +++ b/geopdes/inst/utils/kntunclamp.m @@ -79,7 +79,6 @@ U(m-kk+ii) = U(m-kk+ii-1) + U(p+ii+1+1) - U(p+ii+1); end -% defect = p - kk - 1; uknt{idim} = U; end From ff008fc6e4e45f9213b5507cf0be70fa65ddb217 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 14 Jul 2020 13:54:18 +0200 Subject: [PATCH 173/366] Fixed bug --- geopdes/inst/space/sp_bspline_1d_param.m | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 3b0067fb..e74fd8ee 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -111,15 +111,13 @@ shape_functions = permute (shape_functions, [1, 3, 2]); if (periodic) - - uniknots = unique(knots); - regularity = degree-nnz(uniknots(degree+1) == knots); - n_extra_dofs = regularity+1; + regularity = degree - nnz(knots == knots(degree+1)); + n_extra_dofs = regularity + 1; - ndof = ndof-n_extra_dofs; + ndof = ndof - n_extra_dofs; nsh = repmat(nsh_max,1,size(connectivity,2)); - connectivity = mod(connectivity-1,ndof)+1; + connectivity = mod(connectivity-1,ndof) + 1; for k = 1:n_extra_dofs supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; From f3588d563178d6bc47cbafc00559fe0c60b6772e Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 14 Jul 2020 15:35:02 +0200 Subject: [PATCH 174/366] Optimized support id procedure in 1d constructor --- geopdes/inst/space/sp_bspline_1d_param.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index e74fd8ee..9375f864 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -102,11 +102,6 @@ ders(inqn,:,ind:ind+p) = tders(inqn,:,:); end -supp = cell (ndof, 1); -for ii = 1:ndof - [~, supp{ii}] = find (connectivity == ii); -end - shape_functions = reshape (ders(:, 1, :), nqn, nel, []); shape_functions = permute (shape_functions, [1, 3, 2]); @@ -119,10 +114,15 @@ connectivity = mod(connectivity-1,ndof) + 1; - for k = 1:n_extra_dofs - supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; - supp(end) = []; % deletes cell-array element! - end +% % % for k = 1:n_extra_dofs +% % % supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; +% % % supp(end) = []; % deletes cell-array element! +% % % end +end + +supp = cell (ndof, 1); +for ii = 1:ndof + [~, supp{ii}] = find (connectivity == ii); end sp = struct ('nsh_max', nsh_max, 'nsh', nsh, 'ndof', ndof, ... From d0d5f02276f042f7f99a5704b6c41a50d5ece9e2 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 14 Jul 2020 20:48:26 +0200 Subject: [PATCH 175/366] Fixed bug with non-full connectivity --- geopdes/inst/space/sp_bspline_1d_param.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 9375f864..39f5c611 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -85,8 +85,9 @@ c = numbasisfun (s, nodes(:, iel)', p, knots); c = unique(c(:))+1; connectivity(1:numel(c), iel) = c; - nsh(iel) = nnz (connectivity(:,iel)); + % nsh(iel) = nnz (connectivity(:,iel)); % faster outside loop? end +nsh = sum(connectivity ~= 0,1); % faster outside loop? nsh_max = max (nsh); @@ -110,10 +111,14 @@ n_extra_dofs = regularity + 1; ndof = ndof - n_extra_dofs; - nsh = repmat(nsh_max,1,size(connectivity,2)); + filter = (connectivity == 0); connectivity = mod(connectivity-1,ndof) + 1; - + connectivity(filter) = 0; + + nsh = sum(connectivity ~= 0,1); +% nsh = repmat(nsh_max,1,size(connectivity,2)); + % % % for k = 1:n_extra_dofs % % % supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; % % % supp(end) = []; % deletes cell-array element! From cdd3d4b330e6e05052d0e1000d2b2b988bf224b6 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 14 Jul 2020 23:31:24 +0200 Subject: [PATCH 176/366] Added possibility of periodicity in boundary spaces --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 6 +++++- geopdes/inst/space/sp_bspline.m | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 135714b4..510414d6 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -149,7 +149,11 @@ end weights = squeeze (sp.weights(indices{:})); end - sp.boundary(iside) = sp_scalar (sp.knots(ind), sp.degree(ind), weights, msh.boundary(iside)); + + [~,bnd_periodic_dir] = ismember(periodic_directions,ind); + bnd_periodic_dir = nonzeros(bnd_periodic_dir); + sp.boundary(iside) = sp_scalar (sp.knots(ind), sp.degree(ind), weights, msh.boundary(iside),... + 'grad-preserving',bnd_periodic_dir); end bnd_ndof_dir = sp.ndof_dir(ind); diff --git a/geopdes/inst/space/sp_bspline.m b/geopdes/inst/space/sp_bspline.m index bed62078..197bcf9b 100644 --- a/geopdes/inst/space/sp_bspline.m +++ b/geopdes/inst/space/sp_bspline.m @@ -37,6 +37,8 @@ if (nargin < 5) periodic_directions = []; + else % more robust + periodic_directions = sort(periodic_directions); end if (nargin == 3) From fd7981c980ea349ba462d84bd0bfe38e901599bc Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 15 Jul 2020 11:04:31 +0200 Subject: [PATCH 177/366] Empty space object --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 510414d6..d6eab39f 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -77,6 +77,15 @@ function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_directions) + if (nargin < 1) + sp = struct ('space_type', [], 'knots', [], 'degree', [], 'weights', [], 'sp_univ', [], ... + 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', [], 'ncomp', [], 'boundary', [], ... + 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_directions', [], ... + 'constructor', @(MSH) sp_scalar()); + sp = class (sp, 'sp_scalar'); + return + end + if (nargin < 6) periodic_directions = []; end @@ -99,22 +108,15 @@ error ('The dimension of the mesh and the space do not correspond to each other') end -% % % if (numel(periodic_directions) > 0) -% % % knots = kntunclamp(knots, degree, regularity, periodic_directions); -% % % end - - sp.knots = knots; sp.degree = degree; sp.weights = weights; - nodes = msh.qn; for idim = 1:msh.ndim sp.sp_univ(idim) = sp_bspline_1d_param (knots{idim}, degree(idim), nodes{idim},... - 'gradient', true, 'hessian', true,... - 'periodic',ismember(idim,periodic_directions)); - + 'gradient', true, 'hessian', true,... + 'periodic',ismember(idim,periodic_directions)); end sp.nsh_dir = [sp.sp_univ.nsh_max]; @@ -177,9 +179,7 @@ end else - sp.boundary(iside).ndof = 0; - sp.boundary(iside).dofs = []; - sp.boundary(iside).adjacent_dofs = []; + sp.boundary(iside) = sp_scalar(); end end From 143a23ea533d8ddb5da33f9c4e19eb7da0f061fc Mon Sep 17 00:00:00 2001 From: bkapidani Date: Thu, 16 Jul 2020 13:55:34 +0200 Subject: [PATCH 178/366] Scalar objects in empty sp_scalar constructors have scalar values --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 25 ++++++++++++----------- geopdes/inst/space/sp_bspline_1d_param.m | 10 ++------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index d6eab39f..f0a2bee0 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -1,6 +1,6 @@ % SP_SCALAR: Constructor of the class of scalar tensor-product spaces (B-Splines or NURBS). % -% sp = sp_scalar (knots, degree, weights, msh, [transform, periodic_directions]) +% sp = sp_scalar (knots, degree, weights, msh, [transform, periodic_dir]) % % INPUTS: % @@ -10,7 +10,7 @@ % msh: msh object that defines the quadrature rule (see msh_cartesian) % transform: string with the transformation to the physical domain, one of % 'grad-preserving' (default) and 'integral-preserving', for N-forms -% periodic_directions: Cartesian directions in which the space should be made periodic +% periodic_dir: Cartesian directions in which the space should be made periodic % % % OUTPUT: @@ -75,19 +75,19 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_directions) +function sp = sp_scalar (knots, degree, weights, msh, transform, periodic_dir) if (nargin < 1) sp = struct ('space_type', [], 'knots', [], 'degree', [], 'weights', [], 'sp_univ', [], ... - 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', [], 'ncomp', [], 'boundary', [], ... - 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_directions', [], ... + 'nsh_dir', 0, 'nsh_max', 0, 'ndof_dir', 0, 'ndof', 0, 'ncomp', 0, 'boundary', [], ... + 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_dir', [], ... 'constructor', @(MSH) sp_scalar()); sp = class (sp, 'sp_scalar'); return end if (nargin < 6) - periodic_directions = []; + periodic_dir = []; end if (nargin == 4) transform = 'grad-preserving'; @@ -116,7 +116,7 @@ for idim = 1:msh.ndim sp.sp_univ(idim) = sp_bspline_1d_param (knots{idim}, degree(idim), nodes{idim},... 'gradient', true, 'hessian', true,... - 'periodic',ismember(idim,periodic_directions)); + 'periodic',ismember(idim,periodic_dir)); end sp.nsh_dir = [sp.sp_univ.nsh_max]; @@ -138,7 +138,7 @@ ind2 = ceil (iside/2); ind = setdiff (1:msh.ndim, ind2); - if (~ismember(ind2,periodic_directions)) + if (~ismember(ind2,periodic_dir)) if (~isempty (msh.boundary)) if (strcmpi (sp.space_type, 'spline')) weights = []; @@ -152,8 +152,9 @@ weights = squeeze (sp.weights(indices{:})); end - [~,bnd_periodic_dir] = ismember(periodic_directions,ind); + [~,bnd_periodic_dir] = ismember(periodic_dir,ind); bnd_periodic_dir = nonzeros(bnd_periodic_dir); + sp.boundary(iside) = sp_scalar (sp.knots(ind), sp.degree(ind), weights, msh.boundary(iside),... 'grad-preserving',bnd_periodic_dir); end @@ -183,7 +184,7 @@ end end - elseif (msh.ndim == 1 && numel(periodic_directions) == 0 ) + elseif (msh.ndim == 1 && numel(periodic_dir) == 0 ) sp.boundary(1).dofs = 1; sp.boundary(2).dofs = sp.ndof; if (sp.ndof > 1) @@ -202,10 +203,10 @@ sp.transform = transform; - sp.periodic_directions = periodic_directions; + sp.periodic_dir = periodic_dir; sp.constructor = @(MSH) sp_scalar (sp.knots, sp.degree, sp.weights, MSH, sp.transform,... - sp.periodic_directions); + sp.periodic_dir); sp = class (sp, 'sp_scalar'); end diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 39f5c611..99bbf2d8 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -85,9 +85,9 @@ c = numbasisfun (s, nodes(:, iel)', p, knots); c = unique(c(:))+1; connectivity(1:numel(c), iel) = c; - % nsh(iel) = nnz (connectivity(:,iel)); % faster outside loop? + % nsh(iel) = nnz (connectivity(:,iel)); % faster outside of loop? end -nsh = sum(connectivity ~= 0,1); % faster outside loop? +nsh = sum(connectivity ~= 0,1); % faster outside of loop? nsh_max = max (nsh); @@ -117,12 +117,6 @@ connectivity(filter) = 0; nsh = sum(connectivity ~= 0,1); -% nsh = repmat(nsh_max,1,size(connectivity,2)); - -% % % for k = 1:n_extra_dofs -% % % supp{n_extra_dofs-k+1} = [supp{end}; supp{n_extra_dofs-k+1}]; -% % % supp(end) = []; % deletes cell-array element! -% % % end end supp = cell (ndof, 1); From 1a06700058ff4328f149a06ec952c2b47d6075e6 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Thu, 16 Jul 2020 16:02:35 +0200 Subject: [PATCH 179/366] Fixed case when sp_scalar(void) constructor has to be called --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index f0a2bee0..9e2a13e9 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -180,7 +180,16 @@ end else - sp.boundary(iside) = sp_scalar(); + if (~isempty (msh.boundary)) + sp.boundary(iside) = sp_scalar(); + else % define relevant struct fields to zero + sp.boundary(iside).nsh_dir = 0; + sp.boundary(iside).nsh_max = 0; + sp.boundary(iside).ndof_dir = 0; + sp.boundary(iside).ndof = 0; + sp.boundary(iside).ncomp = 0; + end + end end From f24ee48135ae97cc18403dd6ee33fb9f0390d1b5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 16 Jul 2020 16:48:52 +0200 Subject: [PATCH 180/366] e knots to determine first and last point. Fixed bug for non-open knot vector. --- geopdes/inst/space/@sp_scalar/sp_plot_solution.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_plot_solution.m b/geopdes/inst/space/@sp_scalar/sp_plot_solution.m index 9a306376..f76136bf 100644 --- a/geopdes/inst/space/@sp_scalar/sp_plot_solution.m +++ b/geopdes/inst/space/@sp_scalar/sp_plot_solution.m @@ -54,9 +54,10 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) end end +degree = space.degree; if (~exist ('vtk_pts', 'var')) for idim = 1:ndim - vtk_pts{idim} = linspace (space.knots{idim}(1), space.knots{idim}(end), npts(idim)); + vtk_pts{idim} = linspace (space.knots{idim}(1+degree(idim)), space.knots{idim}(end-degree(idim)), npts(idim)); end end @@ -84,7 +85,7 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) for idim = 1:ndim plot_pts = vtk_pts; - plot_pts{idim} = linspace(space.knots{idim}(1), space.knots{idim}(end), ncuts(idim)+2); + plot_pts{idim} = linspace(space.knots{idim}(1+degree(idim)), space.knots{idim}(end-degree(idim)), ncuts(idim)+2); [eu, F] = sp_eval (u, space, geometry, plot_pts); indices = {1:npts(1), 1:npts(2), 1:npts(3)}; From 595220d28756bde1738eedfdca08f8713973c987 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 21 Jul 2020 15:57:02 +0200 Subject: [PATCH 181/366] Modified src solution to maxwell problem to accommodate periodic spaces tests --- geopdes/inst/solve/solve_maxwell_src.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 6919587c..4c33fca7 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -56,6 +56,8 @@ function [geometry, msh, space, u] = ... solve_maxwell_src (problem_data, method_data) +periodic_directions = []; + % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); for iopt = 1:numel (data_names) @@ -80,7 +82,8 @@ % Construct space structure scalar_spaces = cell (msh.ndim, 1); for idim = 1:msh.ndim - scalar_spaces{idim} = sp_bspline (knots_hcurl{idim}, degree_hcurl{idim}, msh); + scalar_spaces{idim} = sp_bspline (knots_hcurl{idim}, degree_hcurl{idim}, msh,... + 'grad-preserving',periodic_directions); end space = sp_vector (scalar_spaces, msh, 'curl-preserving'); clear scalar_spaces From 5c03ad72e98ffc50f7fb46f48d82d808314725d7 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Wed, 29 Jul 2020 18:02:21 +0200 Subject: [PATCH 182/366] Enumeration of bnd dofs is not consistent with periodic domains --- .../maxwell/ex_maxwell_src_periodic_square.m | 113 ++++++++++++++++++ geopdes/inst/solve/solve_maxwell_src.m | 9 +- geopdes/inst/space/@sp_scalar/sp_scalar.m | 21 ++-- geopdes/inst/space/@sp_vector/sp_vector.m | 113 +++++++++++++++--- 4 files changed, 230 insertions(+), 26 deletions(-) create mode 100644 geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m new file mode 100644 index 00000000..2fef039d --- /dev/null +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -0,0 +1,113 @@ +% EX_MAXWELL_SRC_PERIODIC_SQUARE: solve Maxwell source problem in the unit square. + +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +problem_data.geo_name = 'geo_square.txt'; + +% Type of boundary conditions +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [3 4]; +problem_data.periodic_sides = [1 2]; + +% Physical parameters +problem_data.c_stiff = @(x, y) ones(size(x)); +problem_data.c_mass = @(x, y) pi^2 * ones(size(x)); + +% Source and boundary terms +problem_data.f = @(x, y) cat(1, zeros (1, size (x, 1), size (x, 2)), ... + reshape (5*pi^2*sin(2*pi*x), [1, size(x)])); +problem_data.g = @(x, y, ind) zeros (2, size (x, 1), size (x, 2)); +problem_data.h = @(x, y, ind) zeros (2, size (x, 1), size (x, 2)); + +% Exact solution (optional) +problem_data.uex = @(x, y) cat(1, zeros (1, size (x, 1), size (x, 2)), ... + reshape ( sin(2*pi*x), [1, size(x)])); +problem_data.curluex = @(x, y) 2*pi*cos(2*pi*x); + +% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +method_data.degree = [3 3]; % Degree of the bsplines +method_data.regularity = [2 2]; % Regularity of the splines +method_data.nsub = [16 16]; % Number of subdivisions +method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule + +% 3) CALL TO THE SOLVER +[geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data); + +% % % % 4) POST-PROCESSING +% % % vtk_pts = {linspace(0, 1, 30), linspace(0, 1, 30)}; +% % % % 4.1) EXPORT TO PARAVIEW +% % % output_file = 'maxwell_square_Deg3_Reg2_Sub8'; +% % % fprintf ('The result is saved in the file %s \n \n', output_file); +% % % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') + +% 4.2) Plot in Matlab. Comparison with the exact solution +% % % [eu, F] = sp_eval (u, space, geometry, vtk_pts); +% % % [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +% % % eu2 = problem_data.uex (X, Y); +% % % +% % % subplot(1,2,1) +% % % quiver (X, Y, squeeze(eu(1,:,:)), squeeze(eu(2,:,:))) +% % % axis equal tight +% % % title('Computed solution') +% % % ylim([0,1]); +% % % subplot(1,2,2) +% % % quiver (X, Y, squeeze(eu2(1,:,:)), squeeze(eu2(2,:,:))) +% % % axis equal tight +% % % title('Exact solution') +% % % ylim([0,1]); + + +y_pt = 0.75; +vtk_pts = {linspace(0,1,30),y_pt}; +[eu, F] = sp_eval (u, space, geometry, vtk_pts); +[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +eu2 = problem_data.uex (X, Y); + +eu = squeeze(eu(2,:,:)); %eu = eu(:,1); +eu2 = squeeze(eu2(2,:,:)); %eu2 = eu2(:,1); + +subplot(1,2,1) +plot (X, eu); +grid on; +title('Computed solution') + +subplot(1,2,2) +plot (X, eu2) +grid on; +title('Exact solution') + +[error_hcurl, error_l2] = ... + sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex) + +%!demo +%! ex_maxwell_src_square + +%!test +%! problem_data.geo_name = 'geo_square.txt'; +%! problem_data.nmnn_sides = [2 3]; +%! problem_data.drchlt_sides = [1 4]; +%! problem_data.c_stiff = @(x, y) ones(size(x)); +%! problem_data.c_mass = @(x, y) ones(size(x)); +%! problem_data.f = @(x, y) cat(1, ... +%! reshape (-exp(x) .* sin(y) + 2*sin(y), [1, size(x)]), ... +%! zeros ([1, size(x)])); +%! problem_data.g = @(x, y, ind) test_maxwell_square_g_nmnn (x, y, ind); +%! problem_data.h = @(x, y, ind) cat(1, ... +%! reshape (sin(y), [1, size(x)]), ... +%! reshape (exp(x) .* cos(y), [1, size(x)])); +%! problem_data.uex = @(x, y) cat(1, ... +%! reshape (sin(y), [1, size(x)]), ... +%! reshape (exp(x) .* cos(y), [1, size(x)])); +%! problem_data.curluex = @(x, y) exp(x).*cos(y) - cos(y); +%! method_data.degree = [3 3]; % Degree of the bsplines +%! method_data.regularity = [2 2]; % Regularity of the splines +%! method_data.nsub = [8 8]; % Number of subdivisions +%! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule +%! [geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data); +%! [error_hcurl, error_l2] = sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex); +%! assert (msh.nel, 64) +%! assert (space.ndof, 220) +%! assert (error_l2, 9.90499820528337e-06, 1e-16) +%! assert (error_hcurl, 1.94621849955079e-05, 1e-16) \ No newline at end of file diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 4c33fca7..5cc0a5a2 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -56,7 +56,7 @@ function [geometry, msh, space, u] = ... solve_maxwell_src (problem_data, method_data) -periodic_directions = []; +periodic_sides = []; % a bit hacky... % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); @@ -68,6 +68,13 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end +% check for periodic directions +if ~isempty(periodic_sides) + periodic_directions = unique(ceil(periodic_sides./2)); +else + periodic_directions = []; +end + % Construct geometry structure geometry = geo_load (geo_name); diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 9e2a13e9..3ddf3b7f 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -79,9 +79,9 @@ if (nargin < 1) sp = struct ('space_type', [], 'knots', [], 'degree', [], 'weights', [], 'sp_univ', [], ... - 'nsh_dir', 0, 'nsh_max', 0, 'ndof_dir', 0, 'ndof', 0, 'ncomp', 0, 'boundary', [], ... - 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_dir', [], ... - 'constructor', @(MSH) sp_scalar()); + 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', [], 'ncomp', [], ... + 'boundary', [], 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_dir', [], ... + 'constructor', @(MSH) sp_scalar()); sp = class (sp, 'sp_scalar'); return end @@ -182,12 +182,17 @@ else if (~isempty (msh.boundary)) sp.boundary(iside) = sp_scalar(); - else % define relevant struct fields to zero - sp.boundary(iside).nsh_dir = 0; - sp.boundary(iside).nsh_max = 0; - sp.boundary(iside).ndof_dir = 0; + else % define relevant struct fields +% sp.boundary(iside).nsh_dir = 0; +% sp.boundary(iside).nsh_max = 0; +% sp.boundary(iside).ndof_dir = 0; +% sp.boundary(iside).ndof = 0; +% sp.boundary(iside).ncomp = 0; + sp.boundary(iside).nsh_dir = []; + sp.boundary(iside).nsh_max = []; + sp.boundary(iside).ndof_dir = []; sp.boundary(iside).ndof = 0; - sp.boundary(iside).ncomp = 0; + sp.boundary(iside).ncomp = []; end end diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 377bb4c3..9bea5e37 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -68,15 +68,43 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_vector (scalar_spaces, msh, transform) - +function sp = sp_vector (scalar_spaces, msh, transform)%, periodic_dir) + + if (nargin < 1) + sp = struct ('ncomp', [], 'ncomp_param', [], 'scalar_spaces', [],... + 'nsh_max', [], 'ndof', [], 'ndof_dir', [], ... + 'cumsum_ndof', [], 'cumsum_nsh', [], ... %'periodic_dir',[],... + 'comp_dofs', [], 'boundary', [], 'dofs', [], ... + 'transform', [], 'constructor', @(MSH) sp_vector()); + sp = class (sp, 'sp_vector'); + return + + else + comps = 1:numel(scalar_spaces); + for icomp = comps + if isempty(scalar_spaces{icomp}.ndof) || (scalar_spaces{icomp}.ndof == 0) + sp = struct ('ncomp', [], 'ncomp_param', [], 'scalar_spaces', [],... + 'nsh_max', [], 'ndof', [], 'ndof_dir', [], ... + 'cumsum_ndof', [], 'cumsum_nsh', [], ... %'periodic_dir',[],... + 'comp_dofs', [], 'boundary', [], 'dofs', [], ... + 'transform', [], 'constructor', @(MSH) sp_vector()); + sp = class (sp, 'sp_vector'); + return + end + end + end + +% % % if (nargin < 4) +% % % periodic_dir = []; +% % % end + if (nargin == 2) transform = 'grad-preserving'; end sp.ncomp = msh.rdim; sp.ncomp_param = numel (scalar_spaces); - + switch (transform) case {'grad-preserving'} if (sp.ncomp ~= sp.ncomp_param) @@ -109,30 +137,74 @@ % Boundary construction if (msh.ndim > 1) for iside = 1:2*msh.ndim + + %% handling periodic vector spaces? +% % % dir = ceil(iside/2); +% % % if (~ismember(dir,periodic_dir)) + %% + for icomp = 1:sp.ncomp_param scalar_bnd{icomp} = scalar_spaces{icomp}.boundary(iside); end - + if (strcmpi (transform, 'grad-preserving')) ind = 1:sp.ncomp; + if (~isempty (msh.boundary)) - sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); + + periodic_bnd = false; + for ii = ind + if (isempty(scalar_bnd{ii}.ndof) || scalar_bnd{ii}.ndof == 0) + periodic_bnd = true; + break; + end + end + + if periodic_bnd == true + sp.boundary(iside) = sp_vector(); + continue; + else + sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); + end + end elseif (strcmpi (transform, 'curl-preserving')) % Only tangential components are computed ind = setdiff (1:msh.ndim, ceil(iside/2)); % ind =[2 3; 2 3; 1 3; 1 3; 1 2; 1 2] in 3D, %ind = [2 2 1 1] in 2D; if (~isempty (msh.boundary)) - sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); + periodic_bnd = false; + for ii = ind + if (isempty(scalar_bnd{ii}.ndof) || scalar_bnd{ii}.ndof == 0) + periodic_bnd = true; + break; + end + end + + if periodic_bnd == true + sp.boundary(iside) = sp_vector(); + continue; + else + sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); + end end elseif (strcmpi (transform, 'div-preserving')) % Only normal components are computed, and treated as a scalar ind = ceil (iside/2); % ind =[1, 1, 2, 2, 3, 3] in 3D, %ind = [1, 1, 2, 2] in 2D; if (~isempty (msh.boundary)) sp_bnd = scalar_bnd{ind}; - if (iside == 1) % This fixes a bug with the use of subsasgn/subsref - sp.boundary = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); + if (isempty(sp_bnd.ndof) || sp_bnd.ndof == 0) + if (iside == 1) + sp.boundary = sp_scalar(); + else + sp.boundary(iside) = sp_scalar(); + end + continue; else - sp.boundary(iside) = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); + if (iside == 1) % This fixes a bug with the use of subsasgn/subsref + sp.boundary = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); + else + sp.boundary(iside) = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); + end end end @@ -142,18 +214,18 @@ dofs = []; bnd_cumsum_ndof(1) = 0; - bnd_cumsum_ndof(2:numel(ind)+1) = cumsum (cellfun (@(x) x.ndof, scalar_bnd(ind))); + bnd_cumsum_ndof(2:numel(ind)+1) = cumsum (cellfun (@(x) x.ndof, scalar_bnd(ind)));%,'UniformOutput',0)); for icomp = 1:numel(ind) new_dofs = sp.cumsum_ndof(ind(icomp)) + scalar_bnd{ind(icomp)}.dofs; dofs = union (dofs, new_dofs); comp_dofs{icomp} = bnd_cumsum_ndof(icomp) + (1:scalar_bnd{ind(icomp)}.ndof); end - + sp.boundary(iside).dofs = dofs(:)'; if (~strcmpi (transform, 'div-preserving') && isstruct (sp.boundary)) sp.boundary(iside).comp_dofs = comp_dofs; end - + if (isempty (msh.boundary)) sp.boundary(iside).ndof = numel (sp.boundary(iside).dofs); if (strcmpi (transform, 'curl-preserving')) % Needed for the interfaces on the boundary, in sp_multipatch @@ -163,10 +235,17 @@ sp.boundary(iside).ndof_dir = ndof_dir; end end + + %% handling periodic vector spaces +% % % else +% % % +% % % end + %% + end elseif (msh.ndim == 1) - if (strcmpi (transform, 'grad-preserving')) + if (strcmpi (transform, 'grad-preserving') && isempty(scalar_spaces{1}.periodic_dir)) sp.boundary(1).dofs = sp.cumsum_ndof(1:end-1)+1; sp.boundary(2).dofs = sp.cumsum_ndof(2:end); @@ -179,20 +258,20 @@ sp.boundary = []; end - sp.dofs = []; + sp.dofs = []; % is this correct? What about boundary vector spaces? sp.transform = transform; if (sp.ncomp_param == 2) sp.constructor = @(MSH) sp_vector ({scalar_spaces{1}.constructor(MSH), ... - scalar_spaces{2}.constructor(MSH)}, MSH, transform); + scalar_spaces{2}.constructor(MSH)}, MSH, transform);%,periodic_dir); elseif (sp.ncomp_param == 3) sp.constructor = @(MSH) sp_vector ({scalar_spaces{1}.constructor(MSH), ... scalar_spaces{2}.constructor(MSH), ... - scalar_spaces{3}.constructor(MSH)}, MSH, transform); + scalar_spaces{3}.constructor(MSH)}, MSH, transform);%,periodic_dir); elseif (sp.ncomp_param == 1) sp.constructor = @(MSH) sp_vector ... - ({scalar_spaces{1}.constructor(MSH)}, MSH, transform); + ({scalar_spaces{1}.constructor(MSH)}, MSH, transform);%,periodic_dir); end sp = class (sp, 'sp_vector'); From 93e800e8bc526f34a70240f88da70b41215e296e Mon Sep 17 00:00:00 2001 From: bkapidani Date: Wed, 29 Jul 2020 18:52:55 +0200 Subject: [PATCH 183/366] sp_eval needs dofs field in dummy sp.boundary structs --- .../maxwell/ex_maxwell_src_periodic_square.m | 101 ++++++------------ geopdes/inst/space/@sp_scalar/sp_scalar.m | 17 +-- 2 files changed, 46 insertions(+), 72 deletions(-) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m index 2fef039d..7782f534 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -16,14 +16,14 @@ % Source and boundary terms problem_data.f = @(x, y) cat(1, zeros (1, size (x, 1), size (x, 2)), ... - reshape (5*pi^2*sin(2*pi*x), [1, size(x)])); + reshape (17*pi^2*sin(4*pi*x), [1, size(x)])); problem_data.g = @(x, y, ind) zeros (2, size (x, 1), size (x, 2)); problem_data.h = @(x, y, ind) zeros (2, size (x, 1), size (x, 2)); % Exact solution (optional) problem_data.uex = @(x, y) cat(1, zeros (1, size (x, 1), size (x, 2)), ... - reshape ( sin(2*pi*x), [1, size(x)])); -problem_data.curluex = @(x, y) 2*pi*cos(2*pi*x); + reshape ( sin(4*pi*x), [1, size(x)])); +problem_data.curluex = @(x, y) 4*pi*cos(4*pi*x); % 2) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data @@ -35,79 +35,48 @@ % 3) CALL TO THE SOLVER [geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data); -% % % % 4) POST-PROCESSING -% % % vtk_pts = {linspace(0, 1, 30), linspace(0, 1, 30)}; -% % % % 4.1) EXPORT TO PARAVIEW -% % % output_file = 'maxwell_square_Deg3_Reg2_Sub8'; -% % % fprintf ('The result is saved in the file %s \n \n', output_file); -% % % sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') +% 4) POST-PROCESSING +vtk_pts = {linspace(0, 1, 30), linspace(0, 1, 30)}; +% 4.1) EXPORT TO PARAVIEW +output_file = 'maxwell_square_Deg3_Reg2_Sub8'; +fprintf ('The result is saved in the file %s \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') % 4.2) Plot in Matlab. Comparison with the exact solution -% % % [eu, F] = sp_eval (u, space, geometry, vtk_pts); -% % % [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); -% % % eu2 = problem_data.uex (X, Y); -% % % -% % % subplot(1,2,1) -% % % quiver (X, Y, squeeze(eu(1,:,:)), squeeze(eu(2,:,:))) -% % % axis equal tight -% % % title('Computed solution') -% % % ylim([0,1]); -% % % subplot(1,2,2) -% % % quiver (X, Y, squeeze(eu2(1,:,:)), squeeze(eu2(2,:,:))) -% % % axis equal tight -% % % title('Exact solution') -% % % ylim([0,1]); - - -y_pt = 0.75; -vtk_pts = {linspace(0,1,30),y_pt}; [eu, F] = sp_eval (u, space, geometry, vtk_pts); [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); eu2 = problem_data.uex (X, Y); -eu = squeeze(eu(2,:,:)); %eu = eu(:,1); -eu2 = squeeze(eu2(2,:,:)); %eu2 = eu2(:,1); - subplot(1,2,1) -plot (X, eu); -grid on; +quiver (X, Y, squeeze(eu(1,:,:)), squeeze(eu(2,:,:))) +axis equal tight title('Computed solution') - +ylim([0,1]); xlim([0,1]); subplot(1,2,2) -plot (X, eu2) -grid on; +quiver (X, Y, squeeze(eu2(1,:,:)), squeeze(eu2(2,:,:))) +axis equal tight title('Exact solution') +ylim([0,1]); xlim([0,1]); -[error_hcurl, error_l2] = ... - sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex) -%!demo -%! ex_maxwell_src_square +% % % y_pt = 0.5; +% % % vtk_pts = {linspace(0,1,60),y_pt}; +% % % [eu, F] = sp_eval (u, space, geometry, vtk_pts); +% % % [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +% % % eu2 = problem_data.uex (X, Y); +% % % +% % % eu = squeeze(eu(2,:,:)); %eu = eu(:,1); +% % % eu2 = squeeze(eu2(2,:,:)); %eu2 = eu2(:,1); +% % % +% % % subplot(1,2,1) +% % % plot (X, eu); +% % % grid on; +% % % title('Computed solution') +% % % +% % % subplot(1,2,2) +% % % plot (X, eu2) +% % % grid on; +% % % title('Exact solution') -%!test -%! problem_data.geo_name = 'geo_square.txt'; -%! problem_data.nmnn_sides = [2 3]; -%! problem_data.drchlt_sides = [1 4]; -%! problem_data.c_stiff = @(x, y) ones(size(x)); -%! problem_data.c_mass = @(x, y) ones(size(x)); -%! problem_data.f = @(x, y) cat(1, ... -%! reshape (-exp(x) .* sin(y) + 2*sin(y), [1, size(x)]), ... -%! zeros ([1, size(x)])); -%! problem_data.g = @(x, y, ind) test_maxwell_square_g_nmnn (x, y, ind); -%! problem_data.h = @(x, y, ind) cat(1, ... -%! reshape (sin(y), [1, size(x)]), ... -%! reshape (exp(x) .* cos(y), [1, size(x)])); -%! problem_data.uex = @(x, y) cat(1, ... -%! reshape (sin(y), [1, size(x)]), ... -%! reshape (exp(x) .* cos(y), [1, size(x)])); -%! problem_data.curluex = @(x, y) exp(x).*cos(y) - cos(y); -%! method_data.degree = [3 3]; % Degree of the bsplines -%! method_data.regularity = [2 2]; % Regularity of the splines -%! method_data.nsub = [8 8]; % Number of subdivisions -%! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule -%! [geometry, msh, space, u] = solve_maxwell_src (problem_data, method_data); -%! [error_hcurl, error_l2] = sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex); -%! assert (msh.nel, 64) -%! assert (space.ndof, 220) -%! assert (error_l2, 9.90499820528337e-06, 1e-16) -%! assert (error_hcurl, 1.94621849955079e-05, 1e-16) \ No newline at end of file +[error_hcurl, error_l2] = ... + sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 3ddf3b7f..4ad323da 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -183,16 +183,21 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_scalar(); else % define relevant struct fields -% sp.boundary(iside).nsh_dir = 0; -% sp.boundary(iside).nsh_max = 0; -% sp.boundary(iside).ndof_dir = 0; -% sp.boundary(iside).ndof = 0; -% sp.boundary(iside).ncomp = 0; + sp.boundary(iside).ndof = 0; + sp.boundary(iside).space_type = []; + sp.boundary(iside).weights = []; + sp.boundary(iside).knots = []; + sp.boundary(iside).degree = []; + sp.boundary(iside).sp_univ = []; sp.boundary(iside).nsh_dir = []; sp.boundary(iside).nsh_max = []; sp.boundary(iside).ndof_dir = []; - sp.boundary(iside).ndof = 0; sp.boundary(iside).ncomp = []; + sp.boundary(iside).dofs = []; + sp.boundary(iside).boundary = []; + sp.boundary(iside).adjacent_dofs = []; + sp.boundary(iside).transform = []; + sp.boundary(iside).periodic_dir = []; end end From d59f15bac7613c71b1cc592d3d96018aa9ed6a75 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Thu, 30 Jul 2020 11:36:23 +0200 Subject: [PATCH 184/366] solve scripts require optional unclamping in case of periodic spaces, added in maxwell and laplace --- .../maxwell/ex_maxwell_src_periodic_square.m | 6 +++--- geopdes/inst/solve/solve_laplace.m | 13 +++++++++++++ geopdes/inst/solve/solve_maxwell_src.m | 5 +++++ geopdes/inst/space/@sp_scalar/sp_scalar.m | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m index 7782f534..f2722a58 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -7,8 +7,8 @@ % Type of boundary conditions problem_data.nmnn_sides = []; -problem_data.drchlt_sides = [3 4]; -problem_data.periodic_sides = [1 2]; +problem_data.drchlt_sides = []; +problem_data.periodic_sides = [1 2 3 4]; % Physical parameters problem_data.c_stiff = @(x, y) ones(size(x)); @@ -29,7 +29,7 @@ clear method_data method_data.degree = [3 3]; % Degree of the bsplines method_data.regularity = [2 2]; % Regularity of the splines -method_data.nsub = [16 16]; % Number of subdivisions +method_data.nsub = [16 16]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule % 3) CALL TO THE SOLVER diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 87844923..55caf7a0 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -56,6 +56,8 @@ function [geometry, msh, space, u] = ... solve_laplace (problem_data, method_data) +periodic_sides = []; + % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); for iopt = 1:numel (data_names) @@ -66,11 +68,22 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end +% check for periodic directions +if ~isempty(periodic_sides) + periodic_directions = unique(ceil(periodic_sides./2)); +else + periodic_directions = []; +end + % Construct geometry structure geometry = geo_load (geo_name); [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); +if ~isempty(periodic_directions) + knots = kntunclamp(knots, degree, regularity, periodic_directions); +end + % Construct msh structure rule = msh_gauss_nodes (nquad); [qn, qw] = msh_set_quad_nodes (zeta, rule); diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 5cc0a5a2..d448defe 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -79,6 +79,11 @@ geometry = geo_load (geo_name); [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); + +if ~isempty(periodic_directions) + knots = kntunclamp(knots, degree, regularity, periodic_directions); +end + [knots_hcurl, degree_hcurl] = knt_derham (knots, degree, 'Hcurl'); % Construct msh structure diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 4ad323da..d81cf35d 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -203,7 +203,7 @@ end end - elseif (msh.ndim == 1 && numel(periodic_dir) == 0 ) + elseif (msh.ndim == 1 && isempty(periodic_dir) ) sp.boundary(1).dofs = 1; sp.boundary(2).dofs = sp.ndof; if (sp.ndof > 1) From c60055c521f135f7781dbbacb930437f8809d65a Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 11 Aug 2020 10:27:07 +0200 Subject: [PATCH 185/366] Return same type of variable --- geopdes/inst/utils/kntunclamp.m | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/utils/kntunclamp.m b/geopdes/inst/utils/kntunclamp.m index 10ee3d1c..3ddbc164 100644 --- a/geopdes/inst/utils/kntunclamp.m +++ b/geopdes/inst/utils/kntunclamp.m @@ -11,7 +11,7 @@ % knt : open knot vector: see kntrefine % deg : polynomial degree of the spline space % k : continuity for the unclamping (from 0 up to p-1) -% dim : dimension in which to unclamp (all by default). +% dim : dimensions in which to unclamp (all by default). % % OUTPUT: % @@ -38,8 +38,10 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . + knt_is_cell = true; if (~iscell (knt)) knt = {knt}; + knt_is_cell = false; end uknt = knt; @@ -83,6 +85,10 @@ end + if (~knt_is_cell) + uknt = uknt{1}; + end + end From 1b3d1a96c60199f16cb473d46e5b8b30b4675f26 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 11 Aug 2020 10:37:48 +0200 Subject: [PATCH 186/366] Periodic conditions --- geopdes/inst/solve/solve_laplace.m | 17 ++++++----------- geopdes/inst/space/sp_bspline.m | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 55caf7a0..9513f208 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -56,8 +56,6 @@ function [geometry, msh, space, u] = ... solve_laplace (problem_data, method_data) -periodic_sides = []; - % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); for iopt = 1:numel (data_names) @@ -68,20 +66,17 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end -% check for periodic directions -if ~isempty(periodic_sides) - periodic_directions = unique(ceil(periodic_sides./2)); -else - periodic_directions = []; -end - % Construct geometry structure geometry = geo_load (geo_name); [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); -if ~isempty(periodic_directions) +% check for periodic directions +if (exist('periodic_sides', 'var')) + periodic_directions = unique(ceil(periodic_sides./2)); knots = kntunclamp(knots, degree, regularity, periodic_directions); +else + periodic_directions = []; end % Construct msh structure @@ -90,7 +85,7 @@ msh = msh_cartesian (zeta, qn, qw, geometry); % Construct space structure -space = sp_bspline (knots, degree, msh); +space = sp_bspline (knots, degree, msh, [], periodic_directions); % Assemble the matrices stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); diff --git a/geopdes/inst/space/sp_bspline.m b/geopdes/inst/space/sp_bspline.m index 197bcf9b..cfda2b9e 100644 --- a/geopdes/inst/space/sp_bspline.m +++ b/geopdes/inst/space/sp_bspline.m @@ -41,7 +41,7 @@ periodic_directions = sort(periodic_directions); end - if (nargin == 3) + if (nargin == 3 || isempty (transform)) transform = 'grad-preserving'; end From ffb19ea2e9c9e99dbcc9f6c299ac0484cd1940ca Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 11 Aug 2020 11:35:05 +0200 Subject: [PATCH 187/366] Added legacy option, for empty vectors --- geopdes/inst/solve/solve_laplace.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 9513f208..d98bee34 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -73,7 +73,7 @@ % check for periodic directions if (exist('periodic_sides', 'var')) - periodic_directions = unique(ceil(periodic_sides./2)); + periodic_directions = unique(ceil(periodic_sides./2), 'legacy'); knots = kntunclamp(knots, degree, regularity, periodic_directions); else periodic_directions = []; From a89deda3bccc3cbe39af7f39101914369254c59b Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 11 Aug 2020 14:38:11 +0200 Subject: [PATCH 188/366] Removed unused fields --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index d81cf35d..2eec3d75 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -79,7 +79,7 @@ if (nargin < 1) sp = struct ('space_type', [], 'knots', [], 'degree', [], 'weights', [], 'sp_univ', [], ... - 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', [], 'ncomp', [], ... + 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', 0, 'ncomp', [], ... 'boundary', [], 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_dir', [], ... 'constructor', @(MSH) sp_scalar()); sp = class (sp, 'sp_scalar'); @@ -183,21 +183,9 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_scalar(); else % define relevant struct fields - sp.boundary(iside).ndof = 0; - sp.boundary(iside).space_type = []; - sp.boundary(iside).weights = []; - sp.boundary(iside).knots = []; - sp.boundary(iside).degree = []; - sp.boundary(iside).sp_univ = []; - sp.boundary(iside).nsh_dir = []; - sp.boundary(iside).nsh_max = []; - sp.boundary(iside).ndof_dir = []; - sp.boundary(iside).ncomp = []; + sp.boundary(iside).ndof = []; sp.boundary(iside).dofs = []; - sp.boundary(iside).boundary = []; sp.boundary(iside).adjacent_dofs = []; - sp.boundary(iside).transform = []; - sp.boundary(iside).periodic_dir = []; end end From 42b0e10026a17f893e36347e81bd6108d64ac696 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 11 Aug 2020 15:32:06 +0200 Subject: [PATCH 189/366] Removed all periodicity checks based on ndof variable --- geopdes/inst/space/@sp_vector/sp_vector.m | 109 +++++++++------------- 1 file changed, 43 insertions(+), 66 deletions(-) diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 9bea5e37..03d5815c 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -68,36 +68,18 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp = sp_vector (scalar_spaces, msh, transform)%, periodic_dir) +function sp = sp_vector (scalar_spaces, msh, transform) if (nargin < 1) sp = struct ('ncomp', [], 'ncomp_param', [], 'scalar_spaces', [],... 'nsh_max', [], 'ndof', [], 'ndof_dir', [], ... - 'cumsum_ndof', [], 'cumsum_nsh', [], ... %'periodic_dir',[],... + 'cumsum_ndof', [], 'cumsum_nsh', [], ... % 'periodic_dir',[],... 'comp_dofs', [], 'boundary', [], 'dofs', [], ... 'transform', [], 'constructor', @(MSH) sp_vector()); sp = class (sp, 'sp_vector'); return - - else - comps = 1:numel(scalar_spaces); - for icomp = comps - if isempty(scalar_spaces{icomp}.ndof) || (scalar_spaces{icomp}.ndof == 0) - sp = struct ('ncomp', [], 'ncomp_param', [], 'scalar_spaces', [],... - 'nsh_max', [], 'ndof', [], 'ndof_dir', [], ... - 'cumsum_ndof', [], 'cumsum_nsh', [], ... %'periodic_dir',[],... - 'comp_dofs', [], 'boundary', [], 'dofs', [], ... - 'transform', [], 'constructor', @(MSH) sp_vector()); - sp = class (sp, 'sp_vector'); - return - end - end end -% % % if (nargin < 4) -% % % periodic_dir = []; -% % % end - if (nargin == 2) transform = 'grad-preserving'; end @@ -115,7 +97,14 @@ error ('sp_vector: the dimensions of the space and the mesh do not match') end end - + + periodic_dir = scalar_spaces{1}.periodic_dir; + for icomp = 2:1:sp.ncomp_param + if scalar_spaces{icomp}.periodic_dir ~= periodic_dir + error ('sp_vector: the periodic Cartesian directions should match for all vector components') + end + end + sp.scalar_spaces = scalar_spaces; sp.nsh_max = sum (cellfun (@(x) x.nsh_max, scalar_spaces)); @@ -138,73 +127,61 @@ if (msh.ndim > 1) for iside = 1:2*msh.ndim - %% handling periodic vector spaces? -% % % dir = ceil(iside/2); -% % % if (~ismember(dir,periodic_dir)) - %% + % handling periodic vector spaces... + dir = ceil(iside/2); + if (ismember(dir,periodic_dir)) + if (strcmpi (transform, 'grad-preserving') || ... + strcmpi (transform, 'curl-preserving') ) + if (~isempty (msh.boundary)) + sp.boundary(iside) = sp_vector(); + else % define relevant struct fields + sp.boundary(iside).ndof = []; + sp.boundary(iside).dofs = []; + sp.boundary(iside).comp_dofs = []; + end + continue; + elseif (strcmpi (transform, 'div-preserving')) + if (~isempty (msh.boundary)) + sp.boundary(iside) = sp_scalar(); + else % define relevant struct fields + sp.boundary(iside).ndof = []; + sp.boundary(iside).dofs = []; + sp.boundary(iside).adjacent_dofs = []; + end + continue; + else + error ('sp_vector: unknown transformation') + end + end for icomp = 1:sp.ncomp_param scalar_bnd{icomp} = scalar_spaces{icomp}.boundary(iside); end if (strcmpi (transform, 'grad-preserving')) + ind = 1:sp.ncomp; - + if (~isempty (msh.boundary)) - - periodic_bnd = false; - for ii = ind - if (isempty(scalar_bnd{ii}.ndof) || scalar_bnd{ii}.ndof == 0) - periodic_bnd = true; - break; - end - end - - if periodic_bnd == true - sp.boundary(iside) = sp_vector(); - continue; - else sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); - end - end elseif (strcmpi (transform, 'curl-preserving')) % Only tangential components are computed + ind = setdiff (1:msh.ndim, ceil(iside/2)); % ind =[2 3; 2 3; 1 3; 1 3; 1 2; 1 2] in 3D, %ind = [2 2 1 1] in 2D; if (~isempty (msh.boundary)) - periodic_bnd = false; - for ii = ind - if (isempty(scalar_bnd{ii}.ndof) || scalar_bnd{ii}.ndof == 0) - periodic_bnd = true; - break; - end - end - - if periodic_bnd == true - sp.boundary(iside) = sp_vector(); - continue; - else sp.boundary(iside) = sp_vector (scalar_bnd(ind), msh.boundary(iside), transform); - end end elseif (strcmpi (transform, 'div-preserving')) % Only normal components are computed, and treated as a scalar + ind = ceil (iside/2); % ind =[1, 1, 2, 2, 3, 3] in 3D, %ind = [1, 1, 2, 2] in 2D; if (~isempty (msh.boundary)) sp_bnd = scalar_bnd{ind}; - if (isempty(sp_bnd.ndof) || sp_bnd.ndof == 0) - if (iside == 1) - sp.boundary = sp_scalar(); - else - sp.boundary(iside) = sp_scalar(); - end - continue; + if (iside == 1) % This fixes a bug with the use of subsasgn/subsref + sp.boundary = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); else - if (iside == 1) % This fixes a bug with the use of subsasgn/subsref - sp.boundary = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); - else - sp.boundary(iside) = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); - end + sp.boundary(iside) = sp_scalar (sp_bnd.knots, sp_bnd.degree, sp_bnd.weights, msh.boundary(iside), 'integral-preserving'); end end From 934305a51077814ab2348e225d668ab59e4925b7 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Tue, 11 Aug 2020 15:59:38 +0200 Subject: [PATCH 190/366] Eliminated ambiguity in periodic direction check --- .../inst/examples/maxwell/ex_maxwell_src_periodic_square.m | 4 ++-- geopdes/inst/space/@sp_vector/sp_vector.m | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m index f2722a58..12d52c1f 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -7,8 +7,8 @@ % Type of boundary conditions problem_data.nmnn_sides = []; -problem_data.drchlt_sides = []; -problem_data.periodic_sides = [1 2 3 4]; +problem_data.drchlt_sides = [3 4]; +problem_data.periodic_sides = [1 2]; % Physical parameters problem_data.c_stiff = @(x, y) ones(size(x)); diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 03d5815c..85c8ff89 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -100,7 +100,8 @@ periodic_dir = scalar_spaces{1}.periodic_dir; for icomp = 2:1:sp.ncomp_param - if scalar_spaces{icomp}.periodic_dir ~= periodic_dir + if ( numel(scalar_spaces{icomp}.periodic_dir) ~= numel(periodic_dir) || ... + scalar_spaces{icomp}.periodic_dir ~= periodic_dir ) error ('sp_vector: the periodic Cartesian directions should match for all vector components') end end @@ -114,7 +115,7 @@ sp.cumsum_ndof(1) = 0; sp.cumsum_ndof(2:sp.ncomp_param+1) = cumsum (cellfun (@(x) x.ndof, scalar_spaces)); sp.cumsum_nsh(1) = 0; - sp.cumsum_nsh(2:sp.ncomp_param+1) = cumsum (cellfun (@(x) x.nsh_max, scalar_spaces)); + sp.cumsum_nsh(2:sp.ncomp_param+1) = cumsum (cellfun (@(x) x.nsh_max, scalar_spaces)); aux = 0; for icomp = 1:sp.ncomp_param From eb2787a485d72babfb36b6ae1dfbccfd74a6306e Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 Aug 2020 14:51:04 +0200 Subject: [PATCH 191/366] Fixed bug for more than one periodic direction --- geopdes/inst/space/@sp_vector/sp_vector.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 85c8ff89..7bb174eb 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -101,7 +101,7 @@ periodic_dir = scalar_spaces{1}.periodic_dir; for icomp = 2:1:sp.ncomp_param if ( numel(scalar_spaces{icomp}.periodic_dir) ~= numel(periodic_dir) || ... - scalar_spaces{icomp}.periodic_dir ~= periodic_dir ) + any (scalar_spaces{icomp}.periodic_dir ~= periodic_dir )) error ('sp_vector: the periodic Cartesian directions should match for all vector components') end end From 2c33ebf5631d5c3bb1d2cf254a55f25de4771d83 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 Aug 2020 15:35:15 +0200 Subject: [PATCH 192/366] Fixed bug for div-conforming, plus some cleaning --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 6 ++---- geopdes/inst/space/@sp_vector/sp_vector.m | 24 +++++++++-------------- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 2eec3d75..d07dae29 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -79,7 +79,7 @@ if (nargin < 1) sp = struct ('space_type', [], 'knots', [], 'degree', [], 'weights', [], 'sp_univ', [], ... - 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', 0, 'ncomp', [], ... + 'nsh_dir', [], 'nsh_max', [], 'ndof_dir', [], 'ndof', [], 'ncomp', [], ... 'boundary', [], 'dofs', [], 'adjacent_dofs', [], 'transform', [], 'periodic_dir', [], ... 'constructor', @(MSH) sp_scalar()); sp = class (sp, 'sp_scalar'); @@ -183,9 +183,7 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_scalar(); else % define relevant struct fields - sp.boundary(iside).ndof = []; - sp.boundary(iside).dofs = []; - sp.boundary(iside).adjacent_dofs = []; + sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'adjacent_dofs', []); end end diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 7bb174eb..31ef5ecc 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -136,18 +136,18 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_vector(); else % define relevant struct fields - sp.boundary(iside).ndof = []; - sp.boundary(iside).dofs = []; - sp.boundary(iside).comp_dofs = []; + sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'comp_dofs', [], 'ndof_dir', []); end continue; elseif (strcmpi (transform, 'div-preserving')) if (~isempty (msh.boundary)) - sp.boundary(iside) = sp_scalar(); + if (iside == 1) % This fixes a bug with the use of subsasgn/subsref + sp.boundary = sp_scalar(); + else + sp.boundary(iside) = sp_scalar(); + end else % define relevant struct fields - sp.boundary(iside).ndof = []; - sp.boundary(iside).dofs = []; - sp.boundary(iside).adjacent_dofs = []; + sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'adjacent_dofs', []); end continue; else @@ -213,13 +213,7 @@ sp.boundary(iside).ndof_dir = ndof_dir; end end - - %% handling periodic vector spaces -% % % else -% % % -% % % end - %% - + end elseif (msh.ndim == 1) @@ -236,7 +230,7 @@ sp.boundary = []; end - sp.dofs = []; % is this correct? What about boundary vector spaces? + sp.dofs = []; sp.transform = transform; From 8fe49f85e0c281666809d280cc60647d5632f6f5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 12 Aug 2020 15:37:03 +0200 Subject: [PATCH 193/366] Some cleaning for periodic conditions --- geopdes/inst/solve/solve_maxwell_src.m | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index d448defe..995a01f6 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -56,8 +56,6 @@ function [geometry, msh, space, u] = ... solve_maxwell_src (problem_data, method_data) -periodic_sides = []; % a bit hacky... - % Extract the fields from the data structures into local variables data_names = fieldnames (problem_data); for iopt = 1:numel (data_names) @@ -68,20 +66,17 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end -% check for periodic directions -if ~isempty(periodic_sides) - periodic_directions = unique(ceil(periodic_sides./2)); -else - periodic_directions = []; -end - % Construct geometry structure geometry = geo_load (geo_name); [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); -if ~isempty(periodic_directions) +% check for periodic directions +if (exist('periodic_sides', 'var')) + periodic_directions = unique(ceil(periodic_sides./2), 'legacy'); knots = kntunclamp(knots, degree, regularity, periodic_directions); +else + periodic_directions = []; end [knots_hcurl, degree_hcurl] = knt_derham (knots, degree, 'Hcurl'); @@ -95,7 +90,7 @@ scalar_spaces = cell (msh.ndim, 1); for idim = 1:msh.ndim scalar_spaces{idim} = sp_bspline (knots_hcurl{idim}, degree_hcurl{idim}, msh,... - 'grad-preserving',periodic_directions); + [], periodic_directions); end space = sp_vector (scalar_spaces, msh, 'curl-preserving'); clear scalar_spaces From 836ad60db5815994bf4d4322cab0764e68a879a9 Mon Sep 17 00:00:00 2001 From: bkapidani Date: Wed, 12 Aug 2020 16:17:30 +0200 Subject: [PATCH 194/366] More compact check for periodi directions --- geopdes/inst/space/@sp_vector/sp_vector.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 31ef5ecc..6b82c027 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -100,8 +100,7 @@ periodic_dir = scalar_spaces{1}.periodic_dir; for icomp = 2:1:sp.ncomp_param - if ( numel(scalar_spaces{icomp}.periodic_dir) ~= numel(periodic_dir) || ... - any (scalar_spaces{icomp}.periodic_dir ~= periodic_dir )) + if ~isempty(setxor(scalar_spaces{icomp}.periodic_dir, periodic_dir)) error ('sp_vector: the periodic Cartesian directions should match for all vector components') end end From 0bccd97eb2bd2edacf445064dcc935209194ec2b Mon Sep 17 00:00:00 2001 From: bkapidani Date: Thu, 13 Aug 2020 15:39:33 +0200 Subject: [PATCH 195/366] Handled case of too few elements in mesh (periodic space with multi-valued bsplines!) --- geopdes/inst/space/sp_bspline_1d_param.m | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 99bbf2d8..0583c48b 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -78,6 +78,11 @@ nel = size (nodes, 2); nqn = size (nodes, 1); +% if periodic && (p+1 - nel > 0) +% error (['sp_bspline_1d_param: too few elements to ensure single-valued', ... +% ' B-splines on periodic domain']); +% end + nsh = zeros (1, nel); connectivity = zeros (p+1, nel); for iel=1:nel @@ -108,8 +113,8 @@ if (periodic) regularity = degree - nnz(knots == knots(degree+1)); + n_extra_dofs = regularity + 1; - ndof = ndof - n_extra_dofs; filter = (connectivity == 0); @@ -117,6 +122,14 @@ connectivity(filter) = 0; nsh = sum(connectivity ~= 0,1); + nsh_max = max (nsh); + + [~,dummy_supp] = find (connectivity == 1); + if numel(unique(dummy_supp)) Date: Thu, 13 Aug 2020 17:15:46 +0200 Subject: [PATCH 196/366] Cleaned up files related to previous commit bug fix --- geopdes/inst/space/sp_bspline_1d_param.m | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/space/sp_bspline_1d_param.m b/geopdes/inst/space/sp_bspline_1d_param.m index 0583c48b..a73b812f 100644 --- a/geopdes/inst/space/sp_bspline_1d_param.m +++ b/geopdes/inst/space/sp_bspline_1d_param.m @@ -78,21 +78,14 @@ nel = size (nodes, 2); nqn = size (nodes, 1); -% if periodic && (p+1 - nel > 0) -% error (['sp_bspline_1d_param: too few elements to ensure single-valued', ... -% ' B-splines on periodic domain']); -% end - -nsh = zeros (1, nel); connectivity = zeros (p+1, nel); for iel=1:nel s = findspan (mcp, p, nodes(:, iel)', knots); c = numbasisfun (s, nodes(:, iel)', p, knots); c = unique(c(:))+1; connectivity(1:numel(c), iel) = c; - % nsh(iel) = nnz (connectivity(:,iel)); % faster outside of loop? end -nsh = sum(connectivity ~= 0,1); % faster outside of loop? +nsh = sum(connectivity ~= 0,1); nsh_max = max (nsh); @@ -125,9 +118,9 @@ nsh_max = max (nsh); [~,dummy_supp] = find (connectivity == 1); - if numel(unique(dummy_supp)) Date: Fri, 14 Aug 2020 15:58:56 +0200 Subject: [PATCH 197/366] Reverted definition of sp_vector.boundary struct fields to fix mixed b.c. --- geopdes/inst/space/@sp_vector/sp_vector.m | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index 6b82c027..c634e4e8 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -135,7 +135,10 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_vector(); else % define relevant struct fields - sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'comp_dofs', [], 'ndof_dir', []); +% sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'comp_dofs', [], 'ndof_dir', []); + sp.boundary(iside).ndof = []; + sp.boundary(iside).dofs = []; + sp.boundary(iside).comp_dofs = []; end continue; elseif (strcmpi (transform, 'div-preserving')) @@ -205,7 +208,7 @@ if (isempty (msh.boundary)) sp.boundary(iside).ndof = numel (sp.boundary(iside).dofs); - if (strcmpi (transform, 'curl-preserving')) % Needed for the interfaces on the boundary, in sp_multipatch + if (strcmpi (transform, 'curl-preserving')) for icomp = 1:numel(ind) ndof_dir(icomp,:) = sp.ndof_dir(ind(icomp), ind); end From b255f15cd715f34bde91beaaed85983dccdf629a Mon Sep 17 00:00:00 2001 From: Luca Coradello Date: Wed, 30 Sep 2020 16:34:40 +0200 Subject: [PATCH 198/366] Changed to consistent Voigt notation --- geopdes/inst/operators/op_KL_bending_stress.m | 10 +++++----- geopdes/inst/operators/op_KL_membrane_stress.m | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/operators/op_KL_bending_stress.m b/geopdes/inst/operators/op_KL_bending_stress.m index 3ce5a487..201ccf92 100644 --- a/geopdes/inst/operators/op_KL_bending_stress.m +++ b/geopdes/inst/operators/op_KL_bending_stress.m @@ -182,17 +182,17 @@ bending(1, 1, :, :, :) = T_1_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_1_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_1_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + T_1_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); - bending(1, 2, :, :, :) = T_3_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... + bending(1, 2, :, :, :) = .5 * (T_3_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_3_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_3_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + T_3_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel])); bending(2, 2, :, :, :) = T_2_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_2_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_2_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + T_2_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); - bending(2, 1, :, :, :) = bending(1, 2, :, :, :); + bending(2, 1, :, :, :) = bending(1, 2, :, :, :); clear aux diff --git a/geopdes/inst/operators/op_KL_membrane_stress.m b/geopdes/inst/operators/op_KL_membrane_stress.m index 72c8425b..72ae7777 100644 --- a/geopdes/inst/operators/op_KL_membrane_stress.m +++ b/geopdes/inst/operators/op_KL_membrane_stress.m @@ -129,17 +129,17 @@ membrane(1, 1, :, :, :) = T_1_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_1_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_1_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + T_1_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); - membrane(1, 2, :, :, :) = T_3_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... + membrane(1, 2, :, :, :) = .5 * (T_3_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_3_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_3_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + T_3_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel])); membrane(2, 2, :, :, :) = T_2_1 .* reshape(aux(1, 1, :, :, :), [nqn, nsh_u, nel]) + ... T_2_2 .* reshape(aux(2, 2, :, :, :), [nqn, nsh_u, nel]) + ... - .5 * T_2_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); - - membrane(2, 1, :, :, :) = membrane(1, 2, :, :, :); + T_2_3 .* reshape(aux(1, 2, :, :, :), [nqn, nsh_u, nel]); + + membrane(2, 1, :, :, :) = membrane(1, 2, :, :, :); clear aux From 1fbce3aa3aa78867d1e6d25b96dd723d33fe2dac Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 25 Mar 2021 18:06:33 +0100 Subject: [PATCH 199/366] Changes for plotting vectors in the periodic case --- geopdes/inst/space/@sp_vector/sp_plot_solution.m | 7 +++++-- geopdes/inst/space/sp_bspline.m | 6 +----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/geopdes/inst/space/@sp_vector/sp_plot_solution.m b/geopdes/inst/space/@sp_vector/sp_plot_solution.m index 8b2315a1..b85c3e81 100644 --- a/geopdes/inst/space/@sp_vector/sp_plot_solution.m +++ b/geopdes/inst/space/@sp_vector/sp_plot_solution.m @@ -56,8 +56,9 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) if (~exist ('vtk_pts', 'var')) knots = space.scalar_spaces{1}.knots; + degree = space.scalar_spaces{1}.degree; for idim = 1:ndim - vtk_pts{idim} = linspace (knots{idim}(1), knots{idim}(end), npts(idim)); + vtk_pts{idim} = linspace (knots{idim}(1+degree(idim)), knots{idim}(end-degree(idim)), npts(idim)); end end @@ -80,9 +81,11 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) hold_flag = ishold; disp ('Warning: a different scaling is used for each cut') + knots = space.scalar_spaces{1}.knots; + degree = space.scalar_spaces{1}.degree; for idim = 1:ndim plot_pts = vtk_pts; - plot_pts{idim} = linspace(knots{idim}(1), knots{idim}(end), ncuts(idim)+2); + plot_pts{idim} = linspace(knots{idim}(1+degree(idim)), knots{idim}(end-degree(idim)), ncuts(idim)+2); [eu, F] = sp_eval (u, space, geometry, plot_pts); indices = {1:npts(1), 1:npts(2), 1:npts(3)}; diff --git a/geopdes/inst/space/sp_bspline.m b/geopdes/inst/space/sp_bspline.m index cfda2b9e..5aea8bb7 100644 --- a/geopdes/inst/space/sp_bspline.m +++ b/geopdes/inst/space/sp_bspline.m @@ -31,13 +31,9 @@ function sp = sp_bspline (knots, degree, msh, transform, periodic_directions) -% % % if (nargin < 6) -% % % regularity = degree-1; -% % % end - if (nargin < 5) periodic_directions = []; - else % more robust + else periodic_directions = sort(periodic_directions); end From 39c35b3b587f76d58734eee214cfe0e66c766fe5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 25 Mar 2021 18:53:15 +0100 Subject: [PATCH 200/366] Copyright and help --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 3 ++- geopdes/inst/space/@sp_vector/sp_vector.m | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index d07dae29..42a42e32 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -10,7 +10,7 @@ % msh: msh object that defines the quadrature rule (see msh_cartesian) % transform: string with the transformation to the physical domain, one of % 'grad-preserving' (default) and 'integral-preserving', for N-forms -% periodic_dir: Cartesian directions in which the space should be made periodic +% periodic_dir: Cartesian directions in which the space should be made periodic % % % OUTPUT: @@ -61,6 +61,7 @@ % % Copyright (C) 2009, 2010, 2011 Carlo de Falco % Copyright (C) 2011, 2015 Rafael Vazquez +% Copyright (C) 2020, 2021 Bernard Kapidani, Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index c634e4e8..d9690405 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -54,6 +54,7 @@ % % Copyright (C) 2009, 2010, 2011 Carlo de Falco % Copyright (C) 2011, 2015 Rafael Vazquez +% Copyright (C) 2020, 2021 Bernard Kapidani, Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by From 5159f8f4e0ff63381c0af9aba2ab47d093c229bb Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 17:20:37 +0200 Subject: [PATCH 201/366] Using periodic_directions instead of sides. Added comment about continuity --- .../base/ex_laplace_square_periodic.m | 67 +++++++++++++++++++ .../maxwell/ex_maxwell_src_periodic_square.m | 27 ++------ geopdes/inst/solve/solve_laplace.m | 11 +-- geopdes/inst/solve/solve_maxwell_src.m | 11 +-- 4 files changed, 86 insertions(+), 30 deletions(-) create mode 100644 geopdes/inst/examples/base/ex_laplace_square_periodic.m diff --git a/geopdes/inst/examples/base/ex_laplace_square_periodic.m b/geopdes/inst/examples/base/ex_laplace_square_periodic.m new file mode 100644 index 00000000..0e5999ee --- /dev/null +++ b/geopdes/inst/examples/base/ex_laplace_square_periodic.m @@ -0,0 +1,67 @@ +% EX_LAPLACE_SQUARE: solve the Poisson problem with periodic splines in the unit square. + +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +problem_data.geo_name = 'geo_square.txt'; +% The domain must also have the right continuity conditions on the periodic +% sides, otherwise the convergence rate may deteriorate. For instance, the +% following parametrization only has C^0 continuity at periodic sides. A +% discretization with periodic splines of higher continuity will give a +% convergence rate of h^{0.5}. +% nrb = nrbdegelev (nrb4surf ([0 0], [1 0], [0 1], [1 1]), [2 2]); +% nrb.coefs(1:2,2,2) = [0.35 0.3]; nrb.coefs(1:2,2,3) = [0.31 0.7]; +% problem_data.geo_name = nrb; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [3 4]; +problem_data.periodic_directions = [1]; + +% Physical parameters +problem_data.c_diff = @(x, y) ones(size(x)); + +% Source and boundary terms +problem_data.f = @(x, y) 8*pi^2 * sin(2*pi*x) .* sin(2*pi*y); +problem_data.h = @(x, y, ind) sin(2*pi*x) .* sin(2*pi*y); + +% Exact solution (optional) +problem_data.uex = @(x, y) sin(2*pi*x) .* sin(2*pi*y); +problem_data.graduex = @(x, y) cat (1, ... + reshape (2*pi * cos(2*pi*x) .* sin(2*pi*y), [1, size(x)]), ... + reshape (2*pi * sin(2*pi*x) .* cos(2*pi*y), [1, size(x)])); + +% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +method_data.degree = [3 3]; % Degree of the splines +method_data.regularity = [2 2]; % Regularity of the splines +method_data.nsub = [9 9]; % Number of subdivisions +method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule + +% 3) CALL TO THE SOLVER + +[geometry, msh, space, u] = solve_laplace (problem_data, method_data); + +% 4) POST-PROCESSING +% 4.1) EXPORT TO PARAVIEW + +output_file = 'Square_BSP_Deg3_Reg2_Sub9'; + +vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; +fprintf ('The result is saved in the file %s \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') + +% 4.2) PLOT IN MATLAB. COMPARISON WITH THE EXACT SOLUTION + +[eu, F] = sp_eval (u, space, geometry, vtk_pts); +[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +subplot (1,2,1) +surf (X, Y, eu) +title ('Numerical solution'), axis tight +subplot (1,2,2) +surf (X, Y, problem_data.uex (X,Y)) +title ('Exact solution'), axis tight + +% Display errors of the computed solution in the L2 and H1 norm +[error_h1, error_l2] = ... + sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m index 12d52c1f..9c5ff579 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -4,11 +4,14 @@ clear problem_data % Physical domain, defined as NURBS map given in a text file problem_data.geo_name = 'geo_square.txt'; +% The domain must also have the right continuity conditions on the periodic +% sides, otherwise the convergence rate may deteriorate. +% See the example in ex_laplace_square_periodic. % Type of boundary conditions problem_data.nmnn_sides = []; problem_data.drchlt_sides = [3 4]; -problem_data.periodic_sides = [1 2]; +problem_data.periodic_directions = [1]; % Physical parameters problem_data.c_stiff = @(x, y) ones(size(x)); @@ -29,7 +32,7 @@ clear method_data method_data.degree = [3 3]; % Degree of the bsplines method_data.regularity = [2 2]; % Regularity of the splines -method_data.nsub = [16 16]; % Number of subdivisions +method_data.nsub = [9 9]; % Number of subdivisions method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule % 3) CALL TO THE SOLVER @@ -58,25 +61,5 @@ title('Exact solution') ylim([0,1]); xlim([0,1]); - -% % % y_pt = 0.5; -% % % vtk_pts = {linspace(0,1,60),y_pt}; -% % % [eu, F] = sp_eval (u, space, geometry, vtk_pts); -% % % [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); -% % % eu2 = problem_data.uex (X, Y); -% % % -% % % eu = squeeze(eu(2,:,:)); %eu = eu(:,1); -% % % eu2 = squeeze(eu2(2,:,:)); %eu2 = eu2(:,1); -% % % -% % % subplot(1,2,1) -% % % plot (X, eu); -% % % grid on; -% % % title('Computed solution') -% % % -% % % subplot(1,2,2) -% % % plot (X, eu2) -% % % grid on; -% % % title('Exact solution') - [error_hcurl, error_l2] = ... sp_hcurl_error (space, msh, u, problem_data.uex, problem_data.curluex) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index d98bee34..4a4cf230 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -71,10 +71,13 @@ [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); -% check for periodic directions -if (exist('periodic_sides', 'var')) - periodic_directions = unique(ceil(periodic_sides./2), 'legacy'); - knots = kntunclamp(knots, degree, regularity, periodic_directions); +% Check for periodic conditions, and consistency with other boundary conditions +if (exist('periodic_directions', 'var')) + knots = kntunclamp (knots, degree, regularity, periodic_directions); + per_sides = union (periodic_directions*2 - 1, periodic_directions*2); + if (~isempty (intersect(per_sides, [nmnn_sides, drchlt_sides]))) + error ('Neumann or Dirichlet conditions cannot be imposed on periodic sides') + end else periodic_directions = []; end diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 995a01f6..2b5e0c9f 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -71,10 +71,13 @@ [knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); -% check for periodic directions -if (exist('periodic_sides', 'var')) - periodic_directions = unique(ceil(periodic_sides./2), 'legacy'); - knots = kntunclamp(knots, degree, regularity, periodic_directions); +% Check for periodic conditions, and consistency with other boundary conditions +if (exist('periodic_directions', 'var')) + knots = kntunclamp (knots, degree, regularity, periodic_directions); + per_sides = union (periodic_directions*2 - 1, periodic_directions*2); + if (~isempty (intersect(per_sides, [nmnn_sides, drchlt_sides]))) + error ('Neumann or Dirichlet conditions cannot be imposed on periodic sides') + end else periodic_directions = []; end From 2b86e73f1b449b77e3aa9f8aa3f2ee9576490a62 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 17:25:59 +0200 Subject: [PATCH 202/366] Changes in the help, copyright, and remove comments --- geopdes/inst/solve/solve_laplace.m | 4 +++- geopdes/inst/solve/solve_maxwell_src.m | 4 +++- geopdes/inst/space/@sp_vector/sp_vector.m | 1 - 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index 4a4cf230..e1f9cd0c 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -16,6 +16,7 @@ % - geo_name: name of the file containing the geometry % - nmnn_sides: sides with Neumann boundary condition (may be empty) % - drchlt_sides: sides with Dirichlet boundary condition +% - periodic_directions: parametric directions along which to apply periodic conditions % - c_diff: diffusion coefficient (epsilon in the equation) % - f: source term % - g: function for Neumann condition (if nmnn_sides is not empty) @@ -38,7 +39,8 @@ % See also EX_LAPLACE_SQUARE, EX_LAPLACE_THICK_RING for examples. % % Copyright (C) 2009, 2010, 2011 Carlo de Falco -% Copyright (C) 2011, 2015, 2017 Rafael Vazquez +% Copyright (C) 2011, 2015, 2017, 2021 Rafael Vazquez +% Copyright (C) 2021 Bernard Kapidani % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 2b5e0c9f..07ea8e53 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -16,6 +16,7 @@ % - geo_name: name of the file containing the geometry % - nmnn_sides: sides with Neumann boundary condition (may be empty) % - drchlt_sides: sides with Dirichlet boundary condition +% - periodic_directions: parametric directions along which to apply periodic conditions % - c_mass: coefficient for the mass matrix (mu in the equation) % - c_stiff: coefficient for the stiffness matrix (epsilon in the equation) % - f: source term @@ -38,7 +39,8 @@ % % See also EX_MAXWELL_SRC_LSHAPED for an example. % -% Copyright (C) 2010, 2011, 2015 Rafael Vazquez +% Copyright (C) 2010, 2011, 2015, 2021 Rafael Vazquez +% Copyright (C) 2021 Bernard Kapidani % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index d9690405..a8404a3a 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -136,7 +136,6 @@ if (~isempty (msh.boundary)) sp.boundary(iside) = sp_vector(); else % define relevant struct fields -% sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'comp_dofs', [], 'ndof_dir', []); sp.boundary(iside).ndof = []; sp.boundary(iside).dofs = []; sp.boundary(iside).comp_dofs = []; From 5d927b55f0963076b1b7bddf47d528d6b109fa8f Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 17:27:13 +0200 Subject: [PATCH 203/366] Changed name of output file --- geopdes/inst/examples/base/ex_laplace_square_periodic.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/examples/base/ex_laplace_square_periodic.m b/geopdes/inst/examples/base/ex_laplace_square_periodic.m index 0e5999ee..6b618521 100644 --- a/geopdes/inst/examples/base/ex_laplace_square_periodic.m +++ b/geopdes/inst/examples/base/ex_laplace_square_periodic.m @@ -45,7 +45,7 @@ % 4) POST-PROCESSING % 4.1) EXPORT TO PARAVIEW -output_file = 'Square_BSP_Deg3_Reg2_Sub9'; +output_file = 'Square_BSP_Periodic_Deg3_Reg2_Sub9'; vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; fprintf ('The result is saved in the file %s \n \n', output_file); diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m index 9c5ff579..a98e0318 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_src_periodic_square.m @@ -41,7 +41,7 @@ % 4) POST-PROCESSING vtk_pts = {linspace(0, 1, 30), linspace(0, 1, 30)}; % 4.1) EXPORT TO PARAVIEW -output_file = 'maxwell_square_Deg3_Reg2_Sub8'; +output_file = 'maxwell_square_periodic_Deg3_Reg2_Sub8'; fprintf ('The result is saved in the file %s \n \n', output_file); sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') From 6ccc8b64a7cca32daab8afb3f8be45313ab20e39 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 17:46:02 +0200 Subject: [PATCH 204/366] Updated the NEWS file --- geopdes/NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/geopdes/NEWS b/geopdes/NEWS index 7f42e2cd..f67d2aca 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -1,3 +1,7 @@ +Summary of important changes for geopdes-3.2.2: +----------------------------------------------------------------------------- +* Added periodic conditions for spline spaces + Summary of important changes for geopdes-3.2.1: ----------------------------------------------------------------------------- * Fixed bug in MP_DG_PENALTY, causing low order of convergence. From af8c8a74ff850758ce7f3c16caaffe15a551f75d Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 18:24:23 +0200 Subject: [PATCH 205/366] Prepare for new version --- geopdes/DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/DESCRIPTION b/geopdes/DESCRIPTION index 09ac1b9e..3874de7a 100644 --- a/geopdes/DESCRIPTION +++ b/geopdes/DESCRIPTION @@ -1,6 +1,6 @@ Name: geopdes -Version: 3.2.1 -Date: 2020-04-03 +Version: 3.2.2 +Date: 2021-03-30 Author: Rafael Vazquez, Carlo de Falco Maintainer: Rafael Vazquez Title: Iso-Geometric Analysis From 46a651bd652d9f1f88f0b207c6a53b44a3c23fd0 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 30 Mar 2021 19:01:29 +0200 Subject: [PATCH 206/366] Added files to the index --- geopdes/INDEX | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/geopdes/INDEX b/geopdes/INDEX index 3550d4e2..f6e89759 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -20,6 +20,7 @@ Solve: solvers for some simple problems, that you can modify to solve your own p solve_navier_stokes solve_stokes solve_kirchhoff_love_shell + solve_BE_Beam Geometry: read geometry files, that can be created with the NURBS package geo_nurbs geo_load @@ -30,8 +31,8 @@ Mesh: functions to generate and compute quadrature points in the NURBS geometry msh_gauss_nodes msh_set_quad_nodes msh_set_breaks - msh_cartesian msh_restrict_to_cells + msh_cartesian @msh_cartesian/msh_eval_boundary_side @msh_cartesian/msh_evaluate_col @msh_cartesian/msh_evaluate_element_list @@ -43,9 +44,8 @@ Space: functions to generate and compute discrete spline and NURBS spaces sp_h1_error sp_l2_error sp_hcurl_error + sp_hdiv_error sp_eval_msh - sp_to_vtk_b64 - sp_to_vtk_raw sp_bspline sp_nurbs sp_bspline_fluid @@ -86,11 +86,14 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_vector/sp_h1_error @sp_vector/sp_l2_error @sp_vector/sp_hcurl_error + @sp_vector/sp_hdiv_error @sp_vector/sp_precompute @sp_vector/sp_precompute_param @sp_vector/sp_plot_solution @sp_vector/sp_to_vtk @sp_vector/sp_drchlt_l2_proj + @sp_vector/sp_drchlt_l2_proj_udotn + @sp_vector/sp_drchlt_l2_proj_uxn @sp_vector/sp_weak_drchlt_bc_stokes @sp_vector/sp_get_basis_functions @sp_vector/sp_get_cells @@ -137,6 +140,7 @@ Operators: functions to assemble different matrices and vector op_KL_bending_stress op_KL_membrane_stress Multipatch: functions of different kinds to solve problems in domains defined by multiple NURBS patches + mp_dg_penalty mp_geo_load mp_geo_read_nurbs mp_interface @@ -147,8 +151,10 @@ Multipatch: functions of different kinds to solve problems in domains defined by mp_solve_linear_elasticity mp_solve_maxwell_eig mp_solve_maxwell_eig_mixed1 + mp_solve_maxwell_src mp_solve_stokes mp_solve_stokes_div_conforming + msh_restrict_to_patches msh_multipatch @msh_multipatch/msh_evaluate_element_list @msh_multipatch/msh_refine @@ -161,6 +167,7 @@ Multipatch: functions of different kinds to solve problems in domains defined by @sp_multipatch/sp_evaluate_element_list @sp_multipatch/sp_get_cells @sp_multipatch/sp_get_basis_functions + @sp_multipatch/sp_get_boundary_functions @sp_multipatch/sp_get_neighbors @sp_multipatch/sp_drchlt_l2_proj @sp_multipatch/sp_drchlt_l2_proj_udotn @@ -170,5 +177,8 @@ Multipatch: functions of different kinds to solve problems in domains defined by Utilities: other functions in the package collocation_csp knt_derham + kntunclamp msh_to_vtk newtons_method + get_boundary_indices + get_volumetric_indices \ No newline at end of file From fc898540b26b9c1a6eadc1f9986ada321caeb51a Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 31 Mar 2021 19:05:05 +0200 Subject: [PATCH 207/366] Change geometry for positive Jacobian --- .../inst/examples/geometry_files/annulus.mat | Bin 439 -> 1464 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/geopdes/inst/examples/geometry_files/annulus.mat b/geopdes/inst/examples/geometry_files/annulus.mat index 2a3d58d8c3d6442feadbc9e2cd63dc1df66166ca..9cb522d693aa87424c14dcabc035cca77c15fb36 100644 GIT binary patch literal 1464 zcmeZu4DoSvQZUssQ1EpO(M`+DN!3v(FUl+_NzGG8s#Ne#E=ep)RWQ>t&@<3cFfuSQ z)HN{HH8xZ*G`BJ^wlXnM2n}&oAP+DwdiwG)FfbUfGBB_KX$~M}0%ArW1`2`sAT|Uu zGo+{H1I1Yw9H3$iK#8>cqFf-CY><*kk#>f>(%hufBC@S#NX}19D<)q%Lv~(%2_^dT zi&7|YJ_9KJ9Do=We=I;Ydi=3N#eftr_87o=oEUT&{1`$Rf*70_f}vs-KpJKah(G=Q{|#f>(%hufBJ%Yo=clF>Q(%8~UVaHB`tyrYC~-am9}qh*AmWb&Dvlg~ z>`k=6`Cne9-VV_DX3zDX>2GG-BMkFz=G;G1_Tz*7EhvrMd9Q! I0F-WP4*r3b_5c6? From 1d8185cd44b9c0273fc7d59bf5d63ebe88e698c9 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 6 Apr 2021 12:14:35 +0200 Subject: [PATCH 208/366] Updated version --- geopdes/README.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/README.txt b/geopdes/README.txt index e2faec10..670ccd0a 100644 --- a/geopdes/README.txt +++ b/geopdes/README.txt @@ -36,9 +36,9 @@ CONTENTS: Download and uncompress the file GeoPDEs_full.tar.gz. This file contains all that is necessary to install GeoPDEs: - - The GeoPDEs package: geopdes-3.2.0.tar.gz - - The NURBS package: nurbs-1.4.1.tar.gz - - The GeoPDEs-hierarchical package: geopdes_hierarchical-3.2.0.tar.gz + - The GeoPDEs package: geopdes-3.2.2.tar.gz + - The NURBS package: nurbs-1.4.3.tar.gz + - The GeoPDEs-hierarchical package: geopdes_hierarchical-3.2.2.tar.gz - The technical report of GeoPDEs: GeoPDES-report.pdf - The technical report for hierarchical splines: GeoPDES-hierarchical-report.pdf - This README file. @@ -95,7 +95,7 @@ CONTENTS: 3.1. EXAMPLES - * GeoPDEs contains a set of simple examples, that can be run with the commands: + * GeoPDEs contains a set of simple examples. Most of them can be run with the commands: geopdes_base_examples geopdes_elasticity_examples geopdes_fluid_examples From 30e096abde485f92ded14db3fb6f6bd0fe3f6c50 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 7 Apr 2021 10:56:32 +0200 Subject: [PATCH 209/366] Added the default value for periodic_directions --- geopdes/inst/space/@sp_scalar/sp_scalar.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_scalar.m b/geopdes/inst/space/@sp_scalar/sp_scalar.m index 42a42e32..e20c93e4 100644 --- a/geopdes/inst/space/@sp_scalar/sp_scalar.m +++ b/geopdes/inst/space/@sp_scalar/sp_scalar.m @@ -10,7 +10,7 @@ % msh: msh object that defines the quadrature rule (see msh_cartesian) % transform: string with the transformation to the physical domain, one of % 'grad-preserving' (default) and 'integral-preserving', for N-forms -% periodic_dir: Cartesian directions in which the space should be made periodic +% periodic_dir: Cartesian directions in which the space should be made periodic. By default it is empty. % % % OUTPUT: From d5e52d473fb6167abe95f8db131c6d47c222b2c3 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 7 Apr 2021 10:59:53 +0200 Subject: [PATCH 210/366] Explain that periodic_directions may be empty --- geopdes/inst/solve/solve_laplace.m | 2 +- geopdes/inst/solve/solve_maxwell_src.m | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/solve/solve_laplace.m b/geopdes/inst/solve/solve_laplace.m index e1f9cd0c..a16d4133 100644 --- a/geopdes/inst/solve/solve_laplace.m +++ b/geopdes/inst/solve/solve_laplace.m @@ -16,7 +16,7 @@ % - geo_name: name of the file containing the geometry % - nmnn_sides: sides with Neumann boundary condition (may be empty) % - drchlt_sides: sides with Dirichlet boundary condition -% - periodic_directions: parametric directions along which to apply periodic conditions +% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) % - c_diff: diffusion coefficient (epsilon in the equation) % - f: source term % - g: function for Neumann condition (if nmnn_sides is not empty) diff --git a/geopdes/inst/solve/solve_maxwell_src.m b/geopdes/inst/solve/solve_maxwell_src.m index 07ea8e53..547b6cfb 100644 --- a/geopdes/inst/solve/solve_maxwell_src.m +++ b/geopdes/inst/solve/solve_maxwell_src.m @@ -16,7 +16,7 @@ % - geo_name: name of the file containing the geometry % - nmnn_sides: sides with Neumann boundary condition (may be empty) % - drchlt_sides: sides with Dirichlet boundary condition -% - periodic_directions: parametric directions along which to apply periodic conditions +% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) % - c_mass: coefficient for the mass matrix (mu in the equation) % - c_stiff: coefficient for the stiffness matrix (epsilon in the equation) % - f: source term @@ -138,4 +138,4 @@ %! ex_maxwell_src_ring %!demo -%! ex_maxwell_src_pacman \ No newline at end of file +%! ex_maxwell_src_pacman From 729cabdd6c149b7051f57ffd1c2c56302fbc6b26 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 22 Apr 2021 15:46:29 +0200 Subject: [PATCH 211/366] Updated the date --- geopdes/DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/DESCRIPTION b/geopdes/DESCRIPTION index 3874de7a..39893562 100644 --- a/geopdes/DESCRIPTION +++ b/geopdes/DESCRIPTION @@ -1,6 +1,6 @@ Name: geopdes Version: 3.2.2 -Date: 2021-03-30 +Date: 2021-04-07 Author: Rafael Vazquez, Carlo de Falco Maintainer: Rafael Vazquez Title: Iso-Geometric Analysis From 0ba0437aa8e0638cccfc67159b89c04e292186ca Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 7 May 2021 13:53:25 +0200 Subject: [PATCH 212/366] Added message ID, to disable the warning --- geopdes/inst/multipatch/mp_geo_load.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/mp_geo_load.m b/geopdes/inst/multipatch/mp_geo_load.m index d74eecf6..4ee5ff65 100644 --- a/geopdes/inst/multipatch/mp_geo_load.m +++ b/geopdes/inst/multipatch/mp_geo_load.m @@ -135,7 +135,7 @@ for iptc = 1:numel(in) geometry(iptc) = geo_load (in(iptc)); end - warning ('Automatically generating the interface and boundary information with nrbmultipatch') + warning ('geopdes:nrbmultipatch', 'Automatically generating the interface and boundary information with nrbmultipatch') [interfaces, boundaries] = nrbmultipatch (in); subdomains(1).name = 'SUBDOMAIN 1'; subdomains(1).patches = 1:numel(in); From e54aaaead4c6509e1141651aebc7469564dafc36 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 5 Jul 2021 14:03:41 +0200 Subject: [PATCH 213/366] Fixed bug for periodic conditions on div-conforming elements --- geopdes/inst/space/@sp_vector/sp_vector.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_vector/sp_vector.m b/geopdes/inst/space/@sp_vector/sp_vector.m index a8404a3a..615667bc 100644 --- a/geopdes/inst/space/@sp_vector/sp_vector.m +++ b/geopdes/inst/space/@sp_vector/sp_vector.m @@ -149,7 +149,7 @@ sp.boundary(iside) = sp_scalar(); end else % define relevant struct fields - sp.boundary(iside) = struct ('ndof', [], 'dofs', [], 'adjacent_dofs', []); + sp.boundary(iside) = struct ('ndof', [], 'dofs', []); end continue; else From c54a35e5c9bd7b935e4dc0abc55218175d47a4e4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 7 Jul 2021 17:30:48 +0200 Subject: [PATCH 214/366] Added a boundary flag, necessary in some particular cases --- geopdes/inst/geometry/geo_load.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/geometry/geo_load.m b/geopdes/inst/geometry/geo_load.m index 243099dd..5fa70d0e 100644 --- a/geopdes/inst/geometry/geo_load.m +++ b/geopdes/inst/geometry/geo_load.m @@ -80,7 +80,7 @@ if (isfield (geometry, 'nurbs')) if (any (abs(geometry.nurbs.coefs(3,:)) > 1e-12)) rdim = 3; - elseif (any (abs(geometry.nurbs.coefs(2,:)) > 1e-12)) + elseif (any (abs(geometry.nurbs.coefs(2,:)) > 1e-12) || (isfield(in, 'boundary_flag') && in.boundary_flag)) rdim = 2; else rdim = 1; From fc6e66138467aa0fa093635d6dd5fb4fd2ecc628 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 8 Jul 2021 11:13:43 +0200 Subject: [PATCH 215/366] Added new function --- geopdes/INDEX | 1 + geopdes/NEWS | 4 + .../inst/msh/@msh_cartesian/msh_cartesian.m | 1 + .../@msh_cartesian/msh_get_neighbor_cells.m | 99 +++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 geopdes/inst/msh/@msh_cartesian/msh_get_neighbor_cells.m diff --git a/geopdes/INDEX b/geopdes/INDEX index f6e89759..d5638fc1 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -39,6 +39,7 @@ Mesh: functions to generate and compute quadrature points in the NURBS geometry @msh_cartesian/msh_precompute @msh_cartesian/msh_boundary_side_from_interior @msh_cartesian/msh_refine + @msh_cartesian/msh_get_neighbor_cells Space: functions to generate and compute discrete spline and NURBS spaces sp_h2_error sp_h1_error diff --git a/geopdes/NEWS b/geopdes/NEWS index f67d2aca..96f0f929 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -1,3 +1,7 @@ +Summary of important changes for geopdes-3.2.3: +----------------------------------------------------------------------------- +* Added new function: msh_get_neighbor_cells + Summary of important changes for geopdes-3.2.2: ----------------------------------------------------------------------------- * Added periodic conditions for spline spaces diff --git a/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m b/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m index c33c6082..3072b199 100644 --- a/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m +++ b/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m @@ -50,6 +50,7 @@ % points only on one boundary side. Useful to apply boundary % conditions in weak form. % msh_refine: create a msh_cartesian object with a refined mesh. +% msh_get_neighbor_cells: compute the indices of neighbor cells of a given one. % % Copyright (C) 2009, 2010, 2014 Carlo de Falco % Copyright (C) 2011 Rafael Vazquez diff --git a/geopdes/inst/msh/@msh_cartesian/msh_get_neighbor_cells.m b/geopdes/inst/msh/@msh_cartesian/msh_get_neighbor_cells.m new file mode 100644 index 00000000..15521e6a --- /dev/null +++ b/geopdes/inst/msh/@msh_cartesian/msh_get_neighbor_cells.m @@ -0,0 +1,99 @@ +% MSH_GET_NEIGHBOR_CELLS: Compute the indices of the neighbor cells of a given cell +% +% [cell_indices, indices_per_face] = msh_get_neighbor_cells (msh, indices, [diagonal]) +% +% INPUT: +% msh: object defining the domain partition (see msh_cartesian) +% indices: indices of the input cells. +% diagonal: decide whether to include the neighbors in diagonal direction (false by default) +% +% OUTPUT: +% cell_indices: indices of the neighbor elements in global numbering. +% indices_per_cell: indices of the neighbor cells for each input cell, +% in an array of size (numel(indices), 2*ndim) when diagonal is false, +% and an array of size (numel(indices), 3^ndim-1) when diagonal is true +% +% Copyright (C) 2017, 2018 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [neig_indices, indices_per_cell] = msh_get_neighbor_cells (msh, cell_indices, diagonal) + +if (nargin < 3) + diagonal = false; +end + +subindices = cell (msh.ndim, 1); +indices_per_cell = zeros (numel (cell_indices), 2*msh.ndim); +neig_indices = []; + +[subindices{:}] = ind2sub ([msh.nel_dir, 1], cell_indices(:)'); + +if (~diagonal || msh.ndim == 1) + for idim = 1:msh.ndim + subinds = subindices; + +% Indices in the negative direction + subinds{idim} = subindices{idim} - 1; + index_out = find (subinds{idim} == 0); + index_in = setdiff (1:numel(cell_indices), index_out); + subinds_tmp = cellfun (@(x) x(index_in), subinds, 'UniformOutput', false); + + cell_inds = sub2ind ([msh.nel_dir, 1], subinds_tmp{:}); + indices_per_cell(index_out, 2*idim-1) = 0; + indices_per_cell(index_in, 2*idim-1) = cell_inds; + neig_indices = union (neig_indices, cell_inds); + +% Indices in the positive direction + subinds{idim} = subindices{idim} + 1; + index_out = find (subinds{idim} == msh.nel_dir(idim) + 1); + index_in = setdiff (1:numel(cell_indices), index_out); + subinds_tmp = cellfun (@(x) x(index_in), subinds, 'UniformOutput', false); + + cell_inds = sub2ind ([msh.nel_dir, 1], subinds_tmp{:}); + indices_per_cell(index_out,2*idim) = 0; + indices_per_cell(index_in, 2*idim) = cell_inds; + neig_indices = union (neig_indices, cell_inds); + + end + +else + indices_per_cell = zeros (numel(cell_indices), 3^msh.ndim-1); + indices_in = cell (msh.ndim, 1); + subs_cell = cell (msh.ndim, 1); + all_neigs = cell (msh.ndim, 1); + + mid_index = (3^msh.ndim + 1)/2; + for iel = 1:numel (cell_indices) + index_in = true; + for idim = 1:msh.ndim + subs_idim = subindices{idim}(iel) + [-1 0 1]; + indices_in{idim} = subs_idim > 0 & subs_idim < msh.nel_dir(idim)+1; + subs_cell{idim} = subs_idim(indices_in{idim}); + index_in = kron (indices_in{idim}, index_in); + end + [all_neigs{:}] = ndgrid (subs_cell{:}); + neighbors = sub2ind ([msh.nel_dir, 1], all_neigs{:}); + neighbors = setdiff (neighbors, cell_indices(iel), 'stable'); + index_in = [index_in(1:mid_index-1) index_in(mid_index+1:end)]; + + indices_per_cell(iel,logical(index_in)) = neighbors; + neig_indices = union (neig_indices, neighbors); + end + +end +if iscolumn(neig_indices) + neig_indices = neig_indices'; +end +end From 3eb6c45ab467800528c89594e8aff66402ac3df9 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 13 Jul 2021 12:50:20 +0200 Subject: [PATCH 216/366] Check condition before any computation --- .../space/@sp_scalar/sp_evaluate_col_param.m | 88 +++++++++--------- .../sp_evaluate_element_list_param.m | 90 +++++++++---------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_evaluate_col_param.m b/geopdes/inst/space/@sp_scalar/sp_evaluate_col_param.m index aa8421a1..d250764a 100644 --- a/geopdes/inst/space/@sp_scalar/sp_evaluate_col_param.m +++ b/geopdes/inst/space/@sp_scalar/sp_evaluate_col_param.m @@ -119,63 +119,63 @@ 'ndof_dir', space.ndof_dir, 'connectivity', connectivity, ... 'ncomp', 1, 'degree', space.degree); -shp = cell(1,msh.ndim); shg = cell(1,msh.ndim); shh = cell(1,msh.ndim); -for idim = 1:msh.ndim - ssize = ones (1, 3*msh.ndim); - ssize([idim, msh.ndim+idim, 2*msh.ndim+idim]) = [msh.nqn_dir(idim), sp_univ(idim).nsh_max, msh.nel_dir(idim)]; - srep = [msh.nqn_dir, sp_univ.nsh_max, msh.nel_dir]; - srep([idim, msh.ndim+idim, 2*msh.ndim+idim]) = 1; - shp{idim} = reshape (sp_univ(idim).shape_functions(:,:,elem_list{idim}), ssize); - shp{idim} = repmat (shp{idim}, srep); - shp{idim} = reshape (shp{idim}, msh.nqn, space.nsh_max, msh.nel); - shg{idim} = reshape (sp_univ(idim).shape_function_gradients(:,:,elem_list{idim}), ssize); - shg{idim} = repmat (shg{idim}, srep); - shg{idim} = reshape (shg{idim}, msh.nqn, space.nsh_max, msh.nel); - shh{idim} = reshape (sp_univ(idim).shape_function_hessians(:,:,elem_list{idim}), ssize); - shh{idim} = repmat (shh{idim}, srep); - shh{idim} = reshape (shh{idim}, msh.nqn, space.nsh_max, msh.nel); -end - -if (value) - sp.shape_functions = 1; +if (value || gradient || hessian) + shp = cell(1,msh.ndim); shg = cell(1,msh.ndim); shh = cell(1,msh.ndim); for idim = 1:msh.ndim - sp.shape_functions = sp.shape_functions .* shp{idim}; + ssize = ones (1, 3*msh.ndim); + ssize([idim, msh.ndim+idim, 2*msh.ndim+idim]) = [msh.nqn_dir(idim), sp_univ(idim).nsh_max, msh.nel_dir(idim)]; + srep = [msh.nqn_dir, sp_univ.nsh_max, msh.nel_dir]; + srep([idim, msh.ndim+idim, 2*msh.ndim+idim]) = 1; + shp{idim} = reshape (sp_univ(idim).shape_functions(:,:,elem_list{idim}), ssize); + shp{idim} = repmat (shp{idim}, srep); + shp{idim} = reshape (shp{idim}, msh.nqn, space.nsh_max, msh.nel); + shg{idim} = reshape (sp_univ(idim).shape_function_gradients(:,:,elem_list{idim}), ssize); + shg{idim} = repmat (shg{idim}, srep); + shg{idim} = reshape (shg{idim}, msh.nqn, space.nsh_max, msh.nel); + shh{idim} = reshape (sp_univ(idim).shape_function_hessians(:,:,elem_list{idim}), ssize); + shh{idim} = repmat (shh{idim}, srep); + shh{idim} = reshape (shh{idim}, msh.nqn, space.nsh_max, msh.nel); end -end -if (gradient) - for idim = 1:msh.ndim - shape_fun_grad = shg{idim}; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_grad = shape_fun_grad .* shp{jdim}; + if (value) + sp.shape_functions = 1; + for idim = 1:msh.ndim + sp.shape_functions = sp.shape_functions .* shp{idim}; end - sp.shape_function_gradients(idim,:,:,:) = shape_fun_grad; end - sp.shape_function_gradients = reshape (sp.shape_function_gradients, ... - msh.ndim, msh.nqn, sp.nsh_max, msh.nel); -end -if (hessian && isfield (msh, 'geo_map_der2')) - for idim = 1:msh.ndim - shape_fun_hess = shh{idim}; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_hess = shape_fun_hess .* shp{jdim}; + if (gradient) + for idim = 1:msh.ndim + shape_fun_grad = shg{idim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_grad = shape_fun_grad .* shp{jdim}; + end + sp.shape_function_gradients(idim,:,:,:) = shape_fun_grad; end - sp.shape_function_hessians(idim,idim,:,:,:) = shape_fun_hess; + sp.shape_function_gradients = reshape (sp.shape_function_gradients, ... + msh.ndim, msh.nqn, sp.nsh_max, msh.nel); + end + + if (hessian && isfield (msh, 'geo_map_der2')) + for idim = 1:msh.ndim + shape_fun_hess = shh{idim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_hess = shape_fun_hess .* shp{jdim}; + end + sp.shape_function_hessians(idim,idim,:,:,:) = shape_fun_hess; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_hess = shg{idim} .* shg{jdim}; - for kdim = setdiff (1:msh.ndim, [idim, jdim]) - shape_fun_hess = shape_fun_hess .* shp{kdim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_hess = shg{idim} .* shg{jdim}; + for kdim = setdiff (1:msh.ndim, [idim, jdim]) + shape_fun_hess = shape_fun_hess .* shp{kdim}; + end + sp.shape_function_hessians(idim,jdim,:,:,:) = shape_fun_hess; end - sp.shape_function_hessians(idim,jdim,:,:,:) = shape_fun_hess; end end -end -clear shp shg shh + clear shp shg shh -if (value || gradient || hessian) if (strcmpi (space.space_type, 'NURBS')) sp = bsp_2_nrb__ (sp, msh, space.weights); end diff --git a/geopdes/inst/space/@sp_scalar/sp_evaluate_element_list_param.m b/geopdes/inst/space/@sp_scalar/sp_evaluate_element_list_param.m index 3d6bbc1a..3cbf28e2 100644 --- a/geopdes/inst/space/@sp_scalar/sp_evaluate_element_list_param.m +++ b/geopdes/inst/space/@sp_scalar/sp_evaluate_element_list_param.m @@ -81,11 +81,11 @@ elem_ind = cell2mat (elem_ind); nsh = 1; -for idim = 1:msh.ndim; +for idim = 1:msh.ndim nsh = nsh .* sp_univ(idim).nsh(elem_ind(idim,:)); end -for idim = 1:msh.ndim; +for idim = 1:msh.ndim csize = ones (1, msh.ndim); csize(idim) = sp_univ(idim).nsh_max; crep = [sp_univ.nsh_max]; @@ -111,63 +111,63 @@ 'ndof_dir', space.ndof_dir, 'connectivity', connectivity, ... 'ncomp', 1, 'degree', space.degree); +if (value || gradient || hessian) shp = cell(1,msh.ndim); shg = cell(1,msh.ndim); shh = cell(1,msh.ndim); -for idim = 1:msh.ndim - ssize = ones (1, 2*msh.ndim); - ssize([idim, msh.ndim+idim]) = [msh.nqn_dir(idim), sp_univ(idim).nsh_max]; - srep = [msh.nqn_dir, sp_univ.nsh_max]; - srep([idim, msh.ndim+idim]) = 1; - shp{idim} = reshape (sp_univ(idim).shape_functions(:,:,elem_ind(idim,:)), [ssize, msh.nel]); - shp{idim} = repmat (shp{idim}, [srep, 1]); - shp{idim} = reshape (shp{idim}, msh.nqn, space.nsh_max, msh.nel); - shg{idim} = reshape (sp_univ(idim).shape_function_gradients(:,:,elem_ind(idim,:)), [ssize, msh.nel]); - shg{idim} = repmat (shg{idim}, [srep, 1]); - shg{idim} = reshape (shg{idim}, msh.nqn, space.nsh_max, msh.nel); - shh{idim} = reshape (sp_univ(idim).shape_function_hessians(:,:,elem_ind(idim,:)), [ssize, msh.nel]); - shh{idim} = repmat (shh{idim}, [srep, 1]); - shh{idim} = reshape (shh{idim}, msh.nqn, space.nsh_max, msh.nel); -end - -if (value) - sp.shape_functions = 1; for idim = 1:msh.ndim - sp.shape_functions = sp.shape_functions .* shp{idim}; + ssize = ones (1, 2*msh.ndim); + ssize([idim, msh.ndim+idim]) = [msh.nqn_dir(idim), sp_univ(idim).nsh_max]; + srep = [msh.nqn_dir, sp_univ.nsh_max]; + srep([idim, msh.ndim+idim]) = 1; + shp{idim} = reshape (sp_univ(idim).shape_functions(:,:,elem_ind(idim,:)), [ssize, msh.nel]); + shp{idim} = repmat (shp{idim}, [srep, 1]); + shp{idim} = reshape (shp{idim}, msh.nqn, space.nsh_max, msh.nel); + shg{idim} = reshape (sp_univ(idim).shape_function_gradients(:,:,elem_ind(idim,:)), [ssize, msh.nel]); + shg{idim} = repmat (shg{idim}, [srep, 1]); + shg{idim} = reshape (shg{idim}, msh.nqn, space.nsh_max, msh.nel); + shh{idim} = reshape (sp_univ(idim).shape_function_hessians(:,:,elem_ind(idim,:)), [ssize, msh.nel]); + shh{idim} = repmat (shh{idim}, [srep, 1]); + shh{idim} = reshape (shh{idim}, msh.nqn, space.nsh_max, msh.nel); end -end -if (gradient) - for idim = 1:msh.ndim - shape_fun_grad = shg{idim}; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_grad = shape_fun_grad .* shp{jdim}; + if (value) + sp.shape_functions = 1; + for idim = 1:msh.ndim + sp.shape_functions = sp.shape_functions .* shp{idim}; end - sp.shape_function_gradients(idim,:,:,:) = shape_fun_grad; end - sp.shape_function_gradients = reshape (sp.shape_function_gradients, ... - msh.ndim, msh.nqn, sp.nsh_max, msh.nel); -end -if (hessian && (isfield (msh, 'geo_map_der2') || msh.nel == 0)) - for idim = 1:msh.ndim - shape_fun_hess = shh{idim}; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_hess = shape_fun_hess .* shp{jdim}; + if (gradient) + for idim = 1:msh.ndim + shape_fun_grad = shg{idim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_grad = shape_fun_grad .* shp{jdim}; + end + sp.shape_function_gradients(idim,:,:,:) = shape_fun_grad; end - sp.shape_function_hessians(idim,idim,:,:,:) = shape_fun_hess; + sp.shape_function_gradients = reshape (sp.shape_function_gradients, ... + msh.ndim, msh.nqn, sp.nsh_max, msh.nel); + end + + if (hessian && (isfield (msh, 'geo_map_der2') || msh.nel == 0)) + for idim = 1:msh.ndim + shape_fun_hess = shh{idim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_hess = shape_fun_hess .* shp{jdim}; + end + sp.shape_function_hessians(idim,idim,:,:,:) = shape_fun_hess; - for jdim = setdiff (1:msh.ndim, idim) - shape_fun_hess = shg{idim} .* shg{jdim}; - for kdim = setdiff (1:msh.ndim, [idim, jdim]) - shape_fun_hess = shape_fun_hess .* shp{kdim}; + for jdim = setdiff (1:msh.ndim, idim) + shape_fun_hess = shg{idim} .* shg{jdim}; + for kdim = setdiff (1:msh.ndim, [idim, jdim]) + shape_fun_hess = shape_fun_hess .* shp{kdim}; + end + sp.shape_function_hessians(idim,jdim,:,:,:) = shape_fun_hess; end - sp.shape_function_hessians(idim,jdim,:,:,:) = shape_fun_hess; end end -end -clear shp shg shh + clear shp shg shh -if (value || gradient || hessian) if (strcmpi (space.space_type, 'NURBS')) sp = bsp_2_nrb__ (sp, msh, space.weights); end From 36a2fbf909ad266f9a9487f83e1ffb08e864c086 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 Nov 2021 11:32:31 +0100 Subject: [PATCH 217/366] Replace squeeze by reshape --- geopdes/inst/operators/op_f_vxn_3d.m | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/geopdes/inst/operators/op_f_vxn_3d.m b/geopdes/inst/operators/op_f_vxn_3d.m index 8b55a51c..7c813e29 100644 --- a/geopdes/inst/operators/op_f_vxn_3d.m +++ b/geopdes/inst/operators/op_f_vxn_3d.m @@ -28,8 +28,6 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . - - function rhs = op_f_vxn_3d (spv, msh, coeff) rhs = zeros(spv.ndof, 1); @@ -39,7 +37,7 @@ rhs_loc = zeros (spv.nsh_max, 1); for idof = 1:spv.nsh_max - ishp = squeeze(spv.shape_functions(:,:,idof,iel)); + ishp = reshape (spv.shape_functions(:,:,idof,iel), spv.ncomp, msh.nqn(iel)); ishp_x_n = [ishp(2,:) .* msh.normal(3,:,iel) - ... ishp(3,:) .* msh.normal(2,:,iel); ... ishp(3,:) .* msh.normal(1,:,iel) - ... From 6d53365e08038eccc40135c26e19ac4ff9f01883 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 17 Nov 2021 18:47:12 +0100 Subject: [PATCH 218/366] Fixed bug (check on nargin) --- geopdes/inst/geometry/geo_nurbs.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/geometry/geo_nurbs.m b/geopdes/inst/geometry/geo_nurbs.m index eb536761..f09107d5 100644 --- a/geopdes/inst/geometry/geo_nurbs.m +++ b/geopdes/inst/geometry/geo_nurbs.m @@ -27,7 +27,7 @@ % Copyright (C) 2009, 2010 Carlo de Falco % Copyright (C) 2011 Rafael Vazquez % Copyright (C) 2013 Elena Bulgarello, Carlo de Falco, Sara Frizziero -% Copyright (C) 2015 Rafael Vazquez +% Copyright (C) 2015, 2021 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -46,7 +46,7 @@ ndim = numel (nurbs.order); - if (nargin < 4) + if (nargin < 6) if (any (abs(nurbs.coefs(3,:)) > 1e-12)) rdim = 3; elseif (any (abs(nurbs.coefs(2,:)) > 1e-12)) From b207573ca9335cc6f253feb45248a246972b6ac4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 22 Nov 2021 14:32:55 +0100 Subject: [PATCH 219/366] Fixed bug --- geopdes/inst/space/@sp_vector/sp_eval.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/space/@sp_vector/sp_eval.m b/geopdes/inst/space/@sp_vector/sp_eval.m index ee241dc8..61f31a90 100644 --- a/geopdes/inst/space/@sp_vector/sp_eval.m +++ b/geopdes/inst/space/@sp_vector/sp_eval.m @@ -67,7 +67,7 @@ elseif (isfield (struct(space.scalar_spaces{1}), 'knots')) degree = space.scalar_spaces{1}.degree; for idim=1:ndim - endpoints(:,idim) = space.knots{idim}([degree(idim)+1, end-degree(idim)]); + endpoints(:,idim) = space.scalar_spaces{1}.knots{idim}([degree(idim)+1, end-degree(idim)]); end else endpoints(2,:) = 1; From 4618fe5f5525d342464c815697a4991eb91befb5 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 22 Nov 2021 16:03:27 +0100 Subject: [PATCH 220/366] fixed bug --- geopdes/inst/operators/op_f_vxn_3d.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/operators/op_f_vxn_3d.m b/geopdes/inst/operators/op_f_vxn_3d.m index 7c813e29..a887c6ff 100644 --- a/geopdes/inst/operators/op_f_vxn_3d.m +++ b/geopdes/inst/operators/op_f_vxn_3d.m @@ -37,7 +37,7 @@ rhs_loc = zeros (spv.nsh_max, 1); for idof = 1:spv.nsh_max - ishp = reshape (spv.shape_functions(:,:,idof,iel), spv.ncomp, msh.nqn(iel)); + ishp = reshape (spv.shape_functions(:,:,idof,iel), spv.ncomp, msh.nqn); ishp_x_n = [ishp(2,:) .* msh.normal(3,:,iel) - ... ishp(3,:) .* msh.normal(2,:,iel); ... ishp(3,:) .* msh.normal(1,:,iel) - ... From 7c48d98c9db0fcc1870b17886bd2c01cdba59b40 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 15 Jun 2022 09:41:42 +0200 Subject: [PATCH 221/366] Fixed bug for non-NURBS geometries (reshape) --- .../msh/@msh_cartesian/msh_evaluate_element_list.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m b/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m index 31fb131b..8b5e83f5 100644 --- a/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m +++ b/geopdes/inst/msh/@msh_cartesian/msh_evaluate_element_list.m @@ -106,15 +106,15 @@ msh_col.geo_map_der2 = zeros (msh.rdim, msh.ndim, msh.ndim, msh.nqn, msh_col.nel); [F, jac, hess] = cellfun (@(x) feval (msh.map_der2, x), qqn, 'UniformOutput', false); for iel = 1:numel(elem_list) - msh_col.geo_map(:,:,iel) = F{iel}; - msh_col.geo_map_jac(:,:,:,iel) = jac{iel}; - msh_col.geo_map_der2(:,:,:,:,iel) = hess{iel}; + msh_col.geo_map(:,:,iel) = reshape (F{iel}, msh.rdim, msh.nqn); + msh_col.geo_map_jac(:,:,:,iel) = reshape (jac{iel}, msh.rdim, msh.ndim, msh.nqn); + msh_col.geo_map_der2(:,:,:,:,iel) = reshape (hess{iel}, msh.rdim, msh.ndim, msh.ndim, msh.nqn); end else [F, jac] = cellfun (@(x) feval (msh.map_der, x), qqn, 'UniformOutput', false); for iel = 1:numel(elem_list) - msh_col.geo_map(:,:,iel) = F{iel}; - msh_col.geo_map_jac(:,:,:,iel) = jac{iel}; + msh_col.geo_map(:,:,iel) = reshape (F{iel}, msh.rdim, msh.nqn); + msh_col.geo_map_jac(:,:,:,iel) = reshape (jac{iel}, msh.rdim, msh.ndim, msh.nqn); end end From 421033daedbb9c469da0e5a3c62f0abd663841fc Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Oct 2022 12:05:46 +0200 Subject: [PATCH 222/366] Quick fix, not general enough --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index cd95636f..ea7d13fd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -245,7 +245,8 @@ breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); kk = numel(breaks_m{1}) - 2; mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -reg = pp - max(mult(2:end-1)); +% reg = pp - max(mult(2:end-1)); +reg = pp - max(mult([2 end-1])); all_alpha0 = zeros(numel(interfaces_all),2); all_alpha1 = zeros(numel(interfaces_all),2); From 5d6122189cff077216e6e4b2c58df6dac72894d9 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Oct 2022 15:39:23 +0200 Subject: [PATCH 223/366] More checks on input data, and some cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index ea7d13fd..a43eedba 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -69,15 +69,21 @@ function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces_all, vertices) if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') + error ('All the spaces in the array should be of the sp_scalar class') end - aux = struct ([spaces{:}]); + ndof_all = cellfun (@(x) x.ndof, spaces); + degree_all = cellfun (@(x) x.degree, spaces, 'UniformOutput', false); + degree_all = cell2mat (degree_all.'); sp.npatch = numel (spaces); if (sp.npatch ~= msh.npatch) error ('The list of spaces does not correspond to the mesh') end + if (~all (all (degree_all == spaces{1}.degree, 2), 1)) + error ('All the patches should have the same degree, at least for now.') + end + for iptc = 1:numel(geometry) knots = spaces{iptc}.knots; breaks = cellfun (@unique, knots, 'UniformOutput', false); @@ -85,19 +91,19 @@ if (any ([mult{:}] < 2)) error ('The regularity should be at most degree minus two') end - for idim = 1:2 + for idim = 1:msh.ndim if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) error ('The regularity should not be lower than one') end end + if (numel(breaks{1}) ~= numel(breaks{2})) + error ('The number of internal knots should be the same in every patch and every coordinate, at least for now.') + end end sp.ncomp = spaces{1}.ncomp; sp.transform = spaces{1}.transform; - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end for iptc = 1:sp.npatch if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') @@ -108,7 +114,7 @@ end sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; + sp.ndof_per_patch = ndof_all; sp.sp_patch = spaces; % Knot vectors of auxiliary spaces @@ -241,12 +247,24 @@ end end -pp = space.sp_patch{1}.degree(1); -breaks_m = cellfun (@unique, space.sp_patch{1}.knots, 'UniformOutput', false); -kk = numel(breaks_m{1}) - 2; -mult = histc(space.sp_patch{1}.knots{1},breaks_m{1}); -% reg = pp - max(mult(2:end-1)); -reg = pp - max(mult([2 end-1])); +deg_aux = space.sp_patch{1}.degree(1); +breaks_m = unique (space.sp_patch{1}.knots{1}); +nbrk_aux = numel(breaks_m) - 1; % This is k+1 in the paper +mult = histc (space.sp_patch{1}.knots{1},breaks_m); +% reg_aux = deg_aux - max(mult(2:end-1)); +reg_aux = deg_aux - max(mult([2 end-1])); + +% Check that regularity of the first knot is the same in all patches and directions +for iptc = 1:space.npatch + for idim = 1:msh.ndim + breaks_m = cellfun (@unique, space.sp_patch{iptc}.knots, 'UniformOutput', false); + mult = histc(space.sp_patch{iptc}.knots{1},breaks_m{1}); + reg{idim} = space.sp_patch{iptc}.degree(1) - max(mult([2 end-1])); + end + if (any (reg{1} ~= reg{2})) + error ('The regularity of the first internal knot should always be the same, at least for now.') + end +end all_alpha0 = zeros(numel(interfaces_all),2); all_alpha1 = zeros(numel(interfaces_all),2); @@ -279,11 +297,11 @@ geo_map_jac{ii} = msh_side_interior.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) end - if msh.ndim + 1 == msh.rdim - [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); - else - [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); - end + if (msh.ndim + 1 == msh.rdim) + [alpha0, alpha1, beta0, beta1] = compute_gluing_data_surf (geo_map_jac, grev_pts, sides); + else + [alpha0, alpha1, beta0, beta1] = compute_gluing_data (geo_map_jac, grev_pts, sides); + end clear geo_map_jac msh_grev msh_side_interior grev_pts %Saving alphas and betas (first column=i_0, second column=i_1) @@ -413,7 +431,7 @@ % Computation of CC_vertices % Auxiliary constants to deal with different regularity cases in the M matrices -if (reg < pp-2) +if (reg_aux < deg_aux-2) const1 = 2; const2 = 1; else const1 = 3; const2 = 2; @@ -440,7 +458,7 @@ for iptc = 1:valence_p knots = space.sp_patch{iptc}.knots; for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; + brk{idim} = [knots{idim}(1) knots{idim}(end)]; end msh_pts_der1 = msh_cartesian (brk, {0 0}, [], geo_local(iptc),'boundary', true, 'der2', true); msh_der = msh_precompute (msh_pts_der1); @@ -449,13 +467,11 @@ sigma = sigma + norm (derivatives_new1{iptc}, Inf); end - sigma = pp*(kk+1)*valence_p/sigma; + sigma = deg_aux * nbrk_aux * valence_p / sigma; %Storing sigma for output - v_fun_matrices{1,kver}=sigma; + v_fun_matrices{1,kver} = sigma; - if msh.ndim+1==msh.rdim - - disp('Surf code'); + if (msh.ndim+1 == msh.rdim) %Tangent vectors Du_F = derivatives_new1{1}(:,1); Dv_F = derivatives_new1{1}(:,2); @@ -578,21 +594,21 @@ d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+const1*c1_a/(pp*(kk+1))+const2*c2_a/(pp*(pp-1)*(kk+1)^2), ... - d0_a/(pp*(kk+1)), ... - d0_a/(pp*(kk+1))+d1_a/(pp*(pp-1)*(kk+1)^2)].'; + c0+c1_a/(deg_aux*nbrk_aux), ... + c0+const1*c1_a/(deg_aux*nbrk_aux)+const2*c2_a/(deg_aux*(deg_aux-1)*nbrk_aux^2), ... + d0_a/(deg_aux*nbrk_aux), ... + d0_a/(deg_aux*nbrk_aux)+d1_a/(deg_aux*(deg_aux-1)*nbrk_aux^2)].'; M_next(:,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_b/(pp*(kk+1)), ... - c0+const1*c1_b/(pp*(kk+1))+const2*c2_b/(pp*(pp-1)*(kk+1)^2), ... - d0_b/(pp*(kk+1)), ... - d0_b/(pp*(kk+1))+d1_b/(pp*(pp-1)*(kk+1)^2)].'; + c0+c1_b/(deg_aux*nbrk_aux), ... + c0+const1*c1_b/(deg_aux*nbrk_aux)+const2*c2_b/(deg_aux*(deg_aux-1)*nbrk_aux^2), ... + d0_b/(deg_aux*nbrk_aux), ... + d0_b/(deg_aux*nbrk_aux)+d1_b/(deg_aux*(deg_aux-1)*nbrk_aux^2)].'; %V_{i_m,i} e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... - c0+c1_a/(pp*(kk+1)), ... - c0+c1_b/(pp*(kk+1)), ... - c0+(c1_a+c1_b+e11/(pp*(kk+1)))/(pp*(kk+1))]'; + c0+c1_a/(deg_aux*nbrk_aux), ... + c0+c1_b/(deg_aux*nbrk_aux), ... + c0+(c1_a+c1_b+e11/(deg_aux*nbrk_aux))/(deg_aux*nbrk_aux)]'; jfun = jfun+1; end end From 7cb1f3365f8e3d37491d01e71ab5977ab96c6c9e Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 09:16:36 +0100 Subject: [PATCH 224/366] Remove the two-patch class --- .../mp_solve_laplace_C1.m | 133 --- .../@sp_multipatch_C1_twopatch/op_f_v_mp.m | 51 - .../op_gradgradu_gradgradv_mp.m | 54 - .../op_gradu_gradv_mp.m | 54 - .../op_laplaceu_laplacev_mp.m | 55 - .../@sp_multipatch_C1_twopatch/op_u_v_mp.m | 61 -- .../solve_laplace.m | 139 --- .../sp_evaluate_element_list.m | 180 ---- .../sp_get_basis_functions.m | 41 - .../@sp_multipatch_C1_twopatch/sp_get_cells.m | 52 - .../sp_get_neighbors.m | 41 - .../@sp_multipatch_C1_twopatch/sp_h1_error.m | 54 - .../@sp_multipatch_C1_twopatch/sp_h2_error.m | 59 -- .../@sp_multipatch_C1_twopatch/sp_l2_error.m | 48 - .../sp_multipatch_C1.m | 948 ------------------ .../sp_multipatch_C1_curve.m | 423 -------- .../sp_multipatch_C1_new.m | 807 --------------- .../sp_multipatch_C1_new2.m | 911 ----------------- .../sp_multipatch_C1_old.m | 409 -------- .../sp_multipatch_C1_twopatch.m | 592 ----------- .../sp_plot_solution.m | 58 -- .../@sp_multipatch_C1_twopatch/sp_refine.m | 68 -- .../@sp_multipatch_C1_twopatch/sp_to_vtk.m | 82 -- .../sp_weak_drchlt_bc_laplace.m | 95 -- .../@sp_multipatch_C1_twopatch/subsasgn.m | 4 - .../@sp_multipatch_C1_twopatch/subsref.m | 4 - 26 files changed, 5423 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m deleted file mode 100644 index 903b622f..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/mp_solve_laplace_C1.m +++ /dev/null @@ -1,133 +0,0 @@ -% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. -% -% Example to solve the diffusion problem -% -% - div ( epsilon(x) grad (u)) = f in Omega -% epsilon(x) du/dn = g on Gamma_N -% u = h on Gamma_D -% -% where the domain \Omega is formed by several patches of the form F((0,1)^n). -% -% USAGE: -% -% [geometry, msh, space, u] = -% mp_solve_laplace (problem_data, method_data) -% -% INPUT: -% -% problem_data: a structure with data of the problem. It contains the fields: -% - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition -% - c_diff: diffusion coefficient (epsilon in the equation) -% - f: source term -% - g: function for Neumann condition (if nmnn_sides is not empty) -% - h: function for Dirichlet boundary condition -% -% method_data : a structure with discretization data. Its fields are: -% - degree: degree of the spline functions. -% - regularity: continuity of the spline functions. -% - nsub: number of subelements with respect to the geometry mesh -% (nsub=1 leaves the mesh unchanged) -% - nquad: number of points for Gaussian quadrature rule -% -% OUTPUT: -% -% geometry: array of geometry structures (see geo_load) -% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) -% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) -% u: the computed degrees of freedom -% -% Copyright (C) 2009, 2010 Carlo de Falco -% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 2 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [geometry, msh, space, u] = ... - mp_solve_laplace_C1 (problem_data, method_data) - -% Extract the fields from the data structures into local variables -data_names = fieldnames (problem_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); -end -data_names = fieldnames (method_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= method_data.(data_names{iopt});']); -end - -% Construct geometry structure, and information for interfaces and boundaries -[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); -npatch = numel (geometry); - -msh = cell (1, npatch); -sp = cell (1, npatch); -for iptc = 1:npatch - -% Define the refined mesh, with tensor product structure - [knots{iptc}, zeta{iptc}] = ... - kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); - -% Compute the quadrature rule - rule = msh_gauss_nodes (nquad); - [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); - msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); - -% Evaluate the discrete space basis functions in the quadrature points - sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); -end - -msh = msh_multipatch (msh, boundaries); -% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); -space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); -clear sp - -% Compute and assemble the matrices -stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); -rhs = op_f_v_mp (space, msh, f); - -% Apply Neumann boundary conditions -for iref = nmnn_sides - gref = @(varargin) g(varargin{:}, iref); - for bnd_side = 1:msh.boundaries(iref).nsides - iptc = msh.boundaries(iref).patches(bnd_side); - iside = msh.boundaries(iref).faces(bnd_side); - - msh_side = msh.msh_patch{iptc}.boundary(iside); - sp_side = space.sp_patch{iptc}.boundary(iside); - rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); - rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; - end -end - -% Apply Dirichlet boundary conditions in weak form, by Nitsche's method -if (exist ('weak_drchlt_sides', 'var')) - [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, weak_drchlt_sides, h, c_diff, Cpen); - stiff_mat = stiff_mat - N_mat; - rhs = rhs + N_rhs; -end - -% Solve the linear system -u = stiff_mat \ rhs; - -end - -%!demo -%! ex_laplace_Lshaped_mp - -%!demo -%! ex_laplace_cube_mp - -%!demo -%! ex_laplace_thick_L_mp diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m deleted file mode 100644 index 561a3415..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_f_v_mp.m +++ /dev/null @@ -1,51 +0,0 @@ -% OP_F_V_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. -% -% rhs = op_f_v_mp (spv, msh, coeff, [patches]); -% -% INPUT: -% -% spv: object representing the function space (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% coeff: function handle to compute the source function -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. -% -% OUTPUT: -% -% rhs: assembled right-hand side -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function rhs = op_f_v_mp (space, msh, coeff, patch_list) - - if (nargin < 4) - patch_list = 1:msh.npatch; - end - - if (space.npatch ~= msh.npatch) - error ('op_f_v_mp: the number of patches does not coincide') - end - - rhs = zeros (space.ndof, 1); - for iptc = patch_list - rhs_loc = op_f_v_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); - -% if (~isempty (space.dofs_ornt)) -% rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); -% end - rhs = rhs + space.Cpatch{iptc}.' * rhs_loc; - end - -end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m deleted file mode 100644 index 7abebba3..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradgradu_gradgradv_mp.m +++ /dev/null @@ -1,54 +0,0 @@ -% OP_GRADGRADU_GRADGRADV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon grad grad u_j, grad grad v_i), in a multipatch domain. -% -% mat = op_gradgradu_gradgradv_mp (spu, spv, msh, [epsilon], [patches]); -% -% INPUT: -% -% spu: object representing the space of trial functions (see sp_multipatch_C1) -% spv: object representing the space of test functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. -% -% OUTPUT: -% -% mat: assembled matrix -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function A = op_gradgradu_gradgradv_mp (spu, spv, msh, coeff, patch_list) - - if (nargin < 5) - patch_list = 1:msh.npatch; - end - - if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) - error ('op_gradgradu_gradgradv_mp: the number of patches does not coincide') - end - - A = sparse (spv.ndof, spu.ndof); - - for iptc = patch_list - if (nargin < 4 || isempty (coeff)) - Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); - else - Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); - end - - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; - end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m deleted file mode 100644 index 953bba5b..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_gradu_gradv_mp.m +++ /dev/null @@ -1,54 +0,0 @@ -% OP_GRADU_GRADV_MP: assemble the stiffness matrix A = [a(i,j)], a(i,j) = (epsilon grad u_j, grad v_i), in a multipatch domain. -% -% mat = op_gradu_gradv_mp (spu, spv, msh, [epsilon], [patches]); -% -% INPUT: -% -% spu: object representing the space of trial functions (see sp_multipatch_C1) -% spv: object representing the space of test functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% epsilon: function handle to compute the diffusion coefficient. Equal to one if left empty. -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. -% -% OUTPUT: -% -% mat: assembled stiffness matrix -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function A = op_gradu_gradv_mp (spu, spv, msh, coeff, patch_list) - - if (nargin < 5) - patch_list = 1:msh.npatch; - end - - if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) - error ('op_gradu_gradv_mp: the number of patches does not coincide') - end - - A = sparse (spv.ndof, spu.ndof); - - for iptc = patch_list - if (nargin < 4 || isempty (coeff)) - Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); - else - Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); - end - - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; - end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m deleted file mode 100644 index 55ba64ac..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_laplaceu_laplacev_mp.m +++ /dev/null @@ -1,55 +0,0 @@ -% OP_LAPLACEU_LAPLACEV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon laplace u_j, laplace v_i), in a multipatch domain. -% -% mat = op_laplaceu_laplacev_mp (spu, spv, msh, [coeff], [patches]); -% -% INPUT: -% -% spu: object representing the space of trial functions (see sp_multipatch_C1) -% spv: object representing the space of test functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. -% -% OUTPUT: -% -% mat: assembled matrix -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function A = op_laplaceu_laplacev_mp (spu, spv, msh, coeff, patch_list) - - if (nargin < 5) - patch_list = 1:msh.npatch; - end - - if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) - error ('op_laplaceu_laplacev_mp: the number of patches does not coincide') - end - - A = sparse (spv.ndof, spu.ndof); - - for iptc = patch_list - if (nargin < 4 || isempty (coeff)) - Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); - else - Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); - end - - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; - - end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m deleted file mode 100644 index 06151fde..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/op_u_v_mp.m +++ /dev/null @@ -1,61 +0,0 @@ -% OP_U_V_MP: assemble the mass matrix M = [m(i,j)], m(i,j) = (mu u_j, v_i), in a multipatch domain. -% -% mat = op_u_v_mp (spu, spv, msh, [coeff], [patches]); -% -% INPUT: -% -% spu: object representing the space of trial functions (see sp_multipatch_C1) -% spv: object representing the space of test functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% coeff: function handle to compute the reaction coefficient. Equal to one if left empty. -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. -% -% OUTPUT: -% -% mat: assembled mass matrix -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function A = op_u_v_mp (spu, spv, msh, coeff, patch_list) - - if (nargin < 5) - patch_list = 1:msh.npatch; - end - - if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) - error ('op_u_v_mp: the number of patches does not coincide') - end - - A = sparse (spv.ndof, spu.ndof); - - for iptc = patch_list - if (nargin < 4 || isempty (coeff)) - Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}); - else - Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); - end - - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; - -% if (~isempty (spv.dofs_ornt)) -% vs = spv.dofs_ornt{iptc}(rs)' .* vs; -% end -% if (~isempty (spu.dofs_ornt)) -% vs = vs .* spu.dofs_ornt{iptc}(cs)'; -% end - end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m deleted file mode 100644 index 73dc7df5..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/solve_laplace.m +++ /dev/null @@ -1,139 +0,0 @@ -% SOLVE_LAPLACE: Solve a Laplace problem with a B-spline discretization (non-isoparametric approach). -% -% The function solves the diffusion problem -% -% - div ( epsilon(x) grad (u)) = f in Omega = F((0,1)^n) -% epsilon(x) du/dn = g on Gamma_N -% u = h on Gamma_D -% -% USAGE: -% -% [geometry, msh, space, u] = solve_laplace (problem_data, method_data) -% -% INPUT: -% -% problem_data: a structure with data of the problem. It contains the fields: -% - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition -% - c_diff: diffusion coefficient (epsilon in the equation) -% - f: source term -% - g: function for Neumann condition (if nmnn_sides is not empty) -% - h: function for Dirichlet boundary condition -% -% method_data : a structure with discretization data. Its fields are: -% - degree: degree of the spline functions. -% - regularity: continuity of the spline functions. -% - nsub: number of subelements with respect to the geometry mesh -% (nsub=1 leaves the mesh unchanged) -% - nquad: number of points for Gaussian quadrature rule -% -% OUTPUT: -% -% geometry: geometry structure (see geo_load) -% msh: mesh object that defines the quadrature rule (see msh_cartesian) -% space: space object that defines the discrete space (see sp_scalar) -% u: the computed degrees of freedom -% -% See also EX_LAPLACE_SQUARE, EX_LAPLACE_THICK_RING for examples. -% -% Copyright (C) 2009, 2010, 2011 Carlo de Falco -% Copyright (C) 2011, 2015 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [geometry, msh, space, u] = ... - solve_laplace (problem_data, method_data) - -% Extract the fields from the data structures into local variables -data_names = fieldnames (problem_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); -end -data_names = fieldnames (method_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= method_data.(data_names{iopt});']); -end - -% Construct geometry structure -geometry = geo_load (geo_name); - -[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); - -% Construct msh structure -rule = msh_gauss_nodes (nquad); -[qn, qw] = msh_set_quad_nodes (zeta, rule); -msh = msh_cartesian (zeta, qn, qw, geometry); - -% Construct space structure -space = sp_bspline (knots, degree, msh); - -% Assemble the matrices -stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); -rhs = op_f_v_tp (space, msh, f); - -% Apply Neumann boundary conditions -for iside = nmnn_sides - if (msh.ndim > 1) -% Restrict the function handle to the specified side, in any dimension, gside = @(x,y) g(x,y,iside) - gside = @(varargin) g(varargin{:},iside); - dofs = space.boundary(iside).dofs; - rhs(dofs) = rhs(dofs) + op_f_v_tp (space.boundary(iside), msh.boundary(iside), gside); - else - if (iside == 1) - x = msh.breaks{1}(1); - else - x = msh.breaks{1}(end); - end - sp_side = space.boundary(iside); - rhs(sp_side.dofs) = rhs(sp_side.dofs) + g(x,iside); - end -end - -% Apply Dirichlet boundary conditions -u = zeros (space.ndof, 1); -[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); -u(drchlt_dofs) = u_drchlt; - -int_dofs = setdiff (1:space.ndof, drchlt_dofs); -rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; - -% Solve the linear system -u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); - -end - -%!demo -%! ex_laplace_square - -%!demo -%! ex_laplace_plate - -%!demo -%! ex_laplace_ring - -%!demo -%! ex_laplace_ring_mixed_bc - -%!demo -%! ex_laplace_cube - -%!demo -%! ex_laplace_thick_ring - -%!demo -%! ex_laplace_beltrami - -%!demo -%! ex_laplace_1d diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m deleted file mode 100644 index 85072cff..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_evaluate_element_list.m +++ /dev/null @@ -1,180 +0,0 @@ -% SP_EVALUATE_ELEMENT_LIST: compute the basis functions in a given list of elements. -% -% sp = sp_evaluate_element_list (space, msh_elems, 'option1', value1, ...) -% -% INPUTS: -% -% space: object defining the space of discrete functions (see sp_multipatch) -% msh_elems: structure containing the information of quadrature or -% visualization points, for a given list of elements and patches -% (see msh_multipatch/msh_evaluate_element_list) -% 'option', value: additional optional parameters, currently available options are: -% -% Name | Default value | Meaning -% ------------+-----------------+---------------------------------- -% value | true | compute shape_functions -% gradient | false | compute shape_function_gradients -% hessian | false | compute shape_function_hessians (only scalars) -% laplacian | false | compute shape_function_laplacians (only scalars) -% div | false | compute shape_function_divs (only vectors) -% curl | false | compute shape_function_curls (only vectors) -% -% OUTPUT: -% -% sp: struct representing the discrete function space, with the following fields: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space -% ndof (scalar) total number of degrees of freedom -% nsh (1 x nel) number of non-vanishing functions on each element -% nsh_max (scalar) maximum number of nsh -% connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element -% shape_functions, shape_function_gradients... (see sp_evaluate_col for details) -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_evaluate_element_list (space, msh, varargin) - - is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); - - sp.npatch = space.npatch; - sp.ncomp = space.ncomp; - sp.ndof = space.ndof; - - if (isempty (msh.elem_list)), return, end - - sp.nsh_max = []; - if (is_scalar) - fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', 'shape_function_laplacians'}; - cat_position = [2, 2, 3, 4, 5, 3]; -% else -% fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', ... -% 'shape_function_laplacians', 'shape_function_divs', 'shape_function_curls'}; -% if (msh.ndim == 2 || msh.ndim == 1) -% cat_position = [2, 2, 4, 5, 6, 4, 3, 3]; -% elseif (msh.ndim == 3) -% cat_position = [2, 2, 4, 5, 6, 4, 3, 4]; -% end - end - for ii = 1:numel(fields) - sp.(fields{ii}) = []; - end - - for iptc = 1:space.npatch -% msh_patch = msh_evaluate_element_list (msh.msh_patch{iptc}, msh.elem_list_of_patch{iptc}); % Not working anymore - msh_patch = msh_restrict_to_patch (msh, iptc); - - sp_patch = sp_evaluate_element_list (space.sp_patch{iptc}, msh_patch, varargin{:}); - Cpatch = space.Cpatch{iptc}; - - nsh = zeros (1, msh_patch.nel); - connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); - shape_funs = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); - shape_fun_grads = zeros (msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); - shape_fun_hess = zeros (msh.rdim, msh.rdim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); - shape_fun_lapl = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); - - for iel = 1:msh_patch.nel - conn_iel = sp_patch.connectivity(:,iel); - [ii,jj] = find (Cpatch(conn_iel,:)); - funs = unique (jj); - nsh(iel) = numel (funs); - connectivity(1:nsh(iel),iel) = funs; - Cpatch_iel = Cpatch(conn_iel, funs); - - if (isfield (sp_patch, 'shape_functions')) - shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; - end - if (isfield (sp_patch, 'shape_function_gradients')) - for idim = 1:msh.rdim - shape_fun_grads(idim,:,1:nsh(iel),iel) = ... - reshape (sp_patch.shape_function_gradients(idim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; - end - end - if (isfield (sp_patch, 'shape_function_laplacians')) - shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; - end - if (isfield (sp_patch, 'shape_function_hessians')) - for idim = 1:msh.rdim; - for jdim = 1:msh.rdim - shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... - reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; - end - end - end - end - - sp.nsh = cat (2, sp.nsh, nsh); - if (msh_patch.nel > 0) - sp.connectivity = cat (2, sp.connectivity, connectivity); - if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end - if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end - if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end - if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end - end - -% for ii = 1:numel(fields) -% if (isfield (sp_patch, fields{ii})) -% sp.(fields{ii}) = cat (cat_position(ii), sp.(fields{ii}), sp_patch.(fields{ii})); -% end -% end - end - sp.nsh_max = max (sp.nsh); - - for ii = 1:numel(fields) - if (isempty (sp.(fields{ii}))) - sp = rmfield (sp, fields{ii}); - elseif (ii > 1) - field_size = size (sp.(fields{ii})); - inds = repmat ({':'}, 1, numel(field_size)); - inds{cat_position(ii)-1} = 1:sp.nsh_max; - sp.(fields{ii}) = sp.(fields{ii})(inds{:}); - end - end - -end - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% MSH_RESTRICT_TO_PATCH: extracts the fields corresponding to the selected elements of a given patch, -% from the ones of a mesh struct, computed with msh_multipatch/msh_evaluate_element_list. -% The result is the same as calling msh_cartesian/msh_evaluate_element_list, but avoids recomputing. -% -function msh_ptc = msh_restrict_to_patch (msh, patch) - - msh_ptc.ndim = msh.ndim; - msh_ptc.rdim = msh.rdim; - msh_ptc.elem_list = msh.elem_list_of_patch{patch}(:).'; - - msh_ptc.nel = msh.nel_per_patch(patch); - msh_ptc.nel_dir = msh.nel_dir_of_patch{patch}; - msh_ptc.nqn = msh.nqn; - msh_ptc.nqn_dir = msh.nqn_dir; - - if (isempty (msh_ptc.elem_list)), return, end - - Nelem = cumsum ([0, msh.nel_per_patch]); - - global_elem_list = Nelem(patch)+1:Nelem(patch+1); - msh_ptc.quad_weights = msh.quad_weights(:,global_elem_list); - msh_ptc.geo_map = msh.geo_map(:,:,global_elem_list); - msh_ptc.geo_map_jac = msh.geo_map_jac(:,:,:,global_elem_list); - msh_ptc.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); - msh_ptc.jacdet = msh.jacdet(:,global_elem_list); - msh_ptc.element_size = msh.element_size(:,global_elem_list); - -end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m deleted file mode 100644 index 76edf5c8..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_basis_functions.m +++ /dev/null @@ -1,41 +0,0 @@ -% SP_GET_BASIS_FUNCTIONS: Compute the indices of tensor-product B-splines acting on a list of cells. -% -% fun_indices = sp_get_basis_functions (space, msh, indices) -% -% INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% indices: indices of the cells. -% -% OUTPUT: -% fun_indices: indices of the basis functions acting on the cells. -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function function_indices = sp_get_basis_functions (space, msh, cell_indices) - -function_indices = []; -Nelem = cumsum ([0 msh.nel_per_patch]); -for iptc = 1:space.npatch - [~,local_cell_indices,~] = intersect ((Nelem(iptc)+1):Nelem(iptc+1), cell_indices); - if (~isempty (local_cell_indices)) - aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); - [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); - function_indices = union (function_indices, dofs); - end -end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m deleted file mode 100644 index 874f4e92..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_cells.m +++ /dev/null @@ -1,52 +0,0 @@ -% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function. -% -% [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices) -% -% INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% indices: indices of the functions. -% -% OUTPUT: -% cell_indices: indices of the cells within the support of the basis functions. -% indices_per_function: indices of the cells within the support of each basis function. -% -% Copyright (C) 2015, 2016 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [cell_indices, indices_per_function] = sp_get_cells (space, msh, fun_indices) - -fun_indices = fun_indices(:).'; - -indices_per_function = cell (numel (fun_indices), 1); -cell_indices = []; - -Nelem = cumsum ([0 msh.nel_per_patch]); -for iptc = 1:space.npatch - [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices)); - if (~isempty (patch_indices)) - patch_indices = patch_indices(:).'; - [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); - - cell_indices = union (cell_indices, Nelem(iptc)+aux_cell_indices); - - if (nargout == 2) - local_funs = local_funs(:).'; - for ifun = 1:numel(patch_indices) - indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); - end - end - end -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m deleted file mode 100644 index 36a4ec2c..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_get_neighbors.m +++ /dev/null @@ -1,41 +0,0 @@ -% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions -% -% neighbors_indices = sp_get_neighbors (space, msh, indices) -% -% INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% indices: indices of the functions. -% -% OUTPUT: -% neighbors_indices: indices of the functions that interact with the given ones. -% -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function neighbors_indices = sp_get_neighbors (space, msh, fun_indices) - -neighbors_indices = []; - -for iptc = 1:space.npatch - [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices)); - if (~isempty (patch_indices)) - aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); - [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); - neighbors_indices = union (neighbors_indices, global_indices); - end -end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m deleted file mode 100644 index f727b7d2..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h1_error.m +++ /dev/null @@ -1,54 +0,0 @@ -% SP_H1_ERROR: Evaluate the error in H^1 norm. -% -% [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex) -% -% INPUT: -% -% space: object defining the space of discrete functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% u: vector of dof weights -% uex: function handle to evaluate the exact solution -% graduex: function handle to evaluate the gradient of the exact solution -% -% OUTPUT: -% -% errh1: error in H^1 norm -% errl2: error in L^2 norm -% errh1s: error in H^1 seminorm -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software; you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation; either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with Octave; see the file COPYING. If not, see -% . - -function [errh1, errl2, errh1s] = sp_h1_error (space, msh, u, uex, graduex) - - if (space.npatch ~= msh.npatch) - error ('The number of patches does not coincide') - end - - for iptc = 1:msh.npatch -% if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; -% else -% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; -% end - [error_h1(iptc), error_l2(iptc), error_h1s(iptc)] = ... - sp_h1_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex); - end - errl2 = sqrt (sum (error_l2 .* error_l2)); - errh1 = sqrt (sum (error_h1 .* error_h1)); - errh1s = sqrt (sum (error_h1s .* error_h1s)); - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m deleted file mode 100644 index a40be7cb..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_h2_error.m +++ /dev/null @@ -1,59 +0,0 @@ -% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. -% -% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) -% -% INPUT: -% -% space: object defining the space of discrete functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% u: vector of dof weights -% uex: function handle to evaluate the exact solution -% graduex: function handle to evaluate the gradient of the exact solution -% hessuex: function handle to evaluate the hessian of the exact solution -% -% OUTPUT: -% -% errh2: error in H^2 norm -% errh1: error in H^1 norm -% errl2: error in L^2 norm -% errh2s: error in H^2 seminorm -% errh1s: error in H^1 seminorm -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software; you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation; either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with Octave; see the file COPYING. If not, see -% . - -function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex) - - if (space.npatch ~= msh.npatch) - error ('The number of patches does not coincide') - end - - for iptc = 1:msh.npatch -% if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; -% else -% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; -% end - [error_h2(iptc), error_h1(iptc), error_l2(iptc), error_h2s(iptc), error_h1s(iptc)] = ... - sp_h2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex, graduex, hessuex); - end - errl2 = sqrt (sum (error_l2 .* error_l2)); - errh1 = sqrt (sum (error_h1 .* error_h1)); - errh1s = sqrt (sum (error_h1s .* error_h1s)); - errh2 = sqrt (sum (error_h2 .* error_h2)); - errh2s = sqrt (sum (error_h2s .* error_h2s)); - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m deleted file mode 100644 index abbbc9ef..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_l2_error.m +++ /dev/null @@ -1,48 +0,0 @@ -% SP_L2_ERROR: Evaluate the error in L^2 norm. -% -% errl2 = sp_l2_error (space, msh, u, uex) -% -% INPUT: -% -% space: object defining the space of discrete functions (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% u: vector of dof weights -% uex: function handle to evaluate the exact solution -% -% OUTPUT: -% -% errl2: error in L^2 norm -% -% Copyright (C) 2015 Rafael Vazquez -% -% This program is free software; you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation; either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with Octave; see the file COPYING. If not, see -% . - -function errl2 = sp_l2_error (space, msh, u, uex) - - if (space.npatch ~= msh.npatch) - error ('The number of patches does not coincide') - end - - for iptc = 1:msh.npatch -% if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; -% else -% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; -% end - error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); - end - errl2 = sqrt (sum (error_l2 .* error_l2)); - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m deleted file mode 100644 index f38b8eec..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1.m +++ /dev/null @@ -1,948 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundaries) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 - -% if (numel (interfaces) > 1 || msh.npatch > 2) -% error ('For now, the implementation only works for two patches') -% end - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface - - sp.ndof_interior = 0; - [interfaces_all, ~] = vertices_struct(boundaries, interfaces); - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces_all) - patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; - sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, boundaries); -%keyboard - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - end - - for intrfc = 1:numel(interfaces) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - %for iptc_on_interface = 1:2 - iptc1 = interfaces(intrfc).patch1; - iptc2 = interfaces(intrfc).patch2; - Cpatch{iptc1}(:,global_indices) = CC_edges{1,intrfc}; - Cpatch{iptc2}(:,global_indices) = CC_edges{2,intrfc}; - %end - end - -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; - end - end - -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - %keyboard - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) - -[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); - -p = space.sp_patch{1}.degree(1); -k = numel(msh.msh_patch{1}.breaks{1})-2; -n= space.sp_patch{1}.sp_univ(1).ndof; - -ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere -ndof_per_vertex=6*ones(1,numel(vertices)); - -all_alpha0=zeros(numel(interfaces_all),2); -all_alpha1=zeros(numel(interfaces_all),2); -all_beta0=zeros(numel(interfaces_all),2); -all_beta1=zeros(numel(interfaces_all),2); -all_t0=zeros(numel(interfaces_all),2); - -%Initialize the cell array of CC_vertices matrices -for ii=1:space.npatch - for jj=numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end -%Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces_all) - if isempty(interfaces_all(jj).patch1) - CC_edges{1,jj} = []; - else - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); - end - if isempty(interfaces_all(jj).patch2) - CC_edges{2,jj} = []; - else - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); - end -end - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -brk = cell (1,msh.ndim); -for j=1:space.npatch - knots = space.sp_patch{j}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1}=[0 1]'; - pts{2}=[0 1]';%pts{2}=[0 1/2 1]' - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - msh_der1{j}=msh_precompute (msh_pts_der1); - derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x (n_pts{1}x n_pts{2}) (rdim->physical space, ndim->parametric space) - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - msh_der2{j}=msh_precompute (msh_pts_der2); - derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} - %In this case (rdim=2) - %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space - %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) - %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) - %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) - %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) - %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) - %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) - %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) - - %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space - %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) - %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) - %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) - %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) - %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) - %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) - %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) - %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) - %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) - %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) - %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) -end - -%Construction of CC_edges -for iref = 1:numel(interfaces_all) - clear patch - if ~isempty(interfaces_all(iref).patch1) - patch(1) = interfaces_all(iref).patch1; %LEFT - side(1) = interfaces_all(iref).side1; %LEFT - end - if ~isempty(interfaces_all(iref).patch2) - patch(2) = interfaces_all(iref).patch2; %RIGHT - side(2) = interfaces_all(iref).side2; %RIGHT - end - nnz_el=find(patch>0); - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = nnz_el % The two patches (L-R) - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); - for idim = 1:msh.ndim - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% if ii==1 && (side(ii)==3 || side(ii)==4) -% disp('done1') -% geo_map_jac{ii}=flip(geo_map_jac{ii}); -% elseif ii==2 && (side(ii)==1 || side(ii)==2) -% disp('done2') -% geo_map_jac{ii}=flip(geo_map_jac{ii}); -% end - end - - if length(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - if side(2)==1 || side(2)==2 - v=grev_pts{2}(:); - else - v=grev_pts{1}(:); - end - ngrev=numel(v); - DuFR_x=reshape(geo_map_jac{1}(1,1,:,:),ngrev,1); %column vector - DuFR_y=reshape(geo_map_jac{1}(2,1,:,:),ngrev,1); %column vector - DvFL_x=reshape(geo_map_jac{2}(1,2,:,:),ngrev,1); %column vector - DvFL_y=reshape(geo_map_jac{2}(2,2,:,:),ngrev,1); %column vector - DvFR_x=reshape(geo_map_jac{1}(1,2,:,:),ngrev,1); %column vector - DvFR_y=reshape(geo_map_jac{1}(2,2,:,:),ngrev,1); %column vector - - A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %keyboard - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); - gamma=3*C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R - - end - - %Saving alphas and betas (first column=L, second column=R) - all_alpha0(iref,:)=alpha0; - all_alpha1(iref,:)=alpha1; - all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (R-L) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now we assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj)* (-1)^(ii-1); %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - if (ii == 2 & interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - ind0_s{iref}=ind0; %saving the indices for later use; - ind1_s{iref}=ind1; - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii};%CORRECT REMOVING THIS? * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); - end - else - n0=n-k; - ndof=n0+n-k-1; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); -% size(CC_edges{ii,iref}) -% keyboard - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 n0-3:n0+1 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:n0-4 n0+2:ndof-2]); - end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - -end - - - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is the interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM=cell(2,numel(vertices)); -V=cell(numel(vertices),1); -E=cell(numel(vertices),1); -%Previously: -%MM=cell(2,nu,numel(vertices)); -%V=cell(nu,numel(vertices)); -%E=cell(nu+1,numel(vertices)); -sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - -for kver=1:numel(vertices) - - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches=[];%vector with indices of patches containing the vertex - ver_patches_nabla={}; %cell array containing jacobians - ver_ind=[];%vector containing local index of vertex in the patch - nu=numel(vertices(kver).interfaces); - - boundary_v=0; - for im=1:nu - inter=vertices(kver).interfaces(im); - if isempty(interfaces_all(inter).side1) | isempty(interfaces_all(inter).side2) - boundary_v=1; - break - end - end - if boundary_v==0 - -% for h=1:numel(vertices(kver).interfaces) -% hint=vertices(kver).interfaces(h); -% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; -% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... -% sides(interfaces(hint).side2,vertices(kver).ind)]; -% end -% ver_patches=unique(ver_patches,'stable'); -% ver_ind=unique(ver_ind,'stable'); - - for im=1:nu %cycle over all the interfaces containing the vertex - inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch - ver_patches=[ver_patches patch_ind1 patch_ind2]; - ver_ind=[ver_ind vertex_ind1 vertex_ind2]; - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1)); - Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,1)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2)); - Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,2)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,3)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,3)); - Duv_F00=-squeeze(derivatives2{patch_ind1}(:,1,2,3)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,3)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,4)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,4)); - Duv_F00=squeeze(derivatives2{patch_ind1}(:,1,2,4)); - Dvv_F00=squeeze(derivatives2{patch_ind1}(:,2,2,4)); - end - %Store the jacobian of F for the left patch - ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; - - t0(im,:)=Dv_F00; - t0p(im,:)=Dvv_F00; - d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... - /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); - d0p(im,:)=((-all_alpha0(inter,1)+all_alpha1(inter,1))*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00+... - (-all_beta0(inter,1)+all_beta1(inter,1))*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... - ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(im,:)=Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,3)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,3)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,4)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,4)); - end - ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; - - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if vertices(kver).ind(im)==1 %the vertex is the left/bottom endpoint of im-th interface - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); - else %the vertex is the right/top endpoint of im-th interface - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end - end - [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); - %ver_ind=unique(ver_ind,'rows','stable'); - - %if the number of patches coincides with the number of interfaces, - %we add one fictional interface coinciding with the first one - %(just for coding-numbering reasons) -% if numel(ver_patches)==nu -% t0(nu+1,:)=t0(1,:); -% t0p(nu+1,:)=t0p(1,:); -% d0(nu+1,:)=d0(1,:); -% d0p(nu+1,:)=d0p(1,:); -% E{kver}{nu+1,1}=E{kver}{1,1}; -% E{kver}{nu+1,2}=E{kver}{1,2}; -% end - - %computing sigma - sigma=0; - for im=1:nu - sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); - end - sigma=1/(sigma/(p*(k+1)*nu)); - - %computing matrices MM and V - for im=1:nu - - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - V{kver}{im}=zeros(n1*n2,6); - im_edges=ceil(find(ind_patch_rep==im)/2); %indices of the edges containing the vertex (local) - im1=im_edges(1); im2=im_edges(2); - if im==2 %works only if the interfaces and patches are ordered in clockwise order - im1=4; im2=1; - end - j=1; - for j1=0:2 - for j2=0:2-j1 %the following computations work in the standard case - d00=(j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; - d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; - d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; - MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; - d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; - d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; - MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; - %V_{i_m,i} - d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; - V{kver}{im}([1, 2, n2+1, n2+2],j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - - j=j+1; - end - end - %size(V{kver}{im}) - %keyboard - if interfaces_all(vertices(kver).interfaces(im1)).patch2==ver_patches(im)%the considered patch is the second patch edge im1 - E1=E{kver}{im1,2}; - else - E1=E{kver}{im1,1}; - end - if interfaces_all(vertices(kver).interfaces(im2)).patch2==ver_patches(im)%the considered patch is the second patch of edge im2 - E2=E{kver}{im2,2}; - else - E2=E{kver}{im2,1}; - end - CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; - %keyboard - end - end - -end - -end - -%TO DO: -%- case of boundary edges - -%TO BE TESTED -%- plots of the functions -%- continuity \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m deleted file mode 100644 index 975c8377..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_curve.m +++ /dev/null @@ -1,423 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') %da scommentare! -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES - -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') -end - - sp.ndof_interior = 0; -% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 - sides = [interfaces(1).side1, interfaces(1).side2]; - for iptc = 1:sp.npatch -% This should be a loop on the interfaces to which the patch belongs - sp_bnd = spaces{iptc}.boundary(sides(iptc)); - interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - - [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - - sp.ndof_interface = ndof; % The number of functions in V^2 - sp.ndof = sp.ndof_interior + sp.ndof_interface; - - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - - global_indices = (sp.ndof_interior+1):sp.ndof; - Cpatch{iptc}(:,global_indices) = CC{iptc}; - end - - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) - - for iref = 1:numel(interfaces) - patch(1) = interfaces(iref).patch1; - patch(2) = interfaces(iref).patch2; - side(1) = interfaces(iref).side1; - side(2) = interfaces(iref).side2; - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now I assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -% Absolute value of the determinant, to make it work for arbitrary orientation -> IMPORTANT! -% geo_map_jac = msh_side_int{ii}.geo_map_jac; %da scommentare! -% alpha{ii} = abs (geopdes_det__ (geo_map_jac)); -% if (side(ii) == 1 || side(ii) == 2) -% numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); -% denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); -% else -% numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); -% denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); -% end -% beta{ii} = numerator ./ denominator; - if ii==1 - alpha{ii}=113*(41 + 18*grev_pts{2}')/6544; - %-113*(41 + 18*tt{2})/6544; - beta{ii}=6622447/4826200 - (249660873*grev_pts{2}')/98937100; - %6622447/4826200 - (249660873*tt{2})/98937100; - elseif ii==2 - alpha{ii}=339*(17 + 8*grev_pts{2}')/6544; - %339*(17 + 8*tt{2})/6544; - beta{ii}=-225776957/197874200 + (54357979*grev_pts{2}')/24734275; - %-225776957/197874200 + (54357979*tt{2})/24734275; - end -% alpha{ii}(:) -% beta{ii}(:) -% pause - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel - val_aux = val * beta{ii}(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad * (tau1 / degu); - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj); - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces(iref).ornt == -1) - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; - CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); - end - - - end - - -%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% -% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R -% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) -% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) -% and the jacobian (jacdet) at the Greville points. The last index -% indicates the Greville point. -% sp_grev(ii) is a structure with the value of the basis functions -% (.shape_functions) at the Greville points. The last index indicates the Greville point. -% The previous one indicates the basis functions that are non-null on the -% element. This also includes functions from the interior. -% The number of the non-vanishing basis functions is in connectivity - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m deleted file mode 100644 index 2cce7ea5..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new.m +++ /dev/null @@ -1,807 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES - -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') -end - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface - - sp.ndof_interior = 0; - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces) - patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; - sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_vertices -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, vertices); - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - end - - for intrfc = 1:numel(interfaces) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - for iptc_on_interface = 1:2 - iptc = interface(intrfc).patches(iptc_on_interface); - Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; - end - end - -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; - end - end - -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, vertices) %based on first Mario's notes (not refinement mask) - -p = space.sp_patch{1}.degree(1); -k=numel(msh.msh_patch{1}.breaks{1})-2; - -all_alpha0=zeros(numel(interfaces),2); -all_alpha1=zeros(numel(interfaces),2); -all_beta0=zeros(numel(interfaces),2); -all_beta1=zeros(numel(interfaces),2); -all_t0=zeros(numel(interfaces),2); - -%Initialize the cell array of CC_vertices matrices -for ii=1:space.npatch - for jj=numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end -%Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces) - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch1), ndof_per_interface(jj)); - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces(jj).patch2), ndof_per_interface(jj)); -end - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -brk = cell (1,msh.ndim); -for j=1:space.npatch - knots = space.sp_patch{j}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1}=[0 1]'; - pts{2}=[0 1]'; - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - derivatives1{j}=msh_precompute (msh_pts_der1); %rdim x ndim x n_pts{1}x n_pts{2} - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - derivatives2{j}=msh_precompute (msh_pts_der2); %rdim x ndim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) - %At this point (check) - %D_u F^j(0,0)=squeeze(derivatives{j}(:,1,1)) - %D_u F^j(0,1)=squeeze(derivatives{j}(:,1,2)) - %D_u F^j(1,0)=squeeze(derivatives{j}(:,1,3)) - %D_u F^j(1,1)=squeeze(derivatives{j}(:,1,4)) - %D_v F^j(0,0)=squeeze(derivatives{j}(:,2,1)) - %D_v F^j(0,1)=squeeze(derivatives{j}(:,2,2)) - %D_v F^j(1,0)=squeeze(derivatives{j}(:,2,3)) - %D_v F^j(1,1)=squeeze(derivatives{j}(:,2,4)) -end - -%Construction of CC_edges -for iref = 1:numel(interfaces) - patch(1) = interfaces(iref).patch1; %LEFT - patch(2) = interfaces(iref).patch2; %RIGHT - side(1) = interfaces(iref).side1; %LEFT - side(2) = interfaces(iref).side2; %RIGHT - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = 1:2 % The two patches (L-R) - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - for idim = 1:msh.ndim - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) - end - - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector - DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector - DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector - DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector - DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector - DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector - if side(2)==1 || side(2)==2 - v=grev_pts{2}'; - else - v=grev_pts{1}'; - end - A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); - gamma=3*C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R - - end - - %Saving alphas and betas (first column=L, second column=R) - all_alpha0(iref,:)=alpha0; - all_alpha1(iref,:)=alpha1; - all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %Saving t(0) - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now I assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces(iref).ornt == -1) %this should be still the same for the multipatch - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - ind0_s{iref}=ind0; %saving the indices for later use; - ind1_s{iref}=ind1; - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); - end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - -end - - - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is he interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -%I actually need to consider the actual parametrization to compute d, t and sigma, don't I? - -for kver=1:numel(vertices) - nu=numel(vertices(kver).patches); - MM=cell(2,nu,numel(vertices)); - V=cell(nu,numel(vertices)); - E=cell(nu+1,numel(vertices)); - for im=1:nu+1 %cycle over all the interfaces containing the vertex (#interfaces=#patches+1, where the last one coincides with the first if the vertex is interior) - inter=vertices(kver).interface(im).glob_ind; %global index of the interface - patch_ind1=vertices(kver).interface(im).patch_i1; %global index of left patch of im-th interface - patch_ind2=vertices(kver).interface(im).patch_i2; %global index of right patch of im-th interface - vertex_ind1=vertices(kver).interface(im).vertex1; %local index of vertex in left patch - vertex_ind2=vertices(kver).interface(im).vertex2; %local index of vertex in right patch - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 %d0 and D0p to be added in other cases (16 cases in total) ...to be moved where we compute edge functions matrices? - case 1 %vertex (0,0) - t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)); - t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,1)); - d0(im,:)=(squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,1,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)))... - /(all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0); - d0p(im,:)=((all_alpha0(inter,1)*(1-0)+all_alpha0(inter,1)*0)*squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,1,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1))... - +(all_alpha0(inter,1)-all_alpha1(inter,1))*squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,1,2,1)-(all_beta0(inter,1)*(1-0)... - +all_beta1(inter,1)*0)*derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,1)... - +(all_beta0(inter,1)-all_beta1(inter,1))*derivatives1{vertices(kver).interface(im).patch_i1}(:,2,1)))... - /((-all_alpha0(inter,1)+all_alpha1(inter,1))^2); - mix_der2(im,:)=derivatives2{vertices(kver).interface(im).patch_i1}(:,1,2,1); - E{im,kver}=CC_edges_discarded{ii,iref}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - case 2 %vertex (1,0) - t0(im,:)=squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,3)); - t0p(im,:)=squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,3)); - case 3 %vertex (1,1) - t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,4)); - t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,4)); - case 4 %vertex (0,1) - t0(im,:)=-squeeze(derivatives1{vertices(kver).interface(im).patch_i1}(:,2,2)); - t0p(im,:)=-squeeze(derivatives2{vertices(kver).interface(im).patch_i1}(:,2,2,2)); - end - end - %compute sigma - sigma=0; - for im=1:nu - vertex_ind=vertices(kver).patches(im).vertex; %local index of the vertex in im-th pacth - patch_ind=vertices(kver).patches(im).patch_i; %global index of the im-th patch - switch vertex_ind - case 1 %vertex (0,0) - sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,1) derivatives1{vertices(kver).patches(im).patch_i}(2,2,1)]); - case 2 %vertex (1,0) - sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,3) derivatives1{vertices(kver).patches(im).patch_i}(2,2,3)]); - case 3 %vertex (1,1) - sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,4) derivatives1{vertices(kver).patches(im).patch_i}(2,2,4)]); - case 4 %vertex (0,1) - sigma=sigma+norm([derivatives1{vertices(kver).patches(im).patch_i}(1,1,2) derivatives1{vertices(kver).patches(im).patch_i}(2,2,2)]); - end - end - sigma=1/(sigma/(p*(k+1)*nu)); - - %computing matrices MM and V - for im=1:nu - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(1); %dimension of t-p space in the patch (dir 1) - n2=space.sp_patch{vertices(kver).patches(im).patch_i}.ndof_dir(2); %dimension of t-p space in the patch (dir 2) - j=0; - for j1=0:2 - for j2=0:2-j1 - d00=(j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im,:)'; - d20_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im,:)'; - d11_a=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im,:)'; - MM{1,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im+1,:)'; - d20_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im+1,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im+1,:)'; - d11_b=t0(im+1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im+1,:)'; - MM{2,im,kver}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; - %V_{i_m,i} - d11_c=t0(im,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im+1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im,:)'; - V{im,kver}=zeros(n1*n2,6); - - side1=interfaces(vertices(kver).interface(im).patch_i1).side1; %side of left patch - switch side1 - case 1 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; %correct that some of these are the already computed ds? - case 2 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - case 3 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - case 4 - V{im,kver}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - end - j=j+1; - end - end - CC_vertices{vertices(kver).patches(im).patch_i,kver} = E{im,kver}*MM{1,im,kver} + E{im+1,kver}*MM{2,im,kver} + V{im,kver}; - end -end - - -%end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m deleted file mode 100644 index 7d095540..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_new2.m +++ /dev/null @@ -1,911 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -% vertices: information about interfaces and patches neighbouring each vertex (to be implemented) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces, vertices) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES - -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') -end - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE CHANGED STARTING FROM HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% We could store the info of interfaces per patch, as in mp_interface - - sp.ndof_interior = 0; - for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces) - patches = [interfaces(intrfc).patch1, interfaces(intrfc).patch2]; - sides = [interfaces(intrfc).side1, interfaces(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - -% EXPECTED OUTPUT FROM compute_coefficients -% ndof_per_interface: number of edge functions on each interface, array of -% size 1 x numel(interfaces); -% CC_edges: cell array of size 2 x numel(interfaces), the two corresponds -% to the two patches on the interface. The matrix CC_edges{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_interface(jj) -% with patch = interfaces(jj).patches(ii); -% ndof_per_vertex: number of vertex functions on each vertex. An array of size numel(vertices) -% CC_vertices: cell array of size npatch x numel(vertices) -% The matrix CC_vertices{ii,jj} has size -% sp.ndof_per_patch(patch) x ndof_per_vertex{jj} -% with patch being the index of the ii-th patch containing vertex jj; -% - -% [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = ... - compute_coefficients (sp, msh, geometry, interfaces, vertices); - - sp.ndof_edges = sum(ndof_per_interface); % Total number of edge functions - sp.ndof_vertices = sum (ndof_per_vertex); % Total number of vertex functions - sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC_* - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - end - - for intrfc = 1:numel(interfaces) - global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); - for iptc_on_interface = 1:2 - iptc = interface(intrfc).patches(iptc_on_interface); - Cpatch{iptc}(:,global_indices) = CC_edges{iptc_on_interface,intrfc}; - end - end - -% Vertices and patches_on_vertex are not defined yet. For now, this only works for one extraordinary point -% The information of which patches share the vertex can be computed with the help of mp_interface - for ivrt = 1%:numel(vertices) - global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + ndof_per_vertex(ivrt); - for iptc = 1:sp.npatch %patches_on_vertex (TO BE CHANGED) - Cpatch{iptc}(:,global_indices) = CC_vertices{iptc,ivrt}; - end - end - -% sp.patches_on_vertex = patches_on_vertex; TO BE DONE - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% I HAVE FINISHED MY CHANGES HERE -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices] = compute_coefficients (space, msh, geometry, interfaces, boundaries) %based on first Mario's notes (not refinement mask) - -[interfaces_all, vertices]=vertices_struct(boundaries, interfaces); - -p = space.sp_patch{1}.degree(1); -k = numel(msh.msh_patch{1}.breaks{1})-2; -n= space.sp_patch{1}.sp_univ{1}.ndof; - -ndof_per_interface=(2*n-2*k-11)*ones(1,numel(interfaces_all)); %works only if the space is degree and regularity are the same everywhere -ndof_per_vertex=6*ones(1,numel(vertices)); - -all_alpha0=zeros(numel(interfaces_all),2); -all_alpha1=zeros(numel(interfaces_all),2); -all_beta0=zeros(numel(interfaces_all),2); -all_beta1=zeros(numel(interfaces_all),2); -all_t0=zeros(numel(interfaces_all),2); - -%Initialize the cell array of CC_vertices matrices -for ii=1:space.npatch - for jj=numel(vertices) - CC_vertices{ii,jj} = sparse (space.ndof_per_patch(ii), ndof_per_vertex(jj)); - end -end -%Initialize the cell array of CC_edges matrices -for jj=1:numel(interfaces_all) - if isempty(interfaces_all(jj).patch1) - CC_edges{1,jj} = []; - else - CC_edges{1,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch1), ndof_per_interface(jj)); - end - if isempty(interfaces_all(jj).patch2) - CC_edges{2,jj} = []; - else - CC_edges{2,jj} = sparse (space.ndof_per_patch(interfaces_all(jj).patch2), ndof_per_interface(jj)); - end -end - -%computing for each patch all the derivatives we possibly need to compute t,d, and sigma -brk = cell (1,msh.ndim); -for j=1:space.npatch - knots = space.sp_patch{j}.knots; - for idim = 1:msh.ndim - brk{idim}=[knots{idim}(1) knots{idim}(end)]; %is this correct? - end - %the following points correspond to the four vertices of the patch - pts{1}=[0 1]'; - pts{2}=[0 1]'; - msh_pts_der1 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',false); - msh_der1{j}=msh_precompute (msh_pts_der1); - derivatives1{j}=msh_der1{j}.geo_map_jac; %rdim x ndim x n_pts{1}x n_pts{2} (rdim->physical space, ndim->parametric space) - msh_pts_der2 = msh_cartesian (brk, pts, [], geometry(j),'boundary', true, 'der2',true); - msh_der2{j}=msh_precompute (msh_pts_der2); - derivatives2{j}=msh_der1{j}.geo_map_der2; %rdim x ndim x ndim x n_pts{1}x n_pts{2} - %In this case (rdim=2) - %D_u F^j(0,0)=squeeze(derivatives1{j}(:,1,1,1)) %this contains both components in the physical space - %D_u F^j(0,1)=squeeze(derivatives1{j}(:,1,1,2)) - %D_u F^j(1,0)=squeeze(derivatives1{j}(:,1,2,1)) - %D_u F^j(1,1)=squeeze(derivatives1{j}(:,1,2,2)) - %D_v F^j(0,0)=squeeze(derivatives1{j}(:,2,1,1)) - %D_v F^j(0,1)=squeeze(derivatives1{j}(:,2,1,2)) - %D_v F^j(1,0)=squeeze(derivatives1{j}(:,2,2,1)) - %D_v F^j(1,1)=squeeze(derivatives1{j}(:,2,2,2)) - - %D_uu F^j(0,0)=squeeze(derivatives2{j}(:,1,1,1,1)) %this contains both components in the physical space - %D_uu F^j(0,1)=squeeze(derivatives2{j}(:,1,1,1,2)) - %D_uu F^j(1,0)=squeeze(derivatives2{j}(:,1,1,2,1)) - %D_uu F^j(1,1)=squeeze(derivatives2{j}(:,1,1,2,2)) - %D_uv F^j(0,0)=squeeze(derivatives2{j}(:,1,2,1,1)) - %D_uv F^j(0,1)=squeeze(derivatives2{j}(:,1,2,1,2)) - %D_uv F^j(1,0)=squeeze(derivatives2{j}(:,1,2,2,1)) - %D_uv F^j(1,1)=squeeze(derivatives2{j}(:,1,2,2,2)) - %D_vv F^j(0,0)=squeeze(derivatives2{j}(:,2,2,1,1)) - %D_vv F^j(0,1)=squeeze(derivatives2{j}(:,2,2,1,2)) - %D_vv F^j(1,0)=squeeze(derivatives2{j}(:,2,2,2,1)) - %D_vv F^j(1,1)=squeeze(derivatives2{j}(:,2,2,2,2)) -end - -%Construction of CC_edges -for iref = 1:numel(interfaces_all) - if ~isempty(interfaces_all(jj).patch1) - patch(1) = interfaces_all(iref).patch1; %LEFT - side(1) = interfaces_all(iref).side1; %LEFT - end - if ~isempty(interfaces_all(jj).patch2) - patch(2) = interfaces_all(iref).patch2; %RIGHT - side(2) = interfaces_all(iref).side2; %RIGHT - end - nnz_el=find(patch>0); - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = nnz_el % The two patches (L-R) - %in this cycle we must add to the already existing CC_vertices, the part of the "discarded" interface functions - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - for idim = 1:msh.ndim - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) - end - - if nnz(patch)==2 %as it is placed now, this check computes the matrices corresponding only to interior edges - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector - DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector - DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector - DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector - DvFR_x=squeeze(geo_map_jac{2}(1,2,:,:)); %column vector - DvFR_y=squeeze(geo_map_jac{2}(2,2,:,:)); %column vector - if side(2)==1 || side(2)==2 - v=grev_pts{2}'; - else - v=grev_pts{1}'; - end - A_full=[(1-v).*DvFL_x v.*DvFL_x (1-v).*DuFR_x v.*DuFR_x (1-v).^2.*DvFR_x 2*(1-v).*v.*DvFR_x v.^2.*DvFR_x;... - (1-v).*DvFL_y v.*DvFL_y (1-v).*DuFR_y v.*DuFR_y (1-v).^2.*DvFR_y 2*(1-v).*v.*DvFR_y v.^2.*DvFR_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %STEP 4 - Normalizing the alphas - %C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - % +alpha0_n(1)^2+alpha0_n(2)^2; - %C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - %gamma=-C2/(2*C1); - C1=alpha0_n(1)^2+alpha0_n(1)*alpha1_n(1)+alpha1_n(1)^2+alpha0_n(2)^2+alpha0_n(2)*alpha1_n(2)+alpha1_n(2)^2; - C2=alpha0_n(1)+alpha1_n(1)+alpha0_n(2)+alpha1_n(2); - gamma=3*C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R - - end - - %Saving alphas and betas (first column=L, second column=R) - all_alpha0(iref,:)=alpha0; - all_alpha1(iref,:)=alpha1; - all_beta0(iref,:)=beta0; - all_beta1(iref,:)=beta1; - %Saving t(0) - - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now we assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = -val * beta{ii}(jj); %added a minus, as in (6) of multipatch paper - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu)^2; %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj) * (-1)^ii; %with the multipatch settings must be multiplied by -1 for left patch; - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC_edges{ii,iref} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces_all(iref).ornt == -1) %this should be still the same for the multipatch - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - ind0_s{iref}=ind0; %saving the indices for later use; - ind1_s{iref}=ind1; - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC_edges{ii,iref}(ind0,1:sp0_struct.ndof) = coeff0{ii}; %coefficients of trace basis functions... - CC_edges{ii,iref}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC_edges{ii,iref}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); %...and derivative basis functions (associated to iref-th interface) - - %keeping the part of the "actually active" edge functions, the remaining part saved in CC_edges_discarded - CC_edges_discarded{ii,iref}=CC_edges{ii,iref}(:,[1 2 3 sp0_struct.ndof-2:sp0_struct.ndof+2 ndof-1 ndof]); %dimension: n^2 x 10 - CC_edges{ii,iref}=CC_edges{ii,iref}(:,[4:sp0_struct.ndof-3 sp0_struct.ndof+3:ndof-2]); - end - end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - -end - - - -%We assume that the local numbering of interfaces and patches is such that -%vertices(kver).interface(im) is the interface between -%vertices(kver).patches(im) and vertices(kver).patches(im+1) -MM=cell(2,numel(vertices)); -V=cell(numel(vertices),1); -E=cell(numel(vertices),1); -%Previously: -%MM=cell(2,nu,numel(vertices)); -%V=cell(nu,numel(vertices)); -%E=cell(nu+1,numel(vertices)); -sides=[1 4;2 3;1 2;4 3]; %on i-th row the indices of the endpoints of the i-th side (bottom-up, left-right) - -for kver=1:numel(vertices) - - %Everything must be updated by using interfaces_all instead of interfaces TO DO - ver_patches=[];%vector with indices of patches containing the vertex - ver_patches_nabla={}; %cell array containing jacobians - ver_ind=[];%vector containing local index of vertex in the patch - nu=numel(vertices(kver).interfaces); - -% for h=1:numel(vertices(kver).interfaces) -% hint=vertices(kver).interfaces(h); -% ver_patches=[ver_patches interfaces(hint).patch1 interfaces(hint).patch2]; -% ver_ind=[ver_ind sides(interfaces(hint).side1,vertices(kver).ind)... -% sides(interfaces(hint).side2,vertices(kver).ind)]; -% end -% ver_patches=unique(ver_patches,'stable'); -% ver_ind=unique(ver_ind,'stable'); - - for im=1:nu %cycle over all the interfaces containing the vertex - inter=vertices(kver).interfaces(im); %global index of the interface - patch_ind1=interfaces_all(inter).patch1; %global index of left patch of im-th interface - patch_ind2=interfaces_all(inter).patch2; %global index of right patch of im-th interface - vertex_ind1=sides(interfaces_all(inter).side1,vertices(kver).ind(im)); %local index of vertex in left patch - vertex_ind2=sides(interfaces_all(inter).side2,vertices(kver).ind(im)); %local index of vertex in right patch - ver_patches=[ver_patches patch_ind1 patch_ind2]; - ver_ind=[ver_ind vertex_ind1 vertex_ind2]; - %compute t(0) and t'(0), d(0) and d'(0) - switch vertex_ind1 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,1,1)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,1,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind1}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,1,2)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,1,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,1,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind1}(:,2,2,1)); - Duv_F00=-squeeze(derivatives2{j}(:,1,2,2,1)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,1)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind1}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind1}(:,2,2,2)); - Duv_F00=squeeze(derivatives2{j}(:,1,2,2,2)); - Dvv_F00=squeeze(derivatives2{j}(:,2,2,2,2)); - end - %Store the jacobian of F for the left patch - ver_patches_nabla{2*im-1}=[Du_F00 Dv_F00]; - - t0(im,:)=Dv_F00; - t0p(im,:)=Dvv_F00; - d0(im,:)=(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)... - /(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0); - d0p(im,:)=(-all_alpha0(inter,1)*(Du_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dv_F00)+... - (all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)*(Duv_F00... - -all_beta0(inter,1)*Dv_F00+(all_beta0(inter,1)*(1-0)+all_beta1(inter,1)*0)*Dvv_F00... - ))/(all_alpha0(inter,1)*(1-0)+all_alpha1(inter,1)*0)^2; - mix_der2(im,:)=Duv_F00; - %We need to get the jacobian also for the right patch - switch vertex_ind2 - case 1 %vertex (0,0) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,1,1)); - case 2 %vertex (0,1) - Du_F00=squeeze(derivatives1{patch_ind2}(:,1,1,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,1,2)); - case 3 %vertex (1,0) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,1)); - Dv_F00=squeeze(derivatives1{patch_ind2}(:,2,2,1)); - case 4 %vertex (1,1) - Du_F00=-squeeze(derivatives1{patch_ind2}(:,1,2,2)); - Dv_F00=-squeeze(derivatives1{patch_ind2}(:,2,2,2)); - end - ver_patches_nabla{2*im}=[Du_F00 Dv_F00]; - - %Pick the correct part of CC_edges_discarded %TO BE FIXED - if vertices(kver).ind(im)==1 - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[1 2 3 7 8]); %part of the matrix corresponding to edge functions close to the vertex - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[1 2 3 7 8]); - else - E{kver}{im,1}=CC_edges_discarded{1,inter}(:,[4 5 6 9 10]); - E{kver}{im,2}=CC_edges_discarded{2,inter}(:,[4 5 6 9 10]); - end - end - [ver_patches, ind_patch_sigma, ind_patch_rep]=unique(ver_patches,'stable'); - %ver_ind=unique(ver_ind,'rows','stable'); - - %if the number of patches coincides with the number of interfaces, - %we add one fictional interface coinciding with the first one - %(just for coding-numbering reasons) - if numel(ver_patches)==nu - t0(nu+1,:)=t0(1,:); - t0p(nu+1,:)=t0p(1,:); - d0(nu+1,:)=d0(1,:); - d0p(nu+1,:)=d0p(1,:); - E{kver}{nu,1}=E{kver}{1,1}; - E{kver}{nu,2}=E{kver}{1,2}; - end - - %computing sigma - sigma=0; - for im=1:nu - sigma=sigma+norm(ver_patches_nabla{ind_patch_sigma(im)},Inf); - end - sigma=1/(sigma/(p*(k+1)*nu)); - - %computing matrices MM and V - for im=1:nu - %assemble matrix (not final: Ms and Vs, then updated with the "discarded parts" of edge functions) - n1=space.sp_patch{ver_patches(im)}.ndof_dir(1); %dimension of tensor-product space in the patch (dir 1) - n2=space.sp_patch{ver_patches(im)}.ndof_dir(2); %dimension of tensor-product space in the patch (dir 2) - im_edges=floor(find(ind_patch_rep==im)/2); %global indices of the edges - im1=im_edges(1); im2=im_edges(2); - j=0; - for j1=0:2 - for j2=0:2-j1 %the following computations work in the standard case - d00=(j1==0)*(j2==0); - %M_{i_{m-1},i} - d10_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im1,:)'; - d20_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im1,:)'; - d01_a=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im1,:)'; - d11_a=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im1,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im1,:)'; - MM{1,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_a/(p*(k+1)), d00+2*d10_a/(p*(k+1))+d20_a/(p*(p-1)*(k+1)^2),... - d01_a/(p*(k+1)), d01_a/(p*(k+1))+d11_a/(p*(p-1)*(k+1)^2)]'; - %M_{i_{m+1},i} - d10_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0(im2,:)'; - d20_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*t0p(im2,:)'; - d01_b=[(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0(im2,:)'; - d11_b=t0(im2,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*d0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*d0p(im2,:)'; - MM{2,kver}{im}(:,j)=sigma^(j1+j2)*[d00, d00+d10_b/(p*(k+1)), d00+2*d10_b/(p*(k+1))+d20_b/(p*(p-1)*(k+1)^2),... - d01_b/(p*(k+1)), d01_b/(p*(k+1))+d11_b/(p*(p-1)*(k+1)^2)]'; - %V_{i_m,i} - d11_c=t0(im1,:)*[(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]*t0(im2,:)'+... - [(j1==1)*(j2==0), (j1==0)*(j2==1)]*mix_der2(im1,:)'; - V{kver}{im}=zeros(n1*n2,6); - V{kver}{im}([1, 2, n2+1, n2+2],j)=[d00, d00+d10_b/(p*(k+1)), d00+d10_a/(p*(k+1)),... - d00+ (d10_a+d10_b+d11_c/(p*(k+1)))/(p*(k+1))]'; - j=j+1; - end - end - if interfaces_all(vertices(kver).interfaces(im1)).side2==ver_patches(im)%the considered patch is to the right of edge im1 - E1=E{kver}{im1,2}; - else - E1=E{kver}{im1,1}; - end - if interfaces_all(vertices(kver).interfaces(im2)).side2==ver_patches(im)%the considered patch is to the right of edge im2 - E2=E{kver}{im2,2}; - else - E2=E{kver}{im2,1}; - end - CC_vertices{ver_patches(im),kver} = E1*MM{1,kver}{im} + E2*MM{2,kver}{im} - V{kver}{im};%E{kver}{im1,2}*MM{1,kver}{im} + E{kver}{im2,1}*MM{2,kver}{im} - V{kver}{im}; - end -end - - -end - -%TO DO: -%- case of boundary edges -%- compute number of ndof per edge, per vertex - -%TO BE TESTED -%- number of functions -%- plots of the functions -%- continuity \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m deleted file mode 100644 index fb4aee5c..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_old.m +++ /dev/null @@ -1,409 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1 (spaces, msh, geometry, interfaces, boundary_interfaces) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - for iptc = 1:numel(geometry) - if (any (geometry(iptc).nurbs.order > 2)) - error ('For now, only bilinear patches are implemented') - end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES - -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') -end - - sp.ndof_interior = 0; -% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 - sides = [interfaces(1).side1, interfaces(1).side2]; - for iptc = 1:sp.npatch -% This should be a loop on the interfaces to which the patch belongs - sp_bnd = spaces{iptc}.boundary(sides(iptc)); - interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - - [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - - sp.ndof_interface = ndof; % The number of functions in V^2 - sp.ndof = sp.ndof_interior + sp.ndof_interface; - - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - - global_indices = (sp.ndof_interior+1):sp.ndof; - Cpatch{iptc}(:,global_indices) = CC{iptc}; - end - - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) - - for iref = 1:numel(interfaces) - patch(1) = interfaces(iref).patch1; - patch(2) = interfaces(iref).patch2; - side(1) = interfaces(iref).side1; - side(2) = interfaces(iref).side2; - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now I assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -% Absolute value of the determinant, to make it work for arbitrary orientation - geo_map_jac = msh_side_int{ii}.geo_map_jac; - alpha{ii} = abs (geopdes_det__ (geo_map_jac)); - if (side(ii) == 1 || side(ii) == 2) - numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - denominator = reshape (sum (geo_map_jac(:,2,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - else - numerator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,2,:,:), 1), msh_side(ii).nel, 1); - denominator = reshape (sum (geo_map_jac(:,1,:,:) .* geo_map_jac(:,1,:,:), 1), msh_side(ii).nel, 1); - end - beta{ii} = numerator ./ denominator; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel - val_aux = val * beta{ii}(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj); - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces(iref).ornt == -1) - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; - CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); - end - - - end - - -%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% -% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R -% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) -% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) -% and the jacobian (jacdet) at the Greville points. The last index -% indicates the Greville point. -% sp_grev(ii) is a structure with the value of the basis functions -% (.shape_functions) at the Greville points. The last index indicates the Greville point. -% The previous one indicates the basis functions that are non-null on the -% element. This also includes functions from the interior. -% The number of the non-vanishing basis functions is in connectivity - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m deleted file mode 100644 index f0bc345b..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_multipatch_C1_twopatch.m +++ /dev/null @@ -1,592 +0,0 @@ -% SP_MULTIPATCH_C1: Constructor of the class for multipatch spaces with C1 continuity -% -% BETA VERSION. For now, it will only work with two patches -% -% sp = sp_multipatch_C1 (spaces, msh, interfaces) -%%%XXXX sp = sp_multipatch_C1 (spaces, msh, interfaces, boundary_interfaces) -% -% INPUTS: -% -% spaces: cell-array of space objects, one for each patch (see sp_scalar, sp_vector) -% msh: mesh object that defines the multipatch mesh (see msh_multipatch) -% interfaces: information of connectivity between patches (see mp_geo_load) -%%%XXXX boundary_interfaces: information of connectivity between boundary patches (see mp_geo_load) -% -% OUTPUT: -% -% sp: object representing the discrete function space of vector-valued functions, with the following fields and methods: -% -% FIELD_NAME (SIZE) DESCRIPTION -% npatch (scalar) number of patches -% ncomp (scalar) number of components of the functions of the space (always equal to one) -% ndof (scalar) total number of degrees of freedom after gluing patches together -% ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing -% interior_dofs_per_patch -% ndof_interior -% ndof_interface -% sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar and sp_vector) -% gnum (1 x npatch cell-array) global numbering of the degress of freedom (see mp_interface) -% constructor function handle function handle to construct the same discrete space in a different msh -% -% METHODS -% Methods that give a structure with all the functions computed in a certain subset of the mesh -% sp_evaluate_element_list: compute basis functions (and derivatives) in a given list of elements -% -% Methods for post-processing, that require a computed vector of degrees of freedom -% sp_l2_error: compute the error in L2 norm -% sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm -% sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% -% Methods for basic connectivity operations -% sp_get_basis_functions: compute the functions that do not vanish in a given list of elements -% sp_get_cells: compute the cells on which a list of functions do not vanish -% sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one -% -% Copyright (C) 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp = sp_multipatch_C1_twopatch (spaces, msh, geometry, interfaces, boundary_interfaces) - - if (~all (cellfun (@(x) isa (x, 'sp_scalar'), spaces))) - error ('All the spaces in the array should be of the same class') - end - aux = struct ([spaces{:}]); - - sp.npatch = numel (spaces); - if (sp.npatch ~= msh.npatch) - error ('The list of spaces does not correspond to the mesh') - end - - if (msh.ndim ~= 2 || msh.rdim ~= 2) - error ('Only implemented for planar surfaces') - end - - - for iptc = 1:numel(geometry) -% if (any (geometry(iptc).nurbs.order > 2)) -% error ('For now, only bilinear patches are implemented') -% end - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - mult = cellfun (@histc, knots, breaks, 'UniformOutput', false); - if (any ([mult{:}] < 2)) - error ('The regularity should be at most degree minus two') - end - for idim = 1:2 - if (any (mult{idim}(2:end-1) > spaces{iptc}.degree(idim) - 1)) - error ('The regularity should not be lower than one') - end - end - end - - - sp.ncomp = spaces{1}.ncomp; - sp.transform = spaces{1}.transform; - - if (~all ([aux.ncomp] == 1)) - error ('The number of components should be the same for all the spaces, and equal to one') - end - for iptc = 1:sp.npatch - if (~strcmpi (spaces{iptc}.transform, 'grad-preserving')) - error ('The transform to the physical domain should be the same for all the spaces, and the grad-preserving one') - end - if (~strcmpi (spaces{iptc}.space_type, 'spline')) - error ('C1 continuity is only implemented for splines, not for NURBS') - end - end - - sp.ndof = 0; - sp.ndof_per_patch = [aux.ndof]; - sp.sp_patch = spaces; - -% Assuming that the starting space has degree p and regularity r, -% r <= p-2, we compute the knot vectors of the auxiliary spaces: -% knots0: degree p, regularity r+1. -% knots1: degree p-1, regularity r. - - knots0 = cell (sp.npatch, 1); knots1 = knots0; - for iptc = 1:sp.npatch - knots = spaces{iptc}.knots; - breaks = cellfun (@unique, knots, 'UniformOutput', false); - for idim = 1:msh.ndim - mult = histc (knots{idim}, breaks{idim}); - mult0{idim} = mult; mult0{idim}(2:end-1) = mult(2:end-1) - 1; - mult1{idim} = mult - 1; - end - knots0{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree, mult0); - knots1{iptc} = kntbrkdegmult (breaks, spaces{iptc}.degree-1, mult1); - end - sp.knots0_patches = knots0; - sp.knots1_patches = knots1; - -% Computation of the number of degrees of freedom -% We need to give a global numbering to the C^1 basis functions -% We start numbering those away from the interface (V^1) patch by patch -% And then generate the numbering for the functions close to the interface (V^2) - -% Compute the local indices of the functions in V^1 -% and sum them up to get the whole space V^1 -% XXX FOR NOW ONLY FOR TWO PATCHES - -if (numel (interfaces) > 1 || msh.npatch > 2) - error ('For now, the implementation only works for two patches') -end - - sp.ndof_interior = 0; -% Assuming that interfaces(1).patch1 = 1, interfaces(1).patch2 = 2 - sides = [interfaces(1).side1, interfaces(1).side2]; - for iptc = 1:sp.npatch -% This should be a loop on the interfaces to which the patch belongs - sp_bnd = spaces{iptc}.boundary(sides(iptc)); - interior_dofs = setdiff (1:spaces{iptc}.ndof, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - sp.interior_dofs_per_patch{iptc} = interior_dofs; % An array with the indices - sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); - end - - [ndof, CC] = compute_coefficients (sp, msh, geometry, interfaces); - - sp.ndof_interface = ndof; % The number of functions in V^2 - sp.ndof = sp.ndof_interior + sp.ndof_interface; - - -% Computation of the coefficients for basis change -% The matrix Cpatch{iptc} is a matrix of size ndof_per_patch(iptc) x ndof -% The coefficients for basis change have been stored in CC - - Cpatch = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch - Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... - speye (numel (sp.interior_dofs_per_patch{iptc})); - - global_indices = (sp.ndof_interior+1):sp.ndof; - Cpatch{iptc}(:,global_indices) = CC{iptc}; - end - - sp.interfaces = interfaces; - sp.Cpatch = Cpatch; - sp.geometry = geometry; % I store this for simplicity - -% XXXX No boundary for now -% % Boundary construction -% if (nargin == 4 && ~isempty (msh.boundary) && ~isempty (spaces{1}.boundary)) -% sp_bnd = cell (msh.boundary.npatch, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% sp_bnd{iptc} = spaces{patch_number}.boundary(side_number); -% end -% sp.boundary = sp_multipatch (sp_bnd, msh.boundary, boundary_interfaces); -% -% dofs = zeros (sp.boundary.ndof, 1); -% boundary_orientation = []; %boundary_orient = zeros (sp.boundary.ndof, 1); -% for iptc = 1:msh.boundary.npatch -% patch_number = msh.boundary.patch_numbers(iptc); -% side_number = msh.boundary.side_numbers(iptc); -% dofs(sp.boundary.gnum{iptc}) = sp.gnum{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% if (~isempty (sp.boundary.dofs_ornt)) -% boundary_orientation(sp.boundary.gnum{iptc}) = sp.boundary.dofs_ornt{iptc} .* ... -% sp.dofs_ornt{patch_number}(sp.sp_patch{patch_number}.boundary(side_number).dofs); -% end -% end -% sp.boundary.dofs = dofs; -% sp.boundary.boundary_orientation = boundary_orientation; -% -% else -% sp.boundary = []; -% end -% -% sp.dofs = []; -% sp.boundary_orientation = []; - - sp.constructor = @(MSH) sp_multipatch_C1 (patches_constructor(spaces, MSH), MSH, geometry, interfaces); - function spaux = patches_constructor (spaces, MSH) - for ipatch = 1:MSH.npatch - spaux{ipatch} = spaces{ipatch}.constructor(MSH.msh_patch{ipatch}); - end - end - - sp = class (sp, 'sp_multipatch_C1_twopatch'); - -end - - -% There are some issues related to the orientation. -% I am taking the absolute value of alpha -% And for val_grad, I have to change the sign for coeff2, but not for coeff1 -% But everything seems to work!!! - -function [ndof, CC] = compute_coefficients (space, msh, geometry, interfaces) %based on first Mario's notes (not refinement mask) - - - for iref = 1:numel(interfaces) - patch(1) = interfaces(iref).patch1; - patch(2) = interfaces(iref).patch2; - side(1) = interfaces(iref).side1; - side(2) = interfaces(iref).side2; - - %STEP 2 - Stuff necessary to evaluate the geo_mapping and its derivatives - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - for idim = 1:msh.ndim - %Greville points for G^1 conditions system - geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; - p1=geometry(patch(ii)).nurbs.order(1); - aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; - geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; - p2=geometry(patch(ii)).nurbs.order(2); - aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; - grev_pts{1}=aveknt(aug_geo_knot1,p1+1); - grev_pts{2}=aveknt(aug_geo_knot2,p2+1); - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); - geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) - end - - %STEP 3 - Assembling and solving G^1 conditions system %this must depend on orientation! - DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector - DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector - DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector - DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector - DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector - DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector - if side(2)==1 || side(2)==2 - v=grev_pts{2}'; - else - v=grev_pts{1}'; - end - A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... - (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; - if rank(A_full)==6 - A=A_full(:,2:end); - b=-A_full(:,1); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=sols(1); %R - alpha0_n(1)=sols(2); %L - alpha1_n(1)=sols(3); %L - beta0_n=sols(4); - beta1_n=sols(5); - beta2_n=sols(6); - else - A=A_full(:,3:end); - b=-sum(A_full(:,1:2),2); - sols=A\b; - alpha0_n(2)=1; %R - alpha1_n(2)=1; %R - alpha0_n(1)=sols(1); %L - alpha1_n(1)=sols(2); %L - beta0_n=sols(3); - beta1_n=sols(4); - beta2_n=sols(5); - end - - %STEP 4 - Normalizing the alphas - C1=((alpha1_n(1)-alpha0_n(1))^2)/3+((alpha1_n(2)-alpha0_n(2))^2)/3 + (alpha1_n(1)-alpha0_n(1))*alpha0_n(1)+(alpha1_n(2)-alpha0_n(2))*alpha0_n(2)... - +alpha0_n(1)^2+alpha0_n(2)^2; - C2=(alpha1_n(1)-alpha0_n(1))-(alpha1_n(2)-alpha0_n(2))+2*alpha0_n(1)-2*alpha0_n(2); - gamma=-C2/(2*C1); - alpha0(2)=alpha0_n(2)*gamma; %R - alpha1(2)=alpha1_n(2)*gamma; %R - alpha0(1)=alpha0_n(1)*gamma; %L - alpha1(1)=alpha1_n(1)*gamma; %L - bbeta0=beta0_n*gamma; - bbeta1=beta1_n*gamma; - bbeta2=beta2_n*gamma; - - - %STEP 5 - Computing the betas - %alphas and beta evaluated at 0,1,1/2 - alpha_L_0=alpha0(1); %alpha_L(0) - alpha_L_1=alpha1(1); %alpha_L(1) - alpha_L_12=(alpha0(1)+alpha1(1))/2; %alpha_L(1/2) - alpha_R_0=alpha0(2); %alpha_L(0) - alpha_R_1=alpha1(2); %alpha_L(1) - alpha_R_12=(alpha0(2)+alpha1(2))/2; %alpha_L(1/2) - beta_0=bbeta0; %beta(0) - beta_1=bbeta2; %beta(1) - beta_12=(bbeta0+bbeta2)/4+bbeta1/2; %beta(1/2) - - %Computing the matrix of the system considering the relationship between beta^L, beta^R and beta - M=[alpha_L_0 0 -alpha_R_0 0; 0 alpha_L_1 0 -alpha_R_1; alpha_L_12/2 alpha_L_12/2 -alpha_R_12/2 -alpha_R_12/2]; - - if rank(M)==3 - - %Computing beta1_L, beta0_R, beta1_R in terms of beta0_L - quant1=(alpha_R_12/2-(alpha_R_0*alpha_L_12)/(2*alpha_L_0))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - quant2=(beta_12-(beta_0*alpha_L_12)/(2*alpha_L_0)-(beta_1*alpha_L_12)/(2*alpha_L_1))/((alpha_R_1*alpha_L_12)/(2*alpha_L_1)-alpha_R_12/2); - - %beta1_L=a+b*beta0_L, beta0_R=c+d*beta0_L, beta1_R=e+f*beta0_L, where - a=quant2; b=quant1; - c=beta_0/alpha_L_0; d=alpha_R_0/alpha_L_0; - e=(beta_1+alpha_R_1*quant2)/alpha_L_1; f=alpha_R_1*quant1/alpha_L_1; - - %We determine beta0_L by minimizing the sum of the norms of beta_L and beta_R - C1=((b-1)^2)/3+(b-1)+((f-d)^2)/3+(f-d)*d+d^2+1; - C2=2*a*(b-1)/3+a+2*(e-c)*(f-d)/3+(e-c)*d+(f-d)*c+2*c*d; - beta0(1)=-C2/(2*C1); %L - beta1(1)=a+b*beta0(1); %L - beta0(2)=c+d*beta0(1); %R - beta1(2)=e+f*beta0(1); %R - - else - - %Computing beta0_R in terms of beta0_L and beta1_R in terms of beta1_L: - %beta0_R=a+b*beta0_L, beta1_R=c+d*beta1_L, where - a=beta_0/alpha_L_0; b=alpha_R_0/alpha_L_0; - c=beta_1/alpha_L_1; d=alpha_R_1/alpha_L_1; - - %We determine beta0_L and beta_1_L by minimizing the sum of the norms of beta_L and beta_R - %The resuting system is - M2=[2*(1+b^2) 1+b*d; 1+b*d 2*(1+d^2)]; - M2b=[-b*c-2*a*b; -a*d-2*c*d]; - sol=M2\M2b; - beta0(1)= sol(1); %L - beta1(1)= sol(2); %L - beta0(2)= a+b*beta0(1); %R - beta1(2)= c+d*beta1(1); %R - - end - - -% Compute the Greville points, and the auxiliary mesh and space objects - for ii = 1:2 % The two patches (L-R) - brk = cell (1,msh.ndim); - knots = space.sp_patch{patch(ii)}.knots; - -% The knot vectors for the N0 and N1 basis functions, as in Mario's notation -% Only univariate knot vectors are computed -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] - ind2 = ceil (side(ii)/2); - ind1 = setdiff (1:msh.ndim, ind2); - - degree = space.sp_patch{patch(1)}.degree(ind1); - knots0 = space.knots0_patches{patch(ii)}{ind1}; - knots1 = space.knots1_patches{patch(ii)}{ind1}; - for idim = 1:msh.ndim - grev_pts{idim} = aveknt (knots{idim}, space.sp_patch{patch(ii)}.degree(idim)+1); - grev_pts{idim} = grev_pts{idim}(:)'; - if (numel(grev_pts{idim}) > 1) - brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; - else - brk{idim} = [knots{idim}(1) knots{idim}(end)]; - end - end - msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); - -% Degree and first length in the direction normal to the interface - ind2 = ceil (side(ii)/2); - degu = space.sp_patch{patch(ii)}.degree(ind2); - knt = unique (space.sp_patch{patch(ii)}.knots{ind2}); - if (mod (side(ii), 2) == 1) - tau1 = knt(2) - knt(1); - else - tau1 = knt(end) - knt(end-1); - end - -% For now I assume that the orientation is as in the paper, and we do not need any reordering -%XXXX [sp_bnd(2), msh_side(2)] = reorder_elements_and_quad_points (sp_bnd(2), msh_side(2), interfaces(iref), ndim); -% msh_side contains only the univariate parametrization of the boundary (dependence on u) -% msh_side_int contains information for the bivariate parametrization (dependence on u and v) -% sp_grev contains the value and derivatives of the basis functions, at the Greville points - msh_side(ii) = msh_eval_boundary_side (msh_grev, side(ii)); - msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); - sp_aux = space.sp_patch{patch(ii)}.constructor (msh_side_int{ii}); - msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% sp_grev = sp_precompute_param (sp_aux, msh_side_int{ii}, 'value', true, 'gradient', true); % This could be done in just one element - -% The univariate spaces for the basis functions N^{p,r+1} (knots0) and N^{p-1,r} (knots1) - sp0 = sp_bspline (knots0, degree, msh_grev.boundary(side(ii))); - sp1 = sp_bspline (knots1, degree-1, msh_grev.boundary(side(ii))); - sp0_struct = sp_precompute_param (sp0, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - sp1_struct = sp_precompute_param (sp1, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% The univariate space for the basis functions N^{p,r} on the interface -% spn = space.sp_patch{patch(ii)}.boundary(side(ii)).constructor(msh_grev.boundary(side(ii))) - ind = [2 2 1 1]; - knotsn = knots{ind(side(ii))}; - spn = sp_bspline (knotsn, degree, msh_grev.boundary(side(ii))); - spn_struct = sp_precompute_param (spn, msh_grev.boundary(side(ii)), 'value', true, 'gradient', true); - -% Matrix for the linear systems, (14)-(16) in Mario's notes - A = sparse (msh_side(ii).nel, msh_side(ii).nel); - for jj = 1:msh_side(ii).nel - A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); - end - -%alphas and betas - alpha{ii}=abs(alpha0(ii)*(1-grev_pts{2}')+alpha1(ii)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation - beta{ii}=beta0(ii)*(1-grev_pts{2}')+beta1(ii)*grev_pts{2}'; - -% RHS for the first linear system, (14) in Mario's notes - rhss = sparse (msh_side(ii).nel, sp0_struct.ndof); - for jj = 1:msh_side(ii).nel - rhss(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_functions(:,:,jj); - end - coeff0{ii} = A \ rhss; - coeff0{ii}(abs(coeff0{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the second linear system, (15) in Mario's notes - rhsb = sparse (msh_side(ii).nel, sp0_struct.ndof); - if (side(ii) == 1) %paper case - val_grad = sp_aux.sp_univ(1).shape_function_gradients(2); - elseif (side(ii) == 2) - val_grad = sp_aux.sp_univ(1).shape_function_gradients(end-1); - elseif (side(ii) == 3) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(2); - elseif (side(ii) == 4) - val_grad = sp_aux.sp_univ(2).shape_function_gradients(end-1); - end - val = val_grad * (tau1 / degu)^2; - for jj = 1:msh_side(ii).nel %paper case - check beta - val_aux = val * beta{ii}(jj); - rhsb(jj,sp0_struct.connectivity(:,jj)) = sp0_struct.shape_function_gradients(:,:,:,jj) * val_aux; - end - rhsb = rhsb + rhss; - coeff1{ii} = A \ rhsb; - coeff1{ii}(abs(coeff1{ii}) < 1e-12) = 0; % Make more sparse - -% RHS for the third linear system, (16) in Mario's notes -% We need this change of sign to make it work for general orientation. -% I don't understand why we don't need it in the previous system. - val_grad = val_grad * (-1)^(side(ii)+1); - - rhsc = sparse (msh_side(ii).nel, sp1_struct.ndof); - val = val_grad* (tau1 / degu); %WARNING: WE DIVIDED BY tau1/degu, which REQUIRES A SMALL MODIFICATION IN THE REF MASK (ADD MULT. BY 1/2) - for jj = 1:msh_side(ii).nel - val_aux = val * alpha{ii}(jj); - rhsc(jj,sp1_struct.connectivity(:,jj)) = sp1_struct.shape_functions(:,:,jj) * val_aux; - end - coeff2{ii} = A \ rhsc; - coeff2{ii}(abs(coeff2{ii}) < 1e-12) = 0; % Make more sparse - -% Pass the coefficients to the tensor product basis -% The numbering (ndof) only works for the two patch case, for now - ndof = sp0_struct.ndof + sp1_struct.ndof; - CC{ii} = sparse (space.ndof_per_patch(patch(ii)), ndof); - - ndof_dir = space.sp_patch{patch(ii)}.ndof_dir; - if (side(ii) == 1) - ind0 = sub2ind (ndof_dir, ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, 2*ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 2) - ind0 = sub2ind (ndof_dir, ndof_dir(1) * ones(1,spn.ndof), 1:spn.ndof); - ind1 = sub2ind (ndof_dir, (ndof_dir(1)-1) * ones(1,spn.ndof), 1:spn.ndof); - elseif (side(ii) == 3) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, 2*ones(1,spn.ndof)); - elseif (side(ii) == 4) - ind0 = sub2ind (ndof_dir, 1:spn.ndof, ndof_dir(2) * ones(1,spn.ndof)); - ind1 = sub2ind (ndof_dir, 1:spn.ndof, (ndof_dir(2)-1) * ones(1,spn.ndof)); - end - - if (ii == 2 && interfaces(iref).ornt == -1) - ind0 = fliplr (ind0); - ind1 = fliplr (ind1); - coeff0{2} = flipud (fliplr (coeff0{2})); - coeff1{2} = flipud (fliplr (coeff1{2})); - coeff2{2} = flipud (fliplr (coeff2{2})); - end - - CC{ii}(ind0,1:sp0_struct.ndof) = coeff0{ii}; - CC{ii}(ind1,1:sp0_struct.ndof) = coeff1{ii}; - CC{ii}(ind1,sp0_struct.ndof+1:ndof) = coeff2{ii} * (-1)^(ii+1); - end - -%CHECKING G^1 condition -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% geo_map_jac{1} = msh_side_int{1}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% geo_map_jac{2} = msh_side_int{2}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% for ii = 1:2 % The two patches (L-R) -% brk = cell (1,msh.ndim); -% knots = space.sp_patch{patch(ii)}.knots; -% for idim = 1:msh.ndim -% %Greville points for G^1 conditions system -% geo_knot_v1=geometry(patch(ii)).nurbs.knots{1}; -% p1=geometry(patch(ii)).nurbs.order(1); -% aug_geo_knot1=[geo_knot_v1(1)*ones(1,p1+1) repelem(geo_knot_v1(p1+1:end-p1-1),3) geo_knot_v1(end)*ones(1,p1+1)]; -% geo_knot_v2=geometry(patch(ii)).nurbs.knots{2}; -% p2=geometry(patch(ii)).nurbs.order(2); -% aug_geo_knot2=[geo_knot_v2(1)*ones(1,p2+1) repelem(geo_knot_v2(p2+1:end-p2-1),3) geo_knot_v2(end)*ones(1,p2+1)]; -% grev_pts{1}=aveknt(aug_geo_knot1,p1+1); -% grev_pts{2}=aveknt(aug_geo_knot2,p2+1); -% if (numel(grev_pts{idim}) > 1) -% brk{idim} = [knots{idim}(1), grev_pts{idim}(1:end-1) + diff(grev_pts{idim})/2, knots{idim}(end)]; -% else -% brk{idim} = [knots{idim}(1) knots{idim}(end)]; -% end -% end -% -% msh_grev = msh_cartesian (brk, grev_pts, [], geometry(patch(ii)), 'boundary', true, 'der2',false); -% msh_side_int{ii} = msh_boundary_side_from_interior (msh_grev, side(ii)); -% msh_side_int{ii} = msh_precompute (msh_side_int{ii}); -% geo_map_jac{ii} = msh_side_int{ii}.geo_map_jac; %rdim x ndim x 1 x n_grev_pts (rdim->physical space, ndim->parametric space) -% end -% alpha{1}=(alpha0(1)*(1-grev_pts{2}')+alpha1(1)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{1}=beta0(1)*(1-grev_pts{2}')+beta1(1)*grev_pts{2}'; -% alpha{2}=(alpha0(2)*(1-grev_pts{2}')+alpha1(2)*grev_pts{2}'); %we have to take the absolute value to make it work for any orientation -% beta{2}=beta0(2)*(1-grev_pts{2}')+beta1(2)*grev_pts{2}'; -% bbeta=alpha{1}.*beta{2}-alpha{2}.*beta{1}; -% DuFL_x=squeeze(geo_map_jac{1}(1,1,:,:)); %column vector -% DuFL_y=squeeze(geo_map_jac{1}(2,1,:,:)); %column vector -% DuFR_x=squeeze(geo_map_jac{2}(1,1,:,:)); %column vector -% DuFR_y=squeeze(geo_map_jac{2}(2,1,:,:)); %column vector -% DvFL_x=squeeze(geo_map_jac{1}(1,2,:,:)); %column vector -% DvFL_y=squeeze(geo_map_jac{1}(2,2,:,:)); %column vector -%alpha{1}.*beta{2}-alpha{2}.*beta{1}-bbeta -% alpha{2}.*DuFL_x-alpha{1}.*DuFR_x+bbeta.*DvFL_x -% alpha{2}.*DuFL_y-alpha{1}.*DuFR_y+bbeta.*DvFL_y -% A_full=[(1-v).*DuFL_x v.*DuFL_x -(1-v).*DuFR_x -v.*DuFR_x (1-v).^2.*DvFL_x 2*(1-v).*v.*DvFL_x v.^2.*DvFL_x;... -% (1-v).*DuFL_y v.*DuFL_y -(1-v).*DuFR_y -v.*DuFR_y (1-v).^2.*DvFL_y 2*(1-v).*v.*DvFL_y v.^2.*DvFL_y]; -% alpha{1} -% alpha{2} -% beta{1} -% beta{2} -% bbeta -% alpha0 -% alpha1 -% beta0 -% beta1 -%pause -% grev_pts{1} -% grev_pts{2} - - end - - -%%%%%%%%%% FOR MARIO, TRYING TO SUMMARIZE %%%%%%%%%%%%%%%% -% In the inner loop (for ii = 1:2), we consider the two patches. ii = L,R -% msh_side_int{ii} is a structure that contains the information about the parametrization F^(ii) -% In particular, it contains the value (geo_map), the derivatives (geo_map_jac) -% and the jacobian (jacdet) at the Greville points. The last index -% indicates the Greville point. -% sp_grev(ii) is a structure with the value of the basis functions -% (.shape_functions) at the Greville points. The last index indicates the Greville point. -% The previous one indicates the basis functions that are non-null on the -% element. This also includes functions from the interior. -% The number of the non-vanishing basis functions is in connectivity - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m deleted file mode 100644 index 4175c601..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_plot_solution.m +++ /dev/null @@ -1,58 +0,0 @@ -% SP_PLOT_SOLUTION: Plot the computed solution, given the degrees of freedom. -% -% [eu, F] = sp_plot_solution (u, space, geometry, pts, [ncuts=2]); -% [eu, F] = sp_plot_solution (u, space, geometry, [npts], [ncuts=2]); -% -% INPUT: -% -% u: vector of dof weights -% space: object defining the discrete space (see sp_multipatch_C1) -% geometry: an array of geometry structures (see mp_geo_load) -% pts: cell array with coordinates of points along each parametric direction -% npts: number of points along each parametric direction -% ncuts: only for volumetric domains, number of internal "cuts" in each parametric direction. -% The zero value will plot the solution on the boundary. -% -% Copyright (C) 2016, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp_plot_solution (u, space, geometry, npts, ncuts) - -if (nargin < 4) - npts = []; -end -if (nargin < 5) - ncuts = []; -end - -% if (isa (space.sp_patch{1}, 'sp_vector')) -% disp ('Warning: a different scaling is used for each patch') -% end - -hold_flag = ishold ; -for iptc = 1:space.npatch -% if (isempty (space.dofs_ornt)) - sp_plot_solution (space.Cpatch{iptc}* u, space.sp_patch{iptc}, geometry(iptc), npts, ncuts); -% else -% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); -% end - hold on -end - -if (~hold_flag) - hold off -end - -end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m deleted file mode 100644 index 0c799cfc..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_refine.m +++ /dev/null @@ -1,68 +0,0 @@ -% SP_REFINE: construct a refined space from a given one. The function only -% refines the space, the mesh must be refined separately. -% -% [sp_fine, Proj] = sp_refine (space, msh, nsub, [degree], [regularity]); -% -% The same number of subdivisions, degree and regularity is applied to every patch -% -% INPUTS: -% -% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch) -% msh: an object of the msh_multipatch class, usuallly the refined mesh (see msh_multipatch) -% nsub: number of uniform subdivisions to apply on each knot span, and for each direction -% degree: degree of the fine space, and for each direction -% regularity: regularity for the new space, and for each direction -% -% OUTPUT: -% -% sp_fine: the refined space, an object of the class sp_multipatch (see sp_multipatch) -% Proj: the coefficients relating 1D splines of the coarse and the fine spaces for each patch. -% A cell-array of size 1 x npatch, each entry containing the -% coefficients for the patch (either for scalar or vector-valued spaces). -% -% Copyright (C) 2015, 2016 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [sp_fine, Proj, Proj0, Proj1] = sp_refine (space, msh, nsub, degree, regularity) - - if (nargin < 4) - degree = space.sp_patch{1}.degree; - end - if (nargin < 5) - regularity = degree - 2; - end - - sp_fine = cell (1, space.npatch); - Proj = cell (1, space.npatch); - Proj0 = cell (1, space.npatch); - Proj1 = cell (1, space.npatch); - for iptc = 1:space.npatch - if (nargout > 1) - [sp_fine{iptc}, Proj{iptc}] = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); -% Refine also the spaces of degree p, regularity r+1; and degree p-1, regularity r - knots0_fine = kntrefine (space.knots0_patches{iptc}, nsub-1, degree, regularity+1); - knots1_fine = kntrefine (space.knots1_patches{iptc}, nsub-1, degree-1, regularity); - for idim = 1:msh.ndim - Proj0{iptc}{idim} = basiskntins (degree(idim), space.knots0_patches{iptc}{idim}, knots0_fine{idim}); - Proj1{iptc}{idim} = basiskntins (degree(idim)-1, space.knots1_patches{iptc}{idim}, knots1_fine{idim}); - end - else - sp_fine{iptc} = sp_refine (space.sp_patch{iptc}, msh.msh_patch{iptc}, nsub, degree, regularity); - end - end - sp_fine = sp_multipatch_C1_twopatch (sp_fine, msh, space.geometry, space.interfaces, []); - - -end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m deleted file mode 100644 index e3d71569..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_to_vtk.m +++ /dev/null @@ -1,82 +0,0 @@ -% SP_TO_VTK: Export multipatch results to VTK format for plotting. -% -% sp_to_vtk (u, space, geometry, npts, filename, fieldnames, [option], [lambda_lame, mu_lame]) -% -% INPUT: -% -% u: vector of dof weights -% space: object representing the space of discrete functions (see sp_multipatch) -% geometry: geometry structure (see geo_load) -% npts: number of points along each parametric direction where to evaluate -% filename: name of the output file. -% fieldnames: how to name the saved variables in the vtk file -% options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient', -% and for vectors also 'curl', 'divergence', 'stress' -% lambda_lame: function handle to the first Lame coefficient (only needed to compute 'stress') -% mu_lame: function handle for the second Lame coefficient (only needed to compute 'stress') -% -% OUTPUT: -% -% none -% -% Copyright (C) 2010 Carlo de Falco, Rafael Vazquez -% Copyright (C) 2011, 2012, 2015 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) - - str1 = cat (2,' \n', ... -' \n', ... -' \n'); - - str2 = cat (2, ' \n'); - - str3 = cat (2, ... -'\n', ... -' \n'); - - if (length (filename) < 4 || ~strcmp (filename(end-3:end), '.pvd')) - pvd_filename = cat (2, filename, '.pvd'); - else - pvd_filename = filename; - filename = filename (1:end-4); - end - - fid = fopen (pvd_filename, 'w'); - if (fid < 0) - error ('mp_sp_to_vtk: could not open file %s', pvd_filename); - end - - fprintf (fid, str1); - ind = union (find (filename == '/', 1, 'last'), find (filename == '\', 1, 'last')) + 1; - if (isempty (ind)); ind = 1; end - for iptc = 1:space.npatch - filename_patch_without_path = cat (2, filename(ind:end), '_', num2str (iptc)); - filename_patch = cat (2, filename, '_', num2str (iptc)); - fprintf (fid, str2, iptc, filename_patch_without_path); -% if (isempty (space.dofs_ornt)) - sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... - filename_patch, fieldname, varargin{:}) -% else -% sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... -% filename_patch, fieldname, varargin{:}) -% end - end - fprintf (fid, str3); - - fclose (fid); - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m deleted file mode 100644 index f36aa68d..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/sp_weak_drchlt_bc_laplace.m +++ /dev/null @@ -1,95 +0,0 @@ -% SP_WEAK_DRCHLT_BC_LAPLACE: compute the matrix and right hand-side to impose -% the Dirichlet boundary conditions in weak form for Laplace (Poisson) problem. -% -% The code computes the following terms in the left hand-side -% -% - \int_{Gamma_D} mu*{du/dn v - dv/dn u + (Cpen / he) * (u v)} -% -% and in the right hand-side -% -% - \int_{Gamma_D} mu*{dv/dn g + (Cpen / he) * (v g)} -% -% with u the trial function, v the test function, he the normal characteristic length, -% and g the boundary condition to be imposed. -% -% -% [N_mat, N_rhs] = sp_weak_drchlt_bc_stokes (space, msh, refs, bnd_func, coeff, Cpen) -% -% INPUTS: -% -% space_v: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch). -% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) -% refs: boundary sides on which the Dirichlet condition is imposed -% bnd_func: the condition to be imposed (g in the equations) -% coeff: function handle for the viscosity coefficient (mu in the equation) -% Cpen: a penalization term -% -% OUTPUT: -% -% N_mat: the computed matrix, to be added in the left hand-side -% N_rhs: the computed right hand-side -% -% Copyright (C) 2014 Adriano Cortes, Rafael Vazquez -% Copyright (C) 2015 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [A, rhs] = sp_weak_drchlt_bc_laplace (space, msh, refs, bnd_func, coeff, Cpen, varargin) - - if (nargin < 6 || isempty (Cpen)) - Cpen = 10 * (min (space.sp_patch{1}.degree) + 1); - end - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - rhs = zeros (space.ndof, 1); - -% Compute the matrices to impose the tangential boundary condition weakly - for iref = refs - for bnd_side = 1:msh.boundaries(iref).nsides - iptc = msh.boundaries(iref).patches(bnd_side); - iside = msh.boundaries(iref).faces(bnd_side); - - msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); - msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); - - sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); - sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); - - for idim = 1:msh.rdim - x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); - end - - coeff_at_qnodes = coeff (x{:}); - - % Since trial and test spaces are the same, we can use B' - B = op_gradv_n_u (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); - - g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; - gradv_n_g = op_gradv_n_f (sp_bnd, msh_side, g_times_coeff); - - coeff_at_qnodes = coeff_at_qnodes * Cpen ./ msh_side.charlen; - C = op_u_v (sp_bnd, sp_bnd, msh_side, coeff_at_qnodes); - - g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; - g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); - - A = A + space.Cpatch{iptc}.' * (B + B' - C ) * space.Cpatch{iptc}; - rhs = rhs + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); -% dofs = space.gnum{iptc}; -% A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); -% rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; - end - end - -end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m deleted file mode 100644 index 1c89450c..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsasgn.m +++ /dev/null @@ -1,4 +0,0 @@ -%% override private write access of objects in this class -function obj = subsasgn (obj, S, value) -obj = builtin('subsasgn', obj, S, value); -end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m b/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m deleted file mode 100644 index 9f7048b6..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1_twopatch/subsref.m +++ /dev/null @@ -1,4 +0,0 @@ -%% override private read access of object data -function value = subsref (obj, S) -value = builtin ('subsref', obj, S); -end \ No newline at end of file From 844f6f0d1f2dd4be741fd067cb6f07f28edb1086 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 09:20:49 +0100 Subject: [PATCH 225/366] Changa functions to use the local version of Cpatch --- .../multipatch/@sp_multipatch_C1/op_f_v_mp.m | 4 +-- .../op_gradgradu_gradgradv_mp.m | 5 ++-- .../@sp_multipatch_C1/op_gradu_gradv_mp.m | 6 +++-- .../op_laplaceu_laplacev_mp.m | 5 ++-- .../multipatch/@sp_multipatch_C1/op_u_v_mp.m | 5 ++-- .../sp_bilaplacian_drchlt_C1.m | 23 +++++++++-------- .../sp_bilaplacian_drchlt_C1_exact.m | 23 +++++++++-------- .../sp_evaluate_element_list.m | 9 ++++--- .../sp_get_basis_functions.m | 4 +-- .../@sp_multipatch_C1/sp_get_cells.m | 9 ++++--- .../@sp_multipatch_C1/sp_get_neighbors.m | 7 +++--- .../sp_get_vertex_neighbors.m | 5 ++-- .../@sp_multipatch_C1/sp_h1_error.m | 4 +-- .../@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 4 +-- .../@sp_multipatch_C1/sp_h2_error.m | 4 +-- .../@sp_multipatch_C1/sp_l2_error.m | 4 +-- .../@sp_multipatch_C1/sp_multipatch_C1.m | 25 +++++++++++++------ .../@sp_multipatch_C1/sp_plot_solution.m | 2 +- .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 4 +-- .../sp_weak_drchlt_bc_laplace.m | 7 ++++-- 20 files changed, 95 insertions(+), 64 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m index 561a3415..ca302787 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m @@ -13,7 +13,7 @@ % % rhs: assembled right-hand side % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ % if (~isempty (space.dofs_ornt)) % rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); % end - rhs = rhs + space.Cpatch{iptc}.' * rhs_loc; + rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * rhs_loc; end end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m index 7abebba3..fd77dd30 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m @@ -14,7 +14,7 @@ % % mat: assembled matrix % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -48,7 +48,8 @@ Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m index 953bba5b..948c0a47 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -14,7 +14,7 @@ % % mat: assembled stiffness matrix % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -40,6 +40,7 @@ end A = sparse (spv.ndof, spu.ndof); + A2 = sparse (spv.ndof, spu.ndof); for iptc = patch_list if (nargin < 4 || isempty (coeff)) @@ -48,7 +49,8 @@ Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m index 55ba64ac..5b7f2464 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m @@ -14,7 +14,7 @@ % % mat: assembled matrix % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -48,7 +48,8 @@ Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m index 06151fde..66972524 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m @@ -14,7 +14,7 @@ % % mat: assembled mass matrix % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -48,7 +48,8 @@ Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A = A + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... + A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; % if (~isempty (spv.dofs_ornt)) % vs = spv.dofs_ornt{iptc}(rs)' .* vs; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 83ce7c8e..aee7190b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -25,8 +25,8 @@ [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); - drchlt_dofs = union (drchlt_dofs, icol); - drchlt_dofs2 = union (drchlt_dofs2, jcol); + drchlt_dofs = union (drchlt_dofs, space.Cpatch_cols{iptc}(icol)); + drchlt_dofs2 = union (drchlt_dofs2, space.Cpatch_cols{iptc}(jcol)); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); @@ -34,12 +34,13 @@ coeff_at_qnodes = ones (size(x{1})); dudn_at_qnodes = dudn (x{:},iref) .* msh_side.charlen; - M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; - rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); - - M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; - rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + M(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M(space.Cpatch_cols{iptc}, space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); + M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; + rhs2(space.Cpatch_cols{iptc}) = rhs2(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end @@ -73,11 +74,13 @@ indices_loc_L = indices_loc_L(:); Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 space.sp_patch{patches(1)}.ndof_dir(1)+2 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); - M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... - space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(1)}); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(2)}); + M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, inds1); ... + space.Cpatch{patches(2)}(Cpatch_ind_L, inds2)]; % M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); ker = null(full(M_ker)); if (~isempty(ker)) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index e7f58c2f..84f0c477 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -25,8 +25,8 @@ [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); - drchlt_dofs = union (drchlt_dofs, icol); - drchlt_dofs2 = union (drchlt_dofs2, jcol); + drchlt_dofs = union (drchlt_dofs, space.Cpatch_cols{iptc}(icol)); + drchlt_dofs2 = union (drchlt_dofs2, space.Cpatch_cols{iptc}(jcol)); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); @@ -34,12 +34,13 @@ coeff_at_qnodes = ones (size(x{1})); dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel) .* msh_side.charlen; - M = M + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; - rhs = rhs + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); - - M2 = M2 + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; - rhs2 = rhs2 + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + M(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M(space.Cpatch_cols{iptc}, space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; + rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); + M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; + rhs2(space.Cpatch_cols{iptc}) = rhs2(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end @@ -73,11 +74,13 @@ indices_loc_L = indices_loc_L(:); Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 space.sp_patch{patches(1)}.ndof_dir(1)+2 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); - M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... - space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(1)}); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(2)}); + M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, inds1); ... + space.Cpatch{patches(2)}(Cpatch_ind_L, inds2)]; % M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); ker = null(full(M_ker)); if (~isempty(ker)) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 226298ba..160e7d2c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -32,7 +32,7 @@ % connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element % shape_functions, shape_function_gradients... (see sp_evaluate_col for details) % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -90,11 +90,12 @@ for iel = 1:msh_patch.nel conn_iel = sp_patch.connectivity(:,iel); - [ii,jj] = find (Cpatch(conn_iel,:)); - funs = unique (jj); + [~,jj] = find (Cpatch(conn_iel,:)); + col_indices = unique(jj); + funs = space.Cpatch_cols{iptc}(col_indices); nsh(iel) = numel (funs); connectivity(1:nsh(iel),iel) = funs; - Cpatch_iel = Cpatch(conn_iel, funs); + Cpatch_iel = Cpatch(conn_iel, col_indices); if (isfield (sp_patch, 'shape_functions')) shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m index 76edf5c8..63d9a81a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m @@ -10,7 +10,7 @@ % OUTPUT: % fun_indices: indices of the basis functions acting on the cells. % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ if (~isempty (local_cell_indices)) aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); - function_indices = union (function_indices, dofs); + function_indices = union (function_indices, space.Cpatch_cols{iptc}(dofs)); end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m index 874f4e92..0885ad16 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -11,7 +11,7 @@ % cell_indices: indices of the cells within the support of the basis functions. % indices_per_function: indices of the cells within the support of each basis function. % -% Copyright (C) 2015, 2016 Rafael Vazquez +% Copyright (C) 2015, 2016, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -35,7 +35,8 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:space.npatch - [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices)); + [~,loc_f_inds,fun_indices_on_patch] = intersect (fun_indices, space.Cpatch_cols{iptc}); + [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices_on_patch)); if (~isempty (patch_indices)) patch_indices = patch_indices(:).'; [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); @@ -45,8 +46,10 @@ if (nargout == 2) local_funs = local_funs(:).'; for ifun = 1:numel(patch_indices) - indices_per_function{local_funs(ifun)} = union (indices_per_function{local_funs(ifun)}, Nelem(iptc)+ind_per_fun{ifun}); + indices_per_function{loc_f_inds(local_funs(ifun))} = union (indices_per_function{loc_f_inds(local_funs(ifun))}, Nelem(iptc)+ind_per_fun{ifun}); end end end end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m index 36a4ec2c..31b7f639 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -10,7 +10,7 @@ % OUTPUT: % neighbors_indices: indices of the functions that interact with the given ones. % -% Copyright (C) 2015, 2016, 2017 Rafael Vazquez +% Copyright (C) 2015, 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -30,11 +30,12 @@ neighbors_indices = []; for iptc = 1:space.npatch - [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices)); + [~,~,fun_indices_on_patch] = intersect (fun_indices, space.Cpatch_cols{iptc}); + [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices_on_patch)); if (~isempty (patch_indices)) aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); - neighbors_indices = union (neighbors_indices, global_indices); + neighbors_indices = union (neighbors_indices, space.Cpatch_cols{iptc}(global_indices)); end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index 2ed8b10d..3b34039b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -13,7 +13,7 @@ % OUTPUT: % cell_indices: indices of the functions that interact with the given ones. % -% Copyright (C) 2021 Rafael Vazquez +% Copyright (C) 2021, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -38,7 +38,8 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:numel(patch_indices) patch = space.vertices(vertex_index).patches(patch_indices(iptc)); - [bsp_indices, ~] = find (space.Cpatch{patch}(:,space.dofs_on_vertex{vertex_index})); + [~,~,inds] = intersect (space.dofs_on_vertex{vertex_index}, space.Cpatch_cols{patch}); + [bsp_indices, ~] = find (space.Cpatch{patch}(:,inds)); [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); cell_indices{iptc} = Nelem(patch) + aux_cell_indices(:).'; end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m index f727b7d2..ca2cfbf4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m @@ -16,7 +16,7 @@ % errl2: error in L^2 norm % errh1s: error in H^1 seminorm % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -40,7 +40,7 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; + u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m index c272655e..bf9537ac 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -19,7 +19,7 @@ % errh2s: error in H^2 seminorm % errh1s: error in H^1 seminorm % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -43,7 +43,7 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; + u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m index 6aac47e2..9746eb95 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -19,7 +19,7 @@ % errh2s: error in H^2 seminorm % errh1s: error in H^1 seminorm % -% Copyright (C) 2015, 2017 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -43,7 +43,7 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; + u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m index abbbc9ef..d4d462a6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -13,7 +13,7 @@ % % errl2: error in L^2 norm % -% Copyright (C) 2015 Rafael Vazquez +% Copyright (C) 2015, 2022 Rafael Vazquez % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; + u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index a43eedba..973c9f60 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -165,18 +165,21 @@ % Store the coefficients for matrix change in Cpatch Cpatch = cell (sp.npatch, 1); +% Cpatch2 = cell (sp.npatch, 1); + Cpatch_cols = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch -% Cpatch{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); + Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); rows = sp.interior_dofs_per_patch{iptc}; - cols = global_indices; + cols = 1:numel_interior_dofs(iptc);%global_indices; vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); - Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), sp.ndof); -% Cpatch{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... + Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), numel_interior_dofs(iptc)); +% Cpatch2{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... % speye (numel (sp.interior_dofs_per_patch{iptc})); - sp.dofs_on_patch{iptc} = shift_index_patch(iptc)+1:shift_index_patch(iptc+1); + sp.dofs_on_patch{iptc} = global_indices; + Cpatch_cols{iptc} = global_indices; end sp.dofs_on_edge = cell (1, numel(interfaces_all)); @@ -185,7 +188,10 @@ sp.dofs_on_edge{intrfc} = global_indices; patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; for iptc = 1:numel(patches) - Cpatch{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; +% Cpatch2{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; + indices = size(Cpatch{patches(iptc)},2) + (1:numel(global_indices)); + Cpatch{patches(iptc)}(:,indices) = CC_edges{iptc,intrfc}; + Cpatch_cols{patches(iptc)} = union (Cpatch_cols{patches(iptc)}, global_indices); end end @@ -195,11 +201,16 @@ sp.dofs_on_vertex{ivrt} = global_indices; for iptc = 1:vertices(ivrt).valence_p patch = vertices(ivrt).patches(iptc); - Cpatch{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; +% Cpatch2{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; + indices = size(Cpatch{patch},2) + (1:numel(global_indices)); + Cpatch{patch}(:,indices) = CC_vertices{ivrt}{iptc}; + Cpatch_cols{patch} = union (Cpatch_cols{patch}, global_indices); end end sp.Cpatch = Cpatch; +% sp.Cpatch2 = Cpatch2; + sp.Cpatch_cols = Cpatch_cols; % Store information about the geometry, for simplicity sp.interfaces = interfaces_all; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m index 4175c601..fd4a5e9c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -44,7 +44,7 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) hold_flag = ishold ; for iptc = 1:space.npatch % if (isempty (space.dofs_ornt)) - sp_plot_solution (space.Cpatch{iptc}* u, space.sp_patch{iptc}, geometry(iptc), npts, ncuts); + sp_plot_solution (space.Cpatch{iptc}* u(space.Cpatch_cols{iptc}), space.sp_patch{iptc}, geometry(iptc), npts, ncuts); % else % sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index af9bef13..3b4a84f7 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -21,7 +21,7 @@ % none % % Copyright (C) 2010 Carlo de Falco, Rafael Vazquez -% Copyright (C) 2011, 2012, 2015 Rafael Vazquez +% Copyright (C) 2011, 2012, 2015, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) if (numel(u) == space.ndof) % if (isempty (space.dofs_ornt)) - sp_to_vtk (space.Cpatch{iptc} * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + sp_to_vtk (space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}), space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) % else % sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m index e6242b67..291e0168 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -84,8 +84,11 @@ g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); - A = A + space.Cpatch{iptc}.' * (B + B' - C) * space.Cpatch{iptc}; - rhs = rhs + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); + A(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = ... + A(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * (B + B.' - C) * space.Cpatch{iptc}; + rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); % dofs = space.gnum{iptc}; % A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); % rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; From f0feae1ca079ab55e4e796a7357df0860e7eeea6 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 09:21:35 +0100 Subject: [PATCH 226/366] Local Cpatch for Neumann conditions --- geopdes/inst/multipatch/mp_solve_laplace_C1.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index 5d6b6ef8..35c0bec0 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -39,7 +39,7 @@ % u: the computed degrees of freedom % % Copyright (C) 2009, 2010 Carlo de Falco -% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez +% Copyright (C) 2010, 2011, 2013, 2015, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -108,7 +108,8 @@ msh_side = msh.msh_patch{iptc}.boundary(iside); sp_side = space.sp_patch{iptc}.boundary(iside); rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); - rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; + rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + ... + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; end end From 08c4d070dbba280a23b09c4db81ea7e72475428c Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 10:40:37 +0100 Subject: [PATCH 227/366] Remove Cpatch2 --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- .../multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 973c9f60..b6ab7b62 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -170,7 +170,7 @@ numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch - Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); +% Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); rows = sp.interior_dofs_per_patch{iptc}; cols = 1:numel_interior_dofs(iptc);%global_indices; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m index 291e0168..6a0790b6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -30,7 +30,7 @@ % N_rhs: the computed right hand-side % % Copyright (C) 2014 Adriano Cortes, Rafael Vazquez -% Copyright (C) 2015 Rafael Vazquez +% Copyright (C) 2015, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by From 8f180c12caeb58daff3a515755ab3a5638b8efac Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 12:16:36 +0100 Subject: [PATCH 228/366] Remove unused variable --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 1 - 1 file changed, 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index b6ab7b62..bbbc1d60 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -168,7 +168,6 @@ % Cpatch2 = cell (sp.npatch, 1); Cpatch_cols = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - shift_index_patch = cumsum ([0 numel_interior_dofs]); for iptc = 1:sp.npatch % Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); From 45e570d9b6ab45b459f679608e5a4ba700b321cc Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 13:38:07 +0100 Subject: [PATCH 229/366] Remove unused variable --- geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m | 1 - 1 file changed, 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m index 948c0a47..74509a27 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -40,7 +40,6 @@ end A = sparse (spv.ndof, spu.ndof); - A2 = sparse (spv.ndof, spu.ndof); for iptc = patch_list if (nargin < 4 || isempty (coeff)) From 9252580d58d22be653400bab2f0fea8fb53b6112 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 14:02:25 +0100 Subject: [PATCH 230/366] Computation of Cpatch in a separate function --- .../multipatch/@sp_multipatch_C1/op_f_v_mp.m | 4 ++- .../op_gradgradu_gradgradv_mp.m | 8 +++-- .../@sp_multipatch_C1/op_gradu_gradv_mp.m | 8 +++-- .../op_laplaceu_laplacev_mp.m | 8 +++-- .../multipatch/@sp_multipatch_C1/op_u_v_mp.m | 8 +++-- .../sp_bilaplacian_drchlt_C1.m | 33 +++++++++++-------- .../sp_bilaplacian_drchlt_C1_exact.m | 25 ++++++++------ .../sp_evaluate_element_list.m | 4 +-- .../sp_get_basis_functions.m | 5 +-- .../@sp_multipatch_C1/sp_get_cells.m | 5 +-- .../@sp_multipatch_C1/sp_get_neighbors.m | 7 ++-- .../sp_get_vertex_neighbors.m | 5 +-- .../@sp_multipatch_C1/sp_h1_error.m | 4 ++- .../@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 4 ++- .../@sp_multipatch_C1/sp_h2_error.m | 4 ++- .../@sp_multipatch_C1/sp_l2_error.m | 4 ++- .../@sp_multipatch_C1/sp_multipatch_C1.m | 5 ++- .../@sp_multipatch_C1/sp_plot_solution.m | 5 +-- .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 3 +- .../sp_weak_drchlt_bc_laplace.m | 9 +++-- geopdes/inst/multipatch/mp_solve_laplace_C1.m | 6 ++-- 21 files changed, 105 insertions(+), 59 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m index ca302787..e9ac4603 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m @@ -45,7 +45,9 @@ % if (~isempty (space.dofs_ornt)) % rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); % end - rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * rhs_loc; +% rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * rhs_loc; + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch.' * rhs_loc; end end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m index fd77dd30..50a2b4c1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m @@ -48,8 +48,12 @@ Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); + A(Cpatch_cols_v,Cpatch_cols_u) = ... + A(Cpatch_cols_v,Cpatch_cols_u) + Cpatch_v.' * Ap * Cpatch_u; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m index 74509a27..2f80bca5 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -48,8 +48,12 @@ Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); + A(Cpatch_cols_v,Cpatch_cols_u) = ... + A(Cpatch_cols_v,Cpatch_cols_u) + Cpatch_v.' * Ap * Cpatch_u; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m index 5b7f2464..8b911e8a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m @@ -48,8 +48,12 @@ Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); + A(Cpatch_cols_v,Cpatch_cols_u) = ... + A(Cpatch_cols_v,Cpatch_cols_u) + Cpatch_v.' * Ap * Cpatch_u; end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m index 66972524..2b744b2a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m @@ -48,8 +48,12 @@ Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... - A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... +% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); + A(Cpatch_cols_v,Cpatch_cols_u) = ... + A(Cpatch_cols_v,Cpatch_cols_u) + Cpatch_v.' * Ap * Cpatch_u; % if (~isempty (spv.dofs_ornt)) % vs = spv.dofs_ornt{iptc}(rs)' .* vs; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index aee7190b..78f55f76 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -22,11 +22,12 @@ sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); sp_bnd_struct = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); - [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); - [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [~,icol] = find (Cpatch(sp_bnd.boundary(iside).dofs,:)); + [~,jcol] = find (Cpatch(sp_bnd.boundary(iside).adjacent_dofs,:)); - drchlt_dofs = union (drchlt_dofs, space.Cpatch_cols{iptc}(icol)); - drchlt_dofs2 = union (drchlt_dofs2, space.Cpatch_cols{iptc}(jcol)); + drchlt_dofs = union (drchlt_dofs, Cpatch_cols(icol)); + drchlt_dofs2 = union (drchlt_dofs2, Cpatch_cols(jcol)); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); @@ -34,13 +35,13 @@ coeff_at_qnodes = ones (size(x{1})); dudn_at_qnodes = dudn (x{:},iref) .* msh_side.charlen; - M(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M(space.Cpatch_cols{iptc}, space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; - rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); + M(Cpatch_cols,Cpatch_cols) = M(Cpatch_cols, Cpatch_cols) + ... + Cpatch.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * Cpatch; + rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch.' * op_f_v (sp_bnd_struct, msh_side, href(x{:})); - M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; - rhs2(space.Cpatch_cols{iptc}) = rhs2(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + M2(Cpatch_cols,Cpatch_cols) = M2(Cpatch_cols,Cpatch_cols) + ... + Cpatch.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * Cpatch; + rhs2(Cpatch_cols) = rhs2(Cpatch_cols) + Cpatch.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end @@ -76,11 +77,15 @@ Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); - [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(1)}); - [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(2)}); +% TODO: it is probably enough to use CC_vertices (and CC_edges) + [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); + [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); - M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, inds1); ... - space.Cpatch{patches(2)}(Cpatch_ind_L, inds2)]; + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); + + M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... + Cpatch2(Cpatch_ind_L, inds2)]; % M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); ker = null(full(M_ker)); if (~isempty(ker)) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 84f0c477..acbaae3b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -22,6 +22,7 @@ sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); sp_bnd_struct = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); @@ -34,13 +35,13 @@ coeff_at_qnodes = ones (size(x{1})); dudn_at_qnodes = reshape (sum (gradex(x{:}) .* msh_side.normal, 1), msh_side.nqn, msh_side.nel) .* msh_side.charlen; - M(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M(space.Cpatch_cols{iptc}, space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * space.Cpatch{iptc}; - rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); + M(Cpatch_cols,Cpatch_cols) = M(Cpatch_cols, Cpatch_cols) + ... + Cpatch.' * op_u_v (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes) * Cpatch; + rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch.' * op_f_v (sp_bnd_struct, msh_side, uex(x{:})); - M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = M2(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * space.Cpatch{iptc}; - rhs2(space.Cpatch_cols{iptc}) = rhs2(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) + M2(Cpatch_cols,Cpatch_cols) = M2(Cpatch_cols,Cpatch_cols) + ... + Cpatch.' * op_gradu_n_gradv_n (sp_bnd_struct, sp_bnd_struct, msh_side, coeff_at_qnodes.*msh_side.charlen) * Cpatch; + rhs2(Cpatch_cols) = rhs2(Cpatch_cols) + Cpatch.' * op_gradv_n_f (sp_bnd_struct, msh_side, dudn_at_qnodes); % I am missing the other part of the vector. It is in M2 :-) end end @@ -76,11 +77,15 @@ Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); - [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(1)}); - [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, space.Cpatch_cols{patches(2)}); +% TODO: it is probably enough to use CC_vertices (and CC_edges) + [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); + [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); - M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, inds1); ... - space.Cpatch{patches(2)}(Cpatch_ind_L, inds2)]; + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); + + M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... + Cpatch2(Cpatch_ind_L, inds2)]; % M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); ker = null(full(M_ker)); if (~isempty(ker)) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 160e7d2c..6e88b1e1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -79,7 +79,7 @@ msh_patch = msh_restrict_to_patch (msh, iptc); sp_patch = sp_evaluate_element_list (space.sp_patch{iptc}, msh_patch, varargin{:}); - Cpatch = space.Cpatch{iptc}; + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); nsh = zeros (1, msh_patch.nel); connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); @@ -92,7 +92,7 @@ conn_iel = sp_patch.connectivity(:,iel); [~,jj] = find (Cpatch(conn_iel,:)); col_indices = unique(jj); - funs = space.Cpatch_cols{iptc}(col_indices); + funs = Cpatch_cols(col_indices); nsh(iel) = numel (funs); connectivity(1:nsh(iel),iel) = funs; Cpatch_iel = Cpatch(conn_iel, col_indices); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m index 63d9a81a..e016ef0c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m @@ -33,8 +33,9 @@ [~,local_cell_indices,~] = intersect ((Nelem(iptc)+1):Nelem(iptc+1), cell_indices); if (~isempty (local_cell_indices)) aux_indices = sp_get_basis_functions (space.sp_patch{iptc}, msh.msh_patch{iptc}, local_cell_indices); - [~,dofs] = find (space.Cpatch{iptc}(aux_indices,:)); - function_indices = union (function_indices, space.Cpatch_cols{iptc}(dofs)); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [~,dofs] = find (Cpatch(aux_indices,:)); + function_indices = union (function_indices, Cpatch_cols(dofs)); end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m index 0885ad16..bbec9f13 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -35,8 +35,9 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:space.npatch - [~,loc_f_inds,fun_indices_on_patch] = intersect (fun_indices, space.Cpatch_cols{iptc}); - [patch_indices,local_funs] = find (space.Cpatch{iptc}(:,fun_indices_on_patch)); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [~,loc_f_inds,fun_indices_on_patch] = intersect (fun_indices, Cpatch_cols); + [patch_indices,local_funs] = find (Cpatch(:,fun_indices_on_patch)); if (~isempty (patch_indices)) patch_indices = patch_indices(:).'; [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m index 31b7f639..03f620ea 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -30,11 +30,12 @@ neighbors_indices = []; for iptc = 1:space.npatch - [~,~,fun_indices_on_patch] = intersect (fun_indices, space.Cpatch_cols{iptc}); - [patch_indices,~] = find (space.Cpatch{iptc}(:,fun_indices_on_patch)); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [~,~,fun_indices_on_patch] = intersect (fun_indices, Cpatch_cols); + [patch_indices,~] = find (Cpatch(:,fun_indices_on_patch)); if (~isempty (patch_indices)) aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); - [~,global_indices] = find (space.Cpatch{iptc}(aux_indices,:)); + [~,global_indices] = find (Cpatch(aux_indices,:)); neighbors_indices = union (neighbors_indices, space.Cpatch_cols{iptc}(global_indices)); end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index 3b34039b..7c440132 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -38,8 +38,9 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:numel(patch_indices) patch = space.vertices(vertex_index).patches(patch_indices(iptc)); - [~,~,inds] = intersect (space.dofs_on_vertex{vertex_index}, space.Cpatch_cols{patch}); - [bsp_indices, ~] = find (space.Cpatch{patch}(:,inds)); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [~,~,inds] = intersect (space.dofs_on_vertex{vertex_index}, Cpatch_cols); + [bsp_indices, ~] = find (Cpatch(:,inds)); [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); cell_indices{iptc} = Nelem(patch) + aux_cell_indices(:).'; end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m index ca2cfbf4..dd58830e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m @@ -40,7 +40,9 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); +% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m index bf9537ac..722bffbc 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -43,7 +43,9 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); +% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m index 9746eb95..5c7aa50e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -43,7 +43,9 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); +% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m index d4d462a6..0216aa6d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -37,7 +37,9 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); +% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); % else % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index bbbc1d60..b2864bef 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -210,7 +210,10 @@ sp.Cpatch = Cpatch; % sp.Cpatch2 = Cpatch2; sp.Cpatch_cols = Cpatch_cols; - + + sp.CC_edges = CC_edges; + sp.CC_vertices = CC_vertices; + % Store information about the geometry, for simplicity sp.interfaces = interfaces_all; sp.vertices = vertices; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m index fd4a5e9c..c560c9ec 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -13,7 +13,7 @@ % ncuts: only for volumetric domains, number of internal "cuts" in each parametric direction. % The zero value will plot the solution on the boundary. % -% Copyright (C) 2016, 2017 Rafael Vazquez +% Copyright (C) 2016, 2017, 2022 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -44,7 +44,8 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) hold_flag = ishold ; for iptc = 1:space.npatch % if (isempty (space.dofs_ornt)) - sp_plot_solution (space.Cpatch{iptc}* u(space.Cpatch_cols{iptc}), space.sp_patch{iptc}, geometry(iptc), npts, ncuts); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + sp_plot_solution (Cpatch* u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), npts, ncuts); % else % sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); % end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index 3b4a84f7..f686f8ea 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -68,9 +68,10 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) filename_patch = cat (2, filename, '_', num2str (iptc)); fprintf (fid, str2, iptc, filename_patch_without_path); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); if (numel(u) == space.ndof) % if (isempty (space.dofs_ornt)) - sp_to_vtk (space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}), space.sp_patch{iptc}, geometry(iptc), npts, ... + sp_to_vtk (Cpatch * u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) % else % sp_to_vtk (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}', space.sp_patch{iptc}, geometry(iptc), npts, ... diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m index 6a0790b6..99901dc1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -84,11 +84,10 @@ g_times_coeff = bnd_func(x{:}, iref) .* coeff_at_qnodes; g_cdot_v = op_f_v (sp_bnd, msh_side, g_times_coeff); - A(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) = ... - A(space.Cpatch_cols{iptc},space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * (B + B.' - C) * space.Cpatch{iptc}; - rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}.' * (-gradv_n_g + g_cdot_v); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + A(Cpatch_cols,Cpatch_cols) = A(Cpatch_cols,Cpatch_cols) + ... + Cpatch.' * (B + B.' - C) * Cpatch; + rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch.' * (-gradv_n_g + g_cdot_v); % dofs = space.gnum{iptc}; % A(dofs,dofs) = A(dofs,dofs) + (B + B' - C); % rhs(dofs) = rhs(dofs) - gradv_n_g + g_cdot_v; diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index 35c0bec0..ddc79aae 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -108,8 +108,10 @@ msh_side = msh.msh_patch{iptc}.boundary(iside); sp_side = space.sp_patch{iptc}.boundary(iside); rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); - rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + ... - space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch(sp_side.dofs,:).' * rhs_nmnn; +% rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + ... +% space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; end end From 17ec0b03cf236b5686d064db0a7e70d7cf0ca146 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 14:05:58 +0100 Subject: [PATCH 231/366] Fixed bug --- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index acbaae3b..b08b7f6b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -23,11 +23,11 @@ sp_bnd_struct = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true); [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - [~,icol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).dofs,:)); - [~,jcol] = find (space.Cpatch{iptc}(sp_bnd.boundary(iside).adjacent_dofs,:)); + [~,icol] = find (Cpatch(sp_bnd.boundary(iside).dofs,:)); + [~,jcol] = find (Cpatch(sp_bnd.boundary(iside).adjacent_dofs,:)); - drchlt_dofs = union (drchlt_dofs, space.Cpatch_cols{iptc}(icol)); - drchlt_dofs2 = union (drchlt_dofs2, space.Cpatch_cols{iptc}(jcol)); + drchlt_dofs = union (drchlt_dofs, Cpatch_cols(icol)); + drchlt_dofs2 = union (drchlt_dofs2, Cpatch_cols(jcol)); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); From 4bb74c3afcf40cfdd6517621cf3e9f9907a254ea Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 14:06:06 +0100 Subject: [PATCH 232/366] Removed Cpatch from the class --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index b2864bef..fa7a9993 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -164,52 +164,52 @@ sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; % Store the coefficients for matrix change in Cpatch - Cpatch = cell (sp.npatch, 1); +% Cpatch = cell (sp.npatch, 1); % Cpatch2 = cell (sp.npatch, 1); - Cpatch_cols = cell (sp.npatch, 1); +% Cpatch_cols = cell (sp.npatch, 1); numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); for iptc = 1:sp.npatch % Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); - rows = sp.interior_dofs_per_patch{iptc}; - cols = 1:numel_interior_dofs(iptc);%global_indices; - vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); - Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), numel_interior_dofs(iptc)); +% rows = sp.interior_dofs_per_patch{iptc}; +% cols = 1:numel_interior_dofs(iptc);%global_indices; +% vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); +% Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), numel_interior_dofs(iptc)); % Cpatch2{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... % speye (numel (sp.interior_dofs_per_patch{iptc})); sp.dofs_on_patch{iptc} = global_indices; - Cpatch_cols{iptc} = global_indices; +% Cpatch_cols{iptc} = global_indices; end sp.dofs_on_edge = cell (1, numel(interfaces_all)); for intrfc = 1:numel(interfaces_all) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); sp.dofs_on_edge{intrfc} = global_indices; - patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; - for iptc = 1:numel(patches) -% Cpatch2{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; - indices = size(Cpatch{patches(iptc)},2) + (1:numel(global_indices)); - Cpatch{patches(iptc)}(:,indices) = CC_edges{iptc,intrfc}; - Cpatch_cols{patches(iptc)} = union (Cpatch_cols{patches(iptc)}, global_indices); - end +% patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; +% for iptc = 1:numel(patches) +% % Cpatch2{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; +% indices = size(Cpatch{patches(iptc)},2) + (1:numel(global_indices)); +% % Cpatch{patches(iptc)}(:,indices) = CC_edges{iptc,intrfc}; +% % Cpatch_cols{patches(iptc)} = union (Cpatch_cols{patches(iptc)}, global_indices); +% end end sp.dofs_on_vertex = cell (1, numel(vertices)); for ivrt = 1:numel(vertices) global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); sp.dofs_on_vertex{ivrt} = global_indices; - for iptc = 1:vertices(ivrt).valence_p - patch = vertices(ivrt).patches(iptc); -% Cpatch2{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; - indices = size(Cpatch{patch},2) + (1:numel(global_indices)); - Cpatch{patch}(:,indices) = CC_vertices{ivrt}{iptc}; - Cpatch_cols{patch} = union (Cpatch_cols{patch}, global_indices); - end +% for iptc = 1:vertices(ivrt).valence_p +% patch = vertices(ivrt).patches(iptc); +% % Cpatch2{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; +% % indices = size(Cpatch{patch},2) + (1:numel(global_indices)); +% % Cpatch{patch}(:,indices) = CC_vertices{ivrt}{iptc}; +% % Cpatch_cols{patch} = union (Cpatch_cols{patch}, global_indices); +% end end - sp.Cpatch = Cpatch; -% sp.Cpatch2 = Cpatch2; - sp.Cpatch_cols = Cpatch_cols; +% sp.Cpatch = Cpatch; +% % sp.Cpatch2 = Cpatch2; +% sp.Cpatch_cols = Cpatch_cols; sp.CC_edges = CC_edges; sp.CC_vertices = CC_vertices; From 7b8ac90116e7ab49dca0c08afc7e391217eec644 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 15:03:03 +0100 Subject: [PATCH 233/366] Fixed bug --- .../inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index 7c440132..fe8608f9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -38,7 +38,7 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:numel(patch_indices) patch = space.vertices(vertex_index).patches(patch_indices(iptc)); - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, patch); [~,~,inds] = intersect (space.dofs_on_vertex{vertex_index}, Cpatch_cols); [bsp_indices, ~] = find (Cpatch(:,inds)); [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); From 3532a0fb2c1aad19753ee9c98c77788d97595e44 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 15:27:58 +0100 Subject: [PATCH 234/366] Some cleaning --- geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m | 1 - .../multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m | 2 -- geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m | 2 -- .../inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m | 2 -- geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m | 2 -- 5 files changed, 9 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m index e9ac4603..c7047955 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp.m @@ -45,7 +45,6 @@ % if (~isempty (space.dofs_ornt)) % rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); % end -% rhs(space.Cpatch_cols{iptc}) = rhs(space.Cpatch_cols{iptc}) + space.Cpatch{iptc}.' * rhs_loc; [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); rhs(Cpatch_cols) = rhs(Cpatch_cols) + Cpatch.' * rhs_loc; end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m index 50a2b4c1..d4f16073 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradgradu_gradgradv_mp.m @@ -48,8 +48,6 @@ Ap = op_gradgradu_gradgradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); A(Cpatch_cols_v,Cpatch_cols_u) = ... diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m index 2f80bca5..58523bbb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradu_gradv_mp.m @@ -48,8 +48,6 @@ Ap = op_gradu_gradv_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); A(Cpatch_cols_v,Cpatch_cols_u) = ... diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m index 8b911e8a..314a575b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_laplaceu_laplacev_mp.m @@ -48,8 +48,6 @@ Ap = op_laplaceu_laplacev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); A(Cpatch_cols_v,Cpatch_cols_u) = ... diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m index 2b744b2a..7ae8ae76 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_u_v_mp.m @@ -48,8 +48,6 @@ Ap = op_u_v_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); end -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) = ... -% A(spv.Cpatch_cols{iptc},spu.Cpatch_cols{iptc}) + spv.Cpatch{iptc}.' * Ap * spu.Cpatch{iptc}; [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); A(Cpatch_cols_v,Cpatch_cols_u) = ... From ef857b89340f2ab892b46678dc0a70e97a69ecf1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 15:28:56 +0100 Subject: [PATCH 235/366] Some cleaning --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m | 1 - .../inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 1 - geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m | 1 - geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m | 1 - 4 files changed, 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m index dd58830e..50b8dfec 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h1_error.m @@ -40,7 +40,6 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) -% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); u_ptc = Cpatch * u(Cpatch_cols); % else diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m index 722bffbc..790d123b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -43,7 +43,6 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) -% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); u_ptc = Cpatch * u(Cpatch_cols); % else diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m index 5c7aa50e..cc29069e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -43,7 +43,6 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) -% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); u_ptc = Cpatch * u(Cpatch_cols); % else diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m index 0216aa6d..4c95cbe8 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -37,7 +37,6 @@ for iptc = 1:msh.npatch % if (isempty (space.dofs_ornt)) -% u_ptc = space.Cpatch{iptc} * u(space.Cpatch_cols{iptc}); [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); u_ptc = Cpatch * u(Cpatch_cols); % else From 56e0002e6568bc645428d9464a96d9f47fca98fb Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 15:47:23 +0100 Subject: [PATCH 236/366] Added help --- .../@sp_multipatch_C1/sp_compute_Cpatch.m | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m new file mode 100644 index 00000000..f9186c7b --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m @@ -0,0 +1,67 @@ +% SP_COMPUTE_CPATCH: Compute the matrix for B-spline representation, and +% the indices of C^1 functions that do not vanish on a given patch. +% +% [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, patch) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% patch: index of the patch +% +% OUTPUT: +% Cpatch: coefficients of the linear combination of basis functions as standard B-splines, +% The matrix has size ndof_per_patch(iptc) x numel(Cpatch_cols). +% Cpatch_cols: indices of the C^1 basis functions that do not vanish on the patch. +% +% Copyright (C) 2022 Cesare Bracco, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc_ind) + + numel_interior_dofs = cellfun (@numel, space.interior_dofs_per_patch); + ndof_per_interface = cellfun (@numel, space.dofs_on_edge); + ndof_per_vertex = cellfun (@numel, space.dofs_on_vertex); + +% Interior basis functions + global_indices = sum (numel_interior_dofs(1:iptc_ind-1)) + (1:numel_interior_dofs(iptc_ind)); + rows = space.interior_dofs_per_patch{iptc_ind}; + cols = 1:numel_interior_dofs(iptc_ind);%global_indices; + vals = ones (numel_interior_dofs(iptc_ind), 1); + Cpatch = sparse (rows, cols, vals, space.ndof_per_patch(iptc_ind), numel_interior_dofs(iptc_ind)); + Cpatch_cols = global_indices; + +% Edge basis functions + for intrfc = 1:numel(space.interfaces) + global_indices = space.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + patches = [space.interfaces(intrfc).patch1 space.interfaces(intrfc).patch2]; + [patch_is_on_interface,local_patch] = ismember (iptc_ind, patches); + if (patch_is_on_interface) + indices = size(Cpatch,2) + (1:numel(global_indices)); + Cpatch(:,indices) = space.CC_edges{local_patch,intrfc}; + Cpatch_cols = union (Cpatch_cols, global_indices); + end + end + +% Vertex basis functions + for ivrt = 1:numel(space.vertices) + global_indices = space.ndof_interior + space.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + [patch_is_on_vertex,local_patch] = ismember (iptc_ind, space.vertices(ivrt).patches); + if (patch_is_on_vertex) + indices = size(Cpatch,2) + (1:numel(global_indices)); + Cpatch(:,indices) = space.CC_vertices{ivrt}{local_patch}; + Cpatch_cols = union (Cpatch_cols, global_indices); + end + end + +end \ No newline at end of file From de6f5f6e86b7bda23b015bf562604235f9441f28 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 16:01:10 +0100 Subject: [PATCH 237/366] Added new function --- .../@sp_multipatch_C1/sp_compute_Cpatch.m | 5 +- .../sp_get_functions_on_patch.m | 61 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m index f9186c7b..24cee7e6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m @@ -9,8 +9,9 @@ % % OUTPUT: % Cpatch: coefficients of the linear combination of basis functions as standard B-splines, -% The matrix has size ndof_per_patch(iptc) x numel(Cpatch_cols). -% Cpatch_cols: indices of the C^1 basis functions that do not vanish on the patch. +% The matrix has size ndof_per_patch(iptc) x numel(Cpatch_cols). +% Cpatch_cols: indices of the C^1 basis functions that do not vanish on the patch +% (see also sp_get_functions_on_patch) % % Copyright (C) 2022 Cesare Bracco, Rafael Vazquez % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m new file mode 100644 index 00000000..c514de88 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m @@ -0,0 +1,61 @@ +% SP_GET_FUNCTIONS_ON_PATCH: Compute the indices of non-vanishing basis functions on a patch. +% +% [Cpatch_cols] = sp_get_functions_on_patch (space, patch) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% patch: index of the patch +% +% OUTPUT: +% Cpatch_cols: indices of the C^1 basis functions that do not vanish on the patch. +% dofs_interior: indices of the C^1 interior basis functions. +% dofs_edge: indices of the C^1 edge basis functions. +% dofs_vertex: indices of the C^1 vertex basis functions. +% +% Copyright (C) 2022 Cesare Bracco, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [Cpatch_cols, dofs_interior, dofs_edge, dofs_vertex] = sp_get_functions_on_patch (space, iptc_ind) + + numel_interior_dofs = cellfun (@numel, space.interior_dofs_per_patch); + ndof_per_interface = cellfun (@numel, space.dofs_on_edge); + ndof_per_vertex = cellfun (@numel, space.dofs_on_vertex); + +% Interior basis functions + global_indices = sum (numel_interior_dofs(1:iptc_ind-1)) + (1:numel_interior_dofs(iptc_ind)); + dofs_interior = global_indices; + +% Edge basis functions + dofs_edge = []; + for intrfc = 1:numel(space.interfaces) + patches = [space.interfaces(intrfc).patch1 space.interfaces(intrfc).patch2]; + if (ismember (iptc_ind, patches)) + global_indices = space.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); + dofs_edge = union (dofs_edge, global_indices); + end + end + +% Vertex basis functions + dofs_vertex = []; + for ivrt = 1:numel(space.vertices) + if (ismember (iptc_ind, space.vertices(ivrt).patches)) + global_indices = space.ndof_interior + space.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); + dofs_vertex = union (dofs_vertex, global_indices); + end + end + + Cpatch_cols = union (union (dofs_interior, dofs_on_edge), dofs_on_vertex); + +end From 9a2c7771d3f0ae451a2dff6cb2403570518789f3 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 16:39:51 +0100 Subject: [PATCH 238/366] Fixed bug. Compute Cpatch only if needed in sp_get_* --- .../multipatch/@sp_multipatch_C1/sp_get_cells.m | 7 ++++--- .../@sp_multipatch_C1/sp_get_functions_on_patch.m | 2 +- .../multipatch/@sp_multipatch_C1/sp_get_neighbors.m | 7 ++++--- .../@sp_multipatch_C1/sp_get_vertex_neighbors.m | 13 +++++++++---- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m index bbec9f13..922c45f3 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -35,10 +35,11 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:space.npatch - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + Cpatch_cols = sp_get_functions_on_patch (space, iptc); [~,loc_f_inds,fun_indices_on_patch] = intersect (fun_indices, Cpatch_cols); - [patch_indices,local_funs] = find (Cpatch(:,fun_indices_on_patch)); - if (~isempty (patch_indices)) + if (~isempty (fun_indices_on_patch)) + Cpatch = sp_compute_Cpatch (space, iptc); + [patch_indices,local_funs] = find (Cpatch(:,fun_indices_on_patch)); patch_indices = patch_indices(:).'; [aux_cell_indices, ind_per_fun] = sp_get_cells (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m index c514de88..c95631c3 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m @@ -56,6 +56,6 @@ end end - Cpatch_cols = union (union (dofs_interior, dofs_on_edge), dofs_on_vertex); + Cpatch_cols = union (union (dofs_interior, dofs_edge), dofs_vertex); end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m index 03f620ea..5a17a53e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -30,10 +30,11 @@ neighbors_indices = []; for iptc = 1:space.npatch - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + Cpatch_cols = sp_get_functions_on_patch (space, iptc); [~,~,fun_indices_on_patch] = intersect (fun_indices, Cpatch_cols); - [patch_indices,~] = find (Cpatch(:,fun_indices_on_patch)); - if (~isempty (patch_indices)) + if (~isempty (fun_indices_on_patch)) + Cpatch = sp_compute_Cpatch (space, iptc); + [patch_indices,~] = find (Cpatch(:,fun_indices_on_patch)); aux_indices = sp_get_neighbors (space.sp_patch{iptc}, msh.msh_patch{iptc}, patch_indices); [~,global_indices] = find (Cpatch(aux_indices,:)); neighbors_indices = union (neighbors_indices, space.Cpatch_cols{iptc}(global_indices)); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index fe8608f9..297d8e34 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -38,11 +38,16 @@ Nelem = cumsum ([0 msh.nel_per_patch]); for iptc = 1:numel(patch_indices) patch = space.vertices(vertex_index).patches(patch_indices(iptc)); - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, patch); + Cpatch_cols = sp_get_functions_on_patch (space, patch); [~,~,inds] = intersect (space.dofs_on_vertex{vertex_index}, Cpatch_cols); - [bsp_indices, ~] = find (Cpatch(:,inds)); - [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); - cell_indices{iptc} = Nelem(patch) + aux_cell_indices(:).'; + if (~isempty (inds)) + Cpatch = sp_compute_Cpatch (space, patch); + [bsp_indices, ~] = find (Cpatch(:,inds)); + [aux_cell_indices, ~] = sp_get_cells (space.sp_patch{patch}, msh.msh_patch{patch}, bsp_indices(:)'); + cell_indices{iptc} = Nelem(patch) + aux_cell_indices(:).'; + else + cell_indices{iptc} = []; + end end end \ No newline at end of file From 9a1cdd2f27b40d709dcb73314f9e540348fd936e Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 16:52:29 +0100 Subject: [PATCH 239/366] Removed dofs_on_patch, to save memory --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index fa7a9993..1386c343 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -167,19 +167,19 @@ % Cpatch = cell (sp.npatch, 1); % Cpatch2 = cell (sp.npatch, 1); % Cpatch_cols = cell (sp.npatch, 1); - numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); - for iptc = 1:sp.npatch +% numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); +% for iptc = 1:sp.npatch % Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); - global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); +% global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); % rows = sp.interior_dofs_per_patch{iptc}; % cols = 1:numel_interior_dofs(iptc);%global_indices; % vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); % Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), numel_interior_dofs(iptc)); % Cpatch2{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... % speye (numel (sp.interior_dofs_per_patch{iptc})); - sp.dofs_on_patch{iptc} = global_indices; +% sp.dofs_on_patch{iptc} = global_indices; % Cpatch_cols{iptc} = global_indices; - end +% end sp.dofs_on_edge = cell (1, numel(interfaces_all)); for intrfc = 1:numel(interfaces_all) From 2de725ed27590ccddf12e2bda49a4cc22f4eb212 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 17:40:44 +0100 Subject: [PATCH 240/366] Removed use of interior_dofs_per_patch --- .../@sp_multipatch_C1/sp_compute_Cpatch.m | 4 +-- .../sp_get_functions_on_patch.m | 2 +- .../sp_get_local_interior_functions.m | 32 +++++++++++++++++++ .../@sp_multipatch_C1/sp_multipatch_C1.m | 27 +++++++++------- 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_local_interior_functions.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m index 24cee7e6..9eb0bccd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch.m @@ -30,13 +30,13 @@ function [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc_ind) - numel_interior_dofs = cellfun (@numel, space.interior_dofs_per_patch); + numel_interior_dofs = space.ndof_interior_per_patch; ndof_per_interface = cellfun (@numel, space.dofs_on_edge); ndof_per_vertex = cellfun (@numel, space.dofs_on_vertex); % Interior basis functions global_indices = sum (numel_interior_dofs(1:iptc_ind-1)) + (1:numel_interior_dofs(iptc_ind)); - rows = space.interior_dofs_per_patch{iptc_ind}; + rows = sp_get_local_interior_functions (space, iptc_ind);%space.interior_dofs_per_patch{iptc_ind}; cols = 1:numel_interior_dofs(iptc_ind);%global_indices; vals = ones (numel_interior_dofs(iptc_ind), 1); Cpatch = sparse (rows, cols, vals, space.ndof_per_patch(iptc_ind), numel_interior_dofs(iptc_ind)); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m index c95631c3..e14e7386 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m @@ -29,7 +29,7 @@ function [Cpatch_cols, dofs_interior, dofs_edge, dofs_vertex] = sp_get_functions_on_patch (space, iptc_ind) - numel_interior_dofs = cellfun (@numel, space.interior_dofs_per_patch); + numel_interior_dofs = space.ndof_interior_per_patch; ndof_per_interface = cellfun (@numel, space.dofs_on_edge); ndof_per_vertex = cellfun (@numel, space.dofs_on_vertex); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_local_interior_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_local_interior_functions.m new file mode 100644 index 00000000..1b5d8d80 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_local_interior_functions.m @@ -0,0 +1,32 @@ +% SP_GET_LOCAL_INTERIOR_FUNCTIONS: Compute the local indices of interior basis functions on a patch. +% +% [indices] = sp_get_local_interior_functions (space, patch) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% patch: index of the patch +% +% OUTPUT: +% indices: local indices of the C^1 interior basis functions. +% +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [interior_functions_per_patch] = sp_get_local_interior_functions (space, iptc_ind) + + [ii,jj] = ndgrid (3:space.sp_patch{iptc_ind}.ndof_dir(1)-2, 3:space.sp_patch{iptc_ind}.ndof_dir(2)-2); + interior_functions_per_patch = sub2ind (space.sp_patch{iptc_ind}.ndof_dir, ii(:)', jj(:)'); + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 1386c343..97edb470 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -19,6 +19,7 @@ % ncomp (scalar) number of components of the functions of the space (always equal to one) % ndof (scalar) total number of degrees of freedom after gluing patches together % ndof_per_patch (1 x npatch array) number of degrees of freedom per patch, without gluing +% ndof_interior_per_patch (1 x npatch array) number of interior basis functions on each patch % ndof_interior (scalar) total number of interior degrees of freedom % ndof_edges (scalar) total number of edge degrees of freedom % ndof_vertices (scalar) total number of vertex degrees of freedom @@ -138,18 +139,22 @@ % See the function compute_coefficients below for details. sp.ndof_interior = 0; for iptc = 1:sp.npatch - interior_dofs = 1:spaces{iptc}.ndof; - for intrfc = 1:numel(interfaces_all) - patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; - sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; - [is_interface,position] = ismember (iptc, patches); - if (is_interface) - sp_bnd = spaces{iptc}.boundary(sides(position)); - interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); - end - end - sp.interior_dofs_per_patch{iptc} = interior_dofs; + [ii,jj] = ndgrid (3:spaces{iptc}.ndof_dir(1)-2, 3:spaces{iptc}.ndof_dir(2)-2); + interior_dofs = sub2ind (spaces{iptc}.ndof_dir, ii(:)', jj(:)'); + +% interior_dofs = 1:spaces{iptc}.ndof; +% for intrfc = 1:numel(interfaces_all) +% patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; +% sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; +% [is_interface,position] = ismember (iptc, patches); +% if (is_interface) +% sp_bnd = spaces{iptc}.boundary(sides(position)); +% interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); +% end +% end +% sp.interior_dofs_per_patch{iptc} = interior_dofs; sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); + sp.ndof_interior_per_patch(iptc) = numel (interior_dofs); end [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... From 4c0af8447d5d6e52c178e1db8e482690e84de3e8 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 16 Nov 2022 18:00:25 +0100 Subject: [PATCH 241/366] Cleaning and help --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 57 +++---------------- 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 97edb470..28320464 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -23,12 +23,12 @@ % ndof_interior (scalar) total number of interior degrees of freedom % ndof_edges (scalar) total number of edge degrees of freedom % ndof_vertices (scalar) total number of vertex degrees of freedom -% interior_dofs_per_patch (1 x npatch cell-array) local number of interior functions on each patch % dofs_on_edge (1 x nedges cell-array) global numbering of edge functions on each edge % dofs_on_vertex (1 x nvertices cell-array) global numbering of the six functions on each vertex % sp_patch (1 x npatch cell-array) the input spaces, one space object for each patch (see sp_scalar) -% Cpatch (1 x npatch cell-array) coefficients of the linear combination of basis functions as standard B-splines, -% on each patch. The matrix Cpatch{iptc} has size ndof_per_patch(iptc) x ndof +% CC_edges (2 x nedges cell-array) matrices for B-spline representation of edge basis functions +% CC_vertices (1 x nvertices cell-array) matrices for B-spline representation of vertex basis functions, +% as many as the valence for each vertex % constructor function handle function handle to construct the same discrete space in a different msh % % METHODS @@ -46,9 +46,12 @@ % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements % sp_get_cells: compute the cells on which a list of functions do not vanish % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one +% sp_get_functions_on_patch: compute the indices of non-vanishing C^1 functions on a patch +% sp_get_local_interior_functions: compute the local indices of interior functions on a patch % % Other methods % sp_refine: generate a refined space, and subdivision matrices for the univariate spaces +% sp_compute_Cpatch: compute the matrix for B-splines representation on a patch % % Copyright (C) 2015-2022 Rafael Vazquez % Copyright (C) 2019-2022 Cesare Bracco @@ -142,20 +145,10 @@ [ii,jj] = ndgrid (3:spaces{iptc}.ndof_dir(1)-2, 3:spaces{iptc}.ndof_dir(2)-2); interior_dofs = sub2ind (spaces{iptc}.ndof_dir, ii(:)', jj(:)'); -% interior_dofs = 1:spaces{iptc}.ndof; -% for intrfc = 1:numel(interfaces_all) -% patches = [interfaces_all(intrfc).patch1, interfaces_all(intrfc).patch2]; -% sides = [interfaces_all(intrfc).side1, interfaces_all(intrfc).side2]; -% [is_interface,position] = ismember (iptc, patches); -% if (is_interface) -% sp_bnd = spaces{iptc}.boundary(sides(position)); -% interior_dofs = setdiff (interior_dofs, [sp_bnd.dofs, sp_bnd.adjacent_dofs]); -% end -% end -% sp.interior_dofs_per_patch{iptc} = interior_dofs; sp.ndof_interior = sp.ndof_interior + numel (interior_dofs); sp.ndof_interior_per_patch(iptc) = numel (interior_dofs); end + clear interior_dofs [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); @@ -168,53 +161,17 @@ sp.ndof_vertices = sum (ndof_per_vertex); sp.ndof = sp.ndof_interior + sp.ndof_edges + sp.ndof_vertices; -% Store the coefficients for matrix change in Cpatch -% Cpatch = cell (sp.npatch, 1); -% Cpatch2 = cell (sp.npatch, 1); -% Cpatch_cols = cell (sp.npatch, 1); -% numel_interior_dofs = cellfun (@numel, sp.interior_dofs_per_patch); -% for iptc = 1:sp.npatch -% Cpatch2{iptc} = sparse (sp.ndof_per_patch(iptc), sp.ndof); -% global_indices = sum (numel_interior_dofs(1:iptc-1)) + (1:numel_interior_dofs(iptc)); -% rows = sp.interior_dofs_per_patch{iptc}; -% cols = 1:numel_interior_dofs(iptc);%global_indices; -% vals = ones (numel(sp.interior_dofs_per_patch{iptc}), 1); -% Cpatch{iptc} = sparse (rows, cols, vals, sp.ndof_per_patch(iptc), numel_interior_dofs(iptc)); -% Cpatch2{iptc}(sp.interior_dofs_per_patch{iptc}, global_indices) = ... -% speye (numel (sp.interior_dofs_per_patch{iptc})); -% sp.dofs_on_patch{iptc} = global_indices; -% Cpatch_cols{iptc} = global_indices; -% end - sp.dofs_on_edge = cell (1, numel(interfaces_all)); for intrfc = 1:numel(interfaces_all) global_indices = sp.ndof_interior + sum(ndof_per_interface(1:intrfc-1)) + (1:ndof_per_interface(intrfc)); sp.dofs_on_edge{intrfc} = global_indices; -% patches = [interfaces_all(intrfc).patch1 interfaces_all(intrfc).patch2]; -% for iptc = 1:numel(patches) -% % Cpatch2{patches(iptc)}(:,global_indices) = CC_edges{iptc,intrfc}; -% indices = size(Cpatch{patches(iptc)},2) + (1:numel(global_indices)); -% % Cpatch{patches(iptc)}(:,indices) = CC_edges{iptc,intrfc}; -% % Cpatch_cols{patches(iptc)} = union (Cpatch_cols{patches(iptc)}, global_indices); -% end end sp.dofs_on_vertex = cell (1, numel(vertices)); for ivrt = 1:numel(vertices) global_indices = sp.ndof_interior + sp.ndof_edges + sum(ndof_per_vertex(1:ivrt-1)) + (1:ndof_per_vertex(ivrt)); sp.dofs_on_vertex{ivrt} = global_indices; -% for iptc = 1:vertices(ivrt).valence_p -% patch = vertices(ivrt).patches(iptc); -% % Cpatch2{patch}(:,global_indices) = CC_vertices{ivrt}{iptc}; -% % indices = size(Cpatch{patch},2) + (1:numel(global_indices)); -% % Cpatch{patch}(:,indices) = CC_vertices{ivrt}{iptc}; -% % Cpatch_cols{patch} = union (Cpatch_cols{patch}, global_indices); -% end end - -% sp.Cpatch = Cpatch; -% % sp.Cpatch2 = Cpatch2; -% sp.Cpatch_cols = Cpatch_cols; sp.CC_edges = CC_edges; sp.CC_vertices = CC_vertices; From 02d297fe43d20579e6f833e3710a56c4ce4c032c Mon Sep 17 00:00:00 2001 From: cesare Date: Tue, 7 Mar 2023 18:10:26 +0100 Subject: [PATCH 242/366] sign changes in sp_multipatch_C1 --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 28320464..45316fba 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -501,12 +501,12 @@ beta_der_prev = -all_beta0(edges(prev_edge),2) + all_beta1(edges(prev_edge),2); E_prev = CC_edges_discarded{2,edges(prev_edge)}(:,[1 2 3 7 8]); else - alpha_prev = all_alpha1(edges(prev_edge),1); + alpha_prev = -all_alpha1(edges(prev_edge),1); beta_prev = -all_beta1(edges(prev_edge),1); - alpha_der_prev = all_alpha0(edges(prev_edge),1) - all_alpha1(edges(prev_edge),1); + alpha_der_prev = -all_alpha0(edges(prev_edge),1) + all_alpha1(edges(prev_edge),1); beta_der_prev = -all_beta0(edges(prev_edge),1) + all_beta1(edges(prev_edge),1); E_prev = CC_edges_discarded{1,edges(prev_edge)}(:,[6 5 4 10 9]); - E_prev(:,[4 5]) = -E_prev(:,[4 5]); + E_prev(:,[4 5]) = E_prev(:,[4 5]); end if (edge_orientation(next_edge) == 1) alpha_next = all_alpha0(edges(next_edge),1); @@ -515,12 +515,12 @@ beta_der_next = -all_beta0(edges(next_edge),1) + all_beta1(edges(next_edge),1); E_next = CC_edges_discarded{1,edges(next_edge)}(:,[1 2 3 7 8]); else - alpha_next = all_alpha1(edges(next_edge),2); + alpha_next = -all_alpha1(edges(next_edge),2); beta_next = -all_beta1(edges(next_edge),2); - alpha_der_next = all_alpha0(edges(next_edge),2) - all_alpha1(edges(next_edge),2); + alpha_der_next = -all_alpha0(edges(next_edge),2) + all_alpha1(edges(next_edge),2); beta_der_next = -all_beta0(edges(next_edge),2) + all_beta1(edges(next_edge),2); E_next = CC_edges_discarded{2,edges(next_edge)}(:,[6 5 4 10 9]); - E_next(:,[4 5]) = -E_next(:,[4 5]); + E_next(:,[4 5]) = E_next(:,[4 5]); end Du_F = derivatives_new1{ipatch}(1:2,1); From 7aed664bc48e31a69067c51c59f56701030189af Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 17 Mar 2023 15:08:21 +0100 Subject: [PATCH 243/366] Change some variable names, remove unused lines, help and comments --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 45316fba..30ec7636 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -53,8 +53,8 @@ % sp_refine: generate a refined space, and subdivision matrices for the univariate spaces % sp_compute_Cpatch: compute the matrix for B-splines representation on a patch % -% Copyright (C) 2015-2022 Rafael Vazquez -% Copyright (C) 2019-2022 Cesare Bracco +% Copyright (C) 2015-2023 Rafael Vazquez +% Copyright (C) 2019-2023 Cesare Bracco % Copyright (C) 2022 Andrea Farahat % % This program is free software: you can redistribute it and/or modify @@ -335,7 +335,7 @@ A(jj,spn_struct.connectivity(:,jj)) = spn_struct.shape_functions(:,:,jj); end -%alphas and betas +% alphas and betas (gluing data) alpha = alpha0(ii)*(1-grev_pts{3-ii}') + alpha1(ii)*grev_pts{3-ii}'; beta = beta0(ii)*(1-grev_pts{3-ii}') + beta1(ii)*grev_pts{3-ii}'; @@ -506,7 +506,6 @@ alpha_der_prev = -all_alpha0(edges(prev_edge),1) + all_alpha1(edges(prev_edge),1); beta_der_prev = -all_beta0(edges(prev_edge),1) + all_beta1(edges(prev_edge),1); E_prev = CC_edges_discarded{1,edges(prev_edge)}(:,[6 5 4 10 9]); - E_prev(:,[4 5]) = E_prev(:,[4 5]); end if (edge_orientation(next_edge) == 1) alpha_next = all_alpha0(edges(next_edge),1); @@ -520,7 +519,6 @@ alpha_der_next = -all_alpha0(edges(next_edge),2) + all_alpha1(edges(next_edge),2); beta_der_next = -all_beta0(edges(next_edge),2) + all_beta1(edges(next_edge),2); E_next = CC_edges_discarded{2,edges(next_edge)}(:,[6 5 4 10 9]); - E_next(:,[4 5]) = E_next(:,[4 5]); end Du_F = derivatives_new1{ipatch}(1:2,1); @@ -544,7 +542,7 @@ % Compute M and V matrices ndof = space.sp_patch{patches(ipatch)}.ndof; - M_prev = sparse (5,6); M_next = sparse (5,6); + K_prev = sparse (5,6); K_next = sparse (5,6); VV = sparse (ndof,6); ndof_dir = space.sp_patch{patches(ipatch)}.ndof_dir; @@ -568,12 +566,12 @@ d0_b = vec_deltas.'*d0_next; d1_b = t0_next.'*mat_deltas*d0_next + vec_deltas.'*d0p_next; - M_prev(:,jfun) = sigma^(j1+j2)*[c0, ... + K_prev(:,jfun) = sigma^(j1+j2)*[c0, ... c0+c1_a/(deg_aux*nbrk_aux), ... c0+const1*c1_a/(deg_aux*nbrk_aux)+const2*c2_a/(deg_aux*(deg_aux-1)*nbrk_aux^2), ... d0_a/(deg_aux*nbrk_aux), ... d0_a/(deg_aux*nbrk_aux)+d1_a/(deg_aux*(deg_aux-1)*nbrk_aux^2)].'; - M_next(:,jfun) = sigma^(j1+j2)*[c0, ... + K_next(:,jfun) = sigma^(j1+j2)*[c0, ... c0+c1_b/(deg_aux*nbrk_aux), ... c0+const1*c1_b/(deg_aux*nbrk_aux)+const2*c2_b/(deg_aux*(deg_aux-1)*nbrk_aux^2), ... d0_b/(deg_aux*nbrk_aux), ... @@ -587,13 +585,13 @@ jfun = jfun+1; end end - CC_vertices{kver}{ipatch} = E_prev*M_prev + E_next*M_next - VV; + CC_vertices{kver}{ipatch} = E_prev*K_prev + E_next*K_next - VV; %Storing the matrices for output - KV_matrices{ipatch}.K_prev=M_prev; - KV_matrices{ipatch}.K_next=M_next; - KV_matrices{ipatch}.V=VV; - KV_matrices{ipatch}.E_prev=E_prev; - KV_matrices{ipatch}.E_next=E_next; + KV_matrices{ipatch}.K_prev = K_prev; + KV_matrices{ipatch}.K_next = K_next; + KV_matrices{ipatch}.V = VV; + KV_matrices{ipatch}.E_prev = E_prev; + KV_matrices{ipatch}.E_next = E_next; end v_fun_matrices{2,kver}=KV_matrices; end From d9c17c403bc32ed5db7696fa6c34c0d42edbaecc Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 20 Mar 2023 16:50:40 +0100 Subject: [PATCH 244/366] Update the help --- .../@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 18 +++++++++--------- .../space/@sp_scalar/sp_h2_equiv_lap_error.m | 9 +++++---- geopdes/inst/space/sp_h2_equiv_lap_error.m | 5 +++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m index 790d123b..50290b47 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -1,21 +1,21 @@ -% SP_H2_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. +% SP_H2_EQUIV_LAP_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. % % [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, lapuex) % % INPUT: % -% space: object defining the space of discrete functions (see sp_multipatch_C1) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% u: vector of dof weights -% uex: function handle to evaluate the exact solution +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% u: vector of dof weights +% uex: function handle to evaluate the exact solution % graduex: function handle to evaluate the gradient of the exact solution -% lapuex: function handle to evaluate the laplacian of the exact solution +% lapuex: function handle to evaluate the laplacian of the exact solution % % OUTPUT: % -% errh2: error in H^2 norm -% errh1: error in H^1 norm -% errl2: error in L^2 norm +% errh2: error in (equivalent) H^2 norm +% errh1: error in H^1 norm +% errl2: error in L^2 norm % errh2s: error in H^2 seminorm % errh1s: error in H^1 seminorm % diff --git a/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m b/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m index a8dc9bb3..2f9f6490 100644 --- a/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/space/@sp_scalar/sp_h2_equiv_lap_error.m @@ -1,6 +1,6 @@ -% SP_H2_ERROR: Evaluate the error in H^2 norm, H^1 and L^2 norms. +% SP_H2_EQUIV_LAP_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. % -% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, hessuex) +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_equiv_lap_error (sp, msh, u, uex, graduex, lapuex) % % INPUT: % @@ -9,11 +9,11 @@ % u: vector of dof weights % uex: function handle to evaluate the exact solution % graduex: function handle to evaluate the gradient of the exact solution -% hessuex: function handle to evaluate the hessian of the exact solution +% lapuex: function handle to evaluate the laplacian of the exact solution % % OUTPUT: % -% errh2: error in H^2 norm +% errh2: error in (equivalent) H^2 norm % errh1: error in H^1 norm % errl2: error in L^2 norm % errh2s: error in H^2 seminorm @@ -22,6 +22,7 @@ % Copyright (C) 2010 Carlo de Falco % Copyright (C) 2011, 2016, 2017 Rafael Vazquez % Copyright (C) 2015, 2016 Viacheslav Balobanov +% Copyright (C) 2022 Andrea Farahat % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by diff --git a/geopdes/inst/space/sp_h2_equiv_lap_error.m b/geopdes/inst/space/sp_h2_equiv_lap_error.m index 1068b9de..2f76d3c1 100644 --- a/geopdes/inst/space/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/space/sp_h2_equiv_lap_error.m @@ -9,11 +9,11 @@ % u: vector of dof weights % uex: function handle to evaluate the exact solution % graduex: function handle to evaluate the gradient of the exact solution -% lapuex: function handle to evaluate the laplacian of the exact solution +% lapuex: function handle to evaluate the laplacian of the exact solution % % OUTPUT: % -% errh2: error in H^2 norm +% errh2: error in (equivalent) H^2 norm % errh1: error in H^1 norm % errl2: error in L^2 norm % errh2s: error in H^2 seminorm (involving only second dervatives) @@ -27,6 +27,7 @@ % Copyright (C) 2010 Carlo de Falco % Copyright (C) 2011, 2016 Rafael Vazquez % Copyright (C) 2015, 2016 Viacheslav Balobanov +% Copyright (C) 2022 Andrea Farahat % % This program is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by From a9e9b2a601ac82281cf3608c0479524d0770cd48 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 29 Mar 2023 17:46:06 +0200 Subject: [PATCH 245/366] Changed computation of the kernel --- .../sp_bilaplacian_drchlt_C1.m | 79 +++++++++--------- .../sp_bilaplacian_drchlt_C1_exact.m | 81 ++++++++++--------- 2 files changed, 83 insertions(+), 77 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 78f55f76..6d0759fa 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -60,48 +60,51 @@ global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges for iv = 1 : numel(space.vertices) - if numel(space.vertices(iv).patches)>1 + if (space.vertices(iv).boundary_vertex && space.vertices(iv).valence_p>1) % Loop just over Dirichlet boundary vertices - if ~isempty(intersect(global_refs, space.vertices(iv).edges)) - if (space.vertices(iv).boundary_vertex) - - patches = space.vertices(iv).patches([1 end]); - - operations = space.vertices(iv).patch_reorientation([1 end], :); - indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); - indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); - - indices_loc_R = indices_loc_R(:); - indices_loc_L = indices_loc_L(:); - - Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + if (~isempty(intersect(global_refs, space.vertices(iv).edges))) + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + +% Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); +% Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + Cpatch_ind_R = indices_loc_R([1 2 3 space.sp_patch{patches(1)}.ndof_dir(1)+[1 2]]); + if (space.vertices(iv).valence_p == 2) + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + else + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + end % TODO: it is probably enough to use CC_vertices (and CC_edges) - [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); - [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); - - [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); - [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); - - M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... - Cpatch2(Cpatch_ind_L, inds2)]; -% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end - end + [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); + [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); + + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); + + M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... + Cpatch2(Cpatch_ind_L, inds2)]; +% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; end + end end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index b08b7f6b..67d7670e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact_rafa_mp (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); @@ -60,48 +60,51 @@ global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges for iv = 1 : numel(space.vertices) - if numel(space.vertices(iv).patches)>1 + if (space.vertices(iv).boundary_vertex && space.vertices(iv).valence_p>1) % Loop just over Dirichlet boundary vertices - if ~isempty(intersect(global_refs, space.vertices(iv).edges)) - if (space.vertices(iv).boundary_vertex) - - patches = space.vertices(iv).patches([1 end]); - - operations = space.vertices(iv).patch_reorientation([1 end], :); - indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); - indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); - - indices_loc_R = indices_loc_R(:); - indices_loc_L = indices_loc_L(:); - - Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + if (~isempty(intersect(global_refs, space.vertices(iv).edges))) + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + +% Cpatch_ind_R = indices_loc_R([2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); +% Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+1 space.sp_patch{patches(2)}.ndof_dir(1)+2 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + Cpatch_ind_R = indices_loc_R([1 2 3 space.sp_patch{patches(1)}.ndof_dir(1)+[1 2]]); + if (space.vertices(iv).valence_p == 2) + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + else + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + end % TODO: it is probably enough to use CC_vertices (and CC_edges) - [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); - [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); - - [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); - [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); - - M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... - Cpatch2(Cpatch_ind_L, inds2)]; -% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); - ker = null(full(M_ker)); - if (~isempty(ker)) - count_vert = count_vert + 1; - [~, ind] = max(abs(ker)); - - row_inds = (count_vert-1)*6 + (1:6); - B_change_local = blkdiag (B_change_local, ker(:)); - - dofs_on_vertex = space.dofs_on_vertex{iv}; - vertices_numbers(count_vert) = iv; - dofs_to_remove(count_vert) = dofs_on_vertex(ind); - row_indices(row_inds) = dofs_on_vertex; - end - end + [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); + [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); + + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); + + M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... + Cpatch2(Cpatch_ind_L, inds2)]; +% M_ker = M_bdry(space.dofs_on_vertex{iv}, space.dofs_on_vertex{iv}); + ker = null(full(M_ker)); + if (~isempty(ker)) + count_vert = count_vert + 1; + [~, ind] = max(abs(ker)); + + row_inds = (count_vert-1)*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker(:)); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_vert) = iv; + dofs_to_remove(count_vert) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; end + end end end From e0363df5795d68551d759f02f791951a4fb5f3a1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 30 Mar 2023 11:08:54 +0200 Subject: [PATCH 246/366] Correct function name --- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 67d7670e..0799086a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,4 +1,4 @@ -function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact_rafa_mp (space, msh, refs, uex, gradex) +function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); From bfc5e89e79a18e8deb3179273dd924fd60051c8d Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 30 Mar 2023 15:25:58 +0200 Subject: [PATCH 247/366] Fixed mistake --- .../multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m | 2 +- .../@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index 6d0759fa..db34f222 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -78,7 +78,7 @@ if (space.vertices(iv).valence_p == 2) Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); else - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + Cpatch_ind_L = indices_loc_L([2 space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); end % TODO: it is probably enough to use CC_vertices (and CC_edges) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 0799086a..66d0b0ce 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -78,7 +78,7 @@ if (space.vertices(iv).valence_p == 2) Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); else - Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); + Cpatch_ind_L = indices_loc_L([2 space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); end % TODO: it is probably enough to use CC_vertices (and CC_edges) From bdd80537b771837fbd7ab5d6ba75b22abfae2949 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:08:16 +0200 Subject: [PATCH 248/366] Removed unused file --- .../@sp_multipatch_C1/mp_solve_laplace_C1.m | 133 ------------------ 1 file changed, 133 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m deleted file mode 100644 index 903b622f..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/mp_solve_laplace_C1.m +++ /dev/null @@ -1,133 +0,0 @@ -% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. -% -% Example to solve the diffusion problem -% -% - div ( epsilon(x) grad (u)) = f in Omega -% epsilon(x) du/dn = g on Gamma_N -% u = h on Gamma_D -% -% where the domain \Omega is formed by several patches of the form F((0,1)^n). -% -% USAGE: -% -% [geometry, msh, space, u] = -% mp_solve_laplace (problem_data, method_data) -% -% INPUT: -% -% problem_data: a structure with data of the problem. It contains the fields: -% - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition -% - c_diff: diffusion coefficient (epsilon in the equation) -% - f: source term -% - g: function for Neumann condition (if nmnn_sides is not empty) -% - h: function for Dirichlet boundary condition -% -% method_data : a structure with discretization data. Its fields are: -% - degree: degree of the spline functions. -% - regularity: continuity of the spline functions. -% - nsub: number of subelements with respect to the geometry mesh -% (nsub=1 leaves the mesh unchanged) -% - nquad: number of points for Gaussian quadrature rule -% -% OUTPUT: -% -% geometry: array of geometry structures (see geo_load) -% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) -% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) -% u: the computed degrees of freedom -% -% Copyright (C) 2009, 2010 Carlo de Falco -% Copyright (C) 2010, 2011, 2013, 2015, 2017 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 2 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [geometry, msh, space, u] = ... - mp_solve_laplace_C1 (problem_data, method_data) - -% Extract the fields from the data structures into local variables -data_names = fieldnames (problem_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); -end -data_names = fieldnames (method_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= method_data.(data_names{iopt});']); -end - -% Construct geometry structure, and information for interfaces and boundaries -[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); -npatch = numel (geometry); - -msh = cell (1, npatch); -sp = cell (1, npatch); -for iptc = 1:npatch - -% Define the refined mesh, with tensor product structure - [knots{iptc}, zeta{iptc}] = ... - kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); - -% Compute the quadrature rule - rule = msh_gauss_nodes (nquad); - [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); - msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); - -% Evaluate the discrete space basis functions in the quadrature points - sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); -end - -msh = msh_multipatch (msh, boundaries); -% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); -space = sp_multipatch_C1 (sp, msh, geometry, interfaces, boundary_interfaces); -clear sp - -% Compute and assemble the matrices -stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); -rhs = op_f_v_mp (space, msh, f); - -% Apply Neumann boundary conditions -for iref = nmnn_sides - gref = @(varargin) g(varargin{:}, iref); - for bnd_side = 1:msh.boundaries(iref).nsides - iptc = msh.boundaries(iref).patches(bnd_side); - iside = msh.boundaries(iref).faces(bnd_side); - - msh_side = msh.msh_patch{iptc}.boundary(iside); - sp_side = space.sp_patch{iptc}.boundary(iside); - rhs_nmnn = op_f_v_tp (sp_side, msh_side, gref); - rhs = rhs + space.Cpatch{iptc}(sp_side.dofs,:).' * rhs_nmnn; - end -end - -% Apply Dirichlet boundary conditions in weak form, by Nitsche's method -if (exist ('weak_drchlt_sides', 'var')) - [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, weak_drchlt_sides, h, c_diff, Cpen); - stiff_mat = stiff_mat - N_mat; - rhs = rhs + N_rhs; -end - -% Solve the linear system -u = stiff_mat \ rhs; - -end - -%!demo -%! ex_laplace_Lshaped_mp - -%!demo -%! ex_laplace_cube_mp - -%!demo -%! ex_laplace_thick_L_mp From 554768162040eac4e044298b4c139b7b6bdd13bb Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:13:02 +0200 Subject: [PATCH 249/366] Minor change (default variables not necessary) --- .../multipatch/@sp_multipatch_C1/sp_plot_solution.m | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m index c560c9ec..b7ec155e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -28,14 +28,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp_plot_solution (u, space, geometry, npts, ncuts) - -if (nargin < 4) - npts = []; -end -if (nargin < 5) - ncuts = []; -end +function sp_plot_solution (u, space, geometry, varargin) % if (isa (space.sp_patch{1}, 'sp_vector')) % disp ('Warning: a different scaling is used for each patch') @@ -45,7 +38,7 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) for iptc = 1:space.npatch % if (isempty (space.dofs_ornt)) [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - sp_plot_solution (Cpatch* u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), npts, ncuts); + sp_plot_solution (Cpatch* u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), varargin{:}); % else % sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); % end From 9f59c3aaae91ea4f5efe2508d5d18f695a70ab65 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:15:49 +0200 Subject: [PATCH 250/366] Some cleaning --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 30ec7636..16bf7bb6 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -288,7 +288,7 @@ % Compute the Greville points, and the auxiliary mesh and space objects for % functions with reduced degree or increased regularity for ii = 1:npatches_on_edge -%% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] +% %ind1 = [2 2 1 1]; ind2 = [1 1 2 2] ind2 = ceil (sides(ii)/2); ind1 = setdiff (1:msh.ndim, ind2); @@ -424,9 +424,9 @@ KV_matrices=cell(1,valence_p); geo_local = reorientation_patches (operations, geometry(patches)); - %Here we need to further modify geo_local by rotating the parametrization - %of the patches, that is, for each ip in patches, rotate the control points - %geometry(ip).nurbs.coefs (4 x (number of control points in dir 1) x (number of control points in dir 2) matrix) + % Here we need to further modify geo_local by rotating the parametrization + % of the patches, that is, for each ip in patches, rotate the control points + % geometry(ip).nurbs.coefs (4 x (number of control points in dir 1) x (number of control points in dir 2) matrix) % Precompute the derivatives and compute sigma sigma = 0; @@ -443,22 +443,22 @@ sigma = sigma + norm (derivatives_new1{iptc}, Inf); end sigma = deg_aux * nbrk_aux * valence_p / sigma; - %Storing sigma for output +% Store sigma for output v_fun_matrices{1,kver} = sigma; if (msh.ndim+1 == msh.rdim) - %Tangent vectors + % Tangent vectors Du_F = derivatives_new1{1}(:,1); Dv_F = derivatives_new1{1}(:,2); - %Normal vector + % Normal vector normal = cross(Du_F,Dv_F); unit_normal = normal/norm(normal); - %Vector orthogonal to n and z along which the geometry is rotated (rotation axis) + % Vector orthogonal to n and z along which the geometry is rotated (rotation axis) r = cross(unit_normal,[0 0 1]'); - %Angle between n and z + % Angle between n and z cos_th = [0 0 1]*unit_normal; sin_th = norm(r); - %Rotation matrix + % Rotation matrix R = [cos_th + r(1)^2*(1-cos_th),r(1)*r(2)*(1-cos_th)-r(3)*sin_th,r(1)*r(3)*(1-cos_th)+r(2)*sin_th;... r(1)*r(2)*(1-cos_th)+r(3)*sin_th,cos_th + r(2)^2*(1-cos_th),r(2)*r(3)*(1-cos_th)-r(1)*sin_th;... r(1)*r(3)*(1-cos_th)-r(2)*sin_th,r(3)*r(2)*(1-cos_th)+r(1)*sin_th,cos_th + r(3)^2*(1-cos_th)]; @@ -554,13 +554,11 @@ mat_deltas = [(j1==2)*(j2==0), (j1==1)*(j2==1); (j1==1)*(j2==1), (j1==0)*(j2==2)]; vec_deltas = [(j1==1)*(j2==0); (j1==0)*(j2==1)]; c0 = (j1==0)*(j2==0); - %M_{i_{m-1},i} c1_a = vec_deltas.'*t0_prev; c2_a = t0_prev.'*mat_deltas*t0_prev + vec_deltas.'*t0p_prev; d0_a = vec_deltas.'*d0_prev; d1_a = t0_prev.'*mat_deltas*d0_prev + vec_deltas.'*d0p_prev; - %M_{i_{m+1},i} c1_b = vec_deltas.'*t0_next; c2_b = t0_next.'*mat_deltas*t0_next + vec_deltas.'*t0p_next; d0_b = vec_deltas.'*d0_next; @@ -576,7 +574,6 @@ c0+const1*c1_b/(deg_aux*nbrk_aux)+const2*c2_b/(deg_aux*(deg_aux-1)*nbrk_aux^2), ... d0_b/(deg_aux*nbrk_aux), ... d0_b/(deg_aux*nbrk_aux)+d1_b/(deg_aux*(deg_aux-1)*nbrk_aux^2)].'; - %V_{i_m,i} e11 = t0_prev.'*mat_deltas*t0_next + vec_deltas.'*Duv_F; VV(corner_4dofs,jfun) = sigma^(j1+j2)*[c0, ... c0+c1_a/(deg_aux*nbrk_aux), ... @@ -586,7 +583,7 @@ end end CC_vertices{kver}{ipatch} = E_prev*K_prev + E_next*K_next - VV; - %Storing the matrices for output +% Store the matrices for output KV_matrices{ipatch}.K_prev = K_prev; KV_matrices{ipatch}.K_next = K_next; KV_matrices{ipatch}.V = VV; From ffca0b3cf0107ad068f54048dbe84ce93ace4388 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:19:30 +0200 Subject: [PATCH 251/366] Removed unused file --- .../@sp_multipatch_C1/solve_laplace.m | 139 ------------------ 1 file changed, 139 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m deleted file mode 100644 index 73dc7df5..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/solve_laplace.m +++ /dev/null @@ -1,139 +0,0 @@ -% SOLVE_LAPLACE: Solve a Laplace problem with a B-spline discretization (non-isoparametric approach). -% -% The function solves the diffusion problem -% -% - div ( epsilon(x) grad (u)) = f in Omega = F((0,1)^n) -% epsilon(x) du/dn = g on Gamma_N -% u = h on Gamma_D -% -% USAGE: -% -% [geometry, msh, space, u] = solve_laplace (problem_data, method_data) -% -% INPUT: -% -% problem_data: a structure with data of the problem. It contains the fields: -% - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition -% - c_diff: diffusion coefficient (epsilon in the equation) -% - f: source term -% - g: function for Neumann condition (if nmnn_sides is not empty) -% - h: function for Dirichlet boundary condition -% -% method_data : a structure with discretization data. Its fields are: -% - degree: degree of the spline functions. -% - regularity: continuity of the spline functions. -% - nsub: number of subelements with respect to the geometry mesh -% (nsub=1 leaves the mesh unchanged) -% - nquad: number of points for Gaussian quadrature rule -% -% OUTPUT: -% -% geometry: geometry structure (see geo_load) -% msh: mesh object that defines the quadrature rule (see msh_cartesian) -% space: space object that defines the discrete space (see sp_scalar) -% u: the computed degrees of freedom -% -% See also EX_LAPLACE_SQUARE, EX_LAPLACE_THICK_RING for examples. -% -% Copyright (C) 2009, 2010, 2011 Carlo de Falco -% Copyright (C) 2011, 2015 Rafael Vazquez -% -% This program is free software: you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation, either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with this program. If not, see . - -function [geometry, msh, space, u] = ... - solve_laplace (problem_data, method_data) - -% Extract the fields from the data structures into local variables -data_names = fieldnames (problem_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); -end -data_names = fieldnames (method_data); -for iopt = 1:numel (data_names) - eval ([data_names{iopt} '= method_data.(data_names{iopt});']); -end - -% Construct geometry structure -geometry = geo_load (geo_name); - -[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); - -% Construct msh structure -rule = msh_gauss_nodes (nquad); -[qn, qw] = msh_set_quad_nodes (zeta, rule); -msh = msh_cartesian (zeta, qn, qw, geometry); - -% Construct space structure -space = sp_bspline (knots, degree, msh); - -% Assemble the matrices -stiff_mat = op_gradu_gradv_tp (space, space, msh, c_diff); -rhs = op_f_v_tp (space, msh, f); - -% Apply Neumann boundary conditions -for iside = nmnn_sides - if (msh.ndim > 1) -% Restrict the function handle to the specified side, in any dimension, gside = @(x,y) g(x,y,iside) - gside = @(varargin) g(varargin{:},iside); - dofs = space.boundary(iside).dofs; - rhs(dofs) = rhs(dofs) + op_f_v_tp (space.boundary(iside), msh.boundary(iside), gside); - else - if (iside == 1) - x = msh.breaks{1}(1); - else - x = msh.breaks{1}(end); - end - sp_side = space.boundary(iside); - rhs(sp_side.dofs) = rhs(sp_side.dofs) + g(x,iside); - end -end - -% Apply Dirichlet boundary conditions -u = zeros (space.ndof, 1); -[u_drchlt, drchlt_dofs] = sp_drchlt_l2_proj (space, msh, h, drchlt_sides); -u(drchlt_dofs) = u_drchlt; - -int_dofs = setdiff (1:space.ndof, drchlt_dofs); -rhs(int_dofs) = rhs(int_dofs) - stiff_mat(int_dofs, drchlt_dofs)*u_drchlt; - -% Solve the linear system -u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); - -end - -%!demo -%! ex_laplace_square - -%!demo -%! ex_laplace_plate - -%!demo -%! ex_laplace_ring - -%!demo -%! ex_laplace_ring_mixed_bc - -%!demo -%! ex_laplace_cube - -%!demo -%! ex_laplace_thick_ring - -%!demo -%! ex_laplace_beltrami - -%!demo -%! ex_laplace_1d From 2f27c82f1b5f79dd7634737cac957c74e59ea160 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:25:38 +0200 Subject: [PATCH 252/366] Remove unnecessary function --- .../@sp_multipatch_C1/sp_l2_lap_error.m | 48 ------------------- 1 file changed, 48 deletions(-) delete mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m deleted file mode 100644 index 0e108798..00000000 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_lap_error.m +++ /dev/null @@ -1,48 +0,0 @@ -% SP_L2_ERROR: Evaluate the error in L^2 norm. -% -% errl2 = sp_l2_error (space, msh, u, uex) -% -% INPUT: -% -% space: object defining the space of discrete functions (see sp_multipatch) -% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) -% u: vector of dof weights -% uex: function handle to evaluate the exact solution -% -% OUTPUT: -% -% errl2: error in L^2 norm -% -% Copyright (C) 2015 Rafael Vazquez -% -% This program is free software; you can redistribute it and/or modify -% it under the terms of the GNU General Public License as published by -% the Free Software Foundation; either version 3 of the License, or -% (at your option) any later version. - -% This program is distributed in the hope that it will be useful, -% but WITHOUT ANY WARRANTY; without even the implied warranty of -% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -% GNU General Public License for more details. -% -% You should have received a copy of the GNU General Public License -% along with Octave; see the file COPYING. If not, see -% . - -function errl2_lap = sp_l2_lap_error (space, msh, u, lapuex) - - if (space.npatch ~= msh.npatch) - error ('The number of patches does not coincide') - end - - for iptc = 1:msh.npatch -% if (isempty (space.dofs_ornt)) - u_ptc = space.Cpatch{iptc} * u; -% else -% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; -% end - error_l2_lap(iptc) = sp_l2_lap_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, lapuex); - end - errl2_lap = sqrt (sum (error_l2_lap .* error_l2_lap)); - -end \ No newline at end of file From f2f81e84288deac20ca62d089b41831ac2af289c Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:28:49 +0200 Subject: [PATCH 253/366] Added details in the help --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m index d4b7d666..8cc3ab2e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -1,7 +1,7 @@ % SP_REFINE: construct a refined space from a given one. The function only % refines the space, the mesh must be refined separately. % -% [sp_fine, Proj] = sp_refine (space, msh, nsub, [degree], [regularity]); +% [sp_fine, Proj, Proj0, Proj1] = sp_refine (space, msh, nsub, [degree], [regularity]); % % The same number of subdivisions, degree and regularity is applied to every patch % @@ -19,8 +19,10 @@ % Proj: the coefficients relating 1D splines of the coarse and the fine spaces for each patch. % A cell-array of size 1 x npatch, each entry containing the % coefficients for the patch (either for scalar or vector-valued spaces). +% Proj0: similar to Proj, for degree p and regularity r+1. +% Proj1: similar to Proj, for degree p-1 and regularity r. % -% Copyright (C) 2015, 2016 Rafael Vazquez +% Copyright (C) 2015-2023 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by From 6c7b3337df3087f26f0181d83944a317161bce6c Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 12:49:56 +0200 Subject: [PATCH 254/366] Added help, plus two more equations for the kernel. --- .../sp_bilaplacian_drchlt_C1.m | 42 +++++++++++++++++- .../sp_bilaplacian_drchlt_C1_exact.m | 43 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index db34f222..b7d149f4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,6 +1,46 @@ +% SP_BILAPLACIAN_DRCHLT_C1: assign the degrees of freedom of essential boundary conditions (value and normal derivative) through a projection. +% On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. +% +% [u, dofs] = sp_drchlt_l2_proj (sp, msh, refs, h, dudn) +% +% INPUT: +% +% sp: object representing the multipatch space of trial functions (see sp_multipatch) +% msh: object containing the domain partition and the quadrature rule (see msh_multipatch) +% refs: boundary references on which the conditions are imposed +% h: function handle to compute the Dirichlet condition +% dudn: function handle to compute the Neumann condition +% +% OUTPUT: +% +% u: assigned value to the degrees of freedom +% dofs: global numbering of the corresponding basis functions +% kernel_info: a struct with information of kernel computation, containing: +% - vertices_numbers: vertices which contain a function in the kernel +% - all_vertex_dofs: all functions on those vertices +% - quasi_interior_dofs: functions that will be treated as +% internal ones (as many as in the kernel) +% - B_change_local: coefficients of the functions in the kernel, +% in terms of vertex basis functions. Matrix of size +% numel(all_vertex_dofs) x numel (quasi_interior_dofs) +% +% Copyright (C) 2022-2023 Cesare Bracco, Andrea Farahat, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1 (space, msh, refs, h, dudn) -% refs should be the whole boundary, for now M = spalloc (space.ndof, space.ndof, space.ndof); rhs = zeros (space.ndof, 1); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 66d0b0ce..7940670d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,3 +1,44 @@ +% SP_BILAPLACIAN_DRCHLT_C1_EXACT: assign the degrees of freedom of essential boundary conditions (value and normal derivative) through a projection. +% On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. +% +% [u, dofs] = sp_drchlt_l2_proj (sp, msh, refs, h, dudn) +% +% INPUT: +% +% sp: object representing the multipatch space of trial functions (see sp_multipatch) +% msh: object containing the domain partition and the quadrature rule (see msh_multipatch) +% refs: boundary references on which the conditions are imposed +% uex: function handle to compute the Dirichlet condition from the exact solution +% graduex: function handle to compute the Neumann condition from the exact gradient +% +% OUTPUT: +% +% u: assigned value to the degrees of freedom +% dofs: global numbering of the corresponding basis functions +% kernel_info: a struct with information of kernel computation, containing: +% - vertices_numbers: vertices which contain a function in the kernel +% - all_vertex_dofs: all functions on those vertices +% - quasi_interior_dofs: functions that will be treated as +% internal ones (as many as in the kernel) +% - B_change_local: coefficients of the functions in the kernel, +% in terms of vertex basis functions. Matrix of size +% numel(all_vertex_dofs) x numel (quasi_interior_dofs) +% +% Copyright (C) 2022-2023 Cesare Bracco, Andrea Farahat, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + function [u_drchlt, drchlt_dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact (space, msh, refs, uex, gradex) % refs should be the whole boundary, for now @@ -80,6 +121,8 @@ else Cpatch_ind_L = indices_loc_L([2 space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); end +% Cpatch_ind_R = indices_loc_R([1 2 3 space.sp_patch{patches(1)}.ndof_dir(1)+2]); +% Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); % TODO: it is probably enough to use CC_vertices (and CC_edges) [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); From 9a8b172f8c734c9cc5f5db5a193509d88a8e39ca Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 11:22:51 +0100 Subject: [PATCH 255/366] Added new operators --- .../multipatch/@sp_multipatch/op_f_curlv_mp.m | 51 ++++++++++++++++ .../multipatch/@sp_multipatch/op_f_gradv_mp.m | 51 ++++++++++++++++ geopdes/inst/operators/op_f_curlv_3d.m | 59 +++++++++++++++++++ geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m | 52 ++++++++++++++++ geopdes/inst/space/@sp_vector/op_f_curlv_tp.m | 54 +++++++++++++++++ 5 files changed, 267 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m create mode 100644 geopdes/inst/operators/op_f_curlv_3d.m create mode 100644 geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m create mode 100644 geopdes/inst/space/@sp_vector/op_f_curlv_tp.m diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m new file mode 100644 index 00000000..30f6cdd3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m @@ -0,0 +1,51 @@ +% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% +% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_curlv_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_curlv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + + if (~isempty (space.dofs_ornt)) + rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); + end + rhs(space.gnum{iptc}) = rhs(space.gnum{iptc}) + rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m new file mode 100644 index 00000000..e4072c54 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m @@ -0,0 +1,51 @@ +% OP_F_GRADV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, grad v_i), in a multipatch domain. +% +% rhs = op_f_gradv_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_gradv_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_gradv_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_gradv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + + if (~isempty (space.dofs_ornt)) + rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); + end + rhs(space.gnum{iptc}) = rhs(space.gnum{iptc}) + rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/operators/op_f_curlv_3d.m b/geopdes/inst/operators/op_f_curlv_3d.m new file mode 100644 index 00000000..10e215b3 --- /dev/null +++ b/geopdes/inst/operators/op_f_curlv_3d.m @@ -0,0 +1,59 @@ +% OP_F_curlV_3d: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i). +% +% rhs = op_f_curlv_3d (spv, msh, coeff); +% +% INPUT: +% +% spv: structure representing the function space (see sp_vector/sp_evaluate_col) +% msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) +% coeff: source function evaluated at the quadrature points +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2011, 2017, 2019, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_3d (spv, msh, coeff) + + coeff = reshape (coeff, spv.ncomp, [], msh.nqn, msh.nel); + + rhs = zeros (spv.ndof, 1); + curlv = reshape (spv.shape_function_curls, spv.ncomp, msh.nqn, spv.nsh_max, msh.nel); + + jacdet_weights = msh.jacdet .* msh.quad_weights; + + for iel = 1:msh.nel + if (all (msh.jacdet(:,iel))) + coeff_iel = reshape (coeff(:,:,:,iel), spv.ncomp, msh.nqn, 1, 1); + jacdet_iel = reshape (jacdet_weights(:, iel), [1, msh.nqn, 1, 1]); + coeff_times_jw = bsxfun (@times, jacdet_iel, coeff_iel); + + curlv_iel = reshape (curlv(:,:,:,iel), spv.ncomp, msh.nqn, spv.nsh_max, 1); + + aux_val = bsxfun (@times, coeff_times_jw, curlv_iel); + rhs_loc = sum (sum (aux_val, 1), 2); + + indices = find (spv.connectivity(:,iel)); + rhs_loc = rhs_loc(indices); conn_iel = spv.connectivity(indices,iel); + rhs(conn_iel) = rhs(conn_iel) + rhs_loc(:); + else + warning ('geopdes:jacdet_zero_at_quad_node', 'op_f_curlv_3d: singular map in element number %d', iel) + end + end + +end diff --git a/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m b/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m new file mode 100644 index 00000000..45a53beb --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m @@ -0,0 +1,52 @@ +% OP_F_GRADV_TP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, grad v_i), exploiting the tensor product structure. +% +% rhs = op_f_gradv_tp (spv, msh, coeff); +% +% INPUT: +% +% spv: object representing the function space (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% coeff: function handle to compute the source function +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2011, 2017, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_gradv_tp (space, msh, coeff) + + for idim = 1:msh.ndim + size1 = size (space.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + + rhs = zeros (space.ndof, 1); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'value', false, 'gradient', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + rhs = rhs + op_f_gradv (sp_col, msh_col, coeff (x{:})); + end + +end diff --git a/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m b/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m new file mode 100644 index 00000000..e0d268cc --- /dev/null +++ b/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m @@ -0,0 +1,54 @@ +% OP_F_CURLV_TP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i), exploiting the tensor product structure. +% +% rhs = op_f_curlv_tp (spv, msh, coeff); +% +% INPUT: +% +% spv: object representing the function space (see sp_vector) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% coeff: function handle to compute the source function +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2011, 2017, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_tp (space, msh, coeff) + + for icomp = 1:space.ncomp_param + for idim = 1:msh.ndim + size1 = size (space.scalar_spaces{icomp}.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + end + + rhs = zeros (space.ndof, 1); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'value', false, 'curl', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + rhs = rhs + op_f_curlv_3d (sp_col, msh_col, coeff (x{:})); + end + +end From c725308ec83e1b8abb32dadce78651d19df8af2e Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 11:27:08 +0100 Subject: [PATCH 256/366] Updated citation information --- geopdes/CITATION | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geopdes/CITATION b/geopdes/CITATION index 125bfca1..aa9ba063 100644 --- a/geopdes/CITATION +++ b/geopdes/CITATION @@ -2,7 +2,7 @@ To cite the GeoPDEs package, please use R. Vazquez A new design for the implementation of isogeometric analysis in Octave and Matlab: GeoPDEs 3.0 - To appear in Computers and Mathematics with Applications + Computers and Mathematics with Applications, 72(3):523-554, 2016. C. de Falco, A. Reali, and R. Vazquez. GeoPDEs: A research tool for isogeometric analysis of PDEs. @@ -13,14 +13,17 @@ The BibTeX entries for LaTeX users are: @article{geopdes3.0, Author = {R. V{\'a}zquez}, Journal = {Computers and Mathematics with Applications}, + Number = {3}, + Pages = {523-554}, Title = {A new design for the implementation of isogeometric analysis in {O}ctave and {M}atlab: Geo{PDE}s 3.0}, Note = {To appear}, + Volume = {72}, Year = {2016}} @article{geopdes, Author = {C. de Falco and A. Reali and R. V{\'a}zquez}, Journal = {Advances in Engineering Software}, - Number = {12}, + Number = {3}, Pages = {1020-1034}, Title = {Geo{PDE}s: A research tool for Isogeometric Analysis of {PDE}s}, Volume = {42}, From 1bd60f86c5223db07fe2bf754940a0ed2ced2513 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 18:34:40 +0100 Subject: [PATCH 257/366] Changes in the help --- geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m index 30f6cdd3..9d9f0bee 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m @@ -1,10 +1,10 @@ -% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i), in a multipatch domain. % -% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% rhs = op_f_curlv_mp (spv, msh, coeff, [patches]); % % INPUT: % -% spv: object representing the function space (see sp_multipatch) +% spv: object representing the vector-valued function space (see sp_multipatch) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % coeff: function handle to compute the source function % patches: list of patches where the integrals have to be computed. By default, all patches are selected. From bf739238750ef07d858aea6bb8e56457231ace0d Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 8 Mar 2023 14:19:30 +0100 Subject: [PATCH 258/366] Added exterior derivative --- .../@sp_multipatch/sp_exterior_derivative.m | 58 +++++++ geopdes/inst/operators/op_geom_exterior.m | 159 ++++++++++++++++++ .../space/@sp_scalar/sp_exterior_derivative.m | 71 ++++++++ .../space/@sp_vector/sp_exterior_derivative.m | 94 +++++++++++ 4 files changed, 382 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m create mode 100644 geopdes/inst/operators/op_geom_exterior.m create mode 100644 geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m create mode 100644 geopdes/inst/space/@sp_vector/sp_exterior_derivative.m diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m b/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m new file mode 100644 index 00000000..0c2d6006 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m @@ -0,0 +1,58 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (space1.npatch == space2.npatch, 'The spaces correspond to different domains') + npatch = space1.npatch; + + diff_op = sparse (space2.ndof, space1.ndof); + + for iptc = 1:npatch + Dmat = sp_exterior_derivative (space1.sp_patch{iptc}, space2.sp_patch{iptc}); + + ndof1 = space1.sp_patch{iptc}.ndof; + ndof2 = space2.sp_patch{iptc}.ndof; + if (isa (space1.sp_patch{iptc}, 'sp_vector')) + dofs_ornt = space1.dofs_ornt{iptc}; + Dornt_1 = spdiags (dofs_ornt(:), 0, ndof1, ndof1); + else + Dornt_1 = speye (ndof1, ndof1); + end + if (isa (space2.sp_patch{iptc}, 'sp_vector')) + dofs_ornt = space2.dofs_ornt{iptc}; + Dornt_2 = spdiags (dofs_ornt(:), 0, ndof2, ndof2); + else + Dornt_2 = speye (ndof2, ndof2); + end + gnum1 = space1.gnum{iptc}(:); + gnum2 = space2.gnum{iptc}(:); + diff_op(gnum2, gnum1) = Dornt_2 * Dmat * Dornt_1; + end + +end diff --git a/geopdes/inst/operators/op_geom_exterior.m b/geopdes/inst/operators/op_geom_exterior.m new file mode 100644 index 00000000..80767e34 --- /dev/null +++ b/geopdes/inst/operators/op_geom_exterior.m @@ -0,0 +1,159 @@ +function diff_ops = op_geom_exterior (knots, degrees, grad_curl, coo) + +% OP_GEOM_EXTERIOR: computes the exterior derivatives d_0,...,d_(n-1) +% starting from the H^1-conforming space of 0-forms which is deduced by the +% input knot vector and polynomial degrees +% +% diff_ops = op_geom_exterior (knots, degrees, [grad_curl]); +% +% INPUT: +% +% knots: initial knot vector +% degrees: polynomial degree(s) of the (multivariate) space of 0-forms +% grad_curl: can be either 'grad' or 'curl', a flag which denotes which +% sequence of operators is sought between the one starting with +% the gradient and the one starting with the rotated gradient. +% Only valid in the 2D case. Default value is 'grad'. +% coo: true if COO representation of sparse matrices is desired, +% false if Matlab sparse matrix representation is desired. +% Default value is false. +% +% +% OUTPUT: +% +% diff_ops: cell-array containing the (sparse) matrix representation of the +% differential operators. The k-th entry corresponds to the +% exterior derivative d_(k-1). +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + + + if nargin < 3 + grad_curl = 'grad'; + coo = false; + else + assert(ismember(grad_curl,{'grad','curl'}), ... + ' op_geom_exterior: Unrecognized input parameter!'); + if nargin < 4 + coo = false; + end + end + ndim = numel(knots); + + Id = cell(ndim,1); + Id_deriv = cell(ndim,1); + D_univ = cell(ndim,1); + + if strcmpi(grad_curl,'curl') + assert(ndim == 2, strcat(' op_geom_exterior: div-curl short exact sequence',... + ' only available in two dimensions!')); + end + + if ~iscell(knots) + knots = {knots}; + end + + if numel(degrees) == 1 + degrees = repmat(degrees,1,ndim); + end + + %% Build matrices for univariate differential operators + for kdim = 1:ndim + degree = degrees(kdim); + dim_univ = numel(knots{kdim})-degree-1; + dim_d_univ = dim_univ-1; + d_knots = knots{kdim}(2:end-1); + Id{kdim} = speye(dim_univ); + Id_deriv{kdim} = speye(dim_univ-1); + + scaling = degree./(abs(d_knots((1:dim_d_univ)+degree) - d_knots(1:dim_d_univ)).'); + + d_univ_rows = repmat((1:dim_d_univ).',1,2); + d_univ_cols = [ d_univ_rows(:,1), d_univ_rows(:,2)+1]; + d_univ_vals = bsxfun (@times, scaling(:), [ -ones(dim_d_univ,1), ones(dim_d_univ,1)]); + + D_univ{kdim} = sparse(d_univ_rows(:), ... + d_univ_cols(:), ... + d_univ_vals(:), ... + dim_d_univ,dim_univ,numel(d_univ_vals)); + end + + %% Assemble multivariate topologic differential operators + diff_ops = cell (ndim, 1); + switch ndim + case 1 + diff_ops{1} = D_univ{1}; + + case 2 + if strcmpi(grad_curl, 'grad') + diff_ops{1} = vertcat(kron(Id{2},D_univ{1}),kron(D_univ{2},Id{1})); + diff_ops{2} = horzcat(kron(kron(-1,D_univ{2}),Id_deriv{1}),... + kron(kron( 1,Id_deriv{2}),D_univ{1})); + else + diff_ops{1} = vertcat(kron(D_univ{2},Id{1}),-kron(Id{2},D_univ{1})); + diff_ops{2} = horzcat(kron(Id_deriv{2},D_univ{1}),... + kron(D_univ{2},Id_deriv{1})); + + end + + case 3 + diff_ops{1} = vertcat(kron(kron(Id{3},Id{2}),D_univ{1}),... + kron(kron(Id{3},D_univ{2}),Id{1}),... + kron(kron(D_univ{3},Id{2}),Id{1})); + + univ_c = cell(ndim,1); C = cell(ndim); + dim_imm = [ size(Id_deriv{3},2)*size(Id_deriv{2},2)*size(D_univ{1},2) + size(Id_deriv{3},2)*size(D_univ{2},2)*size(Id_deriv{1},2) + size(D_univ{3},2)*size(Id_deriv{2},2)*size(Id_deriv{1},2) ]; + dim_dom = [ size(Id{3},1)*size(Id{2},1)*size(D_univ{1},1) + size(Id{3},1)*size(D_univ{2},1)*size(Id{1},1) + size(D_univ{3},1)*size(Id{2},1)*size(Id{1},1) ]; + + for kdim = 1:ndim + transv_dir = setdiff(1:ndim,kdim); + C(kdim,:) = circshift({0, -1, 1},kdim-1,2); + C{kdim,kdim} = spalloc(dim_imm(kdim),dim_dom(kdim),0); + univ_c{kdim} = Id{kdim}; + + for mm = transv_dir + nn = setdiff(transv_dir,mm); + univ_c{mm} = Id_deriv{mm}; + univ_c{nn} = D_univ{nn}; + + for ll = ndim:-1:1 + C{kdim,mm} = kron(C{kdim,mm},univ_c{ll}); + end + end + end + + diff_ops{2} = vertcat(horzcat(C{1,:}),horzcat(C{2,:}),horzcat(C{3,:})); + diff_ops{3} = horzcat(kron(kron(Id_deriv{3},Id_deriv{2}),D_univ{1}),... + kron(kron(Id_deriv{3},D_univ{2}),Id_deriv{1}),... + kron(kron(D_univ{3},Id_deriv{2}),Id_deriv{1})); + + clear C + + otherwise + error(' op_geom_exterior: Not implemented for dimension greater than three'); + end + + if coo + for idim = 1:ndim + [rows, cols, vals] = find (diff_ops{idim}); + diff_ops{idim} = [rows, cols, vals]; + end + end + +end diff --git a/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m b/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m new file mode 100644 index 00000000..0cca33da --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m @@ -0,0 +1,71 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (strcmpi(space1.transform, 'grad-preserving'), ... + 'The first space cannot be the one for integral-preserving splines (or n-forms)') + + ndim = numel (space1.knots); + if (ndim == 1) + grad_curl = 'grad'; + assert (space1.degree == space2.degree+1, 'The degrees are not compatible') + assert (numel(space1.knots{1}) == numel(space2.knots{1})+2, 'The knot vectors are not compatible') + elseif (ndim == 2) + if (strcmpi (space2.transform, 'curl-preserving')) + grad_curl = 'grad'; + deg_shift = {[1 0], [0 1]}; + knt_shift = {[2 0], [0 2]}; + elseif (strcmpi (space2.transform, 'div-preserving')) + grad_curl = 'curl'; + deg_shift = {[0 1], [1 0]}; + knt_shift = {[0 2], [2 0]}; + else + error ('The second space should be either curl-preserving or div-preserving') + end + for idim = 1:ndim + assert (all(space1.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (ndim == 3) + grad_curl = 'grad'; + deg_shift = {[1 0 0], [0 1 0], [0 0 1]}; + knt_shift = {[2 0 0], [0 2 0], [0 0 2]}; + assert (strcmpi(space2.transform, 'curl-preserving'), ... + 'The second space should be the one for curl-conforming splines') + for idim = 1:ndim + assert (all(space1.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + end + + diff_ops = op_geom_exterior (space1.knots, space1.degree, grad_curl); + diff_op = diff_ops{1}; +end diff --git a/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m b/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m new file mode 100644 index 00000000..a2d5915e --- /dev/null +++ b/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m @@ -0,0 +1,94 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (~strcmpi(space1.transform, 'integral-preserving'), ... + 'The first space cannot be the one for integral-preserving splines (or n-forms)') + + ndim = numel (space1.scalar_spaces{1}.knots); + if (ndim == 1) + error ('Not implemented. For dimension 1, use the scalar spaces') + elseif (ndim == 2) + if (strcmpi (space1.transform, 'curl-preserving')) + grad_curl = 'grad'; + output_der = 2; + deg_shift = {[0 1], [1 0]}; + knt_shift = {[0 2], [2 0]}; + degree = space1.scalar_spaces{1}.degree + [1 0]; + knots = {space1.scalar_spaces{2}.knots{1}, space1.scalar_spaces{1}.knots{2}}; + elseif (strcmpi (space1.transform, 'div-preserving')) + grad_curl = 'curl'; + output_der = 2; + deg_shift = {[1 0], [0 1]}; + knt_shift = {[2 0], [0 2]}; + degree = space1.scalar_spaces{1}.degree + [0 1]; + knots = {space1.scalar_spaces{1}.knots{1}, space1.scalar_spaces{2}.knots{2}}; + else + error ('The second space should be either curl-preserving or div-preserving') + end + assert (isa(space2, 'sp_scalar'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (ndim == 3) + grad_curl = 'grad'; + if (strcmpi (space1.transform, 'curl-preserving')) + output_der = 2; + deg_shift = {[-1 1 1], [1 -1 1], [1 1 -1]}; + knt_shift = {[-2 2 2], [2 -2 2], [2 2 -2]}; + degree = space1.scalar_spaces{1}.degree + [1 0 0]; + knots = {space1.scalar_spaces{2}.knots{1}, space1.scalar_spaces{1}.knots{2}, space1.scalar_spaces{1}.knots{3}}; + assert (isa(space2, 'sp_vector'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (strcmpi (space1.transform, 'div-preserving')) + output_der = 3; + deg_shift = {[1 0 0], [0 1 0], [0 0 1]}; + knt_shift = {[2 0 0], [0 2 0], [0 0 2]}; + degree = space1.scalar_spaces{1}.degree + [0 1 1]; + knots = {space1.scalar_spaces{1}.knots{1}, space1.scalar_spaces{2}.knots{2}, space1.scalar_spaces{3}.knots{3}}; + assert (isa(space2, 'sp_scalar'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + else + error ('Only implemented for curl-preserving and div-preserving transforms') + end + end + + diff_ops = op_geom_exterior (knots, degree, grad_curl); + diff_op = diff_ops{output_der}; +end From 9efe9247341f69bbdeba2a9ccaecc68b86b86698 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 8 Mar 2023 16:25:11 +0100 Subject: [PATCH 259/366] Update --- geopdes/INDEX | 5 +++++ geopdes/NEWS | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/geopdes/INDEX b/geopdes/INDEX index d5638fc1..ca9461a4 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -62,6 +62,7 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_scalar/sp_evaluate_col_param @sp_scalar/sp_evaluate_element_list @sp_scalar/sp_evaluate_element_list_param + @sp_scalar/sp_exterior_derivative @sp_scalar/sp_h2_error @sp_scalar/sp_h1_error @sp_scalar/sp_l2_error @@ -83,6 +84,7 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_vector/sp_evaluate_col_param @sp_vector/sp_evaluate_element_list @sp_vector/sp_evaluate_element_list_param + @sp_vector/sp_exterior_derivative @sp_vector/sp_h2_error @sp_vector/sp_h1_error @sp_vector/sp_l2_error @@ -117,6 +119,7 @@ Operators: functions to assemble different matrices and vector op_eu_ev op_fdotn_vdotn op_fdotn_v + op_f_curlv_3d op_f_gradv op_f_vxn_2d op_f_vxn_3d @@ -140,6 +143,7 @@ Operators: functions to assemble different matrices and vector op_KL_shells op_KL_bending_stress op_KL_membrane_stress + op_geom_exterior Multipatch: functions of different kinds to solve problems in domains defined by multiple NURBS patches mp_dg_penalty mp_geo_load @@ -165,6 +169,7 @@ Multipatch: functions of different kinds to solve problems in domains defined by @sp_multipatch/sp_hcurl_error @sp_multipatch/sp_plot_solution @sp_multipatch/sp_to_vtk + @sp_multipatch/sp_exterior_derivative @sp_multipatch/sp_evaluate_element_list @sp_multipatch/sp_get_cells @sp_multipatch/sp_get_basis_functions diff --git a/geopdes/NEWS b/geopdes/NEWS index 96f0f929..f6cdf7a4 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -1,3 +1,8 @@ +Summary of important changes for geopdes-3.3.0: +----------------------------------------------------------------------------- +* Added functions to compute the exterior derivative. +* Added new operators: op_f_curlv_(mp,tp,3d), op_f_gradv_(mp,tp). + Summary of important changes for geopdes-3.2.3: ----------------------------------------------------------------------------- * Added new function: msh_get_neighbor_cells From 7c76bda60e247ae793cf7f6acb2ba48b3e776fe4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 16 Mar 2023 11:54:06 +0100 Subject: [PATCH 260/366] First version of Cahn-Hilliard equations. --- .../examples/cahn-hilliard/ex_cahn_hilliard.m | 72 ++++ geopdes/inst/solve/solve_cahn_hilliard.m | 346 ++++++++++++++++++ 2 files changed, 418 insertions(+) create mode 100644 geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m create mode 100644 geopdes/inst/solve/solve_cahn_hilliard.m diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m new file mode 100644 index 00000000..d014938a --- /dev/null +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -0,0 +1,72 @@ +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +problem_data.geo_name = 'geo_square.txt'; + +% Physical parameters +lambda = (1/(4*sqrt(2)*pi))^2; +problem_data.lambda = @(x, y) lambda* ones(size(x)); + +% Periodic directions and boundary conditions +problem_data.periodic_directions = [1 2]; + +% Time and time step size +Time_max = .02; +dt = 1e-3; +time_step_save = linspace(dt,Time_max,20); +problem_data.time = 0; +problem_data.Time_max = Time_max; + +% Initial conditions +mean = 0.0; +var = 0.2; +% ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition +ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). +problem_data.fun_u = ic_fun; +% problem_data.fun_udot = []; + +% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +deg = 3; nel = 20; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-1 deg-1]; % Regularity of the splines +method_data.nsub = [nel nel]; % Number of subdivisions +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule + +% time integration parameters +method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method +method_data.dt = dt; % Time step size + +% % 3) INITIAL CONDITIONS +% clear initial_condition +% initial_condition.fun_u = ic_fun; + +% 3) CALL TO THE SOLVER +[geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, time_step_save); + +% 4) POST-PROCESSING +vtk_pts = {linspace(0, 1, nel*4), linspace(0, 1, nel*4)}; +folder_name = strcat('results_CH_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); +status = mkdir(folder_name); + +% 5.1) EXPORT TIME +filename = strcat( folder_name,'/filenum_to_time.mat'); +time_steps = results.time; +save(filename, 'time_steps'); + + +% 5.2) EXPORT TO PARAVIEW +for step = 1:length(results.time) + output_file = strcat( folder_name,'/Square_cahn_hilliard_', num2str(step) ); + fprintf ('The result is saved in the file %s \n \n', output_file); + sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'u','grad_u'}, {'value','gradient'}) +end + +% 5.3) PLOT LAST RESULT +[eu, F] = sp_eval (results.u(:,end), space, geometry, vtk_pts); +[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +surf (X, Y, eu) +colorbar +view(0,90) +shading interp +axis equal tight \ No newline at end of file diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m new file mode 100644 index 00000000..89ad37a8 --- /dev/null +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -0,0 +1,346 @@ +% SOLVE_CAHN_HILLIARD: solve the Cahn-Hilliard equation, with a generalized alpha discretization in time. +% +% The functions solves the problem of finding u such that +% +% du/dt - Delta (f(u) - lambda*Delta u) = 0 +% +% with Delta the Laplacian, and f(u) = alpha u^3 - beta u, and periodic boundary conditions. +% +% The values of alpha and beta (or f itself) can be changed in op_gradmu_gradv_tp. +% +% For details on the problem and the formulation, see +% H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. +% H. Gomez, A. Reali, G. Sangalli, J. Comput. Physics 262 (2014), 153-171. +% +% USAGE: +% +% [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, save_info) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) +% - lambda: parameter representing the length scale of the problem, and the width of the interface +% - Time_max: final time +% - fun_u: initial condition. Equal to zero by default. +% - fun_udot: initial condition for time derivative. Equal to zero by default. +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% - dt: time step size for generalized-alpha method +% - rho_inf_gen_alpha: parameter in [0,1], which governs numerical damping of the generalized alpha method +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete space (see sp_scalar) +% results: a struct with the saved results, containing the following fields: +% - time: (array of length Ntime) time at which the solution was saved +% - u: (size ndof x Ntime) degrees of freedom for the solution +% - udot: (size ndof x Ntime) degrees of freedom for the time derivative +% +% Only periodic and Neumann boundary conditions are implemented. Neumann +% conditions are considered by default. +% +% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, save_info) + +%%------------------------------------------------------------------------- +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +%%------------------------------------------------------------------------- +% Construct geometry structure +geometry = geo_load (geo_name); +[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); + +%%------------------------------------------------------------------------- +% Check for periodic conditions, and consistency with other boundary conditions +if (exist('periodic_directions', 'var')) + knots = kntunclamp (knots, degree, regularity, periodic_directions); +else + periodic_directions = []; +end + +if (exist ('nmnn_sides','var') && ~isempty (nmnn_sides)) + disp('User defined Neumann sides deleted') + clear nmnn_sides +end + +%%------------------------------------------------------------------------- +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (zeta, rule); +msh = msh_cartesian (zeta, qn, qw, geometry); + +% Construct space structure +space = sp_bspline (knots, degree, msh, [], periodic_directions); + +%%------------------------------------------------------------------------- +% Generalized alpha parameters +a_m = .5*((3-rho_inf_gen_alpha)/(1+rho_inf_gen_alpha)); +a_f = 1/(1+rho_inf_gen_alpha); +gamma = .5 + a_m - a_f; + +%%------------------------------------------------------------------------- +% No flux b.c. (essential boundary condition) +% Set Neumann boundary conditions for non-periodic sides +nmnn_sides = []; +for idir = 1:msh.ndim + if (~ismember(idir, periodic_directions)) + nmnn_sides = [nmnn_sides, 2*(idir-1)+[1 2]]; + end +end + +% Matrix and data for Neumann +% [BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh); + +%%------------------------------------------------------------------------- +% Initial conditions, and assemble the mass matrix +time = 0; +mass_mat = op_u_v_tp (space, space, msh); +if (exist('fun_u', 'var') && ~isempty(fun_u)) + rhs = op_f_v_tp (space, msh, fun_u); + u_n = mass_mat\rhs; +else + u_n = zeros(space.ndof, 1); +end + +if (exist('fun_udot', 'var') && ~isempty(fun_udot)) + rhs = op_f_v_tp(space, msh, fun_udot); + udot_n = mass_mat\rhs; +else + udot_n = zeros(space.ndof, 1); +end + +%%------------------------------------------------------------------------- +% Initialize structure to store the results +save_id = 1; +results.u = zeros(length(u_n), length(save_info)+1); +results.udot = zeros(length(u_n), length(save_info)+1); +results.time = zeros(length(save_info)+1,1); +flag_stop_save = false; + +% Save initial conditions +results.u(:,1) = u_n; +results.udot(:,1) = udot_n; +results.time(1) = time; + +%%------------------------------------------------------------------------- +% Loop over time steps +lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); +while time < Time_max + disp('----------------------------------------------------------------') + disp(strcat('time step t=',num2str(time))) + + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, space, msh); + + % Time step update + time = time + dt; + u_n = u_n1; + udot_n = udot_n1; + + % Check max time + if (time + dt > Time_max) + dt = Time_max-time; + end + + % Store results + if (flag_stop_save == false) + if (time >= save_info(save_id)) + save_id = save_id + 1; + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; + if (save_id > length(save_info)) + flag_stop_save = true; + end + end + end +end + +disp('----------------------------------------------------------------') +disp(strcat('END ANALYSIS t=',num2str(time))) +disp('----------------------------------------------------------------') + +% Crop results +results.u = results.u(:,1:save_id); +results.udot = results.udot(:,1:save_id); +results.time = results.time(1:save_id); + +end + +%-------------------------------------------------------------------------- +% FUNCTIONS +%-------------------------------------------------------------------------- + +%-------------------------------------------------------------------------- +% Neumann boundary conditions +%-------------------------------------------------------------------------- +function [BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh) + +if (~isempty(nmnn_sides)) + + BC = spalloc (space.ndof, space.ndof, 3*space.ndof); + indBC = []; + + for iside = nmnn_sides + indBC = union (indBC, space.boundary(iside).dofs); + msh_side = msh_eval_boundary_side (msh, iside); + msh_side_int = msh_boundary_side_from_interior (msh, iside); + sp_side = space.constructor (msh_side_int); + sp_side = sp_precompute (sp_side, msh_side_int, 'value', true, 'gradient', true); + coe_side = ones(msh_side.nqn, msh_side.nel); + BC = BC + op_gradv_n_u(sp_side ,sp_side ,msh_side, coe_side); + end + BC = BC'; + dof_free = setdiff(1:space.ndof, indBC); + +else + BC = []; + indBC = []; + dof_free = 1:space.ndof; +end + + +end + +%-------------------------------------------------------------------------- +% One step of generalized alpha-method +%-------------------------------------------------------------------------- +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, space, msh) + +% Convergence criteria + n_max_iter = 20; + tol_rel_res = 1e-10; +% tol_abs_res = 1e-10; + +% Predictor step + u_n1 = u_n; + udot_n1 = (gamma-1)/gamma * udot_n; + +% Newton loop + for iter = 0:n_max_iter + % Field at alpha level + udot_a = udot_n + a_m *(udot_n1-udot_n); + u_a = u_n + a_f *(u_n1-u_n); + + % Compute the residual (internal) + [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, mass_mat, lapl_mat, u_a, udot_a); + + % Convergence check + if iter == 0 + norm_res_0 = norm(Res_gl); + end + norm_res = norm(Res_gl); + + + if norm_res/norm_res_0 < tol_rel_res + disp(strcat('iteration n°=',num2str(iter))) + disp(strcat('norm (abs) residual=',num2str(norm_res))) + break + end +% if norm_res Date: Thu, 16 Mar 2023 16:22:56 +0100 Subject: [PATCH 261/366] File for testing the boundary condition --- geopdes/inst/solve/solve_cahn_hilliard_test.m | 428 ++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 geopdes/inst/solve/solve_cahn_hilliard_test.m diff --git a/geopdes/inst/solve/solve_cahn_hilliard_test.m b/geopdes/inst/solve/solve_cahn_hilliard_test.m new file mode 100644 index 00000000..0add7727 --- /dev/null +++ b/geopdes/inst/solve/solve_cahn_hilliard_test.m @@ -0,0 +1,428 @@ +% SOLVE_CAHN_HILLIARD: solve the Cahn-Hilliard equation, with a generalized alpha discretization in time. +% +% The functions solves the problem of finding u such that +% +% du/dt - Delta (f(u) - lambda*Delta u) = 0 +% +% with Delta the Laplacian, and f(u) = alpha u^3 - beta u, and periodic boundary conditions. +% +% The values of alpha and beta (or f itself) can be changed in op_gradmu_gradv_tp. +% +% For details on the problem and the formulation, see +% H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. +% H. Gomez, A. Reali, G. Sangalli, J. Comput. Physics 262 (2014), 153-171. +% +% USAGE: +% +% [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, save_info) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) +% - lambda: parameter representing the length scale of the problem, and the width of the interface +% - Time_max: final time +% - fun_u: initial condition. Equal to zero by default. +% - fun_udot: initial condition for time derivative. Equal to zero by default. +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% - dt: time step size for generalized-alpha method +% - rho_inf_gen_alpha: parameter in [0,1], which governs numerical damping of the generalized alpha method +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete space (see sp_scalar) +% results: a struct with the saved results, containing the following fields: +% - time: (array of length Ntime) time at which the solution was saved +% - u: (size ndof x Ntime) degrees of freedom for the solution +% - udot: (size ndof x Ntime) degrees of freedom for the time derivative +% +% Only periodic and Neumann boundary conditions are implemented. Neumann +% conditions are considered by default. +% +% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, results] = solve_cahn_hilliard_test (problem_data, method_data, save_info) + +%%------------------------------------------------------------------------- +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +%%------------------------------------------------------------------------- +% Construct geometry structure +geometry = geo_load (geo_name); +[knots, zeta] = kntrefine (geometry.nurbs.knots, nsub-1, degree, regularity); + +%%------------------------------------------------------------------------- +% Check for periodic conditions, and consistency with other boundary conditions +if (exist('periodic_directions', 'var')) + knots = kntunclamp (knots, degree, regularity, periodic_directions); +else + periodic_directions = []; +end + +if (exist ('nmnn_sides','var') && ~isempty (nmnn_sides)) + disp('User defined Neumann sides deleted') + clear nmnn_sides +end + +%%------------------------------------------------------------------------- +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (zeta, rule); +msh = msh_cartesian (zeta, qn, qw, geometry); + +% Construct space structure +space = sp_bspline (knots, degree, msh, [], periodic_directions); + +%%------------------------------------------------------------------------- +% Generalized alpha parameters +a_m = .5*((3-rho_inf_gen_alpha)/(1+rho_inf_gen_alpha)); +a_f = 1/(1+rho_inf_gen_alpha); +gamma = .5 + a_m - a_f; + +%%------------------------------------------------------------------------- +% No flux b.c. (essential boundary condition) +% Set Neumann boundary conditions for non-periodic sides +nmnn_sides = []; +for idir = 1:msh.ndim + if (~ismember(idir, periodic_directions)) + nmnn_sides = [nmnn_sides, 2*(idir-1)+[1 2]]; + end +end + +% Matrix and data for Neumann +[BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh); + +%%------------------------------------------------------------------------- +% Assemble the mass matrix, the Laplacian matrix, and the boundary term +mass_mat = op_u_v_tp (space, space, msh); +lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); +term4 = int_boundary_term (space, msh, lambda, nmnn_sides); + +%%------------------------------------------------------------------------- +% Initial conditions +time = 0; +if (exist('fun_u', 'var') && ~isempty(fun_u)) + rhs = op_f_v_tp (space, msh, fun_u); + u_n = mass_mat\rhs; +else + u_n = zeros(space.ndof, 1); +end + +if (exist('fun_udot', 'var') && ~isempty(fun_udot)) + rhs = op_f_v_tp(space, msh, fun_udot); + udot_n = mass_mat\rhs; +else + udot_n = zeros(space.ndof, 1); +end + +norm_flux_initial = check_flux_phase_field(space, msh, u_n); +disp(strcat('initial flux =',num2str(norm_flux_initial))) + +%%------------------------------------------------------------------------- +% Initialize structure to store the results +save_id = 1; +results.u = zeros(length(u_n), length(save_info)+1); +results.udot = zeros(length(u_n), length(save_info)+1); +results.time = zeros(length(save_info)+1,1); +flag_stop_save = false; + +% Save initial conditions +results.u(:,1) = u_n; +results.udot(:,1) = udot_n; +results.time(1) = time; + +%%------------------------------------------------------------------------- +% Loop over time steps +while time < Time_max + disp('----------------------------------------------------------------') + disp(strcat('time step t=',num2str(time))) + + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, term4, BC, indBC, dof_free, space, msh); + + % Check flux through the boundary + norm_flux = check_flux_phase_field(space, msh, u_n1); + disp(strcat('flux variation =',num2str(norm_flux - norm_flux_initial))) + + % Time step update + time = time + dt; + u_n = u_n1; + udot_n = udot_n1; + + % Check max time + if (time + dt > Time_max) + dt = Time_max-time; + end + + % Store results + if (flag_stop_save == false) + if (time >= save_info(save_id)) + save_id = save_id + 1; + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; + if (save_id > length(save_info)) + flag_stop_save = true; + end + end + end +end + +disp('----------------------------------------------------------------') +disp(strcat('END ANALYSIS t=',num2str(time))) +disp('----------------------------------------------------------------') + +% Crop results +results.u = results.u(:,1:save_id); +results.udot = results.udot(:,1:save_id); +results.time = results.time(1:save_id); + +end + +%-------------------------------------------------------------------------- +% FUNCTIONS +%-------------------------------------------------------------------------- + +%-------------------------------------------------------------------------- +% Neumann boundary conditions +%-------------------------------------------------------------------------- +function [BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh) + +if (~isempty(nmnn_sides)) + + BC = spalloc (space.ndof, space.ndof, 3*space.ndof); + indBC = []; + + for iside = nmnn_sides + indBC = union (indBC, space.boundary(iside).dofs); + msh_side = msh_eval_boundary_side (msh, iside); + msh_side_int = msh_boundary_side_from_interior (msh, iside); + sp_side = space.constructor (msh_side_int); + sp_side = sp_precompute (sp_side, msh_side_int, 'value', true, 'gradient', true); + coe_side = ones(msh_side.nqn, msh_side.nel); + BC = BC + op_gradv_n_u(sp_side ,sp_side ,msh_side, coe_side); + end + BC = BC'; + dof_free = setdiff(1:space.ndof, indBC); + +else + BC = []; + indBC = []; + dof_free = 1:space.ndof; +end + + +end + +%-------------------------------------------------------------------------- +% One step of generalized alpha-method +%-------------------------------------------------------------------------- +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, term4, BC, ind_BC, dof_free, space, msh) + +% Convergence criteria + n_max_iter = 20; + tol_rel_res = 1e-10; + +% Predictor step + u_n1 = u_n; + udot_n1 = (gamma-1)/gamma * udot_n; + +% Newton loop + for iter = 0:n_max_iter + % Field at alpha level + udot_a = udot_n + a_m *(udot_n1-udot_n); + u_a = u_n + a_f *(u_n1-u_n); + + % Compute the residual (internal) + [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, mass_mat, lapl_mat, term4, u_a, udot_a); + + % Convergence check + if iter == 0 + norm_res_0 = norm(Res_gl(dof_free)); + end + norm_res = norm(Res_gl(dof_free)); + + + if norm_res/norm_res_0 < tol_rel_res + disp(strcat('iteration n° = ',num2str(iter))) + disp(strcat('norm of absolute residual = ',num2str(norm_res))) + break + end + if iter == n_max_iter + disp(strcat('Newton reached the maximum number of iterations')) + disp(strcat('norm of absolute residual = ',num2str(norm_res))) + end + + % Compute the update, and update the solution + A_gl = a_m * mass_mat + a_f * gamma *dt * stiff_mat; + if (~isempty(ind_BC)) + A_gl(ind_BC,:)=0; + A_gl = A_gl +BC; + Res_gl(ind_BC) = 0; + end + d_udot = - A_gl\Res_gl; + + udot_n1 = udot_n1 + d_udot; + u_n1 = u_n1 + gamma * dt* d_udot; + end + +end + +%-------------------------------------------------------------------------- +% Canh-Hilliard residual and tangent matrix +%-------------------------------------------------------------------------- +function [Res_gl, stiff_mat] = Res_K_cahn_hilliard(space, msh, mass_mat, lapl_mat, term4, u_a, udot_a) + + % Double well (matrices) + [term2, term2K] = op_gradmu_gradv_tp(space, msh, u_a); + + % Residual + Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; + + % Tangent stiffness matrix (mass is not considered here) + stiff_mat = term2 + term2K + lapl_mat; + + if (size(term4,1) > 0) + Res_gl = Res_gl - term4 * u_a; + stiff_mat = stiff_mat - term4; + end + +end + + +%-------------------------------------------------------------------------- +% Integral of the double-well function +%-------------------------------------------------------------------------- +function [A, B] = op_gradmu_gradv_tp (space, msh, uhat) + +% Coefficients of the double well function. + alpha = 1; + beta = 1; + + for idim = 1:msh.ndim + size1 = size (space.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + B = spalloc (space.ndof, space.ndof, 6*space.ndof); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'gradient', true); + + % Evaluate the field and its gradient at the Gaussian points + utemp = sp_eval_msh (uhat, sp_col, msh_col, {'value', 'gradient'}); + u = utemp{1}; + gradu = utemp{2}; + + % Polynomial formulation for the double-well + coeffs_A = 3.* alpha .* u.^2 - beta; + A = A + op_gradu_gradv (sp_col, sp_col, msh_col, coeffs_A); + + coeffs_B = 6.* alpha .* u; + coeffs_Bv = gradu; + for idim = 1:msh.ndim + coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); + end + B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv)'; + end +end + +%-------------------------------------------------------------------------- +% Integral of the boundary term +%-------------------------------------------------------------------------- +function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) + + if (~isempty (nmnn_sides)) + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + for iside=1:length(nmnn_sides) + msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside)); + msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ); + sp_side = space.constructor (msh_side_int); + sp_side = sp_precompute (sp_side, msh_side_int, 'gradient', true, 'laplacian', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = lambda (x{:}); + + A = A + op_gradv_n_laplaceu (sp_side, sp_side, msh_side, coe_side); + end + + A = A'; + else + A = []; + end + +end + + + +%-------------------------------------------------------------------------- +% Check flux through the boundaries +%-------------------------------------------------------------------------- + +function norm_flux = check_flux_phase_field(space, msh, uhat) + +sides = [1,2,3,4]; +norm_flux = 0; + +for iside=1:length(sides) + + msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); + + + utemp = sp_eval_msh (uhat, sp_side, msh_side, {'gradient'}); + gradu = utemp{1}; + + valu = zeros(1, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); + for idim = 1:msh.rdim + valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); + end + + valu = reshape (valu, sp_side.ncomp, msh_side.nqn, msh_side.nel); + w =msh_side.quad_weights .* msh_side.jacdet; + errl2_elem = sum (reshape (sum ((valu).^2, 1), [msh_side.nqn, msh_side.nel]) .* w); + errl2 = sqrt (sum (errl2_elem)); + + + norm_flux = norm_flux + errl2; +end + +end \ No newline at end of file From 6cfd8e15bb19555b3d83b0fcaab2667631e1704b Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 17 Mar 2023 14:58:07 +0100 Subject: [PATCH 262/366] Change in the help --- geopdes/inst/operators/op_gradv_n_u.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/operators/op_gradv_n_u.m b/geopdes/inst/operators/op_gradv_n_u.m index ae20d32f..43305ffd 100644 --- a/geopdes/inst/operators/op_gradv_n_u.m +++ b/geopdes/inst/operators/op_gradv_n_u.m @@ -1,4 +1,4 @@ -% OP_GRADV_N_U: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon (grad v n)_j, u_i), with n the normal vector. +% OP_GRADV_N_U: assemble the matrix A = [a(i,j)], a(i,j) = (u_j, epsilon (grad v n)_i), with n the normal vector. % % mat = op_gradv_n_u (spu, spv, msh, epsilon); % [rows, cols, values] = op_gradv_n_u (spu, spv, msh, epsilon); From eedd2adbaefb9f4ae52a7598e7bb57689ff452d8 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 17 Mar 2023 14:59:57 +0100 Subject: [PATCH 263/366] Change in the help --- geopdes/inst/solve/solve_cahn_hilliard.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 89ad37a8..f5cf26c3 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -2,11 +2,11 @@ % % The functions solves the problem of finding u such that % -% du/dt - Delta (f(u) - lambda*Delta u) = 0 +% du/dt - Delta (mu(u) - lambda*Delta u) = 0 % -% with Delta the Laplacian, and f(u) = alpha u^3 - beta u, and periodic boundary conditions. +% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic boundary conditions. % -% The values of alpha and beta (or f itself) can be changed in op_gradmu_gradv_tp. +% The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. % % For details on the problem and the formulation, see % H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. From 710c15668e75b982965c003e51b1772cf99314ec Mon Sep 17 00:00:00 2001 From: torre95michele Date: Thu, 6 Apr 2023 14:39:28 +0200 Subject: [PATCH 264/366] Nitsche's method for Neumann BC --- .../examples/cahn-hilliard/ex_cahn_hilliard.m | 29 +- geopdes/inst/solve/solve_cahn_hilliard.m | 269 ++++++++++++++---- 2 files changed, 237 insertions(+), 61 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index d014938a..91c3b3d5 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -8,26 +8,31 @@ problem_data.lambda = @(x, y) lambda* ones(size(x)); % Periodic directions and boundary conditions -problem_data.periodic_directions = [1 2]; +problem_data.periodic_directions = []; % Time and time step size -Time_max = .02; -dt = 1e-3; +Time_max = .08; +dt = 1e-2; time_step_save = linspace(dt,Time_max,20); problem_data.time = 0; problem_data.Time_max = Time_max; -% Initial conditions -mean = 0.0; -var = 0.2; + +% Penalty parameters +problem_data.pen_nitsche = 1e4 * lambda; % Nitsche's method parameter +problem_data.pen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) + +% 2) INITIAL CONDITIONS +% mean = 0.0; +% var = 0.2; % ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). problem_data.fun_u = ic_fun; % problem_data.fun_udot = []; -% 2) CHOICE OF THE DISCRETIZATION PARAMETERS +% 3) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data -deg = 3; nel = 20; +deg = 2; nel = 10; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-1 deg-1]; % Regularity of the splines method_data.nsub = [nel nel]; % Number of subdivisions @@ -37,14 +42,12 @@ method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method method_data.dt = dt; % Time step size -% % 3) INITIAL CONDITIONS -% clear initial_condition -% initial_condition.fun_u = ic_fun; -% 3) CALL TO THE SOLVER + +% 4) CALL TO THE SOLVER [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, time_step_save); -% 4) POST-PROCESSING +% 5) POST-PROCESSING vtk_pts = {linspace(0, 1, nel*4), linspace(0, 1, nel*4)}; folder_name = strcat('results_CH_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); status = mkdir(folder_name); diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index f5cf26c3..28734595 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -120,27 +120,42 @@ end end -% Matrix and data for Neumann -% [BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh); +%%------------------------------------------------------------------------- +% Precompute matrices + +% Compute the mass matrix +mass_mat = op_u_v_tp(space,space,msh); + +% Compute the laplace matrix +lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); + +% Compute the boundary term +term4 = int_term_4 (space, msh, lambda, nmnn_sides); + +% Compute the penalty matrix +[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, pen_nitsche); + %%------------------------------------------------------------------------- -% Initial conditions, and assemble the mass matrix +% Initial conditions time = 0; -mass_mat = op_u_v_tp (space, space, msh); if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_tp (space, msh, fun_u); - u_n = mass_mat\rhs; + u_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; else u_n = zeros(space.ndof, 1); end if (exist('fun_udot', 'var') && ~isempty(fun_udot)) rhs = op_f_v_tp(space, msh, fun_udot); - udot_n = mass_mat\rhs; + udot_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; else udot_n = zeros(space.ndof, 1); end +flux_initial = check_flux_phase_field(space, msh, u_n, zeros(size(u_n))); +disp(strcat('initial flux =',num2str(flux_initial))) + %%------------------------------------------------------------------------- % Initialize structure to store the results save_id = 1; @@ -156,12 +171,16 @@ %%------------------------------------------------------------------------- % Loop over time steps -lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); while time < Time_max disp('----------------------------------------------------------------') disp(strcat('time step t=',num2str(time))) - [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, space, msh); + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh); + + % check flux through the boundary + flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); + disp(strcat('flux norm =',num2str(flux))) % Time step update time = time + dt; @@ -202,46 +221,18 @@ % FUNCTIONS %-------------------------------------------------------------------------- -%-------------------------------------------------------------------------- -% Neumann boundary conditions -%-------------------------------------------------------------------------- -function [BC, indBC, dof_free] = impose_essential_neumann_weak(nmnn_sides, space, msh) - -if (~isempty(nmnn_sides)) - - BC = spalloc (space.ndof, space.ndof, 3*space.ndof); - indBC = []; - - for iside = nmnn_sides - indBC = union (indBC, space.boundary(iside).dofs); - msh_side = msh_eval_boundary_side (msh, iside); - msh_side_int = msh_boundary_side_from_interior (msh, iside); - sp_side = space.constructor (msh_side_int); - sp_side = sp_precompute (sp_side, msh_side_int, 'value', true, 'gradient', true); - coe_side = ones(msh_side.nqn, msh_side.nel); - BC = BC + op_gradv_n_u(sp_side ,sp_side ,msh_side, coe_side); - end - BC = BC'; - dof_free = setdiff(1:space.ndof, indBC); - -else - BC = []; - indBC = []; - dof_free = 1:space.ndof; -end - - -end %-------------------------------------------------------------------------- % One step of generalized alpha-method %-------------------------------------------------------------------------- -function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mass_mat, lapl_mat, space, msh) + +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh) % Convergence criteria n_max_iter = 20; tol_rel_res = 1e-10; -% tol_abs_res = 1e-10; + tol_abs_res = 1e-10; % Predictor step u_n1 = u_n; @@ -249,12 +240,15 @@ % Newton loop for iter = 0:n_max_iter + % Field at alpha level udot_a = udot_n + a_m *(udot_n1-udot_n); u_a = u_n + a_f *(u_n1-u_n); % Compute the residual (internal) - [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, mass_mat, lapl_mat, u_a, udot_a); + [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, ... + u_a, udot_a); % Convergence check if iter == 0 @@ -268,11 +262,11 @@ disp(strcat('norm (abs) residual=',num2str(norm_res))) break end -% if norm_res0 + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + + + for iside=1:length(nmnn_sides) + + msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = lambda (x{:}); + + A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); + end + + +else + A = []; +end + + +end + +%-------------------------------------------------------------------------- +% Operator grav_n_laplaceu +%-------------------------------------------------------------------------- + +function varargout = op_gradv_n_laplaceu (spu, spv, msh, coeff) + + gradv = reshape (spv.shape_function_gradients, spv.ncomp, [], ... + msh.nqn, spv.nsh_max, msh.nel); + + ndim = size (gradv, 2); + + shpu = reshape (spu.shape_function_laplacians, spu.ncomp, msh.nqn, spu.nsh_max, msh.nel); + + rows = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + cols = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + values = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + + jacdet_weights = msh.jacdet .* msh.quad_weights .* coeff; + + ncounter = 0; + for iel = 1:msh.nel + if (all (msh.jacdet(:,iel))) + gradv_iel = gradv(:,:,:,:,iel); + normal_iel = reshape (msh.normal(:,:,iel), [1, ndim, msh.nqn]); + + gradv_n = reshape (sum (bsxfun (@times, gradv_iel, normal_iel), 2), spv.ncomp, msh.nqn, spv.nsh_max, 1); + shpu_iel = reshape (shpu(:, :, :, iel), spu.ncomp, msh.nqn, 1, spu.nsh_max); + + jacdet_iel = reshape (jacdet_weights(:,iel), [1,msh.nqn,1,1]); + + gradv_n_times_jw = bsxfun (@times, jacdet_iel, gradv_n); + tmp1 = sum (bsxfun (@times, gradv_n_times_jw, shpu_iel), 1); + elementary_values = reshape (sum (tmp1, 2), spv.nsh_max, spu.nsh_max); + + [rows_loc, cols_loc] = ndgrid (spv.connectivity(:,iel), spu.connectivity(:,iel)); + indices = rows_loc & cols_loc; + rows(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = rows_loc(indices); + cols(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = cols_loc(indices); + values(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = elementary_values(indices); + ncounter = ncounter + spu.nsh(iel)*spv.nsh(iel); + + else + warning ('geopdes:jacdet_zero_at_quad_node', 'op_gradv_n_u: singular map in element number %d', iel) + end + end + + + if (nargout == 1 || nargout == 0) + varargout{1} = sparse (rows, cols, values, spv.ndof, spu.ndof); + elseif (nargout == 3) + varargout{1} = rows; + varargout{2} = cols; + varargout{3} = values; + else + error ('op_gradv_n_u: wrong number of output arguments') + end + + +end + +%-------------------------------------------------------------------------- +% penalty term +%-------------------------------------------------------------------------- + +function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) + + P = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros(space.ndof,1); + + for iside = 1:length(nmnn_sides) + [mass_pen, rhs_pen] = penalty_grad (space, msh, nmnn_sides(iside), pen); + P = P + mass_pen; + rhs = rhs + rhs_pen; + + end + +end + + +function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) + +msh_side = msh_eval_boundary_side (msh, i_side ) ; +msh_side_int = msh_boundary_side_from_interior (msh, i_side ) ; +sp_side = space.constructor ( msh_side_int) ; +sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient', true ); + + +coe_side = pen .* msh_side.charlen; +mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); + + +rhs_pen = zeros(space.ndof,1); % no flux + +end + +%-------------------------------------------------------------------------- +% check flux through the boundaries +%-------------------------------------------------------------------------- + +function flux = check_flux_phase_field(space, msh, uhat, uhat0) + +sides = [1,2,3,4]; % all the boundaries +flux = 0; + +for iside=1:length(sides) + + msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); + + + gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); + + + + valu = zeros(sp_side.ncomp, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); + for idim = 1:msh.rdim + valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); + end + + + w =msh_side.quad_weights .* msh_side.jacdet; + err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); + err = sum (err_elem); + + + flux = flux + err; + +end + + + +end + From 51bf2062ef2f93a98c75a3e01cbd5afc7193117c Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 17:06:29 +0200 Subject: [PATCH 265/366] Change some names, and other minor things --- geopdes/inst/solve/solve_cahn_hilliard.m | 131 ++++++++++------------- 1 file changed, 57 insertions(+), 74 deletions(-) diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 28734595..e4d95bf2 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -130,7 +130,7 @@ lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); % Compute the boundary term -term4 = int_term_4 (space, msh, lambda, nmnn_sides); +bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); % Compute the penalty matrix [Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, pen_nitsche); @@ -176,7 +176,7 @@ disp(strcat('time step t=',num2str(time))) [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); % check flux through the boundary flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); @@ -227,7 +227,7 @@ %-------------------------------------------------------------------------- function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) % Convergence criteria n_max_iter = 20; @@ -247,8 +247,7 @@ % Compute the residual (internal) [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, ... - u_a, udot_a); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a); % Convergence check if iter == 0 @@ -278,7 +277,7 @@ udot_n1 = udot_n1 + d_udot; u_n1 = u_n1 + gamma * dt* d_udot; -end + end end @@ -287,23 +286,22 @@ %-------------------------------------------------------------------------- function [Res_gl, stiff_mat] = Res_K_cahn_hilliard(space, msh, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, ... - u_a, udot_a) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a) - % Double well (matrices) - [term2, term2K] = op_gradmu_gradv_tp(space, msh, u_a); + % Double well (matrices) + [term2, term2K] = op_gradmu_gradv_tp(space, msh, u_a); - % Residual - Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; + % Residual + Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; - % Tangent stiffness matrix (mass is not considered here) - stiff_mat = term2 + term2K + lapl_mat; + % Tangent stiffness matrix (mass is not considered here) + stiff_mat = term2 + term2K + lapl_mat; - % in case of neumann BC, add boundary terms - if isempty(term4) == 0 - Res_gl = Res_gl - (term4 + term4') * u_a + Pen*u_a - pen_rhs; - stiff_mat = stiff_mat - (term4 + term4') + Pen; - end + % In case of neumann BC, add boundary terms + if (~isempty(bnd_mat)) + Res_gl = Res_gl - (bnd_mat + bnd_mat.') * u_a + Pen*u_a - pen_rhs; + stiff_mat = stiff_mat - (bnd_mat + bnd_mat.') + Pen; + end end %-------------------------------------------------------------------------- @@ -349,37 +347,33 @@ end %-------------------------------------------------------------------------- -% term 4, boundary term +% Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) %-------------------------------------------------------------------------- -function [A] = int_term_4 (space, msh, lambda, nmnn_sides) +function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) - if length(nmnn_sides)>0 + if (~isempty(nmnn_sides)) A = spalloc (space.ndof, space.ndof, 3*space.ndof); + for iside=1:numel(nmnn_sides) - for iside=1:length(nmnn_sides) + msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); - msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; - msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; - sp_side = space.constructor ( msh_side_int) ; - sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); - - for idim = 1:msh.rdim - x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); - end - coe_side = lambda (x{:}); + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = lambda (x{:}); - A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); + A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); end - -else + else A = []; -end - - + end end %-------------------------------------------------------------------------- @@ -438,25 +432,23 @@ else error ('op_gradv_n_u: wrong number of output arguments') end - - + end %-------------------------------------------------------------------------- -% penalty term +% Penalty term %-------------------------------------------------------------------------- function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) - P = spalloc (space.ndof, space.ndof, 3*space.ndof); - rhs = zeros(space.ndof,1); - - for iside = 1:length(nmnn_sides) - [mass_pen, rhs_pen] = penalty_grad (space, msh, nmnn_sides(iside), pen); - P = P + mass_pen; - rhs = rhs + rhs_pen; + P = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros(space.ndof,1); - end + for iside = 1:numel(nmnn_sides) + [mass_pen, rhs_pen] = penalty_grad (space, msh, nmnn_sides(iside), pen); + P = P + mass_pen; + rhs = rhs + rhs_pen; + end end @@ -472,13 +464,12 @@ coe_side = pen .* msh_side.charlen; mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); - -rhs_pen = zeros(space.ndof,1); % no flux +rhs_pen = zeros(space.ndof,1); end %-------------------------------------------------------------------------- -% check flux through the boundaries +% Check flux through the boundaries %-------------------------------------------------------------------------- function flux = check_flux_phase_field(space, msh, uhat, uhat0) @@ -486,34 +477,26 @@ sides = [1,2,3,4]; % all the boundaries flux = 0; -for iside=1:length(sides) - - msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; - msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; - sp_side = space.constructor ( msh_side_int) ; - sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); - +for iside = 1:numel(sides) - gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); - + msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); + gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); - valu = zeros(sp_side.ncomp, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); - for idim = 1:msh.rdim - valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); - end - - - w =msh_side.quad_weights .* msh_side.jacdet; - err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); - err = sum (err_elem); - + valu = zeros(sp_side.ncomp, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); + for idim = 1:msh.rdim + valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); + end - flux = flux + err; + w =msh_side.quad_weights .* msh_side.jacdet; + err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); + err = sum (err_elem); + flux = flux + err; end - - end From 7232b5015c268bfe23f22143fe62c565824fc941 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 17:07:26 +0200 Subject: [PATCH 266/366] Added Neumann conditions in the help --- geopdes/inst/solve/solve_cahn_hilliard.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index e4d95bf2..9bd0a633 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -4,7 +4,7 @@ % % du/dt - Delta (mu(u) - lambda*Delta u) = 0 % -% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic boundary conditions. +% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic or Neumann boundary conditions. % % The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. % From f41062001f63e4fed4361a710f4a9abc44b06304 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 6 Apr 2023 17:28:38 +0200 Subject: [PATCH 267/366] Moved function to operators folder. Renamed penalization parameters. --- .../examples/cahn-hilliard/ex_cahn_hilliard.m | 4 +- geopdes/inst/operators/op_gradv_n_laplaceu.m | 92 +++++++++++++++++++ geopdes/inst/solve/solve_cahn_hilliard.m | 67 +------------- 3 files changed, 99 insertions(+), 64 deletions(-) create mode 100644 geopdes/inst/operators/op_gradv_n_laplaceu.m diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index 91c3b3d5..dc42053b 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -19,8 +19,8 @@ % Penalty parameters -problem_data.pen_nitsche = 1e4 * lambda; % Nitsche's method parameter -problem_data.pen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) +problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter +problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) % 2) INITIAL CONDITIONS % mean = 0.0; diff --git a/geopdes/inst/operators/op_gradv_n_laplaceu.m b/geopdes/inst/operators/op_gradv_n_laplaceu.m new file mode 100644 index 00000000..9b807a02 --- /dev/null +++ b/geopdes/inst/operators/op_gradv_n_laplaceu.m @@ -0,0 +1,92 @@ +% OP_GRADV_N_LAPLACEU: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon (grad v n)_j, Delta u_i), with n the normal vector. +% +% mat = op_gradv_n_laplaceu (spu, spv, msh, epsilon); +% [rows, cols, values] = op_gradv_n_laplaceu (spu, spv, msh, epsilon); +% +% INPUT: +% +% spu: structure representing the space of trial functions (see sp_scalar/sp_evaluate_col) +% spv: structure representing the space of test functions (see sp_scalar/sp_evaluate_col) +% msh: structure containing the domain partition and the quadrature rule for the boundary, +% since it must contain the normal vector (see msh_cartesian/msh_eval_boundary_side) +% epsilon: coefficient +% +% OUTPUT: +% +% mat: assembled matrix +% rows: row indices of the nonzero entries +% cols: column indices of the nonzero entries +% values: values of the nonzero entries +% +% Copyright (C) 2014 Adriano Cortes +% Copyright (C) 2014, 2017, 2023 Rafael Vazquez +% Copyright (C) 2023 Michele Torre +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function varargout = op_gradv_n_laplaceu (spu, spv, msh, coeff) + + gradv = reshape (spv.shape_function_gradients, spv.ncomp, [], ... + msh.nqn, spv.nsh_max, msh.nel); + + ndim = size (gradv, 2); + + shpu = reshape (spu.shape_function_laplacians, spu.ncomp, msh.nqn, spu.nsh_max, msh.nel); + + rows = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + cols = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + values = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + + jacdet_weights = msh.jacdet .* msh.quad_weights .* coeff; + + ncounter = 0; + for iel = 1:msh.nel + if (all (msh.jacdet(:,iel))) + gradv_iel = gradv(:,:,:,:,iel); + normal_iel = reshape (msh.normal(:,:,iel), [1, ndim, msh.nqn]); + + gradv_n = reshape (sum (bsxfun (@times, gradv_iel, normal_iel), 2), spv.ncomp, msh.nqn, spv.nsh_max, 1); + shpu_iel = reshape (shpu(:, :, :, iel), spu.ncomp, msh.nqn, 1, spu.nsh_max); + + jacdet_iel = reshape (jacdet_weights(:,iel), [1,msh.nqn,1,1]); + + gradv_n_times_jw = bsxfun (@times, jacdet_iel, gradv_n); + tmp1 = sum (bsxfun (@times, gradv_n_times_jw, shpu_iel), 1); + elementary_values = reshape (sum (tmp1, 2), spv.nsh_max, spu.nsh_max); + + [rows_loc, cols_loc] = ndgrid (spv.connectivity(:,iel), spu.connectivity(:,iel)); + indices = rows_loc & cols_loc; + rows(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = rows_loc(indices); + cols(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = cols_loc(indices); + values(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = elementary_values(indices); + ncounter = ncounter + spu.nsh(iel)*spv.nsh(iel); + + else + warning ('geopdes:jacdet_zero_at_quad_node', 'op_gradv_n_laplaceu: singular map in element number %d', iel) + end + end + + + if (nargout == 1 || nargout == 0) + varargout{1} = sparse (rows, cols, values, spv.ndof, spu.ndof); + elseif (nargout == 3) + varargout{1} = rows; + varargout{2} = cols; + varargout{3} = values; + else + error ('op_gradv_n_laplaceu: wrong number of output arguments') + end + + +end diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 9bd0a633..453bda04 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -35,6 +35,8 @@ % - nquad: number of points for Gaussian quadrature rule % - dt: time step size for generalized-alpha method % - rho_inf_gen_alpha: parameter in [0,1], which governs numerical damping of the generalized alpha method +% - Cpen_nitsche: penalization parameter for Nitsche's method, to impose Neumann conditions +% - Cpen_projection: penalization parameter to impose zero flux for the initial condition % % OUTPUT: % @@ -133,7 +135,7 @@ bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); % Compute the penalty matrix -[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, pen_nitsche); +[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, Cpen_nitsche); %%------------------------------------------------------------------------- @@ -141,14 +143,14 @@ time = 0; if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_tp (space, msh, fun_u); - u_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; + u_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; else u_n = zeros(space.ndof, 1); end if (exist('fun_udot', 'var') && ~isempty(fun_udot)) rhs = op_f_v_tp(space, msh, fun_udot); - udot_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; + udot_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; else udot_n = zeros(space.ndof, 1); end @@ -376,65 +378,6 @@ end end -%-------------------------------------------------------------------------- -% Operator grav_n_laplaceu -%-------------------------------------------------------------------------- - -function varargout = op_gradv_n_laplaceu (spu, spv, msh, coeff) - - gradv = reshape (spv.shape_function_gradients, spv.ncomp, [], ... - msh.nqn, spv.nsh_max, msh.nel); - - ndim = size (gradv, 2); - - shpu = reshape (spu.shape_function_laplacians, spu.ncomp, msh.nqn, spu.nsh_max, msh.nel); - - rows = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - cols = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - values = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - - jacdet_weights = msh.jacdet .* msh.quad_weights .* coeff; - - ncounter = 0; - for iel = 1:msh.nel - if (all (msh.jacdet(:,iel))) - gradv_iel = gradv(:,:,:,:,iel); - normal_iel = reshape (msh.normal(:,:,iel), [1, ndim, msh.nqn]); - - gradv_n = reshape (sum (bsxfun (@times, gradv_iel, normal_iel), 2), spv.ncomp, msh.nqn, spv.nsh_max, 1); - shpu_iel = reshape (shpu(:, :, :, iel), spu.ncomp, msh.nqn, 1, spu.nsh_max); - - jacdet_iel = reshape (jacdet_weights(:,iel), [1,msh.nqn,1,1]); - - gradv_n_times_jw = bsxfun (@times, jacdet_iel, gradv_n); - tmp1 = sum (bsxfun (@times, gradv_n_times_jw, shpu_iel), 1); - elementary_values = reshape (sum (tmp1, 2), spv.nsh_max, spu.nsh_max); - - [rows_loc, cols_loc] = ndgrid (spv.connectivity(:,iel), spu.connectivity(:,iel)); - indices = rows_loc & cols_loc; - rows(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = rows_loc(indices); - cols(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = cols_loc(indices); - values(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = elementary_values(indices); - ncounter = ncounter + spu.nsh(iel)*spv.nsh(iel); - - else - warning ('geopdes:jacdet_zero_at_quad_node', 'op_gradv_n_u: singular map in element number %d', iel) - end - end - - - if (nargout == 1 || nargout == 0) - varargout{1} = sparse (rows, cols, values, spv.ndof, spu.ndof); - elseif (nargout == 3) - varargout{1} = rows; - varargout{2} = cols; - varargout{3} = values; - else - error ('op_gradv_n_u: wrong number of output arguments') - end - -end - %-------------------------------------------------------------------------- % Penalty term %-------------------------------------------------------------------------- From 79ce4bbc17c16202f10caef9f0da36fc89290cd0 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 2 May 2023 14:13:58 +0200 Subject: [PATCH 268/366] Use local version of Cpatch for shells --- .../@sp_multipatch_C1/op_KL_shells_mp.m | 67 ++++++ .../@sp_multipatch_C1/op_f_v_mp_vector.m | 62 ++++++ .../@sp_multipatch_C1/op_su_ev_mp.m | 65 ++++++ .../@sp_multipatch_C1/sp_drchlt_C1_shells.m | 128 +++++++++++ .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 10 +- ...olve_kirchhoff_love_shell_C1_scalarspace.m | 169 +++++++++++++++ ...p_solve_linear_elasticity_C1_scalarspace.m | 204 ++++++++++++++++++ 7 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m create mode 100644 geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m create mode 100644 geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m new file mode 100644 index 00000000..1ab2ee82 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m @@ -0,0 +1,67 @@ +% OP_KL_SHELLS_MP: assemble the Kirchhoff-Love shell stiffness matrix. +% +% mat = op_KL_shells_mp (spu, spv, msh, E_coeff, nu_coeff, t_coeff, [patches]); +% [rows, cols, values] = op_KL_shells_mp (spu, spv, msh, E_coeff, nu_coeff, t_coeff, [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% E_coeff: function handle to compute the Young's modulus +% nu_coeff: function handle to compute the Poisson's ratio +% t_coeff: thickness of the shell, scalar value +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. + +% OUTPUT: +% +% mat: assembled stiffness matrix +% +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_KL_shells_mp (space_u, space_v, msh, E_coeff, nu_coeff, t_coeff, patch_list) + + if (nargin < 7) + patch_list = 1:msh.npatch; + end + + if ((space_u.npatch ~= space_v.npatch) || (space_u.npatch ~= msh.npatch)) + error ('op_KL_shells_mp: the number of patches does not coincide') + end + + A = sparse (msh.rdim*space_v.ndof, msh.rdim*space_u.ndof); + + for iptc = patch_list + Ap = op_KL_shells_tp (space_u.sp_patch{iptc}, space_v.sp_patch{iptc}, msh.msh_patch{iptc}, E_coeff, nu_coeff, t_coeff); + + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (space_u, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (space_v, iptc); + Cpatch_u = repmat ({Cpatch_u}, 1, msh.rdim); + Cpatch_v = repmat ({Cpatch_v}, 1, msh.rdim); + Cpatch_vector_spu = blkdiag (Cpatch_u{:}); + Cpatch_vector_spv = blkdiag (Cpatch_v{:}); + + cols_u = []; cols_v = []; + for icomp = 1:msh.rdim + cols_u = union (cols_u, (icomp-1)*space_u.ndof + Cpatch_cols_u); + cols_v = union (cols_v, (icomp-1)*space_v.ndof + Cpatch_cols_v); + end + + A(cols_v,cols_u) = ... + A(cols_v,cols_u) + Cpatch_vector_spv.' * Ap * Cpatch_vector_spu; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m new file mode 100644 index 00000000..9a7484bf --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m @@ -0,0 +1,62 @@ +% OP_F_V_MP_VECTOR: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain, +% where f is vector-valued, and the basis functions in each component belong to the same scalar space. +% +% rhs = op_f_v_mp_vector (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2017, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_v_mp_vector (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_v_mp_vector: the number of patches does not coincide') + end + + rhs = zeros (msh.rdim*space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_v_tp_vector (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + +% if (~isempty (space.dofs_ornt)) +% rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); +% end + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + + Cpatch = repmat ({Cpatch}, 1, msh.rdim); + Cpatch_vector = blkdiag (Cpatch{:}); + + cols = []; + for icomp = 1:msh.rdim + cols = union (cols, (icomp-1)*space.ndof + Cpatch_cols); + end + + rhs(cols) = rhs(cols) + Cpatch_vector.' * rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m new file mode 100644 index 00000000..b56d1ca8 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m @@ -0,0 +1,65 @@ +% OP_SU_EV_MP: assemble the matrix A = [a(i,j)], a(i,j) = 1/2 (sigma (u_j), epsilon (v_i)), in a multipatch domain. +% +% mat = op_su_ev_mp (spu, spv, msh, lambda, mu, [patches]); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_multipatch) +% spv: object representing the space of test functions (see sp_multipatch) +% msh: object that defines the domain partition and the quadrature rule (see msh_multipatch) +% lambda, mu: function handles to compute the Lame' coefficients +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2015, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = op_su_ev_mp (spu, spv, msh, lambda, mu, patch_list) + + if (nargin < 6) + patch_list = 1:msh.npatch; + end + + if ((spu.npatch ~= spv.npatch) || (spu.npatch ~= msh.npatch)) + error ('op_su_ev_mp: the number of patches does not coincide') + end + + A = sparse (msh.rdim*spv.ndof, msh.rdim*spu.ndof); + + for iptc = patch_list + Ap = op_su_ev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, lambda, mu); + + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); + [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); + + Cpatch_u = repmat ({Cpatch_u}, 1, msh.rdim); + Cpatch_v = repmat ({Cpatch_v}, 1, msh.rdim); + Cpatch_vector_spu = blkdiag (Cpatch_u{:}); + Cpatch_vector_spv = blkdiag (Cpatch_v{:}); + + cols_u = []; cols_v = []; + for icomp = 1:msh.rdim + cols_u = union (cols_u, (icomp-1)*spu.ndof + Cpatch_cols_u); + cols_v = union (cols_v, (icomp-1)*spv.ndof + Cpatch_cols_v); + end + + A(cols_v,cols_u) = ... + A(cols_v,cols_u) + Cpatch_vector_spv.' * Ap * Cpatch_vector_spu; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m new file mode 100644 index 00000000..dda4d66f --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m @@ -0,0 +1,128 @@ +function [u_drchlt, drchlt_dofs, kernel_info] = sp_drchlt_C1_shells (space, msh, refs, drchlt_components) + +% TODO: IT WILL ALWAYS SET THE VALUE TO ZERO + +% refs should be the whole boundary, for now +% M = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, msh.rdim*space.ndof); +% rhs = zeros (msh.rdim*space.ndof, 1); + +drchlt_dofs = []; + +boundaries = msh.boundaries; +for iref = refs +% href = @(varargin) h(varargin{:}, iref); + if (~exist('drchlt_components','var')) + components = 1:3; + else + components = drchlt_components{iref}; + end + scalar_dofs_on_ref = []; + for bnd_side = 1:boundaries(iref).nsides + iptc = boundaries(iref).patches(bnd_side); + iside = boundaries(iref).faces(bnd_side); + + msh_side = msh.msh_patch{iptc}.boundary(iside); + sp_bnd = space.sp_patch{iptc}.boundary(iside); + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + + [~,scalar_dofs] = find (Cpatch(sp_bnd.dofs,:)); + scalar_dofs_on_ref = union (scalar_dofs_on_ref, Cpatch_cols(scalar_dofs)); +% Cpatch_bnd = space.Cpatch{iptc}(sp_bnd.dofs,:); +% [~,scalar_dofs] = find (abs(Cpatch_bnd)>1e-15); +% +% scalar_dofs_on_ref = union (scalar_dofs_on_ref, scalar_dofs); + end + for icomp = components + drchlt_dofs = union (drchlt_dofs, (icomp-1)*space.ndof + scalar_dofs_on_ref); + end +end + +dofs_to_remove = []; +vertices_numbers = []; +row_indices = []; +count_vert = 0; +count_fun = 0; + +% Check the kernel of vertex functions on Dirichlet boundary vertices +% Pick up the basis function with the max. abs. coeff in the kernel, +% remove it from drchlt_dofs, and add the function in the kernel into the +% internal part (it goes in the output) +B_change_local = []; +n_boundaries = numel(msh.boundaries); % number of boundary edges +global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges + +for iv = 1 : numel(space.vertices) + % Loop just over Dirichlet boundary vertices + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + + Cpatch_ind_R = indices_loc_R([1 2 3]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); +% Cpatch_ind_R = indices_loc_R([1 2 3 space.sp_patch{patches(1)}.ndof_dir(1)+[1 2]]); +% if (space.vertices(iv).valence_p == 2) +% Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); +% else +% Cpatch_ind_L = indices_loc_L([2 space.sp_patch{patches(2)}.ndof_dir(1)+[1 2] 2*space.sp_patch{patches(2)}.ndof_dir(1)+1]); +% end + + [Cpatch1, Cpatch_cols1] = sp_compute_Cpatch (space, patches(1)); + [Cpatch2, Cpatch_cols2] = sp_compute_Cpatch (space, patches(2)); + + [~,~,inds1] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols1); + [~,~,inds2] = intersect (space.dofs_on_vertex{iv}, Cpatch_cols2); + + M_ker = [Cpatch1(Cpatch_ind_R, inds1); ... + Cpatch2(Cpatch_ind_L, inds2)]; +% M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... +% space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + + ker = null(full(M_ker)); + if (~isempty(ker)) + nfun = size(ker,2); + [~, ind] = max(abs(ker)); % TODO: NOT A GOOD CHOICE (it may be repeated) + + row_inds = count_vert*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_fun+(1:nfun)) = iv; + dofs_to_remove(count_fun+(1:nfun)) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + count_vert = count_vert + 1; + count_fun = count_fun + nfun; + end + end + end +end + +kernel_info = struct ('vertices_numbers', vertices_numbers, 'all_vertex_dofs', row_indices, 'quasi_interior_dofs', dofs_to_remove, 'B_change_local', sparse(B_change_local)); + +dofs_to_remove = [dofs_to_remove(:), dofs_to_remove(:)+space.ndof, dofs_to_remove(:)+2*space.ndof]; +drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); +% drchlt_dofs = [drchlt_dofs(:); drchlt_dofs(:)+space.ndof; drchlt_dofs(:)+2*space.ndof]; + +u_drchlt = zeros (numel(drchlt_dofs), 1); + +end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index f686f8ea..98313b66 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -78,9 +78,15 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) % filename_patch, fieldname, varargin{:}) % end elseif (numel(u) == space.ndof*geometry(iptc).rdim) - Cpatch_repmat = repmat (space.Cpatch(iptc), 1, geometry(iptc).rdim); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + Cpatch_repmat = repmat ({Cpatch}, 1, geometry(iptc).rdim); Cpatch_vector = blkdiag (Cpatch_repmat{:}); - sp_to_vtk (Cpatch_vector * u, space.sp_patch{iptc}, geometry(iptc), npts, ... + + cols = []; + for icomp = 1:geometry(iptc).rdim + cols = union (cols, (icomp-1)*space.ndof + Cpatch_cols); + end + sp_to_vtk (Cpatch_vector * u(cols), space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) end end diff --git a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m new file mode 100644 index 00000000..fb748e6c --- /dev/null +++ b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m @@ -0,0 +1,169 @@ +% SOLVE_KIRCHHOFF_LOVE_SHELL_C1_SCALARSPACE: Solve the Kirchhoff-Love shell model in a NURBS domain. +% It uses an object space of type sp_multipatch_C1 with scalar values, instead of vector valued. +% +% USAGE: +% +% [geometry, msh, space, u] = mp_solve_kirchhoff_love_shell_C1_scalarspace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - drchlt_sides: sides with Dirichlet boundary condition +% - drchlt_components: cell-array, the components that are set to zero for each drchlt_side +% - E_coeff: function handle for Young's modulus +% - nu_coeff: function handle for Poisson's ratio +% - thickness: scalar value, thickness of the shell +% - f: source term, distributed load +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree (>=3) of the spline functions. +% - regularity: continuity (>=1, <=degree-2) of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: geometry structure (see mp_geo_load) +% msh: mesh object that defines the quadrature rule (see msh_multipatch) +% space: space object that defines the discrete basis functions (see sp_multipatch_C1) +% u: the computed degrees of freedom +% +% Copyright (C) 2017-2019 Pablo Antolin, Luca Coradello, Rafael Vazquez +% Copyright (C) 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 2 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_kirchhoff_love_shell_C1_scalarspace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +if (any(degree <= 1) || any(regularity == 0)) + error ('The degree must be at least two, and the regularity at least C^1') +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +[edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); +msh = msh_multipatch (msh, boundaries); +space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); +clear sp + +% Compute and assemble the matrices +K = op_KL_shells_mp (space, space, msh, E_coeff, nu_coeff, thickness); +rhs = op_f_v_mp_vector (space, msh, f); + +% Apply boundary conditions +% drchlt_dofs = []; drchlt_dofs2 = []; +% for iref = 1:numel(drchlt_sides) +% if (~exist('drchlt_components','var')) +% components = 1:3; +% else +% components = drchlt_components{iref}; +% end +% bnd_ref = drchlt_sides(iref); +% scalar_dofs_on_ref = []; +% scalar_dofs_on_ref2 = []; +% for bnd_side = 1:msh.boundaries(bnd_ref).nsides +% iptc = msh.boundaries(bnd_ref).patches(bnd_side); +% iside = msh.boundaries(bnd_ref).faces(bnd_side); +% +% % msh_side = msh.msh_patch{iptc}.boundary(iside); +% side_dofs = space.sp_patch{iptc}.boundary(iside).dofs; +% +% [~,scalar_dofs] = find (abs(space.Cpatch{iptc}(side_dofs,:))>1e-15); +% % [~,scalar_dofs] = find (space.Cpatch{iptc}(side_dofs,:)); +% scalar_dofs_on_ref = union (scalar_dofs_on_ref, scalar_dofs); +% end +% for icomp = components +% drchlt_dofs = union (drchlt_dofs, (icomp-1)*space.ndof + scalar_dofs_on_ref); +% drchlt_dofs2 = union (drchlt_dofs2, (icomp-1)*space2.ndof + scalar_dofs_on_ref2); +% end +% end +% +% ndof = msh.rdim * space.ndof; +% u = zeros (ndof, 1); +% int_dofs = setdiff (1:ndof, drchlt_dofs); +% +% % Solve the linear system +% u(int_dofs) = K(int_dofs, int_dofs) \ rhs(int_dofs); + +if (~isfield (problem_data, 'uex')) + [u_drchlt, drchlt_dofs, kernel_dofs] = sp_drchlt_C1_shells (space, msh, drchlt_sides, drchlt_components); +else + [u_drchlt, drchlt_dofs, kernel_dofs] = sp_drchlt_C1_exact_shells (space, msh, drchlt_sides, problem_data.uex); +end + +ndof = msh.rdim * space.ndof; +u = zeros (ndof, 1); +u(drchlt_dofs) = u_drchlt; + +int_dofs = setdiff (1:ndof, drchlt_dofs); +add_dofs = kernel_dofs.quasi_interior_dofs; %this will contain the "boundary" vertex dofs which have been removed from drchlt_dofs +add_dofs = [add_dofs, space.ndof+add_dofs, 2*space.ndof+add_dofs]; + +% We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking +% into account the Dirichlet conditions), and the basis change matrix (we will need it +% to go from the basis with kernel vectors obtained when examnining the dirichlet conditions +% to the usual basis) +vertex_dofs = kernel_dofs.all_vertex_dofs; +vertex_dofs = [vertex_dofs, space.ndof+vertex_dofs, 2*space.ndof+vertex_dofs]; +% B_change = speye (space.ndof); %basis change matrix +% B_change(kernel_dofs.all_vertex_dofs,kernel_dofs.quasi_interior_dofs) = kernel_dofs.B_change_local; + +B_change_vector = blkdiag(kernel_dofs.B_change_local, kernel_dofs.B_change_local, kernel_dofs.B_change_local); +K(:,add_dofs) = K(:,vertex_dofs) * B_change_vector; +K(add_dofs,:) = B_change_vector.' * K(vertex_dofs,:); +rhs(add_dofs) = B_change_vector.' * rhs(vertex_dofs); + +% rhs(int_dofs) = rhs(int_dofs) - K(int_dofs, drchlt_dofs)*u_drchlt; + +% Solve the linear system +u(int_dofs) = K(int_dofs, int_dofs) \ rhs(int_dofs); + +% Switching to the usual basis using the local matrix for the vertex dofs +u_old = u(setdiff(vertex_dofs, add_dofs)); % Coefficients of the vertex functions that were already in the old basis +u(vertex_dofs) = B_change_vector * u(add_dofs); +u(setdiff(vertex_dofs, add_dofs)) = u(setdiff(vertex_dofs, add_dofs)) + u_old; + +end diff --git a/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m new file mode 100644 index 00000000..fd9ce2ee --- /dev/null +++ b/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m @@ -0,0 +1,204 @@ +% MP_SOLVE_LINEAR_ELASTICITY_C1_SCALARSPACE: Solve a linear elasticity problem in a multipatch domain. +% It uses an object space of type sp_multipatch_C1 with scalar values, instead of vector valued. +% +% Example to solve the linear elasticity problem +% +% - div (sigma(u)) = f in Omega +% sigma(u) \cdot n = g on Gamma_N +% u = h on Gamma_D +% +% with sigma(u) = mu*(grad(u) + grad(u)^t) + lambda*div(u)*I, +% and the domain \Omega is formed by several patches of the form F((0,1)^n). +% +% u: displacement vector +% sigma: Cauchy stress tensor +% lambda, mu: Lame' parameters +% I: identity tensor +% +% USAGE: +% +% [geometry, msh, space, u] = +% mp_solve_linear_elasticity (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition +% - lambda_lame: first Lame' parameter +% - mu_lame: second Lame' parameter +% - f: source term +% - h: function for Dirichlet boundary condition +% - g: function for Neumann condition (if nmnn_sides is not empty) +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: array of geometry structures (see geo_load) +% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch_C1) +% u: the computed degrees of freedom +% +% Copyright (C) 2010, 2011 Carlo de Falco +% Copyright (C) 2010, 2011, 2015, 2017, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, u] = ... + mp_solve_linear_elasticity_C1_scalarspace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +for iptc = 1:npatch +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +[edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); +msh = msh_multipatch (msh, boundaries); +space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); +clear sp + +% Compute and assemble the matrices +mat = op_su_ev_mp (space, space, msh, lambda_lame, mu_lame); +rhs = op_f_v_mp_vector (space, msh, f); + +% % % Apply Neumann boundary conditions +% % Nbnd = cumsum ([0, boundaries.nsides]); +% % for iref = nmnn_sides +% % iref_patch_list = Nbnd(iref)+1:Nbnd(iref+1); +% % gref = @(varargin) g(varargin{:},iref); +% % rhs_nmnn = op_f_v_mp (space.boundary, msh.boundary, gref, iref_patch_list); +% % rhs(space.boundary.dofs) = rhs(space.boundary.dofs) + rhs_nmnn; +% % end +% % +% % if (exist ('press_sides', 'var')) +% % for iref = press_sides +% % rhs_press = zeros (space.boundary.ndof, 1); +% % for iside = 1:numel(boundaries(iref).nsides) +% % patch = boundaries(iref).patches(iside); +% % side = boundaries(iref).faces(iside); +% % msh_side = msh_eval_boundary_side (msh.msh_patch{patch}, side); +% % sp_side = sp_eval_boundary_side (space.sp_patch{patch}, msh_side); +% % +% % x = cell (msh_side.rdim, 1); +% % for idim = 1:msh_side.rdim +% % x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); +% % end +% % pval = reshape (p (x{:}, iside), msh_side.nqn, msh_side.nel); +% % +% % rhs_press(space.boundary.gnum{patch}) = rhs_press(space.boundary.gnum{patch}) + op_pn_v (sp_side, msh_side, pval); +% % end +% % rhs(space.boundary.dofs) = rhs(space.boundary.dofs) - rhs_press; +% % end +% % end +% % +% % symm_dofs = []; +% % if (exist ('symm_sides', 'var')) +% % for iref = symm_sides +% % if (~strcmpi (space.transform, 'grad-preserving')) +% % error ('The symmetry condition is only implemented for spaces with grad-preserving transform') +% % end +% % for iside = 1:boundaries(iref).nsides +% % patch = boundaries(iref).patches(iside); +% % side = boundaries(iref).faces(iside); +% % msh_side = msh_eval_boundary_side (msh.msh_patch{patch}, side); +% % normal_comp = zeros (msh_side.rdim, msh_side.nqn * msh_side.nel); +% % for idim = 1:msh_side.rdim +% % normal_comp(idim,:) = reshape (msh_side.normal(idim,:,:), 1, msh_side.nqn*msh_side.nel); +% % end +% % +% % parallel_to_axes = false; +% % for ind = 1:msh_side.rdim +% % ind2 = setdiff (1:msh_side.rdim, ind); +% % if (all (all (abs (normal_comp(ind2,:)) < 1e-10))) +% % bnd_side = space.sp_patch{patch}.boundary(side); +% % dofs = bnd_side.dofs(bnd_side.comp_dofs{ind}); +% % symm_dofs = union (symm_dofs, space.gnum{patch}(dofs)); +% % parallel_to_axes = true; +% % break +% % end +% % end +% % if (~parallel_to_axes) +% % error ('mp_solve_linear_elasticity: We have only implemented the symmetry condition for boundaries parallel to the axes') +% % end +% % end +% % end +% % end + +% Apply Dirichlet boundary conditions +% TODO: implement non-homogeneous conditions +drchlt_dofs = []; +for iref = 1:numel(drchlt_sides) + bnd_ref = drchlt_sides(iref); + scalar_dofs_on_ref = []; + for bnd_side = 1:msh.boundaries(bnd_ref).nsides + iptc = msh.boundaries(bnd_ref).patches(bnd_side); + iside = msh.boundaries(bnd_ref).faces(bnd_side); + +% msh_side = msh.msh_patch{iptc}.boundary(iside); + side_dofs = space.sp_patch{iptc}.boundary(iside).dofs; + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + + [~,scalar_dofs] = find (Cpatch(side_dofs,:)); + scalar_dofs_on_ref = union (scalar_dofs_on_ref, Cpatch_cols(scalar_dofs)); + end + for icomp = 1:msh.rdim + drchlt_dofs = union (drchlt_dofs, (icomp-1)*space.ndof + scalar_dofs_on_ref); + end +end + +ndof = msh.rdim * space.ndof; +u = zeros (ndof, 1); + +int_dofs = setdiff (1:ndof, drchlt_dofs); +% Solve the linear system +u(int_dofs) = mat(int_dofs, int_dofs) \ rhs(int_dofs); + +end + +%!demo +%! ex_plane_strain_Lshaped_mp + +%!demo +%! ex_lin_elast_cube_mp From 1f991048e235a7d209324ad81d56fe4c509c5ee4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 2 May 2023 17:10:49 +0200 Subject: [PATCH 269/366] New function to compute Cpatch for vector-valued spaces. --- .../@sp_multipatch_C1/op_KL_shells_mp.m | 19 ++------ .../@sp_multipatch_C1/op_f_v_mp_vector.m | 15 ++----- .../@sp_multipatch_C1/op_su_ev_mp.m | 22 +++------- .../sp_compute_Cpatch_vector.m | 44 +++++++++++++++++++ .../multipatch/@sp_multipatch_C1/sp_to_vtk.m | 15 ++----- 5 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch_vector.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m index 1ab2ee82..ba7837cc 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m @@ -17,7 +17,7 @@ % % mat: assembled stiffness matrix % -% Copyright (C) 2022 Rafael Vazquez +% Copyright (C) 2022-2023 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -47,21 +47,10 @@ for iptc = patch_list Ap = op_KL_shells_tp (space_u.sp_patch{iptc}, space_v.sp_patch{iptc}, msh.msh_patch{iptc}, E_coeff, nu_coeff, t_coeff); - [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (space_u, iptc); - [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (space_v, iptc); - Cpatch_u = repmat ({Cpatch_u}, 1, msh.rdim); - Cpatch_v = repmat ({Cpatch_v}, 1, msh.rdim); - Cpatch_vector_spu = blkdiag (Cpatch_u{:}); - Cpatch_vector_spv = blkdiag (Cpatch_v{:}); - - cols_u = []; cols_v = []; - for icomp = 1:msh.rdim - cols_u = union (cols_u, (icomp-1)*space_u.ndof + Cpatch_cols_u); - cols_v = union (cols_v, (icomp-1)*space_v.ndof + Cpatch_cols_v); - end + [Cpatch_u, cols_u] = sp_compute_Cpatch_vector (space_u, iptc, msh.rdim); + [Cpatch_v, cols_v] = sp_compute_Cpatch_vector (space_v, iptc, msh.rdim); - A(cols_v,cols_u) = ... - A(cols_v,cols_u) + Cpatch_vector_spv.' * Ap * Cpatch_vector_spu; + A(cols_v,cols_u) = A(cols_v,cols_u) + Cpatch_v.' * Ap * Cpatch_u; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m index 9a7484bf..7a2fdd25 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_f_v_mp_vector.m @@ -14,7 +14,7 @@ % % rhs: assembled right-hand side % -% Copyright (C) 2015, 2017, 2022 Rafael Vazquez +% Copyright (C) 2015, 2017, 2022, 2023 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -46,17 +46,8 @@ % if (~isempty (space.dofs_ornt)) % rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); % end - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - - Cpatch = repmat ({Cpatch}, 1, msh.rdim); - Cpatch_vector = blkdiag (Cpatch{:}); - - cols = []; - for icomp = 1:msh.rdim - cols = union (cols, (icomp-1)*space.ndof + Cpatch_cols); - end - - rhs(cols) = rhs(cols) + Cpatch_vector.' * rhs_loc; + [Cpatch, cols] = sp_compute_Cpatch_vector (space, iptc, msh.rdim); + rhs(cols) = rhs(cols) + Cpatch.' * rhs_loc; end end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m index b56d1ca8..e6a0a242 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m @@ -14,7 +14,7 @@ % % mat: assembled matrix % -% Copyright (C) 2015, 2022 Rafael Vazquez +% Copyright (C) 2015, 2022, 2023 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -44,22 +44,10 @@ for iptc = patch_list Ap = op_su_ev_tp (spu.sp_patch{iptc}, spv.sp_patch{iptc}, msh.msh_patch{iptc}, lambda, mu); - [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (spu, iptc); - [Cpatch_v, Cpatch_cols_v] = sp_compute_Cpatch (spv, iptc); - - Cpatch_u = repmat ({Cpatch_u}, 1, msh.rdim); - Cpatch_v = repmat ({Cpatch_v}, 1, msh.rdim); - Cpatch_vector_spu = blkdiag (Cpatch_u{:}); - Cpatch_vector_spv = blkdiag (Cpatch_v{:}); - - cols_u = []; cols_v = []; - for icomp = 1:msh.rdim - cols_u = union (cols_u, (icomp-1)*spu.ndof + Cpatch_cols_u); - cols_v = union (cols_v, (icomp-1)*spv.ndof + Cpatch_cols_v); - end - - A(cols_v,cols_u) = ... - A(cols_v,cols_u) + Cpatch_vector_spv.' * Ap * Cpatch_vector_spu; + [Cpatch_u, cols_u] = sp_compute_Cpatch_vector (spu, iptc, msh.rdim); + [Cpatch_v, cols_v] = sp_compute_Cpatch_vector (spv, iptc, msh.rdim); + + A(cols_v,cols_u) = A(cols_v,cols_u) + Cpatch_v.' * Ap * Cpatch_u; end end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch_vector.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch_vector.m new file mode 100644 index 00000000..a3d6426d --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_compute_Cpatch_vector.m @@ -0,0 +1,44 @@ +% SP_COMPUTE_CPATCH_VECTOR: Compute the matrix for B-spline representation, and +% the indices of C^1 functions that do not vanish on a given patch, for vector-valued functions. +% +% [Cpatch, Cpatch_cols] = sp_compute_Cpatch_vector (space, patch, ncomp) +% +% INPUT: +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% patch: index of the patch +% ncomp: number of components of the vector-valued space +% +% OUTPUT: +% Cpatch: coefficients of the linear combination of basis functions as standard B-splines, +% The matrix is block diagonal, with each block computed as sp_compute_Cpatch. +% Cpatch_cols: indices of the C^1 basis functions that do not vanish on the patch +% (see also sp_get_functions_on_patch) +% +% Copyright (C) 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [Cpatch, Cpatch_cols] = sp_compute_Cpatch_vector (space, iptc, rdim) + + [Cpatch, cols] = sp_compute_Cpatch (space, iptc); + + Cpatch = repmat ({Cpatch}, 1, rdim); + Cpatch = blkdiag (Cpatch{:}); + + Cpatch_cols = []; + for icomp = 1:rdim + Cpatch_cols = union (Cpatch_cols, (icomp-1)*space.ndof + cols); + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index 98313b66..f131ef2b 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -21,7 +21,7 @@ % none % % Copyright (C) 2010 Carlo de Falco, Rafael Vazquez -% Copyright (C) 2011, 2012, 2015, 2022 Rafael Vazquez +% Copyright (C) 2011, 2012, 2015, 2022, 2023 Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -68,8 +68,8 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) filename_patch = cat (2, filename, '_', num2str (iptc)); fprintf (fid, str2, iptc, filename_patch_without_path); - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); if (numel(u) == space.ndof) + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); % if (isempty (space.dofs_ornt)) sp_to_vtk (Cpatch * u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) @@ -78,15 +78,8 @@ function sp_to_vtk (u, space, geometry, npts, filename, fieldname, varargin) % filename_patch, fieldname, varargin{:}) % end elseif (numel(u) == space.ndof*geometry(iptc).rdim) - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - Cpatch_repmat = repmat ({Cpatch}, 1, geometry(iptc).rdim); - Cpatch_vector = blkdiag (Cpatch_repmat{:}); - - cols = []; - for icomp = 1:geometry(iptc).rdim - cols = union (cols, (icomp-1)*space.ndof + Cpatch_cols); - end - sp_to_vtk (Cpatch_vector * u(cols), space.sp_patch{iptc}, geometry(iptc), npts, ... + [Cpatch, Cpatch_cols] = sp_compute_Cpatch_vector (space, iptc, geometry(iptc).rdim); + sp_to_vtk (Cpatch * u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), npts, ... filename_patch, fieldname, varargin{:}) end end From b3dc4fdc1386e35f238c08f83fbe70e4001b8bfb Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 3 May 2023 17:22:09 +0200 Subject: [PATCH 270/366] Fixed wrong nonzero connectivities --- geopdes/inst/space/sp_scalar2vector.m | 18 ++++++++++++++++-- geopdes/inst/space/sp_scalar2vector_param.m | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/space/sp_scalar2vector.m b/geopdes/inst/space/sp_scalar2vector.m index 8334fb3b..44ca483b 100644 --- a/geopdes/inst/space/sp_scalar2vector.m +++ b/geopdes/inst/space/sp_scalar2vector.m @@ -44,6 +44,7 @@ divergence = false; curl = false; hessian = false; +laplacian = false; if (~isempty (varargin)) if (~rem (length (varargin), 2) == 0) error ('sp_scalar2vector: options must be passed in the [option, value] format'); @@ -59,6 +60,8 @@ divergence = varargin {ii+1}; elseif (strcmpi (varargin {ii}, 'hessian')) hessian = varargin {ii+1}; + elseif (strcmpi (varargin {ii}, 'laplacian')) + laplacian = varargin {ii+1}; else warning ('Ignoring unknown option %s', varargin {ii}); end @@ -69,12 +72,15 @@ space_vec.nsh_max = ncomp * space.nsh_max; space_vec.nsh = ncomp * space.nsh; space_vec.ndof = ncomp * space.ndof; - space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + if (isfield (space, 'ndof_dir')) + space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + end space_vec.ncomp = ncomp; space_vec.connectivity = []; + isnonzero = space.connectivity~=0; for icomp = 1:ncomp - space_vec.connectivity = [space_vec.connectivity; space.connectivity+(icomp-1)*space.ndof]; + space_vec.connectivity = [space_vec.connectivity; (space.connectivity+(icomp-1)*space.ndof).*isnonzero]; end if (value) @@ -131,4 +137,12 @@ end end + if (laplacian) + space_vec.shape_function_laplacians = zeros (ncomp, msh.nqn, space_vec.nsh_max, msh.nel); + for icomp = 1:ncomp + fun_inds = (icomp-1)*space.nsh_max+1:icomp*space.nsh_max; + space_vec.shape_function_laplacians(icomp,:,fun_inds,:) = space.shape_function_laplacians; + end + end + end diff --git a/geopdes/inst/space/sp_scalar2vector_param.m b/geopdes/inst/space/sp_scalar2vector_param.m index 882ce5e9..d1c7a9a5 100644 --- a/geopdes/inst/space/sp_scalar2vector_param.m +++ b/geopdes/inst/space/sp_scalar2vector_param.m @@ -68,8 +68,9 @@ space_vec.ncomp = ncomp; space_vec.connectivity = []; + isnonzero = space.connectivity~=0; for icomp = 1:ncomp - space_vec.connectivity = [space_vec.connectivity; space.connectivity+(icomp-1)*space.ndof]; + space_vec.connectivity = [space_vec.connectivity; (space.connectivity+(icomp-1)*space.ndof).*isnonzero]; end if (value) From 5b5636bf0aec226d42959fcc69cab4185b631dda Mon Sep 17 00:00:00 2001 From: torre95michele Date: Mon, 8 May 2023 09:57:55 +0200 Subject: [PATCH 271/366] Cahn Hilliard solver for multipatch C1 (tensor product) --- .../cahn-hilliard/ex_cahn_hilliard_mpC1.m | 78 +++ geopdes/inst/solve/solve_cahn_hilliard_mpC1.m | 587 ++++++++++++++++++ 2 files changed, 665 insertions(+) create mode 100644 geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m create mode 100644 geopdes/inst/solve/solve_cahn_hilliard_mpC1.m diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m new file mode 100644 index 00000000..46d32d83 --- /dev/null +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -0,0 +1,78 @@ +clc + +% 1) PHYSICAL DATA OF THE PROBLEM +clear problem_data +% Physical domain, defined as NURBS map given in a text file +nrb1 = nrb4surf ([0 0], [.5 0], [0 1], [.5 1]); +nrb2 = nrb4surf ([.5 0], [1 0], [.5 1], [1 1]); +problem_data.geo_name = [nrb1,nrb2]; %'geo_square_mp.txt'; + +% Physical parameters +lambda = (1/(4*sqrt(2)*pi))^2; +problem_data.lambda = @(x, y) lambda* ones(size(x)); + + +% Time and time step size +Time_max = .5; +dt = 1e-2; +time_step_save = linspace(dt,Time_max,9); +problem_data.time = 0; +problem_data.Time_max = Time_max; + + +% Penalty parameters +problem_data.pen_nitsche = 1e4 * lambda; % Nitsche's method parameter +problem_data.pen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) + +% 2) INITIAL CONDITIONS +mean = 0.0; +var = 0.05; +ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition +%ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). +problem_data.fun_u = ic_fun; +% problem_data.fun_udot = []; + +% 3) CHOICE OF THE DISCRETIZATION PARAMETERS +clear method_data +deg = 3; nel = 10; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [nel nel]; % Number of subdivisions +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule + +% time integration parameters +method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method +method_data.dt = dt; % Time step size + + + +% 4) CALL TO THE SOLVER +[geometry, msh, space, results] = solve_cahn_hilliard_mpC1 (problem_data, method_data, time_step_save); + + +% 5) POST-PROCESSING +vtk_pts = {linspace(0, 1, nel*4), linspace(0, 1, nel*4)}; +folder_name = strcat('results_CH_mpC1_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); +status = mkdir(folder_name); + +% 5.1) EXPORT TIME +filename = strcat( folder_name,'/filenum_to_time.mat'); +time_steps = results.time; +save(filename, 'time_steps'); + + +% 5.2) EXPORT TO PARAVIEW +for step = 1:length(results.time) + output_file = strcat( folder_name,'/Square_cahn_hilliard_', num2str(step) ); + fprintf ('The result is saved in the file %s \n \n', output_file); + sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'u','grad_u'}, {'value','gradient'}) +end + +% % 5.3) PLOT LAST RESULT +% [eu, F] = sp_eval (results.u(:,end), space, geometry, vtk_pts); +% [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); +% surf (X, Y, eu) +% colorbar +% view(0,90) +% shading interp +% axis equal tight \ No newline at end of file diff --git a/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m b/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m new file mode 100644 index 00000000..78dd9d93 --- /dev/null +++ b/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m @@ -0,0 +1,587 @@ +% SOLVE_CAHN_HILLIARD: solve the Cahn-Hilliard equation, with a generalized alpha discretization in time. +% +% The functions solves the problem of finding u such that +% +% du/dt - Delta (mu(u) - lambda*Delta u) = 0 +% +% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic boundary conditions. +% +% The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. +% +% For details on the problem and the formulation, see +% H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. +% H. Gomez, A. Reali, G. Sangalli, J. Comput. Physics 262 (2014), 153-171. +% +% USAGE: +% +% [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, save_info) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) +% - lambda: parameter representing the length scale of the problem, and the width of the interface +% - Time_max: final time +% - fun_u: initial condition. Equal to zero by default. +% - fun_udot: initial condition for time derivative. Equal to zero by default. +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% - dt: time step size for generalized-alpha method +% - rho_inf_gen_alpha: parameter in [0,1], which governs numerical damping of the generalized alpha method +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete space (see sp_scalar) +% results: a struct with the saved results, containing the following fields: +% - time: (array of length Ntime) time at which the solution was saved +% - u: (size ndof x Ntime) degrees of freedom for the solution +% - udot: (size ndof x Ntime) degrees of freedom for the time derivative +% +% Only periodic and Neumann boundary conditions are implemented. Neumann +% conditions are considered by default. +% +% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, space, results] = solve_cahn_hilliard_mpC1 (problem_data, method_data, save_info) + +%%------------------------------------------------------------------------- +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +%%------------------------------------------------------------------------- +% Construct geometry structure + + + + +% Construct geometry structure, and information for interfaces and boundaries +[geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); +npatch = numel (geometry); + +msh = cell (1, npatch); +sp = cell (1, npatch); +for iptc = 1:npatch + +% Define the refined mesh, with tensor product structure + [knots{iptc}, zeta{iptc}] = ... + kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); + +% Compute the quadrature rule + rule = msh_gauss_nodes (nquad); + [qn, qw] = msh_set_quad_nodes (zeta{iptc}, rule); + msh{iptc} = msh_cartesian (zeta{iptc}, qn, qw, geometry(iptc)); + +% Evaluate the discrete space basis functions in the quadrature points + sp{iptc} = sp_bspline (knots{iptc}, degree, msh{iptc}); +end + +[edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); +msh = msh_multipatch (msh, boundaries); +% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); +space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); +clear sp + +% % Compute and assemble the matrices +% c_diff = @(x, y) ones(size(x)); +% stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); +% f = @(x, y) ones(size(x)); +% rhs = op_f_v_mp (space, msh, f); +% drchlt_dofs = 1:10; +% int_dofs = setdiff (1:space.ndof, drchlt_dofs); +% % Solve the linear system +% u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); +% output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; +% vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; +% fprintf ('The result is saved in the file %s.pvd \n \n', output_file); +% sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') +% figure +% sp_plot_solution (u, space, geometry, vtk_pts) +% return + + +%%------------------------------------------------------------------------- +% Generalized alpha parameters +a_m = .5*((3-rho_inf_gen_alpha)/(1+rho_inf_gen_alpha)); +a_f = 1/(1+rho_inf_gen_alpha); +gamma = .5 + a_m - a_f; + +%%------------------------------------------------------------------------- +% No flux b.c. (essential boundary condition) +% Set Neumann boundary conditions for non-periodic sides +nmnn_bou = 1:numel(boundaries); + +%%------------------------------------------------------------------------- +% Precompute matrices + +% Compute the mass matrix +mass_mat = op_u_v_mp(space,space,msh); + +% Compute the laplace matrix +lapl_mat = op_laplaceu_laplacev_mp (space, space, msh, lambda); + +% Compute the boundary term +term4 = int_term_4 (space, msh, lambda, nmnn_bou); + +% Compute the penalty matrix +[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_bou, pen_nitsche); + + +%%------------------------------------------------------------------------- +% Initial conditions +time = 0; +if (exist('fun_u', 'var') && ~isempty(fun_u)) + rhs = op_f_v_mp (space, msh, fun_u); + u_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; +else + u_n = zeros(space.ndof, 1); +end + +if (exist('fun_udot', 'var') && ~isempty(fun_udot)) + rhs = op_f_v_mp(space, msh, fun_udot); + udot_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; +else + udot_n = zeros(space.ndof, 1); +end + +% flux_initial = check_flux_phase_field(space, msh, u_n, zeros(size(u_n))); +% disp(strcat('initial flux =',num2str(flux_initial))) + +%%------------------------------------------------------------------------- +% Initialize structure to store the results +save_id = 1; +results.u = zeros(length(u_n), length(save_info)+1); +results.udot = zeros(length(u_n), length(save_info)+1); +results.time = zeros(length(save_info)+1,1); +flag_stop_save = false; + +% Save initial conditions +results.u(:,1) = u_n; +results.udot(:,1) = udot_n; +results.time(1) = time; + +%%------------------------------------------------------------------------- +% Loop over time steps +while time < Time_max + disp('----------------------------------------------------------------') + disp(strcat('time step t=',num2str(time))) + + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh); + + % check flux through the boundary +% flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); +% disp(strcat('flux norm =',num2str(flux))) + + % Time step update + time = time + dt; + u_n = u_n1; + udot_n = udot_n1; + + % Check max time + if (time + dt > Time_max) + dt = Time_max-time; + end + + % Store results + if (flag_stop_save == false) + if (time >= save_info(save_id)) + save_id = save_id + 1; + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; + if (save_id > length(save_info)) + flag_stop_save = true; + end + end + end +end + +disp('----------------------------------------------------------------') +disp(strcat('END ANALYSIS t=',num2str(time))) +disp('----------------------------------------------------------------') + +% Crop results +results.u = results.u(:,1:save_id); +results.udot = results.udot(:,1:save_id); +results.time = results.time(1:save_id); + +end + +%-------------------------------------------------------------------------- +% FUNCTIONS +%-------------------------------------------------------------------------- + + +%-------------------------------------------------------------------------- +% One step of generalized alpha-method +%-------------------------------------------------------------------------- + +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh) + +% Convergence criteria + n_max_iter = 20; + tol_rel_res = 1e-10; + tol_abs_res = 1e-10; + +% Predictor step + u_n1 = u_n; + udot_n1 = (gamma-1)/gamma * udot_n; + +% Newton loop + for iter = 0:n_max_iter + + % Field at alpha level + udot_a = udot_n + a_m *(udot_n1-udot_n); + u_a = u_n + a_f *(u_n1-u_n); + + % Compute the residual (internal) + [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... + mass_mat, lapl_mat, term4, Pen, pen_rhs, ... + u_a, udot_a); + + % Convergence check + if iter == 0 + norm_res_0 = norm(Res_gl); + end + norm_res = norm(Res_gl); + + + if norm_res/norm_res_0 < tol_rel_res + disp(strcat('iteration n°=',num2str(iter))) + disp(strcat('norm (abs) residual=',num2str(norm_res))) + break + end + if norm_res0 + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + + for iref = nmnn_sides + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside ) ; + msh_side_int = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside ) ; + + sp_side = space.sp_patch{iptc}.constructor (msh_side_int); + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = lambda (x{:}); + tmp = op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); + + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + A(Cpatch_cols,Cpatch_cols) = ... + A(Cpatch_cols,Cpatch_cols) + Cpatch.' * tmp * Cpatch; + + end + end + +else + A = []; +end + + +end + +%-------------------------------------------------------------------------- +% Operator grav_n_laplaceu +%-------------------------------------------------------------------------- + +function varargout = op_gradv_n_laplaceu (spu, spv, msh, coeff) + + gradv = reshape (spv.shape_function_gradients, spv.ncomp, [], ... + msh.nqn, spv.nsh_max, msh.nel); + + ndim = size (gradv, 2); + + shpu = reshape (spu.shape_function_laplacians, spu.ncomp, msh.nqn, spu.nsh_max, msh.nel); + + rows = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + cols = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + values = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); + + jacdet_weights = msh.jacdet .* msh.quad_weights .* coeff; + + ncounter = 0; + for iel = 1:msh.nel + if (all (msh.jacdet(:,iel))) + gradv_iel = gradv(:,:,:,:,iel); + normal_iel = reshape (msh.normal(:,:,iel), [1, ndim, msh.nqn]); + + gradv_n = reshape (sum (bsxfun (@times, gradv_iel, normal_iel), 2), spv.ncomp, msh.nqn, spv.nsh_max, 1); + shpu_iel = reshape (shpu(:, :, :, iel), spu.ncomp, msh.nqn, 1, spu.nsh_max); + + jacdet_iel = reshape (jacdet_weights(:,iel), [1,msh.nqn,1,1]); + + gradv_n_times_jw = bsxfun (@times, jacdet_iel, gradv_n); + tmp1 = sum (bsxfun (@times, gradv_n_times_jw, shpu_iel), 1); + elementary_values = reshape (sum (tmp1, 2), spv.nsh_max, spu.nsh_max); + + [rows_loc, cols_loc] = ndgrid (spv.connectivity(:,iel), spu.connectivity(:,iel)); + indices = rows_loc & cols_loc; + rows(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = rows_loc(indices); + cols(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = cols_loc(indices); + values(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = elementary_values(indices); + ncounter = ncounter + spu.nsh(iel)*spv.nsh(iel); + + else + warning ('geopdes:jacdet_zero_at_quad_node', 'op_gradv_n_u: singular map in element number %d', iel) + end + end + + + if (nargout == 1 || nargout == 0) + varargout{1} = sparse (rows, cols, values, spv.ndof, spu.ndof); + elseif (nargout == 3) + varargout{1} = rows; + varargout{2} = cols; + varargout{3} = values; + else + error ('op_gradv_n_u: wrong number of output arguments') + end + + +end + +%-------------------------------------------------------------------------- +% penalty term +%-------------------------------------------------------------------------- + +function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) + + P = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros(space.ndof,1); + + for iref = nmnn_sides + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', false, 'gradient', true); + + coe_side = pen .* msh_side.charlen; + tmp = op_gradu_n_gradv_n(sp_bnd, sp_bnd, msh_side, coe_side); + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... + Cpatch.' * (tmp) * Cpatch; + + + %rhs = rhs + rhs_pen; + + end + end + +end + + +% function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) +% +% msh_side = msh_eval_boundary_side (msh, i_side ) ; +% msh_side_int = msh_boundary_side_from_interior (msh, i_side ) ; +% sp_side = space.constructor ( msh_side_int) ; +% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient', true ); +% +% +% coe_side = pen .* msh_side.charlen; +% mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); +% +% +% rhs_pen = zeros(space.ndof,1); % no flux +% +% end + +%-------------------------------------------------------------------------- +% check flux through the boundaries +%-------------------------------------------------------------------------- + +% function flux = check_flux_phase_field(space, msh, uhat, uhat0) +% +% sides = [1,2,3,4]; % all the boundaries +% flux = 0; +% +% for iside=1:length(sides) +% +% msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; +% msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; +% sp_side = space.constructor ( msh_side_int) ; +% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); +% +% +% gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); +% +% +% +% valu = zeros(sp_side.ncomp, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); +% for idim = 1:msh.rdim +% valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); +% end +% +% +% w =msh_side.quad_weights .* msh_side.jacdet; +% err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); +% err = sum (err_elem); +% +% +% flux = flux + err; +% +% end +% +% +% +% end + From 4775cd6747550b8ae1956c1b287da0036223ee0d Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 14:59:09 +0200 Subject: [PATCH 272/366] Fixed bug for C1 multipatch --- geopdes/inst/space/sp_scalar2vector_param.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/space/sp_scalar2vector_param.m b/geopdes/inst/space/sp_scalar2vector_param.m index d1c7a9a5..b6973d4e 100644 --- a/geopdes/inst/space/sp_scalar2vector_param.m +++ b/geopdes/inst/space/sp_scalar2vector_param.m @@ -64,7 +64,9 @@ space_vec.nsh_max = ncomp * space.nsh_max; space_vec.nsh = ncomp * space.nsh; space_vec.ndof = ncomp * space.ndof; - space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + if (isfield (space, 'ndof_dir')) + space_vec.ndof_dir = repmat (space.ndof_dir, ncomp, 1); + end space_vec.ncomp = ncomp; space_vec.connectivity = []; From 94f802e3688ae4cebf27dbf783197715071ceab1 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 15:00:22 +0200 Subject: [PATCH 273/366] Working for vector-valued space --- .../@sp_multipatch_C1/sp_l2_error.m | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m index 4c95cbe8..e826b89a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -35,14 +35,22 @@ error ('The number of patches does not coincide') end + error_l2 = zeros (msh.npatch, 1); for iptc = 1:msh.npatch -% if (isempty (space.dofs_ornt)) - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - u_ptc = Cpatch * u(Cpatch_cols); -% else -% u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; -% end - error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); + if (space.ndof == numel(u)) + % if (isempty (space.dofs_ornt)) + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); + % else + % u_ptc = u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.'; + % end + error_l2(iptc) = sp_l2_error (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, uex); + else + [Cpatch, Cpatch_cols] = sp_compute_Cpatch_vector (space, iptc, msh.rdim); + u_ptc = Cpatch * u(Cpatch_cols); + sp_vec = sp_vector (repmat (space.sp_patch(iptc), msh.rdim, 1), msh.msh_patch{iptc}); + error_l2(iptc) = sp_l2_error (sp_vec, msh.msh_patch{iptc}, u_ptc, uex); + end end errl2 = sqrt (sum (error_l2 .* error_l2)); From 767f233c0f7bd07521803f91798599aa0c87633d Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 15:04:33 +0200 Subject: [PATCH 274/366] Added computation of normals --- .../@msh_multipatch/msh_evaluate_element_list.m | 9 +++++++-- geopdes/inst/multipatch/msh_restrict_to_patches.m | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@msh_multipatch/msh_evaluate_element_list.m b/geopdes/inst/multipatch/@msh_multipatch/msh_evaluate_element_list.m index b4bcbf8c..0e5aa0a7 100644 --- a/geopdes/inst/multipatch/@msh_multipatch/msh_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@msh_multipatch/msh_evaluate_element_list.m @@ -54,8 +54,13 @@ if (isempty (elem_list)), return, end - fields = {'quad_weights', 'geo_map', 'geo_map_jac', 'geo_map_der2', 'jacdet', 'element_size'}; - cat_position = [2 3 4 5 2 2]; + if (msh.ndim == 2 && msh.rdim == 3) + fields = {'quad_weights', 'geo_map', 'geo_map_jac', 'geo_map_der2', 'jacdet', 'element_size', 'normal'}; + cat_position = [2 3 4 5 2 2 3]; + else + fields = {'quad_weights', 'geo_map', 'geo_map_jac', 'geo_map_der2', 'jacdet', 'element_size'}; + cat_position = [2 3 4 5 2 2]; + end for ii = 1:numel (fields) msh_col.(fields{ii}) = []; end diff --git a/geopdes/inst/multipatch/msh_restrict_to_patches.m b/geopdes/inst/multipatch/msh_restrict_to_patches.m index 8650bd32..82392cd7 100644 --- a/geopdes/inst/multipatch/msh_restrict_to_patches.m +++ b/geopdes/inst/multipatch/msh_restrict_to_patches.m @@ -83,5 +83,8 @@ msh_col.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); msh_col.jacdet = msh.jacdet(:,global_elem_list); msh_col.element_size = msh.element_size(:,global_elem_list); + if (isfield (msh, 'normal')) + msh_col.normal = msh.normal(:,:,global_elem_list); + end end \ No newline at end of file From effa7761c6ab99a4f1acb2decf35ab6996724242 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 15:08:41 +0200 Subject: [PATCH 275/366] Added file, without help --- .../sp_evaluate_element_list_param__.m | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m new file mode 100644 index 00000000..d372b053 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m @@ -0,0 +1,195 @@ +% SP_EVALUATE_ELEMENT_LIST_PARAM__: compute the basis functions in a given +% list of elements, in the parametric domain. To be used with care: the +% parametric domain does not have an intuitive meaning in the multipatch case. +% +% sp = sp_evaluate_element_list_param__ (space, msh_elems, 'option1', value1, ...) +% +% INPUT: +% +% space: object defining the space of discrete functions (see sp_multipatch_C1) +% msh_elems: structure containing the information of quadrature or +% visualization points, for a given list of elements and patches +% (see msh_multipatch/msh_evaluate_element_list) +% 'option', value: additional optional parameters, currently available options are: +% +% Name | Default value | Meaning +% ------------+-----------------+---------------------------------- +% value | true | compute shape_functions +% gradient | false | compute shape_function_gradients +% hessian | false | compute shape_function_hessians (only scalars) +% laplacian | false | compute shape_function_laplacians (only scalars) +% +% OUTPUT: +% +% sp: struct representing the discrete function space, with the following fields: +% +% FIELD_NAME (SIZE) DESCRIPTION +% npatch (scalar) number of patches +% ncomp (scalar) number of components of the functions of the space +% ndof (scalar) total number of degrees of freedom +% nsh (1 x nel) number of non-vanishing functions on each element +% nsh_max (scalar) maximum number of nsh +% connectivity (nsh_max x nel) global numbering of the non-vanishing functions on each element +% shape_functions, shape_function_gradients... (see sp_evaluate_col for details) +% +% Copyright (C) 2015, 2017, 2022, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function sp = sp_evaluate_element_list_param__ (space, msh, varargin) + + is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); + + sp.npatch = space.npatch; + sp.ncomp = space.ncomp; + sp.ndof = space.ndof; + + if (isempty (msh.elem_list)), return, end + + sp.nsh_max = []; + if (is_scalar) + fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', 'shape_function_laplacians'}; + cat_position = [2, 2, 3, 4, 5, 3]; +% else +% fields = {'nsh', 'connectivity', 'shape_functions', 'shape_function_gradients', 'shape_function_hessians', ... +% 'shape_function_laplacians', 'shape_function_divs', 'shape_function_curls'}; +% if (msh.ndim == 2 || msh.ndim == 1) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 3]; +% elseif (msh.ndim == 3) +% cat_position = [2, 2, 4, 5, 6, 4, 3, 4]; +% end + end + for ii = 1:numel(fields) + sp.(fields{ii}) = []; + end + + for iptc = 1:space.npatch +% msh_patch = msh_evaluate_element_list (msh.msh_patch{iptc}, msh.elem_list_of_patch{iptc}); % Not working anymore + msh_patch = msh_restrict_to_patch (msh, iptc); + + sp_patch = sp_evaluate_element_list_param (space.sp_patch{iptc}, msh_patch, varargin{:}); + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + + nsh = zeros (1, msh_patch.nel); + connectivity = zeros (sp_patch.nsh_max, msh_patch.nel); + shape_funs = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_grads = zeros (msh.ndim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_hess = zeros (msh.ndim, msh.ndim, msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + shape_fun_lapl = zeros (msh_patch.nqn, sp_patch.nsh_max, msh_patch.nel); + + for iel = 1:msh_patch.nel + conn_iel = sp_patch.connectivity(:,iel); + [~,jj] = find (Cpatch(conn_iel,:)); + col_indices = unique(jj); + funs = Cpatch_cols(col_indices); + nsh(iel) = numel (funs); + connectivity(1:nsh(iel),iel) = funs; + Cpatch_iel = Cpatch(conn_iel, col_indices); + + if (isfield (sp_patch, 'shape_functions')) + shape_funs(:,1:nsh(iel),iel) = sp_patch.shape_functions(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_gradients')) + for idim = 1:msh.ndim + shape_fun_grads(idim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_gradients(idim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + if (isfield (sp_patch, 'shape_function_laplacians')) + shape_fun_lapl(:,1:nsh(iel),iel) = sp_patch.shape_function_laplacians(:,:,iel) * Cpatch_iel; + end + if (isfield (sp_patch, 'shape_function_hessians')) + for idim = 1:msh.ndim + for jdim = 1:msh.ndim + shape_fun_hess(idim,jdim,:,1:nsh(iel),iel) = ... + reshape (sp_patch.shape_function_hessians(idim,jdim,:,:,iel), msh_patch.nqn, sp_patch.nsh_max) * Cpatch_iel; + end + end + end + end + + nsh_max = max(sp.nsh); nsh_max_patch = max(nsh); + sp.nsh = cat (2, sp.nsh, nsh); + if (msh_patch.nel > 0) + if (nsh_max > nsh_max_patch) + connectivity(nsh_max_patch+1:nsh_max,:) = 0; + if (isfield (sp_patch, 'shape_functions')); shape_funs(:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_gradients')); shape_fun_grads(:,:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_hessians')); shape_fun_hess(:,:,:,nsh_max_patch+1:nsh_max,:) = 0; end + if (isfield (sp_patch, 'shape_function_laplacians')); shape_fun_lapl(:,nsh_max_patch+1:nsh_max,:) = 0; end + elseif (nsh_max_patch > nsh_max) + sp.connectivity(nsh_max+1:nsh_max_patch,:) = 0; + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions(:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients(:,:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians(:,:,:,nsh_max+1:nsh_max_patch,:) = 0; end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians(:,nsh_max+1:nsh_max_patch,:) = 0; end + end + sp.connectivity = cat (2, sp.connectivity, connectivity); + if (isfield (sp_patch, 'shape_functions')); sp.shape_functions = cat (3, sp.shape_functions, shape_funs); end + if (isfield (sp_patch, 'shape_function_gradients')); sp.shape_function_gradients = cat (4, sp.shape_function_gradients, shape_fun_grads); end + if (isfield (sp_patch, 'shape_function_hessians')); sp.shape_function_hessians = cat (5, sp.shape_function_hessians, shape_fun_hess); end + if (isfield (sp_patch, 'shape_function_laplacians')); sp.shape_function_laplacians = cat (3, sp.shape_function_laplacians, shape_fun_lapl); end + end + +% for ii = 1:numel(fields) +% if (isfield (sp_patch, fields{ii})) +% sp.(fields{ii}) = cat (cat_position(ii), sp.(fields{ii}), sp_patch.(fields{ii})); +% end +% end + end + sp.nsh_max = max (sp.nsh); + + for ii = 1:numel(fields) + if (isempty (sp.(fields{ii}))) + sp = rmfield (sp, fields{ii}); + elseif (ii > 1) + field_size = size (sp.(fields{ii})); + inds = repmat ({':'}, 1, numel(field_size)); + inds{cat_position(ii)-1} = 1:sp.nsh_max; + sp.(fields{ii}) = sp.(fields{ii})(inds{:}); + end + end + +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% MSH_RESTRICT_TO_PATCH: extracts the fields corresponding to the selected elements of a given patch, +% from the ones of a mesh struct, computed with msh_multipatch/msh_evaluate_element_list. +% The result is the same as calling msh_cartesian/msh_evaluate_element_list, but avoids recomputing. +% +function msh_ptc = msh_restrict_to_patch (msh, patch) + + msh_ptc.ndim = msh.ndim; + msh_ptc.rdim = msh.rdim; + msh_ptc.elem_list = msh.elem_list_of_patch{patch}(:).'; + + msh_ptc.nel = msh.nel_per_patch(patch); + msh_ptc.nel_dir = msh.nel_dir_of_patch{patch}; + msh_ptc.nqn = msh.nqn; + msh_ptc.nqn_dir = msh.nqn_dir; + + if (isempty (msh_ptc.elem_list)), return, end + + Nelem = cumsum ([0, msh.nel_per_patch]); + + global_elem_list = Nelem(patch)+1:Nelem(patch+1); + msh_ptc.quad_weights = msh.quad_weights(:,global_elem_list); + msh_ptc.geo_map = msh.geo_map(:,:,global_elem_list); + msh_ptc.geo_map_jac = msh.geo_map_jac(:,:,:,global_elem_list); + msh_ptc.geo_map_der2 = msh.geo_map_der2(:,:,:,:,global_elem_list); + msh_ptc.jacdet = msh.jacdet(:,global_elem_list); + msh_ptc.element_size = msh.element_size(:,global_elem_list); + +end \ No newline at end of file From ce0154d22cdc6e5e431f01b93560725128175076 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 15:21:09 +0200 Subject: [PATCH 276/366] Change in the help --- .../multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m index fb748e6c..3c8127e4 100644 --- a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m +++ b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m @@ -1,4 +1,4 @@ -% SOLVE_KIRCHHOFF_LOVE_SHELL_C1_SCALARSPACE: Solve the Kirchhoff-Love shell model in a NURBS domain. +% MP_SOLVE_KIRCHHOFF_LOVE_SHELL_C1_SCALARSPACE: Solve the Kirchhoff-Love shell model in a NURBS domain. % It uses an object space of type sp_multipatch_C1 with scalar values, instead of vector valued. % % USAGE: @@ -144,7 +144,7 @@ % We assemble the (pieces of the) stiffness matrix, the rhs (and its correction taking % into account the Dirichlet conditions), and the basis change matrix (we will need it -% to go from the basis with kernel vectors obtained when examnining the dirichlet conditions +% to go from the basis with kernel vectors obtained when examining the Dirichlet conditions % to the usual basis) vertex_dofs = kernel_dofs.all_vertex_dofs; vertex_dofs = [vertex_dofs, space.ndof+vertex_dofs, 2*space.ndof+vertex_dofs]; From f199ce2fb6dad662eeaa381041015c49faad26c2 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 16:12:34 +0200 Subject: [PATCH 277/366] Small change in the help --- .../@sp_multipatch_C1/sp_evaluate_element_list_param__.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m index d372b053..28a99ecb 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list_param__.m @@ -16,8 +16,8 @@ % ------------+-----------------+---------------------------------- % value | true | compute shape_functions % gradient | false | compute shape_function_gradients -% hessian | false | compute shape_function_hessians (only scalars) -% laplacian | false | compute shape_function_laplacians (only scalars) +% hessian | false | compute shape_function_hessians +% laplacian | false | compute shape_function_laplacians % % OUTPUT: % From 550c21a1ef2459e39cc27f7677a96fedca60bdfd Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 17:06:21 +0200 Subject: [PATCH 278/366] Some cleaning --- .../cahn-hilliard/ex_cahn_hilliard_mpC1.m | 4 +- geopdes/inst/solve/solve_cahn_hilliard.m | 4 +- geopdes/inst/solve/solve_cahn_hilliard_mpC1.m | 174 ++++-------------- 3 files changed, 41 insertions(+), 141 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index 46d32d83..055bead6 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -21,8 +21,8 @@ % Penalty parameters -problem_data.pen_nitsche = 1e4 * lambda; % Nitsche's method parameter -problem_data.pen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) +problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter +problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) % 2) INITIAL CONDITIONS mean = 0.0; diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 453bda04..e4982b05 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -149,7 +149,7 @@ end if (exist('fun_udot', 'var') && ~isempty(fun_udot)) - rhs = op_f_v_tp(space, msh, fun_udot); + rhs = op_f_v_tp (space, msh, fun_udot); udot_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; else udot_n = zeros(space.ndof, 1); @@ -344,7 +344,7 @@ for idim = 1:msh.ndim coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); end - B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv)'; + B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv).'; end end diff --git a/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m b/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m index 78dd9d93..69733c48 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m +++ b/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m @@ -1,10 +1,10 @@ -% SOLVE_CAHN_HILLIARD: solve the Cahn-Hilliard equation, with a generalized alpha discretization in time. +% SOLVE_CAHN_HILLIARD_MP_C1: solve the Cahn-Hilliard equation, with C^1 multipatch splines, and a generalized alpha discretization in time. % % The functions solves the problem of finding u such that % % du/dt - Delta (mu(u) - lambda*Delta u) = 0 % -% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic boundary conditions. +% with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and Neumann boundary conditions. % % The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. % @@ -14,7 +14,7 @@ % % USAGE: % -% [geometry, msh, space, results] = solve_cahn_hilliard (problem_data, method_data, save_info) +% [geometry, msh, space, results] = solve_cahn_hilliard_mp_C1 (problem_data, method_data, save_info) % % INPUT: % @@ -29,7 +29,7 @@ % % method_data : a structure with discretization data. Its fields are: % - degree: degree of the spline functions. -% - regularity: continuity of the spline functions. +% - regularity: continuity of the spline functions (at most degree minus two). % - nsub: number of subelements with respect to the geometry mesh % (nsub=1 leaves the mesh unchanged) % - nquad: number of points for Gaussian quadrature rule @@ -78,11 +78,6 @@ end %%------------------------------------------------------------------------- -% Construct geometry structure - - - - % Construct geometry structure, and information for interfaces and boundaries [geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); npatch = numel (geometry); @@ -90,7 +85,6 @@ msh = cell (1, npatch); sp = cell (1, npatch); for iptc = 1:npatch - % Define the refined mesh, with tensor product structure [knots{iptc}, zeta{iptc}] = ... kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); @@ -106,28 +100,9 @@ [edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); msh = msh_multipatch (msh, boundaries); -% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); clear sp -% % Compute and assemble the matrices -% c_diff = @(x, y) ones(size(x)); -% stiff_mat = op_gradu_gradv_mp (space, space, msh, c_diff); -% f = @(x, y) ones(size(x)); -% rhs = op_f_v_mp (space, msh, f); -% drchlt_dofs = 1:10; -% int_dofs = setdiff (1:space.ndof, drchlt_dofs); -% % Solve the linear system -% u(int_dofs) = stiff_mat(int_dofs, int_dofs) \ rhs(int_dofs); -% output_file = 'Lshaped_mp_BSP_Deg3_Reg2_Sub9'; -% vtk_pts = {linspace(0, 1, 20), linspace(0, 1, 20)}; -% fprintf ('The result is saved in the file %s.pvd \n \n', output_file); -% sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'u') -% figure -% sp_plot_solution (u, space, geometry, vtk_pts) -% return - - %%------------------------------------------------------------------------- % Generalized alpha parameters a_m = .5*((3-rho_inf_gen_alpha)/(1+rho_inf_gen_alpha)); @@ -143,13 +118,13 @@ % Precompute matrices % Compute the mass matrix -mass_mat = op_u_v_mp(space,space,msh); +mass_mat = op_u_v_mp (space,space,msh); % Compute the laplace matrix lapl_mat = op_laplaceu_laplacev_mp (space, space, msh, lambda); % Compute the boundary term -term4 = int_term_4 (space, msh, lambda, nmnn_bou); +bnd_mat = int_boundary_term (space, msh, lambda, nmnn_bou); % Compute the penalty matrix [Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_bou, pen_nitsche); @@ -160,14 +135,14 @@ time = 0; if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_mp (space, msh, fun_u); - u_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; + u_n = (mass_mat + Cpen_projection/pen_nitsche * Pen)\rhs; else u_n = zeros(space.ndof, 1); end if (exist('fun_udot', 'var') && ~isempty(fun_udot)) - rhs = op_f_v_mp(space, msh, fun_udot); - udot_n = (mass_mat + pen_projection/pen_nitsche * Pen)\rhs; + rhs = op_f_v_mp (space, msh, fun_udot); + udot_n = (mass_mat + Cpen_projection/pen_nitsche * Pen)\rhs; else udot_n = zeros(space.ndof, 1); end @@ -195,7 +170,7 @@ disp(strcat('time step t=',num2str(time))) [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); % check flux through the boundary % flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); @@ -246,7 +221,7 @@ %-------------------------------------------------------------------------- function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, space, msh) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) % Convergence criteria n_max_iter = 20; @@ -266,8 +241,7 @@ % Compute the residual (internal) [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, ... - u_a, udot_a); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a); % Convergence check if iter == 0 @@ -297,7 +271,7 @@ udot_n1 = udot_n1 + d_udot; u_n1 = u_n1 + gamma * dt* d_udot; -end + end end @@ -306,23 +280,22 @@ %-------------------------------------------------------------------------- function [Res_gl, stiff_mat] = Res_K_cahn_hilliard(space, msh, ... - mass_mat, lapl_mat, term4, Pen, pen_rhs, ... - u_a, udot_a) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a) - % Double well (matrices) - [term2, term2K] = op_gradmu_gradv_mp(space, msh, u_a); + % Double well (matrices) + [term2, term2K] = op_gradmu_gradv_mp(space, msh, u_a); - % Residual - Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; + % Residual + Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; - % Tangent stiffness matrix (mass is not considered here) - stiff_mat = term2 + term2K + lapl_mat; + % Tangent stiffness matrix (mass is not considered here) + stiff_mat = term2 + term2K + lapl_mat; - % in case of neumann BC, add boundary terms - if isempty(term4) == 0 - Res_gl = Res_gl - (term4 + term4') * u_a + Pen*u_a - pen_rhs; - stiff_mat = stiff_mat - (term4 + term4') + Pen; - end + % in case of neumann BC, add boundary terms + if (~isempty(bnd_mat)) + Res_gl = Res_gl - (bnd_mat + bnd_mat.') * u_a + Pen*u_a - pen_rhs; + stiff_mat = stiff_mat - (bnd_mat + bnd_mat.') + Pen; + end end %-------------------------------------------------------------------------- @@ -331,22 +304,15 @@ function [A, B] = op_gradmu_gradv_mp (space, msh, uhat) - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); B = spalloc (space.ndof, space.ndof, 6*space.ndof); - - for iptc = 1:msh.npatch [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (space, iptc); u_ptc = Cpatch_u * uhat(Cpatch_cols_u); - [Ap, Bp] = op_gradmu_gradv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc ); - - A(Cpatch_cols_u,Cpatch_cols_u) = ... A(Cpatch_cols_u,Cpatch_cols_u) + Cpatch_u.' * Ap * Cpatch_u; @@ -384,7 +350,7 @@ for idim = 1:msh.ndim coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); end - B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv)'; + B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv).'; end end @@ -392,17 +358,17 @@ %-------------------------------------------------------------------------- -% term 4, boundary term +% Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) %-------------------------------------------------------------------------- -function [A] = int_term_4 (space, msh, lambda, nmnn_sides) +function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) - if length(nmnn_sides)>0 + if (~isempty(nmnn_sides)) A = spalloc (space.ndof, space.ndof, 3*space.ndof); for iref = nmnn_sides - for bnd_side = 1:msh.boundaries(iref).nsides + for bnd_side = 1:msh.boundaries(iref).nsides iptc = msh.boundaries(iref).patches(bnd_side); iside = msh.boundaries(iref).faces(bnd_side); @@ -413,84 +379,20 @@ sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); for idim = 1:msh.rdim - x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); end coe_side = lambda (x{:}); tmp = op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); A(Cpatch_cols,Cpatch_cols) = ... A(Cpatch_cols,Cpatch_cols) + Cpatch.' * tmp * Cpatch; - - end + end end -else - A = []; -end - - -end - -%-------------------------------------------------------------------------- -% Operator grav_n_laplaceu -%-------------------------------------------------------------------------- - -function varargout = op_gradv_n_laplaceu (spu, spv, msh, coeff) - - gradv = reshape (spv.shape_function_gradients, spv.ncomp, [], ... - msh.nqn, spv.nsh_max, msh.nel); - - ndim = size (gradv, 2); - - shpu = reshape (spu.shape_function_laplacians, spu.ncomp, msh.nqn, spu.nsh_max, msh.nel); - - rows = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - cols = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - values = zeros (msh.nel * spu.nsh_max * spv.nsh_max, 1); - - jacdet_weights = msh.jacdet .* msh.quad_weights .* coeff; - - ncounter = 0; - for iel = 1:msh.nel - if (all (msh.jacdet(:,iel))) - gradv_iel = gradv(:,:,:,:,iel); - normal_iel = reshape (msh.normal(:,:,iel), [1, ndim, msh.nqn]); - - gradv_n = reshape (sum (bsxfun (@times, gradv_iel, normal_iel), 2), spv.ncomp, msh.nqn, spv.nsh_max, 1); - shpu_iel = reshape (shpu(:, :, :, iel), spu.ncomp, msh.nqn, 1, spu.nsh_max); - - jacdet_iel = reshape (jacdet_weights(:,iel), [1,msh.nqn,1,1]); - - gradv_n_times_jw = bsxfun (@times, jacdet_iel, gradv_n); - tmp1 = sum (bsxfun (@times, gradv_n_times_jw, shpu_iel), 1); - elementary_values = reshape (sum (tmp1, 2), spv.nsh_max, spu.nsh_max); - - [rows_loc, cols_loc] = ndgrid (spv.connectivity(:,iel), spu.connectivity(:,iel)); - indices = rows_loc & cols_loc; - rows(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = rows_loc(indices); - cols(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = cols_loc(indices); - values(ncounter+(1:spu.nsh(iel)*spv.nsh(iel))) = elementary_values(indices); - ncounter = ncounter + spu.nsh(iel)*spv.nsh(iel); - - else - warning ('geopdes:jacdet_zero_at_quad_node', 'op_gradv_n_u: singular map in element number %d', iel) - end - end - - - if (nargout == 1 || nargout == 0) - varargout{1} = sparse (rows, cols, values, spv.ndof, spu.ndof); - elseif (nargout == 3) - varargout{1} = rows; - varargout{2} = cols; - varargout{3} = values; else - error ('op_gradv_n_u: wrong number of output arguments') + A = []; end - - end %-------------------------------------------------------------------------- @@ -499,10 +401,10 @@ function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) - P = spalloc (space.ndof, space.ndof, 3*space.ndof); - rhs = zeros(space.ndof,1); + P = spalloc (space.ndof, space.ndof, 3*space.ndof); + rhs = zeros(space.ndof,1); - for iref = nmnn_sides + for iref = nmnn_sides for bnd_side = 1:msh.boundaries(iref).nsides iptc = msh.boundaries(iref).patches(bnd_side); iside = msh.boundaries(iref).faces(bnd_side); @@ -520,11 +422,9 @@ P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... Cpatch.' * (tmp) * Cpatch; - %rhs = rhs + rhs_pen; - - end end + end end From 08a462b7ab30bab4b3d679cd184f5e21610e3581 Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 17:13:44 +0200 Subject: [PATCH 279/366] Changed function name --- geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m | 2 +- .../mp_solve_cahn_hilliard_C1.m} | 6 +++--- geopdes/inst/multipatch/mp_solve_laplace_C1.m | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) rename geopdes/inst/{solve/solve_cahn_hilliard_mpC1.m => multipatch/mp_solve_cahn_hilliard_C1.m} (98%) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index 055bead6..fb0567c1 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -47,7 +47,7 @@ % 4) CALL TO THE SOLVER -[geometry, msh, space, results] = solve_cahn_hilliard_mpC1 (problem_data, method_data, time_step_save); +[geometry, msh, space, results] = mp_solve_cahn_hilliard_C1 (problem_data, method_data, time_step_save); % 5) POST-PROCESSING diff --git a/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m similarity index 98% rename from geopdes/inst/solve/solve_cahn_hilliard_mpC1.m rename to geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 69733c48..6f272394 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard_mpC1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -1,4 +1,4 @@ -% SOLVE_CAHN_HILLIARD_MP_C1: solve the Cahn-Hilliard equation, with C^1 multipatch splines, and a generalized alpha discretization in time. +% MP_SOLVE_CAHN_HILLIARD_C1: solve the Cahn-Hilliard equation, with C^1 multipatch splines, and a generalized alpha discretization in time. % % The functions solves the problem of finding u such that % @@ -14,7 +14,7 @@ % % USAGE: % -% [geometry, msh, space, results] = solve_cahn_hilliard_mp_C1 (problem_data, method_data, save_info) +% [geometry, msh, space, results] = mp_solve_cahn_hilliard_C1 (problem_data, method_data, save_info) % % INPUT: % @@ -64,7 +64,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function [geometry, msh, space, results] = solve_cahn_hilliard_mpC1 (problem_data, method_data, save_info) +function [geometry, msh, space, results] = mp_solve_cahn_hilliard_C1 (problem_data, method_data, save_info) %%------------------------------------------------------------------------- % Extract the fields from the data structures into local variables diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index ddc79aae..1ca962b4 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -74,7 +74,6 @@ msh = cell (1, npatch); sp = cell (1, npatch); for iptc = 1:npatch - % Define the refined mesh, with tensor product structure [knots{iptc}, zeta{iptc}] = ... kntrefine (geometry(iptc).nurbs.knots, nsub-1, degree, regularity); @@ -90,7 +89,6 @@ [edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces); msh = msh_multipatch (msh, boundaries); -% space = sp_multipatch (sp, msh, interfaces, boundary_interfaces); space = sp_multipatch_C1 (sp, msh, geometry, edges, vertices); clear sp From 38db0512d5c01f9aa033d7e405186c146b153ebc Mon Sep 17 00:00:00 2001 From: vazquez Date: Thu, 11 May 2023 17:47:59 +0200 Subject: [PATCH 280/366] New operator for nonlinear terms --- .../space/@sp_scalar/op_gradfu_gradv_tp.m | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m diff --git a/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m b/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m new file mode 100644 index 00000000..69a62c1c --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m @@ -0,0 +1,70 @@ +% OP_GRADFU_GRADV_TP: assemble the matrix A = [a(i,j)], a(i,j) = (grad (F(w) u_j), grad v_i) = +% = (F(w) grad u_j, grad v_i) + (u_j grad (F(w)), grad v_i), +% exploiting the tensor product structure, with "F" a given function +% (derivative also needed), and "w" a discrete solution defined on the +% same space. Useful to have nonlinear terms. +% +% [mat1, mat2] = op_gradfu_gradv_tp (space, msh, uhat, f, df); +% +% INPUT: +% +% space: object representing the space of trial and test functions (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% uhat: degrees of freedom of "w", of size space.ndof x 1. +% f: function handle to compute F(w). +% dF: function handle to compute dF(w). +% +% OUTPUT: +% +% mat1: assembled matrix for (F(w) grad u_j, grad v_i) +% mat2: assembled matrix for (u_j grad (F(w)), grad v_i) +% +% Copyright (C) 2011, Carlo de Falco, Rafael Vazquez +% Copyright (C) 2016, 2017, Rafael Vazquez +% Copyright (C) 2023, Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A, B] = op_gradfu_gradv_tp (space, msh, uhat, f, df) + + for idim = 1:msh.ndim + size1 = size (space.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + B = spalloc (space.ndof, space.ndof, 6*space.ndof); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'gradient', true); + + % Evaluate the field and its gradient at the Gaussian points + utemp = sp_eval_msh (uhat, sp_col, msh_col, {'value', 'gradient'}); + u = utemp{1}; + gradu = utemp{2}; + + % Polynomial formulation for the double-well + coeffs_A = f(u); + A = A + op_gradu_gradv (sp_col, sp_col, msh_col, coeffs_A); + + coeffs_B = df(u); + coeffs_Bv = gradu; + for idim = 1:msh.ndim + coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); + end + B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv).'; + end From 8d4ba9778ef12921e5b287158e3ab538bdc72a00 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 12 May 2023 11:55:07 +0200 Subject: [PATCH 281/366] Created new operator for multi-patch, and some cleaning --- .../@sp_multipatch_C1/op_gradfu_gradv_mp.m | 56 +++++++++++++ .../multipatch/mp_solve_cahn_hilliard_C1.m | 83 ++++--------------- geopdes/inst/solve/solve_cahn_hilliard.m | 60 +++----------- .../space/@sp_scalar/op_gradfu_gradv_tp.m | 18 ++-- 4 files changed, 94 insertions(+), 123 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_gradfu_gradv_mp.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradfu_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradfu_gradv_mp.m new file mode 100644 index 00000000..a0100878 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_gradfu_gradv_mp.m @@ -0,0 +1,56 @@ +% OP_GRADFU_GRADV_MP: assemble the matrix A = [a(i,j)], a(i,j) = (grad (f(w) u_j), grad v_i) = +% = (f(w) grad u_j, grad v_i) + (u_j grad (f(w)), grad v_i), +% for C^1 multipatch splines, with "f" a given function +% (derivative also needed), and "w" a discrete solution defined on the +% same space. Useful to compute nonlinear terms. +% +% [mat1, mat2] = op_gradfu_gradv_mp (space, msh, uhat, f, df, [patches]); +% +% INPUT: +% +% space: object representing the space of trial functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% uhat: degrees of freedom of "w", of size space.ndof x 1. +% f: function handle to compute f(w). +% df: function handle to compute df(w), the gradient of f. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% mat1: assembled matrix for (f(w) grad u_j, grad v_i) +% mat2: assembled matrix for (u_j grad (f(w)), grad v_i) +% +% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A, B] = op_gradfu_gradv_mp (space, msh, uhat, f, df) + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + B = spalloc (space.ndof, space.ndof, 6*space.ndof); + + for iptc = 1:msh.npatch + [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch_u * uhat(Cpatch_cols_u); + + [Ap, Bp] = op_gradfu_gradv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc, f, df); + + A(Cpatch_cols_u,Cpatch_cols_u) = ... + A(Cpatch_cols_u,Cpatch_cols_u) + Cpatch_u.' * Ap * Cpatch_u; + + B(Cpatch_cols_u,Cpatch_cols_u) = ... + B(Cpatch_cols_u,Cpatch_cols_u) + Cpatch_u.' * Bp * Cpatch_u; + end + +end diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 6f272394..11c19c39 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -77,6 +77,13 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end +%%------------------------------------------------------------------------- +% Parameters for the double-well function (to be given in problem_data) +alpha = 1; +beta = 1; +mu = @(x) 3 * alpha * x.^2 - beta; +dmu = @(x) 6 * alpha * x; + %%------------------------------------------------------------------------- % Construct geometry structure, and information for interfaces and boundaries [geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); @@ -127,7 +134,7 @@ bnd_mat = int_boundary_term (space, msh, lambda, nmnn_bou); % Compute the penalty matrix -[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_bou, pen_nitsche); +[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_bou, Cpen_nitsche); %%------------------------------------------------------------------------- @@ -135,14 +142,14 @@ time = 0; if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_mp (space, msh, fun_u); - u_n = (mass_mat + Cpen_projection/pen_nitsche * Pen)\rhs; + u_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; else u_n = zeros(space.ndof, 1); end if (exist('fun_udot', 'var') && ~isempty(fun_udot)) rhs = op_f_v_mp (space, msh, fun_udot); - udot_n = (mass_mat + Cpen_projection/pen_nitsche * Pen)\rhs; + udot_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; else udot_n = zeros(space.ndof, 1); end @@ -169,7 +176,7 @@ disp('----------------------------------------------------------------') disp(strcat('time step t=',num2str(time))) - [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); % check flux through the boundary @@ -220,7 +227,7 @@ % One step of generalized alpha-method %-------------------------------------------------------------------------- -function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) % Convergence criteria @@ -241,7 +248,8 @@ % Compute the residual (internal) [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... - mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, ... + u_a, udot_a, mu, dmu); % Convergence check if iter == 0 @@ -280,10 +288,10 @@ %-------------------------------------------------------------------------- function [Res_gl, stiff_mat] = Res_K_cahn_hilliard(space, msh, ... - mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a, mu, dmu) % Double well (matrices) - [term2, term2K] = op_gradmu_gradv_mp(space, msh, u_a); + [term2, term2K] = op_gradfu_gradv_mp (space, msh, u_a, mu, dmu); % Residual Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; @@ -298,65 +306,6 @@ end end -%-------------------------------------------------------------------------- -% Integral of the double-well function -%-------------------------------------------------------------------------- - -function [A, B] = op_gradmu_gradv_mp (space, msh, uhat) - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - B = spalloc (space.ndof, space.ndof, 6*space.ndof); - - for iptc = 1:msh.npatch - [Cpatch_u, Cpatch_cols_u] = sp_compute_Cpatch (space, iptc); - u_ptc = Cpatch_u * uhat(Cpatch_cols_u); - - [Ap, Bp] = op_gradmu_gradv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, u_ptc ); - - A(Cpatch_cols_u,Cpatch_cols_u) = ... - A(Cpatch_cols_u,Cpatch_cols_u) + Cpatch_u.' * Ap * Cpatch_u; - - B(Cpatch_cols_u,Cpatch_cols_u) = ... - B(Cpatch_cols_u,Cpatch_cols_u) + Cpatch_u.' * Bp * Cpatch_u; - end - - -end - - -function [A, B] = op_gradmu_gradv_tp (space, msh, uhat) - -% Coefficients of the double well function. - alpha = 1; - beta = 1; - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - B = spalloc (space.ndof, space.ndof, 6*space.ndof); - - for iel = 1:msh.nel_dir(1) - msh_col = msh_evaluate_col (msh, iel); - sp_col = sp_evaluate_col (space, msh_col, 'gradient', true); - - % Evaluate the field and its gradient at the Gaussian points - utemp = sp_eval_msh (uhat, sp_col, msh_col, {'value', 'gradient'}); - u = utemp{1}; - gradu = utemp{2}; - - % Polynomial formulation for the double-well - coeffs_A = 3.* alpha .* u.^2 - beta; - A = A + op_gradu_gradv (sp_col, sp_col, msh_col, coeffs_A); - - coeffs_B = 6.* alpha .* u; - coeffs_Bv = gradu; - for idim = 1:msh.ndim - coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); - end - B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv).'; - end - -end - - - %-------------------------------------------------------------------------- % Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) %-------------------------------------------------------------------------- diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index e4982b05..242c4cca 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -79,6 +79,13 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end +%%------------------------------------------------------------------------- +% Parameters for the double-well function (to be given in problem_data) +alpha = 1; +beta = 1; +mu = @(x) 3 * alpha * x.^2 - beta; +dmu = @(x) 6 * alpha * x; + %%------------------------------------------------------------------------- % Construct geometry structure geometry = geo_load (geo_name); @@ -177,7 +184,7 @@ disp('----------------------------------------------------------------') disp(strcat('time step t=',num2str(time))) - [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... + [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); % check flux through the boundary @@ -228,7 +235,7 @@ % One step of generalized alpha-method %-------------------------------------------------------------------------- -function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, ... +function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) % Convergence criteria @@ -249,7 +256,8 @@ % Compute the residual (internal) [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... - mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a); + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, ... + u_a, udot_a, mu, dmu); % Convergence check if iter == 0 @@ -288,10 +296,10 @@ %-------------------------------------------------------------------------- function [Res_gl, stiff_mat] = Res_K_cahn_hilliard(space, msh, ... - mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a) + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a, mu, dmu) % Double well (matrices) - [term2, term2K] = op_gradmu_gradv_tp(space, msh, u_a); + [term2, term2K] = op_gradfu_gradv_tp(space, msh, u_a, mu, dmu); % Residual Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; @@ -306,48 +314,6 @@ end end -%-------------------------------------------------------------------------- -% Integral of the double-well function -%-------------------------------------------------------------------------- - -function [A, B] = op_gradmu_gradv_tp (space, msh, uhat) - -% Coefficients of the double well function. - alpha = 1; - beta = 1; - - for idim = 1:msh.ndim - size1 = size (space.sp_univ(idim).connectivity); - if (size1(2) ~= msh.nel_dir(idim)) - error ('The discrete space is not associated to the mesh') - end - end - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - B = spalloc (space.ndof, space.ndof, 6*space.ndof); - - for iel = 1:msh.nel_dir(1) - msh_col = msh_evaluate_col (msh, iel); - sp_col = sp_evaluate_col (space, msh_col, 'gradient', true); - - % Evaluate the field and its gradient at the Gaussian points - utemp = sp_eval_msh (uhat, sp_col, msh_col, {'value', 'gradient'}); - u = utemp{1}; - gradu = utemp{2}; - - % Polynomial formulation for the double-well - coeffs_A = 3.* alpha .* u.^2 - beta; - A = A + op_gradu_gradv (sp_col, sp_col, msh_col, coeffs_A); - - coeffs_B = 6.* alpha .* u; - coeffs_Bv = gradu; - for idim = 1:msh.ndim - coeffs_Bv(idim,:,:) = coeffs_Bv(idim,:,:) .* reshape(coeffs_B, 1, size(coeffs_B,1), size(coeffs_B,2)); - end - B = B + op_vel_dot_gradu_v (sp_col, sp_col, msh_col, coeffs_Bv).'; - end -end - %-------------------------------------------------------------------------- % Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) %-------------------------------------------------------------------------- diff --git a/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m b/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m index 69a62c1c..a10b0a2b 100644 --- a/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m +++ b/geopdes/inst/space/@sp_scalar/op_gradfu_gradv_tp.m @@ -1,8 +1,8 @@ -% OP_GRADFU_GRADV_TP: assemble the matrix A = [a(i,j)], a(i,j) = (grad (F(w) u_j), grad v_i) = -% = (F(w) grad u_j, grad v_i) + (u_j grad (F(w)), grad v_i), -% exploiting the tensor product structure, with "F" a given function +% OP_GRADFU_GRADV_TP: assemble the matrix A = [a(i,j)], a(i,j) = (grad (f(w) u_j), grad v_i) = +% = (f(w) grad u_j, grad v_i) + (u_j grad (f(w)), grad v_i), +% exploiting the tensor product structure, with "f" a given function % (derivative also needed), and "w" a discrete solution defined on the -% same space. Useful to have nonlinear terms. +% same space. Useful to compute nonlinear terms. % % [mat1, mat2] = op_gradfu_gradv_tp (space, msh, uhat, f, df); % @@ -11,14 +11,14 @@ % space: object representing the space of trial and test functions (see sp_scalar) % msh: object defining the domain partition and the quadrature rule (see msh_cartesian) % uhat: degrees of freedom of "w", of size space.ndof x 1. -% f: function handle to compute F(w). -% dF: function handle to compute dF(w). +% f: function handle to compute f(w). +% df: function handle to compute df(w), the gradient of f. % % OUTPUT: % -% mat1: assembled matrix for (F(w) grad u_j, grad v_i) -% mat2: assembled matrix for (u_j grad (F(w)), grad v_i) -% +% mat1: assembled matrix for (f(w) grad u_j, grad v_i) +% mat2: assembled matrix for (u_j grad (f(w)), grad v_i) +% % Copyright (C) 2011, Carlo de Falco, Rafael Vazquez % Copyright (C) 2016, 2017, Rafael Vazquez % Copyright (C) 2023, Michele Torre, Rafael Vazquez From 8dca4e831b668275c9d8e863d66e9f3819e89fc8 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 15 May 2023 14:34:26 +0200 Subject: [PATCH 282/366] Evaluate at points in the physical domain --- geopdes/inst/space/@sp_scalar/sp_eval_phys.m | 146 +++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 geopdes/inst/space/@sp_scalar/sp_eval_phys.m diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m new file mode 100644 index 00000000..3aa0ad02 --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m @@ -0,0 +1,146 @@ +% SP_EVAL_PHYS: Compute the value or derivatives of a function from its degrees of freedom, at a given set of points in the physical domain. +% +% eu = sp_eval_phys (u, space, geometry, pts, [options]); +% [eu, pts_list] = sp_eval_phys (u, space, geometry, pts, [options]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_scalar) +% geometry: geometry structure (see geo_load) +% pts: array (rdim x npts) with coordinates of points +% npts: number of points along each parametric direction +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient' and 'laplacian' +% +% OUTPUT: +% +% eu: cell-array with the fields evaluated at the given points. +% pts_list: list of points that are on the geometry, for which the +% values are computed. +% If there is only one output argument, points not on the geometry get a NaN value. +% +% Copyright (C) 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [eu, pts_list] = sp_eval_phys (u, space, geometry, pts, options) + + if (numel (u) ~= space.ndof) + error ('The number of degrees of freedom of the vector and the space do not match') + end + if (~isfield (geometry, 'nurbs')) + error ('Only implemented for NURBS geometries') + end + + if (nargin < 5) + options = {'value'}; + end + if (~iscell (options)) + options = {options}; + end + nopts = numel (options); + + ndim = numel (space.knots); + rdim = geometry.rdim; + + nurbs = geometry.nurbs; + if (ndim == 1) + nurbs.knots = {nurbs.knots}; + end + + npts = size (pts, 2); + pts_param = zeros (ndim, npts); flag = false (npts, 1); + for ipt = 1:npts + [pts_param(:,ipt), flag(ipt)] = nrbinverse (nurbs, pts(:,ipt)); + end + if (~all(flag)) + warning ('Some of the points are not on the geometry') + pts_param = pts_param(:,flag); + npts_on_F = size (pts_param, 2); + if (nargout == 2) + npts_out = npts_on_F; + pts_list = find (flag(:)'); + inds_on_F = 1:npts_out; + else + npts_out = npts; + inds_on_F = find (flag); + end + else + npts_on_F = npts; + npts_out = npts; + inds_on_F = 1:npts; + pts_list = 1:npts; + end + + for idim = 1:ndim + zeta{idim} = unique (space.knots{idim}); + ind{idim} = findspan (numel(zeta{idim})-2, 0, pts_param(idim,:), zeta{idim}) + 1; + end + + value = false; grad = false; laplacian = false; hessian = false; + + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (1, npts_out); + eunum{iopt} = {1}; + eusize{iopt} = npts_out; + value = true; + + case 'gradient' + eu{iopt} = NaN (rdim, npts_out); + eunum{iopt} = {1:rdim}; + eusize{iopt} = [rdim, npts_out]; + grad = true; + + case 'laplacian' + eu{iopt} = NaN (1, npts_out); + eunum{iopt} = {1}; + eusize{iopt} = npts_out; + laplacian = true; + + case 'hessian' + eu{iopt} = NaN (rdim, rdim, npts_out); + eunum{iopt} = {1:rdim, 1:rdim}; + eusize{iopt} = [rdim, rdim, npts_out]; + hessian = true; + end + end + + for ipt = 1:npts_on_F + for idim = 1:ndim + brk{idim} = zeta{idim}(ind{idim}(ipt):ind{idim}(ipt)+1); + end + msh = msh_cartesian (brk, num2cell(pts_param(:,ipt)), [], geometry, 'boundary', false); + sp = space.constructor (msh); + + msh_col = msh_evaluate_element_list (msh, 1); + sp_col = sp_evaluate_element_list (sp, msh_col, 'value', value, 'gradient', grad, ... + 'laplacian', laplacian, 'hessian', hessian); + eu_aux = sp_eval_msh (u, sp_col, msh_col, options); + + for iopt = 1:nopts + eu{iopt}(eunum{iopt}{:},inds_on_F(ipt)) = eu_aux{iopt}; + end + end + for iopt = 1:nopts + eu{iopt} = reshape (eu{iopt}, [eusize{iopt}, 1]); % The extra 1 makes things work also in 1D + end + + if (nopts == 1) + eu = eu{1}; + end + +end From 92b078c45c518a210f0aa228cad34c229a5382da Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 15 May 2023 17:35:37 +0200 Subject: [PATCH 283/366] Evaluate at points in physical domain, scalar case --- .../multipatch/@sp_multipatch/sp_eval_phys.m | 161 +++++++++++++++++ .../@sp_multipatch_C1/sp_eval_phys.m | 162 ++++++++++++++++++ geopdes/inst/space/@sp_scalar/sp_eval_phys.m | 9 +- 3 files changed, 329 insertions(+), 3 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m new file mode 100644 index 00000000..4326ff09 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -0,0 +1,161 @@ +% SP_EVAL_PHYS: Compute the value or derivatives of a function from its degrees of freedom, at a given set of points in the physical domain. +% +% eu = sp_eval_phys (u, space, geometry, pts, [patch_list], [options]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_multipatch) +% geometry: geometry structure (see mp_geo_load) +% pts: array (rdim x npts) with coordinates of points +% npts: number of points along each parametric direction +% patch_list: patch to which each point begins. If empty, the patch +% will be found using nrbinverse +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient' and 'laplacian' +% +% OUTPUT: +% +% eu: cell-array with the fields evaluated at the given points. +% pts_list: list of points that are on the geometry, for which the +% values are computed. +% If there is only one output argument, points not on the geometry get a NaN value. +% +% Copyright (C) 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function eu = sp_eval_phys (u, space, geometry, pts, patch_list, options) + + if (numel (u) ~= space.ndof) + error ('The number of degrees of freedom of the vector and the space do not match') + end + if (numel(geometry) ~= space.npatch) + error ('The number of patches of the space and geometry do not coincide') + end + if (~isfield (geometry, 'nurbs')) + error ('Only implemented for NURBS geometries') + end + if (nargin > 4 && ~isempty(patch_list) && numel(patch_list) ~= size(pts, 2) ) + error ('The number of patches in the list must be equal to the number of points') + end + + npatch = numel (geometry); + + if (nargin < 6) + options = {'value'}; + end + if (~iscell (options)) + options = {options}; + end + nopts = numel (options); + + ndim = numel (space.sp_patch{1}.knots); + rdim = geometry.rdim; + + nurbs = geometry.nurbs; + if (ndim == 1) + for iptc = 1:npatch + geometry(iptc).nurbs.knots = {nurbs.knots}; + end + end + + npts = size (pts, 2); + pts_param = zeros (ndim, npts); flag = false (npts, 1); + +% This is necessary because the NURBS toolbox works in the 3D space + if (size(pts, 1) < 3) + pts(end+1:3,:) = 0; + end + + if (nargin < 5 || isempty (patch_list)) + patch_list = zeros (1, npts); + for ipnt = 1:npts + for iptc = 1:npatch + [pts_param(:,ipnt), flag(ipnt)] = nrbinverse (geometry(iptc).nurbs, pts(:,ipnt)); + if (flag(ipnt)) + patch_list(ipnt) = iptc; + break + end + end + end + end + + vals = cell (1, npatch); + pts_on_patch = cell (1, npatch); + for iptc = 1:npatch + pts_on_patch{iptc} = find (patch_list == iptc); + if (~isempty (pts_on_patch{iptc})) + u_ptc = u(space.gnum{iptc}); + vals{iptc} = sp_eval_phys (u_ptc, space.sp_patch{iptc}, geometry(iptc), pts(:,pts_on_patch{iptc}), options); + if (nopts == 1) + vals{iptc} = {vals{iptc}}; + end + end + end + + value = false; grad = false; laplacian = false; hessian = false; + + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + eusize{iopt} = npts; + value = true; + + case 'gradient' + eu{iopt} = NaN (rdim, npts); + eunum{iopt} = {1:rdim}; + eusize{iopt} = [rdim, npts]; + grad = true; + + case 'laplacian' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + eusize{iopt} = npts; + laplacian = true; + + case 'hessian' + eu{iopt} = NaN (rdim, rdim, npts); + eunum{iopt} = {1:rdim, 1:rdim}; + eusize{iopt} = [rdim, rdim, npts]; + hessian = true; + end + end + + for iopt = 1:nopts + for iptc = 1:npatch + if (~isempty (pts_on_patch{iptc})) + eu{iopt}(eunum{iopt}{:},pts_on_patch{iptc}) = vals{iptc}{iopt}; + end + end + end + + if (nargout == 2) + pts_list = sort (cell2mat (pts_on_patch)); + for iopt = 1:nopts + eu{iopt} = eu{iopt}(eunum{iopt}{:}, pts_list); + end + end + + if (any (isnan(eu{1}))) + warning ('Some points are either not on the geometry, or not on the given patch') + end + + if (nopts == 1) + eu = eu{1}; + end + +end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m new file mode 100644 index 00000000..22cc2c3e --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -0,0 +1,162 @@ +% SP_EVAL_PHYS: Compute the value or derivatives of a function from its degrees of freedom, at a given set of points in the physical domain. +% +% eu = sp_eval_phys (u, space, geometry, pts, [patch_list], [options]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_multipatch_C1) +% geometry: geometry structure (see mp_geo_load) +% pts: array (rdim x npts) with coordinates of points +% npts: number of points along each parametric direction +% patch_list: patch to which each point begins. If empty, the patch +% will be found using nrbinverse +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient' and 'laplacian' +% +% OUTPUT: +% +% eu: cell-array with the fields evaluated at the given points. +% pts_list: list of points that are on the geometry, for which the +% values are computed. +% If there is only one output argument, points not on the geometry get a NaN value. +% +% Copyright (C) 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function eu = sp_eval_phys (u, space, geometry, pts, patch_list, options) + + if (numel (u) ~= space.ndof) + error ('The number of degrees of freedom of the vector and the space do not match') + end + if (numel(geometry) ~= space.npatch) + error ('The number of patches of the space and geometry do not coincide') + end + if (~isfield (geometry, 'nurbs')) + error ('Only implemented for NURBS geometries') + end + if (nargin > 4 && ~isempty(patch_list) && numel(patch_list) ~= size(pts, 2) ) + error ('The number of patches in the list must be equal to the number of points') + end + + npatch = numel (geometry); + + if (nargin < 6) + options = {'value'}; + end + if (~iscell (options)) + options = {options}; + end + nopts = numel (options); + + ndim = numel (space.sp_patch{1}.knots); + rdim = geometry.rdim; + + nurbs = geometry.nurbs; + if (ndim == 1) + for iptc = 1:npatch + geometry(iptc).nurbs.knots = {nurbs.knots}; + end + end + + npts = size (pts, 2); + pts_param = zeros (ndim, npts); flag = false (npts, 1); + +% This is necessary because the NURBS toolbox works in the 3D space + if (size(pts, 1) < 3) + pts(end+1:3,:) = 0; + end + + if (nargin < 5 || isempty (patch_list)) + patch_list = zeros (1, npts); + for ipnt = 1:npts + for iptc = 1:npatch + [pts_param(:,ipnt), flag(ipnt)] = nrbinverse (geometry(iptc).nurbs, pts(:,ipnt), 'MaxIter', 11); + if (flag(ipnt)) + patch_list(ipnt) = iptc; + break + end + end + end + end + + vals = cell (1, npatch); + pts_on_patch = cell (1, npatch); + for iptc = 1:npatch + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + pts_on_patch{iptc} = find (patch_list == iptc); + if (~isempty (pts_on_patch{iptc})) + u_ptc = Cpatch * u(Cpatch_cols); + vals{iptc} = sp_eval_phys (u_ptc, space.sp_patch{iptc}, geometry(iptc), pts(:,pts_on_patch{iptc}), options); + if (nopts == 1) + vals{iptc} = {vals{iptc}}; + end + end + end + + value = false; grad = false; laplacian = false; hessian = false; + + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + eusize{iopt} = npts; + value = true; + + case 'gradient' + eu{iopt} = NaN (rdim, npts); + eunum{iopt} = {1:rdim}; + eusize{iopt} = [rdim, npts]; + grad = true; + + case 'laplacian' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + eusize{iopt} = npts; + laplacian = true; + + case 'hessian' + eu{iopt} = NaN (rdim, rdim, npts); + eunum{iopt} = {1:rdim, 1:rdim}; + eusize{iopt} = [rdim, rdim, npts]; + hessian = true; + end + end + + for iopt = 1:nopts + for iptc = 1:npatch + if (~isempty (pts_on_patch{iptc})) + eu{iopt}(eunum{iopt}{:},pts_on_patch{iptc}) = vals{iptc}{iopt}; + end + end + end + + if (nargout == 2) + pts_list = sort (cell2mat (pts_on_patch)); + for iopt = 1:nopts + eu{iopt} = eu{iopt}(eunum{iopt}{:}, pts_list); + end + end + + if (any (isnan(eu{1}))) + warning ('Some points are either not on the geometry, or not on the given patch') + end + + if (nopts == 1) + eu = eu{1}; + end + +end diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m index 3aa0ad02..b4e04671 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m @@ -56,15 +56,18 @@ rdim = geometry.rdim; nurbs = geometry.nurbs; - if (ndim == 1) - nurbs.knots = {nurbs.knots}; - end npts = size (pts, 2); pts_param = zeros (ndim, npts); flag = false (npts, 1); +% This is necessary because the NURBS toolbox works in the 3D space + if (size(pts, 1) < 3) + pts(end+1:3,:) = 0; + end + for ipt = 1:npts [pts_param(:,ipt), flag(ipt)] = nrbinverse (nurbs, pts(:,ipt)); end + if (~all(flag)) warning ('Some of the points are not on the geometry') pts_param = pts_param(:,flag); From 16f0434999bc0656d00e3f6bd5f1444f20c2936b Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 15 May 2023 17:36:48 +0200 Subject: [PATCH 284/366] Make sure that nqn_dir is a row vector --- geopdes/inst/msh/@msh_cartesian/msh_cartesian.m | 1 + 1 file changed, 1 insertion(+) diff --git a/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m b/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m index 3072b199..8c98d29b 100644 --- a/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m +++ b/geopdes/inst/msh/@msh_cartesian/msh_cartesian.m @@ -131,6 +131,7 @@ msh.nel = prod (msh.nel_dir); msh.nqn_dir = cellfun (@(x) size(x,1), qn); + msh.nqn_dir = msh.nqn_dir(:)'; msh.nqn = prod (msh.nqn_dir); if (boundary && msh.ndim > 1) From f9d83a6ef171e0d282867aca8299f771d35c5d62 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 15 May 2023 17:43:06 +0200 Subject: [PATCH 285/366] Change in the help --- geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m | 2 +- geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m | 2 +- geopdes/inst/space/@sp_scalar/sp_eval.m | 2 +- geopdes/inst/space/@sp_scalar/sp_eval_phys.m | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m index 4326ff09..66c4e973 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -12,7 +12,7 @@ % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient' and 'laplacian' +% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' % % OUTPUT: % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m index 22cc2c3e..5b087b07 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -12,7 +12,7 @@ % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient' and 'laplacian' +% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' % % OUTPUT: % diff --git a/geopdes/inst/space/@sp_scalar/sp_eval.m b/geopdes/inst/space/@sp_scalar/sp_eval.m index 1f9326b3..e0de9d21 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval.m @@ -11,7 +11,7 @@ % pts: cell array with coordinates of points along each parametric direction % npts: number of points along each parametric direction % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient' and 'laplacian' +% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' % % OUTPUT: % diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m index b4e04671..545cd037 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m @@ -11,7 +11,7 @@ % pts: array (rdim x npts) with coordinates of points % npts: number of points along each parametric direction % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient' and 'laplacian' +% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' % % OUTPUT: % From ae8c62bc09da0ccc73978da4be1d4a64e31e4e38 Mon Sep 17 00:00:00 2001 From: vazquez Date: Mon, 15 May 2023 18:04:53 +0200 Subject: [PATCH 286/366] Evaluation at physical points --- geopdes/inst/space/@sp_vector/sp_eval_phys.m | 155 +++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 geopdes/inst/space/@sp_vector/sp_eval_phys.m diff --git a/geopdes/inst/space/@sp_vector/sp_eval_phys.m b/geopdes/inst/space/@sp_vector/sp_eval_phys.m new file mode 100644 index 00000000..81fe207f --- /dev/null +++ b/geopdes/inst/space/@sp_vector/sp_eval_phys.m @@ -0,0 +1,155 @@ +% SP_EVAL_PHYS: Compute the value or derivatives of a function from its degrees of freedom, at a given set of points in the physical domain. +% +% eu = sp_eval_phys (u, space, geometry, pts, [options]); +% [eu, pts_list] = sp_eval_phys (u, space, geometry, pts, [options]); +% +% INPUT: +% +% u: vector of dof weights +% space: object defining the discrete space (see sp_scalar) +% geometry: geometry structure (see geo_load) +% pts: array (rdim x npts) with coordinates of points +% npts: number of points along each parametric direction +% options: cell array with the fields to plot +% accepted options are 'value' (default), 'gradient' and 'laplacian' +% +% OUTPUT: +% +% eu: cell-array with the fields evaluated at the given points. +% pts_list: list of points that are on the geometry, for which the +% values are computed. +% If there is only one output argument, points not on the geometry get a NaN value. +% +% Copyright (C) 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [eu, pts_list] = sp_eval_phys (u, space, geometry, pts, options) + + if (numel (u) ~= space.ndof) + error ('The number of degrees of freedom of the vector and the space do not match') + end + if (~isfield (geometry, 'nurbs')) + error ('Only implemented for NURBS geometries') + end + + if (nargin < 5) + options = {'value'}; + end + if (~iscell (options)) + options = {options}; + end + nopts = numel (options); + + ndim = numel (space.scalar_spaces{1}.knots); + rdim = geometry.rdim; + + nurbs = geometry.nurbs; + + npts = size (pts, 2); + pts_param = zeros (ndim, npts); flag = false (npts, 1); +% This is necessary because the NURBS toolbox works in the 3D space + if (size(pts, 1) < 3) + pts(end+1:3,:) = 0; + end + + for ipt = 1:npts + [pts_param(:,ipt), flag(ipt)] = nrbinverse (nurbs, pts(:,ipt)); + end + + if (~all(flag)) + warning ('Some of the points are not on the geometry') + pts_param = pts_param(:,flag); + npts_on_F = size (pts_param, 2); + if (nargout == 2) + npts_out = npts_on_F; + pts_list = find (flag(:)'); + inds_on_F = 1:npts_out; + else + npts_out = npts; + inds_on_F = find (flag); + end + else + npts_on_F = npts; + npts_out = npts; + inds_on_F = 1:npts; + pts_list = 1:npts; + end + + for idim = 1:ndim + zeta{idim} = unique (space.scalar_spaces{1}.knots{idim}); + ind{idim} = findspan (numel(zeta{idim})-2, 0, pts_param(idim,:), zeta{idim}) + 1; + end + + value = false; grad = false; curl = false; divergence = false; + + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (space.ncomp, npts_out); + eunum{iopt} = {1:space.ncomp}; + eusize{iopt} = [space.ncomp, npts_out]; + value = true; + + case 'gradient' + eu{iopt} = NaN (space.ncomp, rdim, npts_out); + eunum{iopt} = {1:space.ncomp, 1:rdim}; + eusize{iopt} = [space.ncomp, rdim, npts_out]; + grad = true; + + case 'curl' + if (ndim == 2 && rdim == 2) + eu{iopt} = NaN (1, npts_out); + eunum{iopt} = {1}; + eusize{iopt} = npts_out; + elseif (ndim == 3 && rdim == 3) + eu{iopt} = NaN (space.ncomp, rdim, npts_out); + eunum{iopt} = {1:space.ncomp}; + eusize{iopt} = [rdim, npts_out]; + end + curl = true; + + case 'divergence' + eu{iopt} = NaN (1, npts_out); + eunum{iopt} = {1}; + eusize{iopt} = npts_out; + divergence = true; + end + end + + for ipt = 1:npts_on_F + for idim = 1:ndim + brk{idim} = zeta{idim}(ind{idim}(ipt):ind{idim}(ipt)+1); + end + msh = msh_cartesian (brk, num2cell(pts_param(:,ipt)), [], geometry, 'boundary', false); + sp = space.constructor (msh); + + msh_col = msh_evaluate_element_list (msh, 1); + sp_col = sp_evaluate_element_list (sp, msh_col, 'value', value, 'gradient', grad, ... + 'curl', curl, 'divergence', divergence); + eu_aux = sp_eval_msh (u, sp_col, msh_col, options); + + for iopt = 1:nopts + eu{iopt}(eunum{iopt}{:},inds_on_F(ipt)) = eu_aux{iopt}; + end + end + for iopt = 1:nopts + eu{iopt} = reshape (eu{iopt}, [eusize{iopt}, 1]); % The extra 1 makes things work also in 1D + end + + if (nopts == 1) + eu = eu{1}; + end + +end From ce1e27a1ff97346ccc9ab2e66dc9edccc40e3187 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 16 May 2023 12:13:24 +0200 Subject: [PATCH 287/366] Added vector-valued spaces --- .../multipatch/@sp_multipatch/sp_eval_phys.m | 87 ++++++++++++------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m index 66c4e973..199ff600 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -61,7 +61,12 @@ end nopts = numel (options); - ndim = numel (space.sp_patch{1}.knots); + is_scalar = isa (space.sp_patch{1}, 'sp_scalar'); + if (is_scalar) + ndim = numel (space.sp_patch{1}.knots); + else + ndim = numel (space.sp_patch{1}.scalar_spaces{1}.knots); + end rdim = geometry.rdim; nurbs = geometry.nurbs; @@ -98,6 +103,9 @@ pts_on_patch{iptc} = find (patch_list == iptc); if (~isempty (pts_on_patch{iptc})) u_ptc = u(space.gnum{iptc}); + if (~isempty (space.dofs_ornt)) + u_ptc = u_ptc .* space.dofs_ornt{iptc}(:); + end vals{iptc} = sp_eval_phys (u_ptc, space.sp_patch{iptc}, geometry(iptc), pts(:,pts_on_patch{iptc}), options); if (nopts == 1) vals{iptc} = {vals{iptc}}; @@ -105,35 +113,7 @@ end end - value = false; grad = false; laplacian = false; hessian = false; - - for iopt = 1:nopts - switch (lower (options{iopt})) - case 'value' - eu{iopt} = NaN (1, npts); - eunum{iopt} = {1}; - eusize{iopt} = npts; - value = true; - - case 'gradient' - eu{iopt} = NaN (rdim, npts); - eunum{iopt} = {1:rdim}; - eusize{iopt} = [rdim, npts]; - grad = true; - - case 'laplacian' - eu{iopt} = NaN (1, npts); - eunum{iopt} = {1}; - eusize{iopt} = npts; - laplacian = true; - - case 'hessian' - eu{iopt} = NaN (rdim, rdim, npts); - eunum{iopt} = {1:rdim, 1:rdim}; - eusize{iopt} = [rdim, rdim, npts]; - hessian = true; - end - end + [eu, eunum] = set_output_sizes (ndim, rdim, npts, space.ncomp, is_scalar, options); for iopt = 1:nopts for iptc = 1:npatch @@ -159,3 +139,50 @@ end end + +function [eu, eunum] = set_output_sizes (ndim, rdim, npts, ncomp, is_scalar, options) + + nopts = numel(options); + eu = cell (nopts, 1); eunum = eu; + + if (is_scalar) + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + case 'gradient' + eu{iopt} = NaN (rdim, npts); + eunum{iopt} = {1:rdim}; + case 'laplacian' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + case 'hessian' + eu{iopt} = NaN (rdim, rdim, npts); + eunum{iopt} = {1:rdim, 1:rdim}; + end + end + else + for iopt = 1:numel(options) + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (ncomp, npts); + eunum{iopt} = {1:ncomp}; + case 'gradient' + eu{iopt} = NaN (ncomp, rdim, npts); + eunum{iopt} = {1:ncomp, 1:rdim}; + case 'curl' + if (ndim == 2 && rdim == 2) + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + elseif (ndim == 3 && rdim == 3) + eu{iopt} = NaN (ncomp, rdim, npts); + eunum{iopt} = {1:ncomp}; + end + case 'divergence' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + end + end + end +end From 5e69c3c646ded0e4dfcdbdbb563b19fb29bc8444 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 16 May 2023 12:45:50 +0200 Subject: [PATCH 288/366] Working for vectors --- .../multipatch/@sp_multipatch/sp_eval_phys.m | 5 +- .../@sp_multipatch_C1/sp_eval_phys.m | 127 ++++++++++++------ 2 files changed, 86 insertions(+), 46 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m index 199ff600..8b1ba882 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -67,12 +67,11 @@ else ndim = numel (space.sp_patch{1}.scalar_spaces{1}.knots); end - rdim = geometry.rdim; + rdim = geometry(1).rdim; - nurbs = geometry.nurbs; if (ndim == 1) for iptc = 1:npatch - geometry(iptc).nurbs.knots = {nurbs.knots}; + geometry(iptc).nurbs.knots = {geometry(iptc).nurbs.knots}; end end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m index 5b087b07..3d874782 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -38,9 +38,6 @@ function eu = sp_eval_phys (u, space, geometry, pts, patch_list, options) - if (numel (u) ~= space.ndof) - error ('The number of degrees of freedom of the vector and the space do not match') - end if (numel(geometry) ~= space.npatch) error ('The number of patches of the space and geometry do not coincide') end @@ -51,6 +48,15 @@ error ('The number of patches in the list must be equal to the number of points') end + if (numel (u) == space.ndof) + is_scalar = true; + elseif (numel (u) == (geometry(1).rdim * space.ndof)) + is_scalar = false; + ncomp = geometry(1).rdim; + else + error ('The number of degrees of freedom of the vector and the space do not match') + end + npatch = numel (geometry); if (nargin < 6) @@ -62,12 +68,11 @@ nopts = numel (options); ndim = numel (space.sp_patch{1}.knots); - rdim = geometry.rdim; + rdim = geometry(1).rdim; - nurbs = geometry.nurbs; if (ndim == 1) for iptc = 1:npatch - geometry(iptc).nurbs.knots = {nurbs.knots}; + geometry(iptc).nurbs.knots = {geometry(iptc).nurbs.knots}; end end @@ -94,48 +99,36 @@ vals = cell (1, npatch); pts_on_patch = cell (1, npatch); - for iptc = 1:npatch - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - pts_on_patch{iptc} = find (patch_list == iptc); - if (~isempty (pts_on_patch{iptc})) - u_ptc = Cpatch * u(Cpatch_cols); - vals{iptc} = sp_eval_phys (u_ptc, space.sp_patch{iptc}, geometry(iptc), pts(:,pts_on_patch{iptc}), options); - if (nopts == 1) - vals{iptc} = {vals{iptc}}; + if (is_scalar) + for iptc = 1:npatch + pts_on_patch{iptc} = find (patch_list == iptc); + if (~isempty (pts_on_patch{iptc})) + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + u_ptc = Cpatch * u(Cpatch_cols); + vals{iptc} = sp_eval_phys (u_ptc, space.sp_patch{iptc}, geometry(iptc), pts(:,pts_on_patch{iptc}), options); + if (nopts == 1) + vals{iptc} = {vals{iptc}}; + end end end - end - - value = false; grad = false; laplacian = false; hessian = false; - - for iopt = 1:nopts - switch (lower (options{iopt})) - case 'value' - eu{iopt} = NaN (1, npts); - eunum{iopt} = {1}; - eusize{iopt} = npts; - value = true; - - case 'gradient' - eu{iopt} = NaN (rdim, npts); - eunum{iopt} = {1:rdim}; - eusize{iopt} = [rdim, npts]; - grad = true; - - case 'laplacian' - eu{iopt} = NaN (1, npts); - eunum{iopt} = {1}; - eusize{iopt} = npts; - laplacian = true; - - case 'hessian' - eu{iopt} = NaN (rdim, rdim, npts); - eunum{iopt} = {1:rdim, 1:rdim}; - eusize{iopt} = [rdim, rdim, npts]; - hessian = true; + else + msh_aux = struct ('ndim', ndim, 'rdim', rdim, 'boundary', []); + for iptc = 1:npatch + pts_on_patch{iptc} = find (patch_list == iptc); + if (~isempty (pts_on_patch{iptc})) + [Cpatch, Cpatch_cols] = sp_compute_Cpatch_vector (space, iptc, rdim); + u_ptc = Cpatch * u(Cpatch_cols); + sp_vec = sp_vector (repmat (space.sp_patch(iptc), rdim, 1), msh_aux); + vals{iptc} = sp_eval_phys (u_ptc, sp_vec, geometry(iptc), pts(:,pts_on_patch{iptc}), options); + if (nopts == 1) + vals{iptc} = {vals{iptc}}; + end + end end end + [eu, eunum] = set_output_sizes (ndim, rdim, npts, ncomp, is_scalar, options); + for iopt = 1:nopts for iptc = 1:npatch if (~isempty (pts_on_patch{iptc})) @@ -160,3 +153,51 @@ end end + + +function [eu, eunum] = set_output_sizes (ndim, rdim, npts, ncomp, is_scalar, options) + + nopts = numel(options); + eu = cell (nopts, 1); eunum = eu; + + if (is_scalar) + for iopt = 1:nopts + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + case 'gradient' + eu{iopt} = NaN (rdim, npts); + eunum{iopt} = {1:rdim}; + case 'laplacian' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + case 'hessian' + eu{iopt} = NaN (rdim, rdim, npts); + eunum{iopt} = {1:rdim, 1:rdim}; + end + end + else + for iopt = 1:numel(options) + switch (lower (options{iopt})) + case 'value' + eu{iopt} = NaN (ncomp, npts); + eunum{iopt} = {1:ncomp}; + case 'gradient' + eu{iopt} = NaN (ncomp, rdim, npts); + eunum{iopt} = {1:ncomp, 1:rdim}; + case 'curl' + if (ndim == 2 && rdim == 2) + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + elseif (ndim == 3 && rdim == 3) + eu{iopt} = NaN (ncomp, rdim, npts); + eunum{iopt} = {1:ncomp}; + end + case 'divergence' + eu{iopt} = NaN (1, npts); + eunum{iopt} = {1}; + end + end + end +end From c9f77daccb9871e96e3d5bb3858e07ebc7129a14 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 16 May 2023 16:09:24 +0200 Subject: [PATCH 289/366] Changes in the help --- geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m | 8 ++++---- geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m | 8 ++++---- geopdes/inst/space/@sp_vector/sp_eval_phys.m | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m index 8b1ba882..69f71909 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -12,14 +12,14 @@ % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' +% accepted options for scalars are 'value' (default), 'gradient', 'laplacian', 'hessian' +% accepted options for vectors are 'value' (default), 'gradient', 'curl', 'divergence' % % OUTPUT: % % eu: cell-array with the fields evaluated at the given points. -% pts_list: list of points that are on the geometry, for which the -% values are computed. -% If there is only one output argument, points not on the geometry get a NaN value. +% +% Points not on the geometry get a NaN value. % % Copyright (C) 2023 Rafael Vazquez % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m index 3d874782..c348e658 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -12,14 +12,14 @@ % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' +% accepted options for scalars are 'value' (default), 'gradient', 'laplacian', 'hessian' +% accepted options for vectors are 'value' (default), 'gradient', 'curl', 'divergence' % % OUTPUT: % % eu: cell-array with the fields evaluated at the given points. -% pts_list: list of points that are on the geometry, for which the -% values are computed. -% If there is only one output argument, points not on the geometry get a NaN value. +% +% Points not on the geometry get a NaN value. % % Copyright (C) 2023 Rafael Vazquez % diff --git a/geopdes/inst/space/@sp_vector/sp_eval_phys.m b/geopdes/inst/space/@sp_vector/sp_eval_phys.m index 81fe207f..d6ba3fa5 100644 --- a/geopdes/inst/space/@sp_vector/sp_eval_phys.m +++ b/geopdes/inst/space/@sp_vector/sp_eval_phys.m @@ -6,12 +6,12 @@ % INPUT: % % u: vector of dof weights -% space: object defining the discrete space (see sp_scalar) +% space: object defining the discrete space (see sp_vector) % geometry: geometry structure (see geo_load) % pts: array (rdim x npts) with coordinates of points % npts: number of points along each parametric direction % options: cell array with the fields to plot -% accepted options are 'value' (default), 'gradient' and 'laplacian' +% accepted options are 'value' (default), 'gradient', 'curl' and 'divergence' % % OUTPUT: % From 406366f27a8d09193ee4e31ebecb75ba06be99bc Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 16 May 2023 17:02:56 +0200 Subject: [PATCH 290/366] One more change in the help --- geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m | 1 - geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m | 1 - geopdes/inst/space/@sp_scalar/sp_eval_phys.m | 1 - geopdes/inst/space/@sp_vector/sp_eval_phys.m | 1 - 4 files changed, 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m index 69f71909..9ae76471 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_eval_phys.m @@ -8,7 +8,6 @@ % space: object defining the discrete space (see sp_multipatch) % geometry: geometry structure (see mp_geo_load) % pts: array (rdim x npts) with coordinates of points -% npts: number of points along each parametric direction % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m index c348e658..f24778e0 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -8,7 +8,6 @@ % space: object defining the discrete space (see sp_multipatch_C1) % geometry: geometry structure (see mp_geo_load) % pts: array (rdim x npts) with coordinates of points -% npts: number of points along each parametric direction % patch_list: patch to which each point begins. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot diff --git a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m index 545cd037..0c5f1791 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval_phys.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval_phys.m @@ -9,7 +9,6 @@ % space: object defining the discrete space (see sp_scalar) % geometry: geometry structure (see geo_load) % pts: array (rdim x npts) with coordinates of points -% npts: number of points along each parametric direction % options: cell array with the fields to plot % accepted options are 'value' (default), 'gradient', 'laplacian', 'hessian' % diff --git a/geopdes/inst/space/@sp_vector/sp_eval_phys.m b/geopdes/inst/space/@sp_vector/sp_eval_phys.m index d6ba3fa5..c6056d52 100644 --- a/geopdes/inst/space/@sp_vector/sp_eval_phys.m +++ b/geopdes/inst/space/@sp_vector/sp_eval_phys.m @@ -9,7 +9,6 @@ % space: object defining the discrete space (see sp_vector) % geometry: geometry structure (see geo_load) % pts: array (rdim x npts) with coordinates of points -% npts: number of points along each parametric direction % options: cell array with the fields to plot % accepted options are 'value' (default), 'gradient', 'curl' and 'divergence' % From 1b3223970045269532175247e708e627e8586353 Mon Sep 17 00:00:00 2001 From: torre95michele Date: Thu, 15 Jun 2023 14:42:06 +0200 Subject: [PATCH 291/366] cahn_hilliard_mp_C1_tp --- geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m | 4 ++-- geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index dc42053b..23a24bbb 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -12,8 +12,8 @@ % Time and time step size Time_max = .08; -dt = 1e-2; -time_step_save = linspace(dt,Time_max,20); +dt = 1e-4; +time_step_save = linspace(dt,Time_max,9); problem_data.time = 0; problem_data.Time_max = Time_max; diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index fb0567c1..1d9d86a6 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -25,7 +25,7 @@ problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) % 2) INITIAL CONDITIONS -mean = 0.0; +mean = 0.4; var = 0.05; ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition %ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). From 7080230bce3896e337139805e6a716370130cdea Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 16 Jun 2023 15:37:27 +0200 Subject: [PATCH 292/366] Fixed bad use of references --- .../multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m index dda4d66f..551658e7 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m @@ -9,7 +9,7 @@ drchlt_dofs = []; boundaries = msh.boundaries; -for iref = refs +for iref = 1:numel(refs) % href = @(varargin) h(varargin{:}, iref); if (~exist('drchlt_components','var')) components = 1:3; @@ -17,9 +17,9 @@ components = drchlt_components{iref}; end scalar_dofs_on_ref = []; - for bnd_side = 1:boundaries(iref).nsides - iptc = boundaries(iref).patches(bnd_side); - iside = boundaries(iref).faces(bnd_side); + for bnd_side = 1:boundaries(refs(iref)).nsides + iptc = boundaries(refs(iref)).patches(bnd_side); + iside = boundaries(refs(iref)).faces(bnd_side); msh_side = msh.msh_patch{iptc}.boundary(iside); sp_bnd = space.sp_patch{iptc}.boundary(iside); From da664eedeea6943254bf7257fb675557c774d200 Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 16 Jun 2023 15:39:09 +0200 Subject: [PATCH 293/366] Fixed bad use of references --- .../sp_drchlt_C1_exact_shells.m | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m new file mode 100644 index 00000000..d4cf2ce4 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m @@ -0,0 +1,108 @@ +function [u_drchlt, drchlt_dofs, kernel_info] = sp_drchlt_C1_exact_shells (space, msh, refs, uex) + +% TODO: IT WILL ALWAYS USE ALL THE COMPONENTS ON EACH SIDE (leave it like that) + +% refs should be the whole boundary, for now +error ('This function is not implemented correctly yet') + +M = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, msh.rdim*space.ndof); +rhs = zeros (msh.rdim*space.ndof, 1); + +drchlt_dofs = []; + +boundaries = msh.boundaries; +for iref = 1:numel(refs) +% href = @(varargin) h(varargin{:}, iref); + for bnd_side = 1:boundaries(refs(iref)).nsides + iptc = boundaries(refs(iref)).patches(bnd_side); + iside = boundaries(refs(iref)).faces(bnd_side); + + msh_side = msh.msh_patch{iptc}.boundary(iside); + sp_bnd = space.sp_patch{iptc}.boundary(iside); + + Cpatch_bnd = space.Cpatch{iptc}(sp_bnd.dofs,:); + [~,icol] = find (Cpatch_bnd); + + drchlt_dofs = union (drchlt_dofs, icol); + + M_scalar = Cpatch_bnd.' * op_u_v_tp (sp_bnd, sp_bnd, msh_side) * Cpatch_bnd; + M = M + blkdiag (M_scalar, M_scalar, M_scalar); + Cpatch_vector = blkdiag (Cpatch_bnd, Cpatch_bnd, Cpatch_bnd); + rhs = rhs + Cpatch_vector.' * op_f_v_tp_vector (sp_bnd, msh_side, uex); + end +end + +dofs_to_remove = []; +vertices_numbers = []; +row_indices = []; +count_vert = 0; +count_fun = 0; + +% Check the kernel of vertex functions on Dirichlet boundary vertices +% Pick up the basis function with the max. abs. coeff in the kernel, +% remove it from drchlt_dofs, and add the function in the kernel into the +% internal part (it goes in the output) +B_change_local = []; +n_boundaries = numel(msh.boundaries); % number of boundary edges +global_refs = numel(space.interfaces) - n_boundaries + refs; % global numbering of Dirichlet boundary edges + +for iv = 1 : numel(space.vertices) + % Loop just over Dirichlet boundary vertices + if ~isempty(intersect(global_refs, space.vertices(iv).edges)) + if (space.vertices(iv).boundary_vertex) + patches = space.vertices(iv).patches([1 end]); + + operations = space.vertices(iv).patch_reorientation([1 end], :); + indices_loc_R = indices_reorientation(space.sp_patch{patches(1)}.ndof_dir, operations(1, :)); + indices_loc_L = indices_reorientation(space.sp_patch{patches(2)}.ndof_dir, operations(2, :)); + indices_loc_R = indices_loc_R(:); + indices_loc_L = indices_loc_L(:); + + Cpatch_ind_R = indices_loc_R([1 2 3]); +% Cpatch_ind_L = indices_loc_L([1 space.sp_patch{patches(1)}.ndof_dir(1)+1 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + Cpatch_ind_L = indices_loc_L([space.sp_patch{patches(1)}.ndof_dir(1)+1 2*space.sp_patch{patches(1)}.ndof_dir(1)+1]); + + M_ker = [space.Cpatch{patches(1)}(Cpatch_ind_R, space.dofs_on_vertex{iv}); ... + space.Cpatch{patches(2)}(Cpatch_ind_L, space.dofs_on_vertex{iv})]; + + ker = null(full(M_ker)); + if (~isempty(ker)) + nfun = size(ker,2); + [~, ind] = max(abs(ker)); % TODO: NOT A GOOD CHOICE (it may be repeated) + + row_inds = count_vert*6 + (1:6); + B_change_local = blkdiag (B_change_local, ker); + + dofs_on_vertex = space.dofs_on_vertex{iv}; + vertices_numbers(count_fun+(1:nfun)) = iv; + dofs_to_remove(count_fun+(1:nfun)) = dofs_on_vertex(ind); + row_indices(row_inds) = dofs_on_vertex; + count_vert = count_vert + 1; + count_fun = count_fun + nfun; + end + end + end +end + +kernel_info = struct ('vertices_numbers', vertices_numbers, 'all_vertex_dofs', row_indices, 'quasi_interior_dofs', dofs_to_remove, 'B_change_local', sparse(B_change_local)); + +drchlt_dofs = setdiff(drchlt_dofs, dofs_to_remove); +drchlt_dofs = [drchlt_dofs(:); drchlt_dofs(:)+space.ndof; drchlt_dofs(:)+2*space.ndof]; + +u_drchlt = M(drchlt_dofs,drchlt_dofs) \ rhs(drchlt_dofs); + +end + +function indices = indices_reorientation (ndof_dir, operations) + ndof = prod (ndof_dir); + indices = reshape (1:ndof, ndof_dir); + if (operations(1)) + indices = flipud (indices); + end + if (operations(2)) + indices = fliplr (indices); + end + if (operations(3)) + indices = indices.'; + end +end From 94f540253ed7c46274caacd0a917dd6a468fb894 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 22 Feb 2024 19:57:14 +0100 Subject: [PATCH 294/366] Added imposition of zero rotation with Nitsche --- .../sp_nitsche_KL_rotation.m | 67 ++++++ ...olve_kirchhoff_love_shell_C1_scalarspace.m | 4 + .../inst/operators/op_nitsche_KL_boundary.m | 126 ++++++++++ .../inst/solve/solve_kirchhoff_love_shell.m | 4 + .../solve_kirchhoff_love_shell_scalarspace.m | 4 + .../space/@sp_scalar/sp_nitsche_KL_rotation.m | 63 +++++ .../space/@sp_vector/sp_nitsche_KL_rotation.m | 62 +++++ geopdes/inst/utils/op_KL_rotation_fluxes.m | 222 ++++++++++++++++++ 8 files changed, 552 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m create mode 100644 geopdes/inst/operators/op_nitsche_KL_boundary.m create mode 100644 geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m create mode 100644 geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m create mode 100644 geopdes/inst/utils/op_KL_rotation_fluxes.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m new file mode 100644 index 00000000..28952a68 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m @@ -0,0 +1,67 @@ +% SP_NITSCHE_KL_ROTATION: impose zero rotation for Kirchhoff-Love shells using Nitsche method +% +% N_mat = sp_nitsche_KL_rotation (space, msh, bnd_sides, E_coeff, nu_coeff, thickness, C_penalty) +% +% INPUT: +% +% space: space object (see sp_vector) +% msh: mesh object (see msh_cartesian) +% bnd_sides: boundary sides on which the rotation free condition is imposed +% E_coeff: function handle for the Young modulus +% nu_coeff: function handle for the Poisson ratio +% thickness: scalar value for the thickness +% C_penalty: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% +% Copyright (C) 2023, 2024 Giuliano Guarino, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . +function A = sp_nitsche_KL_rotation (space, msh, refs, E_coeff, nu_coeff, thickness, penalty_coeff) + + A = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, 3*msh.rdim*space.ndof); + +% Compute the matrices to impose the tangential boundary condition weakly + for iref = refs + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + msh_side_fi = msh_precompute (msh_side_from_interior); + sp_bnd_param = sp_precompute_param (sp_bnd, msh_side_fi, 'value', true, 'gradient', true, 'hessian', true); + sp_bnd_param = sp_scalar2vector_param (sp_bnd_param, msh_side_fi, 'value', true, 'gradient', true, 'hessian', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + +% Evaluating parameters on the boundary + E_bnd = reshape(E_coeff (x{:}), msh_side.nqn, msh_side.nel); + nu_bnd = reshape(nu_coeff (x{:}), msh_side.nqn, msh_side.nel); + + A_side = op_nitsche_KL_boundary (sp_bnd_param, sp_bnd_param, msh_side, msh_side_fi, E_bnd, nu_bnd, thickness, penalty_coeff); + + [Cpatch_u, cols_u] = sp_compute_Cpatch_vector (space, iptc, msh.rdim); + A(cols_u,cols_u) = A(cols_u,cols_u) + Cpatch_u.' * A_side * Cpatch_u; + % rhs(cols_u) = rhs(cols_u) + Cpatch_u.' * rhs_side; + end + end + +end diff --git a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m index 3c8127e4..48450852 100644 --- a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m +++ b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m @@ -92,6 +92,10 @@ % Compute and assemble the matrices K = op_KL_shells_mp (space, space, msh, E_coeff, nu_coeff, thickness); rhs = op_f_v_mp_vector (space, msh, f); +% Apply zero rotation with Nitsche method +if (exist ('rotation_sides', 'var') && ~isempty(rotation_sides)) + K = K + sp_nitsche_KL_rotation (space, msh, rotation_sides, E_coeff, nu_coeff, thickness, penalty_coeff); +end % Apply boundary conditions % drchlt_dofs = []; drchlt_dofs2 = []; diff --git a/geopdes/inst/operators/op_nitsche_KL_boundary.m b/geopdes/inst/operators/op_nitsche_KL_boundary.m new file mode 100644 index 00000000..cb78eb22 --- /dev/null +++ b/geopdes/inst/operators/op_nitsche_KL_boundary.m @@ -0,0 +1,126 @@ +% OP_NITSCHE_KL_BOUNDARY: compute matrix to impose zero rotation +% +% N_mat = op_nitsche_KL_boundary (spu_param, spv_param, msh_side, msh_side_fi, E_coeff, nu_coeff, thickness, C_penalty) +% +% INPUT: +% +% spu_param: space structure in the paramatric domain (see sp_vector/sp_evaluate_col_param) +% spv_param: space structure in the paramatric domain (see sp_vector/sp_evaluate_col_param) +% msh_side: mesh structure on the boundary +% msh_side_fi: mesh side from interior, with information on the normal derivative +% E_coeff: Young modulus evaluated at quadrature points +% nu_coeff: Poisson ratio evaluated at quadrature points +% thickness: thickness of the shell +% C_penalty: penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% +% Copyright (C) 2023, 2024 Giuliano Guarino, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function mat = op_nitsche_KL_boundary (spu_param, spv_param, msh_side, msh_side_from_interior, E_bnd, nu_bnd, thickness, penalty_coeff) + +nel = msh_side.nel; +nqn = msh_side.nqn; +ndim = msh_side_from_interior.ndim; +rdim = msh_side.rdim; + +qw_jacdet = msh_side.quad_weights .* msh_side.jacdet; +normals = msh_side.normal; +tangents = msh_side.geo_map_jac; +tangents_der = msh_side.geo_map_der2; + +nsh_u = spu_param.nsh_max; +nsh_v = spv_param.nsh_max; +% Preallocating rows, columns and values for the interface +M_rows = zeros(nsh_v*nsh_u*nel,1); +M_columns = zeros(nsh_v*nsh_u*nel,1); +M_values = zeros(nsh_v*nsh_u*nel,1); +R_rows = zeros(nsh_v *nel,1); +R_values = zeros(nsh_v *nel,1); + +M_ncounter = 0; +R_ncounter = 0; + +% Penalty coefficient +mu_r = penalty_coeff*E_bnd(1,1)*thickness^3; + +for ise = 1:nel + K = zeros(nsh_v,nsh_u); + R = zeros(nsh_v,1); + for iqn = 1:nqn + w = qw_jacdet(iqn,ise); + % Tangent and derivative + T_t = tangents (:,1,iqn,ise); + T_tt = tangents_der(:,1,1,iqn,ise); + % Geometry + Aa = msh_side_from_interior.geo_map_jac (:,:,iqn,ise); + Aa_b = msh_side_from_interior.geo_map_der2(:,:,:,iqn,ise); + % Test and Trial shape functions + U = reshape(spu_param.shape_functions(:,iqn,:,ise), [rdim, nsh_u]); + V = reshape(spv_param.shape_functions(:,iqn,:,ise), [rdim, nsh_u]); + % % Exact rotation + % if ~isempty(rot_coeffs) + % Ta = Ta_L(:,iqn,ise); + % end + % Test and Trial shape functions derivatives + u_a = permute(reshape(spu_param.shape_function_gradients (:,:, iqn,:,ise), [rdim,ndim,nsh_u]),[1,3,2 ]); + u_ab = permute(reshape(spu_param.shape_function_hessians (:,:,:,iqn,:,ise), [rdim,ndim,ndim,nsh_u]),[1,4,2,3 ]); + v_a = permute(reshape(spu_param.shape_function_gradients (:,:, iqn,:,ise), [rdim,ndim,nsh_v]),[1,3,2 ]); + v_ab = permute(reshape(spu_param.shape_function_hessians (:,:,:,iqn,:,ise), [rdim,ndim,ndim,nsh_v]),[1,4,2,3 ]); + % Material and normal + Young = E_bnd (iqn,ise); + Poisson = nu_bnd(iqn,ise); + [A_ort,B_ort,C_ort,D_ort] = isotropic_stiffness (Young,Poisson,thickness); + normal = normals(:,iqn,ise); + + % Eventually flipping the tangent + if (normal.'*cross(T_t,cross(Aa(:,1),Aa(:,2)))<0) + T_t = -T_t; + T_tt = -T_tt; + end + % Rotation and forces and moment fluxes +% [Tu, Fu, Mu] = op_KL_fluxes(u_a, u_ab, u_abc, Aa, Aa_b, Aa_bc, T_t, T_tt, A_ort, B_ort, C_ort, D_ort, C_ort_e, D_ort_e, normal); + [Tu, Mu] = op_KL_rotation_fluxes(u_a, u_ab, Aa, Aa_b, T_t, D_ort, normal); + [Tv, Mv] = op_KL_rotation_fluxes(v_a, v_ab, Aa, Aa_b, T_t, D_ort, normal); + + % Contribution of one Gauss point to the stiffness matrix + K = K + w*mu_r*Tv'*Tu; +% R = R + w*mu_r*Tv'*Ta; + K = K - w*Mv'*Tu - w*Tv'*Mu; +% R = R - w*Mv'*Ta; + end + % Assembling in the global matrix + % rows and column dof list of the element in the global numeration + rows_v = spv_param.connectivity(:,ise); + columns_v = spu_param.connectivity(:,ise); + [rows_s,columns_s] = ndgrid(rows_v,columns_v); + % Global rows and columns sparse vector + M_rows ((M_ncounter+1) : (M_ncounter+nsh_v*nsh_u) ) = rows_s(:); + M_columns((M_ncounter+1) : (M_ncounter+nsh_v*nsh_u) ) = columns_s(:); + M_values ((M_ncounter+1) : (M_ncounter+nsh_v*nsh_u) ) = K(:); +% R_rows ((R_ncounter+1) : (R_ncounter+nsh_v)) = rows_v(:); +% R_values ((R_ncounter+1) : (R_ncounter+nsh_v)) = R(:); + % Updating the ncounter + M_ncounter = M_ncounter + nsh_v*nsh_u; +% R_ncounter = R_ncounter + nsh_v; +end + +mat = sparse(M_rows,M_columns,M_values,spv_param.ndof,spu_param.ndof); +% rhs = full(sparse(R_rows,ones(size(R_rows)),R_values,global_start_index(2),1)); + +end \ No newline at end of file diff --git a/geopdes/inst/solve/solve_kirchhoff_love_shell.m b/geopdes/inst/solve/solve_kirchhoff_love_shell.m index b821e6ef..69b4e955 100644 --- a/geopdes/inst/solve/solve_kirchhoff_love_shell.m +++ b/geopdes/inst/solve/solve_kirchhoff_love_shell.m @@ -85,6 +85,10 @@ % Assemble the stiffness matrix and right-hand side K = op_KL_shells_tp (space, space, msh, E_coeff, nu_coeff, thickness); rhs = op_f_v_tp (space, msh, f); +% Apply zero rotation with Nitsche method +if (exist ('rotation_sides', 'var') && ~isempty(rotation_sides)) + K = K + sp_nitsche_KL_rotation (space, msh, rotation_sides, E_coeff, nu_coeff, thickness, penalty_coeff); +end u = zeros (space.ndof, 1); diff --git a/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m index af941a43..35198b16 100644 --- a/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m +++ b/geopdes/inst/solve/solve_kirchhoff_love_shell_scalarspace.m @@ -85,6 +85,10 @@ % Assemble the stiffness matrix and right-hand side K = op_KL_shells_tp (space, space, msh, E_coeff, nu_coeff, thickness); rhs = op_f_v_tp_vector (space, msh, f); +% Apply zero rotation with Nitsche method +if (exist ('rotation_sides', 'var') && ~isempty(rotation_sides)) + K = K + sp_nitsche_KL_rotation (space, msh, rotation_sides, E_coeff, nu_coeff, thickness, penalty_coeff); +end % Apply boundary conditions drchlt_dofs = []; diff --git a/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m new file mode 100644 index 00000000..8b3287ce --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m @@ -0,0 +1,63 @@ +% SP_NITSCHE_KL_ROTATION: impose zero rotation for Kirchhoff-Love shells using Nitsche method +% +% N_mat = sp_nitsche_KL_rotation (space, msh, bnd_sides, E_coeff, nu_coeff, thickness, C_penalty) +% +% INPUT: +% +% space: space object (see sp_scalar) +% msh: mesh object (see msh_cartesian) +% bnd_sides: boundary sides on which the rotation free condition is imposed +% E_coeff: function handle for the Young modulus +% nu_coeff: function handle for the Poisson ratio +% thickness: scalar value for the thickness +% C_penalty: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% +% Copyright (C) 2023, 2024 Giuliano Guarino, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = sp_nitsche_KL_rotation (space, msh, bnd_sides, E_coeff, nu_coeff, thickness, penalty_coeff) + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + +% Compute the matrices to impose the tangential boundary condition weakly + for iside = bnd_sides + + msh_side = msh_eval_boundary_side (msh, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh, iside); + + sp_bnd = space.constructor (msh_side_from_interior); + sp_bnd_param = sp_precompute_param (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true, 'hessian', true); + msh_side_fi = msh_precompute (msh_side_from_interior); + sp_bnd_param = sp_scalar2vector_param (sp_bnd_param, msh_side_fi, 'value', true, 'gradient', true, 'hessian', true); + % sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true, 'hessian', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + +% Evaluating parameters on the boundary + E_bnd = reshape(E_coeff (x{:}), msh_side.nqn, msh_side.nel); + nu_bnd = reshape(nu_coeff (x{:}), msh_side.nqn, msh_side.nel); + + A_side = op_nitsche_KL_boundary (sp_bnd_param, sp_bnd_param, msh_side, msh_side_fi, E_bnd, nu_bnd, thickness, penalty_coeff); + + A = A + A_side; + end + +end diff --git a/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m new file mode 100644 index 00000000..c3679ae8 --- /dev/null +++ b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m @@ -0,0 +1,62 @@ +% SP_NITSCHE_KL_ROTATION: impose zero rotation for Kirchhoff-Love shells using Nitsche method +% +% N_mat = sp_nitsche_KL_rotation (space, msh, bnd_sides, E_coeff, nu_coeff, thickness, C_penalty) +% +% INPUT: +% +% space: space object (see sp_vector) +% msh: mesh object (see msh_cartesian) +% bnd_sides: boundary sides on which the rotation free condition is imposed +% E_coeff: function handle for the Young modulus +% nu_coeff: function handle for the Poisson ratio +% thickness: scalar value for the thickness +% C_penalty: a penalization term +% +% OUTPUT: +% +% N_mat: the computed matrix, to be added in the left hand-side +% +% Copyright (C) 2023, 2024 Giuliano Guarino, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function A = sp_nitsche_KL_rotation (space, msh, bnd_sides, E_coeff, nu_coeff, thickness, penalty_coeff) + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + +% Compute the matrices to impose the tangential boundary condition weakly + for iside = bnd_sides + + msh_side = msh_eval_boundary_side (msh, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh, iside); + + sp_bnd = space.constructor (msh_side_from_interior); + sp_bnd_param = sp_precompute_param (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true, 'hessian', true); + msh_side_fi = msh_precompute (msh_side_from_interior); + % sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', true, 'gradient', true, 'hessian', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + +% Evaluating parameters on the boundary + E_bnd = reshape(E_coeff (x{:}), msh_side.nqn, msh_side.nel); + nu_bnd = reshape(nu_coeff (x{:}), msh_side.nqn, msh_side.nel); + + A_side = op_nitsche_KL_boundary (sp_bnd_param, sp_bnd_param, msh_side, msh_side_fi, E_bnd, nu_bnd, thickness, penalty_coeff); + + A = A + A_side; + end + +end diff --git a/geopdes/inst/utils/op_KL_rotation_fluxes.m b/geopdes/inst/utils/op_KL_rotation_fluxes.m new file mode 100644 index 00000000..5471dcaa --- /dev/null +++ b/geopdes/inst/utils/op_KL_rotation_fluxes.m @@ -0,0 +1,222 @@ +% OP_KL_ROTATION_FLUXES: compute the rotation and the bending moment along the boundary identified by normal and tangent +% +% [Rotation, Moment] = op_KL_rotation_fluxes(u_a, u_ab, Aa, Aa_b, T_t, Dabcd_ort, normal) +% +% INPUT: +% +% u_a: [3 x nsh x 2] multidimenional array. u_a(i,j,k) is the derivative along xi_k of the j-th shape function associated to the i-th Cartesian component of the dispacement field +% u_ab: [3 x nsh x 2 x 2] multidimenional array. u_a(i,j,k,l) is the derivative along xi_l of u_a(i,j,k) +% Aa: [3 x 2] matrix. A_a(i,j) is the derivative along xi_j of the i-th Cartesian component of the surface map +% Aa_b: [3 x 2 x 2] multidimenional array. A_a(i,j,k) is the derivative along xi_k of A_a(i,j) +% T_t: [3 x 1] vector. T_t(i) is the derivative of the i-th Cartesian component of the map of the boundary with respect to the curvilinear cordinate that parametrizes the boundary +% Dabcd_ort: [2 x 2 x 2 x 2] multidimensional array. Constitutive tensor in local orthonormal coordinates (normalized first covariant and second contravariant basis vectors). +% normal: [3 x 1] vector. Outer unit normal +% +% +% OUTPUT: +% +% Rotation: [1 x nsh] vector. Multiplied for the vector of the correspondent dofs returns the rotation along the tangent +% Moment: [1 x nsh] vector. Multiplied for the vector of the correspondent dofs returns the moment along the tangent +% +% +% NOTES: +% +% 1) While normal has to be normalized (unit vector) T_t does not have to +% 2) Dabcd_ort is in tensor form. If the constitutive relationship is available in Voigt for it has to be converted +% 3) The quantities involved all refer to a single point along the boundary line +% +% +% Copyright (C) 2024 Giuliano Guarino +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + + + +function [Rotation, Moment] = op_KL_rotation_fluxes(u_a, u_ab, Aa, Aa_b, T_t, Dabcd_ort, normal) +% Data from input ========================================================= +% Number of shape functions ----------------------------------------------- +nsh = size(u_a,2); +% ========================================================================= + + + +%% Geometry =============================================================== +% Covariant base on the shell surface ------------------------------------- +A1 = Aa(:,1); +A2 = Aa(:,2); +% Vector V orthogonal to the surface (not normalized) and its derivative -- +V = cross(A1,A2); +% Norm of V and its derivatives ------------------------------------------- +lam = norm(V); +% Normalized vector orthogonal to the surface and its derivatives --------- +A3 = V/lam; +% Carthesian basis -------------------------------------------------------- +e1_cart = [1;0;0]; +e2_cart = [0;1;0]; +e3_cart = [0;0;1]; +% Auxiliary matrix for linearization of n0 and derivatives ---------------- +auxM1 = [cross(e1_cart,A1),cross(e2_cart,A1),cross(e3_cart,A1)]; +auxM2 = [cross(e1_cart,A2),cross(e2_cart,A2),cross(e3_cart,A2)]; +auxM = A3*A3'/lam; +% Covariant components of the surface metric tensor ----------------------- +A11_cov = A1'*A1; +A12_cov = A1'*A2; +A21_cov = A2'*A1; +A22_cov = A2'*A2; +Aab_cov = [A11_cov,A12_cov;A21_cov,A22_cov]; +% Contravariant components of the surface metric tensor ------------------- +Aab_con = Aab_cov^-1; +% Contravariant basis on the surface --------------------------------------- +Aa_con(:,1) = Aab_con(1,1)*Aa(:,1) + Aab_con(1,2)*Aa(:,2); +Aa_con(:,2) = Aab_con(2,1)*Aa(:,1) + Aab_con(2,2)*Aa(:,2); +% Vector t and its derivatives -------------------------------------------- +tau = norm(T_t); +t = T_t/tau; +% Checking the orientation of the normal vector --------------------------- +aux = normal'*cross(t,A3); +if aux>0 + flip = false; +elseif aux<0 + flip = true; +end +% Vector n and its derivatives -------------------------------------------- +if flip + n = -( cross(t,A3) ); +else + n = cross(t,A3); +end +% Cov components of the vector n ------------------------------------------ +n1 = n'*A1; +n2 = n'*A2; +na = [n1,n2]; +% Cross products useful for the computations ------------------------------ +Aa_bxAc = zeros(3,2,2,2); +for i1 = 1:2 + for i2 = 1:2 + for i3 = 1:2 + Aa_bxAc(:,i1,i2,i3) = cross(Aa_b(:,i1,i2),Aa(:,i3)); + end + end +end +% Orthonormal basis vectors and their derivatives ------------------------- +e1 = A1/norm(A1); +e2 = cross(A3,e1); +ea = [e1,e2]; +% ========================================================================= + + + +%% Displacements and rotations ============================================ +% Rotation ---------------------------------------------------------------- +txA3 = cross(t,A3); +txA3xA1 = cross(txA3,A1); +txA3xA2 = cross(txA3,A2); +phin = txA3xA1'/lam*u_a(:,:,2) - txA3xA2'/lam*u_a(:,:,1) + txA3'*auxM*(-auxM2*u_a(:,:,1)+auxM1*u_a(:,:,2)); +% ========================================================================= + + + +%% Deformations =========================================================== +kab = zeros(nsh,2,2); +% Cycle for computing eab and kab ----------------------------------------- +for i1 = 1:2 + for i2 = 1:2 + kab(:,i1,i2) = -A3'*u_ab(:,:,i1,i2) - Aa_bxAc(:,i1,i2,1)'/lam*u_a(:,:,2) + Aa_bxAc(:,i1,i2,2)'/lam*u_a(:,:,1)+... + -Aa_b(:,i1,i2)'*auxM*auxM1*u_a(:,:,2) + Aa_b(:,i1,i2)'*auxM*auxM2*u_a(:,:,1); + end +end +% ========================================================================= + + + +%% Stiffness coefficient ================================================== +% Computation of the cosine directors and derivatives --------------------- +eaAb_con = zeros(2,2); +for i1 = 1:2 + for i2 = 1:2 + eaAb_con(i1,i2) = ea(:,i1)'*Aa_con(:,i2); + end +end +% Computation of the stiffness coefficients ------------------------------- +Dabcd = zeros(2,2,2,2); +for i1 = 1:2 + for i2 = 1:2 + for i3 = 1:2 + for i4 = 1:2 + for i5 = 1:2 + for i6 = 1:2 + for i7 = 1:2 + for i8 = 1:2 + Dabcd(i1,i2,i3,i4) = Dabcd(i1,i2,i3,i4) + Dabcd_ort(i5,i6,i7,i8)*eaAb_con(i5,i1)*eaAb_con(i6,i2)*eaAb_con(i7,i3)*eaAb_con(i8,i4); + end + end + end + end + end + end + end +end +% ========================================================================= + + + +%% Stress resultant ======================================================= +mab = zeros(nsh,2,2); +% Cycle for computing mab ------------------------------------------------- +for i1 = 1:2 + for i2 = 1:2 + for i3 = 1:2 + for i4 = 1:2 + mab(:,i1,i2) = mab(:,i1,i2) + Dabcd(i1,i2,i3,i4)*kab(:,i3,i4); + end + end + end +end +% ========================================================================= + + + +%% Forces for the penalization ============================================ +% Cycle for computing Mt -------------------------------------------------- +Mt = zeros(nsh,1); +for i1 = 1:2 + for i2 = 1:2 + Mt = Mt + mab(:,i1,i2)*na(i1)*na(i2); + end +end +Mt = Mt'; +% Eventual flipping of mt ------------------------------------------------- +if flip + Mt = -Mt; +end +% ========================================================================= + + + +%% Output ================================================================= +Rotation = phin; +Moment = Mt; +% ========================================================================= +end + + + + + + + + + + + From 712422530310569ebd7fcc49d650699ba4e5609e Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 14:13:10 +0200 Subject: [PATCH 295/366] new file, and small changes --- .../inst/operators/op_nitsche_KL_boundary.m | 23 ++++---- geopdes/inst/utils/isotropic_stiffness.m | 55 +++++++++++++++++++ 2 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 geopdes/inst/utils/isotropic_stiffness.m diff --git a/geopdes/inst/operators/op_nitsche_KL_boundary.m b/geopdes/inst/operators/op_nitsche_KL_boundary.m index cb78eb22..d4f31967 100644 --- a/geopdes/inst/operators/op_nitsche_KL_boundary.m +++ b/geopdes/inst/operators/op_nitsche_KL_boundary.m @@ -42,7 +42,7 @@ qw_jacdet = msh_side.quad_weights .* msh_side.jacdet; normals = msh_side.normal; tangents = msh_side.geo_map_jac; -tangents_der = msh_side.geo_map_der2; +% tangents_der = msh_side.geo_map_der2; nsh_u = spu_param.nsh_max; nsh_v = spv_param.nsh_max; @@ -50,29 +50,26 @@ M_rows = zeros(nsh_v*nsh_u*nel,1); M_columns = zeros(nsh_v*nsh_u*nel,1); M_values = zeros(nsh_v*nsh_u*nel,1); -R_rows = zeros(nsh_v *nel,1); -R_values = zeros(nsh_v *nel,1); +% R_rows = zeros(nsh_v *nel,1); +% R_values = zeros(nsh_v *nel,1); M_ncounter = 0; -R_ncounter = 0; +% R_ncounter = 0; % Penalty coefficient mu_r = penalty_coeff*E_bnd(1,1)*thickness^3; for ise = 1:nel K = zeros(nsh_v,nsh_u); - R = zeros(nsh_v,1); + % R = zeros(nsh_v,1); for iqn = 1:nqn w = qw_jacdet(iqn,ise); % Tangent and derivative T_t = tangents (:,1,iqn,ise); - T_tt = tangents_der(:,1,1,iqn,ise); + % T_tt = tangents_der(:,1,1,iqn,ise); % Geometry Aa = msh_side_from_interior.geo_map_jac (:,:,iqn,ise); Aa_b = msh_side_from_interior.geo_map_der2(:,:,:,iqn,ise); - % Test and Trial shape functions - U = reshape(spu_param.shape_functions(:,iqn,:,ise), [rdim, nsh_u]); - V = reshape(spv_param.shape_functions(:,iqn,:,ise), [rdim, nsh_u]); % % Exact rotation % if ~isempty(rot_coeffs) % Ta = Ta_L(:,iqn,ise); @@ -80,18 +77,18 @@ % Test and Trial shape functions derivatives u_a = permute(reshape(spu_param.shape_function_gradients (:,:, iqn,:,ise), [rdim,ndim,nsh_u]),[1,3,2 ]); u_ab = permute(reshape(spu_param.shape_function_hessians (:,:,:,iqn,:,ise), [rdim,ndim,ndim,nsh_u]),[1,4,2,3 ]); - v_a = permute(reshape(spu_param.shape_function_gradients (:,:, iqn,:,ise), [rdim,ndim,nsh_v]),[1,3,2 ]); - v_ab = permute(reshape(spu_param.shape_function_hessians (:,:,:,iqn,:,ise), [rdim,ndim,ndim,nsh_v]),[1,4,2,3 ]); + v_a = permute(reshape(spv_param.shape_function_gradients (:,:, iqn,:,ise), [rdim,ndim,nsh_v]),[1,3,2 ]); + v_ab = permute(reshape(spv_param.shape_function_hessians (:,:,:,iqn,:,ise), [rdim,ndim,ndim,nsh_v]),[1,4,2,3 ]); % Material and normal Young = E_bnd (iqn,ise); Poisson = nu_bnd(iqn,ise); - [A_ort,B_ort,C_ort,D_ort] = isotropic_stiffness (Young,Poisson,thickness); + [A_ort,B_ort,C_ort,D_ort] = isotropic_stiffness (Young, Poisson, thickness); normal = normals(:,iqn,ise); % Eventually flipping the tangent if (normal.'*cross(T_t,cross(Aa(:,1),Aa(:,2)))<0) T_t = -T_t; - T_tt = -T_tt; + % T_tt = -T_tt; end % Rotation and forces and moment fluxes % [Tu, Fu, Mu] = op_KL_fluxes(u_a, u_ab, u_abc, Aa, Aa_b, Aa_bc, T_t, T_tt, A_ort, B_ort, C_ort, D_ort, C_ort_e, D_ort_e, normal); diff --git a/geopdes/inst/utils/isotropic_stiffness.m b/geopdes/inst/utils/isotropic_stiffness.m new file mode 100644 index 00000000..e9b3df71 --- /dev/null +++ b/geopdes/inst/utils/isotropic_stiffness.m @@ -0,0 +1,55 @@ +function [A_ort,B_ort,C_ort,D_ort] = isotropic_stiffness(young,poisson,thickness) +% +% Copyright (C) 2024 Giuliano Guarino +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + + +% Computing the stiffness matrix in two dimensions ------------------------ +E = young/(1-poisson^2)*[1,poisson,0;poisson,1,0;0,0,0.5-poisson/2]; +% membrane and flexural stiffness matrices -------------------------------- +A_ort = E*thickness; +D_ort = E*thickness*thickness*thickness/12; +% transforming to tensor -------------------------------------------------- +A_ort = stiffness_mat2ten(A_ort); +D_ort = stiffness_mat2ten(D_ort); +B_ort = zeros(2,2,2,2); +C_ort = zeros(2,2,2,2); +end + + + + +function T = stiffness_mat2ten(M) +% this function transform a plate stiffness matrix in a tensor + T(1,1 , 1,1) = M(1,1); + T(1,1 , 1,2) = M(1,3); + T(1,1 , 2,1) = M(1,3); + T(1,1 , 2,2) = M(1,2); + + T(1,2 , 1,1) = M(3,1); + T(1,2 , 1,2) = M(3,3); + T(1,2 , 2,1) = M(3,3); + T(1,2 , 2,2) = M(3,2); + + T(2,1 , 1,1) = M(3,1); + T(2,1 , 1,2) = M(3,3); + T(2,1 , 2,1) = M(3,3); + T(2,1 , 2,2) = M(3,2); + + T(2,2 , 1,1) = M(2,1); + T(2,2 , 1,2) = M(2,3); + T(2,2 , 2,1) = M(2,3); + T(2,2 , 2,2) = M(2,2); +end \ No newline at end of file From 84a4aca8afe017263bd402ac276de9aa4e3cba42 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 16:33:21 +0200 Subject: [PATCH 296/366] Change computation of characteristic length --- .../@msh_cartesian/msh_eval_boundary_side.m | 120 +++++++++++++----- 1 file changed, 86 insertions(+), 34 deletions(-) diff --git a/geopdes/inst/msh/@msh_cartesian/msh_eval_boundary_side.m b/geopdes/inst/msh/@msh_cartesian/msh_eval_boundary_side.m index ea0edb28..67bb2e4c 100644 --- a/geopdes/inst/msh/@msh_cartesian/msh_eval_boundary_side.m +++ b/geopdes/inst/msh/@msh_cartesian/msh_eval_boundary_side.m @@ -91,39 +91,40 @@ % Compute the characteristic length in the normal direction % This has to be computed using information from the interior - qn = msh.qn; qw = msh.qw; nel_dir = msh.nel_dir; - if (mod (iside, 2) == 0) - qn{ind2} = qn{ind2}(:,end); - if (~isempty(msh.qw)) - qw = qw{ind2}(:,end); - else - qw = []; - end - else - qn{ind2} = qn{ind2}(:,1); - if (~isempty(msh.qw)) - qw = qw{ind2}(:,1); - else - qw = []; - end - end - nel_dir(ind2) = 1; - - reorder = @(x) x(:)'; - psize = reorder ([msh.nqn_dir; nel_dir]); - vorder = [1:2:msh.ndim*2, 2:2:msh.ndim*2]; % [1 3 5 2 4 6], for ndim = 3 - - jac = feval (msh.map_der, cellfun (reorder, qn, 'UniformOutput', false)); - jac = reshape (jac, [msh.rdim, msh.ndim, psize]); - jac = permute (jac, [1 2 vorder+2]); - jac = reshape (jac, [msh.rdim, msh.ndim, msh.nqn_dir, msh_side.nel]); - - jac = reshape (sqrt (sum (jac(:,ind2,:,:,:,:).^2, 1)), [msh.nqn_dir, msh_side.nel]); % Module - - qsize = ones (1, msh.ndim); - qsize(ind2) = numel (qw); - jac_times_qw = bsxfun(@times, jac, reshape (qw, qsize)); - msh_side.charlen = reshape (sum (jac_times_qw, ind2), msh_side.nqn, msh_side.nel); + msh_side.charlen = compute_characteristic_length (msh, iside); +% qn = msh.qn; qw = msh.qw; nel_dir = msh.nel_dir; +% if (mod (iside, 2) == 0) +% qn{ind2} = qn{ind2}(:,end); +% if (~isempty(msh.qw)) +% qw = qw{ind2}(:,end); +% else +% qw = []; +% end +% else +% qn{ind2} = qn{ind2}(:,1); +% if (~isempty(msh.qw)) +% qw = qw{ind2}(:,1); +% else +% qw = []; +% end +% end +% nel_dir(ind2) = 1; +% +% reorder = @(x) x(:)'; +% psize = reorder ([msh.nqn_dir; nel_dir]); +% vorder = [1:2:msh.ndim*2, 2:2:msh.ndim*2]; % [1 3 5 2 4 6], for ndim = 3 +% +% jac = feval (msh.map_der, cellfun (reorder, qn, 'UniformOutput', false)); +% jac = reshape (jac, [msh.rdim, msh.ndim, psize]); +% jac = permute (jac, [1 2 vorder+2]); +% jac = reshape (jac, [msh.rdim, msh.ndim, msh.nqn_dir, msh_side.nel]); +% +% jac = reshape (sqrt (sum (jac(:,ind2,:,:,:,:).^2, 1)), [msh.nqn_dir, msh_side.nel]); % Module +% +% qsize = ones (1, msh.ndim); +% qsize(ind2) = numel (qw); +% jac_times_qw = bsxfun(@times, jac, reshape (qw, qsize)); +% msh_side.charlen = reshape (sum (jac_times_qw, ind2), msh_side.nqn, msh_side.nel); end elseif (nargin == 3) @@ -183,7 +184,8 @@ % Now normalize norms = reshape (geopdes_norm__ (normal), [1, msh_side.nqn, msh_side.nel]); msh_side.normal = bsxfun (@rdivide, normal, norms); - + + msh_side.charlen = compute_characteristic_length (msh, iside, element_list); end end @@ -213,3 +215,53 @@ end + +function charlen = compute_characteristic_length (msh, iside, element_list) + + if (nargin == 2) + element_list = 1:msh.boundary(iside).nel; + end + + ind2 = ceil (iside/2); + qn = msh.qn; qw = msh.qw; nel_dir = msh.nel_dir; + if (mod (iside, 2) == 0) + qn{ind2} = qn{ind2}(:,end); + if (~isempty(msh.qw)) + qw = qw{ind2}(:,end); + else + qw = []; + end + else + qn{ind2} = qn{ind2}(:,1); + if (~isempty(msh.qw)) + qw = qw{ind2}(:,1); + else + qw = []; + end + end + nel_dir(ind2) = 1; + + reorder = @(x) x(:)'; + psize = reorder ([msh.nqn_dir; nel_dir]); + vorder = [1:2:msh.ndim*2, 2:2:msh.ndim*2]; % [1 3 5 2 4 6], for ndim = 3 + + jac = feval (msh.map_der, cellfun (reorder, qn, 'UniformOutput', false)); + jac = reshape (jac, [msh.rdim, msh.ndim, psize]); + jac = permute (jac, [1 2 vorder+2]); + jac = reshape (jac, [msh.rdim, msh.ndim, msh.nqn_dir, msh.boundary(iside).nel]); + + jac = reshape (sqrt (sum (jac(:,ind2,:,:,:,:).^2, 1)), [msh.nqn_dir, msh.boundary(iside).nel]); % Module + + if (msh.ndim == 2) + jac = jac(:,:,element_list); + elseif (msh.ndim == 3) + jac = jac(:,:,:,element_list); + end + qsize = ones (1, msh.ndim); + qsize(ind2) = numel (qw); + jac_times_qw = bsxfun(@times, jac, reshape (qw, qsize)); + + charlen = sum (jac_times_qw, ind2); + charlen = reshape (charlen, msh.boundary(iside).nqn, numel(element_list)); + +end From 3089640b5687ca7eacddde229de2e59c8aac38f5 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 16:34:15 +0200 Subject: [PATCH 297/366] Linear elasticity operator for scalar spaces --- geopdes/inst/space/@sp_scalar/op_su_ev_tp.m | 70 +++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 geopdes/inst/space/@sp_scalar/op_su_ev_tp.m diff --git a/geopdes/inst/space/@sp_scalar/op_su_ev_tp.m b/geopdes/inst/space/@sp_scalar/op_su_ev_tp.m new file mode 100644 index 00000000..db839cf4 --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_su_ev_tp.m @@ -0,0 +1,70 @@ +% OP_SU_EV_TP: assemble the matrix A = [a(i,j)], a(i,j) = 1/2 (sigma (u_j), epsilon (v_i)), exploiting the tensor product structure. +% +% mat = op_su_ev_tp (spu, spv, msh, lambda, mu); +% [rows, cols, values] = op_su_ev_tp (spu, spv, msh, lambda, mu); +% +% INPUT: +% +% spu: object representing the space of trial functions (see sp_vector) +% spv: object representing the space of test functions (see sp_vector) +% msh: object that defines the domain partition and the quadrature rule (see msh_cartesian) +% lambda, mu: function handles to compute the Lame' coefficients +% +% OUTPUT: +% +% mat: assembled matrix +% rows: row indices of the nonzero entries +% cols: column indices of the nonzero entries +% values: values of the nonzero entries +% +% Copyright (C) 2011, 2017 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function varargout = op_su_ev_tp (space1, space2, msh, lambda, mu) + + for idim = 1:msh.ndim + size1 = size (space1.sp_univ(idim).connectivity); + size2 = size (space2.sp_univ(idim).connectivity); + if (size1(2) ~= size2(2) || size1(2) ~= msh.nel_dir(idim)) + error ('One of the discrete spaces is not associated to the mesh') + end + end + + A = spalloc (msh.rdim*space2.ndof, msh.rdim*space1.ndof, 5*msh.rdim*space1.ndof); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp1_col = sp_evaluate_col (space1, msh_col, 'value', false, 'gradient', true); + sp2_col = sp_evaluate_col (space2, msh_col, 'value', false, 'gradient', true); + sp1_col = sp_scalar2vector (sp1_col, msh_col, 'value', false, 'gradient', true, 'divergence', true); + sp2_col = sp_scalar2vector (sp2_col, msh_col, 'value', false, 'gradient', true, 'divergence', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + A = A + op_su_ev (sp1_col, sp2_col, msh_col, lambda (x{:}), mu (x{:})); + end + + if (nargout == 1) + varargout{1} = A; + elseif (nargout == 3) + [rows, cols, vals] = find (A); + varargout{1} = rows; + varargout{2} = cols; + varargout{3} = vals; + end + +end From 52371dad444f17de1a7ccdad1d787380e6c4a3c2 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 16:36:29 +0200 Subject: [PATCH 298/366] Added computation of endpoints --- geopdes/inst/space/@sp_scalar/sp_eval.m | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/geopdes/inst/space/@sp_scalar/sp_eval.m b/geopdes/inst/space/@sp_scalar/sp_eval.m index e0de9d21..d1a80460 100644 --- a/geopdes/inst/space/@sp_scalar/sp_eval.m +++ b/geopdes/inst/space/@sp_scalar/sp_eval.m @@ -72,6 +72,14 @@ if (iscell (npts)) pts = npts; npts = cellfun (@numel, pts); + degree = space.degree; + for idim = 1:ndim + knt_aux = space.knots{idim}(degree(idim)+1:end-degree(idim)); + ind = find (pts{idim}(1)>=knt_aux(1:end-1), 1, 'last'); + endpoints(1,idim) = knt_aux(ind); + ind = find (pts{idim}(end)>=knt_aux(1:end-1), 1, 'last'); + endpoints(2,idim) = knt_aux(ind+1); + end elseif (isvector (npts)) if (numel (npts) == 1) npts = npts * ones (1,ndim); From 79c04550498c39fb4f85db0478f54539cd916ed3 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 16:37:35 +0200 Subject: [PATCH 299/366] Value by default --- geopdes/inst/space/@sp_scalar/sp_plot_solution.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/space/@sp_scalar/sp_plot_solution.m b/geopdes/inst/space/@sp_scalar/sp_plot_solution.m index f76136bf..dae25a4e 100644 --- a/geopdes/inst/space/@sp_scalar/sp_plot_solution.m +++ b/geopdes/inst/space/@sp_scalar/sp_plot_solution.m @@ -31,7 +31,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function sp_plot_solution (u, space, geometry, npts, ncuts) +function sp_plot_solution (u, space, geometry, npts, ncuts, option) ndim = numel (space.knots); @@ -54,6 +54,10 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) end end +if (nargin < 6 || isempty (option)) + option = 'value'; +end + degree = space.degree; if (~exist ('vtk_pts', 'var')) for idim = 1:ndim @@ -61,7 +65,7 @@ function sp_plot_solution (u, space, geometry, npts, ncuts) end end -[eu, F] = sp_eval (u, space, geometry, vtk_pts); +[eu, F] = sp_eval (u, space, geometry, vtk_pts, option); rdim = size (F, 1); if (ndim == 1) From 8d9058a729fe6851cbaf8e6e0c06f9b2b24ad57a Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 16:39:00 +0200 Subject: [PATCH 300/366] Change in the penalty coefficient --- .../inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m | 1 + geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m | 1 + geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m | 1 + 3 files changed, 3 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m index 28952a68..3782b699 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m @@ -35,6 +35,7 @@ A = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, 3*msh.rdim*space.ndof); % Compute the matrices to impose the tangential boundary condition weakly + penalty_coeff = penalty_coeff * max (msh.msh_patch{1}.nel_dir); for iref = refs for bnd_side = 1:msh.boundaries(iref).nsides iptc = msh.boundaries(iref).patches(bnd_side); diff --git a/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m index 8b3287ce..dc9e3533 100644 --- a/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m @@ -36,6 +36,7 @@ A = spalloc (space.ndof, space.ndof, 3*space.ndof); % Compute the matrices to impose the tangential boundary condition weakly + penalty_coeff = penalty_coeff * max (msh.nel_dir); for iside = bnd_sides msh_side = msh_eval_boundary_side (msh, iside); diff --git a/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m index c3679ae8..dd819e7d 100644 --- a/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m @@ -36,6 +36,7 @@ A = spalloc (space.ndof, space.ndof, 3*space.ndof); % Compute the matrices to impose the tangential boundary condition weakly + penalty_coeff = penalty_coeff * max (msh.nel_dir); for iside = bnd_sides msh_side = msh_eval_boundary_side (msh, iside); From e0bbad65d06975b5e75e842db1ad06fcf9e8dcc4 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 19:26:15 +0200 Subject: [PATCH 301/366] Several changes in the help --- geopdes/inst/multipatch/@sp_multipatch/sp_to_vtk.m | 2 +- geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m | 2 +- .../multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m | 4 +--- .../multipatch/@sp_multipatch_C1/sp_get_basis_functions.m | 4 ++-- geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m | 4 ++-- .../@sp_multipatch_C1/sp_get_functions_on_patch.m | 2 +- .../inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m | 4 ++-- .../multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m | 3 +-- .../multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m | 2 +- geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m | 3 +++ geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m | 2 +- .../inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 6 +++++- geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m | 4 ++-- 13 files changed, 23 insertions(+), 19 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch/sp_to_vtk.m index a0c5a898..f008700c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_to_vtk.m @@ -6,7 +6,7 @@ % % u: vector of dof weights % space: object representing the space of discrete functions (see sp_multipatch) -% geometry: geometry structure (see geo_load) +% geometry: geometry structure (see mp_geo_load) % npts: number of points along each parametric direction where to evaluate % filename: name of the output file. % fieldnames: how to name the saved variables in the vtk file diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m index f24778e0..9c3939f0 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_eval_phys.m @@ -8,7 +8,7 @@ % space: object defining the discrete space (see sp_multipatch_C1) % geometry: geometry structure (see mp_geo_load) % pts: array (rdim x npts) with coordinates of points -% patch_list: patch to which each point begins. If empty, the patch +% patch_list: patch to which each point belongs. If empty, the patch % will be found using nrbinverse % options: cell array with the fields to plot % accepted options for scalars are 'value' (default), 'gradient', 'laplacian', 'hessian' diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m index 6e88b1e1..2884351a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_evaluate_element_list.m @@ -4,7 +4,7 @@ % % INPUTS: % -% space: object defining the space of discrete functions (see sp_multipatch) +% space: object defining the space of discrete functions (see sp_multipatch_C1) % msh_elems: structure containing the information of quadrature or % visualization points, for a given list of elements and patches % (see msh_multipatch/msh_evaluate_element_list) @@ -16,8 +16,6 @@ % gradient | false | compute shape_function_gradients % hessian | false | compute shape_function_hessians (only scalars) % laplacian | false | compute shape_function_laplacians (only scalars) -% div | false | compute shape_function_divs (only vectors) -% curl | false | compute shape_function_curls (only vectors) % % OUTPUT: % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m index e016ef0c..6651649d 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_basis_functions.m @@ -1,9 +1,9 @@ -% SP_GET_BASIS_FUNCTIONS: Compute the indices of tensor-product B-splines acting on a list of cells. +% SP_GET_BASIS_FUNCTIONS: Compute the indices of basis functions acting on a list of cells. % % fun_indices = sp_get_basis_functions (space, msh, indices) % % INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) +% space: object defining the space of discrete functions (see sp_multipatch_C1) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % indices: indices of the cells. % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m index 922c45f3..df6f058f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_cells.m @@ -1,9 +1,9 @@ -% SP_GET_CELLS: Compute the indices of the cells within the support of a list of tensor-product B-spline function. +% SP_GET_CELLS: Compute the indices of the cells within the support of a list of B-spline functions. % % [cell_indices, indices_per_function] = sp_get_cells (space, msh, indices) % % INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) +% space: object defining the space of discrete functions (see sp_multipatch_C1) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % indices: indices of the functions. % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m index e14e7386..b26f9e44 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_functions_on_patch.m @@ -1,6 +1,6 @@ % SP_GET_FUNCTIONS_ON_PATCH: Compute the indices of non-vanishing basis functions on a patch. % -% [Cpatch_cols] = sp_get_functions_on_patch (space, patch) +% [Cpatch_cols, dofs_interior, dofs_edge, dofs_vertex] = sp_get_functions_on_patch (space, patch) % % INPUT: % space: object defining the space of discrete functions (see sp_multipatch_C1) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m index 5a17a53e..3c911dcf 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_neighbors.m @@ -1,9 +1,9 @@ -% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions +% SP_GET_NEIGHBORS: Compute the indices of functions that share one element in the support of a given list of functions. % % neighbors_indices = sp_get_neighbors (space, msh, indices) % % INPUT: -% space: object defining the space of discrete functions (see sp_multipatch) +% space: object defining the space of discrete functions (see sp_multipatch_C1) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % indices: indices of the functions. % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m index 297d8e34..26ac5be2 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_get_vertex_neighbors.m @@ -1,5 +1,4 @@ -% SP_GET_VERTEX_NEIGHBORS: Compute the indices of elements in the support -% of vertex functions, separated by patches +% SP_GET_VERTEX_NEIGHBORS: Compute the indices of elements in the support of vertex functions, separated by patches. % % cell_indices = sp_get_vertex_neighbors (space, msh, vertex_index, patch_indices) % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m index 50290b47..7d72a4d9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_equiv_lap_error.m @@ -1,6 +1,6 @@ % SP_H2_EQUIV_LAP_ERROR: Evaluate the error in H^2 equivalent seminorm with laplacian, H^1 and L^2 norms. % -% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (sp, msh, u, uex, graduex, lapuex) +% [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_equiv_lap_error (sp, msh, u, uex, graduex, lapuex) % % INPUT: % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m index cc29069e..8daf912f 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_h2_error.m @@ -37,6 +37,9 @@ function [errh2, errh1, errl2, errh2s, errh1s] = sp_h2_error (space, msh, u, uex, graduex, hessuex) + if (msh.rdim == 3) + error ('The H2 error is only computed for planar surfaces') + end if (space.npatch ~= msh.npatch) error ('The number of patches does not coincide') end diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m index e826b89a..78981566 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_l2_error.m @@ -4,7 +4,7 @@ % % INPUT: % -% space: object defining the space of discrete functions (see sp_multipatch) +% space: object defining the space of discrete functions (see sp_multipatch_C1) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % u: vector of dof weights % uex: function handle to evaluate the exact solution diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 16bf7bb6..d45c22dd 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -38,7 +38,8 @@ % Methods for post-processing, that require a computed vector of degrees of freedom % sp_l2_error: compute the error in L2 norm % sp_h1_error: compute the error in H1 norm -% sp_h2_error: compute the error in H2 norm +% sp_h2_error: compute the error in H2 norm (only for planar surfaces) +% sp_eval_phys: compute the value of the solution in a given set of points % sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch % sp_plot_solution: plot the solution in Matlab % @@ -48,10 +49,13 @@ % sp_get_neighbors: compute the neighbors, functions that share at least one element with a given one % sp_get_functions_on_patch: compute the indices of non-vanishing C^1 functions on a patch % sp_get_local_interior_functions: compute the local indices of interior functions on a patch +% sp_get_vertex_neighbors: compute the indices of elements in the support of vertex functions % % Other methods % sp_refine: generate a refined space, and subdivision matrices for the univariate spaces % sp_compute_Cpatch: compute the matrix for B-splines representation on a patch +% sp_compute_Cpatch_vector: compute the matrix for B-splines representation on a patch +% for vector-valued spaces with the same space on each component % % Copyright (C) 2015-2023 Rafael Vazquez % Copyright (C) 2019-2023 Cesare Bracco diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m index f131ef2b..fd94f914 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_to_vtk.m @@ -5,8 +5,8 @@ % INPUT: % % u: vector of dof weights -% space: object representing the space of discrete functions (see sp_multipatch) -% geometry: geometry structure (see geo_load) +% space: object representing the space of discrete functions (see sp_multipatch_C1) +% geometry: geometry structure (see mp_geo_load) % npts: number of points along each parametric direction where to evaluate % filename: name of the output file. % fieldnames: how to name the saved variables in the vtk file From 5e2e36a6bfec3eebb91b4179e60a137bf31960e6 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 19 Jun 2024 19:38:38 +0200 Subject: [PATCH 302/366] More changes in the help --- .../@sp_multipatch_C1/sp_multipatch_C1.m | 2 +- .../@sp_multipatch_C1/sp_plot_solution.m | 20 +++++++++++-------- .../multipatch/@sp_multipatch_C1/sp_refine.m | 2 +- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index d45c22dd..15bb2a9a 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -41,7 +41,7 @@ % sp_h2_error: compute the error in H2 norm (only for planar surfaces) % sp_eval_phys: compute the value of the solution in a given set of points % sp_to_vtk: export the computed solution to a pvd file, using a Cartesian grid of points on each patch -% sp_plot_solution: plot the solution in Matlab +% sp_plot_solution: plot the solution in Matlab (only for the scalar-valued case) % % Methods for basic connectivity operations % sp_get_basis_functions: compute the functions that do not vanish in a given list of elements diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m index b7ec155e..8b889109 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_plot_solution.m @@ -35,14 +35,18 @@ function sp_plot_solution (u, space, geometry, varargin) % end hold_flag = ishold ; -for iptc = 1:space.npatch -% if (isempty (space.dofs_ornt)) - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - sp_plot_solution (Cpatch* u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), varargin{:}); -% else -% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); -% end - hold on +if (numel(u) == space.ndof) + for iptc = 1:space.npatch +% if (isempty (space.dofs_ornt)) + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + sp_plot_solution (Cpatch* u(Cpatch_cols), space.sp_patch{iptc}, geometry(iptc), varargin{:}); +% else +% sp_plot_solution (u(space.gnum{iptc}) .* space.dofs_ornt{iptc}.', space.sp_patch{iptc}, geometry(iptc), npts, ncuts); +% end + hold on + end +else + error ('Not implemented yet') end if (~hold_flag) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m index 8cc3ab2e..b9639ec3 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_refine.m @@ -7,7 +7,7 @@ % % INPUTS: % -% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch) +% space: the coarse space, an object of the sp_multipatch class (see sp_multipatch_C1) % msh: an object of the msh_multipatch class, usuallly the refined mesh (see msh_multipatch) % nsub: number of uniform subdivisions to apply on each knot span, and for each direction % degree: degree of the fine space, and for each direction From 54432b5025bc82af1d847c066465643736b1dcfb Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 17:11:39 +0200 Subject: [PATCH 303/366] Changes in the help --- .../@sp_multipatch_C1/op_KL_shells_mp.m | 2 +- .../@sp_multipatch_C1/op_su_ev_mp.m | 4 +- .../sp_bilaplacian_drchlt_C1.m | 4 +- .../sp_bilaplacian_drchlt_C1_exact.m | 7 +-- .../@sp_multipatch_C1/sp_drchlt_C1_shells.m | 46 ++++++++++++++++--- .../sp_nitsche_KL_rotation.m | 5 +- .../sp_weak_drchlt_bc_laplace.m | 6 +-- 7 files changed, 55 insertions(+), 19 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m index ba7837cc..dc48574e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_KL_shells_mp.m @@ -11,7 +11,7 @@ % E_coeff: function handle to compute the Young's modulus % nu_coeff: function handle to compute the Poisson's ratio % t_coeff: thickness of the shell, scalar value -% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. % OUTPUT: % diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m index e6a0a242..a0bc8d6e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_su_ev_mp.m @@ -4,8 +4,8 @@ % % INPUT: % -% spu: object representing the space of trial functions (see sp_multipatch) -% spv: object representing the space of test functions (see sp_multipatch) +% spu: object representing the space of trial functions (see sp_multipatch_C1) +% spv: object representing the space of test functions (see sp_multipatch_C1) % msh: object that defines the domain partition and the quadrature rule (see msh_multipatch) % lambda, mu: function handles to compute the Lame' coefficients % patches: list of patches where the integrals have to be computed. By default, all patches are selected. diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m index b7d149f4..cc55af15 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1.m @@ -1,11 +1,11 @@ % SP_BILAPLACIAN_DRCHLT_C1: assign the degrees of freedom of essential boundary conditions (value and normal derivative) through a projection. % On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. % -% [u, dofs] = sp_drchlt_l2_proj (sp, msh, refs, h, dudn) +% [u, dofs, kernel_info] = sp_bilaplacian_drchlt_C1 (sp, msh, refs, h, dudn) % % INPUT: % -% sp: object representing the multipatch space of trial functions (see sp_multipatch) +% sp: object representing the multipatch space of trial functions (see sp_multipatch_C1) % msh: object containing the domain partition and the quadrature rule (see msh_multipatch) % refs: boundary references on which the conditions are imposed % h: function handle to compute the Dirichlet condition diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m index 7940670d..87b8102c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact.m @@ -1,11 +1,12 @@ -% SP_BILAPLACIAN_DRCHLT_C1_EXACT: assign the degrees of freedom of essential boundary conditions (value and normal derivative) through a projection. +% SP_BILAPLACIAN_DRCHLT_C1_EXACT: assign the degrees of freedom of essential boundary conditions (value and normal derivative) +% through a projection, from a known exact solution. % On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. % -% [u, dofs] = sp_drchlt_l2_proj (sp, msh, refs, h, dudn) +% [u, dofs, kernel_info] = sp_bilaplacian_drchlt_C1_exact (sp, msh, refs, uex, graduex) % % INPUT: % -% sp: object representing the multipatch space of trial functions (see sp_multipatch) +% sp: object representing the multipatch space of trial functions (see sp_multipatch_C1) % msh: object containing the domain partition and the quadrature rule (see msh_multipatch) % refs: boundary references on which the conditions are imposed % uex: function handle to compute the Dirichlet condition from the exact solution diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m index 551658e7..d3b7e610 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m @@ -1,10 +1,44 @@ -function [u_drchlt, drchlt_dofs, kernel_info] = sp_drchlt_C1_shells (space, msh, refs, drchlt_components) - -% TODO: IT WILL ALWAYS SET THE VALUE TO ZERO +% SP_DRCHLT_C1_SHELLS: assign the degrees of freedom to impose zero displacement boundary conditions. +% On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. +% +% [u, dofs, kernel_info] = sp_drchlt_C1_shells (sp, msh, refs, drchlt_components) +% +% INPUT: +% +% sp: object representing the multipatch space of trial functions (see sp_multipatch_C1) +% msh: object containing the domain partition and the quadrature rule (see msh_multipatch) +% refs: boundary references on which the conditions are imposed +% drchlt_components: cell-array, the components that are set to zero for each drchlt_side +% +% OUTPUT: +% +% u: assigned value to the degrees of freedom +% dofs: global numbering of the corresponding basis functions +% kernel_info: a struct with information of kernel computation, containing: +% - vertices_numbers: vertices which contain a function in the kernel +% - all_vertex_dofs: all functions on those vertices +% - quasi_interior_dofs: functions that will be treated as +% internal ones (as many as in the kernel) +% - B_change_local: coefficients of the functions in the kernel, +% in terms of vertex basis functions. Matrix of size +% numel(all_vertex_dofs) x numel (quasi_interior_dofs) +% +% Copyright (C) 2022-2023 Cesare Bracco, Andrea Farahat, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . -% refs should be the whole boundary, for now -% M = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, msh.rdim*space.ndof); -% rhs = zeros (msh.rdim*space.ndof, 1); +function [u_drchlt, drchlt_dofs, kernel_info] = sp_drchlt_C1_shells (space, msh, refs, drchlt_components) drchlt_dofs = []; diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m index 3782b699..cb9332e1 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m @@ -4,8 +4,8 @@ % % INPUT: % -% space: space object (see sp_vector) -% msh: mesh object (see msh_cartesian) +% space: space object (see sp_multipatch_C1) +% msh: mesh object (see msh_multipatch) % bnd_sides: boundary sides on which the rotation free condition is imposed % E_coeff: function handle for the Young modulus % nu_coeff: function handle for the Poisson ratio @@ -30,6 +30,7 @@ % % You should have received a copy of the GNU General Public License % along with this program. If not, see . + function A = sp_nitsche_KL_rotation (space, msh, refs, E_coeff, nu_coeff, thickness, penalty_coeff) A = spalloc (msh.rdim*space.ndof, msh.rdim*space.ndof, 3*msh.rdim*space.ndof); diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m index 99901dc1..bfb0e87e 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_weak_drchlt_bc_laplace.m @@ -13,12 +13,12 @@ % and g the boundary condition to be imposed. % % -% [N_mat, N_rhs] = sp_weak_drchlt_bc_stokes (space, msh, refs, bnd_func, coeff, Cpen) +% [N_mat, N_rhs] = sp_weak_drchlt_bc_laplace (space, msh, refs, bnd_func, coeff, Cpen) % % INPUTS: % -% space_v: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch). -% msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) +% space_v: object for the multipatch space (see sp_multipatch_C1). +% msh: object for the multipatch mesh (see msh_multipatch) % refs: boundary sides on which the Dirichlet condition is imposed % bnd_func: the condition to be imposed (g in the equations) % coeff: function handle for the viscosity coefficient (mu in the equation) From cf0fb1e8db0ff10a740feddc34218bc038ee5cf7 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 17:11:50 +0200 Subject: [PATCH 304/366] Added help. Unfinished function. --- .../sp_drchlt_C1_exact_shells.m | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m index d4cf2ce4..2138d4f5 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_exact_shells.m @@ -1,3 +1,44 @@ +% SP_DRCHLT_C1_EXACT_SHELLS: assign the degrees of freedom of Dirichlet boundary conditions (displacement) through a projection. +% On boundary vertices, the kernel is computed to remove linear dependencies when restricting the functions to the boundary. +% THIS FUNCTION IS NOT IMPLEMENTED YET! +% +% [u, dofs, kernel_info] = sp_bilaplacian_drchlt_C1 (sp, msh, refs, uex) +% +% INPUT: +% +% sp: object representing the multipatch space of trial functions (see sp_multipatch_C1) +% msh: object containing the domain partition and the quadrature rule (see msh_multipatch) +% refs: boundary references on which the conditions are imposed +% uex: function handle to compute the Dirichlet condition from the exact displacement +% +% OUTPUT: +% +% u: assigned value to the degrees of freedom +% dofs: global numbering of the corresponding basis functions +% kernel_info: a struct with information of kernel computation, containing: +% - vertices_numbers: vertices which contain a function in the kernel +% - all_vertex_dofs: all functions on those vertices +% - quasi_interior_dofs: functions that will be treated as +% internal ones (as many as in the kernel) +% - B_change_local: coefficients of the functions in the kernel, +% in terms of vertex basis functions. Matrix of size +% numel(all_vertex_dofs) x numel (quasi_interior_dofs) +% +% Copyright (C) 2022-2023 Cesare Bracco, Andrea Farahat, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + function [u_drchlt, drchlt_dofs, kernel_info] = sp_drchlt_C1_exact_shells (space, msh, refs, uex) % TODO: IT WILL ALWAYS USE ALL THE COMPONENTS ON EACH SIDE (leave it like that) From b8ffe237c2300ee7d83c7d12ab055131caf9a17f Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 17:32:17 +0200 Subject: [PATCH 305/366] Changes in the help --- geopdes/inst/multipatch/mp_solve_bilaplace_C1.m | 2 +- ..._solve_kirchhoff_love_shell_C1_scalarspace.m | 2 +- geopdes/inst/multipatch/mp_solve_laplace_C1.m | 17 ++++------------- .../mp_solve_linear_elasticity_C1_scalarspace.m | 16 ++++------------ 4 files changed, 10 insertions(+), 27 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index 53410e0e..c01df29a 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -1,4 +1,4 @@ -% MP_SOLVE_BILAPLACE_C1: solve the bilaplacian problem in a multipatch geometry. +% MP_SOLVE_BILAPLACE_C1: solve the bilaplacian problem in an AS-G1 multipatch geometry. % % USAGE: % diff --git a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m index 48450852..d6269779 100644 --- a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m +++ b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m @@ -1,4 +1,4 @@ -% MP_SOLVE_KIRCHHOFF_LOVE_SHELL_C1_SCALARSPACE: Solve the Kirchhoff-Love shell model in a NURBS domain. +% MP_SOLVE_KIRCHHOFF_LOVE_SHELL_C1_SCALARSPACE: Solve the Kirchhoff-Love shell model in an AS-G1 multipatch domain. % It uses an object space of type sp_multipatch_C1 with scalar values, instead of vector valued. % % USAGE: diff --git a/geopdes/inst/multipatch/mp_solve_laplace_C1.m b/geopdes/inst/multipatch/mp_solve_laplace_C1.m index ddc79aae..92487921 100644 --- a/geopdes/inst/multipatch/mp_solve_laplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_laplace_C1.m @@ -1,4 +1,4 @@ -% MP_SOLVE_LAPLACE: solve the Laplacian problem in a multipatch geometry. +% MP_SOLVE_LAPLACE_C1: solve the Laplacian problem in a multipatch geometry, with C1 continuity. % % Example to solve the diffusion problem % @@ -6,12 +6,12 @@ % epsilon(x) du/dn = g on Gamma_N % u = h on Gamma_D % -% where the domain \Omega is formed by several patches of the form F((0,1)^n). +% where \Omega is an analysis-suitable G1 multipatch domain. % % USAGE: % % [geometry, msh, space, u] = -% mp_solve_laplace (problem_data, method_data) +% mp_solve_laplace_C1 (problem_data, method_data) % % INPUT: % @@ -35,7 +35,7 @@ % % geometry: array of geometry structures (see geo_load) % msh: multipatch mesh, consisting of several Cartesian meshes (see msh_multipatch) -% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch) +% space: multipatch space, formed by several tensor product spaces plus the connectivity (see sp_multipatch_C1) % u: the computed degrees of freedom % % Copyright (C) 2009, 2010 Carlo de Falco @@ -126,12 +126,3 @@ u = stiff_mat \ rhs; end - -%!demo -%! ex_laplace_Lshaped_mp - -%!demo -%! ex_laplace_cube_mp - -%!demo -%! ex_laplace_thick_L_mp diff --git a/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m index fd9ce2ee..96f29f9e 100644 --- a/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m +++ b/geopdes/inst/multipatch/mp_solve_linear_elasticity_C1_scalarspace.m @@ -8,7 +8,7 @@ % u = h on Gamma_D % % with sigma(u) = mu*(grad(u) + grad(u)^t) + lambda*div(u)*I, -% and the domain \Omega is formed by several patches of the form F((0,1)^n). +% and \Omega is an analysis-suitable G1 multipatch domain. % % u: displacement vector % sigma: Cauchy stress tensor @@ -18,19 +18,17 @@ % USAGE: % % [geometry, msh, space, u] = -% mp_solve_linear_elasticity (problem_data, method_data) +% mp_solve_linear_elasticity_C1_scalarspace (problem_data, method_data) % % INPUT: % % problem_data: a structure with data of the problem. It contains the fields: % - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition +% - nmnn_sides: sides with Neumann boundary condition (NOT IMPLEMENTED) +% - drchlt_sides: sides with Dirichlet boundary condition (ONLY HOMOGENEOUS CONDITIONS) % - lambda_lame: first Lame' parameter % - mu_lame: second Lame' parameter % - f: source term -% - h: function for Dirichlet boundary condition -% - g: function for Neumann condition (if nmnn_sides is not empty) % % method_data : a structure with discretization data. Its fields are: % - degree: degree of the spline functions. @@ -196,9 +194,3 @@ u(int_dofs) = mat(int_dofs, int_dofs) \ rhs(int_dofs); end - -%!demo -%! ex_plane_strain_Lshaped_mp - -%!demo -%! ex_lin_elast_cube_mp From 7c7f3e7493ccccd9cfbb2771037d7b68699f4bb0 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 18:02:10 +0200 Subject: [PATCH 306/366] Help --- geopdes/inst/multipatch/vertices_struct.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/vertices_struct.m b/geopdes/inst/multipatch/vertices_struct.m index be470b53..ab0c0a37 100644 --- a/geopdes/inst/multipatch/vertices_struct.m +++ b/geopdes/inst/multipatch/vertices_struct.m @@ -1,4 +1,4 @@ -% VERTICES_STRUCT: Compute interfaces and vertices struct, necessary to build the basis +% VERTICES_STRUCT: Compute interfaces and vertices struct, necessary to build the C1 basis % % [edges, vertices] = vertices_struct (geometry, interfaces, boundaries, boundary_interfaces) % From 3f8b9b6464047188f5dcadba0758118dc7c89831 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 18:04:57 +0200 Subject: [PATCH 307/366] Change in the help --- geopdes/inst/utils/op_KL_rotation_fluxes.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/utils/op_KL_rotation_fluxes.m b/geopdes/inst/utils/op_KL_rotation_fluxes.m index 5471dcaa..f2177352 100644 --- a/geopdes/inst/utils/op_KL_rotation_fluxes.m +++ b/geopdes/inst/utils/op_KL_rotation_fluxes.m @@ -22,7 +22,7 @@ % NOTES: % % 1) While normal has to be normalized (unit vector) T_t does not have to -% 2) Dabcd_ort is in tensor form. If the constitutive relationship is available in Voigt for it has to be converted +% 2) Dabcd_ort is in tensor form. If the constitutive relationship is available in Voigt form it has to be converted % 3) The quantities involved all refer to a single point along the boundary line % % From f6fcaf8e79353ab67c094540761900bda8f53542 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 18:07:34 +0200 Subject: [PATCH 308/366] Change in the help --- .../solve_linear_elasticity_scalarspace.m | 177 ++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 geopdes/inst/solve/solve_linear_elasticity_scalarspace.m diff --git a/geopdes/inst/solve/solve_linear_elasticity_scalarspace.m b/geopdes/inst/solve/solve_linear_elasticity_scalarspace.m new file mode 100644 index 00000000..6972f473 --- /dev/null +++ b/geopdes/inst/solve/solve_linear_elasticity_scalarspace.m @@ -0,0 +1,177 @@ +% SOLVE_LINEAR_ELASTICITY_SCALARSPACE: Solve a linear elasticity problem on a NURBS domain. +% It uses a scalar space of type sp_scalar, instead of sp_vector. +% +% The function solves the linear elasticity problem +% +% - div (sigma(u)) = f in Omega = F((0,1)^n) +% sigma(u) \cdot n = g on Gamma_N +% u = h on Gamma_D +% +% with sigma(u) = mu*(grad(u) + grad(u)^t) + lambda*div(u)*I. +% +% u: displacement vector +% sigma: Cauchy stress tensor +% lambda, mu: Lame' parameters +% I: identity tensor +% +% USAGE: +% +% [geometry, msh, space, u] = solve_linear_elasticity_scalarspace (problem_data, method_data) +% +% INPUT: +% +% problem_data: a structure with data of the problem. It contains the fields: +% - geo_name: name of the file containing the geometry +% - nmnn_sides: sides with Neumann boundary condition (may be empty) +% - drchlt_sides: sides with Dirichlet boundary condition (ONLY HOMOGENEOUS CONDITIONS) +% - press_sides: sides with pressure boundary condition (NOT IMPLEMENTED) +% - symm_sides: sides with symmetry boundary condition (NOT IMPLEMENTED) +% - lambda_lame: first Lame' parameter +% - mu_lame: second Lame' parameter +% - f: source term +% - g: function for Neumann condition (if nmnn_sides is not empty) +% +% method_data : a structure with discretization data. Its fields are: +% - degree: degree of the spline functions. +% - regularity: continuity of the spline functions. +% - nsub: number of subelements with respect to the geometry mesh +% (nsub=1 leaves the mesh unchanged) +% - nquad: number of points for Gaussian quadrature rule +% +% OUTPUT: +% +% geometry: geometry structure (see geo_load) +% msh: mesh object that defines the quadrature rule (see msh_cartesian) +% space: space object that defines the discrete basis functions (see sp_scalar) +% u: the computed degrees of freedom +% +% See also EX_LIN_ELAST_HORSESHOE for an example. +% +% Copyright (C) 2010 Carlo de Falco +% Copyright (C) 2011, 2015, 2022 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [geometry, msh, sp, u] = ... + solve_linear_elasticity_scalarspace (problem_data, method_data) + +% Extract the fields from the data structures into local variables +data_names = fieldnames (problem_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= problem_data.(data_names{iopt});']); +end +data_names = fieldnames (method_data); +for iopt = 1:numel (data_names) + eval ([data_names{iopt} '= method_data.(data_names{iopt});']); +end + +% Construct geometry structure +geometry = geo_load (geo_name); +degelev = max (degree - (geometry.nurbs.order-1), 0); +nurbs = nrbdegelev (geometry.nurbs, degelev); +[rknots, zeta, nknots] = kntrefine (nurbs.knots, nsub-1, nurbs.order-1, regularity); + +nurbs = nrbkntins (nurbs, nknots); +geometry = geo_load (nurbs); + +% Construct msh structure +rule = msh_gauss_nodes (nquad); +[qn, qw] = msh_set_quad_nodes (geometry.nurbs.knots, rule); +msh = msh_cartesian (geometry.nurbs.knots, qn, qw, geometry); + +% Construct space structure +sp = sp_nurbs (nurbs, msh); + +% Assemble the matrices +mat = op_su_ev_tp (sp, sp, msh, lambda_lame, mu_lame); +rhs = op_f_v_tp_vector (sp, msh, f); + +% Apply Neumann boundary conditions +for iside = nmnn_sides +% Restrict the function handle to the specified side, in any dimension, gside = @(x,y) g(x,y,iside) + gside = @(varargin) g(varargin{:},iside); + scalar_dofs = sp.boundary(iside).dofs; + dofs = []; + for icomp = 1:msh.rdim + dofs = union (dofs, (icomp-1)*sp.ndof + scalar_dofs); + end + rhs_loc = op_f_v_tp_vector (sp.boundary(iside), msh.boundary(iside), gside); + rhs(dofs) = rhs(dofs) + rhs_loc; +end + +% % % Apply pressure conditions +% % for iside = press_sides +% % msh_side = msh_eval_boundary_side (msh, iside); +% % sp_side = sp_eval_boundary_side (sp, msh_side); +% % +% % x = cell (msh_side.rdim, 1); +% % for idim = 1:msh_side.rdim +% % x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); +% % end +% % pval = reshape (p (x{:}, iside), msh_side.nqn, msh_side.nel); +% % +% % rhs(sp_side.dofs) = rhs(sp_side.dofs) - op_pn_v (sp_side, msh_side, pval); +% % end +% % +% % % Apply symmetry conditions +% % symm_dofs = []; +% % for iside = symm_sides +% % if (~strcmpi (sp.transform, 'grad-preserving')) +% % error ('The symmetry condition is only implemented for spaces with grad-preserving transform') +% % end +% % msh_side = msh_eval_boundary_side (msh, iside); +% % for idim = 1:msh.rdim +% % normal_comp(idim,:) = reshape (msh_side.normal(idim,:,:), 1, msh_side.nqn*msh_side.nel); +% % end +% % +% % parallel_to_axes = false; +% % for ind = 1:msh.rdim +% % ind2 = setdiff (1:msh.rdim, ind); +% % if (all (all (abs (normal_comp(ind2,:)) < 1e-10))) +% % symm_dofs = union (symm_dofs, sp.boundary(iside).dofs(sp.boundary(iside).comp_dofs{ind})); +% % parallel_to_axes = true; +% % break +% % end +% % end +% % if (~parallel_to_axes) +% % error ('solve_linear_elasticity: We have only implemented the symmetry condition for boundaries parallel to the axes') +% % end +% % +% % end + +% Apply Dirichlet boundary conditions +ndof = msh.rdim * sp.ndof; +u = zeros (ndof, 1); +% TO BE DONE. FOR NOW, ONLY HOMOGENEOUS CONDITIONS +drchlt_dofs = []; +for iside = 1:numel(drchlt_sides) + side = drchlt_sides(iside); + if (~exist('drchlt_components','var')) + components = 1:msh.rdim; + else + components = drchlt_components{iside}; + end + scalar_dofs = sp.boundary(side).dofs; + for icomp = components + drchlt_dofs = union (drchlt_dofs, (icomp-1)*sp.ndof + scalar_dofs); + end +end + +int_dofs = setdiff (1:ndof, drchlt_dofs); +rhs(int_dofs) = rhs(int_dofs) - mat(int_dofs, drchlt_dofs)*u(drchlt_dofs); + +% Solve the linear system +u(int_dofs) = mat(int_dofs, int_dofs) \ rhs(int_dofs); + +end From 2f6471b896edcb8a8dc73942055423f5fe3f7ae3 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 18:28:48 +0200 Subject: [PATCH 309/366] Preparing for new version --- geopdes/DESCRIPTION | 4 ++-- geopdes/INDEX | 28 +++++++++++++++++++++++++++- geopdes/NEWS | 15 +++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/geopdes/DESCRIPTION b/geopdes/DESCRIPTION index 39893562..fa00e383 100644 --- a/geopdes/DESCRIPTION +++ b/geopdes/DESCRIPTION @@ -1,6 +1,6 @@ Name: geopdes -Version: 3.2.2 -Date: 2021-04-07 +Version: 3.4.0 +Date: 2023-06-20 Author: Rafael Vazquez, Carlo de Falco Maintainer: Rafael Vazquez Title: Iso-Geometric Analysis diff --git a/geopdes/INDEX b/geopdes/INDEX index d5638fc1..0219f153 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -13,6 +13,7 @@ Solve: solvers for some simple problems, that you can modify to solve your own p solve_bilaplace_gradgrad_2d_iso solve_adv_diff_2d solve_linear_elasticity + solve_linear_elasticity_scalarspace solve_maxwell_eig solve_maxwell_eig_mixed1 solve_maxwell_eig_mixed2_2d @@ -20,6 +21,7 @@ Solve: solvers for some simple problems, that you can modify to solve your own p solve_navier_stokes solve_stokes solve_kirchhoff_love_shell + solve_kirchhoff_love_shell_scalarspace solve_BE_Beam Geometry: read geometry files, that can be created with the NURBS package geo_nurbs @@ -175,6 +177,28 @@ Multipatch: functions of different kinds to solve problems in domains defined by @sp_multipatch/sp_weak_drchlt_bc_laplace @sp_multipatch/sp_weak_drchlt_bc_stokes @sp_multipatch/sp_refine + sp_multipatch_C1 + @sp_multipatch/sp_l2_error + @sp_multipatch/sp_h1_error + @sp_multipatch/sp_h2_error + @sp_multipatch/sp_h2_equiv_lap_error + @sp_multipatch/sp_plot_solution + @sp_multipatch/sp_to_vtk + @sp_multipatch/sp_eval_phys + @sp_multipatch/sp_evaluate_element_list + @sp_multipatch/sp_get_cells + @sp_multipatch/sp_get_basis_functions + @sp_multipatch/sp_get_functions_on_patch + @sp_multipatch/sp_get_local_interior_functions + @sp_multipatch/sp_get_neighbors + @sp_multipatch/sp_compute_Cpatch + @sp_multipatch/sp_compute_Cpatch_vector + @sp_multipatch/sp_bilaplacian_drchlt_C1_exact + @sp_multipatch/sp_bilaplacian_drchlt_C1 + @sp_multipatch/sp_drchlt_C1_shells + @sp_multipatch/sp_nitsche_KL_rotation + @sp_multipatch/sp_weak_drchlt_bc_laplace + @sp_multipatch/sp_refine Utilities: other functions in the package collocation_csp knt_derham @@ -182,4 +206,6 @@ Utilities: other functions in the package msh_to_vtk newtons_method get_boundary_indices - get_volumetric_indices \ No newline at end of file + get_volumetric_indices + isotropic_stiffness + op_KL_rotation_fluxes \ No newline at end of file diff --git a/geopdes/NEWS b/geopdes/NEWS index 96f0f929..75947b27 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -1,3 +1,18 @@ +Summary of important changes for geopdes-3.4.0: +----------------------------------------------------------------------------- +* Added new class SP_MULTIPATCH_C1. +* Added solvers for C1 spaces: Laplace, bilaplace, linear elast., Kirchhoff-Love shell. +* Added solver for linear elasticity and Kirchhoff-Love using scalar spaces. + +Summary of important changes for geopdes-3.3.0: +----------------------------------------------------------------------------- +* Added functions to compute the exterior derivative. +* Added new operators: op_f_curlv_(mp,tp,3d), op_f_gradv_(mp,tp). + +Summary of important changes for geopdes-3.2.3: +----------------------------------------------------------------------------- +* Added new function: msh_get_neighbor_cells + Summary of important changes for geopdes-3.2.3: ----------------------------------------------------------------------------- * Added new function: msh_get_neighbor_cells From 57ac25a2ccb5d7e0bcd5fc8c1bc21b0399608098 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 11:22:51 +0100 Subject: [PATCH 310/366] Added new operators --- .../multipatch/@sp_multipatch/op_f_curlv_mp.m | 51 ++++++++++++++++ .../multipatch/@sp_multipatch/op_f_gradv_mp.m | 51 ++++++++++++++++ geopdes/inst/operators/op_f_curlv_3d.m | 59 +++++++++++++++++++ geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m | 52 ++++++++++++++++ geopdes/inst/space/@sp_vector/op_f_curlv_tp.m | 54 +++++++++++++++++ 5 files changed, 267 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m create mode 100644 geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m create mode 100644 geopdes/inst/operators/op_f_curlv_3d.m create mode 100644 geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m create mode 100644 geopdes/inst/space/@sp_vector/op_f_curlv_tp.m diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m new file mode 100644 index 00000000..30f6cdd3 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m @@ -0,0 +1,51 @@ +% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% +% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_curlv_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_curlv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + + if (~isempty (space.dofs_ornt)) + rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); + end + rhs(space.gnum{iptc}) = rhs(space.gnum{iptc}) + rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m new file mode 100644 index 00000000..e4072c54 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_gradv_mp.m @@ -0,0 +1,51 @@ +% OP_F_GRADV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, grad v_i), in a multipatch domain. +% +% rhs = op_f_gradv_mp (spv, msh, coeff, [patches]); +% +% INPUT: +% +% spv: object representing the function space (see sp_multipatch) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% coeff: function handle to compute the source function +% patches: list of patches where the integrals have to be computed. By default, all patches are selected. +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2015, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_gradv_mp (space, msh, coeff, patch_list) + + if (nargin < 4) + patch_list = 1:msh.npatch; + end + + if (space.npatch ~= msh.npatch) + error ('op_f_gradv_mp: the number of patches does not coincide') + end + + rhs = zeros (space.ndof, 1); + for iptc = patch_list + rhs_loc = op_f_gradv_tp (space.sp_patch{iptc}, msh.msh_patch{iptc}, coeff); + + if (~isempty (space.dofs_ornt)) + rhs_loc = space.dofs_ornt{iptc}(:) .* rhs_loc(:); + end + rhs(space.gnum{iptc}) = rhs(space.gnum{iptc}) + rhs_loc; + end + +end \ No newline at end of file diff --git a/geopdes/inst/operators/op_f_curlv_3d.m b/geopdes/inst/operators/op_f_curlv_3d.m new file mode 100644 index 00000000..10e215b3 --- /dev/null +++ b/geopdes/inst/operators/op_f_curlv_3d.m @@ -0,0 +1,59 @@ +% OP_F_curlV_3d: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i). +% +% rhs = op_f_curlv_3d (spv, msh, coeff); +% +% INPUT: +% +% spv: structure representing the function space (see sp_vector/sp_evaluate_col) +% msh: structure containing the domain partition and the quadrature rule (see msh_cartesian/msh_evaluate_col) +% coeff: source function evaluated at the quadrature points +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2009, 2010 Carlo de Falco +% Copyright (C) 2011, 2017, 2019, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_3d (spv, msh, coeff) + + coeff = reshape (coeff, spv.ncomp, [], msh.nqn, msh.nel); + + rhs = zeros (spv.ndof, 1); + curlv = reshape (spv.shape_function_curls, spv.ncomp, msh.nqn, spv.nsh_max, msh.nel); + + jacdet_weights = msh.jacdet .* msh.quad_weights; + + for iel = 1:msh.nel + if (all (msh.jacdet(:,iel))) + coeff_iel = reshape (coeff(:,:,:,iel), spv.ncomp, msh.nqn, 1, 1); + jacdet_iel = reshape (jacdet_weights(:, iel), [1, msh.nqn, 1, 1]); + coeff_times_jw = bsxfun (@times, jacdet_iel, coeff_iel); + + curlv_iel = reshape (curlv(:,:,:,iel), spv.ncomp, msh.nqn, spv.nsh_max, 1); + + aux_val = bsxfun (@times, coeff_times_jw, curlv_iel); + rhs_loc = sum (sum (aux_val, 1), 2); + + indices = find (spv.connectivity(:,iel)); + rhs_loc = rhs_loc(indices); conn_iel = spv.connectivity(indices,iel); + rhs(conn_iel) = rhs(conn_iel) + rhs_loc(:); + else + warning ('geopdes:jacdet_zero_at_quad_node', 'op_f_curlv_3d: singular map in element number %d', iel) + end + end + +end diff --git a/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m b/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m new file mode 100644 index 00000000..45a53beb --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_f_gradv_tp.m @@ -0,0 +1,52 @@ +% OP_F_GRADV_TP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, grad v_i), exploiting the tensor product structure. +% +% rhs = op_f_gradv_tp (spv, msh, coeff); +% +% INPUT: +% +% spv: object representing the function space (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% coeff: function handle to compute the source function +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2011, 2017, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_gradv_tp (space, msh, coeff) + + for idim = 1:msh.ndim + size1 = size (space.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + + rhs = zeros (space.ndof, 1); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'value', false, 'gradient', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + rhs = rhs + op_f_gradv (sp_col, msh_col, coeff (x{:})); + end + +end diff --git a/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m b/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m new file mode 100644 index 00000000..e0d268cc --- /dev/null +++ b/geopdes/inst/space/@sp_vector/op_f_curlv_tp.m @@ -0,0 +1,54 @@ +% OP_F_CURLV_TP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i), exploiting the tensor product structure. +% +% rhs = op_f_curlv_tp (spv, msh, coeff); +% +% INPUT: +% +% spv: object representing the function space (see sp_vector) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% coeff: function handle to compute the source function +% +% OUTPUT: +% +% rhs: assembled right-hand side +% +% Copyright (C) 2011, 2017, 2023 Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function rhs = op_f_curlv_tp (space, msh, coeff) + + for icomp = 1:space.ncomp_param + for idim = 1:msh.ndim + size1 = size (space.scalar_spaces{icomp}.sp_univ(idim).connectivity); + if (size1(2) ~= msh.nel_dir(idim)) + error ('The discrete space is not associated to the mesh') + end + end + end + + rhs = zeros (space.ndof, 1); + + for iel = 1:msh.nel_dir(1) + msh_col = msh_evaluate_col (msh, iel); + sp_col = sp_evaluate_col (space, msh_col, 'value', false, 'curl', true); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_col.geo_map(idim,:,:), msh_col.nqn, msh_col.nel); + end + + rhs = rhs + op_f_curlv_3d (sp_col, msh_col, coeff (x{:})); + end + +end From 14eef1a21968f7f3eedd876014b1228a7a6209a4 Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 11:27:08 +0100 Subject: [PATCH 311/366] Updated citation information --- geopdes/CITATION | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/geopdes/CITATION b/geopdes/CITATION index 125bfca1..aa9ba063 100644 --- a/geopdes/CITATION +++ b/geopdes/CITATION @@ -2,7 +2,7 @@ To cite the GeoPDEs package, please use R. Vazquez A new design for the implementation of isogeometric analysis in Octave and Matlab: GeoPDEs 3.0 - To appear in Computers and Mathematics with Applications + Computers and Mathematics with Applications, 72(3):523-554, 2016. C. de Falco, A. Reali, and R. Vazquez. GeoPDEs: A research tool for isogeometric analysis of PDEs. @@ -13,14 +13,17 @@ The BibTeX entries for LaTeX users are: @article{geopdes3.0, Author = {R. V{\'a}zquez}, Journal = {Computers and Mathematics with Applications}, + Number = {3}, + Pages = {523-554}, Title = {A new design for the implementation of isogeometric analysis in {O}ctave and {M}atlab: Geo{PDE}s 3.0}, Note = {To appear}, + Volume = {72}, Year = {2016}} @article{geopdes, Author = {C. de Falco and A. Reali and R. V{\'a}zquez}, Journal = {Advances in Engineering Software}, - Number = {12}, + Number = {3}, Pages = {1020-1034}, Title = {Geo{PDE}s: A research tool for Isogeometric Analysis of {PDE}s}, Volume = {42}, From f8cdc32107ab921bb5d89ef25b4a550d5ae87caf Mon Sep 17 00:00:00 2001 From: vazquez Date: Tue, 7 Mar 2023 18:34:40 +0100 Subject: [PATCH 312/366] Changes in the help --- geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m index 30f6cdd3..9d9f0bee 100644 --- a/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m +++ b/geopdes/inst/multipatch/@sp_multipatch/op_f_curlv_mp.m @@ -1,10 +1,10 @@ -% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, v_i), in a multipatch domain. +% OP_F_CURLV_MP: assemble the right-hand side vector r = [r(i)], with r(i) = (f, curl v_i), in a multipatch domain. % -% rhs = op_f_v_mp (spv, msh, coeff, [patches]); +% rhs = op_f_curlv_mp (spv, msh, coeff, [patches]); % % INPUT: % -% spv: object representing the function space (see sp_multipatch) +% spv: object representing the vector-valued function space (see sp_multipatch) % msh: object defining the domain partition and the quadrature rule (see msh_multipatch) % coeff: function handle to compute the source function % patches: list of patches where the integrals have to be computed. By default, all patches are selected. From 7c481e5442e52bf519e54358d3d80d90909c6089 Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 8 Mar 2023 14:19:30 +0100 Subject: [PATCH 313/366] Added exterior derivative --- .../@sp_multipatch/sp_exterior_derivative.m | 58 +++++++ geopdes/inst/operators/op_geom_exterior.m | 159 ++++++++++++++++++ .../space/@sp_scalar/sp_exterior_derivative.m | 71 ++++++++ .../space/@sp_vector/sp_exterior_derivative.m | 94 +++++++++++ 4 files changed, 382 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m create mode 100644 geopdes/inst/operators/op_geom_exterior.m create mode 100644 geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m create mode 100644 geopdes/inst/space/@sp_vector/sp_exterior_derivative.m diff --git a/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m b/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m new file mode 100644 index 00000000..0c2d6006 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch/sp_exterior_derivative.m @@ -0,0 +1,58 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (space1.npatch == space2.npatch, 'The spaces correspond to different domains') + npatch = space1.npatch; + + diff_op = sparse (space2.ndof, space1.ndof); + + for iptc = 1:npatch + Dmat = sp_exterior_derivative (space1.sp_patch{iptc}, space2.sp_patch{iptc}); + + ndof1 = space1.sp_patch{iptc}.ndof; + ndof2 = space2.sp_patch{iptc}.ndof; + if (isa (space1.sp_patch{iptc}, 'sp_vector')) + dofs_ornt = space1.dofs_ornt{iptc}; + Dornt_1 = spdiags (dofs_ornt(:), 0, ndof1, ndof1); + else + Dornt_1 = speye (ndof1, ndof1); + end + if (isa (space2.sp_patch{iptc}, 'sp_vector')) + dofs_ornt = space2.dofs_ornt{iptc}; + Dornt_2 = spdiags (dofs_ornt(:), 0, ndof2, ndof2); + else + Dornt_2 = speye (ndof2, ndof2); + end + gnum1 = space1.gnum{iptc}(:); + gnum2 = space2.gnum{iptc}(:); + diff_op(gnum2, gnum1) = Dornt_2 * Dmat * Dornt_1; + end + +end diff --git a/geopdes/inst/operators/op_geom_exterior.m b/geopdes/inst/operators/op_geom_exterior.m new file mode 100644 index 00000000..80767e34 --- /dev/null +++ b/geopdes/inst/operators/op_geom_exterior.m @@ -0,0 +1,159 @@ +function diff_ops = op_geom_exterior (knots, degrees, grad_curl, coo) + +% OP_GEOM_EXTERIOR: computes the exterior derivatives d_0,...,d_(n-1) +% starting from the H^1-conforming space of 0-forms which is deduced by the +% input knot vector and polynomial degrees +% +% diff_ops = op_geom_exterior (knots, degrees, [grad_curl]); +% +% INPUT: +% +% knots: initial knot vector +% degrees: polynomial degree(s) of the (multivariate) space of 0-forms +% grad_curl: can be either 'grad' or 'curl', a flag which denotes which +% sequence of operators is sought between the one starting with +% the gradient and the one starting with the rotated gradient. +% Only valid in the 2D case. Default value is 'grad'. +% coo: true if COO representation of sparse matrices is desired, +% false if Matlab sparse matrix representation is desired. +% Default value is false. +% +% +% OUTPUT: +% +% diff_ops: cell-array containing the (sparse) matrix representation of the +% differential operators. The k-th entry corresponds to the +% exterior derivative d_(k-1). +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + + + if nargin < 3 + grad_curl = 'grad'; + coo = false; + else + assert(ismember(grad_curl,{'grad','curl'}), ... + ' op_geom_exterior: Unrecognized input parameter!'); + if nargin < 4 + coo = false; + end + end + ndim = numel(knots); + + Id = cell(ndim,1); + Id_deriv = cell(ndim,1); + D_univ = cell(ndim,1); + + if strcmpi(grad_curl,'curl') + assert(ndim == 2, strcat(' op_geom_exterior: div-curl short exact sequence',... + ' only available in two dimensions!')); + end + + if ~iscell(knots) + knots = {knots}; + end + + if numel(degrees) == 1 + degrees = repmat(degrees,1,ndim); + end + + %% Build matrices for univariate differential operators + for kdim = 1:ndim + degree = degrees(kdim); + dim_univ = numel(knots{kdim})-degree-1; + dim_d_univ = dim_univ-1; + d_knots = knots{kdim}(2:end-1); + Id{kdim} = speye(dim_univ); + Id_deriv{kdim} = speye(dim_univ-1); + + scaling = degree./(abs(d_knots((1:dim_d_univ)+degree) - d_knots(1:dim_d_univ)).'); + + d_univ_rows = repmat((1:dim_d_univ).',1,2); + d_univ_cols = [ d_univ_rows(:,1), d_univ_rows(:,2)+1]; + d_univ_vals = bsxfun (@times, scaling(:), [ -ones(dim_d_univ,1), ones(dim_d_univ,1)]); + + D_univ{kdim} = sparse(d_univ_rows(:), ... + d_univ_cols(:), ... + d_univ_vals(:), ... + dim_d_univ,dim_univ,numel(d_univ_vals)); + end + + %% Assemble multivariate topologic differential operators + diff_ops = cell (ndim, 1); + switch ndim + case 1 + diff_ops{1} = D_univ{1}; + + case 2 + if strcmpi(grad_curl, 'grad') + diff_ops{1} = vertcat(kron(Id{2},D_univ{1}),kron(D_univ{2},Id{1})); + diff_ops{2} = horzcat(kron(kron(-1,D_univ{2}),Id_deriv{1}),... + kron(kron( 1,Id_deriv{2}),D_univ{1})); + else + diff_ops{1} = vertcat(kron(D_univ{2},Id{1}),-kron(Id{2},D_univ{1})); + diff_ops{2} = horzcat(kron(Id_deriv{2},D_univ{1}),... + kron(D_univ{2},Id_deriv{1})); + + end + + case 3 + diff_ops{1} = vertcat(kron(kron(Id{3},Id{2}),D_univ{1}),... + kron(kron(Id{3},D_univ{2}),Id{1}),... + kron(kron(D_univ{3},Id{2}),Id{1})); + + univ_c = cell(ndim,1); C = cell(ndim); + dim_imm = [ size(Id_deriv{3},2)*size(Id_deriv{2},2)*size(D_univ{1},2) + size(Id_deriv{3},2)*size(D_univ{2},2)*size(Id_deriv{1},2) + size(D_univ{3},2)*size(Id_deriv{2},2)*size(Id_deriv{1},2) ]; + dim_dom = [ size(Id{3},1)*size(Id{2},1)*size(D_univ{1},1) + size(Id{3},1)*size(D_univ{2},1)*size(Id{1},1) + size(D_univ{3},1)*size(Id{2},1)*size(Id{1},1) ]; + + for kdim = 1:ndim + transv_dir = setdiff(1:ndim,kdim); + C(kdim,:) = circshift({0, -1, 1},kdim-1,2); + C{kdim,kdim} = spalloc(dim_imm(kdim),dim_dom(kdim),0); + univ_c{kdim} = Id{kdim}; + + for mm = transv_dir + nn = setdiff(transv_dir,mm); + univ_c{mm} = Id_deriv{mm}; + univ_c{nn} = D_univ{nn}; + + for ll = ndim:-1:1 + C{kdim,mm} = kron(C{kdim,mm},univ_c{ll}); + end + end + end + + diff_ops{2} = vertcat(horzcat(C{1,:}),horzcat(C{2,:}),horzcat(C{3,:})); + diff_ops{3} = horzcat(kron(kron(Id_deriv{3},Id_deriv{2}),D_univ{1}),... + kron(kron(Id_deriv{3},D_univ{2}),Id_deriv{1}),... + kron(kron(D_univ{3},Id_deriv{2}),Id_deriv{1})); + + clear C + + otherwise + error(' op_geom_exterior: Not implemented for dimension greater than three'); + end + + if coo + for idim = 1:ndim + [rows, cols, vals] = find (diff_ops{idim}); + diff_ops{idim} = [rows, cols, vals]; + end + end + +end diff --git a/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m b/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m new file mode 100644 index 00000000..0cca33da --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/sp_exterior_derivative.m @@ -0,0 +1,71 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (strcmpi(space1.transform, 'grad-preserving'), ... + 'The first space cannot be the one for integral-preserving splines (or n-forms)') + + ndim = numel (space1.knots); + if (ndim == 1) + grad_curl = 'grad'; + assert (space1.degree == space2.degree+1, 'The degrees are not compatible') + assert (numel(space1.knots{1}) == numel(space2.knots{1})+2, 'The knot vectors are not compatible') + elseif (ndim == 2) + if (strcmpi (space2.transform, 'curl-preserving')) + grad_curl = 'grad'; + deg_shift = {[1 0], [0 1]}; + knt_shift = {[2 0], [0 2]}; + elseif (strcmpi (space2.transform, 'div-preserving')) + grad_curl = 'curl'; + deg_shift = {[0 1], [1 0]}; + knt_shift = {[0 2], [2 0]}; + else + error ('The second space should be either curl-preserving or div-preserving') + end + for idim = 1:ndim + assert (all(space1.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (ndim == 3) + grad_curl = 'grad'; + deg_shift = {[1 0 0], [0 1 0], [0 0 1]}; + knt_shift = {[2 0 0], [0 2 0], [0 0 2]}; + assert (strcmpi(space2.transform, 'curl-preserving'), ... + 'The second space should be the one for curl-conforming splines') + for idim = 1:ndim + assert (all(space1.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + end + + diff_ops = op_geom_exterior (space1.knots, space1.degree, grad_curl); + diff_op = diff_ops{1}; +end diff --git a/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m b/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m new file mode 100644 index 00000000..a2d5915e --- /dev/null +++ b/geopdes/inst/space/@sp_vector/sp_exterior_derivative.m @@ -0,0 +1,94 @@ +% SP_EXTERIOR_DERIVAITVE: computes the exterior derivative as a matrix with size +% given by the dimension of two consecutive spaces in the De Rham sequence. +% +% diff_op = sp_exterior_derivative (space1, space2); +% +% INPUT: +% +% space1: domain space of the exterior derivative (number of columns) +% space2: image space of the exterior derivative (number of rows) +% +% OUTPUT: +% +% diff_op: sparse matrix representation of the differential operator. +% +% Copyright (C) 2020-2023 Bernard Kapidani, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function diff_op = sp_exterior_derivative (space1, space2) + + assert (~strcmpi(space1.transform, 'integral-preserving'), ... + 'The first space cannot be the one for integral-preserving splines (or n-forms)') + + ndim = numel (space1.scalar_spaces{1}.knots); + if (ndim == 1) + error ('Not implemented. For dimension 1, use the scalar spaces') + elseif (ndim == 2) + if (strcmpi (space1.transform, 'curl-preserving')) + grad_curl = 'grad'; + output_der = 2; + deg_shift = {[0 1], [1 0]}; + knt_shift = {[0 2], [2 0]}; + degree = space1.scalar_spaces{1}.degree + [1 0]; + knots = {space1.scalar_spaces{2}.knots{1}, space1.scalar_spaces{1}.knots{2}}; + elseif (strcmpi (space1.transform, 'div-preserving')) + grad_curl = 'curl'; + output_der = 2; + deg_shift = {[1 0], [0 1]}; + knt_shift = {[2 0], [0 2]}; + degree = space1.scalar_spaces{1}.degree + [0 1]; + knots = {space1.scalar_spaces{1}.knots{1}, space1.scalar_spaces{2}.knots{2}}; + else + error ('The second space should be either curl-preserving or div-preserving') + end + assert (isa(space2, 'sp_scalar'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (ndim == 3) + grad_curl = 'grad'; + if (strcmpi (space1.transform, 'curl-preserving')) + output_der = 2; + deg_shift = {[-1 1 1], [1 -1 1], [1 1 -1]}; + knt_shift = {[-2 2 2], [2 -2 2], [2 2 -2]}; + degree = space1.scalar_spaces{1}.degree + [1 0 0]; + knots = {space1.scalar_spaces{2}.knots{1}, space1.scalar_spaces{1}.knots{2}, space1.scalar_spaces{1}.knots{3}}; + assert (isa(space2, 'sp_vector'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.scalar_spaces{idim}.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.scalar_spaces{idim}.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + elseif (strcmpi (space1.transform, 'div-preserving')) + output_der = 3; + deg_shift = {[1 0 0], [0 1 0], [0 0 1]}; + knt_shift = {[2 0 0], [0 2 0], [0 0 2]}; + degree = space1.scalar_spaces{1}.degree + [0 1 1]; + knots = {space1.scalar_spaces{1}.knots{1}, space1.scalar_spaces{2}.knots{2}, space1.scalar_spaces{3}.knots{3}}; + assert (isa(space2, 'sp_scalar'), 'The two spaces are not compatible') + for idim = 1:ndim + assert (all(space1.scalar_spaces{idim}.degree == space2.degree+deg_shift{idim}), 'The degrees are not compatible') + assert (all(cellfun(@numel,space1.scalar_spaces{idim}.knots) == (cellfun(@numel, space2.knots)+knt_shift{idim})), ... + 'The knot vectors are not compatible') + end + else + error ('Only implemented for curl-preserving and div-preserving transforms') + end + end + + diff_ops = op_geom_exterior (knots, degree, grad_curl); + diff_op = diff_ops{output_der}; +end From 5d295da0cac054a1d4f7b871368e918dc10bd5ad Mon Sep 17 00:00:00 2001 From: vazquez Date: Wed, 8 Mar 2023 16:25:11 +0100 Subject: [PATCH 314/366] Update --- geopdes/INDEX | 5 +++++ geopdes/NEWS | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/geopdes/INDEX b/geopdes/INDEX index d5638fc1..ca9461a4 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -62,6 +62,7 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_scalar/sp_evaluate_col_param @sp_scalar/sp_evaluate_element_list @sp_scalar/sp_evaluate_element_list_param + @sp_scalar/sp_exterior_derivative @sp_scalar/sp_h2_error @sp_scalar/sp_h1_error @sp_scalar/sp_l2_error @@ -83,6 +84,7 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_vector/sp_evaluate_col_param @sp_vector/sp_evaluate_element_list @sp_vector/sp_evaluate_element_list_param + @sp_vector/sp_exterior_derivative @sp_vector/sp_h2_error @sp_vector/sp_h1_error @sp_vector/sp_l2_error @@ -117,6 +119,7 @@ Operators: functions to assemble different matrices and vector op_eu_ev op_fdotn_vdotn op_fdotn_v + op_f_curlv_3d op_f_gradv op_f_vxn_2d op_f_vxn_3d @@ -140,6 +143,7 @@ Operators: functions to assemble different matrices and vector op_KL_shells op_KL_bending_stress op_KL_membrane_stress + op_geom_exterior Multipatch: functions of different kinds to solve problems in domains defined by multiple NURBS patches mp_dg_penalty mp_geo_load @@ -165,6 +169,7 @@ Multipatch: functions of different kinds to solve problems in domains defined by @sp_multipatch/sp_hcurl_error @sp_multipatch/sp_plot_solution @sp_multipatch/sp_to_vtk + @sp_multipatch/sp_exterior_derivative @sp_multipatch/sp_evaluate_element_list @sp_multipatch/sp_get_cells @sp_multipatch/sp_get_basis_functions diff --git a/geopdes/NEWS b/geopdes/NEWS index 96f0f929..f6cdf7a4 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -1,3 +1,8 @@ +Summary of important changes for geopdes-3.3.0: +----------------------------------------------------------------------------- +* Added functions to compute the exterior derivative. +* Added new operators: op_f_curlv_(mp,tp,3d), op_f_gradv_(mp,tp). + Summary of important changes for geopdes-3.2.3: ----------------------------------------------------------------------------- * Added new function: msh_get_neighbor_cells From 366bae8d7388e64cc23053e0338f42a096bf77ca Mon Sep 17 00:00:00 2001 From: vazquez Date: Fri, 17 Mar 2023 14:58:07 +0100 Subject: [PATCH 315/366] Change in the help --- geopdes/inst/operators/op_gradv_n_u.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/operators/op_gradv_n_u.m b/geopdes/inst/operators/op_gradv_n_u.m index ae20d32f..43305ffd 100644 --- a/geopdes/inst/operators/op_gradv_n_u.m +++ b/geopdes/inst/operators/op_gradv_n_u.m @@ -1,4 +1,4 @@ -% OP_GRADV_N_U: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon (grad v n)_j, u_i), with n the normal vector. +% OP_GRADV_N_U: assemble the matrix A = [a(i,j)], a(i,j) = (u_j, epsilon (grad v n)_i), with n the normal vector. % % mat = op_gradv_n_u (spu, spv, msh, epsilon); % [rows, cols, values] = op_gradv_n_u (spu, spv, msh, epsilon); From fd54501ccea7de3ed506df303ef3bd6c064fcbca Mon Sep 17 00:00:00 2001 From: Melina Merkel Date: Mon, 10 Jul 2023 11:27:56 +0200 Subject: [PATCH 316/366] fixed memory issue in mp_geo_load by introducing temporary variables --- geopdes/inst/multipatch/mp_geo_load.m | 28 +++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/multipatch/mp_geo_load.m b/geopdes/inst/multipatch/mp_geo_load.m index 4ee5ff65..30059abe 100644 --- a/geopdes/inst/multipatch/mp_geo_load.m +++ b/geopdes/inst/multipatch/mp_geo_load.m @@ -103,12 +103,13 @@ npatch = numel (geometry); for iptc = 1:npatch + tmp_nurbs = geometry(iptc).nurbs; geometry(iptc).map = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 0); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 0); geometry(iptc).map_der = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 1); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 1); geometry(iptc).map_der2 = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 2); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 2); end elseif (strcmpi (in(end-3:end), '.txt')) @@ -120,12 +121,13 @@ dim = numel (nurbs(1).knots); for iptc = 1:numel(nurbs) geometry(iptc).nurbs = nurbs(iptc); + tmp_nurbs = geometry(iptc).nurbs; geometry(iptc).map = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 0); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 0); geometry(iptc).map_der = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 1); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 1); geometry(iptc).map_der2 = ... - @(PTS) geo_nurbs (geometry(iptc).nurbs, PTS, 2); + @(PTS) geo_nurbs (tmp_nurbs, PTS, 2); end else error ('mp_geo_load: unknown file extension'); @@ -163,9 +165,10 @@ geometry(iptc).dnurbs = deriv; geometry(iptc).dnurbs2 = deriv2; - geometry(iptc).map = @(PTS) geo_nurbs (geometry(iptc).nurbs, deriv, deriv2, PTS, 0, rdim); - geometry(iptc).map_der = @(PTS) geo_nurbs (geometry(iptc).nurbs, deriv, deriv2, PTS, 1, rdim); - geometry(iptc).map_der2 = @(PTS) geo_nurbs (geometry(iptc).nurbs, deriv, deriv2, PTS, 2, rdim); + tmp_nurbs = geometry(iptc).nurbs; + geometry(iptc).map = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 0, rdim); + geometry(iptc).map_der = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 1, rdim); + geometry(iptc).map_der2 = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 2, rdim); if (numel (geometry(1).nurbs.order) > 1) bnd = nrbextract (geometry(iptc).nurbs); @@ -175,9 +178,10 @@ geometry(iptc).boundary(ibnd).dnurbs = deriv; geometry(iptc).boundary(ibnd).dnurbs2 = deriv2; geometry(iptc).boundary(ibnd).rdim = rdim; - geometry(iptc).boundary(ibnd).map = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 0, rdim); - geometry(iptc).boundary(ibnd).map_der = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 1, rdim); - geometry(iptc).boundary(ibnd).map_der2 = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 2, rdim); + tmp_bnd = bnd(ibnd); + geometry(iptc).boundary(ibnd).map = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 0, rdim); + geometry(iptc).boundary(ibnd).map_der = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 1, rdim); + geometry(iptc).boundary(ibnd).map_der2 = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 2, rdim); end end end From e263f558d1d11def0d0ccbe7f91a670fbd35475e Mon Sep 17 00:00:00 2001 From: Melina Merkel Date: Mon, 10 Jul 2023 13:30:11 +0200 Subject: [PATCH 317/366] fixed memory issue also in geo_load, geo_read_nurbs, mp_geo_read_nurbs --- geopdes/inst/geometry/geo_load.m | 19 +++++++++++-------- geopdes/inst/geometry/geo_read_nurbs.m | 8 ++++---- geopdes/inst/multipatch/mp_geo_read_nurbs.m | 7 ++++--- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/geopdes/inst/geometry/geo_load.m b/geopdes/inst/geometry/geo_load.m index 5fa70d0e..da81eaf5 100644 --- a/geopdes/inst/geometry/geo_load.m +++ b/geopdes/inst/geometry/geo_load.m @@ -93,9 +93,10 @@ geometry.dnurbs = deriv; geometry.dnurbs2 = deriv2; - geometry.map = @(PTS) geo_nurbs (geometry.nurbs, deriv, deriv2, PTS, 0, rdim); - geometry.map_der = @(PTS) geo_nurbs (geometry.nurbs, deriv, deriv2, PTS, 1, rdim); - geometry.map_der2 = @(PTS) geo_nurbs (geometry.nurbs, deriv, deriv2, PTS, 2, rdim); + tmp_nurbs = geometry.nurbs; + geometry.map = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 0, rdim); + geometry.map_der = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 1, rdim); + geometry.map_der2 = @(PTS) geo_nurbs (tmp_nurbs, deriv, deriv2, PTS, 2, rdim); if (numel (geometry.nurbs.order) > 1) bnd = nrbextract (geometry.nurbs); @@ -105,9 +106,10 @@ geometry.boundary(ibnd).dnurbs = deriv; geometry.boundary(ibnd).dnurbs2 = deriv2; geometry.boundary(ibnd).rdim = rdim; - geometry.boundary(ibnd).map = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 0, rdim); - geometry.boundary(ibnd).map_der = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 1, rdim); - geometry.boundary(ibnd).map_der2 = @(PTS) geo_nurbs (bnd(ibnd), deriv, deriv2, PTS, 2, rdim); + tmp_bnd = bnd(ibnd); + geometry.boundary(ibnd).map = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 0, rdim); + geometry.boundary(ibnd).map_der = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 1, rdim); + geometry.boundary(ibnd).map_der2 = @(PTS) geo_nurbs (tmp_bnd, deriv, deriv2, PTS, 2, rdim); end end if (strcmpi (wrn_struct.state, 'on')) @@ -115,8 +117,9 @@ end else for ibnd = 1:6 % This loop should be until 2*ndim, but ndim is not known - geometry.boundary(ibnd).map = @(PTS) boundary_map (geometry.map, ibnd, PTS); - geometry.boundary(ibnd).map_der = @(PTS) boundary_map_der (geometry.map, geometry.map_der, ibnd, PTS); + tmp_map = geometry.map; + geometry.boundary(ibnd).map = @(PTS) boundary_map (tmp_map, ibnd, PTS); + geometry.boundary(ibnd).map_der = @(PTS) boundary_map_der (tmp_map, geometry.map_der, ibnd, PTS); end end diff --git a/geopdes/inst/geometry/geo_read_nurbs.m b/geopdes/inst/geometry/geo_read_nurbs.m index a4f22078..c896fb88 100644 --- a/geopdes/inst/geometry/geo_read_nurbs.m +++ b/geopdes/inst/geometry/geo_read_nurbs.m @@ -123,10 +123,10 @@ else geom(iptc).nurbs.coefs(4,:,:,:) = str2num (line); end - - geom(iptc).map = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 0, rdim); - geom(iptc).map_der = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 1, rdim); - geom(iptc).map_der2 = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 2, rdim); + tmp_nurbs = geom(iptc).nurbs; + geom(iptc).map = @(PTS) geo_nurbs (tmp_nurbs, PTS, 0, rdim); + geom(iptc).map_der = @(PTS) geo_nurbs (tmp_nurbs, PTS, 1, rdim); + geom(iptc).map_der2 = @(PTS) geo_nurbs (tmp_nurbs, PTS, 2, rdim); end fclose (fid); diff --git a/geopdes/inst/multipatch/mp_geo_read_nurbs.m b/geopdes/inst/multipatch/mp_geo_read_nurbs.m index d9be82fa..54b7452d 100644 --- a/geopdes/inst/multipatch/mp_geo_read_nurbs.m +++ b/geopdes/inst/multipatch/mp_geo_read_nurbs.m @@ -146,9 +146,10 @@ end geom(iptc).nurbs.coefs(4,:,:,:) = reshape(str2num (line), geom(iptc).nurbs.number); - geom(iptc).map = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 0); - geom(iptc).map_der = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 1); - geom(iptc).map_der2 = @(PTS) geo_nurbs (geom(iptc).nurbs, PTS, 2); + tmp_nurbs = geom(iptc).nurbs; + geom(iptc).map = @(PTS) geo_nurbs (tmp_nurbs, PTS, 0); + geom(iptc).map_der = @(PTS) geo_nurbs (tmp_nurbs, PTS, 1); + geom(iptc).map_der2 = @(PTS) geo_nurbs (tmp_nurbs, PTS, 2); end interfaces = []; From 125a54076ff5de98f75a0af86dcc6a4ed69b595e Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 31 Oct 2023 11:37:12 +0100 Subject: [PATCH 318/366] Fixed number --- geopdes/CITATION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/CITATION b/geopdes/CITATION index aa9ba063..d38710eb 100644 --- a/geopdes/CITATION +++ b/geopdes/CITATION @@ -23,7 +23,7 @@ The BibTeX entries for LaTeX users are: @article{geopdes, Author = {C. de Falco and A. Reali and R. V{\'a}zquez}, Journal = {Advances in Engineering Software}, - Number = {3}, + Number = {12}, Pages = {1020-1034}, Title = {Geo{PDE}s: A research tool for Isogeometric Analysis of {PDE}s}, Volume = {42}, From 731e3a94a9fc73f1b4645cef0c862b6a4c30fec9 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 20:05:09 +0200 Subject: [PATCH 319/366] Added two geometries --- .../multipatch/geo_hyperboloid_ASG1.txt | 62 ++++++++++++++ .../multipatch/geo_paraboloid_ASG1.txt | 81 +++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_hyperboloid_ASG1.txt create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_paraboloid_ASG1.txt diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_hyperboloid_ASG1.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_hyperboloid_ASG1.txt new file mode 100644 index 00000000..a631cb1d --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_hyperboloid_ASG1.txt @@ -0,0 +1,62 @@ +# nurbs mesh v.2.1 +# +# 20-Jun-2024 +# +2 3 3 3 0 +PATCH 1 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-0.500000000000000 -0.500000000000000 -0.500000000000000 -0.375000000000000 -0.300000000000000 -0.225000000000000 -0.250000000000000 -0.100000000000000 0.050000000000000 +-0.500000000000000 0.000000000000000 0.500000000000000 -0.500000000000000 -0.150000000000000 0.200000000000000 -0.500000000000000 -0.300000000000000 -0.100000000000000 +0.000000000000000 0.500000000000000 0.000000000000000 -0.125000000000000 0.150000000000000 0.025000000000000 -0.187500000000000 -0.062500000000000 -0.007500000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.500000000000000 0.125000000000000 -0.250000000000000 0.500000000000000 0.200000000000000 -0.100000000000000 0.500000000000000 0.275000000000000 0.050000000000000 +-0.500000000000000 -0.500000000000000 -0.500000000000000 -0.225000000000000 -0.262500000000000 -0.300000000000000 0.050000000000000 -0.025000000000000 -0.100000000000000 +0.000000000000000 -0.375000000000000 -0.187500000000000 0.275000000000000 -0.062500000000000 -0.062500000000000 0.247500000000000 0.030000000000000 -0.007500000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.050000000000000 -0.225000000000000 -0.500000000000000 0.275000000000000 0.137500000000000 0.000000000000000 0.500000000000000 0.500000000000000 0.500000000000000 +-0.100000000000000 0.200000000000000 0.500000000000000 -0.025000000000000 0.237500000000000 0.500000000000000 0.050000000000000 0.275000000000000 0.500000000000000 +-0.007500000000000 0.025000000000000 0.000000000000000 0.030000000000000 -0.100000000000000 -0.500000000000000 0.247500000000000 0.225000000000000 0.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 2 +3 3 +-1 +INTERFACE 2 +1 4 +2 2 +1 +INTERFACE 3 +2 4 +3 1 +-1 +BOUNDARY 1 +1 +1 1 +BOUNDARY 2 +1 +1 3 +BOUNDARY 3 +1 +2 1 +BOUNDARY 4 +1 +2 3 +BOUNDARY 5 +1 +3 2 +BOUNDARY 6 +1 +3 4 diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_paraboloid_ASG1.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_paraboloid_ASG1.txt new file mode 100644 index 00000000..a5fb9961 --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_paraboloid_ASG1.txt @@ -0,0 +1,81 @@ +# nurbs mesh v.2.1 +# +# 20-Jun-2024 +# +2 3 4 4 0 +PATCH 1 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-1.000000000000000 -0.500000000000000 0.000000000000000 -1.000000000000000 -0.500000000000000 0.000000000000000 -1.000000000000000 -0.500000000000000 0.000000000000000 +-1.000000000000000 -1.000000000000000 -1.000000000000000 -0.500000000000000 -0.500000000000000 -0.500000000000000 0.000000000000000 0.000000000000000 0.000000000000000 +-1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.500000000000000 1.000000000000000 0.000000000000000 0.500000000000000 1.000000000000000 0.000000000000000 0.500000000000000 1.000000000000000 +-1.000000000000000 -1.000000000000000 -1.000000000000000 -0.500000000000000 -0.500000000000000 -0.500000000000000 0.000000000000000 0.000000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 -1.000000000000000 1.000000000000000 1.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 0.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-1.000000000000000 -0.500000000000000 0.000000000000000 -1.000000000000000 -0.500000000000000 0.000000000000000 -1.000000000000000 -0.500000000000000 0.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 1.000000000000000 1.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 -1.000000000000000 0.000000000000000 0.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 4 +2 2 +3 3 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.500000000000000 1.000000000000000 0.000000000000000 0.500000000000000 1.000000000000000 0.000000000000000 0.500000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +1.000000000000000 1.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 -1.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 2 +2 1 +1 +INTERFACE 2 +1 4 +3 3 +1 +INTERFACE 3 +2 4 +4 3 +1 +INTERFACE 4 +3 2 +4 1 +1 +BOUNDARY 1 +1 +1 1 +BOUNDARY 2 +1 +1 3 +BOUNDARY 3 +1 +2 2 +BOUNDARY 4 +1 +2 3 +BOUNDARY 5 +1 +3 1 +BOUNDARY 6 +1 +3 4 +BOUNDARY 7 +1 +4 2 +BOUNDARY 8 +1 +4 4 From ff7f830e9d458602399c0f07aeca5d32fe58ee3e Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 20 Jun 2024 19:59:10 +0200 Subject: [PATCH 320/366] Added planar geometries --- .../multipatch/geo_3patch_ASG1.txt | 59 ++++++++ .../multipatch/geo_6patch_ASG1.txt | 109 ++++++++++++++ .../multipatch/geo_Lshaped_8patches.txt | 139 ++++++++++++++++++ 3 files changed, 307 insertions(+) create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_3patch_ASG1.txt create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_6patch_ASG1.txt create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_Lshaped_8patches.txt diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_3patch_ASG1.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_3patch_ASG1.txt new file mode 100644 index 00000000..16ba9d53 --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_3patch_ASG1.txt @@ -0,0 +1,59 @@ +# nurbs mesh v.2.1 +# +# 16-Sep-2021 +# +2 2 3 3 0 +PATCH 1 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +5.666666666666667 5.666666666666667 5.633900000000000 5.439455555555556 5.277777777777778 5.000000000000000 6.208333333333333 6.241900000000000 6.241400000000000 6.147984000092007 6.036044193499551 5.833333333333333 6.777200000000000 6.808500000000000 6.812700000000000 6.782200000000000 6.714700000000000 6.666666666666667 7.999422222222222 7.990148739426865 8.015100000000000 8.061900000000000 8.192500000000001 8.333333333333334 8.652777777777779 8.701866960496190 8.601200000000000 8.699299999999999 8.841500000000000 9.166666666666666 9.250000000000000 9.291666666666666 9.229166666666666 9.333333333333334 9.500000000000000 10.000000000000000 +2.000000000000000 1.416666666666667 0.804900000000000 -0.361766666666667 -0.916666666666667 -1.500000000000000 2.166666666666667 1.506800000000000 0.851500000000000 -0.291639621880354 -0.899855334153224 -1.550000000000000 2.361400000000000 1.667300000000000 1.084600000000000 -0.169500000000000 -0.803900000000000 -1.425000000000000 2.813780952380952 2.170033757091749 1.574200000000000 0.382300000000000 -0.255800000000000 -0.900000000000000 3.071428571428572 2.405795068676388 1.891200000000000 0.724300000000000 0.119600000000000 -0.500000000000000 3.428571428571428 2.785714285714286 2.214285714285714 1.107142857142857 0.571428571428571 0.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +5.666666666666667 6.208333333333333 6.777200000000000 7.999422222222222 8.652777777777779 9.250000000000000 5.111111111111111 5.639155744403569 6.250564194121289 7.658478846315900 8.387925786693820 9.125000000000000 4.564169530533325 5.149800000000000 5.833100000000000 7.248200000000000 7.978800000000000 8.666666666666666 3.453058419422213 4.146219669571138 4.845400000000000 6.228700000000000 6.899100000000000 7.583333333333333 2.888888888888889 3.633748286311416 4.327800000000000 5.711600000000000 6.354700000000000 6.958333333333333 2.333333333333333 3.083333333333333 3.805555555555555 5.194444444444445 5.861111111111111 6.500000000000000 +2.000000000000000 2.166666666666667 2.361400000000000 2.813780952380952 3.071428571428572 3.428571428571428 2.350000000000000 2.592297513146954 2.840248105875064 3.312053453874116 3.623680658333797 4.035714285714286 2.707653301988516 2.991300000000000 3.303500000000000 3.944000000000000 4.303000000000000 4.642857142857143 3.407653301988516 3.898900251230890 4.290600000000000 5.067700000000000 5.395900000000000 5.714285714285714 3.750000000000000 4.277090978635564 4.834800000000000 5.583700000000000 5.927200000000000 6.178571428571429 4.250000000000000 4.825000000000000 5.325000000000000 6.100000000000000 6.375000000000000 6.500000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +5.666666666666667 5.111111111111111 4.564169530533325 3.453058419422213 2.888888888888889 2.333333333333333 5.666666666666667 5.064140447700447 4.450571739783129 3.253643116398854 2.660104826540696 2.111111111111111 5.633900000000000 4.990821066288887 4.326000000000000 3.047000000000000 2.432800000000000 1.805555555555556 5.439455555555556 4.690337572023205 3.904400000000000 2.433300000000000 1.722900000000000 1.027777777777778 5.277777777777778 4.490038555985794 3.628500000000000 2.064100000000000 1.312000000000000 0.555555555555556 5.000000000000000 4.166666666666667 3.333333333333333 1.666666666666667 0.833333333333333 0.000000000000000 +2.000000000000000 2.350000000000000 2.707653301988516 3.407653301988516 3.750000000000000 4.250000000000000 1.416666666666667 1.783478535111612 2.149553862334488 2.746877848337288 3.049844414866536 3.458333333333333 0.804900000000000 1.190897550616160 1.480500000000000 2.082500000000000 2.394400000000000 2.708333333333333 -0.361766666666667 -0.052514840751322 0.363000000000000 0.856700000000000 1.071800000000000 1.291666666666667 -0.916666666666667 -0.536330245690870 -0.169900000000000 0.271700000000000 0.452900000000000 0.625000000000000 -1.500000000000000 -1.000000000000000 -0.708333333333333 -0.291666666666667 -0.166666666666667 0.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 1 +2 3 +1 +INTERFACE 2 +1 3 +3 1 +1 +INTERFACE 3 +2 1 +3 3 +1 +BOUNDARY 1 +1 +1 2 +BOUNDARY 2 +1 +1 4 +BOUNDARY 3 +1 +2 2 +BOUNDARY 4 +1 +2 4 +BOUNDARY 5 +1 +3 2 +BOUNDARY 6 +1 +3 4 diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_6patch_ASG1.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_6patch_ASG1.txt new file mode 100644 index 00000000..42707423 --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_6patch_ASG1.txt @@ -0,0 +1,109 @@ +# nurbs mesh v.2.1 +# +# 17-Sep-2021 +# +2 2 6 8 0 +PATCH 1 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.555555555555556 0.538754000000000 0.514630000000000 0.477850000000000 0.459573000000000 0.423126000000000 0.407297000000000 0.388888888888889 1.111111111111111 1.073088000000000 1.036001000000000 0.959812000000000 0.922982000000000 0.850288000000000 0.815904000000000 0.779534000000000 2.222222222222222 2.148970000000000 2.074666000000000 1.926175000000000 1.851030000000000 1.701246000000000 1.626955000000000 1.555590170718171 2.777777777777778 2.686413000000000 2.593830000000000 2.407641000000000 2.314191000000000 2.123402000000000 2.028218000000000 1.941001230325230 3.888888888888889 3.761127000000000 3.632957000000000 3.374940000000000 3.243285000000000 2.976724000000000 2.841044541689422 2.718761700521700 4.444444444444445 4.296968000000000 4.149732000000000 3.860081000000000 3.710076000000000 3.401161869818234 3.254716800982721 3.111111111111111 5.000000000000000 4.833333333333333 4.665094626350675 4.330978987454352 4.165102055540688 3.832945895146845 3.666666666666667 3.500000000000000 +0.000000000000000 0.555555555555556 1.111111111111111 2.222222222222222 2.777777777777778 3.888888888888889 4.444444444444445 5.000000000000000 0.000000000000000 0.538754000000000 1.073087000000000 2.148971000000000 2.686402000000000 3.761123000000000 4.296910000000000 4.833333333333333 0.000000000000000 0.514628000000000 1.036005000000000 2.074664000000000 2.593824000000000 3.632927000000000 4.149714000000000 4.665149000000000 0.000000000000000 0.477847000000000 0.959800000000000 1.926154000000000 2.407592000000000 3.374879000000000 3.860064000000000 4.331040371866229 0.000000000000000 0.459546000000000 0.922955000000000 1.850958000000000 2.314095000000000 3.243142000000000 3.709955000000000 4.165116077065791 0.000000000000000 0.423101000000000 0.850194000000000 1.701097000000000 2.123182000000000 2.976477000000000 3.400916770384932 3.832929224466010 0.000000000000000 0.407186000000000 0.815829000000000 1.626831000000000 2.027968000000000 2.840779019473424 3.254566114678020 3.666666666666667 0.000000000000000 0.388888888888889 0.779622090367879 1.555694596239084 1.941033900631299 2.718742158067312 3.111111111111111 3.500000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +5.000000000000000 4.833333333333333 4.665094626350675 4.330978987454352 4.165102055540688 3.832945895146845 3.666666666666667 3.500000000000000 5.555555555555555 5.365906779541446 5.171951752991978 4.782608335716815 4.595086635155102 4.229527914681709 4.036059150292654 3.833333333333333 6.111111111111111 5.895785000000000 5.677173000000000 5.242318000000000 5.030509000000000 4.601894000000000 4.378820000000000 4.153006885776483 7.222222222222222 6.958372000000000 6.693215000000000 6.159557000000000 5.892878000000000 5.361997000000000 5.093826000000000 4.825344000000000 7.777777777777778 7.494054000000000 7.200309000000000 6.618518000000000 6.326534000000000 5.751704000000000 5.471074000000000 5.178007561780369 8.888888888888889 8.560335000000000 8.234724000000000 7.549803000000000 7.189648000000000 6.507249000000000 6.182962000000000 5.848668895113702 9.444444444444445 9.116581000000000 8.756610999999999 8.005255999999999 7.642483000000000 6.852490000000000 6.517942637122097 6.166666666666667 10.000000000000000 9.611111111111111 9.218025438523787 8.438085068849439 8.051230371762419 7.276632281782143 6.888888888888889 6.500000000000000 +0.000000000000000 0.388888888888889 0.779622090367879 1.555694596239084 1.941033900631299 2.718742158067312 3.111111111111111 3.500000000000000 0.000000000000000 0.420591777777778 0.844968720022595 1.690129648561377 2.113744976552004 2.976087241808016 3.408204966211953 3.833333333333333 0.000000000000000 0.452411000000000 0.907819000000000 1.830252000000000 2.295962000000000 3.233350000000000 3.698379000000000 4.152949940332169 0.000000000000000 0.518281000000000 1.047155000000000 2.121785000000000 2.673702000000000 3.762585000000000 4.299974000000000 4.825540000000000 0.000000000000000 0.551061000000000 1.100072000000000 2.266825000000000 2.862055000000000 4.042084000000000 4.621730000000000 5.178513452668995 0.000000000000000 0.627148000000000 1.297224000000000 2.659945000000000 3.329941000000000 4.618242000000000 5.257342000000000 5.849076786002328 0.000000000000000 0.741922000000000 1.506972000000000 2.919307000000000 3.558345000000000 4.962420000000000 5.551804619204887 6.166666666666667 0.500000000000000 1.166666666666667 1.850328465161853 3.191496650253986 3.849003036850930 5.169921378390606 5.833333333333333 6.500000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +6.500000000000000 6.777777777777778 7.022512918552806 7.571706000000000 7.876163940672165 8.451422051783277 8.722222222222221 9.000000000000000 6.888888888888889 7.101054949896628 7.368808000000000 7.867969000000000 8.171174000000001 8.775447000000000 9.074198000000001 9.444444444444445 7.276632281782143 7.495339351458582 7.707134000000000 8.202054000000000 8.457682999999999 9.088398000000000 9.450671000000000 9.899868285415877 8.051230371762419 8.234164138532279 8.450092000000000 8.841134000000000 9.031407000000000 9.736731000000001 10.233790000000001 10.792747025310454 8.438085068849439 8.662373106384416 8.834535000000001 9.167608000000000 9.334486000000000 10.059049999999999 10.599740000000001 11.230201924233601 9.218025438523787 9.547172119770202 9.680066000000000 9.823988999999999 9.818391000000000 10.638303000000001 11.292205795010991 12.111606189356150 9.611111111111111 10.032660718950281 10.188765999999999 10.082516000000000 10.057646999999999 10.825633000000000 11.643980751245202 12.555555555555555 10.000000000000000 10.555555555555555 10.666666666666666 10.333333333333334 10.333333333333334 11.000000000000000 12.000000000000000 13.000000000000000 +6.500000000000000 6.777777777777778 7.022441237842748 7.570491000000000 7.873877302092283 8.449742913203393 8.722222222222221 9.000000000000000 5.833333333333333 6.261046508037513 6.530781000000000 7.238151000000000 7.615201000000000 8.282449000000000 8.583602000000001 8.833333333333334 5.169921378390606 5.622616665957094 6.074879000000000 6.910491000000000 7.373786000000000 8.122790000000000 8.427854000000000 8.651497975436087 3.849003036850930 4.452495762327970 4.996953000000000 6.206679000000000 6.852805000000000 7.796005000000000 8.098515000000001 8.292923354461346 3.191496650253986 3.763790367049425 4.424093000000000 5.806057000000000 6.562814000000000 7.615157000000000 7.942868000000000 8.116184091383852 1.850328465161853 2.394394605192702 3.153263000000000 4.898824000000000 5.953903000000000 7.310550000000000 7.665293948538742 7.803055747486511 1.166666666666667 1.699765917425622 2.403326000000000 4.436763000000000 5.649632000000000 7.171176000000000 7.571680340325956 7.666666666666667 0.500000000000000 1.000000000000000 1.666666666666667 4.000000000000000 5.333333333333333 7.000000000000000 7.500000000000000 7.500000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 4 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +9.000000000000000 8.833333333333334 8.666666666666666 8.333333333333334 8.166666666666666 7.833333333333333 7.666666666666667 7.500000000000000 9.444444444444445 9.301107999854519 9.164541925415902 8.911942539000155 8.778108236019929 8.484561441670539 8.314441767616724 8.111111111111111 9.899868285415877 9.771549907186184 9.641442000000000 9.413301000000001 9.301876000000000 9.036213000000000 8.873398000000000 8.722222222222221 10.792747025310454 10.656989611438862 10.576582999999999 10.414116999999999 10.332606999999999 10.142944000000000 10.047751000000000 9.944444444444445 11.230201924233601 11.103316810976596 11.043013000000000 10.920389000000000 10.854734000000001 10.710418000000001 10.632490000000001 10.555555555555555 12.111606189356150 12.048774922368544 12.015010999999999 11.957814000000001 11.925755000000001 11.852790000000001 11.816579000000001 11.777777777777779 12.555555555555555 12.524827530580071 12.511968000000000 12.480362000000000 12.464917000000000 12.430043000000000 12.405848000000001 12.388888888888889 13.000000000000000 13.000000000000000 13.000000000000000 13.000000000000000 13.000000000000000 13.000000000000000 13.000000000000000 13.000000000000000 +9.000000000000000 9.444444444444445 9.888888888888889 10.777777777777779 11.222222222222221 12.111111111111111 12.555555555555555 13.000000000000000 8.833333333333334 9.309260429644429 9.770417398742820 10.642295839638667 11.091514840891504 12.034114691586858 12.512399324154515 13.000000000000000 8.651497975436087 9.161052819497458 9.640369000000000 10.570940999999999 11.034663999999999 12.006195000000000 12.508729000000001 13.000000000000000 8.292923354461346 8.882946194994123 9.399984999999999 10.413660999999999 10.919064000000001 11.957248000000000 12.478864000000000 13.000000000000000 8.116184091383852 8.731432682756873 9.275131000000000 10.330273999999999 10.852948000000000 11.925689000000000 12.464850000000000 13.000000000000000 7.803055747486511 8.426017494998201 9.013774000000000 10.139777000000000 10.709148000000001 11.853211999999999 12.430111000000000 13.000000000000000 7.666666666666667 8.289777251347390 8.860374000000000 10.046036000000001 10.631117000000000 11.816798000000000 12.405851000000000 13.000000000000000 7.500000000000000 8.111111111111111 8.722222222222221 9.944444444444445 10.555555555555555 11.777777777777779 12.388888888888889 13.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 5 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.500000000000000 1.000000000000000 1.913153000000000 4.035370000000000 5.254856000000000 6.964839000000000 7.500000000000000 7.500000000000000 1.166666666666667 1.713188818862578 2.517677000000000 4.481149000000000 5.596460000000000 7.163345000000000 7.601963000000000 7.666666666666667 1.850882000000000 2.407559654152397 3.168683000000000 4.929300000000000 5.939549000000000 7.324514000000000 7.719859000000000 7.833333333333333 3.191910581669772 3.763441931637984 4.423562000000000 5.802064000000000 6.564092000000000 7.644787000000000 7.988114860943798 8.166666666666666 3.848723830006211 4.451598288717544 4.996322000000000 6.206983000000000 6.851148000000000 7.811719000000000 8.131131125447776 8.333333333333334 5.169435205837991 5.623252586739892 6.073931000000000 6.909156000000000 7.373680000000000 8.126274000000000 8.435267867030323 8.666666666666666 5.833333333333333 6.260479647611377 6.530300070025519 7.238296406597696 7.616852417543083 8.283451271071502 8.581644088934606 8.833333333333334 6.500000000000000 6.777777777777778 7.022512918552806 7.571706000000000 7.876163940672165 8.451422051783277 8.722222222222221 9.000000000000000 +10.000000000000000 10.555555555555555 10.579674000000001 10.535035000000001 10.498073000000000 11.274652000000000 12.000000000000000 13.000000000000000 9.611111111111111 10.025187026445389 10.157757000000000 10.174182000000000 10.183543999999999 10.947870999999999 11.650861000000001 12.555555555555555 9.216182000000000 9.540692665377753 9.686377000000000 9.838100000000001 9.883319000000000 10.651572000000000 11.298000999999999 12.111111111111111 8.435238102364346 8.659095174322713 8.825214000000001 9.162715000000000 9.317045000000000 10.047299000000001 10.584697706905580 11.222222222222221 8.049223315839805 8.230933799110893 8.447523000000000 8.835201000000000 9.029226000000000 9.724311000000000 10.213602104934107 10.777777777777779 7.276048709102076 7.494930184980866 7.705419000000000 8.199792000000000 8.453001000000000 9.082490000000000 9.441989587518973 9.888888888888889 6.888888888888889 7.100535876610532 7.368390190867071 7.865859030766006 8.167980248476677 8.773565385818380 9.073359514654529 9.444444444444445 6.500000000000000 6.777777777777778 7.022441237842748 7.570491000000000 7.873877302092283 8.449742913203393 8.722222222222221 9.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 6 +3 3 +8 8 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.388888888888889 0.420665962962963 0.452258000000000 0.518027000000000 0.549192000000000 0.624641000000000 0.728406000000000 1.166666666666667 0.779534000000000 0.845021085643739 0.907977000000000 1.046258000000000 1.099113000000000 1.290064000000000 1.494464000000000 1.850882000000000 1.555590170718171 1.690305318468445 1.830363000000000 2.121464000000000 2.265239000000000 2.656781000000000 2.919942000000000 3.191910581669772 1.941001230325230 2.113983856634477 2.296197000000000 2.673661000000000 2.861507000000000 3.328983000000000 3.558204130998351 3.848723830006211 2.718761700521700 2.976249267814408 3.233519000000000 3.762660000000000 4.041702000000000 4.617943000000000 4.960593122118437 5.169435205837991 3.111111111111111 3.408283468374588 3.698572752129576 4.299906214706404 4.621350782884497 5.256340649422164 5.552305514484281 5.833333333333333 3.500000000000000 3.833333333333333 4.153006885776483 4.825344000000000 5.178007561780369 5.848668895113702 6.166666666666667 6.500000000000000 +5.000000000000000 5.555555555555555 6.111111111111111 7.222222222222222 7.777777777777778 8.888888888888889 9.444444444444445 10.000000000000000 4.833333333333333 5.365885414462081 5.895920000000000 6.958347000000000 7.495197000000000 8.560504999999999 9.124109000000001 9.611111111111111 4.665149000000000 5.171952947498110 5.677088000000000 6.693659000000000 7.200518000000000 8.237510000000000 8.759131999999999 9.216182000000000 4.331040371866229 4.782522058622119 5.242322000000000 6.159660000000000 6.619347000000000 7.550061000000000 8.003171000000000 8.435238102364346 4.165116077065791 4.594986867667381 5.030486000000000 5.892961000000000 6.326963000000000 7.189665000000000 7.642416780951086 8.049223315839805 3.832929224466010 4.229615069191183 4.601895000000000 5.362113000000000 5.752053000000000 6.507820000000000 6.852156474947033 7.276048709102076 3.666666666666667 4.036162961541651 4.378899174368473 5.093968218757987 5.471557676793573 6.183001541289816 6.518670138450728 6.888888888888889 3.500000000000000 3.833333333333333 4.152949940332169 4.825540000000000 5.178513452668995 5.849076786002328 6.166666666666667 6.500000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 2 +6 1 +1 +INTERFACE 2 +1 4 +2 3 +1 +INTERFACE 3 +2 2 +6 4 +1 +INTERFACE 4 +2 4 +3 1 +-1 +INTERFACE 5 +3 2 +4 1 +1 +INTERFACE 6 +3 3 +5 4 +1 +INTERFACE 7 +4 3 +5 2 +-1 +INTERFACE 8 +5 1 +6 2 +1 +BOUNDARY 1 +1 +1 1 +BOUNDARY 2 +1 +1 3 +BOUNDARY 3 +1 +2 1 +BOUNDARY 4 +1 +3 4 +BOUNDARY 5 +1 +4 2 +BOUNDARY 6 +1 +4 4 +BOUNDARY 7 +1 +5 3 +BOUNDARY 8 +1 +6 3 diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_Lshaped_8patches.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_Lshaped_8patches.txt new file mode 100644 index 00000000..be2e8bbd --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_Lshaped_8patches.txt @@ -0,0 +1,139 @@ +# nurbs mesh v.2.1 +# +# 20-Jun-2024 +# +2 2 8 13 0 +PATCH 1 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 1.000000000000000 -0.333333333333333 0.666666666666667 +0.000000000000000 0.000000000000000 0.333333333333333 0.333333333333333 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 -0.333333333333333 -0.333333333333333 +0.000000000000000 -1.000000000000000 0.333333333333333 -0.666666666666667 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +-0.333333333333333 0.000000000000000 -0.666666666666667 -1.000000000000000 +-0.666666666666667 -1.000000000000000 -0.666666666666667 -1.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 4 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +-1.000000000000000 -1.000000000000000 -0.666666666666667 -0.666666666666667 +-1.000000000000000 1.000000000000000 -0.666666666666667 0.666666666666667 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 5 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +-0.666666666666667 -0.666666666666667 -0.333333333333333 -0.333333333333333 +-0.666666666666667 0.666666666666667 -0.666666666666667 0.333333333333333 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 6 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +-0.666666666666667 0.666666666666667 -0.333333333333333 0.666666666666667 +0.666666666666667 0.666666666666667 0.333333333333333 0.333333333333333 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 7 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +-1.000000000000000 1.000000000000000 -0.666666666666667 0.666666666666667 +1.000000000000000 1.000000000000000 0.666666666666667 0.666666666666667 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 8 +1 1 +2 2 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 1.000000000000000 1.000000000000000 +0.666666666666667 0.666666666666667 1.000000000000000 1.000000000000000 +0.333333333333333 0.666666666666667 0.000000000000000 1.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 1 +2 1 +1 +INTERFACE 2 +1 2 +8 1 +-1 +INTERFACE 3 +1 4 +6 4 +1 +INTERFACE 4 +2 2 +3 3 +-1 +INTERFACE 5 +2 4 +5 4 +-1 +INTERFACE 6 +3 1 +5 1 +-1 +INTERFACE 7 +3 4 +4 1 +-1 +INTERFACE 8 +4 2 +7 1 +1 +INTERFACE 9 +4 4 +5 3 +1 +INTERFACE 10 +5 2 +6 1 +1 +INTERFACE 11 +6 2 +8 3 +-1 +INTERFACE 12 +6 3 +7 4 +1 +INTERFACE 13 +7 2 +8 2 +-1 +BOUNDARY 1 +1 +2 3 +BOUNDARY 2 +1 +1 3 +BOUNDARY 3 +1 +3 2 +BOUNDARY 4 +1 +4 3 +BOUNDARY 5 +1 +7 3 +BOUNDARY 6 +1 +8 4 From 063e9c739d17bdf27970feed39088709feddc939 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 11:03:16 +0200 Subject: [PATCH 321/366] Added geometry file --- .../geo_open_quasisphere_5p_ASG1.txt | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 geopdes/inst/examples/geometry_files/multipatch/geo_open_quasisphere_5p_ASG1.txt diff --git a/geopdes/inst/examples/geometry_files/multipatch/geo_open_quasisphere_5p_ASG1.txt b/geopdes/inst/examples/geometry_files/multipatch/geo_open_quasisphere_5p_ASG1.txt new file mode 100644 index 00000000..306aa9c2 --- /dev/null +++ b/geopdes/inst/examples/geometry_files/multipatch/geo_open_quasisphere_5p_ASG1.txt @@ -0,0 +1,94 @@ +# nurbs mesh v.2.1 +# +# 02-Dec-2021 +# +2 3 5 8 0 +PATCH 1 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -1.555555555555556 -1.792830136989621 -2.074313615081064 -2.074313615081064 -1.792830136989621 -1.555555555555556 -0.843731811253360 -0.984353779795587 -1.219052005864282 -1.219052005864282 -0.984353779795587 -0.843731811253360 0.843731811253360 0.984353779795587 1.219052005864282 1.219052005864282 0.984353779795587 0.843731811253360 1.555555555555556 1.792830136989621 2.074313615081064 2.074313615081064 1.792830136989621 1.555555555555556 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 +-2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 2 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -1.555555555555556 -1.792830136989621 -2.074313615081064 -2.074313615081064 -1.792830136989621 -1.555555555555556 -0.843731811253360 -0.984353779795587 -1.219052005864282 -1.219052005864282 -0.984353779795587 -0.843731811253360 0.843731811253360 0.984353779795587 1.219052005864282 1.219052005864282 0.984353779795587 0.843731811253360 1.555555555555556 1.792830136989621 2.074313615081064 2.074313615081064 1.792830136989621 1.555555555555556 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +-2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 +2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 2.222222222222222 2.497295067451282 2.833088549374007 2.833088549374007 2.497295067451282 2.222222222222222 2.453701082227536 2.833088549374007 3.466396953773710 3.466396953773710 2.833088549374007 2.453701082227536 2.453701082227536 2.833088549374007 3.466396953773710 3.466396953773710 2.833088549374007 2.453701082227536 2.222222222222222 2.497295067451282 2.833088549374007 2.833088549374007 2.497295067451282 2.222222222222222 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 3 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -1.555555555555556 -1.792830136989621 -2.074313615081064 -2.074313615081064 -1.792830136989621 -1.555555555555556 -0.843731811253360 -0.984353779795587 -1.219052005864282 -1.219052005864282 -0.984353779795587 -0.843731811253360 0.843731811253360 0.984353779795587 1.219052005864282 1.219052005864282 0.984353779795587 0.843731811253360 1.555555555555556 1.792830136989621 2.074313615081064 2.074313615081064 1.792830136989621 1.555555555555556 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 2.222222222222222 2.497295067451282 2.833088549374007 2.833088549374007 2.497295067451282 2.222222222222222 2.453701082227536 2.833088549374007 3.466396953773710 3.466396953773710 2.833088549374007 2.453701082227536 2.453701082227536 2.833088549374007 3.466396953773710 3.466396953773710 2.833088549374007 2.453701082227536 2.222222222222222 2.497295067451282 2.833088549374007 2.833088549374007 2.497295067451282 2.222222222222222 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +2.000000000000000 1.555555555555556 0.843731811253360 -0.843731811253360 -1.555555555555556 -2.000000000000000 2.222222222222222 1.792830136989621 0.984353779795587 -0.984353779795587 -1.792830136989621 -2.222222222222222 2.453701082227536 2.074313615081064 1.219052005864282 -1.219052005864282 -2.074313615081064 -2.453701082227536 2.453701082227536 2.074313615081064 1.219052005864282 -1.219052005864282 -2.074313615081064 -2.453701082227536 2.222222222222222 1.792830136989621 0.984353779795587 -0.984353779795587 -1.792830136989621 -2.222222222222222 2.000000000000000 1.555555555555556 0.843731811253360 -0.843731811253360 -1.555555555555556 -2.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 4 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -1.555555555555556 -1.792830136989621 -2.074313615081064 -2.074313615081064 -1.792830136989621 -1.555555555555556 -0.843731811253360 -0.984353779795587 -1.219052005864282 -1.219052005864282 -0.984353779795587 -0.843731811253360 0.843731811253360 0.984353779795587 1.219052005864282 1.219052005864282 0.984353779795587 0.843731811253360 1.555555555555556 1.792830136989621 2.074313615081064 2.074313615081064 1.792830136989621 1.555555555555556 2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 +2.000000000000000 1.555555555555556 0.843731811253360 -0.843731811253360 -1.555555555555556 -2.000000000000000 2.222222222222222 1.792830136989621 0.984353779795587 -0.984353779795587 -1.792830136989621 -2.222222222222222 2.453701082227536 2.074313615081064 1.219052005864282 -1.219052005864282 -2.074313615081064 -2.453701082227536 2.453701082227536 2.074313615081064 1.219052005864282 -1.219052005864282 -2.074313615081064 -2.453701082227536 2.222222222222222 1.792830136989621 0.984353779795587 -0.984353779795587 -1.792830136989621 -2.222222222222222 2.000000000000000 1.555555555555556 0.843731811253360 -0.843731811253360 -1.555555555555556 -2.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +PATCH 5 +3 3 +6 6 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +0.000000000000000 0.000000000000000 0.000000000000000 0.000000000000000 0.500000000000000 0.500000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +-2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.453701082227536 -2.833088549374007 -3.466396953773710 -3.466396953773710 -2.833088549374007 -2.453701082227536 -2.222222222222222 -2.497295067451282 -2.833088549374007 -2.833088549374007 -2.497295067451282 -2.222222222222222 -2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 +2.000000000000000 2.222222222222222 2.453701082227536 2.453701082227536 2.222222222222222 2.000000000000000 1.555555555555556 1.792830136989621 2.074313615081064 2.074313615081064 1.792830136989621 1.555555555555556 0.843731811253360 0.984353779795587 1.219052005864282 1.219052005864282 0.984353779795587 0.843731811253360 -0.843731811253360 -0.984353779795587 -1.219052005864282 -1.219052005864282 -0.984353779795587 -0.843731811253360 -1.555555555555556 -1.792830136989621 -2.074313615081064 -2.074313615081064 -1.792830136989621 -1.555555555555556 -2.000000000000000 -2.222222222222222 -2.453701082227536 -2.453701082227536 -2.222222222222222 -2.000000000000000 +-2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.453701082227536 -2.074313615081064 -1.219052005864282 1.219052005864282 2.074313615081064 2.453701082227536 -2.222222222222222 -1.792830136989621 -0.984353779795587 0.984353779795587 1.792830136989621 2.222222222222222 -2.000000000000000 -1.555555555555556 -0.843731811253360 0.843731811253360 1.555555555555556 2.000000000000000 +1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 1.000000000000000 +INTERFACE 1 +1 1 +4 2 +1 +INTERFACE 2 +1 2 +2 1 +1 +INTERFACE 3 +1 3 +5 4 +1 +INTERFACE 4 +2 2 +3 1 +1 +INTERFACE 5 +2 3 +5 2 +-1 +INTERFACE 6 +3 2 +4 1 +1 +INTERFACE 7 +3 3 +5 3 +-1 +INTERFACE 8 +4 3 +5 1 +1 +BOUNDARY 1 +1 +1 4 +BOUNDARY 2 +1 +2 4 +BOUNDARY 3 +1 +3 4 +BOUNDARY 4 +1 +4 4 From 66a9f5daf90bba4ce7e9f5d131ede8656b271d9a Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:07:49 +0200 Subject: [PATCH 322/366] Multipatch Kirchhoff-Love shell examples. --- .../ex_KL_3patch_hyperboloid_clamped.m | 46 +++++++++++++++++++ .../ex_KL_4patch_paraboloid.m | 43 +++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m create mode 100644 geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m new file mode 100644 index 00000000..50959ddf --- /dev/null +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m @@ -0,0 +1,46 @@ +clear problem_data method_data + +problem_data.geo_name = 'geo_hyperboloid_ASG1.txt'; + +problem_data.drchlt_sides = 2; +problem_data.drchlt_components = {[1 2 3]}; +problem_data.rotation_sides = 2; + +% Physical parameters +E = 2e11; +nu = 0.3; +thickness = 0.01; + +problem_data.E_coeff = @(x, y, z) E * ones(size(x)); +problem_data.nu_coeff = @(x, y, z) nu * ones(size(x)); +problem_data.thickness = thickness; + +% Source and boundary terms +hx = @(x, y, z) zeros(size(x)); +hy = @(x, y, z) zeros(size(x)); +% hz = @(x, y, z) 80000*ones(size(x)); +hz = @(x, y, z) -8000*thickness*ones(size(x)); + +problem_data.f = @(x, y, z, ind) cat(1, ... + reshape (hx (x,y,z), [1, size(x)]), ... + reshape (hy (x,y,z), [1, size(x)]), ... + reshape (hz (x,y,z), [1, size(x)])); + +% Discretization parameters +deg = 4; +method_data.degree = deg*[1 1]; % Degree of the splines +method_data.regularity = (deg-2)*[1 1]; % Regularity of the splines +method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = (deg+1)*[1 1]; % Points for the Gaussian quadrature rule +method_data.penalty_coeff = 10; + +[geometry, msh, space, u] = ... + mp_solve_kirchhoff_love_shell_C1_scalarspace (problem_data, method_data); +% K = op_KL_shells_mp (space, space, msh, problem_data.E_coeff, problem_data.nu_coeff, thickness); +% energy = 0.5 * u.' * K * u; +% displ = sp_eval_phys (u, space, geometry, [0.5; 0; 0.25]); + +output_file = 'hyperboloid_3patch'; +vtk_pts = {linspace(0, 1, 51), linspace(0, 1, 51)}; +fprintf ('The result is saved in the file %s \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'Displacement', 'value') diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m new file mode 100644 index 00000000..f940dd04 --- /dev/null +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m @@ -0,0 +1,43 @@ +clear problem_data method_data + +problem_data.geo_name = 'geo_paraboloid_ASG1.txt'; + +problem_data.drchlt_sides = [1 2 3 4 5 6 7 8]; +problem_data.drchlt_components = {[1 2 3] [1 2 3] [1 2 3] [1 2 3] [1 2 3] [1 2 3] [1 2 3] [1 2 3]}; + +% Physical parameters +E = 2e11; +nu = 0.3; +thickness = 0.01; + +problem_data.E_coeff = @(x, y, z) E * ones(size(x)); +problem_data.nu_coeff = @(x, y, z) nu * ones(size(x)); +problem_data.thickness = thickness; + +% Source and boundary terms +hx = @(x, y, z) zeros(size(x)); +hy = @(x, y, z) zeros(size(x)); +hz = @(x, y, z) 80000*ones(size(x)); + +problem_data.f = @(x, y, z, ind) cat(1, ... + reshape (hx (x,y,z), [1, size(x)]), ... + reshape (hy (x,y,z), [1, size(x)]), ... + reshape (hz (x,y,z), [1, size(x)])); + +% Discretization parameters +deg = 4; +method_data.degree = deg*[1 1]; % Degree of the splines +method_data.regularity = (deg-2)*[1 1]; % Regularity of the splines +method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = (deg+1)*[1 1]; % Points for the Gaussian quadrature rule + +[geometry, msh, space, u] = ... + mp_solve_kirchhoff_love_shell_C1_scalarspace (problem_data, method_data); +% K = op_KL_shells_mp (space, space, msh, problem_data.E_coeff, problem_data.nu_coeff, thickness); +% energy = 0.5 * u.' * K * u; +% displ = sp_eval_phys (u, space, geometry, [0 0.93; 0 0.93; 1 -0.7298]); + +output_file = 'paraboloid_4patch'; +vtk_pts = {linspace(0, 1, 51), linspace(0, 1, 51)}; +fprintf ('The result is saved in the file %s \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'Displacement', 'value') From 710a832ea32ac58ef283d2510ed997d7045596ee Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:22:52 +0200 Subject: [PATCH 323/366] Hyperboloid with one patch --- .../ex_KL_3patch_hyperboloid_clamped.m | 1 - .../ex_KL_hyperboloid_clamped.m | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m index 50959ddf..5b9dec32 100644 --- a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m @@ -18,7 +18,6 @@ % Source and boundary terms hx = @(x, y, z) zeros(size(x)); hy = @(x, y, z) zeros(size(x)); -% hz = @(x, y, z) 80000*ones(size(x)); hz = @(x, y, z) -8000*thickness*ones(size(x)); problem_data.f = @(x, y, z, ind) cat(1, ... diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m new file mode 100644 index 00000000..2fdadfaa --- /dev/null +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m @@ -0,0 +1,41 @@ +clear problem_data method_data + +nrb = nrb4surf ([-0.5, -0.5], [0.5, -0.5], [-0.5, 0.5], [0.5 0.5]); +nrb = nrbdegelev (nrb, [1 1]); +nrb.coefs (3,:,:) = [0 0.5 0; -0.5 0 -0.5; 0 0.5 0]; +problem_data.geo_name = nrb; + +problem_data.drchlt_sides = 1; +problem_data.drchlt_components = {[1 2 3]}; +problem_data.rotation_sides = 1; + +% Physical parameters +E = 2e11; +nu = 0.3; +thickness = 0.01; + +problem_data.E_coeff = @(x, y, z) E * ones(size(x)); +problem_data.nu_coeff = @(x, y, z) nu * ones(size(x)); +problem_data.thickness = thickness; + +% Source and boundary terms +hx = @(x, y, z) zeros(size(x)); +hy = @(x, y, z) zeros(size(x)); +hz = @(x, y, z) -8000*thickness*ones(size(x)); + +problem_data.f = @(x, y, z, ind) cat(1, ... + reshape (hx (x,y,z), [1, size(x)]), ... + reshape (hy (x,y,z), [1, size(x)]), ... + reshape (hz (x,y,z), [1, size(x)])); + +% Discretization parameters +deg = 3; +method_data.degree = deg*[1 1]; % Degree of the splines +method_data.regularity = (deg-1)*[1 1]; % Regularity of the splines +method_data.nsub = 16*[1 1]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = (deg+1)*[1 1]; % Points for the Gaussian quadrature rule +method_data.penalty_coeff = 10; + +[geometry, msh, space, u] = solve_kirchhoff_love_shell (problem_data, method_data); +pts = {[1], [0.5]}; +displ = sp_eval (u, space, geometry, pts) From 3c8f7cbd99a570a53e95ecc1eee20de28e701ced Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:28:25 +0200 Subject: [PATCH 324/366] Output to paraview --- .../kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m index 2fdadfaa..4b4f4a6a 100644 --- a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m @@ -39,3 +39,8 @@ [geometry, msh, space, u] = solve_kirchhoff_love_shell (problem_data, method_data); pts = {[1], [0.5]}; displ = sp_eval (u, space, geometry, pts) + +output_file = 'hyperboloid_1patch'; +vtk_pts = {linspace(0, 1, 51), linspace(0, 1, 51)}; +fprintf ('The result is saved in the file %s \n \n', output_file); +sp_to_vtk (u, space, geometry, vtk_pts, output_file, 'Displacement', 'value') From fddc7e0d39c67245120d602e6e79887ddcfd600d Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:43:43 +0200 Subject: [PATCH 325/366] Change in the help --- geopdes/inst/multipatch/mp_solve_bilaplace_C1.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m index c01df29a..0b8e5a5b 100644 --- a/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m +++ b/geopdes/inst/multipatch/mp_solve_bilaplace_C1.m @@ -9,8 +9,7 @@ % % problem_data: a structure with data of the problem. It contains the fields: % - geo_name: name of the file containing the geometry -% - nmnn_sides: sides with Neumann boundary condition (may be empty) -% - drchlt_sides: sides with Dirichlet boundary condition +% - drchlt_sides: sides with essential (Dirichlet and Neumann) boundary condition % - c_diff: diffusion coefficient % - f: source term % - g: function for Neumann condition From e8fb4b57e7cf33bfd930f807cb278adcdc6f1beb Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:44:13 +0200 Subject: [PATCH 326/366] Removed old file --- .../base/ex_bilaplacian_Lshape_5patch.m | 473 ------------------ 1 file changed, 473 deletions(-) delete mode 100644 geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m deleted file mode 100644 index 3d1d1f82..00000000 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshape_5patch.m +++ /dev/null @@ -1,473 +0,0 @@ -close all -clear all -% clc -warning ('off','geopdes:nrbmultipatch') - -% PHYSICAL DATA OF THE PROBLEM -% 5 patches (L-shape) -% p1=[0 0 1]; p2=[1 0 1]; p3=[1 1 1]; p4=[-1/3 1/3 1]; p5=[0 -1 1]; p6=[-2/3 -1/3 1]; p7=[-1 -1 1]; p8=[-2/3 1/3 1]; p9=[-1 1 1]; -% nrb(1) = nrb4surf(p1,p2,p4,p3); -% nrb(2) = nrb4surf(p5,p1,p7,p6); -% nrb(3) = nrb4surf(p7,p6,p9,p8); -% nrb(4) = nrb4surf(p6,p1,p8,p4); -% nrb(5) = nrb4surf(p8,p4,p9,p3); -% -% problem_data.geo_name = nrb; - -% coefs_1(:,1,:)=[0 0 1; 1 0 1]; -% coefs_1(:,2,:)=[-1/3 1/3 1; 1 1 1]; -% -% coefs_2(:,1,:)=[-1 -1 1; 0 -1 1]; -% coefs_2(:,2,:)=[-2/3 -1/3 1; 0 0 1]; -% -% coefs_3(:,1,:)=[-1 -1 1; -2/3 -1/3 1]; -% coefs_3(:,2,:)=[-1 1 1; -2/3 1/3 1]; -% -% coefs_4(:,1,:)=[-2/3 -1/3 1; 0 0 1]; -% coefs_4(:,2,:)=[-2/3 1/3 1; -1/3 1/3 1]; -% -% coefs_5(:,1,:)=[-2/3 1/3 1; -1/3 1/3 1]; -% coefs_5(:,2,:)=[-1 1 1; 1 1 1]; -% -% -% knots{1} = [0 0 1 1]; -% knots{2} = [0 0 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -% butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% nrb(4)=butterf4; -% nrb(5)=butterf5; -% -% problem_data.geo_name = nrb; - -% % 3 patch surf parabolic -% coefs_1(:,3,:)=[0.125 -0.125 0.96875; 0.4625 0.1375 0.95; 0.8 0.4 0.2]; -% coefs_1(:,2,:)=[-0.3125 0.1875 1.15625; 0.04375 0.44375 1.2625; 0.4 0.7 0.6]; -% coefs_1(:,1,:)=[-0.75 0.5 0.1875;-0.375 0.75 0.5; 0.0 1.0 0.0]; -% -% coefs_2(:,3,:)=[0.125 -0.125 0.96875; 0.0125 -0.5125 0.9; -0.1 -0.9 0.18]; -% coefs_2(:,2,:)=[0.4625 0.1375 0.95; 0.42375 -0.28125 1.134375; 0.385 -0.7 0.637]; -% coefs_2(:,1,:)=[0.8 0.4 0.2; 0.835 -0.05 0.504; 0.87 -0.5 -0.0069]; -% -% coefs_3(:,3,:)=[0.125 -0.125 0.96875; -0.3125 0.1875 1.15625; -0.75 0.5 0.1875]; -% coefs_3(:,2,:)=[0.0125 -0.5125 0.9; -0.39875 -0.25625 1.210625; -0.81 0.0 0.5975]; -% coefs_3(:,1,:)=[-0.1 -0.9 0.18; -0.485 -0.7 0.463; -0.87 -0.5 -0.0069]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% % nrb(1)=nrbtform (nrb(1), vecrot(pi/3,[1 2 3])); -% % nrb(2)=nrbtform (nrb(2), vecrot(pi/3,[1 2 3])); -% % nrb(3)=nrbtform (nrb(3), vecrot(pi/3,[1 2 3])); -% problem_data.geo_name = nrb; - -% 5 patch surf parabolic -% coefs_1(:,1,:)=[0.125 -0.125 0.96875; 0.4375 0.2875 0.99375; 0.75 0.7 -0.0525]; -% coefs_1(:,2,:)=[-0.2375 0.3375 1.175; 0.06875 0.59375 1.0075; 0.375 0.85 0.3]; -% coefs_1(:,3,:)=[-0.6 0.8 0.0; -0.3 0.9 0.2; 0.0 1.0 0.0]; -% -% coefs_2(:,1,:)=[0.125 -0.125 0.96875; -0.2375 0.3375 1.175; -0.6 0.8 0.0]; -% coefs_2(:,2,:)=[-0.3875 -0.1625 1.0875; -0.58125 0.19625 0.88875; -0.775 0.555 0.182]; -% coefs_2(:,3,:)=[-0.9 -0.2 0.15; -0.925 0.055 0.207; -0.95 0.31 0.0014]; -% -% coefs_3(:,1,:)=[0.125 -0.125 0.96875; -0.3875 -0.1625 1.0875; -0.9 -0.2 0.15]; -% coefs_3(:,2,:)=[0.1125 -0.5458333333333333 0.8666666666666667; -0.29375 -0.5354166666666667 0.9264583333333334; -0.7 -0.525 0.38]; -% coefs_3(:,3,:)=[0.1 -0.9666666666666667 0.05555555555555555; -0.2 -0.9083333333333333 0.22833333333333333; -0.5 -0.85 0.0275]; -% -% coefs_4(:,1,:)=[0.125 -0.125 0.96875; 0.1125 -0.5458333333333333 0.8666666666666667; 0.1 -0.9666666666666667 0.05555555555555555]; -% coefs_4(:,2,:)=[0.5125 -0.2625 0.8375; 0.40625 -0.5854166666666667 0.6772916666666666; 0.3 -0.9083333333333333 0.12833333333333333]; -% coefs_4(:,3,:)=[0.9 -0.4 0.03; 0.7 -0.625 0.21; 0.5 -0.85 0.0275]; -% -% coefs_5(:,1,:)=[0.125 -0.125 0.96875; 0.5125 -0.2625 0.8375; 0.9 -0.4 0.03]; -% coefs_5(:,2,:)=[0.4375 0.2875 0.99375; 0.68125 0.12125 0.7625; 0.925 -0.045 0.269]; -% coefs_5(:,3,:)=[0.75 0.7 -0.0525; 0.85 0.505 0.0705; 0.95 0.31 0.0014]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -% butterf5 = nrbmak(permute(coefs_5,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% nrb(4)=butterf4; -% nrb(5)=butterf5; -% problem_data.geo_name = nrb; - - -% % 4 patch surf hyperbolic smooth boundary -coefs_1(:,1,:)=[-0.5 -0.5 0.0; -0.25 -0.5 -0.25; 0.0 -0.5 -0.25]; -coefs_1(:,2,:)=[-0.5 -0.2 0.3; -0.2375 -0.25 -0.0125; 0.025 -0.3 -0.05]; -coefs_1(:,3,:)=[-0.5 0.1 0.24; -0.225 0.0 -0.015; 0.05 -0.1 -0.0075]; - -coefs_2(:,1,:)=[0.5 -0.5 0.0; 0.5 -0.225 0.275; 0.5 0.05 0.2475]; -coefs_2(:,2,:)=[0.25 -0.5 -0.25; 0.2625 -0.2625 0.0; 0.275 -0.025 0.03]; -coefs_2(:,3,:)=[0.0 -0.5 -0.25; 0.025 -0.3 -0.05; 0.05 -0.1 -0.0075]; - -coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.275 -0.025 0.03; 0.5 0.05 0.2475]; -coefs_3(:,2,:)=[0.0 0.2 0.0475; 0.25 0.2375 0.0125; 0.5 0.275 0.225]; -coefs_3(:,3,:)=[-0.05 0.5 -0.2475; 0.225 0.5 -0.275; 0.5 0.5 0.0]; - -coefs_4(:,1,:)=[-0.5 0.5 0.0; -0.5 0.3 0.2; -0.5 0.1 0.24]; -coefs_4(:,2,:)=[-0.275 0.5 -0.225; -0.25 0.25 0.0; -0.225 0.0 -0.015]; -coefs_4(:,3,:)=[-0.05 0.5 -0.2475; 0.0 0.2 0.0475; 0.05 -0.1 -0.0075]; - -knots{1} = [0 0 0 1 1 1]; -knots{2} = [0 0 0 1 1 1]; - -butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); - -nrb(1)=butterf1; -nrb(2)=butterf2; -nrb(3)=butterf3; -nrb(4)=butterf4; -problem_data.geo_name = nrb; - -% 4 patch surf hyperbolic non smooth boundary -% coefs_1(:,1,:)=[-1.2 -1.0 0.44; -0.65 -1.1 -1.08; -0.1 -1.2 -1.43]; -% coefs_1(:,2,:)=[-1.3 -0.6 1.48; -0.625 -0.575 -0.12; 0.05 -0.55 0.1]; -% coefs_1(:,3,:)=[-1.4 -0.2 1.92; -0.6 -0.05 -0.26; 0.2 0.1 0.03]; -% -% coefs_2(:,1,:)=[-0.1 -1.2 -1.43; 0.45 -1.1 -1.3; 1.0 -1.0 0.0]; -% coefs_2(:,2,:)=[0.05 -0.55 0.1; 0.625 -0.625 -0.16; 1.2 -0.7 1.0]; -% coefs_2(:,3,:)=[0.2 0.1 0.03; 0.8 -0.15 0.32; 1.4 -0.4 1.8]; -% -% coefs_3(:,1,:)=[0.2 0.1 0.03; 0.8 -0.15 0.32; 1.4 -0.4 1.8]; -% coefs_3(:,2,:)=[0.1 0.75 -0.14; 0.65 0.475 0.34; 1.2 0.2 1.72]; -% coefs_3(:,3,:)=[0.0 1.4 -1.96; 0.5 1.1 -1.12; 1.0 0.8 0.36]; -% -% coefs_4(:,1,:)=[-1.4 -0.2 1.92; -0.6 -0.05 -0.26; 0.2 0.1 0.03]; -% coefs_4(:,2,:)=[-1.2 0.2 1.52; -0.55 0.475 0.01; 0.1 0.75 -0.14]; -% coefs_4(:,3,:)=[-1.0 0.6 0.64; -0.5 1.0 -0.84; 0.0 1.4 -1.96]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% butterf4 = nrbmak(permute(coefs_4,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% nrb(4)=butterf4; -% problem_data.geo_name = nrb; - -% 3 patch surf hyperbolic non smooth boundary -% coefs_1(:,1,:)=[-0.75 -0.5 0.3125; -0.5416666666666666 -0.75 -0.25; -0.3333333333333333 -1.0 -0.8888888888888888]; -% coefs_1(:,2,:)=[-0.625 0.0 0.625; -0.38333333333333336 -0.275 0.28958333333333336; -0.14166666666666666 -0.55 -0.11666666666666667]; -% coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.025; 0.05 -0.1 -0.0075]; -% -% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 -0.8888888888888888; 0.3333333333333333 -0.875 -1.0833333333333333; 1.0 -0.75 0.4375]; -% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 -0.11666666666666667; 0.5125 -0.4625 -0.23472222222222222; 1.1666666666666667 -0.375 1.3333333333333333]; -% coefs_2(:,3,:)=[0.05 -0.1 -0.0075; 0.6916666666666667 -0.05 0.06666666666666667; 1.3333333333333333 0.0 1.7777777777777777]; -% -% coefs_3(:,1,:)=[0.05 -0.1 -0.0075; 0.6916666666666667 -0.05 0.06666666666666667; 1.3333333333333333 0.0 1.7777777777777777]; -% coefs_3(:,2,:)=[-0.225 0.2 0.025; 0.3458333333333333 0.2875 -0.2833333333333333; 0.9166666666666666 0.375 0.6666666666666666]; -% coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 -0.625; 0.5 0.75 -0.3125]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% problem_data.geo_name = nrb; - -% % 3 patch surf hyperbolic non smooth boundary flat -% coefs_1(:,1,:)=[-0.75 -0.5 1.0; -0.5416666666666666 -0.75 1.0; -0.3333333333333333 -1.0 1.0]; -% coefs_1(:,2,:)=[-0.625 0.0 1.0; -0.38333333333333336 -0.275 1.0; -0.14166666666666666 -0.55 1.0]; -% coefs_1(:,3,:)=[-0.5 0.5 1.0; -0.225 0.2 1.0; 0.05 -0.1 1.0]; -% -% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 1.0; 0.3333333333333333 -0.875 1.0; 1.0 -0.75 1.0]; -% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 1.0; 0.5125 -0.4625 1.0; 1.1666666666666667 -0.375 1.0]; -% coefs_2(:,3,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; -% -% coefs_3(:,1,:)=[0.05 -0.1 1.0; 0.6916666666666667 -0.05 1.0; 1.3333333333333333 0.0 1.0]; -% coefs_3(:,2,:)=[-0.225 0.2 1.0; 0.3458333333333333 0.2875 1.0; 0.9166666666666666 0.375 1.0]; -% coefs_3(:,3,:)=[-0.5 0.5 1.0; 0.0 0.625 1.0; 0.5 0.75 1.0]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% problem_data.geo_name = nrb; - - -% 3 patch surf hyperbolic non smooth boundary flat 2D -% coefs_1(:,1,:)=[-0.75 -0.5 0.0; -0.5416666666666666 -0.75 0.0; -0.3333333333333333 -1.0 0.0]; -% coefs_1(:,2,:)=[-0.625 0.0 0.0; -0.38333333333333336 -0.275 0.0; -0.14166666666666666 -0.55 0.0]; -% coefs_1(:,3,:)=[-0.5 0.5 0.0; -0.225 0.2 0.0; 0.05 -0.1 0.0]; -% -% coefs_2(:,1,:)=[-0.3333333333333333 -1.0 0.0; 0.3333333333333333 -0.875 0.0; 1.0 -0.75 0.0]; -% coefs_2(:,2,:)=[-0.14166666666666666 -0.55 0.0; 0.5125 -0.4625 0.0; 1.1666666666666667 -0.375 0.0]; -% coefs_2(:,3,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; -% -% coefs_3(:,1,:)=[0.05 -0.1 0.0; 0.6916666666666667 -0.05 0.0; 1.3333333333333333 0.0 0.0]; -% coefs_3(:,2,:)=[-0.225 0.2 0.0; 0.3458333333333333 0.2875 0.0; 0.9166666666666666 0.375 0.0]; -% coefs_3(:,3,:)=[-0.5 0.5 0.0; 0.0 0.625 0.0; 0.5 0.75 0.0]; -% -% knots{1} = [0 0 0 1 1 1]; -% knots{2} = [0 0 0 1 1 1]; -% -% butterf1 = nrbmak(permute(coefs_1,[3,2,1]),knots); -% butterf2 = nrbmak(permute(coefs_2,[3,2,1]),knots); -% butterf3 = nrbmak(permute(coefs_3,[3,2,1]),knots); -% -% nrb(1)=butterf1; -% nrb(2)=butterf2; -% nrb(3)=butterf3; -% problem_data.geo_name = nrb; - -% Type of boundary conditions for each side of the domain -problem_data.nmnn_sides = []; -problem_data.drchlt_sides = [1 2 3 4 5 6 7 8]; -problem_data.weak_drchlt_sides = []; - -% Physical parameters -problem_data.c_diff = @(x, y, z) ones(size(x)); -% Source and boundary terms -% C = 1; -% p=-1; -% Bilaplacian -% problem_data.f = @(x,y,z) bilaplacian_rhs_Lshape2(x,y); -% % problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); -% % problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); -% problem_data.h = @(x, y, z, ind) solution_bilaplacian_Lshape (x, y); -% -% % Exact solution (optional) -% problem_data.uex = @(x, y, z) solution_bilaplacian_Lshape (x, y); -% problem_data.graduex = @(x, y, z) solution_bilaplacian_Lshape_grad (x, y); -% problem_data.hessuex = @(x, y, z) solution_bilaplacian_Lshape_hessian (x, y); - - -% Cos(5x) Cos(5y) parabolic -% problem_data.f = @(x,y,z) (1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^5) ) * 40 .* (8 * x .* sin(5 * x) .* (-4 * (16 + 151 * x.^2 + 681 * x.^4 + 1408 * x.^6 + 1200 * x.^8 + ... -% 4 * (19 + 153 * x.^2 + 456 * x.^4 + 600 * x.^6) .* y.^2 - 3 * (23 + 192 * x.^2) .* y.^4 - 32 * (31 + 75 * x.^2) .* y.^6 - 1200 * y.^8) .* cos(5 * y) + ... -% 5 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* (63 + 354 * x.^2 + 912 * x.^4 + 800 * x.^6 + 6 * (59 + 304 * x.^2 + 400 * x.^4) .* y.^2 + ... -% 48 * (19 + 50 * x.^2) .* y.^4 + 800 * y.^6) .* sin(5 * y) ) + cos(5 * x) .* (5 * (1 + 4 * x.^2 + 4 * y.^2) .* (37 + 276 * y.^2 + ... -% 4 * (400 * x.^8 + 8 * x.^6 .* (77 + 400 * y.^2) + y.^4 .* (333 + 616 * y.^2 + 400 * y.^4) + ... -% x.^4 .* (333 + 2648 * y.^2 + 5600 * y.^4) + x.^2 .* (69 + 766 * y.^2 + 2648 * y.^4 + 3200 * y.^6) ) ) .* cos(5 * y) - ... -% 32 * y .* (16 - 1200 * x.^8 + 151 * y.^2 + 681 * y.^4 - 32 * x.^6 .* (31 + 75 * y.^2) + 16 * y.^6 .* (88 + 75 * y.^2) - ... -% 3 * x.^4 .* (23 + 192 * y.^2) + 4 * x.^2 .* (19 + 153 * y.^2 + 456 * y.^4 + 600 * y.^6) ) .* sin(5 * y))); -% % problem_data.g = @(x,y, ind) bilaplacian_Lshape_g_nmnn_r_8patches(x,y,ind); -% % problem_data.g = @(x,y,z, ind) bilaplacian_Lshape_g_nmnn_r_5patches(x,y,ind); -% problem_data.h = @(x, y, z, ind) 2 * cos(5 * x) .* cos(5 * y); -% -% problem_data.uex = @(x, y, z) 2 * cos(5 * x) .* cos(5 * y); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape ((-10 * (1 + 4 * y.^2) .* cos(5 * y) .* sin(5 * x) + 40 * x .* y .* cos(5 * x) .* sin(5 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... -% reshape ((40 * x .* y .* cos(5 * y) .* sin(5 * x) - 10 * (1 + 4 * x.^2) .* cos(5 * x) .* sin(5 * y) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)]), ... -% reshape ((20 * (x .* cos(5 * y) .* sin(5 * x) + y .* cos(5 * x) .* sin(5 * y) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); -% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -% problem_data.lapuex = @(x, y, z) (1 ./ ( (1 + 4 * x.^2 + 4 * y.^2).^2) ) .* (-20 * (1 + 2 * x.^2 + 2 * y.^2) .* cos(5 * x) .* (5 * (1 + 4 * x.^2 + 4 * y.^2) .* cos(5 * y) - ... -% 4 * y .* sin(5 * y) ) + 80 * x .* sin(5 * x) .* ( (1 + 2 * x.^2 + 2 * y.^2) .* cos(5 * y) - 5 * y .* (1 + 4 * x.^2 + 4 * y.^2) .* sin(5 * y) ) ); - -% Cos(3x) Cos(y) -% problem_data.f = @(x, y, z) (2./((1 + 4*x.^2 + 4*y.^2).^2)).*(cos(3*x).*((5 + 8*x.^4 + 38*y.^2 + 72*y.^4 + x.^2 .*(22 + 80*y.^2)).*cos(y) - 4*y.*(1 + 2*x.^2 + 2*y.^2).*sin(y)) + 12*x.*sin(3*x).*(-(1 + 2*x.^2 + 2*y.^2).*cos(y) + y.*(1 + 4*x.^2 + 4*y.^2).*sin(y))); -% problem_data.g = @(x, y, z, ind) 1; -% problem_data.h = @(x, y, z, ind) cos(3*x) .* cos(y); -% problem_data.uex = @(x, y, z) cos(3*x) .* cos(y); -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape ((-3*(1 + 4*y.^2).*cos(y).*sin(3*x) + 4*x.*y.*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... -% reshape ((12*x.*y.*cos(y).*sin(3*x) - (1 + 4*x.^2).*cos(3*x).*sin(y))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... -% reshape ((2*(3*x.*cos(y).*sin(3*x) + y.*cos(3*x).*sin(y)))./(1 + 4*x.^2 + 4*y.^2), [1, size(x)])); - - -% z parabolic -% % problem_data.f = @(x, y, z) -((32 .* (-3 + 24 * x.^4 + 22 * y.^2 + 24 * y.^4 + x.^2 .* (22 + 48 *y.^2) ) ) ./ (1 + 4 * x.^2 + 4 * y.^2).^5); -% problem_data.f = @(x, y, z) z; -% % problem_data.g = @(x, y, z, ind) z; -% problem_data.h = @(x, y, z, ind) z; -% problem_data.uex = @(x, y, z) z; -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (-( (2 * x) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... -% reshape (-( (2 * y) ./ (1 + 4 * x.^2 + 4 * y.^2) ), [1, size(x)]), ... -% reshape ( (4 * (x.^2 + y.^2) ) ./ (1 + 4 * x.^2 + 4 * y.^2), [1, size(x)])); -% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -% problem_data.lapuex = @(x, y, z) -((4*(1 + 2*x.^2 + 2*y.^2))./(1 + 4*x.^2 + 4*y.^2).^2); - -% z hyperbolic -% problem_data.f = @(x, y, z) z; -problem_data.f = @(x, y, z) (64 * (x - y) .* (x + y) .* (13 + 64 *x.^4 + 12 *y.^2 + 64 *y.^4 + x.^2 .*(12 - 768 *y.^2)))./(1 + 4 *x.^2 + 4 *y.^2).^5; -% problem_data.g = @(x, y, z, ind) z; -problem_data.h = @(x, y, z, ind) z; -problem_data.uex = @(x, y, z) z; -problem_data.graduex = @(x, y, z) cat (1, ... - reshape ((2*x)./(1 + 4*x.^2 + 4*y.^2), [1, size(x)]), ... - reshape (-((2*y)./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)]), ... - reshape (((4*(x.^2 + y.^2))./(1 + 4*x.^2 + 4*y.^2)), [1, size(x)])); -% problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -problem_data.lapuex = @(x, y, z) -((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2); - - -% z planar 3d -% problem_data.f = @(x, y, z) z;-((8 .*(x.^2 - y.^2))./(1 + 4 *x.^2 + 4 *y.^2).^2) -% problem_data.f = @(x, y, z) zeros(size(x)); -% % problem_data.g = @(x, y, z, ind) z; -% problem_data.h = @(x, y, z, ind) z; -% problem_data.uex = @(x, y, z) z; -% problem_data.graduex = @(x, y, z) cat (1, ... -% reshape (zeros(size(x)), [1, size(x)]), ... -% reshape (zeros(size(x)), [1, size(x)]), ... -% reshape (ones(size(x)), [1, size(x)])); -% % problem_data.hessuex = @(x, y, z) zeros([3, 3, size(x)]); -% problem_data.lapuex = @(x, y, z) zeros(size(x)); - -% 3D problem -C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; -% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); -% problem_data.f = @(x,y,z) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); -% problem_data.g = @(x, y, z, ind) zeros(size(x)); -% problem_data.h = @(x, y, z, ind) exp(-C*normax2(x,y)); -% -% % Exact solution (optional) -% problem_data.uex =@(x,y,z) exp(-C*normax2(x,y)); -% problem_data.graduex = @(x,y,z) -2*C*cat (1, ... -% reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... -% reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)]), ... -% reshape (zeros(size(x)), [1, size(x)]) ); - -% % 2D with coefficients -% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; -% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); -% problem_data.f = @(x,y) 4*C*(1-C*normax2(x,y)).*exp(-C*normax2(x,y)); -% % problem_data.g = @(x, y, ind) zeros(size(x)); -% problem_data.h = @(x, y, ind) exp(-C*normax2(x,y)); -% -% % Exact solution (optional) -% problem_data.uex =@(x,y) exp(-C*normax2(x,y)); -% problem_data.graduex = @(x,y) -2*C*cat (1, ... -% reshape (problem_data.uex(x,y).*(x-P(1)), [1, size(x)]), ... -% reshape (problem_data.uex(x,y).*(y-P(2)), [1, size(x)])); - - -% 2D cos -% C = 20; P=[0.0, 0.0];%[17/6 1]; %[1.5, 0.5]; -% normax2 = @(x,y) ((x-P(1)).^2+(y-P(2)).^2); -% problem_data.f = @(x,y) 256*cos(4*x); -% % problem_data.g = @(x, y, ind) zeros(size(x)); -% problem_data.h = @(x, y, ind) cos(4*x); -% -% % Exact solution (optional) -% problem_data.uex =@(x,y) cos(4*x); -% problem_data.graduex = @(x,y) cat (1, ... -% reshape (-4*sin(4*x), [1, size(x)]), ... -% reshape (zeros(size(x)), [1, size(x)])); - -% CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) -clear method_data -method_data.degree = [3 3]; % Degree of the splines -method_data.regularity = [1 1]; % Regularity of the splines -% method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry -method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule -method_data.Cpen = 10 * (min(method_data.degree) + 1); -method_data.space_type = 'standard'; % 'simplified' (only children functions) or 'standard' (full basis) - -% SOLVE AND DISPLAY RESULTS -plot_data.print_info = true; -plot_data.plot_hmesh = false; -plot_data.plot_discrete_sol = false; - -h=[]; - -for i= 1:3 - fprintf ('Loop %d \n', i); - method_data.nsub = [2^(i+1) 2^(i+1)]; % Number of subdivisions - % 3) CALL TO THE SOLVER - - [geometry, hmsh, hspace, u] = mp_solve_bilaplace_C1 (problem_data, method_data); - - h = [h 1/sqrt(hmsh.nel_per_patch(1))]; - fprintf ('h %g \n', h(i)); - - if (isfield (problem_data, 'hessuex')) - [err_h2(i), err_h1(i), err_l2(i), err_h2s(i), err_h1s(i)] = sp_h2_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex); - if (plot_data.print_info) - fprintf('Error in L2 seminorm = %g\n', err_l2(i)); - fprintf('Error in H1 seminorm = %g\n', err_h1(i)); - fprintf('Error in H2 seminorm = %g\n', err_h2(i)); - end - elseif (isfield (problem_data, 'lapuex')) - [err_h2(i), err_h1(i), err_l2(i), err_h2s(i), err_h1s(i)] = sp_h2_equiv_lap_error (hspace, hmsh, u, problem_data.uex, problem_data.graduex, problem_data.lapuex); - if (plot_data.print_info) - fprintf('Error in L2 seminorm = %g\n', err_l2(i)); - fprintf('Error in H1 seminorm = %g\n', err_h1s(i)); - fprintf('Error in H2 seminorm = %g\n', err_h2s(i)); - end - end -end - - - - -% EXPORT VTK FILE -subplot(1,2,1) -npts = [10 10]; -sp_plot_solution (u, hspace, geometry, npts); shading interp -vtk_pts = {linspace(0,1,npts(1)), linspace(0,1,npts(2))}; -subplot(1,2,2) -for iptc = 1:hmsh.npatch - F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); - X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); - Z = reshape (F(3,:), npts); - surf(X, Y, Z, problem_data.uex(X,Y,Z)); - hold on; - shading interp -end -warning ('on','geopdes:nrbmultipatch') - - -% figure -% for iptc = 1:hmsh.npatch -% F = reshape (geometry(iptc).map(vtk_pts), [hmsh.rdim, npts]); -% X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); Z = reshape (F(3,:), npts); -% -% eu = sp_eval (hspace.Cpatch{iptc}*u, hspace.sp_patch{iptc}, geometry(iptc), vtk_pts); -% surf(X, Y, Z, problem_data.uex(X,Y, Z)-eu); -% hold on; -% shading interp -% end - - -figure -loglog(h, err_l2,'-o') -hold on -loglog(h, err_h1s,'-o') -loglog(h, err_h2s,'-o') -loglog(h, 0.001*h.^4,'-x') -loglog(h, 0.01*h.^3,'-x') -loglog(h, 0.1*h.^2,'-x') -legend("L^2 error", "H^1 error", "H^2 error", "h^4", "h^3", "h^2",'Location','southeast'); From c6121630c306528e6f208a554d8421d84d6e0e16 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 12:52:53 +0200 Subject: [PATCH 327/366] Added bilaplacian on L-shaped domain --- .../bilaplacian_Lshaped_g_nmnn_8patches.m | 34 +++++++++++++ .../base/data_files/bilaplacian_rhs_Lshaped.m | 21 ++++++++ .../data_files/solution_bilaplacian_Lshaped.m | 16 ++++++ .../solution_bilaplacian_Lshaped_grad.m | 19 +++++++ .../solution_bilaplacian_Lshaped_hessian.m | 36 +++++++++++++ .../base/ex_bilaplacian_Lshaped_8patch.m | 51 +++++++++++++++++++ 6 files changed, 177 insertions(+) create mode 100644 geopdes/inst/examples/base/data_files/bilaplacian_Lshaped_g_nmnn_8patches.m create mode 100644 geopdes/inst/examples/base/data_files/bilaplacian_rhs_Lshaped.m create mode 100644 geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped.m create mode 100644 geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_grad.m create mode 100644 geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_hessian.m create mode 100644 geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m diff --git a/geopdes/inst/examples/base/data_files/bilaplacian_Lshaped_g_nmnn_8patches.m b/geopdes/inst/examples/base/data_files/bilaplacian_Lshaped_g_nmnn_8patches.m new file mode 100644 index 00000000..25f89092 --- /dev/null +++ b/geopdes/inst/examples/base/data_files/bilaplacian_Lshaped_g_nmnn_8patches.m @@ -0,0 +1,34 @@ +% TEST_PLATE_MIXED_BC_G_NMNN: data function for Neumann boundary condition. + +function g = bilaplacian_Lshaped_g_nmnn_8patches (x, y, ind) + [th, r] = cart2pol (x, y); + th = (th < 0).*(2*acos(-1) + th) + (th >= 0) .* th; +% f = @(z) sin(3*pi/2*z).^2 - z.^2 * sin(3*pi/2)^2; + z = 0.544483736782464; %z = fsolve(f, 0.5) The one on the left is more precise, computed with bisection method + + C1 = 1/(z-1)*sin(3*pi/2*(z-1)) - 1/(z+1)*sin(3*pi/2*(z+1)); + C2 = cos(3*pi/2*(z-1)) - cos(3*pi/2*(z+1)); + F1 = cos((z-1)*th) - cos((z+1)*th); + F2 = 1/(z-1)*sin((z-1)*th) - 1/(z+1)*sin((z+1)*th); + DF1 = -(z-1)*sin((z-1)*th)+(z+1)*sin((z+1)*th); + DF2 = cos((z-1)*th)-cos((z+1)*th); + + psi = C1*F1 - C2*F2; %C1 and C2 are constants + Dpsi = C1*DF1 - C2*DF2; + + switch (ind) + case {4} %n=(-1,0) + g = -((z+1)*r.^(z).* psi.*cos(th) - r.^z.*Dpsi.*sin(th)); + case {2,6} %n=(1,0) + g = (z+1)*r.^(z).* psi.*cos(th) - r.^z.*Dpsi.*sin(th); + case {1,3} %n=(0,-1) + g = -((z+1)*r.^(z).* psi.*sin(th) + r.^z.*Dpsi.*cos(th)); + case {5} %n=(0,1) + g = (z+1)*r.^(z).* psi.*sin(th) + r.^z.*Dpsi.*cos(th); + + otherwise + error ('g_nmnn: unknown reference number') + end + +end + diff --git a/geopdes/inst/examples/base/data_files/bilaplacian_rhs_Lshaped.m b/geopdes/inst/examples/base/data_files/bilaplacian_rhs_Lshaped.m new file mode 100644 index 00000000..e9459426 --- /dev/null +++ b/geopdes/inst/examples/base/data_files/bilaplacian_rhs_Lshaped.m @@ -0,0 +1,21 @@ +function uex = bilaplacian_rhs_Lshaped (x, y) +[th, r] = cart2pol (x, y); +th = (th < 0).*(2*acos(-1) + th) + (th >= 0) .* th; +z = 0.544483736782464; + +C1 = 1/(z-1)*sin(3*pi/2*(z-1)) - 1/(z+1)*sin(3*pi/2*(z+1)); +C2 = cos(3*pi/2*(z-1)) - cos(3*pi/2*(z+1)); +F1 = cos((z-1)*th) - cos((z+1)*th); +F1_2 = -(z-1)^2*cos((z-1)*th) + (z+1)^2*cos((z+1)*th); +F1_4 = (z-1)^4*cos((z-1)*th) - (z+1)^4*cos((z+1)*th); +F2 = 1/(z-1)*sin((z-1)*th) - 1/(z+1)*sin((z+1)*th); +F2_2 = -(z-1)*sin((z-1)*th) + (z+1)*sin((z+1)*th); +F2_4 = (z-1)^3*sin((z-1)*th) - (z+1)^3*sin((z+1)*th); + +psi = C1*F1 - C2*F2; +psi2 = C1*F1_2 - C2*F2_2; +psi4 = C1*F1_4 - C2*F2_4; + +uex = (r.^(z-3)).*(((z-1)^2)*(((z+1)^2)*psi+psi2)+((z+1)^2)*psi2+psi4); + +end \ No newline at end of file diff --git a/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped.m b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped.m new file mode 100644 index 00000000..9e940a60 --- /dev/null +++ b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped.m @@ -0,0 +1,16 @@ +function uex = solution_bilaplacian_Lshaped (x, y) + [th, r] = cart2pol (x, y); + th = (th < 0).*(2*acos(-1) + th) + (th >= 0) .* th; +% f = @(z) sin(3*pi/2*z).^2 - z.^2 * sin(3*pi/2)^2; + z = 0.544483736782464; %z = fsolve(f, 0.5) The one on the left is more precise, computed with bisection method + + C1 = 1/(z-1)*sin(3*pi/2*(z-1)) - 1/(z+1)*sin(3*pi/2*(z+1)); + C2 = cos(3*pi/2*(z-1)) - cos(3*pi/2*(z+1)); + F1 = cos((z-1)*th) - cos((z+1)*th); + F2 = 1/(z-1)*sin((z-1)*th) - 1/(z+1)*sin((z+1)*th); + + psi = C1*F1 - C2*F2; %C1 and C2 are constants + + uex = r.^(z+1).* psi; +end + diff --git a/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_grad.m b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_grad.m new file mode 100644 index 00000000..14e2eda3 --- /dev/null +++ b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_grad.m @@ -0,0 +1,19 @@ +function graduex = solution_bilaplacian_Lshaped_grad (x, y) + graduex = zeros(2, size(x,1), size(x,2)); + [th, r] = cart2pol (x, y); + th = (th < 0).*(2*acos(-1) + th) + (th >= 0) .* th; +% f = @(z) sin(3*pi/2*z).^2 - z.^2 * sin(3*pi/2)^2; + z = 0.544483736782464; %z = fsolve(f, 0.5) The one on the left is more precise, computed with bisection method + + C1 = 1/(z-1)*sin(3*pi/2*(z-1)) - 1/(z+1)*sin(3*pi/2*(z+1)); + C2 = cos(3*pi/2*(z-1)) - cos(3*pi/2*(z+1)); + F1 = cos((z-1)*th) - cos((z+1)*th); + F2 = 1/(z-1)*sin((z-1)*th) - 1/(z+1)*sin((z+1)*th); + + psi = C1*F1 - C2*F2; %C1 and C2 are constants + Dpsi = C1*(-(z-1)*sin((z-1)*th)+(z+1)*sin((z+1)*th)) - C2*(cos((z-1)*th)-cos((z+1)*th)); + + graduex(1,:,:) = (z+1)*r.^(z).* psi.*cos(th) - r.^z.*Dpsi.*sin(th); + graduex(2,:,:) = (z+1)*r.^(z).* psi.*sin(th) + r.^z.*Dpsi.*cos(th); +end + diff --git a/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_hessian.m b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_hessian.m new file mode 100644 index 00000000..33fae134 --- /dev/null +++ b/geopdes/inst/examples/base/data_files/solution_bilaplacian_Lshaped_hessian.m @@ -0,0 +1,36 @@ +function hessian = solution_bilaplacian_Lshaped_hessian (x, y) +hessian = zeros(2,2,size(x,1), size(x,2)); +[th, r] = cart2pol (x, y); +th = (th < 0).*(2*acos(-1) + th) + (th >= 0) .* th; +z = 0.544483736782464; + +C1 = 1/(z-1)*sin(3*pi/2*(z-1)) - 1/(z+1)*sin(3*pi/2*(z+1)); +C2 = cos(3*pi/2*(z-1)) - cos(3*pi/2*(z+1)); +F1 = cos((z-1)*th) - cos((z+1)*th); +F2 = 1/(z-1)*sin((z-1)*th) - 1/(z+1)*sin((z+1)*th); + +psi = C1*F1 - C2*F2; %C1 and C2 are constants +Dpsi = C1*(-(z-1)*sin((z-1)*th)+(z+1)*sin((z+1)*th)) - C2*(cos((z-1)*th)-cos((z+1)*th)); +D2psi = C1*(-((z-1)^2)*cos((z-1)*th)+((z+1)^2)*cos((z+1)*th)) - C2*(-(z-1)*sin((z-1)*th)+(z+1)*sin((z+1)*th)); + +ur=(z+1)*r.^(z).*psi; +uth=r.^(z+1).*Dpsi; +urr=z*(z+1)*r.^(z-1).*psi; +uthr=(z+1)*r.^(z).*Dpsi; +uthth=r.^(z+1).*D2psi; + +uxr=cos(th).*urr-sin(th).*(r.*uthr-uth)./(r.^2); +uxth=-sin(th).*ur+cos(th).*uthr-cos(th).*uth./r-sin(th).*uthth./r; +uyr=sin(th).*urr+cos(th).*(r.*uthr-uth)./(r.^2); +uyth=cos(th).*ur+sin(th).*uthr-sin(th).*uth./r+cos(th).*uthth./r; + +uxx=cos(th).*uxr-sin(th).*uxth./r; +uxy=sin(th).*uxr+cos(th).*uxth./r; +uyy=sin(th).*uyr+cos(th).*uyth./r; + +hessian(1,1,:,:) = uxx; +hessian(1,2,:,:) = uxy; +hessian(2,1,:,:) = uxy; +hessian(2,2,:,:) = uyy; + +end \ No newline at end of file diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m new file mode 100644 index 00000000..17e31273 --- /dev/null +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m @@ -0,0 +1,51 @@ +% PHYSICAL DATA OF THE PROBLEM +clear problem_data +problem_data.geo_name = 'geo_Lshaped_8patches.txt'; + +%EXAMPLE SMOOTH +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [1 2 3 4 5 6]; +problem_data.weak_drchlt_sides = []; + +% Physical parameters +problem_data.c_diff = @(x, y) ones(size(x)); +% problem_data.grad_c_diff = @(x, y) cat (1, ... +% reshape (zeros(size(x)), [1, size(x)]), ... +% reshape (zeros(size(x)), [1, size(x)])); + +% Source and boundary terms +C = 1; +p = -1; +% Bilaplacian +problem_data.f = @bilaplacian_rhs_Lshaped; +% problem_data.g = @(x, y, ind) bilaplacian_Lshaped_g_nmnn_8patches (x,y,ind); +problem_data.h = @(x, y, ind) solution_bilaplacian_Lshaped (x, y); + +% Exact solution (optional) +problem_data.uex = @(x, y) solution_bilaplacian_Lshaped (x, y); +problem_data.graduex = @(x, y) solution_bilaplacian_Lshaped_grad (x, y); +problem_data.hessuex = @(x, y) solution_bilaplacian_Lshaped_hessian (x, y); + +% CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) +clear method_data +method_data.degree = [4 4]; % Degree of the splines +method_data.regularity = [2 2]; % Regularity of the splines +method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = method_data.degree+1; % Points for the Gaussian quadrature rule + +[geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); + +[err_h2,~,~,err_h2s] = sp_h2_error (space, msh, u, problem_data.uex, problem_data.graduex, problem_data.hessuex) + +subplot(1,2,1) +npts = [51 51]; +sp_plot_solution (u, space, geometry, npts); shading interp +vtk_pts = {linspace(0,1,npts(1)), linspace(0,1,npts(2))}; +subplot(1,2,2) +for iptc = 1:msh.npatch + F = reshape (geometry(iptc).map(vtk_pts), [2, npts]); + X = reshape (F(1,:), npts); Y = reshape (F(2,:), npts); + surf(X, Y, problem_data.uex(X,Y)); + hold on; shading interp +end From bf681e97e2fe485e6469b6cedaccb7b3d6337866 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 17:29:47 +0200 Subject: [PATCH 328/366] Multipatch examples for the laplacian --- .../examples/base/ex_laplace_3patches_C1.m | 39 +++++++++++++++++++ .../examples/base/ex_laplace_6patches_C1.m | 38 ++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 geopdes/inst/examples/base/ex_laplace_3patches_C1.m create mode 100644 geopdes/inst/examples/base/ex_laplace_6patches_C1.m diff --git a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m new file mode 100644 index 00000000..16446d00 --- /dev/null +++ b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m @@ -0,0 +1,39 @@ +% PHYSICAL DATA OF THE PROBLEM +clear problem_data +problem_data.geo_name = 'geo_3patch_ASG1.txt'; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = []; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; + +problem_data.c_diff = @(x, y) ones(size(x)); + +% Source and boundary terms +C = 20; P=[17/3+0.15, 2+0.075]; +alpha=4/6; +problem_data.f = @(x,y) -2*alpha*((x-P(1)).^2+(y-P(2)).^2).^(alpha-2).*... + (((x-P(1)).^2+(y-P(2)).^2)+2*(alpha-1)*(x-P(1)).^2)... + -2*alpha*((x-P(1)).^2+(y-P(2)).^2).^(alpha-2).*... + (((x-P(1)).^2+(y-P(2)).^2)+2*(alpha-1)*(y-P(2)).^2); +problem_data.g = @(x, y, ind) zeros(size(x)); +problem_data.h = @(x, y, ind) ((x-P(1)).^2+(y-P(2)).^2).^alpha; + +% Exact solution (optional) +problem_data.uex =@(x,y) ((x-P(1)).^2+(y-P(2)).^2).^alpha; +problem_data.graduex = @(x,y) 2*alpha*cat (1, ... + reshape (((x-P(1)).^2+(y-P(2)).^2).^(alpha-1).*(x-P(1)), [1, size(x)]), ... + reshape (((x-P(1)).^2+(y-P(2)).^2).^(alpha-1).*(y-P(2)), [1, size(x)])); + +deg = 4; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); + +[geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); +err_h1 = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) + +npts = [81 81]; +sp_plot_solution (u, space, geometry, npts); shading interp diff --git a/geopdes/inst/examples/base/ex_laplace_6patches_C1.m b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m new file mode 100644 index 00000000..8cca51da --- /dev/null +++ b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m @@ -0,0 +1,38 @@ +% PHYSICAL DATA OF THE PROBLEM +clear problem_data + +problem_data.geo_name = 'geo_6patch_ASG1.txt'; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = []; +problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8]; + +problem_data.c_diff = @(x, y) ones(size(x)); + +% Source and boundary terms (SINGULARITY ALONG THE LINE x=y) +alpha = 7/6; +problem_data.f = @(x,y) exp(-(y-x).^2) .* (16*alpha*((y-x).^2).^alpha ... + -4*alpha*(2*alpha-1)*((y-x).^2).^(alpha-1) ... + +4*((y-x).^2).^alpha - 8*((y-x).^2).^(alpha+1)); +problem_data.g = @(x, y, ind) zeros(size(x)); +problem_data.h = @(x, y, ind) ((y-x).^2).^alpha.*exp(-(y-x).^2); + +% Exact solution (optional) +problem_data.uex = @(x,y) ((y-x).^2).^alpha.*exp(-(y-x).^2); +problem_data.graduex = @(x,y) cat(1, ... + reshape (2 * exp(-(y-x).^2) .* (y-x) .* (-alpha*((y-x).^2).^(alpha-1) + ((y-x).^2).^alpha ), [1, size(x)]), ... + reshape (2 * exp(-(y-x).^2) .* (y-x) .* ( alpha*((y-x).^2).^(alpha-1) - ((y-x).^2).^alpha ), [1, size(x)])); + +deg = 4; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); + +[geometry, msh, space, u] = mp_solve_laplace_C1 (problem_data, method_data); +err_h1 = sp_h1_error (space, msh, u, problem_data.uex, problem_data.graduex) + +npts = [81 81]; +sp_plot_solution (u, space, geometry, npts); shading interp From 93817cfd88ea2f07b7a350725c50a5f84602b180 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Fri, 21 Jun 2024 18:07:56 +0200 Subject: [PATCH 329/366] Example for the bilaplacian --- .../base/ex_bilaplacian_quasisphere.m | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m diff --git a/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m new file mode 100644 index 00000000..93625b84 --- /dev/null +++ b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m @@ -0,0 +1,27 @@ +% PHYSICAL DATA OF THE PROBLEM + +problem_data.geo_name = 'geo_open_quasisphere_5p_ASG1.txt'; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [1 2 3 4]; +problem_data.weak_drchlt_sides = []; + +% Physical parameters +problem_data.c_diff = @(x, y, z) ones(size(x)); + +% Source and boundary terms +problem_data.f = @(x, y, z) ones(size(x)); +problem_data.g = @(x, y, z, ind) zeros(size(x)); +problem_data.h = @(x, y, z, ind) zeros(size(x)); + +deg = 4; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); + +[geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); +npts = [41 41]; +sp_plot_solution (u, space, geometry); shading interp; axis equal From 0a26ce373b3be392f08ad0997f68663ead11e495 Mon Sep 17 00:00:00 2001 From: cesare Date: Mon, 1 Jul 2024 11:50:35 +0200 Subject: [PATCH 330/366] ex_bilaplacian_hyperboloid --- .../base/ex_bilaplacian_hyperboloid.m | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m diff --git a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m new file mode 100644 index 00000000..3c24bcc0 --- /dev/null +++ b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m @@ -0,0 +1,56 @@ +% PHYSICAL DATA OF THE PROBLEM + +problem_data.geo_name = 'geo_hyperboloid_ASG1.txt'; + +% Type of boundary conditions for each side of the domain +problem_data.nmnn_sides = []; +problem_data.drchlt_sides = [1 2 3 4 5 6]; +problem_data.weak_drchlt_sides = []; + +% Physical parameters +problem_data.c_diff = @(x, y, z) ones(size(x)); + +% Source and boundary terms +C = 1; +p = -1; +cons=200; +problem_data.f = @(x, y, z) 16.*cons.*exp(1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).* ... + (1+4.*x.^2+4.*y.^2).^(-5).*(cons.^3.*(1+4.*x.^2+4.*y.^2).^3.*(4.* ... + x.^6+(-4).*x.^4.*((-1)+y.^2)+(y+2.*y.^3).^2+x.^2.*(1+8.*y.^2+(-4) ... + .*y.^4)).^2+8.*(64.*x.^8+x.^6.*(32+(-896).*y.^2)+2.*x.^4.*(7+(-48) ... + .*y.^2+832.*y.^4)+y.^2.*((-1)+14.*y.^2+32.*y.^4+64.*y.^6)+(-1).* ... + x.^2.*(1+60.*y.^2+96.*y.^4+896.*y.^6))+(-4).*cons.^2.*(1+4.*x.^2+ ... + 4.*y.^2).^2.*(72.*x.^10+20.*x.^8.*(5+2.*y.^2)+x.^6.*(50+272.*y.^2+ ... + (-112).*y.^4)+(y+2.*y.^3).^2.*(1+7.*y.^2+18.*y.^4)+x.^4.*(11+142.* ... + y.^2+280.*y.^4+(-112).*y.^6)+x.^2.*(1+26.*y.^2+142.*y.^4+272.* ... + y.^6+40.*y.^8))+2.*cons.*(1+1568.*x.^10+19.*y.^2+174.*y.^4+796.* ... + y.^6+1752.*y.^8+1568.*y.^10+8.*x.^8.*(219+404.*y.^2)+4.*x.^6.*( ... + 199+1064.*y.^2+2896.*y.^4)+2.*x.^4.*(87+786.*y.^2+3720.*y.^4+ ... + 5792.*y.^6)+x.^2.*(19+244.*y.^2+1572.*y.^4+4256.*y.^6+3232.*y.^8))); +problem_data.h = @(x, y, z, ind) exp(-cons*(x.^2 + y.^2 + (x.^2 - y.^2).^2)); + +% Exact solution +problem_data.uex = @(x, y, z) exp(-cons*(x.^2 + y.^2 + (x.^2 - y.^2).^2)); +problem_data.graduex = @(x, y, z) cat (1, ... + reshape ( (-2).*cons.*exp(1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).*x.*(1+4.*x.^2+4.*y.^2).^(-1).*(1+2.*x.^2+6.*y.^2), [1, size(x)]), ... + reshape ( (-2).*cons.*exp(1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).*y.*(1+6.*x.^2+2.*y.^2).*(1+4.*x.^2+4.*y.^2).^(-1), [1, size(x)]), ... + reshape ( (-4).*cons.*exp (1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).*(1+4.*x.^2+4.*y.^2).^(-1).*(x.^2+2.*x.^4+(-1).*y.^2+(-2).*y.^4), [1, size(x)])); + +problem_data.lapuex = @(x, y, z) 4.*cons.*exp(1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).*( ... + 1+4.*x.^2+4.*y.^2).^(-2).*((-1)+20.*cons.*x.^6+16.*cons.*x.^8+(( ... + -8)+cons).*y.^2+4.*((-5)+2.*cons).*y.^4+20.*cons.*y.^6+16.*cons.* ... + y.^8+x.^2.*((-8)+cons+(-24).*y.^2+16.*cons.*y.^2+44.*cons.*y.^4)+( ... + -4).*x.^4.*(5+cons.*((-2)+(-11).*y.^2+8.*y.^4))); + + +deg = 3; +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule +method_data.Cpen = 10 * (min(method_data.degree) + 1); + +[geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); +npts = [41 41]; +sp_plot_solution (u, space, geometry); shading interp; axis equal +fprintf('Error in (equivalent) H2 seminorm = %g\n', sp_h2_equiv_lap_error(space, msh, u, problem_data.uex, problem_data.graduex, problem_data.lapuex)); \ No newline at end of file From c41f38e3369f2539f89beaa456a49092b042cff2 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 1 Jul 2024 18:55:54 +0200 Subject: [PATCH 331/366] Minor --- geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m index 3c24bcc0..1898c4a8 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m @@ -13,7 +13,7 @@ % Source and boundary terms C = 1; p = -1; -cons=200; +cons = 200; problem_data.f = @(x, y, z) 16.*cons.*exp(1).^((-1).*cons.*(x.^2+y.^2+(x.^2+(-1).*y.^2).^2)).* ... (1+4.*x.^2+4.*y.^2).^(-5).*(cons.^3.*(1+4.*x.^2+4.*y.^2).^3.*(4.* ... x.^6+(-4).*x.^4.*((-1)+y.^2)+(y+2.*y.^3).^2+x.^2.*(1+8.*y.^2+(-4) ... @@ -42,7 +42,6 @@ y.^8+x.^2.*((-8)+cons+(-24).*y.^2+16.*cons.*y.^2+44.*cons.*y.^4)+( ... -4).*x.^4.*(5+cons.*((-2)+(-11).*y.^2+8.*y.^4))); - deg = 3; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines @@ -53,4 +52,4 @@ [geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); npts = [41 41]; sp_plot_solution (u, space, geometry); shading interp; axis equal -fprintf('Error in (equivalent) H2 seminorm = %g\n', sp_h2_equiv_lap_error(space, msh, u, problem_data.uex, problem_data.graduex, problem_data.lapuex)); \ No newline at end of file +fprintf('Error in (equivalent) H2 seminorm = %g\n', sp_h2_equiv_lap_error(space, msh, u, problem_data.uex, problem_data.graduex, problem_data.lapuex)); From 8cd4ed0a41cecd2841fcf0e545e99a81c03bfa38 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 1 Jul 2024 18:57:24 +0200 Subject: [PATCH 332/366] Added caption --- geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m index 17e31273..ffeeb85a 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m @@ -40,7 +40,7 @@ subplot(1,2,1) npts = [51 51]; -sp_plot_solution (u, space, geometry, npts); shading interp +sp_plot_solution (u, space, geometry, npts); shading interp; title('Computed solution') vtk_pts = {linspace(0,1,npts(1)), linspace(0,1,npts(2))}; subplot(1,2,2) for iptc = 1:msh.npatch @@ -49,3 +49,4 @@ surf(X, Y, problem_data.uex(X,Y)); hold on; shading interp end +title('Exact solution') From d5534213e435e1eed7369084b9b3b451292ccf19 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 2 Jul 2024 18:56:16 +0200 Subject: [PATCH 333/366] Locally change warning state for geopdes:nrbmultipatch --- .../multipatch/@sp_multipatch_C1/sp_multipatch_C1.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m index 15bb2a9a..48064cc9 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_multipatch_C1.m @@ -57,7 +57,7 @@ % sp_compute_Cpatch_vector: compute the matrix for B-splines representation on a patch % for vector-valued spaces with the same space on each component % -% Copyright (C) 2015-2023 Rafael Vazquez +% Copyright (C) 2015-2024 Rafael Vazquez % Copyright (C) 2019-2023 Cesare Bracco % Copyright (C) 2022 Andrea Farahat % @@ -153,12 +153,15 @@ sp.ndof_interior_per_patch(iptc) = numel (interior_dofs); end clear interior_dofs - + + warnaux = warning('query','geopdes:nrbmultipatch'); + warning ('off', 'geopdes:nrbmultipatch') [ndof_per_interface, CC_edges, ndof_per_vertex, CC_vertices, v_fun_matrices] = ... compute_coefficients (sp, msh, geometry, interfaces_all, vertices); + warning (warnaux.state, 'geopdes:nrbmultipatch') %Sigmas, K and V matrices used in the construction of vertex functions - sp.vertex_function_matrices=v_fun_matrices; + sp.vertex_function_matrices = v_fun_matrices; % Total number of functions, and of functions of each type sp.ndof_edges = sum (ndof_per_interface); @@ -210,7 +213,7 @@ % with patch = vertices(jj).patches(ii). % Initialize cell array containing sigma, K and V matrices for each vertex -v_fun_matrices=cell(2, numel(vertices)); +v_fun_matrices = cell(2, numel(vertices)); %Initialize output variables with correct size ndof_per_interface = zeros (1, numel(interfaces_all)); From daef6972ca2bae6ec27904480d6de3f17903c4b0 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 2 Jul 2024 19:24:39 +0200 Subject: [PATCH 334/366] Minor --- geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m index 96381c55..c7ebf6cb 100644 --- a/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m +++ b/geopdes/inst/multipatch/@msh_multipatch/msh_cells_near_vertex.m @@ -1,4 +1,4 @@ -% MSH_CELLS_NEAR_VERTEX: Identify the elements adjacent to given vertices +% MSH_CELLS_NEAR_VERTEX: Identify the elements adjacent to given vertices. % % [all_adjacent_elemens, elems_near_vertex] = msh_cells_near_vertex (msh, vertices) % From 771628ecd64023b7498a51d78dd9ae666d4190c7 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 2 Jul 2024 19:35:22 +0200 Subject: [PATCH 335/366] Changes in the help --- .../inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m | 2 +- geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m | 2 +- geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m | 2 +- geopdes/inst/space/sp_scalar2vector_param.m | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m index cb9332e1..3795c703 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_nitsche_KL_rotation.m @@ -10,7 +10,7 @@ % E_coeff: function handle for the Young modulus % nu_coeff: function handle for the Poisson ratio % thickness: scalar value for the thickness -% C_penalty: a penalization term +% C_penalty: parameter for the penalization term % % OUTPUT: % diff --git a/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m index dc9e3533..3b03afab 100644 --- a/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/space/@sp_scalar/sp_nitsche_KL_rotation.m @@ -10,7 +10,7 @@ % E_coeff: function handle for the Young modulus % nu_coeff: function handle for the Poisson ratio % thickness: scalar value for the thickness -% C_penalty: a penalization term +% C_penalty: parameter for the penalization term % % OUTPUT: % diff --git a/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m index dd819e7d..67ea4152 100644 --- a/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m +++ b/geopdes/inst/space/@sp_vector/sp_nitsche_KL_rotation.m @@ -10,7 +10,7 @@ % E_coeff: function handle for the Young modulus % nu_coeff: function handle for the Poisson ratio % thickness: scalar value for the thickness -% C_penalty: a penalization term +% C_penalty: parameter for the penalization term % % OUTPUT: % diff --git a/geopdes/inst/space/sp_scalar2vector_param.m b/geopdes/inst/space/sp_scalar2vector_param.m index b6973d4e..4aa72d4a 100644 --- a/geopdes/inst/space/sp_scalar2vector_param.m +++ b/geopdes/inst/space/sp_scalar2vector_param.m @@ -13,6 +13,7 @@ % ------------+-----------------+---------------------------------- % value | true | compute shape_functions % gradient | false | compute shape_function_gradients +% divergence | false | compute shape_function_divs % hessian | false | compute shape_function_hessians % % OUTPUT: From 3cbd00970be359f182bba153635f943ffb211b55 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 2 Jul 2024 19:48:51 +0200 Subject: [PATCH 336/366] Cahnge in the help --- geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m index d3b7e610..7f6b040c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/sp_drchlt_C1_shells.m @@ -12,7 +12,7 @@ % % OUTPUT: % -% u: assigned value to the degrees of freedom +% u: assigned value to the degrees of freedom (zero for now) % dofs: global numbering of the corresponding basis functions % kernel_info: a struct with information of kernel computation, containing: % - vertices_numbers: vertices which contain a function in the kernel From 2fbc211ece1d651449c1baae47b3e665c8464d4b Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 2 Jul 2024 19:51:37 +0200 Subject: [PATCH 337/366] Imposition of exact boundary conditions is not implemented for shells --- ...olve_kirchhoff_love_shell_C1_scalarspace.m | 42 ++----------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m index d6269779..d99aebf4 100644 --- a/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m +++ b/geopdes/inst/multipatch/mp_solve_kirchhoff_love_shell_C1_scalarspace.m @@ -98,45 +98,11 @@ end % Apply boundary conditions -% drchlt_dofs = []; drchlt_dofs2 = []; -% for iref = 1:numel(drchlt_sides) -% if (~exist('drchlt_components','var')) -% components = 1:3; -% else -% components = drchlt_components{iref}; -% end -% bnd_ref = drchlt_sides(iref); -% scalar_dofs_on_ref = []; -% scalar_dofs_on_ref2 = []; -% for bnd_side = 1:msh.boundaries(bnd_ref).nsides -% iptc = msh.boundaries(bnd_ref).patches(bnd_side); -% iside = msh.boundaries(bnd_ref).faces(bnd_side); -% -% % msh_side = msh.msh_patch{iptc}.boundary(iside); -% side_dofs = space.sp_patch{iptc}.boundary(iside).dofs; -% -% [~,scalar_dofs] = find (abs(space.Cpatch{iptc}(side_dofs,:))>1e-15); -% % [~,scalar_dofs] = find (space.Cpatch{iptc}(side_dofs,:)); -% scalar_dofs_on_ref = union (scalar_dofs_on_ref, scalar_dofs); -% end -% for icomp = components -% drchlt_dofs = union (drchlt_dofs, (icomp-1)*space.ndof + scalar_dofs_on_ref); -% drchlt_dofs2 = union (drchlt_dofs2, (icomp-1)*space2.ndof + scalar_dofs_on_ref2); -% end -% end -% -% ndof = msh.rdim * space.ndof; -% u = zeros (ndof, 1); -% int_dofs = setdiff (1:ndof, drchlt_dofs); -% -% % Solve the linear system -% u(int_dofs) = K(int_dofs, int_dofs) \ rhs(int_dofs); - -if (~isfield (problem_data, 'uex')) +% if (~isfield (problem_data, 'uex')) [u_drchlt, drchlt_dofs, kernel_dofs] = sp_drchlt_C1_shells (space, msh, drchlt_sides, drchlt_components); -else - [u_drchlt, drchlt_dofs, kernel_dofs] = sp_drchlt_C1_exact_shells (space, msh, drchlt_sides, problem_data.uex); -end +% else +% [u_drchlt, drchlt_dofs, kernel_dofs] = sp_drchlt_C1_exact_shells (space, msh, drchlt_sides, problem_data.uex); +% end ndof = msh.rdim * space.ndof; u = zeros (ndof, 1); From 14a191df15ce057066df517af1595078239eb6b0 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 3 Jul 2024 15:48:58 +0200 Subject: [PATCH 338/366] Removed unused parameter --- geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m | 3 +-- geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m index 1898c4a8..3b511739 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m @@ -45,9 +45,8 @@ deg = 3; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines -method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry +method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule -method_data.Cpen = 10 * (min(method_data.degree) + 1); [geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); npts = [41 41]; diff --git a/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m index 93625b84..e768e2e1 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m @@ -20,7 +20,6 @@ method_data.regularity = [deg-2 deg-2]; % Regularity of the splines method_data.nsub = [8 8]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule -method_data.Cpen = 10 * (min(method_data.degree) + 1); [geometry, msh, space, u] = mp_solve_bilaplace_C1 (problem_data, method_data); npts = [41 41]; From e8e2e2fced68a82f583ae589f813d5f4f9000784 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 3 Jul 2024 16:38:19 +0200 Subject: [PATCH 339/366] Some cleaning --- .../examples/base/ex_bilaplacian_Lshaped_8patch.m | 5 ++--- .../inst/examples/base/ex_bilaplacian_hyperboloid.m | 4 +++- .../inst/examples/base/ex_bilaplacian_quasisphere.m | 4 +++- geopdes/inst/examples/base/ex_laplace_3patches_C1.m | 4 +++- geopdes/inst/examples/base/ex_laplace_6patches_C1.m | 4 +++- .../ex_KL_3patch_hyperboloid_clamped.m | 6 ++++-- .../kirchhoff_love_shell/ex_KL_4patch_paraboloid.m | 12 +++++++----- .../kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m | 6 ++++-- 8 files changed, 29 insertions(+), 16 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m index ffeeb85a..d1d7f909 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m @@ -1,8 +1,7 @@ % PHYSICAL DATA OF THE PROBLEM -clear problem_data +clear problem_data problem_data.geo_name = 'geo_Lshaped_8patches.txt'; -%EXAMPLE SMOOTH % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; problem_data.drchlt_sides = [1 2 3 4 5 6]; @@ -27,7 +26,7 @@ problem_data.graduex = @(x, y) solution_bilaplacian_Lshaped_grad (x, y); problem_data.hessuex = @(x, y) solution_bilaplacian_Lshaped_hessian (x, y); -% CHOICE OF THE DISCRETIZATION PARAMETERS (Coarse mesh) +% DISCRETIZATION PARAMETERS clear method_data method_data.degree = [4 4]; % Degree of the splines method_data.regularity = [2 2]; % Regularity of the splines diff --git a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m index 3b511739..c6ade11e 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_hyperboloid.m @@ -1,5 +1,5 @@ % PHYSICAL DATA OF THE PROBLEM - +clear problem_data problem_data.geo_name = 'geo_hyperboloid_ASG1.txt'; % Type of boundary conditions for each side of the domain @@ -42,6 +42,8 @@ y.^8+x.^2.*((-8)+cons+(-24).*y.^2+16.*cons.*y.^2+44.*cons.*y.^4)+( ... -4).*x.^4.*(5+cons.*((-2)+(-11).*y.^2+8.*y.^4))); +% DISCRETIZATION PARAMETERS +clear method_data deg = 3; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines diff --git a/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m index e768e2e1..3525fbc7 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_quasisphere.m @@ -1,5 +1,5 @@ % PHYSICAL DATA OF THE PROBLEM - +clear problem_data problem_data.geo_name = 'geo_open_quasisphere_5p_ASG1.txt'; % Type of boundary conditions for each side of the domain @@ -15,6 +15,8 @@ problem_data.g = @(x, y, z, ind) zeros(size(x)); problem_data.h = @(x, y, z, ind) zeros(size(x)); +% DISCRETIZATION PARAMETERS +clear method_data deg = 4; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines diff --git a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m index 16446d00..8d1bf380 100644 --- a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m +++ b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m @@ -1,5 +1,5 @@ % PHYSICAL DATA OF THE PROBLEM -clear problem_data +clear problem_data problem_data.geo_name = 'geo_3patch_ASG1.txt'; % Type of boundary conditions for each side of the domain @@ -25,6 +25,8 @@ reshape (((x-P(1)).^2+(y-P(2)).^2).^(alpha-1).*(x-P(1)), [1, size(x)]), ... reshape (((x-P(1)).^2+(y-P(2)).^2).^(alpha-1).*(y-P(2)), [1, size(x)])); +% DISCRETIZATION PARAMETERS +clear method_data deg = 4; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines diff --git a/geopdes/inst/examples/base/ex_laplace_6patches_C1.m b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m index 8cca51da..076cf841 100644 --- a/geopdes/inst/examples/base/ex_laplace_6patches_C1.m +++ b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m @@ -1,5 +1,5 @@ % PHYSICAL DATA OF THE PROBLEM -clear problem_data +clear problem_data problem_data.geo_name = 'geo_6patch_ASG1.txt'; @@ -24,6 +24,8 @@ reshape (2 * exp(-(y-x).^2) .* (y-x) .* (-alpha*((y-x).^2).^(alpha-1) + ((y-x).^2).^alpha ), [1, size(x)]), ... reshape (2 * exp(-(y-x).^2) .* (y-x) .* ( alpha*((y-x).^2).^(alpha-1) - ((y-x).^2).^alpha ), [1, size(x)])); +% DISCRETIZATION PARAMETERS +clear method_data deg = 4; method_data.degree = [deg deg]; % Degree of the splines method_data.regularity = [deg-2 deg-2]; % Regularity of the splines diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m index 5b9dec32..885d25d7 100644 --- a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_3patch_hyperboloid_clamped.m @@ -1,4 +1,5 @@ -clear problem_data method_data +% PHYSICAL DATA OF THE PROBLEM +clear problem_data problem_data.geo_name = 'geo_hyperboloid_ASG1.txt'; @@ -25,7 +26,8 @@ reshape (hy (x,y,z), [1, size(x)]), ... reshape (hz (x,y,z), [1, size(x)])); -% Discretization parameters +% DISCRETIZATION PARAMETERS +clear method_data deg = 4; method_data.degree = deg*[1 1]; % Degree of the splines method_data.regularity = (deg-2)*[1 1]; % Regularity of the splines diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m index f940dd04..435d4054 100644 --- a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_4patch_paraboloid.m @@ -1,4 +1,5 @@ -clear problem_data method_data +% PHYSICAL DATA OF THE PROBLEM +clear problem_data problem_data.geo_name = 'geo_paraboloid_ASG1.txt'; @@ -24,12 +25,13 @@ reshape (hy (x,y,z), [1, size(x)]), ... reshape (hz (x,y,z), [1, size(x)])); -% Discretization parameters +% DISCRETIZATION PARAMETERS +clear method_data deg = 4; -method_data.degree = deg*[1 1]; % Degree of the splines -method_data.regularity = (deg-2)*[1 1]; % Regularity of the splines +method_data.degree = deg*[1 1]; % Degree of the splines +method_data.regularity = (deg-2)*[1 1]; % Regularity of the splines method_data.nsub = [16 16]; % Number of subdivisions of the coarsest mesh, with respect to the mesh in geometry -method_data.nquad = (deg+1)*[1 1]; % Points for the Gaussian quadrature rule +method_data.nquad = (deg+1)*[1 1]; % Points for the Gaussian quadrature rule [geometry, msh, space, u] = ... mp_solve_kirchhoff_love_shell_C1_scalarspace (problem_data, method_data); diff --git a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m index 4b4f4a6a..46d72893 100644 --- a/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m +++ b/geopdes/inst/examples/kirchhoff_love_shell/ex_KL_hyperboloid_clamped.m @@ -1,4 +1,5 @@ -clear problem_data method_data +% PHYSICAL DATA OF THE PROBLEM +clear problem_data nrb = nrb4surf ([-0.5, -0.5], [0.5, -0.5], [-0.5, 0.5], [0.5 0.5]); nrb = nrbdegelev (nrb, [1 1]); @@ -28,7 +29,8 @@ reshape (hy (x,y,z), [1, size(x)]), ... reshape (hz (x,y,z), [1, size(x)])); -% Discretization parameters +% DISCRETIZATION PARAMETERS +clear method_data deg = 3; method_data.degree = deg*[1 1]; % Degree of the splines method_data.regularity = (deg-1)*[1 1]; % Regularity of the splines From b760798dc838493360bcfd9eab9dc01be6e8edee Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 3 Jul 2024 17:08:01 +0200 Subject: [PATCH 340/366] Cleaning --- geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m index d1d7f909..37015833 100644 --- a/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m +++ b/geopdes/inst/examples/base/ex_bilaplacian_Lshaped_8patch.m @@ -14,9 +14,6 @@ % reshape (zeros(size(x)), [1, size(x)])); % Source and boundary terms -C = 1; -p = -1; -% Bilaplacian problem_data.f = @bilaplacian_rhs_Lshaped; % problem_data.g = @(x, y, ind) bilaplacian_Lshaped_g_nmnn_8patches (x,y,ind); problem_data.h = @(x, y, ind) solution_bilaplacian_Lshaped (x, y); From 7a1cab7a2b2b44407c6837c6024f53b04482d87f Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 3 Jul 2024 17:48:13 +0200 Subject: [PATCH 341/366] Aesthetics --- geopdes/inst/examples/base/ex_laplace_3patches_C1.m | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m index 8d1bf380..2a14e0c7 100644 --- a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m +++ b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m @@ -10,8 +10,9 @@ problem_data.c_diff = @(x, y) ones(size(x)); % Source and boundary terms -C = 20; P=[17/3+0.15, 2+0.075]; -alpha=4/6; +C = 20; +P = [17/3+0.15, 2+0.075]; +alpha = 4/6; problem_data.f = @(x,y) -2*alpha*((x-P(1)).^2+(y-P(2)).^2).^(alpha-2).*... (((x-P(1)).^2+(y-P(2)).^2)+2*(alpha-1)*(x-P(1)).^2)... -2*alpha*((x-P(1)).^2+(y-P(2)).^2).^(alpha-2).*... From 789897eb26304bbc6b42e2edf9cac997c8e3f4da Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 3 Jul 2024 18:02:10 +0200 Subject: [PATCH 342/366] Removed unused boundary type --- geopdes/inst/examples/base/ex_laplace_3patches_C1.m | 1 - geopdes/inst/examples/base/ex_laplace_6patches_C1.m | 1 - 2 files changed, 2 deletions(-) diff --git a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m index 2a14e0c7..11154804 100644 --- a/geopdes/inst/examples/base/ex_laplace_3patches_C1.m +++ b/geopdes/inst/examples/base/ex_laplace_3patches_C1.m @@ -4,7 +4,6 @@ % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; -problem_data.drchlt_sides = []; problem_data.weak_drchlt_sides = [1 2 3 4 5 6]; problem_data.c_diff = @(x, y) ones(size(x)); diff --git a/geopdes/inst/examples/base/ex_laplace_6patches_C1.m b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m index 076cf841..404888e5 100644 --- a/geopdes/inst/examples/base/ex_laplace_6patches_C1.m +++ b/geopdes/inst/examples/base/ex_laplace_6patches_C1.m @@ -5,7 +5,6 @@ % Type of boundary conditions for each side of the domain problem_data.nmnn_sides = []; -problem_data.drchlt_sides = []; problem_data.weak_drchlt_sides = [1 2 3 4 5 6 7 8]; problem_data.c_diff = @(x, y) ones(size(x)); From 430a4e581334c10f2bf4f5b1ada3e1278a42c9df Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 15 Jul 2024 13:04:23 +0200 Subject: [PATCH 343/366] Minor changes in the examples --- .../examples/cahn-hilliard/ex_cahn_hilliard.m | 4 ++-- .../cahn-hilliard/ex_cahn_hilliard_mpC1.m | 16 ++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index 23a24bbb..1a22c36e 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -12,8 +12,8 @@ % Time and time step size Time_max = .08; -dt = 1e-4; -time_step_save = linspace(dt,Time_max,9); +dt = 1e-3; +time_step_save = linspace(dt,Time_max,20); problem_data.time = 0; problem_data.Time_max = Time_max; diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index 1d9d86a6..ae810fde 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -1,5 +1,3 @@ -clc - % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file @@ -68,11 +66,9 @@ sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'u','grad_u'}, {'value','gradient'}) end -% % 5.3) PLOT LAST RESULT -% [eu, F] = sp_eval (results.u(:,end), space, geometry, vtk_pts); -% [X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); -% surf (X, Y, eu) -% colorbar -% view(0,90) -% shading interp -% axis equal tight \ No newline at end of file +% 5.3) PLOT LAST RESULT +sp_plot_solution (results.u(:,end), space, geometry); +colorbar +view(0,90) +shading interp +axis equal tight \ No newline at end of file From c4ca192d3db4346fcfecccbd33d5dc955cc95a54 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 15 Jul 2024 13:05:44 +0200 Subject: [PATCH 344/366] Cosmetics --- .../multipatch/mp_solve_cahn_hilliard_C1.m | 61 ++----------------- geopdes/inst/solve/solve_cahn_hilliard.m | 32 +++++----- 2 files changed, 20 insertions(+), 73 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 11c19c39..bc13f8b0 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -38,9 +38,9 @@ % % OUTPUT: % -% geometry: geometry structure (see geo_load) -% msh: mesh object that defines the quadrature rule (see msh_cartesian) -% space: space object that defines the discrete space (see sp_scalar) +% geometry: geometry structure (see mp_geo_load) +% msh: mesh object that defines the quadrature rule (see msh_multipatch) +% space: space object that defines the discrete space (see sp_multipatch_C1) % results: a struct with the saved results, containing the following fields: % - time: (array of length Ntime) time at which the solution was saved % - u: (size ndof x Ntime) degrees of freedom for the solution @@ -118,7 +118,7 @@ %%------------------------------------------------------------------------- % No flux b.c. (essential boundary condition) -% Set Neumann boundary conditions for non-periodic sides +% Set Neumann boundary conditions for every side nmnn_bou = 1:numel(boundaries); %%------------------------------------------------------------------------- @@ -377,60 +377,9 @@ end - -% function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) -% -% msh_side = msh_eval_boundary_side (msh, i_side ) ; -% msh_side_int = msh_boundary_side_from_interior (msh, i_side ) ; -% sp_side = space.constructor ( msh_side_int) ; -% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient', true ); -% -% -% coe_side = pen .* msh_side.charlen; -% mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); -% -% -% rhs_pen = zeros(space.ndof,1); % no flux -% -% end - %-------------------------------------------------------------------------- % check flux through the boundaries %-------------------------------------------------------------------------- % function flux = check_flux_phase_field(space, msh, uhat, uhat0) -% -% sides = [1,2,3,4]; % all the boundaries -% flux = 0; -% -% for iside=1:length(sides) -% -% msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; -% msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; -% sp_side = space.constructor ( msh_side_int) ; -% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); -% -% -% gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); -% -% -% -% valu = zeros(sp_side.ncomp, size(msh_side.quad_weights,1), size(msh_side.quad_weights,2)); -% for idim = 1:msh.rdim -% valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); -% end -% -% -% w =msh_side.quad_weights .* msh_side.jacdet; -% err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); -% err = sum (err_elem); -% -% -% flux = flux + err; -% -% end -% -% -% -% end - +% NOT IMPLEMENTED IN THE MULTIPATCH CASE diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 242c4cca..f4e9686a 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -25,7 +25,6 @@ % - Time_max: final time % - fun_u: initial condition. Equal to zero by default. % - fun_udot: initial condition for time derivative. Equal to zero by default. -% - nmnn_sides: sides with Neumann boundary condition (may be empty) % % method_data : a structure with discretization data. Its fields are: % - degree: degree of the spline functions. @@ -133,7 +132,7 @@ % Precompute matrices % Compute the mass matrix -mass_mat = op_u_v_tp(space,space,msh); +mass_mat = op_u_v_tp (space,space,msh); % Compute the laplace matrix lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); @@ -282,11 +281,11 @@ end % Compute the update, and update the solution - A_gl = a_m * mass_mat + a_f * gamma *dt * stiff_mat ; + A_gl = a_m * mass_mat + a_f * gamma * dt * stiff_mat ; d_udot = - A_gl\Res_gl; udot_n1 = udot_n1 + d_udot; - u_n1 = u_n1 + gamma * dt* d_udot; + u_n1 = u_n1 + gamma * dt * d_udot; end end @@ -299,7 +298,7 @@ mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, u_a, udot_a, mu, dmu) % Double well (matrices) - [term2, term2K] = op_gradfu_gradv_tp(space, msh, u_a, mu, dmu); + [term2, term2K] = op_gradfu_gradv_tp (space, msh, u_a, mu, dmu); % Residual Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; @@ -324,7 +323,7 @@ A = spalloc (space.ndof, space.ndof, 3*space.ndof); - for iside=1:numel(nmnn_sides) + for iside = 1:numel(nmnn_sides) msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; @@ -364,11 +363,10 @@ function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) -msh_side = msh_eval_boundary_side (msh, i_side ) ; -msh_side_int = msh_boundary_side_from_interior (msh, i_side ) ; -sp_side = space.constructor ( msh_side_int) ; -sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient', true ); - +msh_side = msh_eval_boundary_side (msh, i_side); +msh_side_int = msh_boundary_side_from_interior (msh, i_side); +sp_side = space.constructor (msh_side_int); +sp_side = sp_precompute (sp_side , msh_side_int , 'gradient', true); coe_side = pen .* msh_side.charlen; mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); @@ -388,10 +386,10 @@ for iside = 1:numel(sides) - msh_side = msh_eval_boundary_side (msh, sides(iside) ) ; - msh_side_int = msh_boundary_side_from_interior (msh, sides(iside) ) ; - sp_side = space.constructor ( msh_side_int) ; - sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true ); + msh_side = msh_eval_boundary_side (msh, sides(iside)); + msh_side_int = msh_boundary_side_from_interior (msh, sides(iside)); + sp_side = space.constructor (msh_side_int); + sp_side = sp_precompute (sp_side , msh_side_int , 'gradient', true ); gradu = sp_eval_msh (uhat-uhat0, sp_side, msh_side, 'gradient'); @@ -400,9 +398,9 @@ valu = valu + (gradu(idim,:,:) .* msh_side.normal(idim,:,:)); end - w =msh_side.quad_weights .* msh_side.jacdet; + w = msh_side.quad_weights .* msh_side.jacdet; err_elem = sum (reshape (valu, [msh_side.nqn, msh_side.nel]) .* w); - err = sum (err_elem); + err = sum (err_elem); flux = flux + err; end From 9dda04728fe9e702beb7ceb2d84b96630fc46812 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 15 Jul 2024 13:06:08 +0200 Subject: [PATCH 345/366] Change in the help --- geopdes/inst/utils/newtons_method.m | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/geopdes/inst/utils/newtons_method.m b/geopdes/inst/utils/newtons_method.m index c3a49042..e249f5d4 100644 --- a/geopdes/inst/utils/newtons_method.m +++ b/geopdes/inst/utils/newtons_method.m @@ -7,16 +7,17 @@ % % INPUT: % -% f: function handler of the non-linear system -% x0: starting vector -% jac: function handler of the Jacobian of the non-linear system -% tol: tolerance of the method +% f: function handle of the non-linear system +% x0: starting vector +% jac: function handle of the Jacobian of the non-linear system +% tol: tolerance of the method +% maxit: maximum number of iterations % % OUTPUT: % -% x: solution such that f(x) = 0 +% x: solution such that f(x) = 0 % err: residual of the last iteration -% it: number of iterations +% it: number of iterations % % Copyright (C) 2018 Luca Pegolotti % @@ -51,5 +52,4 @@ disp([' done, error = ',num2str(err)]); end - - +end From 87af349686d4721eddc57beed96f55b57a88abd3 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 15 Jul 2024 19:05:42 +0200 Subject: [PATCH 346/366] Nitsche info in method_data, as in other problems --- geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m | 7 +++---- .../inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m | 8 +++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index 1a22c36e..a2d419fd 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -18,10 +18,6 @@ problem_data.Time_max = Time_max; -% Penalty parameters -problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter -problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) - % 2) INITIAL CONDITIONS % mean = 0.0; % var = 0.2; @@ -42,6 +38,9 @@ method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method method_data.dt = dt; % Time step size +% Penalty parameters +method_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter +method_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) % 4) CALL TO THE SOLVER diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index ae810fde..b26a5ca6 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -17,11 +17,6 @@ problem_data.time = 0; problem_data.Time_max = Time_max; - -% Penalty parameters -problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter -problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) - % 2) INITIAL CONDITIONS mean = 0.4; var = 0.05; @@ -42,6 +37,9 @@ method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method method_data.dt = dt; % Time step size +% Penalty parameters +problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter +problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) % 4) CALL TO THE SOLVER From 6a62077cbff3eb18649c3dafc5abd815d47e8c08 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 16 Jul 2024 14:16:50 +0200 Subject: [PATCH 347/366] Double well data given in problem_data --- .../inst/examples/cahn-hilliard/ex_cahn_hilliard.m | 6 +++++- .../examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m | 7 +++++-- geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m | 12 +++--------- geopdes/inst/solve/solve_cahn_hilliard.m | 11 +++-------- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index a2d419fd..cdfdfddb 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -3,9 +3,13 @@ % Physical domain, defined as NURBS map given in a text file problem_data.geo_name = 'geo_square.txt'; -% Physical parameters +% Physical parameters (see solve_cahn_hilliard) lambda = (1/(4*sqrt(2)*pi))^2; problem_data.lambda = @(x, y) lambda* ones(size(x)); +alpha = 1; +beta = 1; +problem_data.mu = @(x) 3 * alpha * x.^2 - beta; +problem_data.dmu = @(x) 6 * alpha * x; % Periodic directions and boundary conditions problem_data.periodic_directions = []; diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index b26a5ca6..a35a80eb 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -5,10 +5,13 @@ nrb2 = nrb4surf ([.5 0], [1 0], [.5 1], [1 1]); problem_data.geo_name = [nrb1,nrb2]; %'geo_square_mp.txt'; -% Physical parameters +% Physical parameters (see mp_solve_cahn_hilliard_C1) lambda = (1/(4*sqrt(2)*pi))^2; problem_data.lambda = @(x, y) lambda* ones(size(x)); - +alpha = 1; +beta = 1; +problem_data.mu = @(x) 3 * alpha * x.^2 - beta; +problem_data.dmu = @(x) 6 * alpha * x; % Time and time step size Time_max = .5; diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index bc13f8b0..c537ac0a 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -6,7 +6,7 @@ % % with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and Neumann boundary conditions. % -% The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. +% The values of mu and its derivative are given in problem_data, and used in op_gradfu_gradv_tp. % % For details on the problem and the formulation, see % H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. @@ -22,10 +22,11 @@ % - geo_name: name of the file containing the geometry % - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) % - lambda: parameter representing the length scale of the problem, and the width of the interface +% - mu: function handle to compute mu (from the double well function) +% - dmu: function handle to compute the derivative of mu % - Time_max: final time % - fun_u: initial condition. Equal to zero by default. % - fun_udot: initial condition for time derivative. Equal to zero by default. -% - nmnn_sides: sides with Neumann boundary condition (may be empty) % % method_data : a structure with discretization data. Its fields are: % - degree: degree of the spline functions. @@ -77,13 +78,6 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end -%%------------------------------------------------------------------------- -% Parameters for the double-well function (to be given in problem_data) -alpha = 1; -beta = 1; -mu = @(x) 3 * alpha * x.^2 - beta; -dmu = @(x) 6 * alpha * x; - %%------------------------------------------------------------------------- % Construct geometry structure, and information for interfaces and boundaries [geometry, boundaries, interfaces, ~, boundary_interfaces] = mp_geo_load (geo_name); diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index f4e9686a..22e287a3 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -6,7 +6,7 @@ % % with Delta the Laplacian, and mu(u) = alpha u^3 - beta u, and periodic or Neumann boundary conditions. % -% The values of alpha and beta (or mu itself) can be changed in op_gradmu_gradv_tp. +% The values of mu and its derivative are given in problem_data, and used in op_gradfu_gradv_tp. % % For details on the problem and the formulation, see % H. Gomez, V.M. Calo, Y. Bazilevs, T.J.R. Hughes, CMAME 197 (2008), 4333-4352. @@ -22,6 +22,8 @@ % - geo_name: name of the file containing the geometry % - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) % - lambda: parameter representing the length scale of the problem, and the width of the interface +% - mu: function handle to compute mu (from the double well function) +% - dmu: function handle to compute the derivative of mu % - Time_max: final time % - fun_u: initial condition. Equal to zero by default. % - fun_udot: initial condition for time derivative. Equal to zero by default. @@ -78,13 +80,6 @@ eval ([data_names{iopt} '= method_data.(data_names{iopt});']); end -%%------------------------------------------------------------------------- -% Parameters for the double-well function (to be given in problem_data) -alpha = 1; -beta = 1; -mu = @(x) 3 * alpha * x.^2 - beta; -dmu = @(x) 6 * alpha * x; - %%------------------------------------------------------------------------- % Construct geometry structure geometry = geo_load (geo_name); From 455f6d984e1a915075f058137b0a893165deefa9 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 16 Jul 2024 16:52:05 +0200 Subject: [PATCH 348/366] Cosmetics --- .../inst/multipatch/mp_solve_cahn_hilliard_C1.m | 15 +++++++-------- geopdes/inst/solve/solve_cahn_hilliard.m | 8 ++++---- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index c537ac0a..d0b9b3cf 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -108,12 +108,12 @@ % Generalized alpha parameters a_m = .5*((3-rho_inf_gen_alpha)/(1+rho_inf_gen_alpha)); a_f = 1/(1+rho_inf_gen_alpha); -gamma = .5 + a_m - a_f; +gamma = .5 + a_m - a_f; %%------------------------------------------------------------------------- % No flux b.c. (essential boundary condition) % Set Neumann boundary conditions for every side -nmnn_bou = 1:numel(boundaries); +nmnn_bou = 1:numel(boundaries); %%------------------------------------------------------------------------- % Precompute matrices @@ -173,7 +173,7 @@ [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); - % check flux through the boundary +% check flux through the boundary % flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); % disp(strcat('flux norm =',num2str(flux))) @@ -246,23 +246,22 @@ u_a, udot_a, mu, dmu); % Convergence check - if iter == 0 + if (iter == 0) norm_res_0 = norm(Res_gl); end norm_res = norm(Res_gl); - - if norm_res/norm_res_0 < tol_rel_res + if (norm_res/norm_res_0 < tol_rel_res) disp(strcat('iteration n°=',num2str(iter))) disp(strcat('norm (abs) residual=',num2str(norm_res))) break end - if norm_res Date: Thu, 18 Jul 2024 09:13:48 +0200 Subject: [PATCH 351/366] Operator for penalty terms inside the class --- .../@sp_multipatch_C1/op_penalty_dudn.m | 70 +++++++++++++++++++ .../inst/space/@sp_scalar/op_penalty_dudn.m | 60 ++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m create mode 100644 geopdes/inst/space/@sp_scalar/op_penalty_dudn.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m new file mode 100644 index 00000000..fced149c --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m @@ -0,0 +1,70 @@ +% OP_PENALTY_DUDN: matrix and right-hand side to compute penalty terms to impose du/dn = f. +% It computes the terms of the form Cp*(du/dn, dv/dn) and Cp*(f, dv/dn), +% using the same space for trial and test functions. +% +% [mat, rhs] = op_penalty_dudn (space, msh, sides, Cpen, [coeff]); +% +% INPUT: +% +% space: object representing the space of trial functions (see sp_multipatch_C1) +% msh: object defining the domain partition and the quadrature rule (see msh_multipatch) +% sides: boundary sides on which to compute the integrals +% Cpen: penalization parameter, Cp in the equation above +% coeff: function handle to compute the Neumann condition. If empty, the returned rhs will be zero. +% +% OUTPUT: +% +% mat: assembled mass matrix +% rhs: assembled right-hand side +% +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [P, rhs] = op_penalty_dudn (space, msh, sides, Cpen, coeff) + + P = spalloc (space.ndof, space.ndof, space.ndof); + rhs = zeros(space.ndof, 1); + + for iref = sides + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); + msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); + + sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); + sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', false, 'gradient', true); + + coe_side = Cpen .* msh_side.charlen; + tmp = op_gradu_n_gradv_n(sp_bnd, sp_bnd, msh_side, coe_side); + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... + Cpatch.' * (tmp) * Cpatch; + + if (nargin == 6) + x = cell (msh.rdim, 1); + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + rhs(Cpatch_cols) = rhs(Cpatch_cols) + ... + Cpatch.' *op_gradv_n_f (sp_bnd, msh_side, Cpen*coeff(x{:})); + end + + end + end + +end diff --git a/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m b/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m new file mode 100644 index 00000000..73481f8f --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m @@ -0,0 +1,60 @@ +% OP_PENALTY_DUDN: matrix and right-hand side to compute penalty terms to impose du/dn = f. +% It computes the terms of the form Cp*(du/dn, dv/dn) and Cp*(f, dv/dn), +% using the same space for trial and test functions. +% +% [mat, rhs] = op_penalty_dudn (space, msh, sides, Cpen, [coeff]); +% +% INPUT: +% +% space: object representing the space of trial functions (see sp_scalar) +% msh: object defining the domain partition and the quadrature rule (see msh_cartesian) +% sides: boundary sides on which to compute the integrals +% Cpen: penalization parameter, Cp in the equation above +% coeff: function handle to compute the Neumann condition. If empty, the returned rhs will be zero. +% +% OUTPUT: +% +% mat: assembled mass matrix +% rhs: assembled right-hand side +% +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [P, rhs] = op_penalty_dudn (space, msh, sides, Cpen, coeff) + + P = spalloc (space.ndof, space.ndof, space.ndof); + rhs = zeros(space.ndof, 1); + + for iside = 1:numel(sides) + msh_side = msh_eval_boundary_side (msh, iside); + msh_side_int = msh_boundary_side_from_interior (msh, iside); + sp_side = space.constructor (msh_side_int); + sp_side = sp_precompute (sp_side , msh_side_int , 'gradient', true); + + coe_side = Cpen .* msh_side.charlen; + mass_pen = op_gradu_n_gradv_n (sp_side, sp_side, msh_side, coe_side); + + if (nargin == 6) + x = cell (msh.rdim, 1); + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + rhs = rhs + op_gradv_n_f (sp_side, msh_side, Cpen*coeff(x{:})); + end + + P = P + mass_pen; + end + +end From 808e5b3216b5ad57d1216f842e1a7f2b9e553faf Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 18 Jul 2024 09:15:02 +0200 Subject: [PATCH 352/366] Commented penalty operators, to be removed. --- .../multipatch/mp_solve_cahn_hilliard_C1.m | 70 +++++++++---------- geopdes/inst/solve/solve_cahn_hilliard.m | 65 ++++++++--------- .../@sp_scalar/sp_weak_drchlt_bc_laplace.m | 2 +- 3 files changed, 69 insertions(+), 68 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index d0b9b3cf..c0b51d7f 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -113,7 +113,7 @@ %%------------------------------------------------------------------------- % No flux b.c. (essential boundary condition) % Set Neumann boundary conditions for every side -nmnn_bou = 1:numel(boundaries); +nmnn_sides = 1:numel(boundaries); %%------------------------------------------------------------------------- % Precompute matrices @@ -125,10 +125,10 @@ lapl_mat = op_laplaceu_laplacev_mp (space, space, msh, lambda); % Compute the boundary term -bnd_mat = int_boundary_term (space, msh, lambda, nmnn_bou); +bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); % Compute the penalty matrix -[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_bou, Cpen_nitsche); +[Pen, pen_rhs] = op_penalty_dudn (space, msh, nmnn_sides, Cpen_nitsche); %%------------------------------------------------------------------------- @@ -337,38 +337,38 @@ end end -%-------------------------------------------------------------------------- -% penalty term -%-------------------------------------------------------------------------- - -function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) - - P = spalloc (space.ndof, space.ndof, 3*space.ndof); - rhs = zeros(space.ndof,1); - - for iref = nmnn_sides - for bnd_side = 1:msh.boundaries(iref).nsides - iptc = msh.boundaries(iref).patches(bnd_side); - iside = msh.boundaries(iref).faces(bnd_side); - - msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); - msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); - - sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); - sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', false, 'gradient', true); - - coe_side = pen .* msh_side.charlen; - tmp = op_gradu_n_gradv_n(sp_bnd, sp_bnd, msh_side, coe_side); - - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... - Cpatch.' * (tmp) * Cpatch; - - %rhs = rhs + rhs_pen; - end - end - -end +% %-------------------------------------------------------------------------- +% % penalty term +% %-------------------------------------------------------------------------- +% +% function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) +% +% P = spalloc (space.ndof, space.ndof, 3*space.ndof); +% rhs = zeros(space.ndof,1); +% +% for iref = nmnn_sides +% for bnd_side = 1:msh.boundaries(iref).nsides +% iptc = msh.boundaries(iref).patches(bnd_side); +% iside = msh.boundaries(iref).faces(bnd_side); +% +% msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside); +% msh_side_from_interior = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside); +% +% sp_bnd = space.sp_patch{iptc}.constructor (msh_side_from_interior); +% sp_bnd = sp_precompute (sp_bnd, msh_side_from_interior, 'value', false, 'gradient', true); +% +% coe_side = pen .* msh_side.charlen; +% tmp = op_gradu_n_gradv_n(sp_bnd, sp_bnd, msh_side, coe_side); +% +% [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); +% P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... +% Cpatch.' * (tmp) * Cpatch; +% +% %rhs = rhs + rhs_pen; +% end +% end +% +% end %-------------------------------------------------------------------------- % check flux through the boundaries diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index b9f0f9b2..b0d80860 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -136,7 +136,8 @@ bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); % Compute the penalty matrix -[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, Cpen_nitsche); +%[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, Cpen_nitsche); +[Pen, pen_rhs] = op_penalty_dudn (space, msh, nmnn_sides, Cpen_nitsche); %%------------------------------------------------------------------------- @@ -338,37 +339,37 @@ end end -%-------------------------------------------------------------------------- -% Penalty term -%-------------------------------------------------------------------------- - -function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) - - P = spalloc (space.ndof, space.ndof, 3*space.ndof); - rhs = zeros(space.ndof,1); - - for iside = 1:numel(nmnn_sides) - [mass_pen, rhs_pen] = penalty_grad (space, msh, nmnn_sides(iside), pen); - P = P + mass_pen; - rhs = rhs + rhs_pen; - end - -end - - -function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) - -msh_side = msh_eval_boundary_side (msh, i_side); -msh_side_int = msh_boundary_side_from_interior (msh, i_side); -sp_side = space.constructor (msh_side_int); -sp_side = sp_precompute (sp_side , msh_side_int , 'gradient', true); - -coe_side = pen .* msh_side.charlen; -mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); - -rhs_pen = zeros(space.ndof,1); - -end +% %-------------------------------------------------------------------------- +% % Penalty term +% %-------------------------------------------------------------------------- +% +% function [P, rhs] = penalty_matrix (space, msh, nmnn_sides, pen) +% +% P = spalloc (space.ndof, space.ndof, 3*space.ndof); +% rhs = zeros(space.ndof,1); +% +% for iside = 1:numel(nmnn_sides) +% [mass_pen, rhs_pen] = penalty_grad (space, msh, nmnn_sides(iside), pen); +% P = P + mass_pen; +% rhs = rhs + rhs_pen; +% end +% +% end +% +% +% function [mass_pen, rhs_pen] = penalty_grad (space, msh, i_side, pen) +% +% msh_side = msh_eval_boundary_side (msh, i_side); +% msh_side_int = msh_boundary_side_from_interior (msh, i_side); +% sp_side = space.constructor (msh_side_int); +% sp_side = sp_precompute (sp_side , msh_side_int , 'gradient', true); +% +% coe_side = pen .* msh_side.charlen; +% mass_pen = op_gradu_n_gradv_n(sp_side, sp_side, msh_side, coe_side); +% +% rhs_pen = zeros(space.ndof,1); +% +% end %-------------------------------------------------------------------------- % Check flux through the boundaries diff --git a/geopdes/inst/space/@sp_scalar/sp_weak_drchlt_bc_laplace.m b/geopdes/inst/space/@sp_scalar/sp_weak_drchlt_bc_laplace.m index ff3b97aa..89328df8 100644 --- a/geopdes/inst/space/@sp_scalar/sp_weak_drchlt_bc_laplace.m +++ b/geopdes/inst/space/@sp_scalar/sp_weak_drchlt_bc_laplace.m @@ -17,7 +17,7 @@ % % INPUTS: % -% space: space object (see sp_vector) +% space: space object (see sp_scalar) % msh: mesh object (see msh_cartesian) % bnd_sides: boundary sides on which the Dirichlet condition is imposed % bnd_func: the condition to be imposed (g in the equations) From c4960b7e5def19d40f6aadf1e58cd0d684e1aace Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Thu, 18 Jul 2024 10:59:01 +0200 Subject: [PATCH 353/366] Fixed number of input arguments --- geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m | 2 +- geopdes/inst/space/@sp_scalar/op_penalty_dudn.m | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m index fced149c..d6085cb4 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_penalty_dudn.m @@ -55,7 +55,7 @@ P(Cpatch_cols,Cpatch_cols) = P(Cpatch_cols,Cpatch_cols) + ... Cpatch.' * (tmp) * Cpatch; - if (nargin == 6) + if (nargin == 5) x = cell (msh.rdim, 1); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); diff --git a/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m b/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m index 73481f8f..9b56dedb 100644 --- a/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m +++ b/geopdes/inst/space/@sp_scalar/op_penalty_dudn.m @@ -46,7 +46,7 @@ coe_side = Cpen .* msh_side.charlen; mass_pen = op_gradu_n_gradv_n (sp_side, sp_side, msh_side, coe_side); - if (nargin == 6) + if (nargin == 5) x = cell (msh.rdim, 1); for idim = 1:msh.rdim x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); From 32e930941b011b04505a5fd580c8109d98b46c38 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 22 Jul 2024 12:09:30 +0200 Subject: [PATCH 354/366] New functions, intead of int_boundary_term --- geopdes/INDEX | 46 +++++----- .../op_nitsche_consistency_cahn_hilliard.m | 68 +++++++++++++++ .../multipatch/mp_solve_cahn_hilliard_C1.m | 84 +++++++++---------- geopdes/inst/solve/solve_cahn_hilliard.m | 66 +++++++-------- .../op_nitsche_consistency_cahn_hilliard.m | 60 +++++++++++++ 5 files changed, 226 insertions(+), 98 deletions(-) create mode 100644 geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m create mode 100644 geopdes/inst/space/@sp_scalar/op_nitsche_consistency_cahn_hilliard.m diff --git a/geopdes/INDEX b/geopdes/INDEX index 641541e1..8488825d 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -75,6 +75,8 @@ Space: functions to generate and compute discrete spline and NURBS spaces @sp_scalar/sp_to_vtk @sp_scalar/sp_drchlt_l2_proj @sp_scalar/sp_weak_drchlt_bc_laplace + @sp_scalar/op_penalty_dudn + @sp_scalar/op_nitsche_consistency_cahn_hilliard @sp_scalar/sp_get_basis_functions @sp_scalar/sp_get_cells @sp_scalar/sp_get_neighbors @@ -183,27 +185,29 @@ Multipatch: functions of different kinds to solve problems in domains defined by @sp_multipatch/sp_weak_drchlt_bc_stokes @sp_multipatch/sp_refine sp_multipatch_C1 - @sp_multipatch/sp_l2_error - @sp_multipatch/sp_h1_error - @sp_multipatch/sp_h2_error - @sp_multipatch/sp_h2_equiv_lap_error - @sp_multipatch/sp_plot_solution - @sp_multipatch/sp_to_vtk - @sp_multipatch/sp_eval_phys - @sp_multipatch/sp_evaluate_element_list - @sp_multipatch/sp_get_cells - @sp_multipatch/sp_get_basis_functions - @sp_multipatch/sp_get_functions_on_patch - @sp_multipatch/sp_get_local_interior_functions - @sp_multipatch/sp_get_neighbors - @sp_multipatch/sp_compute_Cpatch - @sp_multipatch/sp_compute_Cpatch_vector - @sp_multipatch/sp_bilaplacian_drchlt_C1_exact - @sp_multipatch/sp_bilaplacian_drchlt_C1 - @sp_multipatch/sp_drchlt_C1_shells - @sp_multipatch/sp_nitsche_KL_rotation - @sp_multipatch/sp_weak_drchlt_bc_laplace - @sp_multipatch/sp_refine + @sp_multipatch_C1/sp_l2_error + @sp_multipatch_C1/sp_h1_error + @sp_multipatch_C1/sp_h2_error + @sp_multipatch_C1/sp_h2_equiv_lap_error + @sp_multipatch_C1/sp_plot_solution + @sp_multipatch_C1/sp_to_vtk + @sp_multipatch_C1/sp_eval_phys + @sp_multipatch_C1/sp_evaluate_element_list + @sp_multipatch_C1/sp_get_cells + @sp_multipatch_C1/sp_get_basis_functions + @sp_multipatch_C1/sp_get_functions_on_patch + @sp_multipatch_C1/sp_get_local_interior_functions + @sp_multipatch_C1/sp_get_neighbors + @sp_multipatch_C1/sp_compute_Cpatch + @sp_multipatch_C1/sp_compute_Cpatch_vector + @sp_multipatch_C1/sp_bilaplacian_drchlt_C1_exact + @sp_multipatch_C1/sp_bilaplacian_drchlt_C1 + @sp_multipatch_C1/sp_drchlt_C1_shells + @sp_multipatch_C1/sp_nitsche_KL_rotation + @sp_multipatch_C1/sp_weak_drchlt_bc_laplace + @sp_multipatch_C1/op_penalty_dudn + @sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard + @sp_multipatch_C1/sp_refine Utilities: other functions in the package collocation_csp knt_derham diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m new file mode 100644 index 00000000..f67be7b9 --- /dev/null +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m @@ -0,0 +1,68 @@ +% OP_NITSCHE_CONSISTENCY_CAHN_HILLIARD: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon (grad v n)_j, Delta u_i), +% with n the normal vector to the boundary, using the same space for trial and test functions. +% +% mat = op_nitsche_consistency_cahn_hilliard (space, msh, sides, [coeff]); +% +% INPUT: +% +% space: object representing the space of trial functions (see sp_multipatch_C1) +% msh: object defining the mesh (see msh_multipatch) +% sides: boundary sides on which to compute the integrals +% coeff: function handle to compute the epsilon coefficient. If empty, it is taken equal to one. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A] = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, coeff) + + if (nargin == 3 || isempty(coeff)) + coeff = @(varargin) ones (size(varargin{1})); + end + + if (~isempty(nmnn_sides)) + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + + for iref = nmnn_sides + for bnd_side = 1:msh.boundaries(iref).nsides + iptc = msh.boundaries(iref).patches(bnd_side); + iside = msh.boundaries(iref).faces(bnd_side); + + msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside ) ; + msh_side_int = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside ) ; + + sp_side = space.sp_patch{iptc}.constructor (msh_side_int); + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = coeff (x{:}); + tmp = op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); + + [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); + A(Cpatch_cols,Cpatch_cols) = ... + A(Cpatch_cols,Cpatch_cols) + Cpatch.' * tmp * Cpatch; + end + end + + else + A = []; + end +end diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index c0b51d7f..3dc75453 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -20,7 +20,6 @@ % % problem_data: a structure with data of the problem. It contains the fields: % - geo_name: name of the file containing the geometry -% - periodic_directions: parametric directions along which to apply periodic conditions (may be empty) % - lambda: parameter representing the length scale of the problem, and the width of the interface % - mu: function handle to compute mu (from the double well function) % - dmu: function handle to compute the derivative of mu @@ -50,7 +49,7 @@ % Only periodic and Neumann boundary conditions are implemented. Neumann % conditions are considered by default. % -% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -125,12 +124,11 @@ lapl_mat = op_laplaceu_laplacev_mp (space, space, msh, lambda); % Compute the boundary term -bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); +bnd_mat = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, lambda); % Compute the penalty matrix [Pen, pen_rhs] = op_penalty_dudn (space, msh, nmnn_sides, Cpen_nitsche); - %%------------------------------------------------------------------------- % Initial conditions time = 0; @@ -292,51 +290,51 @@ % Tangent stiffness matrix (mass is not considered here) stiff_mat = term2 + term2K + lapl_mat; - % in case of neumann BC, add boundary terms + % In case of Neumann BC, add boundary terms if (~isempty(bnd_mat)) Res_gl = Res_gl - (bnd_mat + bnd_mat.') * u_a + Pen*u_a - pen_rhs; stiff_mat = stiff_mat - (bnd_mat + bnd_mat.') + Pen; end end -%-------------------------------------------------------------------------- -% Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) -%-------------------------------------------------------------------------- - -function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) - - if (~isempty(nmnn_sides)) - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - - for iref = nmnn_sides - for bnd_side = 1:msh.boundaries(iref).nsides - iptc = msh.boundaries(iref).patches(bnd_side); - iside = msh.boundaries(iref).faces(bnd_side); - - msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside ) ; - msh_side_int = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside ) ; - - sp_side = space.sp_patch{iptc}.constructor (msh_side_int); - sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); - - for idim = 1:msh.rdim - x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); - end - coe_side = lambda (x{:}); - tmp = op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); - - [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); - A(Cpatch_cols,Cpatch_cols) = ... - A(Cpatch_cols,Cpatch_cols) + Cpatch.' * tmp * Cpatch; - end - end - - else - A = []; - end -end - +% %-------------------------------------------------------------------------- +% % Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) +% %-------------------------------------------------------------------------- +% +% function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) +% +% if (~isempty(nmnn_sides)) +% +% A = spalloc (space.ndof, space.ndof, 3*space.ndof); +% +% for iref = nmnn_sides +% for bnd_side = 1:msh.boundaries(iref).nsides +% iptc = msh.boundaries(iref).patches(bnd_side); +% iside = msh.boundaries(iref).faces(bnd_side); +% +% msh_side = msh_eval_boundary_side (msh.msh_patch{iptc}, iside ) ; +% msh_side_int = msh_boundary_side_from_interior (msh.msh_patch{iptc}, iside ) ; +% +% sp_side = space.sp_patch{iptc}.constructor (msh_side_int); +% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); +% +% for idim = 1:msh.rdim +% x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); +% end +% coe_side = lambda (x{:}); +% tmp = op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); +% +% [Cpatch, Cpatch_cols] = sp_compute_Cpatch (space, iptc); +% A(Cpatch_cols,Cpatch_cols) = ... +% A(Cpatch_cols,Cpatch_cols) + Cpatch.' * tmp * Cpatch; +% end +% end +% +% else +% A = []; +% end +% end +% % %-------------------------------------------------------------------------- % % penalty term % %-------------------------------------------------------------------------- diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index b0d80860..625e5797 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -52,7 +52,7 @@ % Only periodic and Neumann boundary conditions are implemented. Neumann % conditions are considered by default. % -% Copyright (C) 2023 Michele Torre, Rafael Vazquez +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by @@ -133,13 +133,12 @@ lapl_mat = op_laplaceu_laplacev_tp (space, space, msh, lambda); % Compute the boundary term -bnd_mat = int_boundary_term (space, msh, lambda, nmnn_sides); +bnd_mat = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, lambda); % Compute the penalty matrix %[Pen, pen_rhs] = penalty_matrix (space, msh, nmnn_sides, Cpen_nitsche); [Pen, pen_rhs] = op_penalty_dudn (space, msh, nmnn_sides, Cpen_nitsche); - %%------------------------------------------------------------------------- % Initial conditions time = 0; @@ -260,7 +259,6 @@ end norm_res = norm(Res_gl); - if (norm_res/norm_res_0 < tol_rel_res) disp(strcat('iteration n°=',num2str(iter))) disp(strcat('norm (abs) residual=',num2str(norm_res))) @@ -302,42 +300,42 @@ % Tangent stiffness matrix (mass is not considered here) stiff_mat = term2 + term2K + lapl_mat; - % In case of neumann BC, add boundary terms + % In case of Neumann BC, add boundary terms if (~isempty(bnd_mat)) Res_gl = Res_gl - (bnd_mat + bnd_mat.') * u_a + Pen*u_a - pen_rhs; stiff_mat = stiff_mat - (bnd_mat + bnd_mat.') + Pen; end end -%-------------------------------------------------------------------------- -% Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) -%-------------------------------------------------------------------------- - -function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) - - if (~isempty(nmnn_sides)) - - A = spalloc (space.ndof, space.ndof, 3*space.ndof); - - for iside = 1:numel(nmnn_sides) - - msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; - msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; - sp_side = space.constructor ( msh_side_int) ; - sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); - - for idim = 1:msh.rdim - x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); - end - coe_side = lambda (x{:}); - - A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); - end - - else - A = []; - end -end +% %-------------------------------------------------------------------------- +% % Boundary term, \int_\Gamma (\Delta u) (\partial v / \partial n) +% %-------------------------------------------------------------------------- +% +% function [A] = int_boundary_term (space, msh, lambda, nmnn_sides) +% +% if (~isempty(nmnn_sides)) +% +% A = spalloc (space.ndof, space.ndof, 3*space.ndof); +% +% for iside = 1:numel(nmnn_sides) +% +% msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; +% msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; +% sp_side = space.constructor ( msh_side_int) ; +% sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); +% +% for idim = 1:msh.rdim +% x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); +% end +% coe_side = lambda (x{:}); +% +% A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); +% end +% +% else +% A = []; +% end +% end % %-------------------------------------------------------------------------- % % Penalty term diff --git a/geopdes/inst/space/@sp_scalar/op_nitsche_consistency_cahn_hilliard.m b/geopdes/inst/space/@sp_scalar/op_nitsche_consistency_cahn_hilliard.m new file mode 100644 index 00000000..f7a9ebdb --- /dev/null +++ b/geopdes/inst/space/@sp_scalar/op_nitsche_consistency_cahn_hilliard.m @@ -0,0 +1,60 @@ +% OP_NITSCHE_CONSISTENCY_CAHN_HILLIARD: assemble the matrix A = [a(i,j)], a(i,j) = (epsilon (grad v n)_j, Delta u_i), +% with n the normal vector to the boundary, using the same space for trial and test functions. +% +% mat = op_nitsche_consistency_cahn_hilliard (space, msh, sides, [coeff]); +% +% INPUT: +% +% space: object representing the space of trial functions (see sp_scalar) +% msh: object defining the mesh (see msh_cartesian) +% sides: boundary sides on which to compute the integrals +% coeff: function handle to compute the epsilon coefficient. If empty, it is taken equal to one. +% +% OUTPUT: +% +% mat: assembled matrix +% +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [A] = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, coeff) + + if (nargin == 3 || isempty(coeff)) + coeff = @(varargin) ones (size(varargin{1})); + end + + if (~isempty(nmnn_sides)) + + A = spalloc (space.ndof, space.ndof, 3*space.ndof); + + for iside = 1:numel(nmnn_sides) + + msh_side = msh_eval_boundary_side (msh, nmnn_sides(iside) ) ; + msh_side_int = msh_boundary_side_from_interior (msh, nmnn_sides(iside) ) ; + sp_side = space.constructor ( msh_side_int) ; + sp_side = sp_precompute ( sp_side , msh_side_int , 'gradient' , true, 'laplacian', true ); + + for idim = 1:msh.rdim + x{idim} = reshape (msh_side.geo_map(idim,:,:), msh_side.nqn, msh_side.nel); + end + coe_side = coeff (x{:}); + + A = A + op_gradv_n_laplaceu(sp_side ,sp_side ,msh_side, coe_side); + end + + else + A = []; + end +end From 5dc132a6f33617d7858b8c1b5d5ab5b1d2e2215e Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Mon, 22 Jul 2024 13:39:24 +0200 Subject: [PATCH 355/366] Moved functions to separate files --- .../op_nitsche_consistency_cahn_hilliard.m | 2 +- .../multipatch/mp_solve_cahn_hilliard_C1.m | 162 +++++++++--------- .../solve/cahn_hilliard/Res_K_cahn_hilliard.m | 43 +++++ .../generalized_alpha_step_cahn_hilliard.m | 95 ++++++++++ geopdes/inst/solve/solve_cahn_hilliard.m | 120 ++++++------- .../op_nitsche_consistency_cahn_hilliard.m | 2 +- 6 files changed, 281 insertions(+), 143 deletions(-) create mode 100644 geopdes/inst/solve/cahn_hilliard/Res_K_cahn_hilliard.m create mode 100644 geopdes/inst/solve/cahn_hilliard/generalized_alpha_step_cahn_hilliard.m diff --git a/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m b/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m index f67be7b9..ec4e918c 100644 --- a/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m +++ b/geopdes/inst/multipatch/@sp_multipatch_C1/op_nitsche_consistency_cahn_hilliard.m @@ -29,7 +29,7 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -function [A] = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, coeff) +function A = op_nitsche_consistency_cahn_hilliard (space, msh, nmnn_sides, coeff) if (nargin == 3 || isempty(coeff)) coeff = @(varargin) ones (size(varargin{1})); diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 3dc75453..b9a32932 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -168,7 +168,7 @@ disp('----------------------------------------------------------------') disp(strcat('time step t=',num2str(time))) - [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... + [u_n1, udot_n1] = generalized_alpha_step_cahn_hilliard (u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); % check flux through the boundary @@ -215,88 +215,88 @@ %-------------------------------------------------------------------------- +% %-------------------------------------------------------------------------- +% % One step of generalized alpha-method +% %-------------------------------------------------------------------------- +% +% function [u_n1, udot_n1] = generalized_alpha_step(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... +% mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) +% +% % Convergence criteria +% n_max_iter = 20; +% tol_rel_res = 1e-10; +% tol_abs_res = 1e-10; +% +% % Predictor step +% u_n1 = u_n; +% udot_n1 = (gamma-1)/gamma * udot_n; +% +% % Newton loop +% for iter = 0:n_max_iter +% +% % Field at alpha level +% udot_a = udot_n + a_m *(udot_n1-udot_n); +% u_a = u_n + a_f *(u_n1-u_n); +% +% % Compute the residual (internal) +% [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... +% mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, ... +% u_a, udot_a, mu, dmu); +% +% % Convergence check +% if (iter == 0) +% norm_res_0 = norm(Res_gl); +% end +% norm_res = norm(Res_gl); +% +% if (norm_res/norm_res_0 < tol_rel_res) +% disp(strcat('iteration n°=',num2str(iter))) +% disp(strcat('norm (abs) residual=',num2str(norm_res))) +% break +% end +% if (norm_res. + +function [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, mass_mat, lapl_mat, ... + bnd_mat, Pen, pen_rhs, u_a, udot_a, mu, dmu) + + % Double well (matrices) + if (isa (space, 'sp_scalar')) + [term2, term2K] = op_gradfu_gradv_tp (space, msh, u_a, mu, dmu); + elseif (isa (space, 'sp_multipatch_C1')) + [term2, term2K] = op_gradfu_gradv_mp (space, msh, u_a, mu, dmu); + else + error ('Not implemented for this kind of space') + end + + % Residual + Res_gl = mass_mat*udot_a + term2*u_a + lapl_mat*u_a; + + % Tangent stiffness matrix (mass is not considered here) + stiff_mat = term2 + term2K + lapl_mat; + + % In case of Neumann BC, add boundary terms + if (~isempty(bnd_mat)) + Res_gl = Res_gl - (bnd_mat + bnd_mat.') * u_a + Pen*u_a - pen_rhs; + stiff_mat = stiff_mat - (bnd_mat + bnd_mat.') + Pen; + end +end diff --git a/geopdes/inst/solve/cahn_hilliard/generalized_alpha_step_cahn_hilliard.m b/geopdes/inst/solve/cahn_hilliard/generalized_alpha_step_cahn_hilliard.m new file mode 100644 index 00000000..08462666 --- /dev/null +++ b/geopdes/inst/solve/cahn_hilliard/generalized_alpha_step_cahn_hilliard.m @@ -0,0 +1,95 @@ +% GENERALIZED_ALPHA_STEP_CAHN_HILLIARD: perform one step of the generalized alpha method +% for the solution of the Cahn-Hilliard equation, solving the nonlinear equation with Newton's method. +% It is called from solve_cahn_hilliard and mp_solve_cahn_hilliard_C1. +% +% INPUT: +% +% u_n: field at the previous time step. +% u_dotn: time derivative at the previous time step. +% dt: time step size +% a_m: parameter for the generalized alpha method +% a_f: parameter for the generalized alpha method +% gamma: parameter for the generalized alpha method +% mu, dmu: function handle for value and derivative of the mu coefficient +% mass_mat: mass matrix, to avoid recomputing +% lapl_mat: bilaplacian matrix (Delta u, Delta v), to avoid recomputing +% bnd_mat: matrix with Nitsche's consistency term, to avoid recomputing +% Pen: penalty matrix from Nitsche's method +% pen_rhs: penalty rhs from Nitsche's method +% space: space object (see sp_scalar or sp_multipatch_C1) +% msh: mesh object (see msh_cartesian or msh_multipatch) +% +% OUTPUT: +% +% u_n1: field at the new step. +% u_dotn1: time derivative at the new step. +% +% Copyright (C) 2023, 2024 Michele Torre, Rafael Vazquez +% +% This program is free software: you can redistribute it and/or modify +% it under the terms of the GNU General Public License as published by +% the Free Software Foundation, either version 3 of the License, or +% (at your option) any later version. + +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with this program. If not, see . + +function [u_n1, udot_n1] = generalized_alpha_step_cahn_hilliard(u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh) + +% Convergence criteria + n_max_iter = 20; + tol_rel_res = 1e-10; + tol_abs_res = 1e-10; + +% Predictor step + u_n1 = u_n; + udot_n1 = (gamma-1)/gamma * udot_n; + +% Newton loop + for iter = 0:n_max_iter + + % Field at alpha level + udot_a = udot_n + a_m *(udot_n1-udot_n); + u_a = u_n + a_f *(u_n1-u_n); + + % Compute the residual (internal) + [Res_gl, stiff_mat] = Res_K_cahn_hilliard (space, msh, ... + mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, ... + u_a, udot_a, mu, dmu); + + % Convergence check + if (iter == 0) + norm_res_0 = norm(Res_gl); + end + norm_res = norm(Res_gl); + + if (norm_res/norm_res_0 < tol_rel_res) + disp(strcat('iteration n°=',num2str(iter))) + disp(strcat('norm (abs) residual=',num2str(norm_res))) + break + end + if (norm_res Date: Tue, 23 Jul 2024 10:20:16 +0200 Subject: [PATCH 357/366] Removed check of the flux --- geopdes/INDEX | 4 ++++ geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m | 7 ------- geopdes/inst/solve/solve_cahn_hilliard.m | 8 -------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/geopdes/INDEX b/geopdes/INDEX index 8488825d..15891c38 100644 --- a/geopdes/INDEX +++ b/geopdes/INDEX @@ -23,6 +23,9 @@ Solve: solvers for some simple problems, that you can modify to solve your own p solve_kirchhoff_love_shell solve_kirchhoff_love_shell_scalarspace solve_BE_Beam + solve_cahn_hilliard + cahn_hilliard/generalized_alpha_step_cahn_hilliard + cahn_hilliard/Res_K_cahn_hilliard Geometry: read geometry files, that can be created with the NURBS package geo_nurbs geo_load @@ -163,6 +166,7 @@ Multipatch: functions of different kinds to solve problems in domains defined by mp_solve_maxwell_src mp_solve_stokes mp_solve_stokes_div_conforming + mp_solve_cahn_hilliard_C1 msh_restrict_to_patches msh_multipatch @msh_multipatch/msh_evaluate_element_list diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index b9a32932..95743343 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -146,9 +146,6 @@ udot_n = zeros(space.ndof, 1); end -% flux_initial = check_flux_phase_field(space, msh, u_n, zeros(size(u_n))); -% disp(strcat('initial flux =',num2str(flux_initial))) - %%------------------------------------------------------------------------- % Initialize structure to store the results save_id = 1; @@ -171,10 +168,6 @@ [u_n1, udot_n1] = generalized_alpha_step_cahn_hilliard (u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); -% check flux through the boundary -% flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1))); -% disp(strcat('flux norm =',num2str(flux))) - % Time step update time = time + dt; u_n = u_n1; diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 9a5b3d26..f04af2c0 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -156,9 +156,6 @@ udot_n = zeros(space.ndof, 1); end -flux_initial = check_flux_phase_field(space, msh, u_n, zeros(size(u_n)), nmnn_sides); -disp(strcat('initial flux =',num2str(flux_initial))) - %%------------------------------------------------------------------------- % Initialize structure to store the results save_id = 1; @@ -181,10 +178,6 @@ [u_n1, udot_n1] = generalized_alpha_step_cahn_hilliard (u_n, udot_n, dt, a_m, a_f, gamma, mu, dmu, ... mass_mat, lapl_mat, bnd_mat, Pen, pen_rhs, space, msh); - % check flux through the boundary - flux = check_flux_phase_field(space, msh, u_n1, zeros(size(u_n1)), nmnn_sides); - disp(strcat('flux norm =',num2str(flux))) - % Time step update time = time + dt; u_n = u_n1; @@ -399,4 +392,3 @@ end end - From 2a9a89ab817b312d27d2e39111e326ef07ce2805 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 23 Jul 2024 11:07:05 +0200 Subject: [PATCH 358/366] Changed the way to store results --- .../multipatch/mp_solve_cahn_hilliard_C1.m | 48 ++++++++++--------- geopdes/inst/solve/solve_cahn_hilliard.m | 48 ++++++++++--------- 2 files changed, 52 insertions(+), 44 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 95743343..66de4e40 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -36,6 +36,8 @@ % - dt: time step size for generalized-alpha method % - rho_inf_gen_alpha: parameter in [0,1], which governs numerical damping of the generalized alpha method % +% save_info: time values at which the solution should be saved (see "results" in the output) +% % OUTPUT: % % geometry: geometry structure (see mp_geo_load) @@ -131,7 +133,7 @@ %%------------------------------------------------------------------------- % Initial conditions -time = 0; +time = problem_data.initial_time; if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_mp (space, msh, fun_u); u_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; @@ -148,16 +150,22 @@ %%------------------------------------------------------------------------- % Initialize structure to store the results -save_id = 1; -results.u = zeros(length(u_n), length(save_info)+1); -results.udot = zeros(length(u_n), length(save_info)+1); -results.time = zeros(length(save_info)+1,1); -flag_stop_save = false; +save_info = save_info(save_info>=problem_data.initial_time & save_info<=problem_data.Time_max); + +results.u = zeros(length(u_n), length(save_info)); +results.udot = zeros(length(u_n), length(save_info)); +results.time = zeros(length(save_info), 1); +save_info(end+1) = problem_data.Time_max + 1e5; % Save initial conditions -results.u(:,1) = u_n; -results.udot(:,1) = udot_n; -results.time(1) = time; +save_id = 1; +if (time >= save_info(1)) + results.u(:,1) = u_n; + results.udot(:,1) = udot_n; + results.time(1) = time; + save_id = 2; + save_info = save_info(save_info > time); +end %%------------------------------------------------------------------------- % Loop over time steps @@ -179,16 +187,12 @@ end % Store results - if (flag_stop_save == false) - if (time >= save_info(save_id)) - save_id = save_id + 1; - results.u(:,save_id) = u_n; - results.udot(:,save_id) = udot_n; - results.time(save_id) = time; - if (save_id > length(save_info)) - flag_stop_save = true; - end - end + if (time >= save_info(1)) + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; + save_id = save_id + 1; + save_info = save_info(save_info > time); end end @@ -197,9 +201,9 @@ disp('----------------------------------------------------------------') % Crop results -results.u = results.u(:,1:save_id); -results.udot = results.udot(:,1:save_id); -results.time = results.time(1:save_id); +results.u = results.u(:,1:save_id-1); +results.udot = results.udot(:,1:save_id-1); +results.time = results.time(1:save_id-1); end diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index f04af2c0..9e2f237b 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -39,6 +39,8 @@ % - Cpen_nitsche: penalization parameter for Nitsche's method, to impose Neumann conditions % - Cpen_projection: penalization parameter to impose zero flux for the initial condition % +% save_info: time values at which the solution should be saved (see "results" in the output) +% % OUTPUT: % % geometry: geometry structure (see geo_load) @@ -141,7 +143,7 @@ %%------------------------------------------------------------------------- % Initial conditions -time = 0; +time = problem_data.initial_time; if (exist('fun_u', 'var') && ~isempty(fun_u)) rhs = op_f_v_tp (space, msh, fun_u); u_n = (mass_mat + Cpen_projection/Cpen_nitsche * Pen)\rhs; @@ -158,16 +160,22 @@ %%------------------------------------------------------------------------- % Initialize structure to store the results -save_id = 1; -results.u = zeros(length(u_n), length(save_info)+1); -results.udot = zeros(length(u_n), length(save_info)+1); -results.time = zeros(length(save_info)+1,1); -flag_stop_save = false; +save_info = save_info(save_info>=problem_data.initial_time & save_info<=problem_data.Time_max); + +results.u = zeros(length(u_n), length(save_info)); +results.udot = zeros(length(u_n), length(save_info)); +results.time = zeros(length(save_info), 1); +save_info(end+1) = problem_data.Time_max + 1e5; % Save initial conditions -results.u(:,1) = u_n; -results.udot(:,1) = udot_n; -results.time(1) = time; +save_id = 1; +if (time >= save_info(1)) + results.u(:,1) = u_n; + results.udot(:,1) = udot_n; + results.time(1) = time; + save_id = 2; + save_info = save_info(save_info > time); +end %%------------------------------------------------------------------------- % Loop over time steps @@ -189,16 +197,12 @@ end % Store results - if (flag_stop_save == false) - if (time >= save_info(save_id)) - save_id = save_id + 1; - results.u(:,save_id) = u_n; - results.udot(:,save_id) = udot_n; - results.time(save_id) = time; - if (save_id > length(save_info)) - flag_stop_save = true; - end - end + if (time >= save_info(1)) + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; + save_id = save_id + 1; + save_info = save_info(save_info > time); end end @@ -207,9 +211,9 @@ disp('----------------------------------------------------------------') % Crop results -results.u = results.u(:,1:save_id); -results.udot = results.udot(:,1:save_id); -results.time = results.time(1:save_id); +results.u = results.u(:,1:save_id-1); +results.udot = results.udot(:,1:save_id-1); +results.time = results.time(1:save_id-1); end From e349b127191c45c9e52666b557296009bea7e4cf Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 23 Jul 2024 15:36:25 +0200 Subject: [PATCH 359/366] Minor --- geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m | 6 +++--- geopdes/inst/solve/solve_cahn_hilliard.m | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m index 66de4e40..430de5e9 100644 --- a/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m +++ b/geopdes/inst/multipatch/mp_solve_cahn_hilliard_C1.m @@ -160,9 +160,9 @@ % Save initial conditions save_id = 1; if (time >= save_info(1)) - results.u(:,1) = u_n; - results.udot(:,1) = udot_n; - results.time(1) = time; + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; save_id = 2; save_info = save_info(save_info > time); end diff --git a/geopdes/inst/solve/solve_cahn_hilliard.m b/geopdes/inst/solve/solve_cahn_hilliard.m index 9e2f237b..7b950dec 100644 --- a/geopdes/inst/solve/solve_cahn_hilliard.m +++ b/geopdes/inst/solve/solve_cahn_hilliard.m @@ -170,9 +170,9 @@ % Save initial conditions save_id = 1; if (time >= save_info(1)) - results.u(:,1) = u_n; - results.udot(:,1) = udot_n; - results.time(1) = time; + results.u(:,save_id) = u_n; + results.udot(:,save_id) = udot_n; + results.time(save_id) = time; save_id = 2; save_info = save_info(save_info > time); end From e593bf51c88ab751f70ef1ee3111099e885a612a Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 23 Jul 2024 18:15:52 +0200 Subject: [PATCH 360/366] Avoid fails in the tests from Inf or -Inf --- geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_cube.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_cube_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_curvedL.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_fichera_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m | 3 ++- .../inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_cube.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_cube_mp.m | 1 + .../inst/examples/maxwell/ex_maxwell_eig_mixed1_fichera_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_square.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_thick_L.m | 1 + .../inst/examples/maxwell/ex_maxwell_eig_mixed1_thick_L_mp.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed2_Lshaped.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed2_square.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_ring_1eighth.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_square.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_thick_L.m | 1 + geopdes/inst/examples/maxwell/ex_maxwell_eig_thick_L_mp.m | 1 + 20 files changed, 21 insertions(+), 1 deletion(-) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped.m b/geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped.m index e2a83027..56a14a23 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_eig_Lshaped.m @@ -52,6 +52,7 @@ %! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule %! [geometry, msh, space, eigv, eigf] = solve_maxwell_eig (problem_data, method_data); %! [eigv, perm] = sort (eigv); +%! eigv = eigv(abs(eigv)0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv Date: Tue, 23 Jul 2024 18:22:02 +0200 Subject: [PATCH 361/366] Fixed test, and removed ; --- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m | 2 +- .../inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped_mp.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_cube.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_cube_mp.m | 2 +- .../inst/examples/maxwell/ex_maxwell_eig_mixed1_fichera_mp.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_square.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_thick_L.m | 2 +- .../inst/examples/maxwell/ex_maxwell_eig_mixed1_thick_L_mp.m | 2 +- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed2_Lshaped.m | 4 ++-- geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed2_square.m | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m b/geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m index df159742..37ea9fb6 100644 --- a/geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m +++ b/geopdes/inst/examples/maxwell/ex_maxwell_eig_mixed1_Lshaped.m @@ -51,7 +51,7 @@ %! method_data.nquad = [4 4]; % Points for the Gaussian quadrature rule %! [geometry, msh, space, sp_mul, eigv, eigf] = solve_maxwell_eig_mixed1 (problem_data, method_data); %! [eigv, perm] = sort (eigv); -%! eigv = eigv(eigv>0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv0 & eigv Date: Tue, 23 Jul 2024 18:36:16 +0200 Subject: [PATCH 362/366] Added subfolders --- geopdes/PKG_ADD | 4 ++-- geopdes/PKG_DEL | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/geopdes/PKG_ADD b/geopdes/PKG_ADD index 3738800d..a07d9919 100644 --- a/geopdes/PKG_ADD +++ b/geopdes/PKG_ADD @@ -3,8 +3,8 @@ dirlist = {"examples", "examples/geometry_files", "examples/geometry_file "examples/elasticity", "examples/elasticity/data_files", ... "examples/fluid", "examples/fluid/data_files", ... "examples/maxwell", "examples/maxwell/data_files", ... - "examples/kirchhoff_love_shell", ... - "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch"}; + "examples/kirchhoff_love_shell", "examples/cahn_hilliard", ... + "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch", "solve/cahn_hilliard"}; dir = fileparts (mfilename ("fullpath")); diff --git a/geopdes/PKG_DEL b/geopdes/PKG_DEL index 680faa6f..117c64e9 100644 --- a/geopdes/PKG_DEL +++ b/geopdes/PKG_DEL @@ -3,8 +3,8 @@ dirlist = {"examples", "examples/geometry_files", "examples/geometry_file "examples/elasticity", "examples/elasticity/data_files", ... "examples/fluid", "examples/fluid/data_files", ... "examples/maxwell", "examples/maxwell/data_files", ... - "examples/kirchhoff_love_shell", ... - "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch"}; + "examples/kirchhoff_love_shell", "examples/cahn_hilliard", ... + "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch", "solve/cahn_hilliard"}; [basename,dir] = fileparts(fileparts (mfilename ("fullpath"))); From 64087e4a5133aed43b2bc180172ef390c38d9895 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Tue, 23 Jul 2024 18:38:10 +0200 Subject: [PATCH 363/366] Wrong name --- geopdes/PKG_ADD | 2 +- geopdes/PKG_DEL | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/geopdes/PKG_ADD b/geopdes/PKG_ADD index a07d9919..6431f8c2 100644 --- a/geopdes/PKG_ADD +++ b/geopdes/PKG_ADD @@ -3,7 +3,7 @@ dirlist = {"examples", "examples/geometry_files", "examples/geometry_file "examples/elasticity", "examples/elasticity/data_files", ... "examples/fluid", "examples/fluid/data_files", ... "examples/maxwell", "examples/maxwell/data_files", ... - "examples/kirchhoff_love_shell", "examples/cahn_hilliard", ... + "examples/kirchhoff_love_shell", "examples/cahn-hilliard", ... "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch", "solve/cahn_hilliard"}; dir = fileparts (mfilename ("fullpath")); diff --git a/geopdes/PKG_DEL b/geopdes/PKG_DEL index 117c64e9..790810e7 100644 --- a/geopdes/PKG_DEL +++ b/geopdes/PKG_DEL @@ -3,7 +3,7 @@ dirlist = {"examples", "examples/geometry_files", "examples/geometry_file "examples/elasticity", "examples/elasticity/data_files", ... "examples/fluid", "examples/fluid/data_files", ... "examples/maxwell", "examples/maxwell/data_files", ... - "examples/kirchhoff_love_shell", "examples/cahn_hilliard", ... + "examples/kirchhoff_love_shell", "examples/cahn-hilliard", ... "geometry", "utils", "msh", "obsolete", "operators", "solve", "space", "multipatch", "solve/cahn_hilliard"}; [basename,dir] = fileparts(fileparts (mfilename ("fullpath"))); From d2e1aaed2e4624fd21ea5dc728fd5d0d8ad1cbdc Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 24 Jul 2024 12:03:35 +0200 Subject: [PATCH 364/366] Updated the examples --- .../examples/cahn-hilliard/ex_cahn_hilliard.m | 20 ++++------ .../cahn-hilliard/ex_cahn_hilliard_mpC1.m | 39 +++++++++---------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m index cdfdfddb..3925c88e 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard.m @@ -15,13 +15,12 @@ problem_data.periodic_directions = []; % Time and time step size -Time_max = .08; +Time_max = 0.08; dt = 1e-3; -time_step_save = linspace(dt,Time_max,20); -problem_data.time = 0; +time_step_save = linspace(0, Time_max, 21); +problem_data.initial_time = 0; problem_data.Time_max = Time_max; - % 2) INITIAL CONDITIONS % mean = 0.0; % var = 0.2; @@ -52,26 +51,23 @@ % 5) POST-PROCESSING vtk_pts = {linspace(0, 1, nel*4), linspace(0, 1, nel*4)}; -folder_name = strcat('results_CH_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); +folder_name = strcat('cahn_hilliard_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); status = mkdir(folder_name); -% 5.1) EXPORT TIME +% 5.1) EXPORT TIME filename = strcat( folder_name,'/filenum_to_time.mat'); time_steps = results.time; save(filename, 'time_steps'); - % 5.2) EXPORT TO PARAVIEW for step = 1:length(results.time) - output_file = strcat( folder_name,'/Square_cahn_hilliard_', num2str(step) ); + output_file = strcat (folder_name,'/Square_Cahn_Hilliard_', num2str(step)); fprintf ('The result is saved in the file %s \n \n', output_file); - sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'u','grad_u'}, {'value','gradient'}) + sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'value','gradient'}, {'value','gradient'}) end % 5.3) PLOT LAST RESULT -[eu, F] = sp_eval (results.u(:,end), space, geometry, vtk_pts); -[X, Y] = deal (squeeze(F(1,:,:)), squeeze(F(2,:,:))); -surf (X, Y, eu) +sp_plot_solution (results.u(:,end), space, geometry); colorbar view(0,90) shading interp diff --git a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m index a35a80eb..081e1a52 100644 --- a/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m +++ b/geopdes/inst/examples/cahn-hilliard/ex_cahn_hilliard_mpC1.m @@ -1,9 +1,9 @@ % 1) PHYSICAL DATA OF THE PROBLEM clear problem_data % Physical domain, defined as NURBS map given in a text file -nrb1 = nrb4surf ([0 0], [.5 0], [0 1], [.5 1]); -nrb2 = nrb4surf ([.5 0], [1 0], [.5 1], [1 1]); -problem_data.geo_name = [nrb1,nrb2]; %'geo_square_mp.txt'; +nrb(1) = nrb4surf ([0 0], [.5 0], [0 1], [.5 1]); +nrb(2) = nrb4surf ([.5 0], [1 0], [.5 1], [1 1]); +problem_data.geo_name = nrb; % Physical parameters (see mp_solve_cahn_hilliard_C1) lambda = (1/(4*sqrt(2)*pi))^2; @@ -14,27 +14,27 @@ problem_data.dmu = @(x) 6 * alpha * x; % Time and time step size -Time_max = .5; -dt = 1e-2; -time_step_save = linspace(dt,Time_max,9); -problem_data.time = 0; +Time_max = .08; +dt = 1e-3; +time_step_save = linspace(0,Time_max,21); +problem_data.initial_time = 0; problem_data.Time_max = Time_max; % 2) INITIAL CONDITIONS -mean = 0.4; -var = 0.05; -ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition -%ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). +% mean = 0.0; +% var = 0.2; +% ic_fun = @(x, y) mean + (rand(size(x))*2-1)*var; % Random initial condition +ic_fun = @(x, y) 0.1 * cos(2*pi*x) .* cos(2*pi*y); % Condition as in Gomes, Reali, Sangalli, JCP (2014). problem_data.fun_u = ic_fun; % problem_data.fun_udot = []; % 3) CHOICE OF THE DISCRETIZATION PARAMETERS clear method_data deg = 3; nel = 10; -method_data.degree = [deg deg]; % Degree of the splines -method_data.regularity = [deg-2 deg-2]; % Regularity of the splines -method_data.nsub = [nel nel]; % Number of subdivisions -method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule +method_data.degree = [deg deg]; % Degree of the splines +method_data.regularity = [deg-2 deg-2]; % Regularity of the splines +method_data.nsub = [nel nel]; % Number of subdivisions +method_data.nquad = [deg+1 deg+1]; % Points for the Gaussian quadrature rule % time integration parameters method_data.rho_inf_gen_alpha = 0.5; % Parameter for generalized-alpha method @@ -42,16 +42,15 @@ % Penalty parameters problem_data.Cpen_nitsche = 1e4 * lambda; % Nitsche's method parameter -problem_data.Cpen_projection = 1000; % parameter of the penalized L2 projection (see initial conditions) +problem_data.Cpen_projection = 1e3; % Parameter of the penalized L2 projection (see initial conditions) % 4) CALL TO THE SOLVER [geometry, msh, space, results] = mp_solve_cahn_hilliard_C1 (problem_data, method_data, time_step_save); - % 5) POST-PROCESSING vtk_pts = {linspace(0, 1, nel*4), linspace(0, 1, nel*4)}; -folder_name = strcat('results_CH_mpC1_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); +folder_name = strcat('cahn_hilliard_mpC1_p',num2str(deg),'_nel',num2str(nel),'_lambda',num2str(lambda)); status = mkdir(folder_name); % 5.1) EXPORT TIME @@ -62,9 +61,9 @@ % 5.2) EXPORT TO PARAVIEW for step = 1:length(results.time) - output_file = strcat( folder_name,'/Square_cahn_hilliard_', num2str(step) ); + output_file = strcat( folder_name,'/Twopatch_Cahn_Hilliard_', num2str(step) ); fprintf ('The result is saved in the file %s \n \n', output_file); - sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'u','grad_u'}, {'value','gradient'}) + sp_to_vtk (results.u(:,step), space, geometry, vtk_pts, output_file, {'value','gradient'}, {'value','gradient'}) end % 5.3) PLOT LAST RESULT From 0a585f7b195a2a80b3a98281687b17b19cb0a5aa Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 24 Jul 2024 12:04:54 +0200 Subject: [PATCH 365/366] Almost ready for release --- geopdes/DESCRIPTION | 4 ++-- geopdes/NEWS | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/geopdes/DESCRIPTION b/geopdes/DESCRIPTION index fa00e383..cecedb5b 100644 --- a/geopdes/DESCRIPTION +++ b/geopdes/DESCRIPTION @@ -1,9 +1,9 @@ Name: geopdes Version: 3.4.0 -Date: 2023-06-20 +Date: 2024-07-24 Author: Rafael Vazquez, Carlo de Falco Maintainer: Rafael Vazquez Title: Iso-Geometric Analysis Description: A research tool for Iso-Geometric Analysis of PDEs -Depends: octave (>= 5.1), nurbs (>= 1.4.1) +Depends: octave (>= 6.4), nurbs (>= 1.4.1) License: GPLv3 diff --git a/geopdes/NEWS b/geopdes/NEWS index 71b923ab..688cca9e 100644 --- a/geopdes/NEWS +++ b/geopdes/NEWS @@ -3,6 +3,7 @@ Summary of important changes for geopdes-3.4.0: * Added new class SP_MULTIPATCH_C1. * Added solvers for C1 spaces: Laplace, bilaplace, linear elast., Kirchhoff-Love shell. * Added solver for linear elasticity and Kirchhoff-Love using scalar spaces. +* Added solver for Cahn-Hilliard equations, in single patch and multipatch. Summary of important changes for geopdes-3.3.0: ----------------------------------------------------------------------------- From c94fe7c3f8ed0ecfdeee136ec46eaa3cd5738c54 Mon Sep 17 00:00:00 2001 From: Rafael Vazquez Date: Wed, 24 Jul 2024 12:29:14 +0200 Subject: [PATCH 366/366] Changed the help --- geopdes/inst/operators/op_u_otimes_n_v_otimes_n.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geopdes/inst/operators/op_u_otimes_n_v_otimes_n.m b/geopdes/inst/operators/op_u_otimes_n_v_otimes_n.m index a01a7b6c..4a3f3056 100644 --- a/geopdes/inst/operators/op_u_otimes_n_v_otimes_n.m +++ b/geopdes/inst/operators/op_u_otimes_n_v_otimes_n.m @@ -14,7 +14,7 @@ % % A: assembled matrix % -% Copyright (C) 2015, Rafael, 2017 Vazquez +% Copyright (C) 2015, 2017, Rafael Vazquez % % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by