blob: f77aeef07b61bbbd3a42ce33cc404d700ca7a39d [file] [log] [blame]
//#####################################################################
// Copyright 2004, Igor Neverov, Eftychios Sifakis.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class FACE_EXAMPLE
//#####################################################################
#ifndef __FACE_EXAMPLE__
#define __FACE_EXAMPLE__
#include "QUASISTATICS_EXAMPLE.h"
#include "../../Public_Library/Collisions_And_Interactions/TETRAHEDRON_COLLISION_BODY.h"
#include "FACE_OPTIMIZATION.h"
#include "FACE_OPTIMIZATION_GOAL.h"
#include "ACTIVATION_CONTROL_SET.h"
#include "ATTACHMENT_FRAME_CONTROL_SET.h"
#include "LANDMARK_3D.h"
#include "../../Public_Library/Utilities/LOG.h"
#include "../../Public_Library/Thread_Utilities/THREAD_POOL.h"
extern bool PHYSBAM_THREADED_RUN;
namespace PhysBAM
{
template <class T, class RW>
class FACE_EXAMPLE: public QUASISTATICS_EXAMPLE<T, RW>
{
public:
using SOLIDS_FLUIDS_EXAMPLE<T>::output_directory;
using SOLIDS_FLUIDS_EXAMPLE<T>::verbose;
using SOLIDS_FLUIDS_EXAMPLE_3D<T, RW>::solids_parameters;
FACE_CONTROL_PARAMETERS<T> control_parameters;
FACE_OPTIMIZATION<T>* optimization;
FACE_OPTIMIZATION_GOAL<T>* optimization_goal;
int restart_step, write_last_step;
int static_target_frame;
std::string input_directory, model_directory;
int number_of_muscles, number_of_attachments;
LIST_ARRAY<LIST_ARRAY<int> > muscle_tets;
LIST_ARRAY<LIST_ARRAY<VECTOR_3D<T> > > muscle_fibers;
LIST_ARRAY<LIST_ARRAY<T> > muscle_densities;
LIST_ARRAY<std::string> muscle_names;
LIST_ARRAY<T> peak_isometric_stress;
LIST_ARRAY<LIST_ARRAY<int> > attached_nodes;
ARRAY<LIST_ARRAY<int> >* attached_nodes_parallel;
int jaw_attachment_index;
ACTIVATION_CONTROL_SET<T> *activation_controls;
ATTACHMENT_FRAME_CONTROL_SET<T> *attachment_frame_controls;
bool use_rigid_body_collision, use_self_collision;
DIAGONALIZED_CONSTITUTIVE_MODEL_3D<T> *face_constitutive_model;
T peak_isometric_stress_boosting;
FACE_EXAMPLE()
: optimization (0), optimization_goal (0), restart_step (0), write_last_step (true), static_target_frame (-1), peak_isometric_stress_boosting ( (T) 1), attached_nodes_parallel (0)
{}
void Write_Output_Files (const int frame) const
{
QUASISTATICS_EXAMPLE<T, RW>::Write_Output_Files (frame);
if (optimization) optimization->template Write_Optimization_Data<RW> (output_directory + "/", frame);
else Write_Controls (output_directory + "/", frame);
}
void Read_Output_Files_Solids (const int frame)
{
QUASISTATICS_EXAMPLE<T, RW>::Read_Output_Files_Solids (frame);
if (optimization) optimization->template Read_Optimization_Data<RW> (output_directory + "/", frame);
else Read_Controls (output_directory + "/", frame);
}
void Write_Controls (const std::string& prefix, const int frame) const
{
std::string f = STRING_UTILITIES::string_sprintf (".%d", frame);
FILE_UTILITIES::Write_To_File<RW> (prefix + "controls" + f, control_parameters);
}
void Read_Controls (const std::string& prefix, const int frame)
{
std::string f = STRING_UTILITIES::string_sprintf (".%d", frame);
FILE_UTILITIES::Read_From_File<RW> (prefix + "controls" + f, control_parameters);
}
void Default() const
{
std::cout << "THIS FACE_EXAMPLE FUNCTION IS NOT DEFINED!" << std::endl;
}
virtual void Set_External_Controls (const T time) {}
virtual void Preprocess_Frame (const int frame) {}
virtual void Postprocess_Frame (const int frame) {}
virtual void Postprocess_Solids_Substep (const T time, const int substep) {}
//#####################################################################
// Function Initialize_Bodies
//#####################################################################
void Initialize_Bodies()
{
Get_Initial_Data();
if (use_self_collision) Initialize_Tetrahedron_Collisions();
QUASISTATICS_EXAMPLE<T, RW>::Initialize_Bodies();
DEFORMABLE_OBJECT_3D<T>& deformable_object = solids_parameters.deformable_body_parameters.list (1);
activation_controls = new ACTIVATION_CONTROL_SET<T>;
for (int i = 1; i <= number_of_muscles; i++) activation_controls->Add_Activation();
control_parameters.list.Append_Element (activation_controls);
attachment_frame_controls = new ATTACHMENT_FRAME_CONTROL_SET<T> (deformable_object.particles.X.array, attached_nodes, jaw_attachment_index);
attachment_frame_controls->template Initialize_Jaw_Joint_From_File<RW> (input_directory + "/jaw_joint_parameters");
control_parameters.list.Append_Element (attachment_frame_controls);
if (use_rigid_body_collision)
{
assert (attachment_frame_controls);
attachment_frame_controls->Set_Original_Attachment_Configuration (solids_parameters.rigid_body_parameters.list.rigid_bodies (1)->Frame(),
solids_parameters.rigid_body_parameters.list.rigid_bodies (2)->Frame());
}
deformable_object.Add_Quasistatic_Diagonalized_Face (*deformable_object.tetrahedralized_volume, muscle_tets, muscle_fibers, muscle_densities,
activation_controls->activations, &activation_controls->single_activation_used_for_force_derivative, &peak_isometric_stress, &face_constitutive_model, (T) 6e4, (T) 2e4, (T) 3e6, (T).1);
activation_controls->muscle_force = deformable_object.diagonalized_finite_volume_3d (1);
attachment_frame_controls->muscle_force = deformable_object.diagonalized_finite_volume_3d (1);
// Collision settings
if (solids_parameters.perform_collision_body_collisions)
{
COLLISION_PENALTY_FORCES<T> *penalty_force = new COLLISION_PENALTY_FORCES<T> (solids_parameters.deformable_body_parameters.list.deformable_objects (1)->tetrahedralized_volume->particles);
penalty_force->Set_Stiffness ( (T) 1e3);
penalty_force->Set_Separation_Parameter ( (T) 1e-4);
penalty_force->Set_Collision_Body_List (solids_parameters.collision_body_list);
if (use_self_collision) penalty_force->Set_Collision_Body_List_ID (solids_parameters.rigid_body_parameters.list.rigid_bodies.m + 1);
penalty_force->Set_Boundary_Only_Collisions (solids_parameters.deformable_body_parameters.list.deformable_objects (1)->tetrahedralized_volume->tetrahedron_mesh);
solids_parameters.deformable_body_parameters.list.deformable_objects (1)->collision_penalty_forces.Append_Element (penalty_force);
solids_parameters.deformable_body_parameters.list.deformable_objects (1)->solids_forces.Append_Element (penalty_force);
if (optimization) optimization->solids_evolution_callbacks = this;
}
}
//#####################################################################
// Function Get_Initial_Data
//#####################################################################
void Get_Initial_Data()
{
solids_parameters.deformable_body_parameters.list.Add_Deformable_Object();
solids_parameters.deformable_body_parameters.list (1).Allocate_Tetrahedralized_Volume();
TETRAHEDRALIZED_VOLUME<T> &tetrahedralized_volume = *solids_parameters.deformable_body_parameters.list (1).tetrahedralized_volume;
TETRAHEDRON_MESH& tetrahedron_mesh = tetrahedralized_volume.tetrahedron_mesh;
SOLIDS_PARTICLE<T, VECTOR_3D<T> >& particles = tetrahedralized_volume.particles;
std::string input_file;
std::istream *input;
int peak_isometric_stress_entries;
if (PHYSBAM_THREADED_RUN)
{
THREAD_POOL& pool = *THREAD_POOL::Singleton();
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/face_simulation_%d.tet", pool.number_of_threads);
}
#ifndef NEW_SERIAL_IMPLEMENTATIOM
else
input_file = input_directory + "/face_simulation.tet";
#else
else
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/face_simulation_%d.tet", 1);
#endif
input = FILE_UTILITIES::Safe_Open_Input (input_file);
std::cout << "Reading simulation model : " << input_file << std::endl;
tetrahedralized_volume.template Read<RW> (*input);
delete input;
std::cout << "Total particles = " << particles.number << std::endl;
std::cout << "Total tetrahedra = " << tetrahedron_mesh.tetrahedrons.m << std::endl;
particles.Store_Velocity (false);
particles.Store_Mass (false);
particles.Store_Mass();
tetrahedralized_volume.Set_Density (1000);
tetrahedralized_volume.Set_Mass_Of_Particles (solids_parameters.use_constant_mass);
tetrahedralized_volume.Update_Bounding_Box();
if (PHYSBAM_THREADED_RUN)
{
THREAD_POOL& pool = *THREAD_POOL::Singleton();
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/node_divisions_%d.dat", pool.number_of_threads);
tetrahedralized_volume.particles.particle_ranges = new ARRAY<VECTOR_2D<int> >;
FILE_UTILITIES::Read_From_File<RW> (input_file, *tetrahedralized_volume.particles.particle_ranges);
}
#ifdef NEW_SERIAL_IMPLEMENTATIOM
else
{
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/node_divisions_%d.dat", 1);
tetrahedralized_volume.particles.particle_ranges = new ARRAY<VECTOR_2D<int> >;
FILE_UTILITIES::Read_From_File<RW> (input_file, *tetrahedralized_volume.particles.particle_ranges);
}
#endif
input_file = input_directory + "/muscle_list.txt";
input = FILE_UTILITIES::Safe_Open_Input (input_file, false);
(*input) >> number_of_muscles;
std::cout << "muscles = " << number_of_muscles << std::endl;
muscle_tets.Resize_Array (number_of_muscles);
muscle_fibers.Resize_Array (number_of_muscles);
muscle_densities.Resize_Array (number_of_muscles);
muscle_names.Resize_Array (number_of_muscles), peak_isometric_stress.Resize_Array (number_of_muscles);
for (int i = 1; i <= number_of_muscles; i++)
{
(*input) >> muscle_names (i);
input_file = input_directory + "/" + muscle_names (i) + ".constitutive_data";
if (verbose) std::cout << "Reading muscle data : " << muscle_names (i) << ".constitutive_data" << std::endl;
std::istream *muscle_input = FILE_UTILITIES::Safe_Open_Input (input_file);
muscle_tets (i).template Read<RW> (*muscle_input);
muscle_fibers (i).template Read<RW> (*muscle_input);
muscle_densities (i).template Read<RW> (*muscle_input);
delete muscle_input;
}
delete input;
LIST_ARRAY<T>::copy ( (T) 3e5, peak_isometric_stress);
input_file = input_directory + "/peak_isometric_stress_list.txt";
input = FILE_UTILITIES::Safe_Open_Input (input_file, false);
(*input) >> peak_isometric_stress_entries;
for (int i = 1; i <= peak_isometric_stress_entries; i++)
{
std::string muscle_name;
T peak_isometric_stress_value;
(*input) >> muscle_name >> peak_isometric_stress_value;
int index;
if (muscle_names.Find (muscle_name, index)) peak_isometric_stress (index) = peak_isometric_stress_value;
}
delete input;
if (verbose) for (int i = 1; i <= number_of_muscles; i++) std::cout << muscle_names (i) << " : Peak isometric stress = " << peak_isometric_stress (i) << std::endl;
for (int i = 1; i <= peak_isometric_stress.m; i++) peak_isometric_stress (i) *= peak_isometric_stress_boosting;
input_file = input_directory + "/attachment_list.txt";
input = FILE_UTILITIES::Safe_Open_Input (input_file, false);
(*input) >> number_of_attachments;
std::cout << "attachments = " << number_of_attachments << std::endl;
attached_nodes.Resize_Array (number_of_attachments);
jaw_attachment_index = 0;
for (int i = 1; i <= number_of_attachments; i++)
{
std::string attachment_name;
(*input) >> attachment_name;
input_file = input_directory + "/" + attachment_name + ".attached_nodes";
if (verbose) std::cout << "Reading attachment data : " << attachment_name << ".attached_nodes" << std::endl;
std::istream *attachment_input = FILE_UTILITIES::Safe_Open_Input (input_file);
attached_nodes (i).template Read<RW> (*attachment_input);
if (attachment_name == "jaw") jaw_attachment_index = i;
}
delete input;
if (!jaw_attachment_index)
{
std::cerr << "ERROR: No jaw attachment specified" << std::endl;
exit (1);
}
if (PHYSBAM_THREADED_RUN)
{
THREAD_POOL& pool = *THREAD_POOL::Singleton();
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/particle_positions_%d.dat", pool.number_of_threads);
ARRAY<int> particle_positions;
FILE_UTILITIES::Read_From_File<RW> (input_file, particle_positions);
for (int i = 1; i <= attached_nodes.m; i++)
for (int j = 1; j <= attached_nodes (i).m; j++) attached_nodes (i) (j) = particle_positions (attached_nodes (i) (j));
attached_nodes_parallel = new ARRAY<LIST_ARRAY<int> > (particles.particle_ranges->m);
for (int i = 1; i <= attached_nodes.m; i++) for (int j = 1; j <= attached_nodes (i).m; j++) for (int k = 1; k <= particles.particle_ranges->m; k++)
if (attached_nodes (i) (j) >= (*particles.particle_ranges) (k).x && attached_nodes (i) (j) <= (*particles.particle_ranges) (k).y)
(*attached_nodes_parallel) (k).Append_Element (attached_nodes (i) (j));
}
#ifdef NEW_SERIAL_IMPLEMENTATIOM
else
{
input_file = input_directory + STRING_UTILITIES::string_sprintf ("/particle_positions_%d.dat", 1);
ARRAY<int> particle_positions;
FILE_UTILITIES::Read_From_File<RW> (input_file, particle_positions);
for (int i = 1; i <= attached_nodes.m; i++)
for (int j = 1; j <= attached_nodes (i).m; j++) attached_nodes (i) (j) = particle_positions (attached_nodes (i) (j));
attached_nodes_parallel = new ARRAY<LIST_ARRAY<int> > (particles.particle_ranges->m);
for (int i = 1; i <= attached_nodes.m; i++) for (int j = 1; j <= attached_nodes (i).m; j++) for (int k = 1; k <= particles.particle_ranges->m; k++)
if (attached_nodes (i) (j) >= (*particles.particle_ranges) (k).x && attached_nodes (i) (j) <= (*particles.particle_ranges) (k).y)
(*attached_nodes_parallel) (k).Append_Element (attached_nodes (i) (j));
}
#endif
if (use_rigid_body_collision)
{
solids_parameters.rigid_body_parameters.list.template Add_Rigid_Body<T> (model_directory + "/eftychis_cranium_collision_surface");
solids_parameters.rigid_body_parameters.list.template Add_Rigid_Body<T> (model_directory + "/eftychis_jaw_collision_surface");
solids_parameters.rigid_body_parameters.list.rigid_bodies (1)->Set_Coefficient_Of_Friction (0);
solids_parameters.rigid_body_parameters.list.rigid_bodies (2)->Set_Coefficient_Of_Friction (0);
LIST_ARRAY<RIGID_BODY_3D<T>*>& rigid_bodies = solids_parameters.rigid_body_parameters.list.rigid_bodies;
solids_parameters.collision_body_list.Add_Bodies (solids_parameters.rigid_body_parameters.list);
}
}
//#####################################################################
// Function Initialize_Tetrahedron_Collisions
//#####################################################################
void Initialize_Tetrahedron_Collisions()
{
std::cout << "Initializing geometric structures for self collision" << std::endl;
TETRAHEDRALIZED_VOLUME<T> &tetrahedralized_volume = *solids_parameters.deformable_body_parameters.list (1).tetrahedralized_volume;
TETRAHEDRON_COLLISION_BODY<T> *face_collision_body = new TETRAHEDRON_COLLISION_BODY<T> (tetrahedralized_volume);
SOLIDS_PARTICLE<T, VECTOR_3D<T> >* undeformed_particles = new SOLIDS_PARTICLE<T, VECTOR_3D<T> > (tetrahedralized_volume.particles);
TRIANGULATED_SURFACE<T> *undeformed_triangulated_surface = new TRIANGULATED_SURFACE<T> (tetrahedralized_volume.triangulated_surface->triangle_mesh, *undeformed_particles);
undeformed_triangulated_surface->Update_Triangle_List();
undeformed_triangulated_surface->Initialize_Triangle_Hierarchy();
std::cout << "Loading implicit surface for self collision" << std::endl;
LEVELSET_IMPLICIT_SURFACE<T>* undeformed_levelset;
FILE_UTILITIES::template Create_From_File<RW> (model_directory + "/face_full.phi", undeformed_levelset);
undeformed_levelset->Update_Box();
face_collision_body->Set_Implicit_Surface (undeformed_levelset);
face_collision_body->Set_Collision_Thickness ( (T) 1e-3);
face_collision_body->Set_Undeformed_Triangulated_Surface (undeformed_triangulated_surface);
solids_parameters.collision_body_list.Add_Body (face_collision_body);
}
//#####################################################################
// Set_External_Positions
//#####################################################################
void Set_External_Positions (ARRAY<VECTOR_3D<T> >& X, const T time, const int id_number)
{
//LOG::Time("Set external positions");
switch (id_number)
{
case 1:
attachment_frame_controls->Set_Attachment_Positions (X);
break;
default:
std::cout << "Unrecognized deformable object id number" << std::endl;
exit (1);
}
}
//#####################################################################
// Zero_Out_Enslaved_Position_Nodes
//#####################################################################
template<class T2> struct ZERO_OUT_ENSLAVED_POSITION_NODES_HELPER
{
ARRAY<VECTOR_3D<T2> >* X;
LIST_ARRAY<int>const* partition_attached_nodes;
};
static void Zero_Out_Enslaved_Position_Nodes_Helper (long thread_id, void* helper_raw)
{
ZERO_OUT_ENSLAVED_POSITION_NODES_HELPER<T>& helper = * (ZERO_OUT_ENSLAVED_POSITION_NODES_HELPER<T>*) helper_raw;
ARRAY<VECTOR_3D<T> >&X = *helper.X;
LIST_ARRAY<int>const& partition_attached_nodes = *helper.partition_attached_nodes;
for (int i = 1; i <= partition_attached_nodes.m; i++) X (partition_attached_nodes (i)) = VECTOR_3D<T>();
}
void Zero_Out_Enslaved_Position_Nodes (ARRAY<VECTOR_3D<T> >& X, const T time, const int id_number)
{
//LOG::Time("Zero out enslaved position nodes");
switch (id_number)
{
case 1:
if (PHYSBAM_THREADED_RUN)
{
THREAD_POOL& pool = *THREAD_POOL::Singleton();
ARRAY<ZERO_OUT_ENSLAVED_POSITION_NODES_HELPER<T> > helpers (pool.number_of_threads);
for (int i = 1; i <= helpers.m; i++)
{
helpers (i).X = &X;
helpers (i).partition_attached_nodes = & ( (*attached_nodes_parallel) (i));
pool.Add_Task (Zero_Out_Enslaved_Position_Nodes_Helper, (void*) &helpers (i));
}
pool.Wait_For_Completion();
}
#ifndef NEW_SERIAL_IMPLEMENTATIOM
else
for (int i = 1; i <= attached_nodes.m; i++) for (int j = 1; j <= attached_nodes (i).m; j++) X (attached_nodes (i) (j)) = VECTOR_3D<T>();
#else
else
{
ARRAY<ZERO_OUT_ENSLAVED_POSITION_NODES_HELPER<T> > helpers (1);
helpers (1).X = &X;
helpers (1).partition_attached_nodes = & ( (*attached_nodes_parallel) (1));
Zero_Out_Enslaved_Position_Nodes_Helper (0, (void*) &helpers (1));
}
#endif
break;
default:
std::cout << "Unrecognized deformable object id number" << std::endl;
exit (1);
}
}
void Zero_Out_Enslaved_Position_Nodes (ARRAY<VECTOR_3D<T> >& X, const T time, const int id_number, const int partition_id)
{
assert (id_number == 1);
LIST_ARRAY<int>const& partition_attached_nodes = (*attached_nodes_parallel) (partition_id);
for (int i = 1; i <= partition_attached_nodes.m; i++) X (partition_attached_nodes (i)) = VECTOR_3D<T>();
}
//#####################################################################
// Function Update_Collision_Body_Positions_And_Velocities
//#####################################################################
void Update_Collision_Body_Positions_And_Velocities (const T time)
{
if (use_rigid_body_collision)
{
assert (attachment_frame_controls);
solids_parameters.rigid_body_parameters.list.rigid_bodies (1)->Set_State (attachment_frame_controls->Cranium_Frame());
solids_parameters.rigid_body_parameters.list.rigid_bodies (2)->Set_State (attachment_frame_controls->Jaw_Frame());
}
}
//#####################################################################
};
}
#endif