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