Electrodes.cpp
00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "Electrodes.hpp"
00030 #include "DistributedTetrahedralMesh.hpp"
00031 #include "IsNan.hpp"
00032 #include "HeartConfig.hpp"
00033
00034 template<unsigned DIM>
00035 Electrodes<DIM>::Electrodes(AbstractTetrahedralMesh<DIM,DIM>& rMesh)
00036 : mpMesh(&rMesh),
00037 mLeftElectrodeArea(0.0),
00038 mRightElectrodeArea(0.0)
00039 {
00040 unsigned axis_index;
00041 double magnitude, duration;
00042
00043 HeartConfig::Instance()->GetElectrodeParameters(mGroundSecondElectrode, axis_index, magnitude, mStartTime, duration);
00044
00045 assert(axis_index < DIM);
00046 assert(duration > 0);
00047 mEndTime = mStartTime + duration;
00048 mAreActive = false;
00049
00050 ChasteCuboid<DIM> bounding_box = mpMesh->CalculateBoundingBox();
00051 double global_min = bounding_box.rGetLowerCorner()[axis_index];
00052 double global_max = bounding_box.rGetUpperCorner()[axis_index];
00053
00054 mpBoundaryConditionsContainer.reset(new BoundaryConditionsContainer<DIM,DIM,2>);
00055
00056
00057 double input_flux;
00058 double output_flux;
00059
00060 try
00061 {
00062 ComputeElectrodesAreasAndCheckEquality(axis_index, global_min, global_max);
00063 input_flux = magnitude;
00064 output_flux = -input_flux;
00065
00066 }
00067 catch (Exception& e)
00068 {
00069
00070 input_flux = magnitude;
00071 output_flux = -input_flux*mLeftElectrodeArea/mRightElectrodeArea;
00072
00073
00074 assert( ! std::isnan(output_flux));
00075 assert( output_flux != 0.0);
00076 }
00077
00078 ConstBoundaryCondition<DIM>* p_bc_flux_in = new ConstBoundaryCondition<DIM>(input_flux);
00079 ConstBoundaryCondition<DIM>* p_bc_flux_out = new ConstBoundaryCondition<DIM>(output_flux);
00080
00081
00082
00083 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00084 = mpMesh->GetBoundaryElementIteratorBegin();
00085 iter != mpMesh->GetBoundaryElementIteratorEnd();
00086 iter++)
00087 {
00088 if (fabs((*iter)->CalculateCentroid()[axis_index] - global_min) < 1e-6)
00089 {
00090 mpBoundaryConditionsContainer->AddNeumannBoundaryCondition(*iter, p_bc_flux_in, 1);
00091 }
00092
00093 if (!mGroundSecondElectrode)
00094 {
00095 if (fabs((*iter)->CalculateCentroid()[axis_index] - global_max) < 1e-6)
00096 {
00097 mpBoundaryConditionsContainer->AddNeumannBoundaryCondition(*iter, p_bc_flux_out, 1);
00098 }
00099 }
00100 }
00101
00102
00103
00104 if (mGroundSecondElectrode)
00105 {
00106 ConstBoundaryCondition<DIM>* p_zero_bc = new ConstBoundaryCondition<DIM>(0.0);
00107
00108 this->mpBoundaryConditionsContainer->ResetDirichletCommunication();
00109
00110 for (typename AbstractTetrahedralMesh<DIM,DIM>::NodeIterator iter=mpMesh->GetNodeIteratorBegin();
00111 iter != mpMesh->GetNodeIteratorEnd();
00112 ++iter)
00113 {
00114 if (fabs((*iter).rGetLocation()[axis_index]-global_max) < 1e-6)
00115 {
00116 mpBoundaryConditionsContainer->AddDirichletBoundaryCondition(&(*iter), p_zero_bc, 1);
00117 }
00118 }
00119
00120
00121 delete p_bc_flux_out;
00122 }
00123 }
00124
00125
00126
00127 template<unsigned DIM>
00128 boost::shared_ptr<BoundaryConditionsContainer<DIM,DIM,2> > Electrodes<DIM>::GetBoundaryConditionsContainer()
00129 {
00130
00131 return mpBoundaryConditionsContainer;
00132 }
00133
00134
00135 template<unsigned DIM>
00136 bool Electrodes<DIM>::SwitchOff(double time)
00137 {
00138
00140 double smidge = 1e-10;
00141 if (mAreActive && time>mEndTime-smidge)
00142 {
00143 mAreActive = false;
00144 return true;
00145 }
00146
00147 return false;
00148 }
00149
00150 template<unsigned DIM>
00151 bool Electrodes<DIM>::SwitchOn(double time)
00152 {
00153
00155 double smidge = 1e-10;
00156 if (!mAreActive && time>=mStartTime && time<=mEndTime - smidge)
00157 {
00158 mAreActive = true;
00159 return true;
00160 }
00161
00162 return false;
00163 }
00164
00165 template<unsigned DIM>
00166 void Electrodes<DIM>::ComputeElectrodesAreasAndCheckEquality(unsigned dimensionIndex, double lowerValue, double upperValue)
00167 {
00168
00169
00170
00171 double local_left_area = 0.0;
00172 double local_right_area = 0.0;
00173
00174 c_vector<double,DIM> weighted_direction;
00175 double jacobian_determinant;
00176
00177
00178 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00179 = mpMesh->GetBoundaryElementIteratorBegin();
00180 iter != mpMesh->GetBoundaryElementIteratorEnd();
00181 iter++)
00182 {
00183 if ( mpMesh->CalculateDesignatedOwnershipOfBoundaryElement( (*iter)->GetIndex() ))
00184 {
00185 if (fabs((*iter)->CalculateCentroid()[dimensionIndex] - lowerValue) < 1e-6)
00186 {
00187 mpMesh->GetWeightedDirectionForBoundaryElement((*iter)->GetIndex(), weighted_direction, jacobian_determinant);
00188 local_left_area += jacobian_determinant;
00189 }
00190
00191 if (fabs((*iter)->CalculateCentroid()[dimensionIndex] - upperValue) < 1e-6)
00192 {
00193 mpMesh->GetWeightedDirectionForBoundaryElement((*iter)->GetIndex(), weighted_direction, jacobian_determinant);
00194 local_right_area += jacobian_determinant;
00195 }
00196 }
00197 }
00198
00199 if(DIM==3)
00200 {
00201
00202
00203
00204
00205
00206
00207
00208 local_left_area /= 2.0;
00209 local_right_area /= 2.0;
00210 }
00211
00212 int mpi_ret = MPI_Allreduce(&local_left_area, &mLeftElectrodeArea, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
00213 assert(mpi_ret == MPI_SUCCESS);
00214
00215 mpi_ret = MPI_Allreduce(&local_right_area, &mRightElectrodeArea, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
00216 assert(mpi_ret == MPI_SUCCESS);
00217
00218 if (mLeftElectrodeArea != mRightElectrodeArea)
00219 {
00220 EXCEPTION("Electrodes have different area");
00221 }
00222 }
00223
00224
00226
00228
00229 template class Electrodes<1>;
00230 template class Electrodes<2>;
00231 template class Electrodes<3>;
00232
00233
00234
00235 #include "SerializationExportWrapperForCpp.hpp"
00236 EXPORT_TEMPLATE_CLASS_SAME_DIMS(Electrodes)