31 const std::filesystem::path root(
argv[1]);
32 const auto folder = std::filesystem::temp_directory_path() /
33 (
"bicrystal-node-classification-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
34 const auto input = folder /
"inputFiles";
35 std::filesystem::create_directories(input);
36 std::filesystem::create_directories(folder /
"F");
37 std::filesystem::copy_file(root /
"Library/Materials/W.txt", input /
"W.txt");
39 std::filesystem::copy_file(root /
"Library/Meshes/bicrystal_48.msh", input /
"mesh.msh");
40 std::filesystem::copy_file(root /
"Library/DislocationDynamics/DD.txt", input /
"DD.txt");
41 std::filesystem::create_directories(folder /
"config");
42 const double length=3671.9477120460206;
44 std::ofstream
f(input /
"DefectiveCrystal.txt");
45 f <<
"physics=DislocationDynamics;\nuseFEM=0;\nNsteps=0;\nmaxResolveSteps=0;\ndtMax=1;\noutputFrequency=1;\noutputBinary=0;\nstartAtTimeStep=0;\nperiodicImageSize=0 0 0;\nEwaldLengthFactor=0;\n";
46 std::ofstream
p(input /
"polycrystal.txt");
47 p << std::setprecision(17) <<
"materialFile=W.txt;\nmeshFile=mesh.msh;\nabsoluteTemperature=300;\nC2G1=1 0 0 0 1 0 0 0 1;\n"
48 <<
"C2G2=0.8 0 0.6 0 1 0 -0.6 0 0.8;\nF=" << length <<
" 0 0 0 " << length <<
" 0 0 0 " << length
49 <<
";\nX0=0 0 0;\nperiodicFaceIDs=-1;\n";
53 const auto dd=input/
"DD.txt";
54 std::ifstream source(dd);
55 std::string contents((std::istreambuf_iterator<char>(source)),std::istreambuf_iterator<char>());
56 const auto location=contents.find(
"Lmax=100;");
57 require(location!=std::string::npos,
"Expected library remeshing default");
58 contents.replace(location,std::string(
"Lmax=100;").size(),
"Lmax=150;");
59 std::ofstream output(dd);
63 auto window=vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
64 window->SetReadyForRendering(
false);
65 auto renderer=vtkSmartPointer<vtkRenderer>::New();
66 window->AddRenderer(renderer);
68 for(
int frame : {430,500})
74 std::ifstream stream(root/
"tests/data"/(
"bicrystalBoundary"+std::to_string(frame)+
".txt"));
75 require(
bool(stream),
"Missing bicrystal fixture");
76 saved.readTxtStream(stream);
78 size_t internal=0,periodicGB=0,sameGrain=0,bulk=0,
corners=0,stale=0;
79 for(
const auto& entry : network.networkNodes())
81 const auto node=entry.second.lock();
82 bool internalFace=
false,crossGrainFace=
false,sameGrainFace=
false,external=
false;
83 for(
const auto* face : node->meshFaces())
85 if(face->regionIDs.first!=face->regionIDs.second)
92 const auto* twin=face->periodicFacePair.second;
95 crossGrainFace|=face->regionIDs.first!=twin->regionIDs.first;
96 sameGrainFace|=face->regionIDs.first==twin->regionIDs.first;
100 const bool gb=internalFace || crossGrainFace;
101 const int expected=gb?2:(external?1:0);
102 require(node->isGrainBoundaryNode()==gb,
"Wrong physical GB classification");
103 require(node->isOnInternalBoundary()==internalFace,
"Geometric internal-face classification changed");
104 require(node->isBoundaryNode()==external,
"Geometric external-face classification changed");
105 require(node->meshLocation()==expected,
"GB does not take priority at periodic boundary");
107 require(output.
meshLocation==expected,
"New output does not serialize updated classification");
108 internal+=internalFace;
109 periodicGB+=crossGrainFace;
110 sameGrain+=sameGrainFace && !gb;
111 bulk+=!gb && !external;
115 "Bicrystal fixture lacks required node categories");
117 size_t internalSegments=0,periodicSegments=0,boundarySegments=0;
118 for(
const auto& entry : network.networkLinks())
120 const auto link=entry.second.lock();
122 for(
const auto* face : link->meshFaces())
124 gb|=face->regionIDs.first!=face->regionIDs.second ||
125 (face->periodicFacePair.second && face->regionIDs!=face->periodicFacePair.second->regionIDs);
127 require(link->isGrainBoundarySegment()==gb,
"Wrong GB segment classification");
130 require(link->meshLocation()==2,
"GB segment has boundary-only output label");
132 if(!link->hasZeroBurgers())
134 internalSegments+=link->isOnInternalBoundary();
135 periodicSegments+=gb && !link->isOnInternalBoundary();
136 boundarySegments+=gb || link->isBoundarySegment();
139 require(internalSegments && periodicSegments,
"Fixture lacks both GB segment types");
141 const int actorCount=renderer->GetActors()->GetNumberOfItems();
144 auto* boundaryActor=vtkActor::SafeDownCast(renderer->GetActors()->GetItemAsObject(actorCount+1));
145 require(boundaryActor && boundaryActor->GetMapper(),
"Missing boundary segment actor");
146 auto* tube=vtkTubeFilter::SafeDownCast(boundaryActor->GetMapper()->GetInputAlgorithm());
147 auto* data=vtkPolyData::SafeDownCast(tube->GetInputDataObject(0,0));
148 require(data && data->GetNumberOfLines()==
static_cast<vtkIdType
>(boundarySegments),
"DDqt omitted GB segments");
149 auto* show=links.findChild<QCheckBox*>(
"showSegments");
150 require(
bool(show),
"Missing segment visibility control");
151 auto* opacity=links.findChild<QSlider*>(
"boundarySegmentOpacity");
152 require(opacity && opacity->value()==0 && !boundaryActor->GetVisibility(),
153 "Boundary segments should default to transparent");
154 opacity->setValue(50);
155 require(boundaryActor->GetVisibility() && std::abs(boundaryActor->GetProperty()->GetOpacity()-0.5)<1.e-12,
156 "Boundary opacity control did not update the actor");
157 show->setChecked(
false);
158 require(!boundaryActor->GetVisibility(),
"Segments control did not hide GB segments");
159 show->setChecked(
true);
160 require(boundaryActor->GetVisibility(),
"Segments control did not show GB segments");
163 auto* colors=actor.
nodePolyData->GetPointData()->GetScalars();
164 require(colors && colors->GetNumberOfTuples()==
static_cast<vtkIdType
>(saved.nodes().size()),
165 "Wrong color tuple count");
167 for(
const auto& savedNode : saved.nodes())
169 const auto node=network.networkNodes().at(savedNode.sID).lock();
170 const int location=node->meshLocation();
171 for(
int component=0;component<3;++component)
173 require(colors->GetComponent(
i,component)==actor.
nodeClr[location][component],
174 "DDqt uses stale serialized classification");
176 stale+=savedNode.meshLocation!=location;
179 require(stale>0,
"Fixture does not exercise legacy boundary labels");
183 for(
const auto& node : saved.nodes())
185 const int index=node.meshLocation>=0 && node.meshLocation<=2?node.meshLocation:3;
186 for(
int component=0;component<3;++component)
189 "Serialized-only node coloring changed");
193 std::cout<<
"Frame "<<frame<<
": internal GB "<<internal<<
", periodic GB "<<periodicGB
194 <<
", same-grain seam "<<sameGrain<<
", corners "<<
corners<<
", corrected labels "<<stale<<std::endl;
196 std::filesystem::remove_all(folder);
199 catch(
const std::exception& error)
201 std::cerr<<error.what()<<std::endl;