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