Merge lp:~jobh/dolfin/misc into lp:~fenics-core/dolfin/trunk

Proposed by Joachim Haga
Status: Merged
Merged at revision: 6626
Proposed branch: lp:~jobh/dolfin/misc
Merge into: lp:~fenics-core/dolfin/trunk
Diff against target: 309 lines (+165/-21)
4 files modified
demo/undocumented/sym-dirichlet-bc/python/speed-up-test.py (+8/-3)
dolfin/common/RangedIndexSet.h (+108/-0)
dolfin/fem/DirichletBC.cpp (+30/-16)
dolfin/mesh/SubDomain.cpp (+19/-2)
To merge this branch: bzr merge lp:~jobh/dolfin/misc
Reviewer Review Type Date Requested Status
Garth Wells Approve
Review via email: mp+96079@code.launchpad.net

Description of the change

This branch finishes the DirichletBC speed-up effort for topological and geometric search (and, incidentally, SubDomain::apply_markers, since that is used when initialising a DirichletBC from a sub domain). These search methods (from a sub domain) are now roughly as fast as pointwise search again.

It also fixes the problem with setting BCs on a subdomain which has been reported (it checks if dofmap is a view before calling ownership_range()).

I seem to have created some problems earlier which may be due to criss-cross merges, so I haven't merged with trunk this time; however, I have performed a test-merge which was clean so there should be no problems.

It passes all tests, and the test-merge has passed the quicktests.

To post a comment you must log in.
Revision history for this message
Garth Wells (garth-wells) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'demo/undocumented/sym-dirichlet-bc/python/speed-up-test.py'
--- demo/undocumented/sym-dirichlet-bc/python/speed-up-test.py 2011-10-10 00:06:19 +0000
+++ demo/undocumented/sym-dirichlet-bc/python/speed-up-test.py 2012-03-06 09:08:20 +0000
@@ -22,8 +22,8 @@
22# First added: 2008-08-1322# First added: 2008-08-13
23# Last changed: 2008-08-1323# Last changed: 2008-08-13
2424
25from dolfin import *
25import time26import time
26from dolfin import *
2727
2828
29# Sub domain for Dirichlet boundary condition29# Sub domain for Dirichlet boundary condition
@@ -31,14 +31,14 @@
31 def inside(self, x, on_boundary):31 def inside(self, x, on_boundary):
32 return bool(on_boundary and x[0] < DOLFIN_EPS)32 return bool(on_boundary and x[0] < DOLFIN_EPS)
3333
34mesh = UnitSquare(500,500)34mesh = UnitCube(32,32,32)
35V = FunctionSpace(mesh, "CG", 1)35V = FunctionSpace(mesh, "CG", 1)
3636
37# Define variational problem37# Define variational problem
38v = TestFunction(V)38v = TestFunction(V)
39u = TrialFunction(V)39u = TrialFunction(V)
4040
41f = Function(V, "500.0*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")41f = Expression("500.0*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)")
4242
4343
44a = dot(grad(v), grad(u))*dx44a = dot(grad(v), grad(u))*dx
@@ -71,5 +71,10 @@
71 t1 = time.time()71 t1 = time.time()
72 print "time for new assembly ", t1-t0, " using ", backend72 print "time for new assembly ", t1-t0, " using ", backend
7373
74 t0 = time.time()
75 A, Aa = symmetric_assemble(a, bcs=bc)
76 b = assemble(L, bcs=bc)
77 t1 = time.time()
78 print "time for symm assembly ", t1-t0, " using ", backend
7479
75#summary()80#summary()
7681
=== added file 'dolfin/common/RangedIndexSet.h'
--- dolfin/common/RangedIndexSet.h 1970-01-01 00:00:00 +0000
+++ dolfin/common/RangedIndexSet.h 2012-03-06 09:08:20 +0000
@@ -0,0 +1,108 @@
1// Copyright (C) 2012 Joachim B Haga
2//
3// This file is part of DOLFIN.
4//
5// DOLFIN is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// DOLFIN is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU Lesser General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with DOLFIN. If not, see <http://www.gnu.org/licenses/>.
17//
18// First added: 2012-03-02
19// Last changed: 2012-03-02
20
21#ifndef __RANGED_INDEX_SET_H
22#define __RANGED_INDEX_SET_H
23
24#include <vector>
25#include <dolfin/log/log.h>
26#include "types.h"
27
28namespace dolfin
29{
30
31 /// This class provides an special-purpose data structure for testing if a given
32 /// index within a range is set. It is very fast.
33 ///
34 /// The memory requirements are one bit per item in range, since it uses a
35 /// (packed) std::vector<bool> for storage.
36
37 class RangedIndexSet
38 {
39
40 public:
41
42 /// Create a ranged set with range given as a (lower, upper) pair.
43 RangedIndexSet(std::pair<uint, uint> range)
44 : _range(range), _is_set(range.second - range.first)
45 {
46 clear();
47 }
48
49 /// Create a ranged set with 0 as lower range
50 RangedIndexSet(uint upper_range)
51 : _range(std::pair<uint, uint>(0, upper_range)), _is_set(upper_range)
52 {
53 clear();
54 }
55
56 /// Return true if a given index is within range, i.e., if it can be stored in the set.
57 bool in_range(uint i) const
58 {
59 return (i >= _range.first && i < _range.second);
60 }
61
62 /// Check is the set contains the given index.
63 bool has_index(uint i) const
64 {
65 dolfin_assert(in_range(i));
66 return _is_set[i - _range.first];
67 }
68
69 /// Insert a given index into the set. Returns true if the index was
70 /// inserted (i.e., the index was not already in the set).
71 bool insert(uint i)
72 {
73 dolfin_assert(in_range(i));
74 std::vector<bool>::reference entry = _is_set[i - _range.first];
75 if (entry)
76 {
77 return false;
78 }
79 else
80 {
81 entry = true;
82 return true;
83 }
84 }
85
86 /// Erase an index from the set.
87 void erase(uint i)
88 {
89 dolfin_assert(in_range(i));
90 _is_set[i - _range.first] = false;
91 }
92
93 /// Erase all indices from the set.
94 void clear()
95 {
96 std::fill(_is_set.begin(), _is_set.end(), false);
97 }
98
99 private:
100
101 const std::pair<uint, uint> _range;
102 std::vector<bool> _is_set;
103
104 };
105
106}
107
108#endif
0109
=== modified file 'dolfin/fem/DirichletBC.cpp'
--- dolfin/fem/DirichletBC.cpp 2012-03-02 15:40:22 +0000
+++ dolfin/fem/DirichletBC.cpp 2012-03-06 09:08:20 +0000
@@ -32,6 +32,7 @@
32#include <dolfin/common/constants.h>32#include <dolfin/common/constants.h>
33#include <dolfin/common/Array.h>33#include <dolfin/common/Array.h>
34#include <dolfin/common/NoDeleter.h>34#include <dolfin/common/NoDeleter.h>
35#include <dolfin/common/RangedIndexSet.h>
35#include <dolfin/function/GenericFunction.h>36#include <dolfin/function/GenericFunction.h>
36#include <dolfin/function/FunctionSpace.h>37#include <dolfin/function/FunctionSpace.h>
37#include <dolfin/function/Constant.h>38#include <dolfin/function/Constant.h>
@@ -818,6 +819,11 @@
818 log(TRACE, "Computing facets, needed for geometric application of boundary conditions.");819 log(TRACE, "Computing facets, needed for geometric application of boundary conditions.");
819 mesh.init(mesh.topology().dim() - 1);820 mesh.init(mesh.topology().dim() - 1);
820821
822 // Speed up the computations by only visiting (most) dofs once
823 RangedIndexSet already_visited(dofmap.is_view()
824 ? std::pair<uint, uint>(0,0)
825 : dofmap.ownership_range());
826
821 // Iterate over facets827 // Iterate over facets
822 Progress p("Computing Dirichlet boundary values, geometric search", facets.size());828 Progress p("Computing Dirichlet boundary values, geometric search", facets.size());
823 for (uint f = 0; f < facets.size(); ++f)829 for (uint f = 0; f < facets.size(); ++f)
@@ -841,17 +847,28 @@
841 {847 {
842 ufc_cell.update(*c, facet_number);848 ufc_cell.update(*c, facet_number);
843849
850 bool tabulated = false;
844 bool interpolated = false;851 bool interpolated = false;
845852
846 // Tabulate coordinates of dofs on cell
847 dofmap.tabulate_coordinates(data.coordinates, ufc_cell);
848
849 // Tabulate dofs on cell853 // Tabulate dofs on cell
850 const std::vector<uint>& cell_dofs = dofmap.cell_dofs(c->index());854 const std::vector<uint>& cell_dofs = dofmap.cell_dofs(c->index());
851855
852 // Loop over all dofs on cell856 // Loop over all dofs on cell
853 for (uint i = 0; i < dofmap.cell_dimension(c->index()); ++i)857 for (uint i = 0; i < cell_dofs.size(); ++i)
854 {858 {
859 const uint global_dof = cell_dofs[i];
860
861 // Skip already checked dofs
862 if (already_visited.in_range(global_dof) && !already_visited.insert(global_dof))
863 continue;
864
865 if (!tabulated)
866 {
867 // Tabulate coordinates of dofs on cell
868 dofmap.tabulate_coordinates(data.coordinates, ufc_cell);
869 tabulated = true;
870 }
871
855 // Check if the coordinates are on current facet and thus on boundary872 // Check if the coordinates are on current facet and thus on boundary
856 if (!on_facet(&(data.coordinates[i][0]), facet))873 if (!on_facet(&(data.coordinates[i][0]), facet))
857 continue;874 continue;
@@ -860,10 +877,10 @@
860 {877 {
861 // Restrict coefficient to cell878 // Restrict coefficient to cell
862 g->restrict(&data.w[0], *_function_space->element(), cell, ufc_cell);879 g->restrict(&data.w[0], *_function_space->element(), cell, ufc_cell);
880 interpolated = true;
863 }881 }
864882
865 // Set boundary value883 // Set boundary value
866 const uint global_dof = cell_dofs[i];
867 const double value = data.w[i];884 const double value = data.w[i];
868 boundary_values[global_dof] = value;885 boundary_values[global_dof] = value;
869 }886 }
@@ -896,10 +913,10 @@
896 // Create UFC cell object913 // Create UFC cell object
897 UFCCell ufc_cell(mesh);914 UFCCell ufc_cell(mesh);
898915
899 // Speeder-upper916 // Speed up the computations by only visiting (most) dofs once
900 std::pair<uint,uint> local_range = dofmap.ownership_range();917 RangedIndexSet already_visited(dofmap.is_view()
901 std::vector<bool> already_visited(local_range.second - local_range.first);918 ? std::pair<uint, uint>(0,0)
902 std::fill(already_visited.begin(), already_visited.end(), false);919 : dofmap.ownership_range());
903920
904 // Iterate over cells921 // Iterate over cells
905 Progress p("Computing Dirichlet boundary values, pointwise search", mesh.num_cells());922 Progress p("Computing Dirichlet boundary values, pointwise search", mesh.num_cells());
@@ -921,13 +938,10 @@
921 for (uint i = 0; i < dofmap.cell_dimension(cell->index()); ++i)938 for (uint i = 0; i < dofmap.cell_dimension(cell->index()); ++i)
922 {939 {
923 const uint global_dof = cell_dofs[i];940 const uint global_dof = cell_dofs[i];
924 if (global_dof >= local_range.first && global_dof < local_range.second)941
925 {942 // Skip already checked dofs
926 const uint dof_index = global_dof - local_range.first;943 if (already_visited.in_range(global_dof) && !already_visited.insert(global_dof))
927 if (already_visited[dof_index])944 continue;
928 continue;
929 already_visited[dof_index] = true;
930 }
931945
932 // Check if the coordinates are part of the sub domain (calls user-defined 'inside' function)946 // Check if the coordinates are part of the sub domain (calls user-defined 'inside' function)
933 Array<double> x(gdim, &data.coordinates[i][0]);947 Array<double> x(gdim, &data.coordinates[i][0]);
934948
=== modified file 'dolfin/mesh/SubDomain.cpp'
--- dolfin/mesh/SubDomain.cpp 2012-03-01 12:01:06 +0000
+++ dolfin/mesh/SubDomain.cpp 2012-03-06 09:08:20 +0000
@@ -21,6 +21,7 @@
21// Last changed: 2011-08-3121// Last changed: 2011-08-31
2222
23#include <dolfin/common/Array.h>23#include <dolfin/common/Array.h>
24#include <dolfin/common/RangedIndexSet.h>
24#include <dolfin/log/log.h>25#include <dolfin/log/log.h>
25#include "Mesh.h"26#include "Mesh.h"
26#include "MeshData.h"27#include "MeshData.h"
@@ -164,6 +165,13 @@
164 // Array for vertex coordinate165 // Array for vertex coordinate
165 Array<double> x;166 Array<double> x;
166167
168 // Speed up the computation by only checking each vertex once (or twice if it
169 // is on the boundary for some but not all facets).
170 RangedIndexSet boundary_visited(mesh.num_vertices());
171 RangedIndexSet interior_visited(mesh.num_vertices());
172 std::vector<bool> boundary_inside(mesh.num_vertices());
173 std::vector<bool> interior_inside(mesh.num_vertices());
174
167 // Compute sub domain markers175 // Compute sub domain markers
168 Progress p("Computing sub domain markers", mesh.num_entities(dim));176 Progress p("Computing sub domain markers", mesh.num_entities(dim));
169 for (MeshEntityIterator entity(mesh, dim); !entity.end(); ++entity)177 for (MeshEntityIterator entity(mesh, dim); !entity.end(); ++entity)
@@ -175,6 +183,10 @@
175 (exterior.empty() || exterior[*entity]);183 (exterior.empty() || exterior[*entity]);
176 }184 }
177185
186 // Select the visited-cache to use for this facet (or entity)
187 RangedIndexSet& is_visited = (on_boundary ? boundary_visited : interior_visited);
188 std::vector<bool>& is_inside = (on_boundary ? boundary_inside : interior_inside);
189
178 // Start by assuming all points are inside190 // Start by assuming all points are inside
179 bool all_points_inside = true;191 bool all_points_inside = true;
180192
@@ -183,8 +195,13 @@
183 {195 {
184 for (VertexIterator vertex(*entity); !vertex.end(); ++vertex)196 for (VertexIterator vertex(*entity); !vertex.end(); ++vertex)
185 {197 {
186 x.update(_geometric_dimension, const_cast<double*>(vertex->x()));198 if (is_visited.insert(vertex->index()))
187 if (!inside(x, on_boundary))199 {
200 x.update(_geometric_dimension, const_cast<double*>(vertex->x()));
201 is_inside[vertex->index()] = inside(x, on_boundary);
202 }
203
204 if (!is_inside[vertex->index()])
188 {205 {
189 all_points_inside = false;206 all_points_inside = false;
190 break;207 break;

Subscribers

People subscribed via source and target branches