1 // TAB_MM_PRMFIT.CPP
2 
3 // Copyright (C) 1998 Tommi Hassinen.
4 
5 // This package is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 
10 // This package is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 
15 // You should have received a copy of the GNU General Public License
16 // along with this package; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 /*################################################################################################*/
20 
21 #include "libghemicalconfig2.h"
22 #include "tab_mm_prmfit.h"
23 
24 #include "typerule.h"
25 #include "utility.h"
26 
27 #include "local_i18n.h"
28 
29 #include <cstring>
30 #include <iomanip>
31 #include <fstream>
32 #include <sstream>
33 #include <algorithm>
34 using namespace std;
35 
36 /*################################################################################################*/
37 
prmfit_tables(const char * p1)38 prmfit_tables::prmfit_tables(const char * p1)
39 {
40 	path = new char[strlen(p1) + 1];
41 	strcpy(path, p1);
42 
43 	ifstream file;
44 	file.unsetf(ios::dec | ios::oct | ios::hex);
45 
46 	ostringstream fns;
47 	char buffer[1024];
48 
49 	ostream * ostr = NULL;		// do not print output.
50 //	ostream * ostr = & cout;	// print output to cout.
51 
52 /*##############################################*/
53 /*##############################################*/
54 
55 	fns.str("");	// blank the filename!
56 	fns << path << "/atomtypes.txt" << ends;
57 
58 	file.open(fns.str().c_str(), ios::in);
59 
60 	if (ostr != NULL) (* ostr) << _("reading file \"") << fns.str() << "\": ";
61 
62 	while (file.peek() != '#')		// #end
63 	{
64 		if (file.peek() == '0')		// 0x????
65 		{
66 			prmfit_at newat;
67 			file >> newat.atomtype[0];
68 			file >> newat.atomtype[1];
69 
70 			file >> newat.vdw_R >> newat.vdw_E;
71 			file >> newat.formal_charge;
72 			file >> newat.flags;
73 
74 			while (file.peek() != '(') file.get();
75 			newat.tr = new typerule(& file, ostr);
76 
77 			while (file.get() != '\"');
78 			file.getline(buffer, sizeof(buffer), '\"');
79 			newat.description = new char[strlen(buffer) + 1];
80 			strcpy(newat.description, buffer);
81 
82 			at2_vector.push_back(newat);
83 		}
84 
85 		file.getline(buffer, sizeof(buffer));
86 	}
87 
88 	file.close();
89 
90 	if (ostr != NULL) (* ostr) << _("found ") << at2_vector.size() << _(" atomtypes.") << endl;
91 
92 /*##############################################*/
93 /*##############################################*/
94 
95 	fns.str("");	// blank the filename!
96 	fns << path << "/parameters1.txt" << ends;
97 
98 	file.open(fns.str().c_str(), ios::in);
99 
100 	if (ostr != NULL) (* ostr) << _("reading file \"") << fns.str() << "\": ";
101 
102 	while (file.peek() != '#')		// #end
103 	{
104 		if (file.peek() == '0')		// 0x????
105 		{
106 			prmfit_bs tmp; char bt[16];
107 			file >> tmp.atmtp[0] >> tmp.atmtp[1] >> bt;
108 			file >> tmp.opt >> tmp.fc >> tmp.ci;
109 
110 			tmp.bndtp = bondtype(bt[0]);
111 			bs_vector.push_back(tmp);
112 		}
113 
114 		file.getline(buffer, sizeof(buffer));
115 	}
116 
117 	file.close();
118 
119 	if (ostr != NULL) (* ostr) << _("found ") << bs_vector.size() << _(" bs-terms.") << endl;
120 
121 /*##############################################*/
122 /*##############################################*/
123 
124 	fns.str("");	// blank the filename!
125 	fns << path << "/parameters2.txt" << ends;
126 
127 	file.open(fns.str().c_str(), ios::in);
128 
129 	if (ostr != NULL) (* ostr) << _("reading file \"") << fns.str() << "\": ";
130 
131 	while (file.peek() != '#')		// #end
132 	{
133 		if (file.peek() == '0')		// 0x????
134 		{
135 			prmfit_ab tmp; char bt[16];
136 			file >> tmp.atmtp[0] >> tmp.atmtp[1] >> tmp.atmtp[2] >> bt;
137 			file >> tmp.opt >> tmp.fc;
138 
139 			for (i32s n1 = 0;n1 < 2;n1++) tmp.bndtp[n1] = bondtype(bt[n1]);
140 			ab_vector.push_back(tmp);
141 		}
142 
143 		file.getline(buffer, sizeof(buffer));
144 	}
145 
146 	file.close();
147 
148 	if (ostr != NULL) (* ostr) << _("found ") << ab_vector.size() << _(" ab-terms.") << endl;
149 
150 /*##############################################*/
151 /*##############################################*/
152 
153 	fns.str("");	// blank the filename!
154 	fns << path << "/parameters3.txt" << ends;
155 
156 	file.open(fns.str().c_str(), ios::in);
157 
158 	if (ostr != NULL) (* ostr) << _("reading file \"") << fns.str() << "\": ";
159 
160 	while (file.peek() != '#')		// #end
161 	{
162 		if (file.peek() == '0')		// 0x????
163 		{
164 			prmfit_tr tmp; char bt[16];
165 			file >> tmp.atmtp[0] >> tmp.atmtp[1] >> tmp.atmtp[2] >> tmp.atmtp[3] >> bt;
166 			file >> tmp.fc1 >> tmp.fc2 >> tmp.fc3;
167 
168 			for (i32s n1 = 0;n1 < 3;n1++) tmp.bndtp[n1] = bondtype(bt[n1]);
169 			tr_vector.push_back(tmp);
170 		}
171 
172 		file.getline(buffer, sizeof(buffer));
173 	}
174 
175 	file.close();
176 
177 	if (ostr != NULL) (* ostr) << _("found ") << tr_vector.size() << _(" tr-terms.") << endl;
178 
179 /*##############################################*/
180 /*##############################################*/
181 
182 	fns.str("");	// blank the filename!
183 	fns << path << "/parameters4.txt" << ends;
184 
185 	file.open(fns.str().c_str(), ios::in);
186 
187 	if (ostr != NULL) (* ostr) << _("reading file \"") << fns.str() << "\": ";
188 
189 	while (file.peek() != '#')		// #end
190 	{
191 		if (file.peek() == '0')		// 0x????
192 		{
193 			prmfit_op tmp; char bt[16];
194 			file >> tmp.atmtp[0] >> tmp.atmtp[1] >> tmp.atmtp[2] >> tmp.atmtp[3] >> bt;
195 			file >> tmp.opt >> tmp.fc;
196 
197 			for (i32s n1 = 0;n1 < 3;n1++) tmp.bndtp[n1] = bondtype(bt[n1]);
198 			op_vector.push_back(tmp);
199 		}
200 
201 		file.getline(buffer, sizeof(buffer));
202 	}
203 
204 	file.close();
205 
206 	if (ostr != NULL) (* ostr) << _("found ") << op_vector.size() << _(" op-terms.") << endl;
207 
208 /*##############################################*/
209 /*##############################################*/
210 
211 	fns.str("");	// blank the filename!
212 }
213 
~prmfit_tables(void)214 prmfit_tables::~prmfit_tables(void)
215 {
216 	for (i32u n1 = 0;n1 < at2_vector.size();n1++)
217 	{
218 		delete at2_vector[n1].tr;
219 		delete[] at2_vector[n1].description;
220 	}
221 
222 	delete[] path;
223 }
224 
PrintAllTypeRules(ostream & p1)225 void prmfit_tables::PrintAllTypeRules(ostream & p1)
226 {
227 	for (i32u n1 = 0;n1 < at2_vector.size();n1++)
228 	{
229 		p1 << (n1 + 1) << ": 0x" << hex << setw(4) << setfill('0') << at2_vector[n1].atomtype << dec;
230 		p1 << " (" << (* at2_vector[n1].tr) << ") \"" << at2_vector[n1].description << "\"" << endl;
231 	}
232 
233 	p1 << at2_vector.size() << _(" entries.") << endl;
234 }
235 
UpdateTypes(setup * su)236 i32u prmfit_tables::UpdateTypes(setup * su)
237 {
238 	model * mdl = su->GetModel();
239 
240 	if (mdl->verbosity >= 3)
241 	{
242 		ostringstream str;
243 		str << _("Setting up atom types and formal charges...") << endl << ends;
244 
245 		mdl->PrintToLog(str.str().c_str());
246 	}
247 
248 	i32u errors = 0;
249 
250 // determine the atomtypes for all atoms, not just MM atoms (might need to skip the virtual atoms of SF if eng2???).
251 // determine the atomtypes for all atoms, not just MM atoms (might need to skip the virtual atoms of SF if eng2???).
252 // determine the atomtypes for all atoms, not just MM atoms (might need to skip the virtual atoms of SF if eng2???).
253 
254 	for (iter_al it1 = mdl->GetAtomsBegin();it1 != mdl->GetAtomsEnd();it1++)
255 	{
256 		i32u at_range[2];
257 
258 		at_range[0] = 0;
259 		while (true)
260 		{
261 			if (at_range[0] == at2_vector.size()) break;
262 			if ((at2_vector[at_range[0]].atomtype[0] >> 8) == (* it1).el.GetAtomicNumber()) break;
263 
264 			at_range[0]++;
265 		}
266 
267 		at_range[1] = at_range[0];
268 		while (true)
269 		{
270 			if (at_range[1] == at2_vector.size()) break;
271 			if ((at2_vector[at_range[1]].atomtype[0] >> 8) != (* it1).el.GetAtomicNumber()) break;
272 
273 			at_range[1]++;
274 		}
275 
276 		i32s index = NOT_DEFINED;
277 		for (i32u n1 = at_range[0];n1 < at_range[1];n1++)
278 		{
279 			bool flag = at2_vector[n1].tr->Check(mdl, & (* it1), 0);
280 			if (flag) index = n1;
281 
282 			// above, the LAST matching type will be selected???
283 		}
284 
285 		if (index != NOT_DEFINED)
286 		{
287 			(* it1).atmtp = at2_vector[index].atomtype[0];
288 			(* it1).charge = at2_vector[index].formal_charge;
289 		}
290 		else
291 		{
292 			if (mdl->verbosity >= 2)
293 			{
294 				ostringstream str;
295 				str << _("WARNING : could not determine atomtype (atom index = ") << (* it1).index << ")." << endl << ends;
296 
297 				mdl->PrintToLog(str.str().c_str());
298 			}
299 
300 			(* it1).atmtp = NOT_DEFINED;
301 			(* it1).charge = 0.0;
302 
303 			(* it1).flags |= ATOMFLAG_USER_SELECTED;
304 			errors++;
305 		}
306 	}
307 
308 	return errors;
309 }
310 
UpdateCharges(setup * su)311 i32u prmfit_tables::UpdateCharges(setup * su)
312 {
313 	model * mdl = su->GetModel();
314 
315 	if (mdl->verbosity >= 3)
316 	{
317 		ostringstream str;
318 		str << _("Setting up partial charges...") << endl << ends;
319 		mdl->PrintToLog(str.str().c_str());
320 	}
321 
322 	i32u errors = 0;
323 
324 //	atom ** atmtab = su->GetMMAtoms();
325 	bond ** bndtab = su->GetMMBonds();
326 
327 	for (i32s n1 = 0;n1 < su->GetMMBondCount();n1++)
328 	{
329 		prmfit_bs_query query; query.strict = false;
330 		query.atmtp[0] = bndtab[n1]->atmr[0]->atmtp;
331 		query.atmtp[1] = bndtab[n1]->atmr[1]->atmtp;
332 		query.bndtp = bndtab[n1]->bt.GetValue();
333 
334 		DoParamSearch(& query, mdl);
335 		if (query.index == NOT_DEFINED) errors++;
336 
337 		f64 delta = query.ci;			// here we also determine...
338 		if (query.dir) delta = -delta;		// ...the effect of direction!!!
339 
340 		bndtab[n1]->atmr[0]->charge -= delta;
341 		bndtab[n1]->atmr[1]->charge += delta;
342 	}
343 
344 	return errors;
345 }
346 
GetAtomType(i32s p1)347 const prmfit_at * prmfit_tables::GetAtomType(i32s p1)
348 {
349 	i32u index = 0;
350 	while (index < at2_vector.size())
351 	{
352 		if (at2_vector[index].atomtype[0] == p1) return (& at2_vector[index]);
353 		else index++;
354 	}
355 
356 	// could not find the requested type -> return a NULL pointer instead...
357 
358 	return NULL;
359 }
360 
DoParamSearch(prmfit_bs_query * query,model * mdl)361 void prmfit_tables::DoParamSearch(prmfit_bs_query * query, model * mdl)
362 {
363 	for (i32u n1 = 0;n1 < bs_vector.size();n1++)
364 	{
365 		if (bs_vector[n1].bndtp.GetValue() != query->bndtp.GetValue()) continue;
366 
367 		bool flag = false; i32s dir;
368 		for (dir = 0;dir < 2;dir++)
369 		{
370 			i32s index[2];
371 			index[0] = (!dir ? 0 : 1);
372 			index[1] = (!dir ? 1 : 0);
373 
374 			bool test1 = (bs_vector[n1].atmtp[0] == query->atmtp[index[0]]);
375 			bool test2 = (bs_vector[n1].atmtp[1] == query->atmtp[index[1]]);
376 
377 			if (test1 && test2) flag = true;
378 
379 			if (flag) break;
380 		}
381 
382 		if (flag)
383 		{
384 			query->index = n1;
385 			query->dir = dir;
386 
387 			query->opt = bs_vector[n1].opt;
388 			query->fc = bs_vector[n1].fc;
389 
390 			query->ci = bs_vector[n1].ci;
391 
392 			return;		// success, return the parameters...
393 		}
394 	}
395 
396 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
397 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
398 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
399 
400 	if (mdl != NULL && mdl->verbosity >= 2)
401 	{
402 		ostringstream str;
403 		str << _("WARNING : unknown bs: ");
404 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[0] << dec << " ";
405 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[1] << dec << " ";
406 		str << query->bndtp.GetValue() << " ";
407 		str << endl << ends;
408 
409 		mdl->PrintToLog(str.str().c_str());
410 	}
411 
412 	// the search failed, return default parameters...
413 
414 	query->index = NOT_DEFINED;
415 	query->dir = false;
416 
417 	query->opt = 0.140;
418 	query->fc = 60.0e+03;
419 
420 	query->ci = 0.0;
421 }
422 
DoParamSearch(prmfit_ab_query * query,model * mdl)423 void prmfit_tables::DoParamSearch(prmfit_ab_query * query, model * mdl)
424 {
425 	for (i32u n1 = 0;n1 < ab_vector.size();n1++)
426 	{
427 		if (ab_vector[n1].atmtp[1] != query->atmtp[1]) continue;
428 
429 		bool flag = false; i32s dir;
430 		for (dir = 0;dir < 2;dir++)
431 		{
432 			i32s btind[2];
433 			btind[0] = (!dir ? 0 : 1);
434 			btind[1] = (!dir ? 1 : 0);
435 
436 			bool bttest1 = (ab_vector[n1].bndtp[0].GetValue() != query->bndtp[btind[0]].GetValue());
437 			bool bttest2 = (ab_vector[n1].bndtp[1].GetValue() != query->bndtp[btind[1]].GetValue());
438 			if (bttest1 || bttest2) continue;	// bond type mismatch detected...
439 
440 			i32s index[2];
441 			index[0] = (!dir ? 0 : 2);
442 			index[1] = (!dir ? 2 : 0);
443 
444 			bool test1 = (ab_vector[n1].atmtp[0] == query->atmtp[index[0]]);
445 			bool test2 = (ab_vector[n1].atmtp[2] == query->atmtp[index[1]]);
446 
447 			if (test1 && test2) flag = true;
448 
449 			if (query->strict == false)
450 			{
451 				bool wc1 = (ab_vector[n1].atmtp[0] == 0xffff);
452 				bool wc2 = (ab_vector[n1].atmtp[2] == 0xffff);
453 
454 				if (wc1 && test2) flag = true;
455 				if (test1 && wc2) flag = true;
456 				if (wc1 && wc2) flag = true;
457 			}
458 
459 			if (flag) break;
460 		}
461 
462 		if (flag)
463 		{
464 			query->index = n1;
465 			query->dir = dir;
466 
467 			query->opt = ab_vector[n1].opt;
468 			query->fc = ab_vector[n1].fc;
469 
470 			return;		// success, return the parameters...
471 		}
472 	}
473 
474 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
475 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
476 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
477 
478 	if (mdl != NULL && mdl->verbosity >= 2)
479 	{
480 		ostringstream str;
481 		str << _("WARNING : unknown ab: ");
482 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[0] << dec << " ";
483 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[1] << dec << " ";
484 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[2] << dec << " ";
485 		str << query->bndtp[0].GetValue() << " ";
486 		str << query->bndtp[1].GetValue() << " ";
487 		str << endl << ends;
488 
489 		mdl->PrintToLog(str.str().c_str());
490 	}
491 
492 	// the search failed, return default parameters...
493 
494 	query->index = NOT_DEFINED;
495 	query->dir = false;
496 
497 	query->opt = 2.10;
498 	query->fc = 250.0;
499 }
500 
DoParamSearch(prmfit_tr_query * query,model * mdl)501 void prmfit_tables::DoParamSearch(prmfit_tr_query * query, model * mdl)
502 {
503 	for (i32u n1 = 0;n1 < tr_vector.size();n1++)
504 	{
505 		if (tr_vector[n1].bndtp[1].GetValue() != query->bndtp[1].GetValue()) continue;
506 
507 		bool flag = false; i32s dir;
508 		for (dir = 0;dir < 2;dir++)
509 		{
510 			i32s btind[2];
511 			btind[0] = (!dir ? 0 : 2);
512 			btind[1] = (!dir ? 2 : 0);
513 
514 			bool bttest1 = (tr_vector[n1].bndtp[0].GetValue() != query->bndtp[btind[0]].GetValue());
515 			bool bttest2 = (tr_vector[n1].bndtp[2].GetValue() != query->bndtp[btind[1]].GetValue());
516 			if (bttest1 || bttest2) continue;	// bond type mismatch detected...
517 
518 			i32s index[4];
519 			index[0] = (!dir ? 0 : 3);
520 			index[1] = (!dir ? 1 : 2);
521 			index[2] = (!dir ? 2 : 1);
522 			index[3] = (!dir ? 3 : 0);
523 
524 			bool test1 = (tr_vector[n1].atmtp[0] == query->atmtp[index[0]]);
525 			bool test2 = (tr_vector[n1].atmtp[1] == query->atmtp[index[1]]);
526 			bool test3 = (tr_vector[n1].atmtp[2] == query->atmtp[index[2]]);
527 			bool test4 = (tr_vector[n1].atmtp[3] == query->atmtp[index[3]]);
528 
529 			if (test1 && test2 && test3 && test4) flag = true;
530 
531 			if (query->strict == false)
532 			{
533 				bool wc1 = (tr_vector[n1].atmtp[0] == 0xffff);
534 				bool wc2 = (tr_vector[n1].atmtp[3] == 0xffff);
535 
536 				if (wc1 && test2 && test3 && test4) flag = true;
537 				if (test1 && test2 && test3 && wc2) flag = true;
538 				if (wc1 && test2 && test3 && wc2) flag = true;
539 			}
540 
541 			if (flag) break;
542 		}
543 
544 		if (flag)
545 		{
546 			query->index = n1;
547 			query->dir = dir;
548 
549 			query->fc1 = tr_vector[n1].fc1;
550 			query->fc2 = tr_vector[n1].fc2;
551 			query->fc3 = tr_vector[n1].fc3;
552 
553 			return;		// success, return the parameters...
554 		}
555 	}
556 
557 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
558 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
559 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
560 
561 	if (mdl != NULL && mdl->verbosity >= 2)
562 	{
563 		ostringstream str;
564 		str << _("WARNING : unknown tr: ");
565 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[0] << dec << " ";
566 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[1] << dec << " ";
567 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[2] << dec << " ";
568 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[3] << dec << " ";
569 		str << query->bndtp[0].GetValue() << " ";
570 		str << query->bndtp[1].GetValue() << " ";
571 		str << query->bndtp[2].GetValue() << " ";
572 		str << endl << ends;
573 
574 		mdl->PrintToLog(str.str().c_str());
575 	}
576 
577 	// the search failed, return default parameters...
578 
579 	query->index = NOT_DEFINED;
580 	query->dir = false;
581 
582 	query->fc1 = 0.0;
583 	query->fc2 = 0.0;
584 	query->fc3 = 0.0;
585 }
586 
DoParamSearch(prmfit_op_query * query,model * mdl)587 void prmfit_tables::DoParamSearch(prmfit_op_query * query, model * mdl)
588 {
589 	for (i32u n1 = 0;n1 < op_vector.size();n1++)
590 	{
591 		// the atomtypes are defined in the following way:
592 		// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
593 		//
594 		//   3  	the idea is to measure how much atom 3
595 		//   |  	is bend from the plane defined by atoms
596 		//   1  	0, 1 and 2.
597 		//  / \
598 		// 0   2	order of atoms 0 and 2 is not relevant,
599 		//		but atoms 1 and 3 must match exactly.
600 
601 		if (op_vector[n1].atmtp[1] != query->atmtp[1]) continue;
602 		if (op_vector[n1].atmtp[3] != query->atmtp[3]) continue;
603 		if (op_vector[n1].bndtp[2].GetValue() != query->bndtp[2].GetValue()) continue;
604 
605 		// proper bondtype checking not yet implemented....
606 		// it will be basically similar to the above, but must be moved into the dir-loop!!!
607 		// it will be basically similar to the above, but must be moved into the dir-loop!!!
608 		// it will be basically similar to the above, but must be moved into the dir-loop!!!
609 
610 		bool flag = false; i32s dir;
611 		for (dir = 0;dir < 2;dir++)
612 		{
613 			i32s btind[2];
614 			btind[0] = (!dir ? 0 : 1);
615 			btind[1] = (!dir ? 1 : 0);
616 
617 			bool bttest1 = (op_vector[n1].bndtp[0].GetValue() != query->bndtp[btind[0]].GetValue());
618 			bool bttest2 = (op_vector[n1].bndtp[1].GetValue() != query->bndtp[btind[1]].GetValue());
619 			if (bttest1 || bttest2) continue;	// bond type mismatch detected...
620 
621 			i32s index[2];
622 			index[0] = (!dir ? 0 : 2);
623 			index[1] = (!dir ? 2 : 0);
624 
625 			bool test1 = (op_vector[n1].atmtp[0] == query->atmtp[index[0]]);
626 			bool test2 = (op_vector[n1].atmtp[2] == query->atmtp[index[1]]);
627 
628 			if (test1 && test2) flag = true;
629 
630 			if (query->strict == false)
631 			{
632 				bool wc1 = (op_vector[n1].atmtp[0] == 0xffff);
633 				bool wc2 = (op_vector[n1].atmtp[2] == 0xffff);
634 
635 				if (wc1 && test2) flag = true;
636 				if (test1 && wc2) flag = true;
637 				if (wc1 && wc2) flag = true;
638 			}
639 
640 			if (flag) break;
641 		}
642 
643 		if (flag)
644 		{
645 			query->index = n1;
646 
647 			query->opt = op_vector[n1].opt;
648 			query->fc = op_vector[n1].fc;
649 
650 			return;		// success, return the parameters...
651 		}
652 	}
653 
654 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
655 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
656 // recursive search?!?!?! DO IT BY CALLING AGAIN USING SECONDARY TYPES!!! NOT RECURSIVELY!!!
657 
658 	if (mdl != NULL && mdl->verbosity >= 2)
659 	{
660 		ostringstream str;
661 		str << _("WARNING : unknown op: ");
662 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[0] << dec << " ";
663 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[1] << dec << " ";
664 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[2] << dec << " ";
665 		str << "0x" << hex << setw(4) << setfill('0') << query->atmtp[3] << dec << " ";
666 		str << query->bndtp[0].GetValue() << " ";
667 		str << query->bndtp[1].GetValue() << " ";
668 		str << query->bndtp[2].GetValue() << " ";
669 		str << endl << ends;
670 
671 		mdl->PrintToLog(str.str().c_str());
672 	}
673 
674 	// the search failed, return default parameters...
675 
676 	query->index = NOT_DEFINED;
677 
678 	query->opt = 0.0;
679 	query->fc = 0.0;
680 }
681 
682 /*################################################################################################*/
683 
684 // eof
685