Commit 446c073f authored by Kirill Terekhov's avatar Kirill Terekhov

Sync changes

Fixed bug in auto-differentiation that would calculate incorrect weights
for derivatives in ad_val().
Adapted several geometrical and adjacency retrieval algorithms to handle
broken conformity of the grid during modification, more attention to the
problem is needed.
Added visual studio debugger helpers.
Fixed several issues with openmp support.
Added openmp parallelization of BiCGStab(L) solver.
Fixed issues that files overwritten with MPI_File* functionality may
contain previous information.
Fixed a bug in OctreeCutcell, added another example for it.
Fixed a bug in collective operations in mesh class.
parent 04aaeaca
...@@ -2,3 +2,4 @@ ...@@ -2,3 +2,4 @@
tests/solver_test001/matrices tests/solver_test001/matrices
solver_mtiluc2.cpp solver_mtiluc2.cpp
solver_mtiluc2.hpp solver_mtiluc2.hpp
solver_mtilu2.hpp
...@@ -52,6 +52,13 @@ else() ...@@ -52,6 +52,13 @@ else()
set(HAVE_SOLVER_MPTILUC2 FALSE) set(HAVE_SOLVER_MPTILUC2 FALSE)
endif() endif()
if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/solver_mtilu2.hpp" )
add_definitions(-DHAVE_SOLVER_MPTILU2)
set(HAVE_SOLVER_MPTILU2 TRUE)
list(APPEND SOURCE solver_mtilu2.hpp)
else()
set(HAVE_SOLVER_MPTILU2 FALSE)
endif()
add_library(inmost STATIC ${SOURCE} ${HEADER}) add_library(inmost STATIC ${SOURCE} ${HEADER})
......
;------------------------------------------------------------------------------
; INMOST::interval
;------------------------------------------------------------------------------
INMOST::interval<*,*>{
preview (
#(
"[",
$e.end_index-$e.beg_index,
"](",
#array(
expr: $e.array[$i+$e.beg_index],
size: $e.end_index-$e.beg_index
),
")"
)
)
children (
#(
#([size] : $e.end_index-$e.beg_index),
#([first] : $e.beg_index),
#([last] : $e.end_index),
#array(
expr: $e.array[$i+$e.beg_index],
size: $e.end_index-$e.beg_index
)
)
)
}
;------------------------------------------------------------------------------
; INMOST::dynarray
;------------------------------------------------------------------------------
INMOST::dynarray<*,*>{
preview (
#(
"[",
$e.pend-$e.pbegin,
"](",
#array(
expr: $e.pbegin[$i],
size: $e.pend-$e.pbegin
),
")"
)
)
children (
#(
#([size] : $e.pend-$e.pbegin),
#([capacity] : $e.preserved-$e.pbegin),
#array(
expr: $e.pbegin[$i],
size: $e.pend-$e.pbegin
)
)
)
}
;------------------------------------------------------------------------------
; INMOST::shell
;------------------------------------------------------------------------------
INMOST::shell<*>{
preview (
#(
"[",
*$e.m_size,
"](",
#array(
expr: (*$e.m_arr)[$i],
size: *$e.m_size
),
")"
)
)
children (
#(
#([size] : *$e.m_size),
#array(
expr: (*$e.m_arr)[$i],
size: *$e.m_size
)
)
)
}
Copy and paste contents of autoexp.dat into
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Packages\Debugger\autoexp.dat
or the directry where Visual Studio was installed.
In future capabilities will grove.
Tested with Visual studio 2010.
This folder contains helper instructions to facilitate representation of custom classes in debuggers.
\ No newline at end of file
...@@ -294,7 +294,7 @@ namespace INMOST ...@@ -294,7 +294,7 @@ namespace INMOST
return ret*var.coef; return ret*var.coef;
case AD_VAL: case AD_VAL:
lval = DerivativePrecompute(*var.left, e, values, user_data); lval = DerivativePrecompute(*var.left, e, values, user_data);
rval = Evaluate(*var.left,e,user_data); rval = Evaluate(*var.right,e,user_data);
values.push_back(rval); values.push_back(rval);
return lval*var.coef; return lval*var.coef;
} }
......
...@@ -341,17 +341,22 @@ namespace INMOST ...@@ -341,17 +341,22 @@ namespace INMOST
{ {
adj_type const & lc = m->LowConn(GetHandle()); adj_type const & lc = m->LowConn(GetHandle());
aret.reserve(lc.size()); aret.reserve(lc.size());
if( lc.size() < 1 ) return aret;
HandleType q = lc[0]; //edge 0 HandleType q = lc[0]; //edge 0
adj_type const & qlc = m->LowConn(q); adj_type const & qlc = m->LowConn(q);
aret.push_back(qlc[0]); //node 0 if( qlc.size() > 0 ) aret.push_back(qlc[0]); //node 0
aret.push_back(qlc[1]); //node 1 if( qlc.size() > 1 ) aret.push_back(qlc[1]); //node 1
if( lc.size() < 2 ) return aret;
HandleType r = lc[1]; //edge 1 HandleType r = lc[1]; //edge 1
adj_type const & rlc = m->LowConn(r); adj_type const & rlc = m->LowConn(r);
if( aret.data()[0] == rlc[0] || aret.data()[0] == rlc[1] ) if( aret.size() == 2 && rlc.size() == 2 )
{ {
HandleType temp = aret.data()[0]; if( aret.data()[0] == rlc[0] || aret.data()[0] == rlc[1] )
aret.data()[0] = aret.data()[1]; {
aret.data()[1] = temp; HandleType temp = aret.data()[0];
aret.data()[0] = aret.data()[1];
aret.data()[1] = temp;
}
} }
adj_type::size_type it = 1, iend = lc.size()-1; adj_type::size_type it = 1, iend = lc.size()-1;
while(it < iend) //loop over edges while(it < iend) //loop over edges
...@@ -392,22 +397,27 @@ namespace INMOST ...@@ -392,22 +397,27 @@ namespace INMOST
adj_type const & lc = m->LowConn(GetHandle()); adj_type const & lc = m->LowConn(GetHandle());
aret.reserve(lc.size()); aret.reserve(lc.size());
i = m->getNext(lc.data(),static_cast<enumerator>(lc.size()),i,hm); i = m->getNext(lc.data(),static_cast<enumerator>(lc.size()),i,hm);
if( i == lc.size() ) return aret;
HandleType q = lc[i]; //edge 0 HandleType q = lc[i]; //edge 0
adj_type const & qlc = m->LowConn(q); adj_type const & qlc = m->LowConn(q);
k = m->getNext(qlc.data(),static_cast<enumerator>(qlc.size()),k,hm); k = m->getNext(qlc.data(),static_cast<enumerator>(qlc.size()),k,hm);
aret.push_back(qlc[k]); //node 0 if( k != qlc.size() ) aret.push_back(qlc[k]); //node 0
k = m->getNext(qlc.data(),static_cast<enumerator>(qlc.size()),k,hm); k = m->getNext(qlc.data(),static_cast<enumerator>(qlc.size()),k,hm);
aret.push_back(qlc[k]); //node 1 if( k != qlc.size() ) aret.push_back(qlc[k]); //node 1
i = m->getNext(lc.data(),static_cast<enumerator>(lc.size()),i,hm); i = m->getNext(lc.data(),static_cast<enumerator>(lc.size()),i,hm);
if( i == lc.size() ) return aret;
HandleType r = lc[i]; //edge 1 HandleType r = lc[i]; //edge 1
adj_type const & rlc = m->LowConn(r); adj_type const & rlc = m->LowConn(r);
k1 = m->getNext(rlc.data(),static_cast<enumerator>(rlc.size()),k1,hm); k1 = m->getNext(rlc.data(),static_cast<enumerator>(rlc.size()),k1,hm);
k2 = m->getNext(rlc.data(),static_cast<enumerator>(rlc.size()),k1,hm); k2 = m->getNext(rlc.data(),static_cast<enumerator>(rlc.size()),k1,hm);
if( aret.data()[0] == rlc[k1] || aret.data()[0] == rlc[k2] ) if( k1 != rlc.size() && k2 != rlc.size() && aret.size() == 2 )
{ {
HandleType temp = aret.data()[0]; if( aret.data()[0] == rlc[k1] || aret.data()[0] == rlc[k2] )
aret.data()[0] = aret.data()[1]; {
aret.data()[1] = temp; HandleType temp = aret.data()[0];
aret.data()[0] = aret.data()[1];
aret.data()[1] = temp;
}
} }
adj_type::size_type it = 1, iend = lc.size()-1; adj_type::size_type it = 1, iend = lc.size()-1;
while(it < iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges while(it < iend) if( !m->GetMarker(lc[it],hm) ) //loop over edges
......
...@@ -30,6 +30,7 @@ int main(int argc, char ** argv) ...@@ -30,6 +30,7 @@ int main(int argc, char ** argv)
case 6: type = Solver::Trilinos_ML; break; case 6: type = Solver::Trilinos_ML; break;
case 7: type = Solver::ANI; break; case 7: type = Solver::ANI; break;
case 8: type = Solver::INNER_MPTILUC; break; case 8: type = Solver::INNER_MPTILUC; break;
case 9: type = Solver::INNER_MPTILU2; break;
} }
Solver::Initialize(&argc,&argv,argc > 4 ? argv[4] : NULL); // Initialize the linear solver in accordance with args Solver::Initialize(&argc,&argv,argc > 4 ? argv[4] : NULL); // Initialize the linear solver in accordance with args
{ {
...@@ -81,8 +82,8 @@ int main(int argc, char ** argv) ...@@ -81,8 +82,8 @@ int main(int argc, char ** argv)
s.SetParameterEnum("adapt_ddpq_tolerance",0); s.SetParameterEnum("adapt_ddpq_tolerance",0);
s.SetParameterReal("drop_tolerance",1.0e-2); s.SetParameterReal("drop_tolerance",1.0e-2);
s.SetParameterReal("reuse_tolerance",1.0e-3); s.SetParameterReal("reuse_tolerance",1.0e-4);
s.SetParameterReal("ddpq_tolerance",0.4); s.SetParameterReal("ddpq_tolerance",0.0);
s.SetParameterEnum("condition_estimation",1); s.SetParameterEnum("condition_estimation",1);
......
...@@ -46,5 +46,5 @@ else(OPENGL_FOUND) ...@@ -46,5 +46,5 @@ else(OPENGL_FOUND)
message("OpenGL not found") message("OpenGL not found")
endif(OPENGL_FOUND) endif(OPENGL_FOUND)
install(TARGETS OctreeCutcell EXPORT inmost-targets RUNTIME DESTINATION bin) install(TARGETS OctreeCutcell EXPORT inmost-targets RUNTIME DESTINATION bin/OctreeCutcell)
install(DIRECTORY Obj EXPORT inmost-targets DESTINATION bin/OctreeCutcell)
...@@ -843,22 +843,33 @@ int main(int argc, char ** argv) ...@@ -843,22 +843,33 @@ int main(int argc, char ** argv)
InitObj(); InitObj();
{ {
std::vector<std::string> layers; std::vector<std::string> layers;
for(int i = 0; i < 3; i++) for(int i = 1; i <= 3; i++)
{ {
std::stringstream name; std::stringstream name;
name << "Obj/bound" << i+1 << ".obj"; //name << "Obj/bound" << i+1 << ".obj";
name << "oil_obj2/proj/layer" << i << ".obj";
layers.push_back(name.str()); layers.push_back(name.str());
} }
make_proj.ReadLayers(layers); make_proj.ReadLayers(layers);
} }
{ {
std::vector<std::string> layers; std::vector<std::string> layers;
for(int i = 0; i < 6; i++) for(int i = 1; i <= 19; i++)
{
std::stringstream name;
//name << "Obj/rt" << i+1 << ".obj";
name << "oil_obj2/mat/layer" << i << ".obj";
layers.push_back(name.str());
}
/*
for(int i = 1; i <= 3; i++)
{ {
std::stringstream name; std::stringstream name;
name << "Obj/rt" << i+1 << ".obj"; //name << "Obj/rt" << i+1 << ".obj";
name << "oil_obj2/proj/layer" << i << ".obj";
layers.push_back(name.str()); layers.push_back(name.str());
} }
*/
get_type.ReadLayers(layers); get_type.ReadLayers(layers);
} }
......
...@@ -22,7 +22,7 @@ char * nowarn2 = NULL; ...@@ -22,7 +22,7 @@ char * nowarn2 = NULL;
//~ extern Projection make_proj; //~ extern Projection make_proj;
bool swapyz = false; bool swapyz = true;
struct ObjVertex struct ObjVertex
...@@ -544,6 +544,7 @@ int ReadObj(char * file) ...@@ -544,6 +544,7 @@ int ReadObj(char * file)
} }
n = objs + cur; n = objs + cur;
strcpy(n->filename,file); strcpy(n->filename,file);
printf("Reading %s\n",file);
// nowarn2 = getcwd(n->filedir,1024); // nowarn2 = getcwd(n->filedir,1024);
FILE * f = fopen(file,"r"); FILE * f = fopen(file,"r");
if( f == NULL ) if( f == NULL )
...@@ -805,6 +806,14 @@ int ReadObj(char * file) ...@@ -805,6 +806,14 @@ int ReadObj(char * file)
&n->verts[n->nverts].v[0], &n->verts[n->nverts].v[0],
&n->verts[n->nverts].v[1], &n->verts[n->nverts].v[1],
&n->verts[n->nverts].v[2]); &n->verts[n->nverts].v[2]);
n->verts[n->nverts].v[0] /= 99.5;
n->verts[n->nverts].v[1] /= 32;
n->verts[n->nverts].v[2] /= 99.5;
n->verts[n->nverts].v[0] -= 0.001;
n->verts[n->nverts].v[1] -= 0.001;
n->verts[n->nverts].v[2] += 0.001;
n->verts[n->nverts].v[2] *= -1;
if( swapyz ) if( swapyz )
{ {
double temp = n->verts[n->nverts].v[1]; double temp = n->verts[n->nverts].v[1];
...@@ -955,6 +964,7 @@ int ReadObj(char * file) ...@@ -955,6 +964,7 @@ int ReadObj(char * file)
if( n->minz > n->pols[i].minz ) if( n->minz > n->pols[i].minz )
n->minz = n->pols[i].minz; n->minz = n->pols[i].minz;
} }
printf("bounds: %g:%g %g:%g %g:%g\n",n->minx,n->maxx,n->miny,n->maxy,n->minz,n->maxz);
kdtree_build(n->t,n->p,n->npols,0); kdtree_build(n->t,n->p,n->npols,0);
/* /*
double center[3]; double center[3];
......
...@@ -156,22 +156,22 @@ int cellAround(struct grid * g, int m, int side, int neighbours[1<<(DIM-1)]) ...@@ -156,22 +156,22 @@ int cellAround(struct grid * g, int m, int side, int neighbours[1<<(DIM-1)])
void vertDestroyINMOST(struct grid *g, int m) void vertDestroyINMOST(struct grid *g, int m)
{ {
//printf("%s\n",__FUNCTION__); //printf("%s\n",__FUNCTION__);
if( g->verts[m].mv.isValid() && !g->verts[m].mv.Hidden() ) if( g->verts[m].mv != InvalidHandle() )
{ {
g->verts[m].mv->Delete(); g->mesh->Delete(g->verts[m].mv);
} }
} }
void vertCreateINMOST(struct grid * g, int m) void vertCreateINMOST(struct grid * g, int m)
{ {
Storage::real xyz[3]; Storage::real xyz[3];
if( g->verts[m].mv.isValid() ) return; if( g->verts[m].mv != InvalidHandle() ) return;
vertGetCoord(g,m,xyz); vertGetCoord(g,m,xyz);
g->transformation(xyz); g->transformation(xyz);
g->verts[m].mv = g->mesh->CreateNode(xyz); g->verts[m].mv = g->mesh->CreateNode(xyz)->GetHandle();
g->verts[m].mv->SetMarker(g->octree_node); g->mesh->SetMarker(g->verts[m].mv,g->octree_node);
//g->verts[m].mv->Integer(g->new_marker) = 1; //g->verts[m].mv->Integer(g->new_marker) = 1;
g->vert_to_INMOST(g,m,g->verts[m].mv); g->vert_to_INMOST(g,m,Node(g->mesh,g->verts[m].mv));
} }
void cellDestroyINMOST(struct grid * g, int m) void cellDestroyINMOST(struct grid * g, int m)
...@@ -299,13 +299,13 @@ void cellGetFaceVerts(struct grid * g, int m, int side, int * nverts, Node verts ...@@ -299,13 +299,13 @@ void cellGetFaceVerts(struct grid * g, int m, int side, int * nverts, Node verts
for(i = 0; i < 4; i++) for(i = 0; i < 4; i++)
{ {
mid[1+faces[0]] = false; mid[1+faces[0]] = false;
verts[(faces[1+faces[0]] = (*nverts))] = g->verts[g->cells[m].vertexes[nvf[side][i]]].mv; verts[(faces[1+faces[0]] = (*nverts))] = Node(g->mesh,g->verts[g->cells[m].vertexes[nvf[side][i]]].mv);
faces[0]++; faces[0]++;
(*nverts)++; (*nverts)++;
if( (middle = vertGetMiddle(g,m,side,i)) != -1) if( (middle = vertGetMiddle(g,m,side,i)) != -1)
{ {
mid[1+faces[0]] = true; mid[1+faces[0]] = true;
verts[(faces[1+faces[0]] = (*nverts))] = g->verts[middle].mv; verts[(faces[1+faces[0]] = (*nverts))] = Node(g->mesh,g->verts[middle].mv);
faces[0]++; faces[0]++;
(*nverts)++; (*nverts)++;
...@@ -1204,7 +1204,7 @@ void cellCreateINMOST(struct grid * g, int m, bool print = false) ...@@ -1204,7 +1204,7 @@ void cellCreateINMOST(struct grid * g, int m, bool print = false)
centers[0] = matcenter(mat0d,&n0->Coords()[0],0); centers[0] = matcenter(mat0d,&n0->Coords()[0],0);
centers[1] = matcenter(mat2d,&n2->Coords()[0],0); centers[1] = matcenter(mat2d,&n2->Coords()[0],0);
//make iterations to find correct position of the node //make iterations to find correct position of the node
int max = 8; int max = 16;
int found = 0; int found = 0;
for(int q = 0; q < max; q++) for(int q = 0; q < max; q++)
{ {
...@@ -2357,7 +2357,7 @@ exit_work: if( !success ) ...@@ -2357,7 +2357,7 @@ exit_work: if( !success )
for(j = 0; j < l; j++) if( node_in_face[j].isValid() ) for(j = 0; j < l; j++) if( node_in_face[j].isValid() )
centers.push_back(matcenter(node_in_face[j]->IntegerArray(g->materials),&node_in_face[j]->Coords()[0])); centers.push_back(matcenter(node_in_face[j]->IntegerArray(g->materials),&node_in_face[j]->Coords()[0]));
//make iterations to find correct position of the node //make iterations to find correct position of the node
int max = 4; int max = 8;
Storage::real div = 1.0/centers.size(); Storage::real div = 1.0/centers.size();
for(int q = 0; q < max; q++) for(int q = 0; q < max; q++)
{ {
...@@ -3485,7 +3485,7 @@ void cellInit(struct grid * g, int cell, int parent) ...@@ -3485,7 +3485,7 @@ void cellInit(struct grid * g, int cell, int parent)
void vertInit(struct grid * g, int vert) void vertInit(struct grid * g, int vert)
{ {
int i; int i;
g->verts[vert].mv = InvalidNode(); g->verts[vert].mv = InvalidHandle();
for(i = 0; i < 1<<DIM; i++) for(i = 0; i < 1<<DIM; i++)
g->verts[vert].env[i] = -1; g->verts[vert].env[i] = -1;
} }
......
...@@ -65,7 +65,7 @@ struct vert ...@@ -65,7 +65,7 @@ struct vert
{ {
int busy; int busy;
int env[1<<DIM]; int env[1<<DIM];
Node mv; HandleType mv;
}; };
struct grid struct grid
......
#
## Alias OBJ Material File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited
newmtl FrontColor
Ka 0.000000 0.000000 0.000000
Kd 1.000000 1.000000 1.000000
Ks 0.330000 0.330000 0.330000
# Alias OBJ Model File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited
# File units = meters
mtllib layer1.mtl
g Mesh1 Model
usemtl FrontColor
v 78.8347 0 -100
vt 3937.01 425.543
vn 0.990556 -0.137107 -0
v 79.3635 3.82023 -0
vt 0 577.38
v 78.8347 0 -0
vt 0 425.543
f 1/1/1 2/2/1 3/3/1
v 79.3635 3.82023 -100
vt 3937.01 577.38
f 2/2/1 1/1/1 4/4/1
v 81.1997 2.90078 -100
vt -3937.01 -2807.37
vn -0.382771 -0.923843 -0
vt 0 -2726.52
vn -0.447738 -0.894165 -0
vt -3937.01 -2726.52
f 5/5/2 2/6/3 4/7/3
v 81.1997 2.90078 -0
vt 0 -2807.37
f 2/6/3 5/5/2 6/8/2
v 83.1481 2.25216 -100
vt -3937.01 -3077.97
vn -0.247321 -0.968934 -0
vt 0 -2997.12
vt -3937.01 -2997.12
f 7/9/4 6/10/2 5/11/2
v 83.1481 2.25216 -0
vt 0 -3077.97
f 6/10/2 7/9/4 8/12/4
v 85.1691 1.8876 -100
vt -3937.01 -3286.66
vn -0.10683 -0.994277 -0
vt 0 -3205.81
vt -3937.01 -3205.81
f 9/13/5 8/14/4 7/15/4
v 85.1691 1.8876 -0
vt 0 -3286.66
f 8/14/4 9/13/5 10/16/5
v 87.2213 1.81452 -100
vt -3937.01 -3429.19
vn 0.0358378 -0.999358 -0
vt 0 -3348.34
vt -3937.01 -3348.34
f 11/17/6 10/18/5 9/19/5
v 87.2213 1.81452 -0
vt 0 -3429.19
f 10/18/5 11/17/6 12/20/6
v 89.2631 2.03441 -100
vt 3937.01 3502.67
vn 0.177775 -0.984071 -0
vt 0 3421.82
vt 3937.01 3421.82
f 13/21/7 12/22/6 11/23/6
v 89.2631 2.03441 -0
vt 0 3502.67
f 12/22/6 13/21/7 14/24/7
v 91.2527 2.5428 -100
vt 3937.01 3505.58
vn 0.31609 -0.948729 -0
vt 0 3424.73
vt 3937.01 3424.73
f 15/25/8 14/26/7 13/27/7
v 91.2527 2.5428 -0
vt 0 3505.58
f 14/26/7 15/25/8 16/28/8
v 93.1497 3.32932 -100
vt 3937.01 3437.87
vn 0.447962 -0.894053 -0
vt 0 3357.02
vt 3937.01 3357.02
f 17/29/9 16/30/8 15/31/8
v 93.1497 3.32932 -0
vt 0 3437.87
f 16/30/8 17/29/9 18/32/9
v 94.9153 4.37794 -100
vt 3937.01 3300.92
vn 0.570705 -0.821155 -0
vt 0 3220.07
vt 3937.01 3220.07
f 19/33/10 18/34/9 17/35/9
v 94.9153 4.37794 -0
vt 0 3300.92
f 18/34/9 19/33/10 20/36/10
v 96.5136 5.66729 -100
vt 3937.01 3097.53
vn 0.681817 -0.731522 -0
vt 0 3016.68
vt 3937.01 3016.68
f 21/37/11 20/38/10 19/39/10
v 96.5136 5.66729 -0
vt 0 3097.53
f 20/38/10 21/37/11 22/40/11
vt 3937.01 2750.98
v 97.9121 7.17109 -0
vt 0 2831.83
vn 0.779034 -0.626982 -0
vt 0 2750.98
f 21/41/11 23/42/12 22/43/11
v 97.9121 7.17109 -100
vt 3937.01 2831.83
f 23/42/12 21/41/11 24/44/12
vt 3937.01 2428.39
v 99.0822 8.85871 -0
vt 0 2509.24
vn 0.860374 -0.509663 -0
vt 0 2428.39
f 24/45/12 25/46/13 23/47/12
v 99.0822 8.85871 -100
vt 3937.01 2509.24
f 25/46/13 24/45/12 26/48/13
vt 3937.01 2055.49
v 100 10.6957 -0
vt 0 2136.34
vn 0.894559 -0.44695 -0
vt 0 2055.49
f 26/49/13 27/50/14 25/51/13
v 100 10.6957 -100
vt 3937.01 2136.34
f 27/50/14 26/49/13 28/52/14
#
## Alias OBJ Material File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited
newmtl FrontColor
Ka 0.000000 0.000000 0.000000
Kd 1.000000 1.000000 1.000000
Ks 0.330000 0.330000 0.330000
# Alias OBJ Model File
# Exported from SketchUp, (c) 2000-2012 Trimble Navigation Limited
# File units = meters