1 /* *****************************************************************
2 MESQUITE -- The Mesh Quality Improvement Toolkit
3
4 Copyright 2004 Sandia Corporation and Argonne National
5 Laboratory. Under the terms of Contract DE-AC04-94AL85000
6 with Sandia Corporation, the U.S. Government retains certain
7 rights in this software.
8
9 This library is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version.
13
14 This library is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
19 You should have received a copy of the GNU Lesser General Public License
20 (lgpl.txt) along with this library; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 diachin2@llnl.gov, djmelan@sandia.gov, mbrewer@sandia.gov,
24 pknupp@sandia.gov, tleurent@mcs.anl.gov, tmunson@mcs.anl.gov
25
26 ***************************************************************** */
27 // -*- Mode : c++; tab-width: 3; c-tab-always-indent: t; indent-tabs-mode: nil; c-basic-offset: 3 -*-
28
29 /*! \file InstructionQueue.cpp
30
31 Member functions of the MBMesquite::InstructionQueue class
32
33 \author Thomas Leurent
34 \date 2002-05-01
35 */
36
37 #include <string>
38 #include <list>
39 #include <memory>
40
41 #include "InstructionQueue.hpp"
42 #include "MsqInterrupt.hpp"
43 #include "QualityImprover.hpp"
44 #include "QualityAssessor.hpp"
45 #include "TargetWriter.hpp"
46 #include "VertexSlaver.hpp"
47 #include "TagVertexMesh.hpp"
48 #include "MsqError.hpp"
49 #include "MsqDebug.hpp"
50 #include "MsqFPE.hpp"
51 #include "ParallelMeshInterface.hpp"
52
53 using namespace MBMesquite;
54
55
InstructionQueue()56 InstructionQueue::InstructionQueue() :
57 autoQualAssess(true),
58 vertexSlaverCount(0),
59 nbPreConditionners(0),
60 isMasterSet(false),
61 masterInstrIndex(0)
62 {
63 }
64
~InstructionQueue()65 InstructionQueue::~InstructionQueue() {}
66
add_target_calculator(TargetWriter * tc,MsqError &)67 void InstructionQueue::add_target_calculator( TargetWriter* tc, MsqError& )
68 {
69 instructions.push_back( tc );
70 }
71
add_vertex_slaver(VertexSlaver * vs,MsqError &)72 void InstructionQueue::add_vertex_slaver( VertexSlaver* vs, MsqError& )
73 {
74 instructions.push_front( vs );
75 if (isMasterSet)
76 ++masterInstrIndex;
77 ++vertexSlaverCount;
78 set_slaved_ho_node_mode( Settings::SLAVE_CALCULATED );
79 }
80
remove_vertex_slaver(VertexSlaver * vs,MsqError & err)81 void InstructionQueue::remove_vertex_slaver( VertexSlaver* vs, MsqError& err)
82 {
83 size_t idx = 0;
84 for (std::list<Instruction*>::iterator i = instructions.begin();
85 i != instructions.end(); ++i, ++idx) {
86 if (*i == vs) {
87 instructions.erase(i);
88 if (isMasterSet && masterInstrIndex > idx)
89 --masterInstrIndex;
90 if (--vertexSlaverCount == 0)
91 set_slaved_ho_node_mode( Settings::SLAVE_ALL );
92 return;
93 }
94 }
95
96 MSQ_SETERR(err)("Not found", MsqError::INVALID_ARG );
97 }
98
add_tag_vertex_mesh(TagVertexMesh * vs,MsqError &)99 void InstructionQueue::add_tag_vertex_mesh( TagVertexMesh* vs, MsqError& )
100 {
101 instructions.push_front( vs );
102 if (isMasterSet)
103 ++masterInstrIndex;
104 }
105
remove_tag_vertex_mesh(TagVertexMesh * vs,MsqError & err)106 void InstructionQueue::remove_tag_vertex_mesh( TagVertexMesh* vs, MsqError& err)
107 {
108 size_t idx = 0;
109 for (std::list<Instruction*>::iterator i = instructions.begin();
110 i != instructions.end(); ++i, ++idx) {
111 if (*i == vs) {
112 instructions.erase(i);
113 if (isMasterSet && masterInstrIndex > idx)
114 --masterInstrIndex;
115 return;
116 }
117 }
118
119 MSQ_SETERR(err)("Not found", MsqError::INVALID_ARG );
120 }
121
122 /*! \fn InstructionQueue::add_preconditioner(QualityImprover* instr, MsqError &err)
123 \brief adds a QualityImprover at the end of the instruction list
124
125 This function cannot be used once the set_master_quality_improver()
126 function has been used.
127
128 See also insert_preconditioner().
129 */
add_preconditioner(QualityImprover * instr,MsqError & err)130 void InstructionQueue::add_preconditioner(QualityImprover* instr,
131 MsqError &err)
132 {
133 if (isMasterSet) {
134 MSQ_SETERR(err)("Cannot add preconditioners once the master "
135 "QualityImprover has been set.", MsqError::INVALID_STATE);
136 return;
137 }
138
139 instructions.push_back(instr);
140 nbPreConditionners++;
141 }
142
143
144 /*! \fn InstructionQueue::remove_preconditioner(size_t index, MsqError &err)
145 \brief removes a QualityImprover* from the instruction queue
146
147 \param index is 0-based. An error is set if the index does not correspond
148 to a valid element in the queue.
149 */
remove_preconditioner(size_t index,MsqError & err)150 void InstructionQueue::remove_preconditioner(size_t index, MsqError &err)
151 {
152 // checks index is valid
153 if ( isMasterSet && index == masterInstrIndex ) {
154 MSQ_SETERR(err)("cannot remove master QualityImprover.", MsqError::INVALID_ARG);
155 return;
156 } else if (index >= instructions.size() ) {
157 MSQ_SETERR(err)("Index points beyond end of list.",MsqError::INVALID_ARG);
158 return;
159 }
160
161 // position the instruction iterator over the preconditioner to delete
162 std::list<Instruction*>::iterator pos;
163 pos = instructions.begin();
164 std::advance(pos, index);
165
166 if (!dynamic_cast<QualityImprover*>(*pos))
167 {
168 MSQ_SETERR(err)("Index does not point to a QualityImprover.",
169 MsqError::INVALID_ARG);
170 return;
171 }
172
173 std::string name = (*pos)->get_name();
174 instructions.erase(pos);
175 nbPreConditionners--;
176 }
177
178
179 /*! \fn InstructionQueue::insert_preconditioner(QualityImprover* instr, size_t index, MsqError &err)
180 \brief inserts a QualityImprover* into the instruction queue.
181
182 Pre-conditionners can only be inserted before the master QualityImprover.
183
184 \param index is 0-based. An error is set if the index does not correspond
185 to a valid position in the queue.
186 */
insert_preconditioner(QualityImprover * instr,size_t index,MsqError & err)187 void InstructionQueue::insert_preconditioner(QualityImprover* instr,
188 size_t index, MsqError &err)
189 {
190 // checks index is valid
191 if (isMasterSet==true && index > masterInstrIndex) {
192 MSQ_SETERR(err)("Cannot add a preconditioner after the master "
193 "QualityImprover.", MsqError::INVALID_STATE);
194 return;
195 }
196 if (index >= instructions.size() ) {
197 MSQ_SETERR(err)("index", MsqError::INVALID_ARG);
198 return;
199 }
200
201 // position the instruction iterator
202 std::list<Instruction*>::iterator pos;
203 pos = instructions.begin();
204 std::advance(pos, index);
205 // adds the preconditioner
206 instructions.insert(pos,instr);
207 nbPreConditionners++;
208 }
209
210
211 /*! \fn InstructionQueue::add_quality_assessor(QualityAssessor* instr, MsqError &err)
212 \brief adds a QualityAssessor to the instruction queue.
213
214 QualityAssessor pointers can be added at any time to the instruction queue.
215 */
add_quality_assessor(QualityAssessor * instr,MsqError &)216 void InstructionQueue::add_quality_assessor(QualityAssessor* instr,
217 MsqError &/*err*/)
218 {
219 instructions.push_back(instr);
220 }
221
222
223 /*! \fn InstructionQueue::remove_quality_assessor(size_t index, MsqError &err)
224 \brief removes a QualityAssessor* from the instruction queue
225
226 \param index is 0-based. An error is set if the index does not correspond
227 to a valid element in the queue.
228 */
remove_quality_assessor(size_t index,MsqError & err)229 void InstructionQueue::remove_quality_assessor(size_t index, MsqError &err)
230 {
231 // checks index is valid
232 if (index >= instructions.size() ) {
233 MSQ_SETERR(err)("index", MsqError::INVALID_ARG);
234 return;
235 }
236
237 // position the instruction iterator over the QualityAssessor to delete
238 std::list<Instruction*>::iterator pos;
239 pos = instructions.begin();
240 std::advance(pos, index);
241
242 if ( !dynamic_cast<QualityAssessor*>(*pos) )
243 {
244 MSQ_SETERR(err)("Index does not point to a QualityImprover.",
245 MsqError::INVALID_ARG);
246 return;
247 }
248
249 std::string name = (*pos)->get_name();
250 instructions.erase(pos);
251 }
252
253
254 /*! \fn InstructionQueue::insert_quality_assessor(QualityAssessor* instr, size_t index, MsqError &err)
255 \brief inserts a QualityAssessor* into the instruction queue.
256
257 QualityAssessors can be inserted at any position in the instruction queue.
258
259 \param index is 0-based. An error is set if the index is past the end of the queue.
260 */
insert_quality_assessor(QualityAssessor * instr,size_t index,MsqError & err)261 void InstructionQueue::insert_quality_assessor(QualityAssessor* instr,
262 size_t index, MsqError &err)
263 {
264 // checks index is valid
265 if (index > instructions.size()) {
266 MSQ_SETERR(err)("index points two positions beyond end of list.",
267 MsqError::INVALID_ARG);
268 return;
269 }
270
271 // position the instruction iterator
272 std::list<Instruction*>::iterator pos;
273 pos = instructions.begin();
274 std::advance(pos, index);
275 // adds the QualityAssessor
276 instructions.insert(pos,instr);
277 }
278
279
set_master_quality_improver(QualityImprover * instr,MsqError & err)280 void InstructionQueue::set_master_quality_improver(QualityImprover* instr,
281 MsqError &err)
282 {
283 if (isMasterSet) {
284 MSQ_DBGOUT(1) << "InstructionQueue::set_master_quality_improver():\n"
285 << "\tOverwriting previously specified master quality improver.\n";
286 // if master is already set, clears it and insert the new one at the same position.
287 std::list<Instruction*>::iterator master_pos;
288 master_pos = this->clear_master(err); MSQ_ERRRTN(err);
289 instructions.insert(master_pos, instr);
290 isMasterSet = true;
291 } else {
292 // if master is not set, add it at the end of the queue.
293 instructions.push_back(instr);
294 isMasterSet = true;
295 masterInstrIndex = instructions.size()-1;
296 }
297 }
298
299
run_common(MeshDomainAssoc * mesh_and_domain,ParallelMesh * pmesh,Settings * settings,MsqError & err)300 void InstructionQueue::run_common( MeshDomainAssoc* mesh_and_domain,
301 ParallelMesh* pmesh,
302 Settings* settings,
303 MsqError &err)
304 {
305 MSQ_DBGOUT(1) << version_string(false) << "\n";
306
307 if (nbPreConditionners != 0 && isMasterSet == false ) {
308 MSQ_SETERR(err)("no pre-conditionners allowed if master QualityImprover "
309 "is not set.", MsqError::INVALID_STATE);
310 return;
311 }
312
313 #ifdef ENABLE_INTERRUPT
314 // Register SIGINT handler
315 MsqInterrupt msq_interrupt;
316 #endif
317
318 Mesh* mesh = mesh_and_domain->get_mesh();
319 MeshDomain* domain = mesh_and_domain->get_domain();
320
321 // Generate SIGFPE on floating point errors
322 MsqFPE fpe_trap( settings->trap_floating_point_exception() );
323
324 std::list<Instruction*>::const_iterator instr;
325
326 // Initialize each instruction
327 for (instr = instructions.begin(); instr != instructions.end(); ++instr)
328 {
329 if (MsqInterrupt::interrupt())
330 {
331 MSQ_SETERR(err)(MsqError::INTERRUPTED);
332 return;
333 }
334
335 (*instr)->initialize_queue( mesh_and_domain, settings, err );
336 MSQ_ERRRTN(err);
337 }
338
339 // Run each instruction
340 for (instr = instructions.begin(); instr != instructions.end(); ++instr)
341 {
342 if (MsqInterrupt::interrupt())
343 {
344 MSQ_SETERR(err)(MsqError::INTERRUPTED);
345 return;
346 }
347
348 if (pmesh) {
349 assert(!mesh || pmesh == mesh);
350 (*instr)->loop_over_mesh( pmesh, domain, settings, err );
351 }
352 else {
353 (*instr)->loop_over_mesh( mesh_and_domain, settings, err );
354 }
355 MSQ_ERRRTN(err);
356 }
357 }
358
clear()359 void InstructionQueue::clear()
360 {
361 instructions.clear();
362 autoQualAssess = true;
363 isMasterSet = false;
364 masterInstrIndex = 0;
365 }
366
367
clear_master(MsqError & err)368 std::list<Instruction*>::iterator InstructionQueue::clear_master(MsqError &err)
369 {
370 std::list<Instruction*>::iterator instr_iter;
371 std::list<Instruction*>::iterator master_pos;
372
373 if (!isMasterSet) {
374 MSQ_SETERR(err)("No master quality improver to clear.", MsqError::INVALID_STATE);
375 return instr_iter;
376 }
377
378 // position the instruction iterator over the master quality improver
379 master_pos = instructions.begin();
380 std::advance(master_pos, masterInstrIndex);
381
382 // erases the master quality improver
383 instr_iter = instructions.erase(master_pos);
384 isMasterSet = false;
385
386 // returns the position where the Master was
387 return instr_iter;
388 }
389