00001 /* 00002 00003 Copyright (c) 2005-2015, University of Oxford. 00004 All rights reserved. 00005 00006 University of Oxford means the Chancellor, Masters and Scholars of the 00007 University of Oxford, having an administrative office at Wellington 00008 Square, Oxford OX1 2JD, UK. 00009 00010 This file is part of Chaste. 00011 00012 Redistribution and use in source and binary forms, with or without 00013 modification, are permitted provided that the following conditions are met: 00014 * Redistributions of source code must retain the above copyright notice, 00015 this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright notice, 00017 this list of conditions and the following disclaimer in the documentation 00018 and/or other materials provided with the distribution. 00019 * Neither the name of the University of Oxford nor the names of its 00020 contributors may be used to endorse or promote products derived from this 00021 software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00024 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00025 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00026 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 */ 00035 #include "PottsElement.hpp" 00036 #include "RandomNumberGenerator.hpp" 00037 #include <cassert> 00038 #include "Exception.hpp" 00039 #include "UblasCustomFunctions.hpp" 00040 #include "petscsys.h" 00041 #include "petscblaslapack.h" 00042 00043 00044 template<unsigned DIM> 00045 PottsElement<DIM>::PottsElement(unsigned index, const std::vector<Node<DIM>*>& rNodes) 00046 : MutableElement<DIM,DIM>(index, rNodes) 00047 { 00048 this->RegisterWithNodes(); 00049 } 00050 00051 template<unsigned DIM> 00052 PottsElement<DIM>::~PottsElement() 00053 { 00054 } 00055 00056 template<unsigned DIM> 00057 void PottsElement<DIM>::AddNode(Node<DIM>* pNode, const unsigned& rIndex) 00058 { 00059 // Add element to this node 00060 pNode->AddElement(this->mIndex); 00061 00062 // Add pNode to mNodes 00063 this->mNodes.push_back(pNode); 00064 } 00065 00066 template<unsigned DIM> 00067 double PottsElement<DIM>::GetAspectRatio() 00068 { 00069 assert(DIM == 2); 00070 00071 assert(this->GetNumNodes() != 0); 00072 00073 if (this->GetNumNodes() <= 2) 00074 { 00075 return 1.0; 00076 } 00077 00078 double eig_max; 00079 double eig_min; 00080 00081 // See http://stackoverflow.com/questions/7059841/estimating-aspect-ratio-of-a-convex-hull for how to do it. 00082 switch(DIM) 00083 { 00084 case 2: 00085 { 00086 // Calculate entries of covariance matrix (var_x,cov_xy;cov_xy,var_y) 00087 double mean_x=0; 00088 double mean_y=0; 00089 00090 for (unsigned i=0; i<this->GetNumNodes(); i++) 00091 { 00092 mean_x += this->mNodes[i]->rGetLocation()[0]; 00093 mean_y += this->mNodes[i]->rGetLocation()[1]; 00094 } 00095 mean_x /= this->GetNumNodes(); 00096 mean_y /= this->GetNumNodes(); 00097 00098 double variance_x = 0; 00099 double variance_y = 0; 00100 double covariance_xy = 0; 00101 00102 for (unsigned i=0; i<this->GetNumNodes(); i++) 00103 { 00104 variance_x += pow((this->mNodes[i]->rGetLocation()[0]-mean_x),2); 00105 variance_y += pow((this->mNodes[i]->rGetLocation()[1]-mean_y),2); 00106 covariance_xy += (this->mNodes[i]->rGetLocation()[0]-mean_x)*(this->mNodes[i]->rGetLocation()[1]-mean_y); 00107 } 00108 variance_x /= this->GetNumNodes(); 00109 variance_y /= this->GetNumNodes(); 00110 covariance_xy /= this->GetNumNodes(); 00111 00112 // Calculate max/min eigenvalues 00113 double trace = variance_x+variance_y; 00114 double det = variance_x*variance_y - covariance_xy*covariance_xy; 00115 00116 eig_max = 0.5*(trace+sqrt(trace*trace - 4*det)); 00117 eig_min = 0.5*(trace-sqrt(trace*trace - 4*det)); 00118 00119 break; 00120 } 00121 // case 3: 00122 // { 00123 // double mean_x = 0; 00124 // double mean_y = 0; 00125 // double mean_z = 0; 00126 // 00127 // for (unsigned i=0; i<this->GetNumNodes(); i++) 00128 // { 00129 // mean_x += this->mNodes[i]->rGetLocation()[0]; 00130 // mean_y += this->mNodes[i]->rGetLocation()[1]; 00131 // mean_z += this->mNodes[i]->rGetLocation()[2]; 00132 // } 00133 // mean_x /= this->GetNumNodes(); 00134 // mean_y /= this->GetNumNodes(); 00135 // mean_z /= this->GetNumNodes(); 00136 // 00137 // double variance_x = 0; 00138 // double variance_y = 0; 00139 // double variance_z = 0; 00140 // 00141 // double covariance_xy = 0; 00142 // double covariance_xz = 0; 00143 // double covariance_yz = 0; 00144 // 00145 // for (unsigned i=0; i<this->GetNumNodes(); i++) 00146 // { 00147 // double diff_x = this->mNodes[i]->rGetLocation()[0]-mean_x; 00148 // double diff_y = this->mNodes[i]->rGetLocation()[1]-mean_y; 00149 // double diff_z = this->mNodes[i]->rGetLocation()[2]-mean_z; 00150 // 00151 // variance_x += diff_x*diff_x; 00152 // variance_y += diff_y*diff_y; 00153 // variance_z += diff_z*diff_z; 00154 // covariance_xy += diff_x*diff_y; 00155 // covariance_xz += diff_x*diff_z; 00156 // covariance_yz += diff_y*diff_z; 00157 // } 00158 // variance_x /= this->GetNumNodes(); 00159 // variance_y /= this->GetNumNodes(); 00160 // variance_z /= this->GetNumNodes(); 00161 // covariance_xy /= this->GetNumNodes(); 00162 // covariance_xz /= this->GetNumNodes(); 00163 // covariance_yz /= this->GetNumNodes(); 00164 // 00165 // c_matrix<PetscScalar, 3, 3> covariance_matrix; 00166 // 00167 // covariance_matrix(0,0) = variance_x; 00168 // covariance_matrix(0,1) = covariance_xy; 00169 // covariance_matrix(0,2) = covariance_xz; 00170 // 00171 // covariance_matrix(1,0) = covariance_xy; 00172 // covariance_matrix(1,1) = variance_y; 00173 // covariance_matrix(1,2) = covariance_yz; 00174 // 00175 // covariance_matrix(2,0) = covariance_xz; 00176 // covariance_matrix(2,1) = covariance_yz; 00177 // covariance_matrix(2,2) = variance_z; 00178 // 00179 // const char N = 'N'; 00180 // const char L = 'L'; 00181 // PetscBLASInt size = DIM; 00182 // PetscReal eigs[DIM]; 00183 // // Optimal work_size (102 entries) computed with a special call to LAPACKsyev_ (see documentation) 00184 // // and rounded to the next power of 2 00185 // const PetscBLASInt work_size = 128; 00186 // PetscScalar workspace[work_size]; 00187 // PetscBLASInt info; 00188 // LAPACKsyev_(&N, &L, &size, covariance_matrix.data(), &size, eigs, workspace, (PetscBLASInt*) &work_size, &info); 00189 // assert(info == 0); 00190 // 00191 // // Lapack returns eigenvalues in ascending order 00192 // eig_max = eigs[DIM-1]; 00193 // eig_min = eigs[0] +eigs[1]; 00194 // break; 00195 // } 00196 default: 00197 NEVER_REACHED; 00198 } 00199 00200 // As matrix is symmetric positive semidefinite 00201 assert(eig_min >= 0); 00202 assert(eig_max >= 0); 00203 00204 if (eig_min == 0) 00205 { 00206 EXCEPTION("All nodes in an element lie in the same line/plane (2D/3D) so aspect ratio is infinite. This interferes with calculation of the Hamiltonian."); 00207 } 00208 00209 return eig_max/eig_min; 00210 } 00211 00212 // Explicit instantiation 00213 template class PottsElement<1>; 00214 template class PottsElement<2>; 00215 template class PottsElement<3>;