Commit df09a1b6 authored by Kirill Terekhov's avatar Kirill Terekhov
parents e27f51ed 5571716c
Pipeline #124 failed with stages
in 7 minutes and 10 seconds
# use the official gcc image, based on debian
# can use versions as well, like gcc:5.2
image: gcc
stages:
- build
- test
build_debug:
stage: build
script:
- mkdir build_debug
- cd build_debug
- cmake -DCOMPILE_TESTS=ON -DUSE_OMP=ON -DCMAKE_CXX_FLAGS="-O0 -g" -DCMAKE_C_FLAGS="-O0 -g" ..
- make VERBOSE=1
artifacts:
paths:
- build_debug/
build_opt:
stage: build
script:
- mkdir build_opt
- cd build_opt
- cmake -DCOMPILE_TESTS=ON -DCOMPILE_EXAMPLES=ON -DUSE_OMP=ON -DCMAKE_CXX_FLAGS="-Ofast -march=native" -DCMAKE_C_FLAGS="-Ofast -march=native" ..
- make VERBOSE=1
artifacts:
paths:
- build_opt/
test_debug:
stage: test
script:
- cd build_debug
- ctest --output-on-failure
dependencies:
- build_debug
test_opt:
stage: test
script:
- cd build_opt
- ctest --output-on-failure
dependencies:
- build_opt
...@@ -16,6 +16,7 @@ option(USE_MPI_P2P "Use MPI point to point functionality, may be faster with har ...@@ -16,6 +16,7 @@ option(USE_MPI_P2P "Use MPI point to point functionality, may be faster with har
option(USE_MPI_FILE "Use MPI extension to work with files, may save a lot of memory" ON) option(USE_MPI_FILE "Use MPI extension to work with files, may save a lot of memory" ON)
option(USE_MPI2 "Use MPI-2 extensions, useful if your MPI library warns you to use new functions" ON) option(USE_MPI2 "Use MPI-2 extensions, useful if your MPI library warns you to use new functions" ON)
option(USE_OMP "Compile with OpenMP support (experimental)" OFF) option(USE_OMP "Compile with OpenMP support (experimental)" OFF)
option(USE_OPENCL "Use OpenCL where possible (experimental)" OFF)
option(USE_MESH "Compile mesh capabilities" ON) option(USE_MESH "Compile mesh capabilities" ON)
option(USE_SOLVER "Compile solver capabilities" ON) option(USE_SOLVER "Compile solver capabilities" ON)
...@@ -33,7 +34,6 @@ option(USE_SOLVER_MONDRIAAN "Use Mondriaan for matrix reordering" OFF) ...@@ -33,7 +34,6 @@ option(USE_SOLVER_MONDRIAAN "Use Mondriaan for matrix reordering" OFF)
option(USE_SOLVER_PETSC "Use PETSc solvers" OFF) option(USE_SOLVER_PETSC "Use PETSc solvers" OFF)
option(USE_SOLVER_TRILINOS "Use Trilinos solvers" OFF) option(USE_SOLVER_TRILINOS "Use Trilinos solvers" OFF)
option(USE_SOLVER_SUPERLU "Use SuperLU solver" OFF) option(USE_SOLVER_SUPERLU "Use SuperLU solver" OFF)
#option(USE_AUTODIFF_OPENCL "Use OpenCL for automatic differentiation (under work)" OFF)
#option(USE_AUTODIFF_ASMJIT "Use AsmJit for automatic differentiation" OFF) #option(USE_AUTODIFF_ASMJIT "Use AsmJit for automatic differentiation" OFF)
#option(USE_AUTODIFF_EXPRESSION_TEMPLATES "Use c++ expression templates for automatic differentiation" OFF) #option(USE_AUTODIFF_EXPRESSION_TEMPLATES "Use c++ expression templates for automatic differentiation" OFF)
...@@ -206,13 +206,13 @@ if(USE_SOLVER_SUPERLU) ...@@ -206,13 +206,13 @@ if(USE_SOLVER_SUPERLU)
endif() endif()
endif() endif()
if(USE_AUTODIFF_OPENCL) if(USE_OPENCL)
find_package(OpenCL) find_package(OpenCL)
if(OPENCL_FOUND) if(OPENCL_FOUND)
include_directories(${OPENCL_INCLUDE_DIRS}) include_directories(${OPENCL_INCLUDE_DIRS})
link_directories(${PETSC_LIBRARY_DIRS}) link_directories(${OpenCL_LIBRARY})
else() else()
set(USE_AUTODIFF_OPENCL OFF CACHE BOOL "Use OpenCL for automatic differentiation" FORCE) set(USE_OPENCL OFF CACHE BOOL "Use OpenCL where possible (experimental)" FORCE)
message("OpenCL not found") message("OpenCL not found")
endif() endif()
endif() endif()
......
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
#ifndef M_PI #ifndef M_PI
...@@ -90,7 +90,7 @@ int main(int argc,char ** argv) ...@@ -90,7 +90,7 @@ int main(int argc,char ** argv)
{ // currently only non-distributed meshes are supported by Inner_RCM partitioner { // currently only non-distributed meshes are supported by Inner_RCM partitioner
ttt = Timer(); ttt = Timer();
Partitioner * p = new Partitioner(m); Partitioner * p = new Partitioner(m);
p->SetMethod(Partitioner::Inner_RCM,Partitioner::Partition); // Specify the partitioner p->SetMethod(Partitioner::INNER_KMEANS,Partitioner::Partition); // Specify the partitioner
p->Evaluate(); // Compute the partitioner and store new processor ID in the mesh p->Evaluate(); // Compute the partitioner and store new processor ID in the mesh
delete p; delete p;
BARRIER; BARRIER;
......
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
#ifndef M_PI #ifndef M_PI
...@@ -125,7 +125,7 @@ int main(int argc,char ** argv) ...@@ -125,7 +125,7 @@ int main(int argc,char ** argv)
{ // Compute mesh partitioning { // Compute mesh partitioning
ttt = Timer(); ttt = Timer();
Partitioner p(m); //Create Partitioning object Partitioner p(m); //Create Partitioning object
p.SetMethod(Partitioner::Inner_RCM,repartition ? Partitioner::Repartition : Partitioner::Partition); // Specify the partitioner p.SetMethod(Partitioner::INNER_KMEANS,repartition ? Partitioner::Repartition : Partitioner::Partition); // Specify the partitioner
p.Evaluate(); // Compute the partitioner and store new processor ID in the mesh p.Evaluate(); // Compute the partitioner and store new processor ID in the mesh
BARRIER BARRIER
if( m->GetProcessorRank() == 0 ) std::cout << "Evaluate: " << Timer()-ttt << std::endl; if( m->GetProcessorRank() == 0 ) std::cout << "Evaluate: " << Timer()-ttt << std::endl;
......
...@@ -332,13 +332,15 @@ namespace INMOST ...@@ -332,13 +332,15 @@ namespace INMOST
//free created tag //free created tag
DeleteTag(indicator,FACE|EDGE); DeleteTag(indicator,FACE|EDGE);
//11. Restore parallel connectivity, global ids //11. Restore parallel connectivity, global ids
//ResolveModification(); ResolveShared(true);
ResolveModification();
//12. Let the user update their data //12. Let the user update their data
//todo: call back function for New() cells //todo: call back function for New() cells
//13. Delete old elements of the mesh //13. Delete old elements of the mesh
ApplyModification(); ApplyModification();
//14. Done //14. Done
EndModification(); EndModification();
//ExchangeData(hanging_nodes,CELL | FACE,0);
//reorder element's data to free up space //reorder element's data to free up space
ReorderEmpty(CELL|FACE|EDGE|NODE); ReorderEmpty(CELL|FACE|EDGE|NODE);
//return number of refined cells //return number of refined cells
...@@ -640,12 +642,14 @@ namespace INMOST ...@@ -640,12 +642,14 @@ namespace INMOST
//free created tag //free created tag
DeleteTag(indicator,FACE|EDGE); DeleteTag(indicator,FACE|EDGE);
//todo: //todo:
//ResolveModification(); ResolveShared(true);
ResolveModification();
//todo: //todo:
//let the user update their data //let the user update their data
ApplyModification(); ApplyModification();
//done //done
EndModification(); EndModification();
//ExchangeData(hanging_nodes,CELL | FACE,0);
//cleanup null links to hanging nodes //cleanup null links to hanging nodes
for(ElementType etype = FACE; etype <= CELL; etype = NextElementType(etype)) for(ElementType etype = FACE; etype <= CELL; etype = NextElementType(etype))
{ {
...@@ -666,4 +670,4 @@ namespace INMOST ...@@ -666,4 +670,4 @@ namespace INMOST
call_counter++; call_counter++;
return ret != 0; return ret != 0;
} }
} }
\ No newline at end of file
...@@ -9,6 +9,7 @@ int main(int argc, char ** argv) ...@@ -9,6 +9,7 @@ int main(int argc, char ** argv)
if( argc > 1 ) if( argc > 1 )
{ {
AdaptiveMesh m; AdaptiveMesh m;
m.SetCommunicator(INMOST_MPI_COMM_WORLD);
m.Load(argv[1]); m.Load(argv[1]);
//m.SetTopologyCheck(NEED_TEST_CLOSURE); //m.SetTopologyCheck(NEED_TEST_CLOSURE);
//m.SetTopologyCheck(PROHIBIT_MULTILINE); //m.SetTopologyCheck(PROHIBIT_MULTILINE);
...@@ -29,6 +30,8 @@ int main(int argc, char ** argv) ...@@ -29,6 +30,8 @@ int main(int argc, char ** argv)
if( it->Coords()[d] < cmin[d] ) cmin[d] = it->Coords()[d]; if( it->Coords()[d] < cmin[d] ) cmin[d] = it->Coords()[d];
} }
} }
m.AggregateMax(cmax,3);
m.AggregateMin(cmin,3);
r = 1; r = 1;
for(int d = 0; d < 3; ++d) for(int d = 0; d < 3; ++d)
{ {
...@@ -47,18 +50,20 @@ int main(int argc, char ** argv) ...@@ -47,18 +50,20 @@ int main(int argc, char ** argv)
numref = 0; numref = 0;
for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it) if( m.GetLevel(it->self()) < max_levels ) for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it) if( m.GetLevel(it->self()) < max_levels )
{ {
it->Centroid(xyz); it->Barycenter(xyz);
//refine a circle //refine a circle
q = 0; q = 0;
for(int d = 0; d < 3; ++d) for(int d = 0; d < 3; ++d)
q += (xyz[d]-cnt[d])*(xyz[d]-cnt[d]); q += (xyz[d]-cnt[d])*(xyz[d]-cnt[d]);
q = sqrt(q); q = sqrt(q);
if( q < r*(k+1) && q > r*k) if( q < r*(k+1) && q > r*k)
//if( q < 0.02 )
{ {
indicator[it->self()] = 1; indicator[it->self()] = 1;
numref++; numref++;
} }
} }
numref = m.Integrate(numref);
if( numref ) if( numref )
{ {
std::cout << "k " << k << " refcnt " << refcnt << " " << r*k << " < r < " << r*(k+1) << " numref " << numref << " cells " << m.NumberOfCells() << std::endl; std::cout << "k " << k << " refcnt " << refcnt << " " << r*k << " < r < " << r*(k+1) << " numref " << numref << " cells " << m.NumberOfCells() << std::endl;
...@@ -89,7 +94,7 @@ int main(int argc, char ** argv) ...@@ -89,7 +94,7 @@ int main(int argc, char ** argv)
numref = 0; numref = 0;
for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it) if( m.GetLevel(it->self()) > 0 ) for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it) if( m.GetLevel(it->self()) > 0 )
{ {
it->Centroid(xyz); it->Barycenter(xyz);
//refine a circle //refine a circle
q = 0; q = 0;
for(int d = 0; d < 3; ++d) for(int d = 0; d < 3; ++d)
...@@ -101,6 +106,7 @@ int main(int argc, char ** argv) ...@@ -101,6 +106,7 @@ int main(int argc, char ** argv)
numref++; numref++;
} }
} }
numref = m.Integrate(numref);
if( numref ) if( numref )
{ {
std::cout << "k " << k << " crscnt " << refcnt << " " << r*k << " < r < " << r*(k+1) << " numcrs " << numref << " cells " << m.NumberOfCells() << std::endl; std::cout << "k " << k << " crscnt " << refcnt << " " << r*k << " < r < " << r*(k+1) << " numcrs " << numref << " cells " << m.NumberOfCells() << std::endl;
...@@ -131,11 +137,19 @@ int main(int argc, char ** argv) ...@@ -131,11 +137,19 @@ int main(int argc, char ** argv)
{ {
std::stringstream file; std::stringstream file;
file << "step_" << k << ".vtk"; file << "step_" << k << ".pvtk";
m.Save(file.str()); m.Save(file.str());
} }
{ {
TagInteger tag_owner = m.CreateTag("OWN",DATA_INTEGER,CELL,NONE,1);
TagInteger tag_owner0 = m.GetTag("OWNER_PROCESSOR");
TagInteger tag_stat = m.CreateTag("STAT",DATA_INTEGER,CELL,NONE,1);
for(Mesh::iteratorCell it = m.BeginCell(); it != m.EndCell(); ++it)
{
tag_owner[*it] = tag_owner0[*it];
tag_stat[*it] = it->GetStatus();
}
std::stringstream file; std::stringstream file;
file << "step_" << k << ".pmf"; file << "step_" << k << ".pmf";
m.Save(file.str()); m.Save(file.str());
...@@ -143,4 +157,6 @@ int main(int argc, char ** argv) ...@@ -143,4 +157,6 @@ int main(int argc, char ** argv)
} }
} }
else std::cout << "Usage: " << argv[0] << " mesh_file [max_levels=2]" << std::endl; else std::cout << "Usage: " << argv[0] << " mesh_file [max_levels=2]" << std::endl;
}
\ No newline at end of file Mesh::Finalize();
}
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
#ifndef M_PI #ifndef M_PI
...@@ -92,7 +92,7 @@ int main(int argc,char ** argv) ...@@ -92,7 +92,7 @@ int main(int argc,char ** argv)
{ // currently only non-distributed meshes are supported by Inner_RCM partitioner { // currently only non-distributed meshes are supported by Inner_RCM partitioner
ttt = Timer(); ttt = Timer();
Partitioner * p = new Partitioner(m); Partitioner * p = new Partitioner(m);
p->SetMethod(Partitioner::Inner_RCM,Partitioner::Partition); // Specify the partitioner p->SetMethod(Partitioner::INNER_KMEANS,Partitioner::Partition); // Specify the partitioner
p->Evaluate(); // Compute the partitioner and store new processor ID in the mesh p->Evaluate(); // Compute the partitioner and store new processor ID in the mesh
delete p; delete p;
BARRIER BARRIER
...@@ -327,4 +327,4 @@ int main(int argc,char ** argv) ...@@ -327,4 +327,4 @@ int main(int argc,char ** argv)
#endif #endif
Solver::Finalize(); // Finalize solver and close MPI activity Solver::Finalize(); // Finalize solver and close MPI activity
return 0; return 0;
} }
\ No newline at end of file
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
#define MESH_SIZE 32 #define MESH_SIZE 32
...@@ -227,7 +227,7 @@ Mesh * ParallelGenerator(INMOST_MPI_Comm comm, int ng, int nx, int ny, int nz) ...@@ -227,7 +227,7 @@ Mesh * ParallelGenerator(INMOST_MPI_Comm comm, int ng, int nx, int ny, int nz)
{ {
CreateCubeElement(m,verts); CreateCubeElement(m,verts);
} }
else if ((i + j) % 2 == 0) // Create two prism cells else if ((i + j) % 2 == 0 || ng == 6) // Create two prism cells
{ {
CreateNWPrismElements(m,verts); CreateNWPrismElements(m,verts);
} }
...@@ -327,4 +327,4 @@ int main(int argc, char *argv[]) ...@@ -327,4 +327,4 @@ int main(int argc, char *argv[])
delete mesh; delete mesh;
Mesh::Finalize(); Mesh::Finalize();
return 0; return 0;
} }
\ No newline at end of file
...@@ -16,6 +16,8 @@ add_executable(Move move.cpp) ...@@ -16,6 +16,8 @@ add_executable(Move move.cpp)
add_executable(Convert convert.cpp) add_executable(Convert convert.cpp)
add_executable(SameMeshDifference difference_same.cpp) add_executable(SameMeshDifference difference_same.cpp)
add_executable(MeshDifference difference_map.cpp) add_executable(MeshDifference difference_map.cpp)
add_executable(Kmeans kmeans.cpp)
add_executable(Agglomerate agglomerate.cpp)
add_library(FractureLib fracture.cpp fracture.h) add_library(FractureLib fracture.cpp fracture.h)
target_link_libraries(FixFaults inmost) target_link_libraries(FixFaults inmost)
...@@ -185,6 +187,26 @@ if(USE_MPI) ...@@ -185,6 +187,26 @@ if(USE_MPI)
endif(USE_MPI) endif(USE_MPI)
install(TARGETS MeshDifference EXPORT inmost-targets RUNTIME DESTINATION bin) install(TARGETS MeshDifference EXPORT inmost-targets RUNTIME DESTINATION bin)
target_link_libraries(Kmeans inmost)
if(USE_MPI)
message("linking Kmeans with MPI")
target_link_libraries(Kmeans ${MPI_LIBRARIES})
if(MPI_LINK_FLAGS)
set_target_properties(Kmeans PROPERTIES LINK_FLAGS "${MPI_LINK_FLAGS}")
endif()
endif(USE_MPI)
install(TARGETS Kmeans EXPORT inmost-targets RUNTIME DESTINATION bin)
target_link_libraries(Agglomerate inmost)
if(USE_MPI)
message("linking Agglomerate with MPI")
target_link_libraries(Agglomerate ${MPI_LIBRARIES})
if(MPI_LINK_FLAGS)
set_target_properties(Agglomerate PROPERTIES LINK_FLAGS "${MPI_LINK_FLAGS}")
endif()
endif(USE_MPI)
install(TARGETS Agglomerate EXPORT inmost-targets RUNTIME DESTINATION bin)
set_property(TARGET FractureLib PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/fracture.h") set_property(TARGET FractureLib PROPERTY PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/fracture.h")
......
#include "inmost.h"
using namespace INMOST;
//todo: want to separate all faces into those that share edges
//see todo: inside text
int main(int argc, char ** argv)
{
if (argc < 2)
{
std::cout << "Usage: " << argv[0] << " mesh [tag=MATERIAL] [mesh_out=grid.vtk]" << std::endl;
return -1;
}
Mesh::Initialize(&argc,&argv);
std::string tag_name = "MATERIAL";
if( argc > 2) tag_name = std::string(argv[2]);
std::string grid_out = "grid.vtk";
if (argc > 3) grid_out = std::string(argv[3]);
Mesh m;
m.SetCommunicator(INMOST_MPI_COMM_WORLD);
m.Load(argv[1]);
if( !m.HaveTag(tag_name) )
{
std::cout << "mesh does not have tag named " << tag_name << std::endl;
exit(-1);
}
TagInteger mat = m.GetTag(tag_name);
std::cout << "Start:" << std::endl;
std::cout << "Cells: " << m.NumberOfCells() << std::endl;
std::cout << "Faces: " << m.NumberOfFaces() << std::endl;
std::cout << "Edges: " << m.NumberOfEdges() << std::endl;
std::map< int,ElementArray<Cell> > mat_cells;
for(int q = 0; q < m.CellLastLocalID(); ++q) if( m.isValidCell(q) )
{
Cell n = m.CellByLocalID(q);
mat_cells[ mat[n] ].push_back(n);
}
//Unite cells
//todo: split cells that are not connected by face
std::cout << "Unite cells" << std::endl;
int nunited = 0;
for(std::map< int,ElementArray<Cell> >::iterator it = mat_cells.begin();
it != mat_cells.end(); ++it)
{
if( it->second.size() > 1 )
{
mat[Cell::UniteCells(it->second,0)] = it->first;
nunited++;
}
}
std::cout << "united: " << nunited << std::endl;
/*
std::cout << "Unite faces" << std::endl;
std::map< std::pair<int,int>, ElementArray<Face> > faces;
nunited = 0;
for(int q = 0; q < m.FaceLastLocalID(); ++q) if( m.isValidFace(q) )
{
Face n = m.FaceByLocalID(q);
std::pair<int,int> f_cells;
int bc = n.BackCell().LocalID();;
int fc = n.FrontCell().isValid() ? n.FrontCell().LocalID() : -1;
f_cells.first = std::min(bc,fc);
f_cells.second = std::max(bc,fc);
faces[f_cells].push_back(n);
}
std::cout << "computed faces" << std::endl;
m.BeginModification();
//todo: split faces that are not connected by edge
for(std::map< std::pair<int,int>, ElementArray<Face> >::iterator it = faces.begin();
it != faces.end(); ++it)
{
if( it->second.size() > 1 )
{
std::cout << it->first.first << "<->" << it->first.second << " faces " << it->second.size() << std::endl;
Face::UniteFaces(it->second,0);
nunited++;
}
}
m.EndModification();
std::cout << "united: " << nunited << std::endl;
*/
std::cout << "Cells: " << m.NumberOfCells() << std::endl;
std::cout << "Faces: " << m.NumberOfFaces() << std::endl;
std::cout << "Edges: " << m.NumberOfEdges() << std::endl;
m.Save(grid_out);
Mesh::Finalize();
return 0;
}
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
...@@ -87,4 +87,4 @@ int main(int argc, char ** argv) ...@@ -87,4 +87,4 @@ int main(int argc, char ** argv)
} }
return 0; return 0;
} }
\ No newline at end of file
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
......
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
......
#include "inmost.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "inmost.h"
using namespace INMOST; using namespace INMOST;
......
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
...@@ -273,4 +273,4 @@ int main(int argc, char ** argv) ...@@ -273,4 +273,4 @@ int main(int argc, char ** argv)
} }
return 0; return 0;
} }
\ No newline at end of file
This diff is collapsed.
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
......
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
......
#include <stdio.h>
#include "inmost.h" #include "inmost.h"
#include <stdio.h>
using namespace INMOST; using namespace INMOST;
...@@ -10,7 +10,7 @@ int main(int argc, char ** argv) ...@@ -10,7 +10,7 @@ int main(int argc, char ** argv)
{ {
if( argc < 2 ) if( argc < 2 )
{ {
printf("Usage: %s input_mesh [rotation_angle=0 degrees] [output_mesh]\n",argv[0]); printf("Usage: %s input_mesh [rotation_angle=0 degrees] [refine_boundary=1] [output_mesh]\n",argv[0]);
return -1; return -1;
} }
...@@ -19,7 +19,9 @@ int main(int argc, char ** argv) ...@@ -19,7 +19,9 @@ int main(int argc, char ** argv)