304 [[maybe_unused]]
double dt)
306 if constexpr (DIM == 2)
309 unsigned num_grid_pts_x = this->rGetMesh().GetNumGridPtsX();
310 unsigned num_grid_pts_y = this->rGetMesh().GetNumGridPtsY();
312 double characteristic_spacing = this->rGetMesh().GetCharacteristicNodeSpacing();
313 double grid_spacing_x = 1.0 / (
double)num_grid_pts_x;
314 double grid_spacing_y = 1.0 / (
double)num_grid_pts_y;
316 unsigned first_idx_x;
317 unsigned first_idx_y;
319 std::vector<unsigned> x_indices(4);
320 std::vector<unsigned> y_indices(4);
322 std::vector<double> x_deltas(4);
323 std::vector<double> y_deltas(4);
327 c_vector<double, DIM> displacement = zero_vector<double>(DIM);
330 const multi_array<double, 3>& vel_grids = this->rGetMesh().rGet2dVelocityGrids();
333 c_vector<double, DIM> node_location;
334 for (
auto node_iter = this->rGetMesh().GetNodeIteratorBegin(
false);
335 node_iter != this->rGetMesh().GetNodeIteratorEnd();
339 node_location = node_iter->rGetLocation();
342 first_idx_x =
unsigned(floor(node_location[0] / grid_spacing_x)) + num_grid_pts_x - 1;
343 first_idx_y =
unsigned(floor(node_location[1] / grid_spacing_y)) + num_grid_pts_y - 1;
346 for (
unsigned i = 0; i < 4; i++)
348 x_indices[i] = (first_idx_x + i) % num_grid_pts_x;
349 y_indices[i] = (first_idx_y + i) % num_grid_pts_y;
351 x_deltas[i] = Delta1D(fabs(x_indices[i] * grid_spacing_x - node_location[0]), grid_spacing_x);
352 y_deltas[i] = Delta1D(fabs(y_indices[i] * grid_spacing_x - node_location[1]), grid_spacing_y);
356 for (
unsigned x_idx = 0; x_idx < 4; ++x_idx)
358 for (
unsigned y_idx = 0; y_idx < 4; ++y_idx)
361 delta = x_deltas[x_idx] * y_deltas[y_idx];
362 displacement[0] += vel_grids[0][x_indices[x_idx]][y_indices[y_idx]] * delta;
363 displacement[1] += vel_grids[1][x_indices[x_idx]][y_indices[y_idx]] * delta;
371 if (norm_2(displacement) > characteristic_spacing)
373 if (norm_2(displacement) > 10.0 * characteristic_spacing)
375 EXCEPTION(
"Nodes are moving more than 10x CharacteristicNodeSpacing. Aborting.");
378 WARN_ONCE_ONLY(
"Nodes are moving more than the CharacteristicNodeSpacing. This could cause elements to become inverted so the motion has been restricted. Use a smaller timestep to avoid these warnings.");
379 displacement *= characteristic_spacing / norm_2(displacement);
383 node_location += displacement;
386 for (
unsigned i = 0; i < DIM; ++i)
388 node_location[i] = fmod(node_location[i] + 1.0, 1.0);
395 this->SetNode(node_iter->GetIndex(), new_point);
399 if (this->DoesPopulationHaveActiveSources())
401 std::vector<std::shared_ptr<FluidSource<DIM>>>& r_element_sources = this->rGetMesh().rGetElementFluidSources();
402 std::vector<std::shared_ptr<FluidSource<DIM>>>& r_balance_sources = this->rGetMesh().rGetBalancingFluidSources();
405 std::vector<std::shared_ptr<FluidSource<DIM>>> combined_sources;
406 combined_sources.insert(combined_sources.end(), r_element_sources.begin(), r_element_sources.end());
407 combined_sources.insert(combined_sources.end(), r_balance_sources.begin(), r_balance_sources.end());
409 c_vector<double, DIM> source_location;
412 for (
unsigned source_idx = 0; source_idx < combined_sources.size(); source_idx++)
415 source_location = combined_sources[source_idx]->rGetLocation();
418 first_idx_x =
unsigned(floor(source_location[0] / grid_spacing_x)) + num_grid_pts_x - 1;
419 first_idx_y =
unsigned(floor(source_location[1] / grid_spacing_y)) + num_grid_pts_y - 1;
422 for (
unsigned i = 0; i < 4; ++i)
424 x_indices[i] = (first_idx_x + i) % num_grid_pts_x;
425 y_indices[i] = (first_idx_y + i) % num_grid_pts_y;
427 x_deltas[i] = Delta1D(fabs(x_indices[i] * grid_spacing_x - source_location[0]), grid_spacing_x);
428 y_deltas[i] = Delta1D(fabs(y_indices[i] * grid_spacing_x - source_location[1]), grid_spacing_y);
432 for (
unsigned x_idx = 0; x_idx < 4; ++x_idx)
434 for (
unsigned y_idx = 0; y_idx < 4; ++y_idx)
437 delta = x_deltas[x_idx] * y_deltas[y_idx];
438 displacement[0] += vel_grids[0][x_indices[x_idx]][y_indices[y_idx]] * delta;
439 displacement[1] += vel_grids[1][x_indices[x_idx]][y_indices[y_idx]] * delta;
447 if (norm_2(displacement) > characteristic_spacing)
449 if (norm_2(displacement) > 10.0 * characteristic_spacing)
451 EXCEPTION(
"Sources are moving more than 10x CharacteristicNodeSpacing. Aborting.");
454 WARN_ONCE_ONLY(
"Sources are moving more than the CharacteristicNodeSpacing. This could cause elements to become inverted so the motion has been restricted. Use a smaller timestep to avoid these warnings.");
455 displacement *= characteristic_spacing / norm_2(displacement);
459 source_location += displacement;
462 for (
unsigned i = 0; i < DIM; ++i)
464 source_location[i] = fmod(source_location[i] + 1.0, 1.0);
468 combined_sources[source_idx]->rGetModifiableLocation() = source_location;
474 if (num_time_steps > 0 && num_time_steps % mReMeshFrequency == 0)
476 mpImmersedBoundaryMesh->ReMesh();
588 const std::string& rDirectory)
596 const std::vector<std::vector<unsigned>>& r_elem_parts = mesh_writer.
rGetElementParts();
599 for (
auto cell_writer_iter = this->mCellWriters.begin();
600 cell_writer_iter != this->mCellWriters.end();
604 std::vector<double> vtk_cell_data;
607 for (
auto elem_iter = mpImmersedBoundaryMesh->GetElementIteratorBegin();
608 elem_iter != mpImmersedBoundaryMesh->GetElementIteratorEnd();
615 const unsigned elem_index = elem_iter->GetIndex();
616 const auto num_elem_parts = r_elem_parts[elem_index].empty() ? 1 : r_elem_parts[elem_index].size();
619 CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
627 for (
unsigned elem_part = 0; elem_part < num_elem_parts; ++elem_part)
629 vtk_cell_data.push_back((*cell_writer_iter)->GetCellDataForVtkOutput(p_cell,
this));
637 for (
auto lam_iter = mpImmersedBoundaryMesh->GetLaminaIteratorBegin();
638 lam_iter != mpImmersedBoundaryMesh->GetLaminaIteratorEnd();
641 vtk_cell_data.push_back(-1.0);
644 mesh_writer.
AddCellData((*cell_writer_iter)->GetVtkCellDataName(), vtk_cell_data);
651 const unsigned num_cell_data_items = this->Begin()->GetCellData()->GetNumItems();
652 std::vector<std::string> cell_data_names = this->Begin()->GetCellData()->GetKeys();
654 std::vector<std::vector<double>> cell_data;
655 for (
unsigned var = 0; var < num_cell_data_items; ++var)
657 std::vector<double> cell_data_var;
658 cell_data.push_back(cell_data_var);
662 for (
auto elem_iter = mpImmersedBoundaryMesh->GetElementIteratorBegin();
663 elem_iter != mpImmersedBoundaryMesh->GetElementIteratorEnd();
670 const unsigned elem_index = elem_iter->GetIndex();
671 const auto num_elem_parts = r_elem_parts[elem_index].empty() ? 1 : r_elem_parts[elem_index].size();
674 CellPtr p_cell = this->GetCellUsingLocationIndex(elem_index);
677 for (
unsigned var = 0; var < num_cell_data_items; var++)
684 for (
unsigned elem_part = 0; elem_part < num_elem_parts; ++elem_part)
686 cell_data[var].push_back(p_cell->GetCellData()->GetItem(cell_data_names[var]));
695 for (
auto lam_iter = mpImmersedBoundaryMesh->GetLaminaIteratorBegin();
696 lam_iter != mpImmersedBoundaryMesh->GetLaminaIteratorEnd();
699 for (
unsigned var = 0; var < num_cell_data_items; ++var)
705 for (
unsigned var = 0; var < num_cell_data_items; ++var)
707 mesh_writer.
AddCellData(cell_data_names[var], cell_data[var]);
711 if (mOutputNodeRegionToVtk)
713 std::vector<double> node_regions;
714 for (
auto node_iter = mpImmersedBoundaryMesh->GetNodeIteratorBegin();
715 node_iter != mpImmersedBoundaryMesh->GetNodeIteratorEnd();
718 node_regions.push_back(
static_cast<double>(node_iter->GetRegion()));
724 std::stringstream time;
725 time << num_timesteps;
729 *(this->mpVtkMetaFile) <<
" <DataSet timestep=\"";
730 *(this->mpVtkMetaFile) << num_timesteps;
731 *(this->mpVtkMetaFile) <<
"\" group=\"\" part=\"0\" file=\"results_";
732 *(this->mpVtkMetaFile) << num_timesteps;
733 *(this->mpVtkMetaFile) <<
".vtu\"/>\n";
784 if constexpr (DIM == 2)
786 unsigned num_vertex_nodes = mpImmersedBoundaryMesh->GetNumNodes();
787 unsigned num_vertex_elements = mpImmersedBoundaryMesh->GetNumElements();
789 std::string mesh_file_name =
"mesh";
792 std::stringstream pid;
794 OutputFileHandler output_file_handler(
"2D_temporary_tetrahedral_mesh_" + pid.str());
798 unsigned num_tetrahedral_nodes = num_vertex_nodes + num_vertex_elements;
801 out_stream p_node_file = output_file_handler.
OpenOutputFile(mesh_file_name+
".node");
802 (*p_node_file) << std::scientific;
803 (*p_node_file) << std::setprecision(20);
804 (*p_node_file) << num_tetrahedral_nodes <<
"\t2\t0\t1" << std::endl;
807 auto nodes = mpImmersedBoundaryMesh->rGetNodes();
808 for (
auto p_node : nodes)
810 unsigned index = p_node->GetIndex();
811 const c_vector<double, DIM>& r_location = p_node->rGetLocation();
812 unsigned is_boundary_node = p_node->IsBoundaryNode() ? 1 : 0;
814 (*p_node_file) << index <<
"\t" << r_location[0] <<
"\t" << r_location[1] <<
"\t" << is_boundary_node << std::endl;
818 unsigned num_tetrahedral_elements = 0;
819 for (
unsigned vertex_elem_index = 0;
820 vertex_elem_index < num_vertex_elements;
823 unsigned index = num_vertex_nodes + vertex_elem_index;
825 c_vector<double, DIM> location = mpImmersedBoundaryMesh->GetCentroidOfElement(vertex_elem_index);
828 unsigned is_boundary_node = 0;
829 (*p_node_file) << index <<
"\t" << location[0] <<
"\t" << location[1] <<
"\t" << is_boundary_node << std::endl;
832 num_tetrahedral_elements += mpImmersedBoundaryMesh->GetElement(vertex_elem_index)->GetNumNodes();
834 p_node_file->close();
837 out_stream p_elem_file = output_file_handler.
OpenOutputFile(mesh_file_name+
".ele");
838 (*p_elem_file) << std::scientific;
839 (*p_elem_file) << num_tetrahedral_elements <<
"\t3\t0" << std::endl;
841 std::set<std::pair<unsigned, unsigned> > tetrahedral_edges;
843 unsigned tetrahedral_elem_index = 0;
844 for (
unsigned vertex_elem_index = 0;
845 vertex_elem_index < num_vertex_elements;
851 unsigned num_nodes_in_vertex_element = p_vertex_element->
GetNumNodes();
852 for (
unsigned local_index = 0;
853 local_index < num_nodes_in_vertex_element;
857 unsigned node_1_index = p_vertex_element->
GetNodeGlobalIndex((local_index+1)%num_nodes_in_vertex_element);
858 unsigned node_2_index = num_vertex_nodes + vertex_elem_index;
860 (*p_elem_file) << tetrahedral_elem_index++ <<
"\t" << node_0_index <<
"\t" << node_1_index <<
"\t" << node_2_index << std::endl;
863 std::pair<unsigned, unsigned> edge_0 = this->CreateOrderedPair(node_0_index, node_1_index);
864 std::pair<unsigned, unsigned> edge_1 = this->CreateOrderedPair(node_1_index, node_2_index);
865 std::pair<unsigned, unsigned> edge_2 = this->CreateOrderedPair(node_2_index, node_0_index);
867 tetrahedral_edges.insert(edge_0);
868 tetrahedral_edges.insert(edge_1);
869 tetrahedral_edges.insert(edge_2);
872 p_elem_file->close();
875 out_stream p_edge_file = output_file_handler.
OpenOutputFile(mesh_file_name+
".edge");
876 (*p_edge_file) << std::scientific;
877 (*p_edge_file) << tetrahedral_edges.size() <<
"\t1" << std::endl;
879 unsigned edge_index = 0;
880 for (
auto edge_iter = tetrahedral_edges.begin();
881 edge_iter != tetrahedral_edges.end();
884 std::pair<unsigned, unsigned> this_edge = *edge_iter;
887 bool is_boundary_edge =
false;
888 if (this_edge.first < mpImmersedBoundaryMesh->GetNumNodes() &&
889 this_edge.second < mpImmersedBoundaryMesh->GetNumNodes())
891 is_boundary_edge = (mpImmersedBoundaryMesh->GetNode(this_edge.first)->IsBoundaryNode() &&
892 mpImmersedBoundaryMesh->GetNode(this_edge.second)->IsBoundaryNode() );
894 unsigned is_boundary_edge_unsigned = is_boundary_edge ? 1 : 0;
896 (*p_edge_file) << edge_index++ <<
"\t" << this_edge.first <<
"\t" << this_edge.second <<
"\t" << is_boundary_edge_unsigned << std::endl;
898 p_edge_file->close();
922 EXCEPTION(
"ImmersedBoundaryCellPopulation::GetTetrahedralMeshForPDEModifier is only implemented in 2D");
961 unsigned pdeNodeIndex,
962 std::string& rVariableName,
963 bool dirichletBoundaryConditionApplies,
964 double dirichletBoundaryValue)
966 unsigned num_nodes = this->GetNumNodes();
973 if (pdeNodeIndex >= num_nodes)
976 assert(pdeNodeIndex-num_nodes < num_nodes);
978 CellPtr p_cell = this->GetCellUsingLocationIndex(pdeNodeIndex - num_nodes);
979 value = p_cell->GetCellData()->GetItem(rVariableName);
984 if (dirichletBoundaryConditionApplies)
987 value = dirichletBoundaryValue;
991 assert(pdeNodeIndex < num_nodes);
992 Node<DIM>* p_node = this->GetNode(pdeNodeIndex);
996 for (
auto index_iter = containing_elements.begin();
997 index_iter != containing_elements.end();
1000 assert(*index_iter < num_nodes);
1001 CellPtr p_cell = this->GetCellUsingLocationIndex(*index_iter);
1002 value += p_cell->GetCellData()->GetItem(rVariableName);
1004 value /= containing_elements.size();