Chaste  Release::3.4
CellwiseDataGradient.cpp
1 /*
2 
3 Copyright (c) 2005-2016, University of Oxford.
4 All rights reserved.
5 
6 University of Oxford means the Chancellor, Masters and Scholars of the
7 University of Oxford, having an administrative office at Wellington
8 Square, Oxford OX1 2JD, UK.
9 
10 This file is part of Chaste.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright notice,
17  this list of conditions and the following disclaimer in the documentation
18  and/or other materials provided with the distribution.
19  * Neither the name of the University of Oxford nor the names of its
20  contributors may be used to endorse or promote products derived from this
21  software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
29 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
36 #include "CellwiseDataGradient.hpp"
37 #include "LinearBasisFunction.hpp"
38 
39 template<unsigned DIM>
40 c_vector<double, DIM>& CellwiseDataGradient<DIM>::rGetGradient(unsigned nodeIndex)
41 {
42  return mGradients[nodeIndex];
43 }
44 
45 template<unsigned DIM>
46 void CellwiseDataGradient<DIM>::SetupGradients(AbstractCellPopulation<DIM>& rCellPopulation, const std::string& rItemName)
47 {
48  MeshBasedCellPopulation<DIM>* pCellPopulation = static_cast<MeshBasedCellPopulation<DIM>*>(&(rCellPopulation));
49  TetrahedralMesh<DIM,DIM>& r_mesh = pCellPopulation->rGetMesh();
50 
51  // Initialise gradients size
52  unsigned num_nodes = pCellPopulation->GetNumNodes();
53  mGradients.resize(num_nodes, zero_vector<double>(DIM));
54 
55  // The constant gradients at each element
56  std::vector<c_vector<double, DIM> > gradients_on_elements;
57  unsigned num_elements = r_mesh.GetNumElements();
58  gradients_on_elements.resize(num_elements, zero_vector<double>(DIM));
59 
60  // The number of elements containing a given node (excl ghost elements)
61  std::vector<unsigned> num_real_elems_for_node(num_nodes, 0);
62 
63  for (unsigned elem_index=0; elem_index<num_elements; elem_index++)
64  {
65  Element<DIM,DIM>& r_elem = *(r_mesh.GetElement(elem_index));
66 
67  // Calculate the basis functions at any point (eg zero) in the element
68  c_matrix<double, DIM, DIM> jacobian, inverse_jacobian;
69  double jacobian_det;
70  r_mesh.GetInverseJacobianForElement(elem_index, jacobian, jacobian_det, inverse_jacobian);
71  const ChastePoint<DIM> zero_point;
72  c_matrix<double, DIM, DIM+1> grad_phi;
73  LinearBasisFunction<DIM>::ComputeTransformedBasisFunctionDerivatives(zero_point, inverse_jacobian, grad_phi);
74 
75  bool is_ghost_element = false;
76 
77  for (unsigned node_index=0; node_index<DIM+1; node_index++)
78  {
79  unsigned node_global_index = r_elem.GetNodeGlobalIndex(node_index);
80 
81  // This code is commented because CellData can't deal with ghost nodes see #1975
82  assert(pCellPopulation->IsGhostNode(node_global_index) == false);
84  //if (pCellPopulation->IsGhostNode(node_global_index) == true)
85  //{
86  // is_ghost_element = true;
87  // break;
88  //}
89 
90  // If no ghost element, get PDE solution
91  CellPtr p_cell = pCellPopulation->GetCellUsingLocationIndex(node_global_index);
92  double pde_solution = p_cell->GetCellData()->GetItem(rItemName);
93 
94  // Interpolate gradient
95  for (unsigned i=0; i<DIM; i++)
96  {
97  gradients_on_elements[elem_index](i) += pde_solution* grad_phi(i, node_index);
98  }
99  }
100 
101  // Add gradient at element to gradient at node
102  if (!is_ghost_element)
103  {
104  for (unsigned node_index=0; node_index<DIM+1; node_index++)
105  {
106  unsigned node_global_index = r_elem.GetNodeGlobalIndex(node_index);
107  mGradients[node_global_index] += gradients_on_elements[elem_index];
108  num_real_elems_for_node[node_global_index]++;
109  }
110  }
111  }
112 
113  // Divide to obtain average gradient
114  for (typename AbstractCellPopulation<DIM>::Iterator cell_iter = pCellPopulation->Begin();
115  cell_iter != pCellPopulation->End();
116  ++cell_iter)
117  {
118  unsigned node_global_index = pCellPopulation->GetLocationIndexUsingCell(*cell_iter);
119 
120  if (!(num_real_elems_for_node[node_global_index] > 0))
121  {
123  // This code is commented because CellwiseData Can't deal with ghost nodes so won't ever come into this statement see #1975
126  //Node<DIM>& this_node = *(pCellPopulation->GetNodeCorrespondingToCell(*cell_iter));
127  //
128  //mGradients[node_global_index] = zero_vector<double>(DIM);
129  //unsigned num_real_adjacent_nodes = 0;
130  //
132  //std::set<Node<DIM>*> real_adjacent_nodes;
133  //real_adjacent_nodes.clear();
134  //
136  //for (typename Node<DIM>::ContainingElementIterator element_iter = this_node.ContainingElementsBegin();
137  // element_iter != this_node.ContainingElementsEnd();
138  // ++element_iter)
139  //{
140  // // Then loop over nodes therein
141  // Element<DIM,DIM>& r_adjacent_elem = *(r_mesh.GetElement(*element_iter));
142  // for (unsigned local_node_index=0; local_node_index<DIM+1; local_node_index++)
143  // {
144  // unsigned adjacent_node_global_index = r_adjacent_elem.GetNodeGlobalIndex(local_node_index);
145  //
146  // // If not a ghost node and not the node we started with
147  // if ( !(pCellPopulation->IsGhostNode(adjacent_node_global_index))
148  // && adjacent_node_global_index != node_global_index )
149  // {
150  //
151  // // Calculate the contribution of gradient from this node
152  // Node<DIM>& adjacent_node = *(r_mesh.GetNode(adjacent_node_global_index));
153  //
154  // double this_cell_concentration = CellwiseData<DIM>::Instance()->GetValue(*cell_iter, 0);
155  // CellPtr p_adjacent_cell = pCellPopulation->GetCellUsingLocationIndex(adjacent_node_global_index);
156  // double adjacent_cell_concentration = CellwiseData<DIM>::Instance()->GetValue(p_adjacent_cell, 0);
157  //
158  // c_vector<double, DIM> gradient_contribution = zero_vector<double>(DIM);
159  //
160  // if (fabs(this_cell_concentration-adjacent_cell_concentration) > 100*DBL_EPSILON)
161  // {
162  // c_vector<double, DIM> edge_vector = r_mesh.GetVectorFromAtoB(this_node.rGetLocation(), adjacent_node.rGetLocation());
163  // double norm_edge_vector = norm_2(edge_vector);
164  // gradient_contribution = edge_vector
165  // * (adjacent_cell_concentration - this_cell_concentration)
166  // / (norm_edge_vector * norm_edge_vector);
167  // }
168  //
169  // mGradients[node_global_index] += gradient_contribution;
170  // num_real_adjacent_nodes++;
171  // }
172  // }
173  //}
174  //mGradients[node_global_index] /= num_real_adjacent_nodes;
175  }
176  else
177  {
178  mGradients[node_global_index] /= num_real_elems_for_node[node_global_index];
179  }
180  }
181 }
182 
184 template class CellwiseDataGradient<1>;
185 template class CellwiseDataGradient<2>;
186 template class CellwiseDataGradient<3>;
virtual CellPtr GetCellUsingLocationIndex(unsigned index)
unsigned GetLocationIndexUsingCell(CellPtr pCell)
unsigned GetNodeGlobalIndex(unsigned localIndex) const
void SetupGradients(AbstractCellPopulation< DIM > &rCellPopulation, const std::string &rItemName)
virtual unsigned GetNumElements() const
virtual void GetInverseJacobianForElement(unsigned elementIndex, c_matrix< double, SPACE_DIM, ELEMENT_DIM > &rJacobian, double &rJacobianDeterminant, c_matrix< double, ELEMENT_DIM, SPACE_DIM > &rInverseJacobian) const
Element< ELEMENT_DIM, SPACE_DIM > * GetElement(unsigned index) const
#define NEVER_REACHED
Definition: Exception.hpp:206
MutableMesh< ELEMENT_DIM, SPACE_DIM > & rGetMesh()
static void ComputeTransformedBasisFunctionDerivatives(const ChastePoint< ELEMENT_DIM > &rPoint, const c_matrix< double, ELEMENT_DIM, ELEMENT_DIM > &rInverseJacobian, c_matrix< double, ELEMENT_DIM, ELEMENT_DIM+1 > &rReturnValue)
c_vector< double, DIM > & rGetGradient(unsigned nodeIndex)