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
00139 double smidge = 1e-10;
00140 if (mAreActive && time>mEndTime-smidge)
00141 {
00142 mAreActive = false;
00143 return true;
00144 }
00145
00146 return false;
00147 }
00148
00149 template<unsigned DIM>
00150 bool Electrodes<DIM>::SwitchOn(double time)
00151 {
00152
00153 double smidge = 1e-10;
00154 if (!mAreActive && time>=mStartTime && time<=mEndTime - smidge)
00155 {
00156 mAreActive = true;
00157 return true;
00158 }
00159
00160 return false;
00161 }
00162
00163 template<unsigned DIM>
00164 void Electrodes<DIM>::ComputeElectrodesAreasAndCheckEquality(unsigned dimensionIndex, double lowerValue, double upperValue)
00165 {
00166
00167
00168
00169 double local_left_area = 0.0;
00170 double local_right_area = 0.0;
00171
00172 c_vector<double,DIM> weighted_direction;
00173 double jacobian_determinant;
00174
00175
00176 for (typename AbstractTetrahedralMesh<DIM,DIM>::BoundaryElementIterator iter
00177 = mpMesh->GetBoundaryElementIteratorBegin();
00178 iter != mpMesh->GetBoundaryElementIteratorEnd();
00179 iter++)
00180 {
00181 if ( mpMesh->CalculateDesignatedOwnershipOfBoundaryElement( (*iter)->GetIndex() ))
00182 {
00183 if (fabs((*iter)->CalculateCentroid()[dimensionIndex] - lowerValue) < 1e-6)
00184 {
00185 mpMesh->GetWeightedDirectionForBoundaryElement((*iter)->GetIndex(), weighted_direction, jacobian_determinant);
00186 local_left_area += jacobian_determinant;
00187 }
00188
00189 if (fabs((*iter)->CalculateCentroid()[dimensionIndex] - upperValue) < 1e-6)
00190 {
00191 mpMesh->GetWeightedDirectionForBoundaryElement((*iter)->GetIndex(), weighted_direction, jacobian_determinant);
00192 local_right_area += jacobian_determinant;
00193 }
00194 }
00195 }
00196
00197 if(DIM==3)
00198 {
00199
00200
00201
00202
00203
00204
00205
00206 local_left_area /= 2.0;
00207 local_right_area /= 2.0;
00208 }
00209
00210 int mpi_ret = MPI_Allreduce(&local_left_area, &mLeftElectrodeArea, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
00211 assert(mpi_ret == MPI_SUCCESS);
00212
00213 mpi_ret = MPI_Allreduce(&local_right_area, &mRightElectrodeArea, 1, MPI_DOUBLE, MPI_SUM, PETSC_COMM_WORLD);
00214 assert(mpi_ret == MPI_SUCCESS);
00215
00216 if (mLeftElectrodeArea != mRightElectrodeArea)
00217 {
00218 EXCEPTION("Electrodes have different area");
00219 }
00220 }
00221
00222
00224
00226
00227 template class Electrodes<1>;
00228 template class Electrodes<2>;
00229 template class Electrodes<3>;
00230
00231
00232
00233 #include "SerializationExportWrapperForCpp.hpp"
00234 EXPORT_TEMPLATE_CLASS_SAME_DIMS(Electrodes)