source: src/datacreator.cpp@ 6d858c

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 6d858c was 36166d, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Removed left over parts from old memory-tracker

  • Property mode set to 100755
File size: 35.9 KB
RevLine 
[14de469]1/** \file datacreator.cpp
2 *
[6ac7ee]3 * Declarations of assisting functions in creating data and plot files.
4 *
[14de469]5 */
6
7//============================ INCLUDES ===========================
8
[112b09]9#include "Helpers/MemDebug.hpp"
10
[14de469]11#include "datacreator.hpp"
[f66195]12#include "helpers.hpp"
13#include "parser.hpp"
[36166d]14#include "verbose.hpp"
15
16#include <iomanip>
[14de469]17
18//=========================== FUNCTIONS============================
19
20/** Opens a file with \a *filename in \a *dir.
21 * \param output file handle on return
22 * \param *dir directory
23 * \param *filename name of file
24 * \return true if file has been opened
25 */
26bool OpenOutputFile(ofstream &output, const char *dir, const char *filename)
27{
[042f82]28 stringstream name;
29 name << dir << "/" << filename;
30 output.open(name.str().c_str(), ios::out);
31 if (output == NULL) {
[a67d19]32 DoLog(0) && (Log() << Verbose(0) << "Unable to open " << name.str() << " for writing, is directory correct?" << endl);
[042f82]33 return false;
34 }
35 return true;
[6ac7ee]36};
[14de469]37
[19f3d6]38/** Opens a file for appending with \a *filename in \a *dir.
39 * \param output file handle on return
40 * \param *dir directory
41 * \param *filename name of file
42 * \return true if file has been opened
43 */
44bool AppendOutputFile(ofstream &output, const char *dir, const char *filename)
45{
[042f82]46 stringstream name;
47 name << dir << "/" << filename;
48 output.open(name.str().c_str(), ios::app);
49 if (output == NULL) {
[a67d19]50 DoLog(0) && (Log() << Verbose(0) << "Unable to open " << name.str() << " for writing, is directory correct?" << endl);
[042f82]51 return false;
52 }
53 return true;
[6ac7ee]54};
[19f3d6]55
[14de469]56/** Plots an energy vs. order.
[390248]57 * \param &Fragments EnergyMatrix class containing matrix values
[f66195]58 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[14de469]59 * \param *prefix prefix in filename (without ending)
60 * \param *msg message to be place in first line as a comment
61 * \return true if file was written successfully
62 */
[f66195]63bool CreateDataEnergyOrder(class EnergyMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[14de469]64{
[042f82]65 stringstream filename;
66 ofstream output;
67
68 filename << prefix << ".dat";
69 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]70 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]71 output << "# " << msg << ", created on " << datum;
[b12a35]72 output << "#Order\tFrag.No.\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[f66195]73 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
74 for(int i=KeySets.FragmentsPerOrder[BondOrder];i--;) {
75 for(int j=Fragments.RowCounter[ KeySets.OrderSet[BondOrder][i] ];j--;)
76 for(int k=Fragments.ColumnCounter[ KeySets.OrderSet[BondOrder][i] ];k--;)
77 Fragments.Matrix[Fragments.MatrixCounter][j][k] += Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][k];
[042f82]78 }
[f66195]79 output << BondOrder+1 << "\t" << KeySets.FragmentsPerOrder[BondOrder];
[f731ae]80 for (int l=0;l<Fragments.ColumnCounter[Fragments.MatrixCounter];l++)
[042f82]81 output << scientific << "\t" << Fragments.Matrix[Fragments.MatrixCounter][ Fragments.RowCounter[Fragments.MatrixCounter]-1 ][l];
82 output << endl;
83 }
84 output.close();
85 return true;
[390248]86};
87
88/** Plots an energy error vs. order.
89 * \param &Energy EnergyMatrix class containing reference values (in MatrixCounter matrix)
90 * \param &Fragments EnergyMatrix class containing matrix values
[f66195]91 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[390248]92 * \param *prefix prefix in filename (without ending)
93 * \param *msg message to be place in first line as a comment
94 * \return true if file was written successfully
95 */
[f66195]96bool CreateDataDeltaEnergyOrder(class EnergyMatrix &Energy, class EnergyMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[390248]97{
[042f82]98 stringstream filename;
99 ofstream output;
100
101 filename << prefix << ".dat";
102 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]103 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]104 output << "# " << msg << ", created on " << datum;
[b12a35]105 output << "#Order\tFrag.No.\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[042f82]106 Fragments.SetLastMatrix(Energy.Matrix[Energy.MatrixCounter],0);
[f66195]107 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
108 for(int i=KeySets.FragmentsPerOrder[BondOrder];i--;) {
109 for(int j=Fragments.RowCounter[ KeySets.OrderSet[BondOrder][i] ];j--;)
110 for(int k=Fragments.ColumnCounter[ KeySets.OrderSet[BondOrder][i] ];k--;)
111 Fragments.Matrix[Fragments.MatrixCounter][j][k] -= Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][k];
[042f82]112 }
[f66195]113 output << BondOrder+1 << "\t" << KeySets.FragmentsPerOrder[BondOrder];
[f731ae]114 for (int l=0;l<Fragments.ColumnCounter[Energy.MatrixCounter];l++)
[042f82]115 if (fabs(Energy.Matrix[Energy.MatrixCounter][ Energy.RowCounter[Energy.MatrixCounter]-1 ][l]) < MYEPSILON)
116 output << scientific << "\t" << Fragments.Matrix[Fragments.MatrixCounter][ Fragments.RowCounter[Fragments.MatrixCounter]-1 ][l];
117 else
118 output << scientific << "\t" << (Fragments.Matrix[Fragments.MatrixCounter][ Fragments.RowCounter[Fragments.MatrixCounter]-1 ][l] / Energy.Matrix[Energy.MatrixCounter][ Energy.RowCounter[Energy.MatrixCounter]-1 ][l]);
119 output << endl;
120 }
121 output.close();
122 return true;
[14de469]123};
124
125/** Plot forces vs. order.
[390248]126 * \param &Fragments ForceMatrix class containing matrix values
[f66195]127 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[390248]128 * \param *prefix prefix in filename (without ending)
129 * \param *msg message to be place in first line as a comment
130 * \param *datum current date and time
131 * \return true if file was written successfully
[14de469]132 */
[f66195]133bool CreateDataForcesOrder(class ForceMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix,const char *msg, const char *datum, void (*CreateForce)(class MatrixContainer &, int))
[14de469]134{
[042f82]135 stringstream filename;
136 ofstream output;
137
138 filename << prefix << ".dat";
139 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]140 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]141 output << "# " << msg << ", created on " << datum;
[b12a35]142 output << "# Order\tFrag.No.\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[042f82]143 Fragments.SetLastMatrix(0.,0);
[f66195]144 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
145 Fragments.SumSubForces(Fragments, KeySets, BondOrder, 1.);
146 output << BondOrder+1 << "\t" << KeySets.FragmentsPerOrder[BondOrder];
[042f82]147 CreateForce(Fragments, Fragments.MatrixCounter);
[f731ae]148 for (int l=0;l<Fragments.ColumnCounter[Fragments.MatrixCounter];l++)
[042f82]149 output << scientific << "\t" << Fragments.Matrix[Fragments.MatrixCounter][ Fragments.RowCounter[Fragments.MatrixCounter] ][l];
150 output << endl;
151 }
152 output.close();
153 return true;
[390248]154};
155
156/** Plot forces error vs. order.
157 * \param &Force ForceMatrix containing reference values (in MatrixCounter matrix)
158 * \param &Fragments ForceMatrix class containing matrix values
[f66195]159 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[390248]160 * \param *prefix prefix in filename (without ending)
161 * \param *msg message to be place in first line as a comment
162 * \param *datum current date and time
163 * \return true if file was written successfully
164 */
[f66195]165bool CreateDataDeltaForcesOrder(class ForceMatrix &Force, class ForceMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum, void (*CreateForce)(class MatrixContainer &, int))
[390248]166{
[042f82]167 stringstream filename;
168 ofstream output;
169
170 filename << prefix << ".dat";
171 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]172 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]173 output << "# " << msg << ", created on " << datum;
[b12a35]174 output << "# Order\tFrag.No.\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[042f82]175 Fragments.SetLastMatrix(Force.Matrix[Force.MatrixCounter],0);
[f66195]176 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
177 Fragments.SumSubForces(Fragments, KeySets, BondOrder, -1.);
178 output << BondOrder+1 << "\t" << KeySets.FragmentsPerOrder[BondOrder];
[042f82]179 CreateForce(Fragments, Fragments.MatrixCounter);
[f731ae]180 for (int l=0;l<Fragments.ColumnCounter[Fragments.MatrixCounter];l++)
[042f82]181 output << scientific << "\t" << Fragments.Matrix[Fragments.MatrixCounter][ Fragments.RowCounter[Fragments.MatrixCounter] ][l];
182 output << endl;
183 }
184 output.close();
185 return true;
[390248]186};
187
188/** Plot forces error vs. vs atom vs. order.
189 * \param &Force ForceMatrix containing reference values (in MatrixCounter matrix)
190 * \param &Fragments ForceMatrix class containing matrix values
[f66195]191 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[390248]192 * \param *prefix prefix in filename (without ending)
193 * \param *msg message to be place in first line as a comment
194 * \param *datum current date and time
195 * \return true if file was written successfully
196 */
[f66195]197bool CreateDataDeltaForcesOrderPerAtom(class ForceMatrix &Force, class ForceMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[390248]198{
[042f82]199 stringstream filename;
200 ofstream output;
201 double norm = 0.;
202
203 filename << prefix << ".dat";
204 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]205 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]206 output << "# " << msg << ", created on " << datum;
[b12a35]207 output << "# AtomNo\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[042f82]208 Fragments.SetLastMatrix(Force.Matrix[Force.MatrixCounter], 0);
[f66195]209 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[e138de]210 //Log() << Verbose(0) << "Current order is " << BondOrder << "." << endl;
[f66195]211 Fragments.SumSubForces(Fragments, KeySets, BondOrder, -1.);
[042f82]212 // errors per atom
213 output << endl << "#Order\t" << BondOrder+1 << endl;
214 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
215 output << Fragments.Indices[Fragments.MatrixCounter][j] << "\t";
[f731ae]216 for (int l=0;l<Fragments.ColumnCounter[ Fragments.MatrixCounter ];l++) {
[042f82]217 if (((l+1) % 3) == 0) {
218 norm = 0.;
219 for (int m=0;m<NDIM;m++)
220 norm += Force.Matrix[Force.MatrixCounter][ j ][l+m]*Force.Matrix[Force.MatrixCounter][ j ][l+m];
221 norm = sqrt(norm);
[437922]222 }
[042f82]223// if (norm < MYEPSILON)
224 output << scientific << Fragments.Matrix[Fragments.MatrixCounter][ j ][l] << "\t";
225// else
226// output << scientific << (Fragments.Matrix[Fragments.MatrixCounter][ j ][l] / norm) << "\t";
227 }
228 output << endl;
229 }
230 output << endl;
231 }
232 output.close();
233 return true;
[390248]234};
235
236/** Plot forces error vs. vs atom vs. order.
237 * \param &Fragments ForceMatrix class containing matrix values
[f66195]238 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[390248]239 * \param *prefix prefix in filename (without ending)
240 * \param *msg message to be place in first line as a comment
241 * \param *datum current date and time
242 * \return true if file was written successfully
243 */
[f66195]244bool CreateDataForcesOrderPerAtom(class ForceMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[390248]245{
[042f82]246 stringstream filename;
247 ofstream output;
248
249 filename << prefix << ".dat";
250 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]251 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]252 output << "# " << msg << ", created on " << datum;
[b12a35]253 output << "# AtomNo\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
[f66195]254 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[e138de]255 //Log() << Verbose(0) << "Current order is " << BondOrder << "." << endl;
[f66195]256 Fragments.SumSubForces(Fragments, KeySets, BondOrder, 1.);
[042f82]257 // errors per atom
258 output << endl << "#Order\t" << BondOrder+1 << endl;
259 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
260 output << Fragments.Indices[Fragments.MatrixCounter][j] << "\t";
[f731ae]261 for (int l=0;l<Fragments.ColumnCounter[ Fragments.MatrixCounter ];l++)
[390248]262 output << scientific << Fragments.Matrix[Fragments.MatrixCounter][ j ][l] << "\t";
263 output << endl;
[14de469]264 }
265 output << endl;
266 }
267 output.close();
268 return true;
269};
270
[b12a35]271
272/** Plot hessian error vs. vs atom vs. order.
273 * \param &Hessian HessianMatrix containing reference values (in MatrixCounter matrix)
274 * \param &Fragments HessianMatrix class containing matrix values
[f66195]275 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[b12a35]276 * \param *prefix prefix in filename (without ending)
277 * \param *msg message to be place in first line as a comment
278 * \param *datum current date and time
279 * \return true if file was written successfully
280 */
[f66195]281bool CreateDataDeltaHessianOrderPerAtom(class HessianMatrix &Hessian, class HessianMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[b12a35]282{
283 stringstream filename;
284 ofstream output;
285
286 filename << prefix << ".dat";
287 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]288 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[b12a35]289 output << "# " << msg << ", created on " << datum;
290 output << "# AtomNo\t" << Fragments.Header[Fragments.MatrixCounter] << endl;
291 Fragments.SetLastMatrix(Hessian.Matrix[Hessian.MatrixCounter], 0);
[f66195]292 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[e138de]293 //Log() << Verbose(0) << "Current order is " << BondOrder << "." << endl;
[f66195]294 Fragments.SumSubHessians(Fragments, KeySets, BondOrder, -1.);
[b12a35]295 // errors per atom
296 output << endl << "#Order\t" << BondOrder+1 << endl;
297 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
298 output << Fragments.Indices[Fragments.MatrixCounter][j] << "\t";
299 for (int l=0;l<Fragments.ColumnCounter[ Fragments.MatrixCounter ];l++) {
300 output << scientific << Fragments.Matrix[Fragments.MatrixCounter][ j ][l] << "\t";
301 }
302 output << endl;
303 }
304 output << endl;
305 }
306 output.close();
307 return true;
308};
[05d2b2]309
310/** Plot hessian error vs. vs atom vs. order in the frobenius norm.
311 * \param &Hessian HessianMatrix containing reference values (in MatrixCounter matrix)
312 * \param &Fragments HessianMatrix class containing matrix values
[f66195]313 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[05d2b2]314 * \param *prefix prefix in filename (without ending)
315 * \param *msg message to be place in first line as a comment
316 * \param *datum current date and time
317 * \return true if file was written successfully
318 */
[f66195]319bool CreateDataDeltaFrobeniusOrderPerAtom(class HessianMatrix &Hessian, class HessianMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[05d2b2]320{
321 stringstream filename;
322 ofstream output;
323 double norm = 0;
324 double tmp;
325
326 filename << prefix << ".dat";
327 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]328 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[05d2b2]329 output << "# " << msg << ", created on " << datum;
330 output << "# AtomNo\t";
331 Fragments.SetLastMatrix(Hessian.Matrix[Hessian.MatrixCounter], 0);
[f66195]332 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[05d2b2]333 output << "Order" << BondOrder+1 << "\t";
334 }
335 output << endl;
336 output << Fragments.RowCounter[ Fragments.MatrixCounter ] << "\t";
[f66195]337 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[e138de]338 //Log() << Verbose(0) << "Current order is " << BondOrder << "." << endl;
[f66195]339 Fragments.SumSubHessians(Fragments, KeySets, BondOrder, -1.);
[05d2b2]340 // frobenius norm of errors per atom
341 norm = 0.;
342 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
343 for (int l=0;l<Fragments.ColumnCounter[ Fragments.MatrixCounter ];l++) {
[ce5ac3]344 tmp = Fragments.Matrix[Fragments.MatrixCounter][ j ][l];
345 norm += tmp*tmp;
[05d2b2]346 }
347 }
348 output << scientific << sqrt(norm)/(Fragments.RowCounter[ Fragments.MatrixCounter ]*Fragments.ColumnCounter[ Fragments.MatrixCounter] ) << "\t";
349 }
350 output << endl;
351 output.close();
352 return true;
353};
[b12a35]354
355/** Plot hessian error vs. vs atom vs. order.
356 * \param &Fragments HessianMatrix class containing matrix values
[f66195]357 * \param KeySets KeySetContainer class holding bond KeySetContainer::Order
[b12a35]358 * \param *prefix prefix in filename (without ending)
359 * \param *msg message to be place in first line as a comment
360 * \param *datum current date and time
361 * \return true if file was written successfully
362 */
[f66195]363bool CreateDataHessianOrderPerAtom(class HessianMatrix &Fragments, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum)
[b12a35]364{
365 stringstream filename;
366 ofstream output;
367
368 filename << prefix << ".dat";
369 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]370 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[b12a35]371 output << "# " << msg << ", created on " << datum;
372 output << "# AtomNo\t" << Fragments.Header[ Fragments.MatrixCounter ] << endl;
373 Fragments.SetLastMatrix(0., 0);
[f66195]374 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[e138de]375 //Log() << Verbose(0) << "Current order is " << BondOrder << "." << endl;
[f66195]376 Fragments.SumSubHessians(Fragments, KeySets, BondOrder, 1.);
[b12a35]377 // errors per atom
378 output << endl << "#Order\t" << BondOrder+1 << endl;
379 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
380 output << Fragments.Indices[Fragments.MatrixCounter][j] << "\t";
381 for (int l=0;l<Fragments.ColumnCounter[ Fragments.MatrixCounter ];l++)
[042f82]382 output << scientific << Fragments.Matrix[Fragments.MatrixCounter][ j ][l] << "\t";
383 output << endl;
384 }
385 output << endl;
386 }
387 output.close();
388 return true;
[14de469]389};
390
391/** Plot matrix vs. fragment.
392 */
[f66195]393bool CreateDataFragment(class MatrixContainer &Fragment, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum, void (*CreateFragment)(class MatrixContainer &, int))
[14de469]394{
[042f82]395 stringstream filename;
396 ofstream output;
397
398 filename << prefix << ".dat";
399 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]400 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]401 output << "# " << msg << ", created on " << datum << endl;
[b12a35]402 output << "#Order\tFrag.No.\t" << Fragment.Header[ Fragment.MatrixCounter ] << endl;
[f66195]403 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
404 for(int i=0;i<KeySets.FragmentsPerOrder[BondOrder];i++) {
405 output << BondOrder+1 << "\t" << KeySets.OrderSet[BondOrder][i]+1;
406 CreateFragment(Fragment, KeySets.OrderSet[BondOrder][i]);
407 for (int l=0;l<Fragment.ColumnCounter[ KeySets.OrderSet[BondOrder][i] ];l++)
408 output << scientific << "\t" << Fragment.Matrix[ KeySets.OrderSet[BondOrder][i] ][ Fragment.RowCounter[ KeySets.OrderSet[BondOrder][i] ] ][l];
[042f82]409 output << endl;
410 }
411 }
412 output.close();
413 return true;
[14de469]414};
415
416/** Copies fragment energy values into last matrix of \a Matrix with greatest total energy.
417 * \param &Matrix MatrixContainer with all fragment energy values
[f66195]418 * \param &KeySets KeySetsContainer with associations of each fragment to a bond order
[14de469]419 * \param BondOrder current bond order
[6ac7ee]420 */
[f66195]421void CreateMaxFragmentOrder(class MatrixContainer &Fragments, class KeySetsContainer &KeySets, int BondOrder)
[14de469]422{
[042f82]423 for(int j=Fragments.RowCounter[ Fragments.MatrixCounter ];j--;) {
[f66195]424 for(int i=KeySets.FragmentsPerOrder[BondOrder];i--;) {
425 if (fabs(Fragments.Matrix[ Fragments.MatrixCounter ][j][1]) < fabs(Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][1])) {
[f731ae]426 for (int k=Fragments.ColumnCounter[ Fragments.MatrixCounter ];k--;)
[f66195]427 Fragments.Matrix[ Fragments.MatrixCounter ][j][k] = Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][k];
[042f82]428 }
429 }
430 }
[14de469]431};
432
433/** Copies fragment energy values into last matrix of \a Matrix with smallest total energy.
434 * \param &Matrix MatrixContainer with all fragment energy values
[f66195]435 * \param &KeySets KeySetsContainer with associations of each fragment to a bond order
[14de469]436 * \param BondOrder current bond order
[6ac7ee]437 */
[f66195]438void CreateMinFragmentOrder(class MatrixContainer &Fragments, class KeySetsContainer &KeySets, int BondOrder)
[14de469]439{
[042f82]440 for(int j=0;j<Fragments.RowCounter[ Fragments.MatrixCounter ];j++) {
441 int i=0;
442 do { // first get a minimum value unequal to 0
[f731ae]443 for (int k=Fragments.ColumnCounter[ Fragments.MatrixCounter ];k--;)
[f66195]444 Fragments.Matrix[ Fragments.MatrixCounter ][j][k] = Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][k];
[042f82]445 i++;
[f66195]446 } while ((fabs(Fragments.Matrix[ Fragments.MatrixCounter ][j][1]) < MYEPSILON) && (i<KeySets.FragmentsPerOrder[BondOrder]));
447 for(;i<KeySets.FragmentsPerOrder[BondOrder];i++) { // then find lowest
448 if (fabs(Fragments.Matrix[ Fragments.MatrixCounter ][j][1]) > fabs(Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][1])) {
[f731ae]449 for (int k=Fragments.ColumnCounter[ Fragments.MatrixCounter ];k--;)
[f66195]450 Fragments.Matrix[ Fragments.MatrixCounter ][j][k] = Fragments.Matrix[ KeySets.OrderSet[BondOrder][i] ][j][k];
[042f82]451 }
452 }
453 }
[14de469]454};
455
456/** Plot matrix vs. fragment.
457 */
[f66195]458bool CreateDataFragmentOrder(class MatrixContainer &Fragment, class KeySetsContainer &KeySets, const char *dir, const char *prefix, const char *msg, const char *datum, void (*CreateFragmentOrder)(class MatrixContainer &, class KeySetsContainer &, int))
[14de469]459{
[042f82]460 stringstream filename;
461 ofstream output;
462
463 filename << prefix << ".dat";
464 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
[a67d19]465 DoLog(0) && (Log() << Verbose(0) << msg << endl);
[042f82]466 output << "# " << msg << ", created on " << datum;
[b12a35]467 output << "#Order\tFrag.No.\t" << Fragment.Header[ Fragment.MatrixCounter ] << endl;
[042f82]468 // max
[f66195]469 for (int BondOrder=0;BondOrder<KeySets.Order;BondOrder++) {
[042f82]470 Fragment.SetLastMatrix(0.,0);
[f66195]471 CreateFragmentOrder(Fragment, KeySets, BondOrder);
472 output << BondOrder+1 << "\t" << KeySets.FragmentsPerOrder[BondOrder];
[f731ae]473 for (int l=0;l<Fragment.ColumnCounter[ Fragment.MatrixCounter ];l++)
[042f82]474 output << scientific << "\t" << Fragment.Matrix[ Fragment.MatrixCounter ][ Fragment.RowCounter[ Fragment.MatrixCounter ]-1 ][l];
475 output << endl;
476 }
477 output.close();
478 return true;
[14de469]479};
480
481/** Takes last but one row and copies into final row.
482 * \param Energy MatrixContainer with matrix values
483 * \param MatrixNumber the index for the ForceMatrix::matrix array
484 */
485void CreateEnergy(class MatrixContainer &Energy, int MatrixNumber)
486{
[f731ae]487 for(int k=0;k<Energy.ColumnCounter[MatrixNumber];k++)
[042f82]488 Energy.Matrix[MatrixNumber][ Energy.RowCounter[MatrixNumber] ] [k] = Energy.Matrix[MatrixNumber][ Energy.RowCounter[MatrixNumber]-1 ] [k];
[14de469]489};
490
491/** Scans forces for the minimum in magnitude.
492 * Results are stored in the matrix ForceMatrix::MatrixCounter of \a Force.
493 * \param Force ForceMatrix class containing matrix values
494 * \param MatrixNumber the index for the ForceMatrix::matrix array
495 */
496void CreateMinimumForce(class MatrixContainer &Force, int MatrixNumber)
497{
[f731ae]498 for (int l=Force.ColumnCounter[MatrixNumber];l--;)
[042f82]499 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l] = 0.;
[f731ae]500 for (int l=5;l<Force.ColumnCounter[MatrixNumber];l+=3) {
[042f82]501 double stored = 0;
502 int k=0;
503 do {
504 for (int m=NDIM;m--;) {
505 stored += Force.Matrix[MatrixNumber][ k ][l+m]
506 * Force.Matrix[MatrixNumber][ k ][l+m];
507 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l+m] = Force.Matrix[MatrixNumber][ k ][l+m];
508 }
509 k++;
510 } while ((fabs(stored) < MYEPSILON) && (k<Force.RowCounter[MatrixNumber]));
511 for (;k<Force.RowCounter[MatrixNumber];k++) {
512 double tmp = 0;
513 for (int m=NDIM;m--;)
514 tmp += Force.Matrix[MatrixNumber][ k ][l+m]
515 * Force.Matrix[MatrixNumber][ k ][l+m];
516 if ((fabs(tmp) > MYEPSILON) && (tmp < stored)) { // current force is greater than stored
517 for (int m=NDIM;m--;)
518 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l+m] = Force.Matrix[MatrixNumber][ k ][l+m];
519 stored = tmp;
520 }
521 }
522 }
[14de469]523};
524
525/** Scans forces for the mean in magnitude.
526 * Results are stored in the matrix ForceMatrix::MatrixCounter of \a Force.
527 * \param Force ForceMatrix class containing matrix values
[042f82]528 * \param MatrixNumber the index for the ForceMatrix::matrix array
[14de469]529 */
530void CreateMeanForce(class MatrixContainer &Force, int MatrixNumber)
531{
[042f82]532 int divisor = 0;
[f731ae]533 for (int l=Force.ColumnCounter[MatrixNumber];l--;)
[042f82]534 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l] = 0.;
[f731ae]535 for (int l=5;l<Force.ColumnCounter[MatrixNumber];l+=3) {
[042f82]536 double tmp = 0;
537 for (int k=Force.RowCounter[MatrixNumber];k--;) {
538 double norm = 0.;
539 for (int m=NDIM;m--;)
540 norm += Force.Matrix[MatrixNumber][ k ][l+m]
541 * Force.Matrix[MatrixNumber][ k ][l+m];
542 tmp += sqrt(norm);
543 if (fabs(norm) > MYEPSILON) divisor++;
544 }
545 tmp /= (double)divisor;
546 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l] = tmp;
547 }
[14de469]548};
549
550/** Scans forces for the maximum in magnitude.
551 * Results are stored in the matrix ForceMatrix::MatrixCounter of \a Force.
552 * \param Force ForceMatrix class containing matrix values
553 * \param MatrixNumber the index for the ForceMatrix::matrix array
554 */
555void CreateMaximumForce(class MatrixContainer &Force, int MatrixNumber)
556{
[f731ae]557 for (int l=5;l<Force.ColumnCounter[MatrixNumber];l+=3) {
[042f82]558 double stored = 0;
559 for (int k=Force.RowCounter[MatrixNumber];k--;) {
560 double tmp = 0;
561 for (int m=NDIM;m--;)
562 tmp += Force.Matrix[MatrixNumber][ k ][l+m]
563 * Force.Matrix[MatrixNumber][ k ][l+m];
564 if (tmp > stored) { // current force is greater than stored
565 for (int m=NDIM;m--;)
566 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l+m] = Force.Matrix[MatrixNumber][ k ][l+m];
567 stored = tmp;
568 }
569 }
570 }
[14de469]571};
572
[390248]573/** Leaves the Force.Matrix as it is.
574 * \param Force ForceMatrix class containing matrix values
575 * \param MatrixNumber the index for the ForceMatrix::matrix array
576*/
577void CreateSameForce(class MatrixContainer &Force, int MatrixNumber)
578{
[042f82]579 // does nothing
[390248]580};
581
[14de469]582/** Adds vectorwise all forces.
583 * Results are stored in the matrix ForceMatrix::MatrixCounter of \a Force.
584 * \param Force ForceMatrix class containing matrix values
585 * \param MatrixNumber the index for the ForceMatrix::matrix array
586 */
587void CreateVectorSumForce(class MatrixContainer &Force, int MatrixNumber)
588{
[f731ae]589 for (int l=Force.ColumnCounter[MatrixNumber];l--;)
[042f82]590 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l] = 0.;
[f731ae]591 for (int l=0;l<Force.ColumnCounter[MatrixNumber];l++) {
[042f82]592 for (int k=Force.RowCounter[MatrixNumber];k--;)
593 Force.Matrix[MatrixNumber][ Force.RowCounter[MatrixNumber] ][l] += Force.Matrix[MatrixNumber][k][l];
594 }
[14de469]595};
596
597/** Writes the standard pyxplot header info.
598 * \param keycolumns number of columns of the key
599 * \param *key position of key
600 * \param *logscale axis for logscale
[6ac7ee]601 * \param *extraline extra set lines if desired
[14de469]602 * \param mxtics small tics at ...
603 * \param xtics large tics at ...
[6ac7ee]604 * \param *xlabel label for x axis
[14de469]605 * \param *ylabel label for y axis
[6ac7ee]606 */
[14de469]607void CreatePlotHeader(ofstream &output, const char *prefix, const int keycolumns, const char *key, const char *logscale, const char *extraline, const int mxtics, const int xtics, const char *xlabel, const char *ylabel)
608{
[042f82]609 //output << "#!/home/heber/build/pyxplot/pyxplot" << endl << endl;
610 output << "reset" << endl;
611 output << "set keycolumns "<< keycolumns << endl;
612 output << "set key " << key << endl;
613 output << "set mxtics "<< mxtics << endl;
614 output << "set xtics "<< xtics << endl;
615 if (logscale != NULL)
616 output << "set logscale " << logscale << endl;
617 if (extraline != NULL)
618 output << extraline << endl;
619 output << "set xlabel '" << xlabel << "'" << endl;
620 output << "set ylabel '" << ylabel << "'" << endl;
621 output << "set terminal eps color" << endl;
622 output << "set output '"<< prefix << ".eps'" << endl;
[14de469]623};
624
625/** Creates the pyxplotfile for energy data.
626 * \param Matrix MatrixContainer with matrix values
[f66195]627 * \param KeySets contains bond order
[14de469]628 * \param *dir directory
629 * \param *prefix prefix for all filenames (without ending)
630 * \param keycolumns number of columns of the key
631 * \param *key position of key
632 * \param logscale axis for logscale
633 * \param mxtics small tics at ...
634 * \param xtics large tics at ...
[6ac7ee]635 * \param xlabel label for x axis
[14de469]636 * \param xlabel label for x axis
637 * \param *xrange xrange
638 * \param *yrange yrange
639 * \param *xargument number of column to plot against (x axis)
640 * \param uses using string for plot command
641 * \param (*CreatePlotLines) function reference that writes a single plot line
642 * \return true if file was written successfully
[6ac7ee]643 */
[f66195]644bool CreatePlotOrder(class MatrixContainer &Matrix, const class KeySetsContainer &KeySets, const char *dir, const char *prefix, const int keycolumns, const char *key, const char *logscale, const char *extraline, const int mxtics, const int xtics, const char *xlabel, const char *ylabel, const char *xrange, const char *yrange, const char *xargument, const char *uses, void (*CreatePlotLines)(ofstream &, class MatrixContainer &, const char *, const char *, const char *))
[14de469]645{
[042f82]646 stringstream filename;
647 ofstream output;
648
649 filename << prefix << ".pyx";
650 if (!OpenOutputFile(output, dir, filename.str().c_str())) return false;
651 CreatePlotHeader(output, prefix, keycolumns, key, logscale, extraline, mxtics, xtics, xlabel, ylabel);
652 output << "plot " << xrange << " " << yrange << " \\" << endl;
653 CreatePlotLines(output, Matrix, prefix, xargument, uses);
654 output.close();
655 return true;
[14de469]656};
657
658/** Writes plot lines for absolute energies.
659 * \param output file handler
660 * \param Energy MatrixContainer with matrix values
661 * \param *prefix prefix of data file
662 * \param *xargument number of column to plot against (x axis)
663 * \param *uses uses command
664 */
665void AbsEnergyPlotLine(ofstream &output, class MatrixContainer &Energy, const char *prefix, const char *xargument, const char *uses)
666{
[b12a35]667 stringstream line(Energy.Header[ Energy.MatrixCounter ]);
[042f82]668 string token;
669
670 getline(line, token, '\t');
[f731ae]671 for (int i=2; i<= Energy.ColumnCounter[Energy.MatrixCounter];i++) {
[042f82]672 getline(line, token, '\t');
673 while (token[0] == ' ') // remove leading white spaces
674 token.erase(0,1);
675 output << "'" << prefix << ".dat' title '" << token << "' using " << xargument << ":(abs($" << i+2 << ")) " << uses;
[f731ae]676 if (i != (Energy.ColumnCounter[Energy.MatrixCounter]))
[042f82]677 output << ", \\";
678 output << endl;
679 }
[14de469]680};
681
682/** Writes plot lines for energies.
683 * \param output file handler
684 * \param Energy MatrixContainer with matrix values
685 * \param *prefix prefix of data file
686 * \param *xargument number of column to plot against (x axis)
687 * \param *uses uses command
688 */
689void EnergyPlotLine(ofstream &output, class MatrixContainer &Energy, const char *prefix, const char *xargument, const char *uses)
690{
[b12a35]691 stringstream line(Energy.Header[Energy.MatrixCounter]);
[042f82]692 string token;
693
694 getline(line, token, '\t');
[f731ae]695 for (int i=1; i<= Energy.ColumnCounter[Energy.MatrixCounter];i++) {
[042f82]696 getline(line, token, '\t');
697 while (token[0] == ' ') // remove leading white spaces
698 token.erase(0,1);
699 output << "'" << prefix << ".dat' title '" << token << "' using " << xargument << ":" << i+2 << " " << uses;
[f731ae]700 if (i != (Energy.ColumnCounter[Energy.MatrixCounter]))
[042f82]701 output << ", \\";
702 output << endl;
703 }
[14de469]704};
705
706/** Writes plot lines for absolute force magnitudes.
707 * \param output file handler
708 * \param Force MatrixContainer with matrix values
709 * \param *prefix prefix of data file
710 * \param *xargument number of column to plot against (x axis)
711 * \param *uses uses command
712 */
713void ForceMagnitudePlotLine(ofstream &output, class MatrixContainer &Force, const char *prefix, const char *xargument, const char *uses)
714{
[b12a35]715 stringstream line(Force.Header[Force.MatrixCounter]);
[042f82]716 string token;
717
718 getline(line, token, '\t');
719 getline(line, token, '\t');
720 getline(line, token, '\t');
721 getline(line, token, '\t');
722 getline(line, token, '\t');
[f731ae]723 for (int i=7; i< Force.ColumnCounter[Force.MatrixCounter];i+=NDIM) {
[042f82]724 getline(line, token, '\t');
725 while (token[0] == ' ') // remove leading white spaces
726 token.erase(0,1);
727 token.erase(token.length(), 1); // kill residual index char (the '0')
728 output << "'" << prefix << ".dat' title '" << token << "' using " << xargument << ":(sqrt($" << i+1 << "*$" << i+1 << "+$" << i+2 << "*$" << i+2 << "+$" << i+3 << "*$" << i+3 << ")) " << uses;
[f731ae]729 if (i != (Force.ColumnCounter[Force.MatrixCounter]-1))
[042f82]730 output << ", \\";
731 output << endl;
732 getline(line, token, '\t');
733 getline(line, token, '\t');
734 }
[14de469]735};
736
737/** Writes plot lines for first component of force vector.
738 * \param output file handler
739 * \param Force MatrixContainer with matrix values
740 * \param *prefix prefix of data file
741 * \param *xargument number of column to plot against (x axis)
742 * \param *uses uses command
743 */
744void AbsFirstForceValuePlotLine(ofstream &output, class MatrixContainer &Force, const char *prefix, const char *xargument, const char *uses)
745{
[b12a35]746 stringstream line(Force.Header[Force.MatrixCounter]);
[042f82]747 string token;
748
749 getline(line, token, '\t');
750 getline(line, token, '\t');
751 getline(line, token, '\t');
752 getline(line, token, '\t');
753 getline(line, token, '\t');
[f731ae]754 for (int i=7; i< Force.ColumnCounter[Force.MatrixCounter];i+=NDIM) {
[042f82]755 getline(line, token, '\t');
756 while (token[0] == ' ') // remove leading white spaces
757 token.erase(0,1);
758 token.erase(token.length(), 1); // kill residual index char (the '0')
759 output << "'" << prefix << ".dat' title '" << token << "' using " << xargument << ":(abs($" << i+1 << ")) " << uses;
[f731ae]760 if (i != (Force.ColumnCounter[Force.MatrixCounter]-1))
[042f82]761 output << ", \\";
762 output << endl;
763 getline(line, token, '\t');
764 getline(line, token, '\t');
765 }
[14de469]766};
767
768/** Writes plot lines for force vector as boxes with a fillcolor.
769 * \param output file handler
770 * \param Force MatrixContainer with matrix values
771 * \param *prefix prefix of data file
772 * \param *xargument number of column to plot against (x axis)
773 * \param *uses uses command
774 */
775void BoxesForcePlotLine(ofstream &output, class MatrixContainer &Force, const char *prefix, const char *xargument, const char *uses)
776{
[b12a35]777 stringstream line(Force.Header[Force.MatrixCounter]);
[1f2217]778 const char *fillcolor[5] = {"black", "red", "blue", "green", "cyan"};
[042f82]779 string token;
780
781 getline(line, token, '\t');
782 getline(line, token, '\t');
783 getline(line, token, '\t');
784 getline(line, token, '\t');
785 getline(line, token, '\t');
[f731ae]786 for (int i=7; i< Force.ColumnCounter[Force.MatrixCounter];i+=NDIM) {
[042f82]787 getline(line, token, '\t');
788 while (token[0] == ' ') // remove leading white spaces
789 token.erase(0,1);
790 token.erase(token.length(), 1); // kill residual index char (the '0')
791 output << "'" << prefix << ".dat' title '" << token << "' using ($" << xargument << "+" << fixed << setprecision(1) << (double)((i-7)/3)*0.2 << "):(sqrt($" << i+1 << "*$" << i+1 << "+$" << i+2 << "*$" << i+2 << "+$" << i+3 << "*$" << i+3 << ")) " << uses << " " << fillcolor[(i-7)/3];
[f731ae]792 if (i != (Force.ColumnCounter[Force.MatrixCounter]-1))
[042f82]793 output << ", \\";
794 output << endl;
795 getline(line, token, '\t');
796 getline(line, token, '\t');
797 }
[14de469]798};
799
800/** Writes plot lines for first force vector component as boxes with a fillcolor.
801 * \param output file handler
802 * \param Force MatrixContainer with matrix values
803 * \param *prefix prefix of data file
804 * \param *xargument number of column to plot against (x axis)
805 * \param *uses uses command
806 */
807void BoxesFirstForceValuePlotLine(ofstream &output, class MatrixContainer &Force, const char *prefix, const char *xargument, const char *uses)
808{
[b12a35]809 stringstream line(Force.Header[Force.MatrixCounter]);
[1f2217]810 const char *fillcolor[5] = {"black", "red", "blue", "green", "cyan"};
[042f82]811 string token;
812
813 getline(line, token, '\t');
814 getline(line, token, '\t');
815 getline(line, token, '\t');
816 getline(line, token, '\t');
817 getline(line, token, '\t');
[f731ae]818 for (int i=7; i< Force.ColumnCounter[Force.MatrixCounter];i+=NDIM) {
[042f82]819 getline(line, token, '\t');
820 while (token[0] == ' ') // remove leading white spaces
821 token.erase(0,1);
822 token.erase(token.length(), 1); // kill residual index char (the '0')
823 output << "'" << prefix << ".dat' title '" << token << "' using ($" << xargument << "+" << fixed << setprecision(1) << (double)((i-7)/3)*0.2 << "):" << i+1 << " " << uses << " " << fillcolor[(i-7)/3];
[f731ae]824 if (i != (Force.ColumnCounter[Force.MatrixCounter]-1))
[042f82]825 output << ", \\";
826 output << endl;
827 getline(line, token, '\t');
828 getline(line, token, '\t');
829 }
[14de469]830};
Note: See TracBrowser for help on using the repository browser.