10 ModelSystem& current_model,
11 QWidget*
p, Qt::WindowFlags f )
14 setWindowTitle(
"Model Editor" );
17 setWindowModality( Qt::WindowModal );
18 setAttribute( Qt::WA_DeleteOnClose );
20 QGridLayout*
main =
new QGridLayout(
this );
21 main->setSpacing( 2 );
28 struct SimulationComponent* sc = &
model.component_vector[
component ];
29 vector< struct SimulationComponent >* scl = &
model.component_vector;
36 main->addWidget(
lb_header, row++, 0, 1, 4 );
41 QLabel* lb_current =
us_label( tr(
"Current Component:" ) );
43 main->addWidget( lb_current, row++, 0, 1, 2 );
49 for (
uint i = 0; i < scl->size(); i++ )
60 QLabel* lb_sedCoef =
us_label( tr(
"Sedimentation Coeff. (sec):" ) );
61 main->addWidget( lb_sedCoef, row, 0 );
64 connect(
le_sed, SIGNAL( textEdited(
const QString& ) ),
66 main->addWidget(
le_sed, row++, 1 );
69 QLabel* lb_diffusion =
us_label( tr(
"Diffusion Coeff. (cm<sup>2</sup>/sec):" ) );
70 main->addWidget( lb_diffusion, row, 0 );
73 connect(
le_diff, SIGNAL( textEdited (
const QString& ) ),
75 main->addWidget(
le_diff, row++, 1 );
78 QLabel* lb_ExtCoef =
us_label( tr(
"Extinction Coeff. (OD/mol):" ) );
79 main->addWidget( lb_ExtCoef, row, 0 );
82 connect(
le_extinction, SIGNAL( textEdited (
const QString& ) ),
89 main->addWidget(
pb_vbar, row, 0 );
92 connect(
le_vbar, SIGNAL( textEdited (
const QString& ) ),
94 main->addWidget(
le_vbar, row++, 1 );
97 QLabel* lb_mw =
us_label( tr(
"Molecular Weight (Da)" ) );
98 main->addWidget( lb_mw, row, 0 );
101 connect(
le_mw, SIGNAL( textEdited(
const QString& ) ),
103 main->addWidget(
le_mw, row++, 1 );
106 QLabel* lb_f_f0 =
us_label( tr(
"Frictional Ratio (f/f0)" ) );
107 main->addWidget( lb_f_f0, row, 0 );
110 connect(
le_f_f0, SIGNAL( textEdited (
const QString& ) ),
112 main->addWidget(
le_f_f0, row++, 1 );
117 main->addWidget( pb_sim, row, 0 );
122 sb_count->setRange( 1, scl->size() );
126 connect(
sb_count, SIGNAL( valueChanged (
int ) ),
129 main->addWidget(
sb_count, row++, 1 );
135 main->addLayout( prolate, row, 0 );
139 main->addLayout( oblate, row++, 1 );
142 rb_rod->setEnabled(
false );
143 main->addLayout( rod, row, 0 );
147 main->addLayout( sphere, row++, 1 );
149 QButtonGroup* shapeButtons =
new QButtonGroup(
this );
154 connect( shapeButtons, SIGNAL( buttonClicked(
int ) ),
161 QLabel* lb_linked =
us_label( tr(
"This component is linked to:" ) );
162 main->addWidget( lb_linked, row++, 2, 1, 2 );
169 for (
uint i = 0; i < sc->show_component.size(); i++ )
170 cmb_component2->addItem( (*scl)[ sc->show_component[ i ] ].name );
176 QLabel* lb_conc =
us_label( tr(
"Partial Conc. (in OD):" ) );
177 main->addWidget( lb_conc, row, 2 );
180 connect(
le_conc, SIGNAL( textEdited (
const QString& ) ),
182 main->addWidget(
le_conc, row++, 3 );
190 le_c0->setEnabled(
false );
191 main->addWidget(
le_c0, row++, 3 );
194 QLabel* lb_adjust =
us_label( tr(
"Please adjust for correct pathlength)" ) );
195 lb_adjust->setAlignment( Qt::AlignCenter );
196 main->addWidget( lb_adjust, row++, 2, 1, 2 );
199 QLabel* lb_keq =
us_label( tr(
"Equilibrium Const. (in OD):" ) );
200 main->addWidget( lb_keq, row, 2 );
203 le_keq->setEnabled(
false );
204 connect(
le_keq, SIGNAL( textEdited(
const QString& ) ),
206 main->addWidget(
le_keq, row++, 3 );
209 QLabel* lb_koff =
us_label( tr(
"K_off Rate Constant (1/sec):" ) );
210 main->addWidget( lb_koff, row, 2 );
214 connect(
le_koff, SIGNAL( textEdited (
const QString& ) ),
216 main->addWidget(
le_koff, row++, 3 );
219 QLabel* lb_stoich =
us_label( tr(
"Stoichiometry:" ) );
220 main->addWidget( lb_stoich, row, 2 );
227 QLabel* lb_sigma =
us_label( tr(
"Conc. Dependency of s (sigma):" ) );
228 main->addWidget( lb_sigma, row, 2 );
232 connect(
le_sigma, SIGNAL( textEdited (
const QString& ) ),
234 main->addWidget(
le_sigma, row++, 3 );
237 QLabel* lb_delta =
us_label( tr(
"Conc. Dependency of D (delta):" ) );
238 main->addWidget( lb_delta, row, 2 );
242 connect(
le_delta, SIGNAL( textEdited (
const QString& ) ),
244 main->addWidget(
le_delta, row++, 3 );
250 QBoxLayout* buttonbox =
new QHBoxLayout;
252 QPushButton* pb_load =
us_pushbutton( tr(
"Load Model File") );
253 connect( pb_load, SIGNAL( clicked() ), SLOT(
load_model()) );
254 buttonbox->addWidget( pb_load );
257 connect( pb_save, SIGNAL( clicked() ), SLOT(
save_model()) );
258 buttonbox->addWidget( pb_save );
261 connect( pb_help, SIGNAL( clicked() ), SLOT(
help()) );
262 buttonbox->addWidget( pb_help );
265 buttonbox->addWidget( pb_close );
266 connect( pb_close, SIGNAL( clicked() ), SLOT( reject()) );
268 QPushButton* pb_accept =
us_pushbutton( tr(
"Accept Model") );
269 buttonbox->addWidget( pb_accept );
270 connect( pb_accept, SIGNAL( clicked() ), SLOT(
accept_model()) );
272 main->addLayout( buttonbox, row++, 0, 1, 4 );
281 connect(
sb_count, SIGNAL( valueChanged(
int ) ),
303 rb_rod ->setEnabled(
false );
307 struct SimulationComponent* sc = &
model.component_vector[
component ];
308 vector< struct SimulationComponent >* scl = &
model.component_vector;
310 le_sed ->setText( QString::number( sc->s ,
'e', 4 ) );
311 le_diff ->setText( QString::number( sc->D ,
'e', 4 ) );
312 le_extinction->setText( QString::number( sc->extinction,
'e', 4 ) );
313 le_vbar ->setText( QString::number( sc->vbar20 ,
'e', 4 ) );
314 le_mw ->setText( QString::number( sc->mw ,
'e', 4 ) );
315 le_f_f0 ->setText( QString::number( sc->f_f0 ,
'e', 4 ) );
317 if ( sc->shape ==
"sphere" )
rb_sphere ->setDown(
true );
318 else if ( sc->shape ==
"prolate" )
rb_prolate ->setDown(
true );
319 else if ( sc->shape ==
"oblate" )
rb_oblate ->setDown(
true );
320 else if ( sc->shape ==
"rod" )
rb_rod ->setDown(
true );
327 for (
uint i = 0; i < sc->show_component.size(); i++ )
328 cmb_component2->addItem( (*scl) [ sc->show_component[ i ] ].name );
333 le_mw ->setEnabled(
true );
338 if ( sc->concentration == -1.0 )
340 le_conc->setText(
"from file" );
345 le_conc->setText( QString::number( sc->concentration,
'e', 4 ) );
346 sc->c0.radius.clear();
347 sc->c0.concentration.clear();
353 le_mw ->setEnabled(
false );
362 le_c0 ->setText (
"" );
366 vector<struct Association>* assoc = &
model.assoc_vector;
370 for (
uint i = 0; i < assoc->size(); i++ )
372 if ( (*assoc)[ i ].component2 ==
component
373 || (*assoc)[ i ].component3 ==
component )
375 le_keq ->setText( QString::number( (*assoc)[ i ].keq,
'e', 4 ) );
376 le_keq ->setEnabled(
true );
378 le_koff->setText( QString::number( (*assoc)[ i ].k_off,
'e', 4 ) );
385 le_keq->setEnabled (
false );
392 if ( sc->show_stoich > 0 )
397 le_stoich->setText( QString::number( sc->show_stoich ) );
399 (*scl) [ sc->show_component[ 0 ] ].mw * sc->show_stoich;
402 le_mw->setText( QString::number( sc->mw,
'e', 4 ) );
406 (*scl) [ sc->show_component[ 0 ] ].vbar20;
408 le_vbar->setText( QString::number( sc->vbar20,
'e', 4 ) );
412 else if ( sc->show_stoich == -1 )
417 le_stoich->setText(
"hetero-associating" );
419 sc->mw = (*scl) [ sc->show_component[ 0 ] ].mw +
420 (*scl) [ sc->show_component[ 1 ] ].mw;
422 le_mw->setText( QString::number( sc->mw,
'e', 4 ) );
424 double fraction1 = (*scl)[ sc->show_component[ 0 ] ].mw / sc->mw;
425 double fraction2 = (*scl)[ sc->show_component[ 1 ] ].mw / sc->mw;
427 sc->vbar20 = (*scl) [ sc->show_component[ 0 ] ].vbar20 * fraction1 +
428 (*scl) [ sc->show_component[ 1 ] ].vbar20 * fraction2;
430 le_vbar->setText( QString::number( sc->vbar20,
'e', 4 ) );
444 struct SimulationComponent* sc = &
model.component_vector[
component ];
446 double base = 0.75 /
AVOGADRO * sc->mw * sc->vbar20 * M_PI * M_PI;
448 sc->s = sc->mw * ( 1.0 - sc->vbar20 *
DENS_20W )
451 base = 2.0 * sc->s * sc->f_f0 * sc->vbar20 *
VISC_20W
457 le_sed ->setText( QString::number( sc->s,
'e', 4 ) );
458 le_diff->setText( QString::number( sc->D,
'e', 4 ) );
464 connect( vbar_dlg, SIGNAL( valueChanged(
double ) ),
471 if ( vbar > 0.0 )
le_vbar->setText( QString::number( vbar,
'f', 4 ) );
477 connect( hydro, SIGNAL( changed() ), SLOT(
update_shape() ) );
482 rb_rod ->setEnabled(
true );
494 struct SimulationComponent* sc = &
model.component_vector[
component ];
502 sc->shape =
"prolate";
509 sc->shape =
"oblate";
523 sc->shape =
"sphere";
535 rb_rod ->setEnabled(
true );
541 QMessageBox::information(
this,
542 tr(
"UltraScan Information" ),
543 tr(
"Please note:\n\n"
544 "The initial concentration file should have\n"
545 "the following format:\n\n"
546 "radius_value1 concentration_value1\n"
547 "radius_value2 concentration_value2\n"
548 "radius_value3 concentration_value3\n"
550 "radius values smaller than the meniscus or\n"
551 "larger than the bottom of the cell will be\n"
552 "excluded from the concentration vector." ) );
554 QString fn = QFileDialog::getOpenFileName(
557 if ( ! fn.isEmpty() )
559 le_c0->setText( fn );
563 if ( f.open( QIODevice::ReadOnly | QIODevice::Text ) )
566 QTextStream ts( &f );
568 struct SimulationComponent* sc = &
model.component_vector[
component ];
570 sc->c0.radius.clear();
571 sc->c0.concentration.clear();
576 le_conc->setText(
"from file" );
581 while ( ! ts.atEnd() )
588 sc->c0.radius .push_back( val1 );
589 sc->c0.concentration .push_back( val2 );
597 QMessageBox::warning(
this,
598 tr(
"UltraScan Warning" ),
599 tr(
"Please note:\n\n"
600 "UltraScan could not open the file specified\n" ) + fn );
607 QString fn = QFileDialog::getOpenFileName(
609 tr(
"Load Model File" ),
611 "*.model.?? *.model-?.?? *model-??.??" );
613 if ( ! fn.isEmpty() )
615 int code = US_FemGlobal::read_modelSystem(
model, fn );
620 QMessageBox::information(
this,
621 tr(
"Simulation Module"),
622 tr(
"Successfully loaded Model:" ) );
629 vector< struct SimulationComponent >* scl = &
model.component_vector;
631 for (
uint i = 0; i< (*scl).size(); i++)
641 sb_count->setRange( 1, (*scl).size() );
647 else if ( code == -40 )
649 QMessageBox::warning(
this,
650 tr(
"UltraScan Warning" ),
651 tr(
"Please note:\n\n"
652 "UltraScan could not open\n"
653 "the selected Model File!" ) );
656 else if ( code == 1 )
658 QMessageBox::warning(
this,
659 tr(
"UltraScan Warning" ),
660 tr(
"Sorry, the old-style models are no longer supported.\n\n"
661 "Please load a different model or create a new Model" ) );
664 else if ( code < 0 && code > -40 )
666 QMessageBox::warning(
this,
667 tr(
"UltraScan Warning" ),
668 tr(
"Please note:\n\n"
669 "There was an error reading\n"
670 "the selected Model File!\n\n"
671 "This file appears to be corrupted" ) );
680 QString fn = QFileDialog::getSaveFileName(
this,
681 tr(
"Save model as" ),
683 "*.model.?? *.model-?.?? *model-??.??" );
685 if ( ! fn.isEmpty() )
687 int k = fn.lastIndexOf(
"." );
690 if ( k != -1 ) fn.resize( k );
692 fn +=
".model-" + QString::number(
model.model ) +
".11";
698 int answer = QMessageBox::question(
this,
701 "This file exists already!\n\n"
702 "Do you want to overwrite it?" ),
703 QMessageBox::Yes, QMessageBox::No );
705 if ( answer == QMessageBox::No )
return;
708 int result = US_FemGlobal::write_modelSystem(
model, fn );
709 if ( result != 0 )
error( tr(
"Could not write file." ) );
722 if ( text ==
"" )
return;
724 struct SimulationComponent* sc = &
model.component_vector[
component ];
725 sc->s = text.toDouble();
730 if ( text ==
"" )
return;
732 struct SimulationComponent* sc = &
model.component_vector[
component ];
733 sc->D = text.toDouble();
738 if ( text ==
"" )
return;
740 struct SimulationComponent* sc = &
model.component_vector[
component ];
741 sc->extinction = text.toDouble();
746 if ( text ==
"" )
return;
748 struct SimulationComponent* sc = &
model.component_vector[
component ];
749 sc->sigma = text.toDouble();
754 if ( text ==
"" )
return;
756 struct SimulationComponent* sc = &
model.component_vector[
component ];
757 sc->delta = text.toDouble();
764 struct SimulationComponent* sc = &
model.component_vector[
component ];
765 double vbar = text.toDouble();
769 error( tr(
"The vbar value must be greater than 0.0" ) );
770 le_vbar->setText( QString::number( sc->vbar20,
'e', 4 ) );
779 struct SimulationComponent* sc = &
model.component_vector[
component ];
780 double mw = text.toDouble();
784 error( tr(
"The Molecular weight must be greater than 0.0" ) );
785 le_mw->setText( QString::number( sc->mw,
'e', 4 ) );
794 if ( text ==
"" )
return;
796 struct SimulationComponent* sc = &
model.component_vector[
component ];
797 sc->f_f0 = text.toDouble();
802 struct SimulationComponent* sc = &
model.component_vector[
component ];
804 if ( text ==
"" )
return;
806 if ( text ==
"from file")
807 sc->concentration = -1.0;
811 double concentration;
812 concentration = text.toDouble( &ok );
815 sc->concentration = concentration;
816 sc->c0.radius.clear();
817 sc->c0.concentration.clear();
819 le_c0->setText(
"" );
822 error( tr(
"The Partial Concentration field is invalid." ) );
830 if ( text ==
"" )
return;
832 vector< struct Association >* av = &
model.assoc_vector;
836 for (
uint i = 0; i < (*av).size(); i++ )
838 struct Association* as = &
model.assoc_vector[ i ];
844 if ( as->stoichiometry1 != as->stoichiometry2
845 || ( as->stoichiometry1 == 0
846 && as->stoichiometry2 == 0))
848 as->keq = text.toDouble();
856 if ( text ==
"" )
return;
858 vector< struct Association >* av = &
model.assoc_vector;
861 for (
uint i = 0; i < (*av).size(); i++ )
863 struct Association* as = &
model.assoc_vector[ i ];
869 if ( as->stoichiometry1 != as->stoichiometry2
870 || ( as->stoichiometry1 == 0
871 && as->stoichiometry2 == 0))
873 as->k_off = text.toDouble();
881 QMessageBox::warning(
this, tr(
"Model Error" ), message );
890 vector< struct Association >* av = &
model.assoc_vector;
891 vector< struct SimulationComponent >* cv = &
model.component_vector;
893 for (
uint i=0; i < (*av).size(); i++ )
895 struct Association* as = &
model.assoc_vector[ i ];
898 if ( as->stoichiometry2 > 0 && as->stoichiometry3 != 1 )
900 if ( fabs( (*cv) [ as->component2 ].mw -
901 ( (*cv) [ as->component1 ].mw *
902 as->stoichiometry2 / as->stoichiometry1
905 str = tr(
"The molecular weights of the reacting species\n"
906 "in reaction " ) + QString::number( i + 1 ) +
907 tr(
"do not agree:\n\n" )
909 + tr(
"Molecular weight of species 1: " ) +
910 QString::number( (*cv) [ as->component1 ].mw,
'e', 4 ) +
"\n"
912 + tr(
"Molecular weight of species 2:" ) +
913 QString::number( (*cv) [ as->component2 ].mw,
'e', 4 ) +
"\n"
915 + tr(
"Stoichiometry of reaction " ) +
916 QString::number( i + 1 ) + tr(
": MW(1) *" ) +
917 QString::number( as->stoichiometry2 ) + tr(
" = MW(2)\n\n" )
919 + tr(
"Please adjust either MW(1) or MW(2) before proceeding..." );
921 QMessageBox::warning(
this, tr(
"Model Definition Error" ), str );
927 if ( as->stoichiometry3 == 1 )
929 if ( fabs(
model.component_vector[ as->component3 ].mw -
930 model.component_vector[ as->component2 ].mw -
931 model.component_vector[ as->component1 ].mw ) > 1.0 )
934 str = tr(
"The molecular weights of the reacting species\n"
935 "in reaction ") + QString::number( i + 1 ) +
936 tr(
"do not agree:\n\n" )
938 + tr(
"Molecular weight of species 1: " ) +
939 QString::number( (*cv) [ as->component1 ].mw,
'e', 4 ) +
"\n"
941 + tr(
"Molecular weight of species 2: " ) +
942 QString::number( (*cv) [ as->component2 ].mw,
'e', 4 ) +
"\n"
944 + tr(
"Molecular weight of species 3: " ) +
945 QString::number( (*cv) [ as->component3 ].mw,
'e', 4 ) +
"\n"
947 + tr(
"Stoichiometry of reaction " ) +
948 QString::number( i + 1 ) + tr(
": MW(1) + MW(2) = MW(3)\n\n" )
950 + tr(
"Please adjust the molecular weight of the appropriate\n"
951 "component before proceeding..." );
953 QMessageBox::warning(
this, tr(
"Model Definition Error" ), str );