UltraScan III
us_dmga_constr.cpp
Go to the documentation of this file.
1 
3 #include "us_dmga_constr.h"
4 #include "us_settings.h"
5 #include "us_util.h"
6 #include "us_model.h"
7 
8 // The constructor initializes the base or constraints model
10 {
11  x_attr = ATYPE_S;
12  y_attr = ATYPE_FF0;
15 
16  if ( imodel != NULL )
17  {
18  if ( imodel->analysis == US_Model::DMGA_CONSTR )
19  { // The input is a constraints model
20  cmodel = *imodel;
21 
22  constraints_from_model(); // Constraints from constraints model
23  base_from_cmodel(); // Base from constraints model
24  }
25 
26  else
27  { // The input is a base model
28  bmodel = *imodel;
29 
30  constraints_from_base(); // Constraints from base model
31  model_from_constraints(); // Constraints model from constraints
32  }
33  }
34 }
35 
36 // The destructor frees vectors
38 {
39  attribs.clear();
40 }
41 
42 // Load a base model
44 {
45  bmodel = *bmodelP;
46  cmodel = bmodel;
48 
49  constraints_from_base(); // Constraints from base model
50  model_from_constraints(); // Constraints model from constraints
51 }
52 
53 // Load a constraints model
55 {
56  cmodel = *cmodelP;
58 
59  constraints_from_model(); // Constraints from constraints model
60  base_from_cmodel(); // Base from constraints model
61 }
62 
63 // Update constraints with new values for a component or association
64 int US_dmGA_Constraints::update_constraints( QVector< Constraint >& cnsv )
65 {
66  int nupdc = cnsv.size(); // Count attributes to be updated
67  int nctot = attribs.size(); // Current count of all attributes
68  if ( nupdc < 1 )
69  return 0; // Nothing to do if no updates
70 
71  int mcompx = cnsv[ 0 ].mcompx; // Initial component index
72  int fcx = -1; // First update component index
73  int ncompc = 0; // Count of old comp/assoc constraints
74 DbgLv(1) << "dgC:upd_cns: mcompx" << mcompx << "nupdc" << nupdc;
75 
76  if ( cnsv[ 0 ].atype < ATYPE_KD )
77  { // Count old constraints for specified component
78  ncompc = count_comp_constraints( mcompx, &fcx, NULL );
79  }
80 
81  else
82  { // Count old constraints for specified association
83  ncompc = count_asso_constraints( mcompx, &fcx, NULL );
84  }
85 DbgLv(1) << "dgC:upd_cns: ncompc" << ncompc << "fcx" << fcx;
86 
87  // Replace old constraint entries with the updates
88  if ( nupdc == ncompc )
89  { // Same number: just replace existing elements
90  int kk = fcx;
91 
92  // Replace old constraint entries with the updates
93  for ( int ii = 0; ii < nupdc; ii++, kk++ )
94  attribs[ kk ] = cnsv[ ii ];
95 DbgLv(1) << "dgC:upd_cns: att" << fcx << "flt" << attribs[fcx].floats;
96 DbgLv(1) << "dgC:upd_cns: att" << fcx+1 << "flt" << attribs[fcx+1].floats;
97 DbgLv(1) << "dgC:upd_cns: att" << fcx+2 << "flt" << attribs[fcx+2].floats;
98  }
99 
100  else if ( nupdc < ncompc )
101  { // Smaller number of updates: replace, then compress
102  int kk = fcx;
103 
104  for ( int ii = 0; ii < nupdc; ii++, kk++ )
105  attribs[ kk ] = cnsv[ ii ];
106 
107  int frx = fcx + nupdc;
108  int fmx = fcx + ncompc;
109  kk = frx;
110 
111  for ( int ii = fmx; ii < nctot; ii++, kk++ )
112  attribs[ kk ] = attribs[ ii ];
113 
114  nctot = nctot - ncompc + nupdc;
115  attribs.resize( nctot );
116  }
117 
118  else if ( ncompc == 0 )
119  { // If no previous components of this type, just append
120  for ( int ii = 0; ii < nupdc; ii++ )
121  attribs << cnsv[ ii ];
122 
123  nctot += nupdc;
124  }
125 
126  else
127  { // Greater number of updates: expand at the end, then replace
128  int ncold = nctot;
129  nctot = nctot - ncompc + nupdc;
130  int fmx = fcx + ncompc;
131  int kk = nctot - 1;
132  attribs.resize( nctot );
133 
134  for ( int ii = ncold - 1; ii >= fmx; ii--, kk-- )
135  attribs[ kk ] = attribs[ ii ];
136 
137  for ( int ii = 0, kk = fcx; ii < nupdc; ii++, kk++ )
138  attribs[ kk ] = cnsv[ ii ];
139  }
140 
141 DbgLv(1) << "dgC:upd_cns: nctot" << nctot;
142  return nctot;
143 }
144 
145 // Load a constraints vector and construct the constraints model
146 void US_dmGA_Constraints::load_constraints( QVector< Constraint >& cnsv )
147 {
148  attribs = cnsv; // Set new constraints vector
150 
151 DbgLv(1) << "dgC:ld_cns: cnsvsz" << cnsv.size();
152  model_from_constraints(); // Build the constraints model
153 }
154 
155 // Initialize the constraints vector
157 {
159  attribs.clear(); // Clear the constraints vector
160 }
161 
162 // Add a constraints vector entry
164  double low, double high, bool floats, bool logscl )
165 {
166 DbgLv(1) << "dgC:add_cns: atype" << atype;
167  Constraint cns;
168  cns.atype = atype; // Attribute type
169  cns.mcompx = mcompx; // Component/Assoc index
170  cns.low = low; // Low or fixed value
171  cns.high = floats ? high : low; // High or fixed value
172  cns.floats = floats; // Floats? flag
173  cns.logscl = floats ? logscl : false; // Log scale? flag
174 
175  attribs << cns; // Add the constraints entry
176 
177 DbgLv(1) << "dgC:add_cns: attrsz" << attribs.size();
178  return attribs.size(); // Return updated vector's count
179 }
180 
181 // Return the current base model
183 {
184  bool is_ok = false;
185 
186  if ( bmodel.components.size() > 0 && bmodelP != NULL )
187  {
188  *bmodelP = bmodel;
189  is_ok = true;
190  }
191 
192  return is_ok;
193 }
194 
195 // A function to return the current constraints model
197 {
198  bool is_ok = false;
199 
200 DbgLv(1) << "dgC:get_cmo: attrsz" << attribs.size();
202 DbgLv(1) << "dgC:get_cmo: rtn";
203 
204  if ( cmodel.components.size() > 0 && cmodelP != NULL )
205  {
206  *cmodelP = cmodel;
207  is_ok = true;
208  }
209 else
210 DbgLv(1) << "dgC: *EMPTY* model";
211 
212  return is_ok;
213 }
214 
215 // A function to return the current work model
217 {
218  bool is_ok = false;
219 
220  if ( wmodel.components.size() > 0 && wmodelP != NULL )
221  {
222  *wmodelP = wmodel;
223  is_ok = true;
224 DbgLv(1) << "dgC:GWM: EXISTING wmodel";
225  }
226 
227  else if ( cmodel.components.size() > 0 )
228  {
229 DbgLv(1) << "dgC:GWM: CALL init_work_model";
230  init_work_model();
231 
232  *wmodelP = wmodel;
233  is_ok = true;
234  }
235 
236 DbgLv(1) << "dgC:GWM: is_ok" << is_ok;
237  return is_ok;
238 }
239 
240 // A function to get a specified component's constraints
242  QVector< Constraint >* cnsvP, int* kfltP )
243 {
244 DbgLv(1) << "dgC:cmp_cns: compx" << compx << "attrsz" << attribs.size();
245  int kattrib = 0; // Count of comp's attributes
246  int kfloat = 0; // Count of comp's floats
247  QVector< Constraint > cnsv; // Work constraints vector
248  cnsv.clear();
249 
250  for ( int ii = 0; ii < attribs.size(); ii++ )
251  {
252 DbgLv(1) << "dgC:cmp_cns: ii" << ii << "atype" << attribs[ii].atype
253  << "mcompx" << attribs[ii].mcompx;
254  if ( attribs[ ii ].atype >= ATYPE_KD )
255  break; // Done if to associations
256 
257  if ( attribs[ ii ].mcompx != compx )
258  continue; // Skip if not specified comp
259 
260  kattrib++; // Bump comp's attrib count
261  cnsv << attribs[ ii ]; // Save attribute for comp
262  if ( attribs[ ii ].floats )
263  kfloat++; // Bump attrib's floats count
264  }
265 DbgLv(1) << "dgC:cmp_cns: ka kf cnssz" << kattrib << kfloat << cnsv.size();
266 
267  if ( cnsvP != NULL )
268  *cnsvP = cnsv; // Return constraints vector
269 
270  if ( kfltP != NULL )
271  *kfltP = kfloat; // Return floats count
272 
273  return kattrib; // Return comp's attrib count
274 }
275 
276 // A function to get a specified association's constraints
278  QVector< Constraint >* cnsvP, int* kfltP )
279 {
280  int kattrib = 0; // Count of assoc's attributes
281  int kfloat = 0; // Count of assoc's floats
282  QVector< Constraint > cnsv; // Work constraints vector
283 DbgLv(1) << "dgC:ass_cns: assox" << assox << "attrsz" << attribs.size();
284 
285  for ( int ii = 0; ii < attribs.size(); ii++ )
286  {
287  if ( attribs[ ii ].atype < ATYPE_KD )
288  continue; // Skip if not association
289 
290  if ( attribs[ ii ].mcompx != assox )
291  continue; // Skip if not specified assoc
292 
293  kattrib++; // Bump assoc's attrib count
294  cnsv << attribs[ ii ]; // Save attribute for assoc
295  if ( attribs[ ii ].floats )
296  kfloat++; // Bump attrib's floats count
297 DbgLv(1) << "dgC:ass_cns: ii" << ii << "kattrib kfloat" << kattrib << kfloat;
298  }
299 
300  if ( cnsvP != NULL )
301  *cnsvP = cnsv; // Return constraints vector
302 
303  if ( kfltP != NULL )
304  *kfltP = kfloat; // Return floats count
305 
306  return kattrib; // Return assoc's attrib count
307 }
308 
309 // A function to get the current model's float constraints
310 int US_dmGA_Constraints::float_constraints( QVector< Constraint >* cnsvP )
311 {
312  nfloat = 0; // Count of float attributes
313  QVector< Constraint > cnsv; // Work constraints vector
314 
315  for ( int ii = 0; ii < attribs.size(); ii++ )
316  {
317  if ( attribs[ ii ].floats )
318  { // Attribute value floats
319  nfloat++; // Bump float attrib count
320  cnsv << attribs[ ii ]; // Save float attribute
321  }
322  }
323 
324  if ( cnsvP != NULL )
325  *cnsvP = cnsv; // Return constraints vector
326 
327  return nfloat; // Return float attrib count
328 }
329 
330 // A function to fetch a specified component attribute value
332  const AttribType atype )
333 {
334  double xval = 0.0;
335 
336  if ( atype == ATYPE_S )
337  xval = sc.s;
338  else if ( atype == ATYPE_FF0 )
339  xval = sc.f_f0;
340  else if ( atype == ATYPE_MW )
341  xval = sc.mw;
342  else if ( atype == ATYPE_D )
343  xval = sc.D;
344  else if ( atype == ATYPE_F )
345  xval = sc.f;
346  else if ( atype == ATYPE_VBAR )
347  xval = sc.vbar20;
348  else if ( atype == ATYPE_CONC )
349  xval = sc.signal_concentration;
350  else if ( atype == ATYPE_EXT )
351  xval = sc.extinction;
352 
353 DbgLv(1) << "dgC:f_att(c): atype xval" << atype << xval;
354  return xval;
355 }
356 
357 // A function to fetch a specified association attribute value
359  const AttribType atype )
360 {
361  double xval = 0.0;
362 
363  if ( atype == ATYPE_KD )
364  xval = as.k_d;
365  else if ( atype == ATYPE_KOFF )
366  xval = as.k_off;
367 
368 DbgLv(1) << "dgC:f_att(a): atype xval" << atype << xval;
369  return xval;
370 }
371 
372 // A function to store a specified component attribute value
374  const AttribType atype, const double xval )
375 {
376  if ( atype == ATYPE_S )
377  sc.s = xval;
378  else if ( atype == ATYPE_FF0 )
379  sc.f_f0 = xval;
380  else if ( atype == ATYPE_MW )
381  sc.mw = xval;
382  else if ( atype == ATYPE_D )
383  sc.D = xval;
384  else if ( atype == ATYPE_F )
385  sc.f = xval;
386  else if ( atype == ATYPE_VBAR )
387  sc.vbar20 = xval;
388  else if ( atype == ATYPE_CONC )
389  sc.signal_concentration = xval;
390  else if ( atype == ATYPE_EXT )
391  sc.extinction = xval;
392 }
393 
394 // A function to store a specified association attribute value
396  const AttribType atype, const double xval )
397 {
398  if ( atype == ATYPE_KD )
399  as.k_d = xval;
400  else if ( atype == ATYPE_KOFF )
401  as.k_off = xval;
402 }
403 
404 // Internal utility to populate constraints definitions
405 // from a constraints model
407 {
408  Constraint attr;
409  attribs.clear(); // Initialize constraints attributes
410  nfloat = 0; // and counts
411  nbcomp = 0;
412  nccomp = 0;
413  nbassoc = 0;
414  ncassoc = 0;
415 
416  QString cname = "";
417  QString pcname = "";
418  int mcompx = 0;
419  int massox = 0;
420  double xlow = 0.0;
421  double ylow = 0.0;
422  double zlow = 0.0;
423  double clow = 0.0;
424 DbgLv(1) << "dgC:cnsfrmo: mdl cmp size" << cmodel.components.size();
425 
426  for ( int ii = 0; ii < cmodel.components.size(); ii++ )
427  { // Scan constraints model components (solutes)
428  pcname = cname;
430  // Extract type flag from first 5 characters of analyte name
431  // For example, "000V_" for all fixed;
432  // "0Y0L_" for Y low;
433  // "0Y0H_" for Y high;
434  // "XY0L_" for X,Y low;
435  // "XY0H_" for X,Y high;
436  // "X0zH_" for X,Z high, with Z on log scale;
437  QString tflag = QString( sc->name ).left( 5 );
438  // Extract base analyte name
439  cname = QString( sc->name ).mid( 5 );
440  // Get component attribute values (non-zero are the selected ones)
441  double sval = sc->s;
442  double kval = sc->f_f0;
443  double wval = sc->mw;
444  double dval = sc->D;
445  double fval = sc->f;
446  double vval = sc->vbar20;
447 DbgLv(1) << "dgC:cnsfrmo: ii" << ii << "s k w d f v" << sval << kval << wval
448  << dval << fval << vval;
449  double xval = 0.0;
450  double yval = 0.0;
451  double zval = 0.0;
452  double cval = sc->signal_concentration;
453  double eval = sc->extinction;
454 
455  // Get X type and value
456  if ( sval != 0.0 )
457  {
458  x_attr = ATYPE_S;
459  xval = sval;
460  }
461  else if ( kval != 0.0 )
462  {
463  x_attr = ATYPE_FF0;
464  xval = kval;
465  }
466  else if ( wval != 0.0 )
467  {
468  x_attr = ATYPE_MW;
469  xval = wval;
470  }
471  else if ( dval != 0.0 )
472  {
473  x_attr = ATYPE_D;
474  xval = dval;
475  }
476  else if ( fval != 0.0 )
477  {
478  x_attr = ATYPE_F;
479  xval = fval;
480  }
481  else if ( vval != 0.0 )
482  {
483  x_attr = ATYPE_VBAR;
484  xval = vval;
485  }
486 
487  // Get Y type and value
488  if ( x_attr != ATYPE_FF0 && kval != 0.0 )
489  {
490  y_attr = ATYPE_FF0;
491  yval = kval;
492  }
493  else if ( x_attr != ATYPE_MW && wval != 0.0 )
494  {
495  y_attr = ATYPE_MW;
496  yval = wval;
497  }
498  else if ( x_attr != ATYPE_D && dval != 0.0 )
499  {
500  y_attr = ATYPE_D;
501  yval = dval;
502  }
503  else if ( x_attr != ATYPE_F && fval != 0.0 )
504  {
505  y_attr = ATYPE_F;
506  yval = fval;
507  }
508  else if ( x_attr != ATYPE_VBAR && vval != 0.0 )
509  {
510  y_attr = ATYPE_VBAR;
511  yval = vval;
512  }
513 
514  // Get Z type and value
515  if ( x_attr != ATYPE_MW && y_attr != ATYPE_MW && wval != 0.0 )
516  {
517  z_attr = ATYPE_MW;
518  zval = wval;
519  }
520  else if ( x_attr != ATYPE_D && y_attr != ATYPE_D && dval != 0.0 )
521  {
522  z_attr = ATYPE_D;
523  zval = dval;
524  }
525  else if ( x_attr != ATYPE_F && y_attr != ATYPE_F && fval != 0.0 )
526  {
527  z_attr = ATYPE_F;
528  zval = fval;
529  }
530  else if ( x_attr != ATYPE_VBAR && y_attr != ATYPE_VBAR && vval != 0.0 )
531  {
532  z_attr = ATYPE_VBAR;
533  zval = vval;
534  }
535 
536 DbgLv(1) << "dgC:cnsfrmo: tflag" << tflag << "xa ya za" << x_attr
537  << y_attr << z_attr;
538  if ( tflag.contains( "V" ) )
539  { // All fixed attributes
540  attr.atype = x_attr;
541  attr.mcompx = mcompx;
542  attr.low = xval;
543  attr.high = attr.low;
544  attr.floats = false;
545  attr.logscl = false;
546  attribs << attr; // Save X attribute constraint
547  attr.atype = y_attr;
548  attr.low = yval;
549  attr.high = attr.low;
550  attribs << attr; // Save Y attribute constraint
551  attr.atype = z_attr;
552  attr.low = zval;
553  attr.high = attr.low;
554  attribs << attr; // Save Z attribute constraint
555  attr.atype = ATYPE_CONC;
556  attr.low = cval;
557  attr.high = attr.low;
558  attribs << attr; // Save concentration constraint
559  } // END: all fixed
560 
561  else
562  { // 1 or 2 attributes are float
563  bool is_low = tflag.contains( "L" );
564  bool log_x = tflag.contains( "x" );
565  bool log_y = tflag.contains( "y" );
566  bool log_z = tflag.contains( "z" );
567 DbgLv(1) << "dgC:cnsfrmo: is_low" << is_low;
568 
569  if ( is_low )
570  { // First of two: just get low values
571  xlow = xval;
572  ylow = yval;
573  zlow = zval;
574  clow = cval;
575  continue;
576  } // END: 1st of pair
577 
578  else
579  { // Second of pair: complete low,high and build constraints
580  attr.atype = x_attr;
581  attr.mcompx = mcompx;
582  attr.low = xlow;
583  attr.high = xval;
584  if ( xval == xlow )
585  { // X Fixed
586  attr.floats = false;
587  attr.logscl = false;
588  }
589  else
590  { // X Floats
591  attr.floats = true;
592  attr.logscl = log_x;
593  nfloat++;
594  }
595  attribs << attr; // Save X attribute constraint
596 DbgLv(1) << "dgC:cnsfrmo: xattr xlow xhigh" << x_attr << xlow << xval;
597 
598  attr.atype = y_attr;
599  attr.low = ylow;
600  attr.high = yval;
601  if ( yval == ylow )
602  { // Y Fixed
603  attr.floats = false;
604  attr.logscl = false;
605  }
606  else
607  { // Y Floating
608  attr.floats = true;
609  attr.logscl = log_y;
610  nfloat++;
611  }
612  attribs << attr; // Save Y attribute constraint
613 DbgLv(1) << "dgC:cnsfrmo: yattr ylow yhigh" << y_attr << ylow << yval;
614 
615  attr.atype = z_attr;
616  attr.low = zlow;
617  attr.high = zval;
618  if ( zval == zlow )
619  { // Z Fixed
620  attr.floats = false;
621  attr.logscl = false;
622  }
623  else
624  { // Z Floating
625  attr.floats = true;
626  attr.logscl = log_z;
627  nfloat++;
628  }
629  attribs << attr; // Save Z attribute constraint
630 DbgLv(1) << "dgC:cnsfrmo: zattr zlow zhigh" << z_attr << zlow << zval;
631 
632  attr.atype = ATYPE_CONC;
633  attr.low = clow;
634  attr.high = cval;
635  attr.logscl = false;
636  if ( cval == clow )
637  { // Conc Fixed
638  attr.floats = false;
639  }
640  else
641  { // Conc Floating
642  attr.floats = true;
643  nfloat++;
644  }
645  attribs << attr; // Save Conc attribute constraint
646 
647  } // END: 2nd of pair
648  } // END: 1 or 2 attributes float
649 
650  // Store extinction value
651  attr.atype = ATYPE_EXT;
652  attr.low = eval;
653  attr.high = attr.low;
654  attr.floats = false;
655  attr.logscl = false;
656  attribs << attr; // Save extinction attribute constraint
657 
658  mcompx++; // Bump model component index
659  } // END: component loop
660 
661  nbcomp = mcompx; // Number base components
662  nccomp = attribs.count(); // Number constraint components
663  ncassoc = cmodel.associations.size(); // Number constraint assocs.
664  nbassoc = ncassoc / 2; // Number base associations
665 
666  for ( int ii = 0; ii < nbassoc; ii++ )
667  { // Loop to interpret pairs of constraints model associations
668  massox = ii;
669  int jj = ii * 2;
670  int kk = jj + 1;
673  double dval = as1->k_d;
674  double oval = as1->k_off;
675  double dhigh = as2->k_d;
676  double ohigh = as2->k_off;
677 
678  if ( dval == dhigh && oval == ohigh )
679  { // All fixed
680  attr.atype = ATYPE_KD;
681  attr.mcompx = massox;
682  attr.floats = false;
683  attr.low = dval;
684  attr.high = attr.low;
685  attr.logscl = false;
686  attribs << attr; // Save k_D attribute constraint
687  attr.atype = ATYPE_KOFF;
688  attr.floats = false;
689  attr.low = oval;
690  attr.high = attr.low;
691  attr.logscl = false;
692  attribs << attr; // Save k_Off attribute constraint
693 DbgLv(1) << "dgC:cnsfrmo: assoc fixed dval oval" << dval << oval;
694  } // END: all fixed
695 
696  else
697  { // One or two floating
698  bool log_d = ( as2->rcomps[ 0 ] < 0.0 );
699  bool log_o = ( as2->rcomps[ 1 ] < 0.0 );
700  bool flt_d = ( dval != dhigh );
701  bool flt_o = ( oval != ohigh );
702 
703  // Build K_d constraint
704  attr.atype = ATYPE_KD;
705  attr.mcompx = massox;
706  attr.floats = flt_d;
707  attr.low = dval;
708  attr.high = dhigh;
709  attr.logscl = log_d;
710  attribs << attr; // Save k_D attribute constraint
711 
712  // Build k_off constraint
713  attr.atype = ATYPE_KOFF;
714  attr.floats = flt_o;
715  attr.low = oval;
716  attr.high = ohigh;
717  attr.logscl = log_o;
718  attribs << attr; // Save k_Off attribute constraint
719 
720  // Bump total number of float attributes when appropriate
721  nfloat += ( ( flt_d ? 1 : 0 ) + ( flt_o ? 1 : 0 ) );
722 DbgLv(1) << "dgC:cnsfrmo: assoc float dlow dhigh olow ohigh"
723  << dval << dhigh << oval << ohigh << "nfloat" << nfloat;
724  } // END: 1 or 2 floating
725 
726  } // END: associations loop
727 }
728 
729 // Internal utility to build the constraints model
730 // from the vector of constraints
732 {
733  const QString pname_fix( "000V_" );
734  if ( attribs.size() < 1 )
735  {
736  qDebug() << "*ERROR* Unable to build a constraints model from an"
737  " empty constraints vector";
738  return;
739  }
740 
741  QList< int > cndxs;
742  QList< int > cflts;
743  QList< int > andxs;
744  QList< int > aflts;
746  cmodel.editGUID = QString( "00000000-0000-0000-0000-000000000000" );
747  cmodel.components .clear();
748  cmodel.associations.clear();
749  nfloat = 0;
750  int ncflt = 0;
751  int naflt = 0;
752  nbcomp = 0;
753  nccomp = 0;
754  nbassoc = 0;
755  ncassoc = 0;
756  int mcompx = attribs[ 0 ].mcompx;
757 
758  // Scan the constraints vector for counts
759 
760  for ( int ii = 0; ii < attribs.size(); ii++ )
761  {
762  AttribType atype = attribs[ ii ].atype;
763  mcompx = attribs[ ii ].mcompx;
764  bool floats = attribs[ ii ].floats;
765  nfloat += ( floats ? 1 : 0 );
766 DbgLv(1) << "dgC:modfrcn:scn: ii" << ii << " mcompx" << mcompx
767  << "atype" << atype << "floats" << floats;
768 
769  if ( atype < ATYPE_KD )
770  { // Component attribute
771  //nbcomp = qMax( nbcomp, ( mcompx + 1 ) );
772  nbcomp++;
773  ncflt += ( floats ? 1 : 0 );
774  if ( cndxs.contains( mcompx ) )
775  { // Component previously seen
776  if ( floats )
777  cflts[ mcompx ] += 1;
778  }
779  else
780  { // Newly-encountered component
781  cndxs << mcompx;
782  cflts << ( floats ? 1 : 0 );
783  }
784  } // END: component attribute
785 
786  else
787  { // Association attribute
788  //nbassoc = qMax( nbassoc, ( mcompx + 1 ) );
789  nbassoc++;
790  naflt += ( floats ? 1 : 0 );
791  if ( andxs.contains( mcompx ) )
792  { // Association previously seen
793  if ( floats )
794  aflts[ mcompx ] += 1;
795  }
796  else
797  { // Newly-encountered association
798  andxs << mcompx;
799  aflts << ( floats ? 1 : 0 );
800  }
801  } // END: association attribute
802 DbgLv(1) << "dgC:modfrcn:scn: ii nbc nba" << ii << nbcomp << nbassoc;
803  } // END: constraints scan loop
804 
805  nccomp = nbcomp + ncflt;
806  ncassoc = nbassoc * 2;
807 DbgLv(1) << "dgC:modfrcn: ncc nca" << nccomp << ncassoc << "nbc ncf"
808  << nbcomp << ncflt << "nba" << nbassoc << "nf" << nfloat;
809  mcompx = attribs[ 0 ].mcompx;
810 DbgLv(1) << "dgC:modfrcn: bmodel compsz assosz"
811  << bmodel.components.size() << bmodel.associations.size();
812  int kfloat = 0;
813  int kcompo = 0;
814  int kassoc = 0;
815  int pmcomx = mcompx;
816  QString pname = pname_fix;
818  sc1 = bmodel.components[ 0 ];
819  sc1.mw = 0.0;
820  sc1.s = 0.0;
821  sc1.D = 0.0;
822  sc1.f = 0.0;
823  sc1.f_f0 = 0.0;
826  if ( bmodel.associations.size() > 0 )
827  as1 = bmodel.associations[ 0 ];
828  US_Model::Association as2 = as1;
829 
830  // Now, loop to create the components and associations of the model
831 
832  for ( int ii = 0; ii < attribs.size(); ii++ )
833  {
834  AttribType atype = attribs[ ii ].atype;
835  pmcomx = mcompx;
836  mcompx = attribs[ ii ].mcompx;
837  double xlow = attribs[ ii ].low;
838  double xhigh = attribs[ ii ].high;
839  bool floats = attribs[ ii ].floats;
840  bool logscl = attribs[ ii ].logscl;
841 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "mcx pmcx" << mcompx << pmcomx
842  << "typ" << atype << "flt" << floats << "lo,hi" << xlow << xhigh;
843 
844  if ( mcompx != pmcomx )
845  { // Initialize component or association for new base component
846  if ( atype < ATYPE_KD )
847  { // New component
848  if ( kfloat == 0 )
849  { // If no floats in component, just output one record
850  sc1.name = pname + QString( sc1.name );
851  cmodel.components << sc1;
852 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc1.name" << sc1.name;
853  }
854 
855  else
856  { // If components had any floats, output low,high records
857  pname = QString( pname ).left( 3 ) + "L_";
858  sc1.name = pname + QString( sc1.name );
859  cmodel.components << sc1;
860  pname = QString( pname ).left( 3 ) + "H_";
861  sc2.name = pname + QString( sc2.name );
862  cmodel.components << sc2;
863 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc1.name" << sc1.name;
864 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc2.name" << sc2.name;
865  }
866 
867  // Initialize for new component
868  kfloat = 0;
869  kcompo = 0;
870  sc1 = bmodel.components[ mcompx ];
871  sc1.mw = 0.0;
872  sc1.s = 0.0;
873  sc1.D = 0.0;
874  sc1.f = 0.0;
875  sc1.f_f0 = 0.0;
876  sc2 = sc1;
877  pname = pname_fix;
878  }
879 
880  else
881  { // New association
882  AttribType ptype = attribs[ ii - 1 ].atype;
883  if ( ptype < ATYPE_KD )
884  { // Save last component entry
885  if ( kfloat == 0 )
886  { // If no floats in component, just output one record
887  sc1.name = pname + QString( sc1.name );
888  cmodel.components << sc1;
889 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc1.name" << sc1.name;
890  }
891 
892  else
893  { // If components had any floats, output low,high records
894  pname = QString( pname ).left( 3 ) + "L_";
895  sc1.name = pname + QString( sc1.name );
896  cmodel.components << sc1;
897  pname = QString( pname ).left( 3 ) + "H_";
898  sc2.name = pname + QString( sc2.name );
899  cmodel.components << sc2;
900 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc1.name" << sc1.name;
901 DbgLv(1) << "dgC:modfrcn:cre: ii" << ii << "sc2.name" << sc2.name;
902  }
903  }
904 
905  else
906  { // Save last association entry
907  cmodel.associations << as1;
908  cmodel.associations << as2;
909  }
910 
911  as1 = bmodel.associations[ mcompx ];
912  as2 = as1;
913  kassoc = 0;
914  }
915  }
916 
917  // Accumulate float count
918  kfloat += ( floats ? 1 : 0 );
919 DbgLv(1) << "dgC:modfrcn:cre: kfloat" << kfloat;
920 
921  // Handle the current constraint
922 
923  if ( atype < ATYPE_KD )
924  { // Component constraint
925  store_attrib( sc1, atype, xlow );
926  store_attrib( sc2, atype, xhigh );
927  kcompo++;
928 
929  if ( floats )
930  { // For float, check logscl; then set pre-name flag
931  if ( kcompo == 1 )
932  { // "x**L" or "X**L"
933  QString xf = logscl ? "x" : "X";
934  pname = xf + "00L_";
935  }
936  else if ( kcompo == 2 )
937  { // "*y*L" or "*Y*L"
938  QString yf = logscl ? "y" : "Y";
939  pname = QString( pname ).left( 1 ) + yf + "0L_";
940  }
941  else if ( kcompo == 3 )
942  { // "**zL" or "**ZL"
943  QString zf = logscl ? "z" : "Z";
944  pname = QString( pname ).left( 2 ) + zf + "L_";
945  }
946  else
947  { // "***L"
948  pname = QString( pname ).left( 3 ) + "L_";
949  }
950  }
951 
952  else
953  { // For non-float, duplicate low,high as value
954  store_attrib( sc1, atype, xlow );
955  store_attrib( sc2, atype, xlow );
956  }
957  }
958 
959  else
960  { // Association constraint
961  store_attrib( as1, atype, xlow );
962  store_attrib( as2, atype, xhigh );
963  if ( logscl )
964  {
965  int mm = ( atype == ATYPE_KD ) ? 0 : 1;
966  as2.rcomps[ mm ] = -( mm + 1 );
967  }
968 
969  kassoc++;
970 DbgLv(1) << "dgC:modfrcn:cre: kassoc" << kassoc << "cmasz"
971  << cmodel.associations.size();
972  }
973  } // END: component,association composition loop
974 
975  // If need be, output the final component(s)
976  if ( kassoc == 0 )
977  {
978  if ( kfloat == 0 )
979  { // If no floats in component, just output one record
980  sc1.name = pname + QString( sc1.name );
981  cmodel.components << sc1;
982  }
983 
984  else
985  { // If components had any floats, output low,high records
986  pname = QString( pname ).left( 3 ) + "L_";
987  sc1.name = pname + QString( sc1.name );
988  cmodel.components << sc1;
989  pname = QString( pname ).left( 3 ) + "H_";
990  sc2.name = pname + QString( sc2.name );
991  cmodel.components << sc2;
992  }
993  }
994 
995  else
996  { // Save last association entry
997  cmodel.associations << as1;
998  cmodel.associations << as2;
999  }
1000 DbgLv(1) << "dgC:modfrcn:cre: 0 sc1.mw" << cmodel.components[0].mw;
1001 DbgLv(1) << "dgC:modfrcn:cre: 0 sc1.name" << cmodel.components[0].name;
1002 DbgLv(1) << "dgC:modfrcn:cre: att0 type flt" << attribs[0].atype
1003  << attribs[0].floats;
1004 DbgLv(1) << "dgC:modfrcn:cre: att1 type flt" << attribs[1].atype
1005  << attribs[1].floats;
1006 DbgLv(1) << "dgC:modfrcn:cre: att2 type flt" << attribs[2].atype
1007  << attribs[2].floats;
1008 }
1009 
1010 // Internal utility to build an initial constraints from a base model
1012 {
1013  if ( bmodel.components.size() < 1 )
1014  {
1015  qDebug() << "*ERROR* Unable to build constraints from empty base";
1016  return;
1017  }
1018 
1019  Constraint attr;
1020  attr.floats = false;
1021  attr.logscl = false;
1022  attribs.clear(); // Initialize constraints attributes
1023  nfloat = 0; // and counts
1024  nbcomp = 0;
1025  nccomp = 0;
1026  nbassoc = 0;
1027  ncassoc = 0;
1028 
1029  for ( int ii = 0; ii < bmodel.components.size(); ii++ )
1030  { // Scan constraints model components (solutes)
1032  // Get component attribute values (selected ones)
1033  attr.mcompx = ii;
1034  attr.atype = ATYPE_MW;
1035  attr.low = sc->mw;
1036  attr.high = attr.low;
1037  attribs << attr; // Save mw attribute constraint
1038 
1039  attr.atype = ATYPE_FF0;
1040  attr.low = sc->f_f0;
1041  attr.high = attr.low;
1042  attribs << attr; // Save f_f0 attribute constraint
1043 
1044  attr.atype = ATYPE_VBAR;
1045  attr.low = sc->vbar20;
1046  attr.high = attr.low;
1047  attribs << attr; // Save vbar attribute constraint
1048 
1049  attr.atype = ATYPE_CONC;
1050  attr.low = sc->signal_concentration;
1051  attr.high = attr.low;
1052  attribs << attr; // Save concentration constraint
1053 
1054  attr.atype = ATYPE_EXT;
1055  attr.low = sc->extinction;
1056  attr.high = attr.low;
1057  attribs << attr; // Save extinction attribute constraint
1058 
1059  nbcomp++; // Bump model component count
1060  } // END: component loop
1061 
1062  nccomp = attribs.count(); // Number constraint components
1063  ncassoc = bmodel.associations.size(); // Number constraint assocs.
1064  nbassoc = ncassoc; // Number base associations
1065 
1066  for ( int ii = 0; ii < nbassoc; ii++ )
1067  { // Loop to interpret constraints model associations
1069 
1070  attr.mcompx = ii;
1071  attr.atype = ATYPE_KD;
1072  attr.low = as1->k_d;
1073  attr.high = attr.low;
1074  attribs << attr; // Save k_D attribute constraint
1075  attr.atype = ATYPE_KOFF;
1076  attr.low = as1->k_off;
1077  attr.high = attr.low;
1078  attribs << attr; // Save k_Off attribute constraint
1079  } // END: associations loop
1080 DbgLv(1) << "dgC:cnfrbas: attr2 atype" << attribs[2].atype;
1081 }
1082 
1083 // Internal utility to count constraints for a given component
1085  int* countfP )
1086 {
1087  int kconstr = 0; // Count of component constraints
1088  int fattrx = -1; // First matching attribute index
1089  int kfloat = 0; // Count of floats for this component
1090 
1091  for ( int ii = 0; ii < attribs.size(); ii++ )
1092  { // Scan all constraints
1093  if ( attribs[ ii ].atype >= ATYPE_KD )
1094  break; // Quit when beyond components (at assocs.)
1095 
1096  int mcompx = attribs[ ii ].mcompx;
1097 
1098  if ( mcompx != mcx )
1099  continue; // Skip all non-matching component indecies
1100 
1101  kconstr++; // Bump constraints count
1102  if ( fattrx < 0 )
1103  fattrx = ii; // Save first index of a match
1104 
1105  if ( attribs[ ii ].floats )
1106  kfloat++; // Bump count if this attribute floats
1107 DbgLv(1) << "dgC:ccc: ii" << ii << "kconstr" << kconstr << "fattrx kfloat"
1108  << fattrx << kfloat;
1109  }
1110 
1111  if ( faxP != NULL )
1112  *faxP = fattrx; // Return first constraints index of match
1113 
1114  if ( countfP != NULL )
1115  *countfP = kfloat; // Return count of floats for this component
1116 
1117  return kconstr; // Return count of matches
1118 }
1119 
1120 // Internal utility to count constraints for a given association
1122  int* countfP )
1123 {
1124  int kconstr = 0; // Count of association constraints
1125  int fattrx = -1; // First matching attribute index
1126  int kfloat = 0; // Count of floats for this association
1127 
1128  for ( int ii = 0; ii < attribs.size(); ii++ )
1129  { // Scan all constraints
1130  if ( attribs[ ii ].atype < ATYPE_KD )
1131  continue; // Skip non-association constraints
1132 
1133  int massox = attribs[ ii ].mcompx;
1134 
1135  if ( massox != msx )
1136  continue; // Skip all non-matching association indecies
1137 
1138  kconstr++; // Bump constraints count
1139  if ( fattrx < 0 )
1140  fattrx = ii; // Save first index of a match
1141 
1142  if ( attribs[ ii ].floats )
1143  kfloat++; // Bump count if this attribute floats
1144  }
1145 
1146  if ( faxP != NULL )
1147  *faxP = fattrx; // Return first constraints index of match
1148 
1149  if ( countfP != NULL )
1150  *countfP = kfloat; // Return count of floats for this association
1151 
1152  return kconstr; // Return count of matches
1153 }
1154 
1155 // Internal utility to build the initial work model
1157 {
1158  QVector< Constraint > cnsv; // Constraints for each attribute
1159  int kfloat = 0; // Count of work model floats per attrib
1161  US_Model::Association as1, as2;
1163 
1164  if ( cmodel.components.size() < 1 )
1165  {
1166 DbgLv(1) << "dgC:inwkmdl: CMODEL EMPTY";
1167  return false;
1168  }
1169 
1170  wmodel = bmodel;
1171  if ( bmodel.components.size() == 0 )
1172  {
1173 DbgLv(1) << "dgC:inwkmdl: nbcomp nbassoc" << nbcomp << nbassoc;
1174  wmodel = cmodel;
1175  }
1176 
1177  wmodel.components .clear();
1178  wmodel.associations.clear();
1179  int mcompx = 0; // Initial output comp/assoc index
1180 
1181  for ( int ii = 0; ii < cmodel.components.size(); ii++ )
1182  {
1183  int kconstr = comp_constraints( mcompx, &cnsv, &kfloat );
1184  sc1 = cmodel.components[ ii ];
1185  sc1.name = QString( sc1.name ).mid( 5 );
1186 DbgLv(1) << "dgC:inwkmdl: ii" << ii << "mcompx" << mcompx
1187  << "kconstr kfloat" << kconstr << kfloat;
1188 
1189  if ( kfloat > 0 )
1190  { // Floats: loop to find values half-way through ranges
1191  sc2 = cmodel.components[ ++ii ];
1192 
1193  for ( int jj = 0; jj < kconstr; jj++ )
1194  {
1195  if ( cnsv[ jj ].floats )
1196  { // This is a floating attribute: store mid-way value
1197  x_attr = cnsv[ jj ].atype;
1198  double xval = fetch_attrib( sc1, x_attr );
1199  double xval2 = fetch_attrib( sc2, x_attr );
1200  if ( cnsv[ jj ].logscl )
1201  { // Treat range as logarithmic
1202  xval = log( xval );
1203  xval2 = log( xval2 );
1204  xval = ( xval + xval2 ) * 0.5;
1205  xval = exp( xval );
1206  }
1207  else
1208  { // Treat range as linear
1209  xval = ( xval + xval2 ) * 0.5;
1210  }
1211  store_attrib( sc1, x_attr, xval );
1212  }
1213  }
1214  }
1215 
1216 DbgLv(1) << "dgC:inwkmdl: out sc1 xval0" << fetch_attrib(sc1,cnsv[0].atype)
1217  << "mcompx" << mcompx;
1218  wmodel.components << sc1;
1219  mcompx++;
1220  }
1221 
1222  mcompx = 0;
1223 
1224  for ( int ii = 0; ii < cmodel.associations.size(); ii += 2 )
1225  {
1226  int kconstr = assoc_constraints( mcompx, &cnsv, &kfloat );
1227  as1 = cmodel.associations[ ii ];
1228 
1229  if ( kfloat > 0 )
1230  { // Floats: loop to find values half-way through ranges
1231  as2 = cmodel.associations[ ii + 1 ];
1232 
1233  for ( int jj = 0; jj < kconstr; jj++ )
1234  {
1235  if ( cnsv[ jj ].floats )
1236  { // This is a floating attribute: store mid-way value
1237  x_attr = cnsv[ jj ].atype;
1238  double xval = fetch_attrib( as1, x_attr );
1239  double xval2 = fetch_attrib( as2, x_attr );
1240 
1241  if ( cnsv[ jj ].logscl )
1242  { // Treat range as logarithmic
1243  xval = log( xval );
1244  xval2 = log( xval2 );
1245  xval = ( xval + xval2 ) * 0.5;
1246  xval = exp( xval );
1247  }
1248 
1249  else
1250  { // Treat range as linear
1251  xval = ( xval + xval2 ) * 0.5;
1252  }
1253  store_attrib( as1, x_attr, xval );
1254  }
1255  }
1256  }
1257 
1258  wmodel.associations << as1;
1259 DbgLv(1) << "dgC:inwkmdl: out as1 xval0" << fetch_attrib(as1,cnsv[0].atype)
1260  << "mcompx" << mcompx;
1261  mcompx++;
1262  }
1263 
1264  if ( bmodel.components.size() == 0 )
1265  bmodel = wmodel;
1266 
1267  return true;
1268 }
1269 
1270 // Internal utility to build the base model from the constraints model
1272 {
1273  if ( cmodel.components.size() < 1 )
1274  {
1275 DbgLv(1) << "dgC:basefrcm: CMODEL EMPTY";
1276  return false;
1277  }
1278 
1280  US_Model::Association as1, as2;
1281 
1282  bmodel = cmodel;
1284  bmodel.description = QString( cmodel.description ).replace(
1285  "DMGA_Constraints", "DMGA_Base" );
1286  bmodel.editGUID = "";
1287  bmodel.components .clear();
1288  bmodel.associations.clear();
1289 
1290  for ( int ii = 0; ii < cmodel.components.size(); ii++ )
1291  {
1292  sc1 = cmodel.components[ ii ];
1293  QString anam = sc1.name;
1294  QString aflg = QString( anam ).left( 4 );
1295  sc1.name = QString( anam ).mid( 5 );
1296 
1297  if ( ! aflg.contains( "V" ) )
1298  { // If float pair, get mid-way attribute values
1299  sc2 = cmodel.components[ ++ii ];
1300  sc1.vbar20 = ( sc1.vbar20 + sc2.vbar20 ) * 0.5;
1301  sc1.s = ( sc1.s + sc2.s ) * 0.5;
1302  sc1.f_f0 = ( sc1.f_f0 + sc2.f_f0 ) * 0.5;
1303  sc1.mw = ( sc1.mw + sc2.mw ) * 0.5;
1304  sc1.D = ( sc1.D + sc2.D ) * 0.5;
1305  sc1.f = ( sc1.f + sc2.f ) * 0.5;
1307  = ( sc1.signal_concentration +
1308  sc2.signal_concentration ) * 0.5;
1309  }
1310 
1311  // Calculate unselected coefficients
1313 
1314  bmodel.components << sc1;
1315  }
1316 
1317  // Loop to combine association pairs by averaging
1318  for ( int ii = 0; ii < cmodel.associations.size(); ii += 2 )
1319  {
1320  as1 = cmodel.associations[ ii ];
1321  as2 = cmodel.associations[ ii + 1 ];
1322 
1323  as1.k_d = ( as1.k_d + as2.k_d ) * 0.5;
1324  as1.k_off = ( as1.k_off + as2.k_off ) * 0.5;
1325 
1326  bmodel.associations << as1;
1327  }
1328 
1329  return true;
1330 }
1331