//****************************************************************************** //** SCATMECH: Polarized Light Scattering C++ Class Library //** //** File: inherit.cpp //** //** Thomas A. Germer //** Sensor Science Division, National Institute of Standards and Technology //** 100 Bureau Dr. Stop 8443; Gaithersburg, MD 20899-8443 //** Phone: (301) 975-2876 //** Email: thomas.germer@nist.gov //** //****************************************************************************** #include "scatmech.h" #include "inherit.h" #include "askuser.h" #include #include "filmtran.h" #include "scattabl.h" #include "dielfunc.h" using namespace std; namespace SCATMECH { bool Inheritance::show_model_mode=false; int Model::quiet=0; // // stringlist takes a string and parses it into a list of // strings without any whitespace... // void stringlist(const string& s,deque& result) { result.clear(); result.push_back(""); for (string::const_iterator ps=s.begin(); ps!=s.end(); ++ps) { if (isspace(*ps)) { if (!result.back().empty()) result.push_back(""); } else { result.back() += *ps; } } if (result.back().empty()) result.pop_back(); } // // Wrap_String takes a string and formats it into lines with an indentation. // void Wrap_String(const string& in,string& out,int indent,int width) { deque ls; stringlist(in,ls); string indenter="\n"; for (int i=0; i::const_iterator pls=ls.begin(); pls!=ls.end(); ++pls) { if (((int)pls->size()+currentwidth+1)>=wide) { out += indenter; currentwidth = pls->size()+1; } else { currentwidth += pls->size()+1; } out += *pls; out += space; } } // // display_descriptions returns a list of all of the class descriptions for a // Model and its child classes. // void display_descriptions(const Inheritance* inherit,const InheritanceList& ilist) { // Make sure the classes are registered... // Register_SCATMECH_Models(); // Print out header... SCATMECH_output << endl << "-- Available " << inherit->get_name() << " Classes --" << endl; // Pointer to the list elements... InheritanceList::const_iterator v; // Point v to the begining of the list... int jj = 0,i; // Find the longest length of names... for (v = ilist.begin(); v != ilist.end(); ++v) { int k = ((*v)->get_name()).size(); if ((*v)->children.size()>1 && (*v)!=inherit) { k+=7; } if (k>jj) jj=k; } for (i=0,v = ilist.begin(); v != ilist.end(); ++i,++v) { int k = ((*v)->get_name()).size(); ostringstream message; message << "(" << (char)(i+'A') << ") "; SCATMECH_output << message.str(); int menu=0; if ((*v)->children.size()>0 && (*v)!=inherit) { SCATMECH_output << " "; menu=7; } SCATMECH_output << (*v)->get_name(); if (Inheritance::show_model_mode) { for (int j=0; jget_description(),message,jj+6,80); SCATMECH_output << message; } SCATMECH_output << endl; } } // // get_model displays a list of a Model's child classes and asks the user to // chose among them... // // If top==true, then one is at the top of the class heirarchy. // Model* Inheritance:: get_model(bool top) const { // First...make sure all the SCATMECH models are registered... // Register_SCATMECH_Models(); while (1) { InheritanceList ilist; get_model_inheritance_list(ilist,2); // If there is only one element in the database, return that // element... if (ilist.size()==1) return ilist[0]->make(); InheritanceList::iterator v; for (v=ilist.begin(); v!=ilist.end(); ++v) { // Remove virtual elements that have no children or are the same as this... if ((*v)->is_virtual()&&((*v)->children.size()==0||(*v)==this)) { v = ilist.erase(v); } } // Print out the class names... display_descriptions(this,ilist); // Print out some other options... SCATMECH_output << endl; if (show_model_mode) { SCATMECH_output << "(?) Turn off descriptions" << endl; } else { SCATMECH_output << "(?) Turn on descriptions" << endl; } if (!top) SCATMECH_output << "(^) Return to previous menu" << endl; string response = AskUser("\nChoose one",string("A")); Model* model = get_named_model(response,true); if (model) { return model; } else if (response[0]=='?') { show_model_mode= !show_model_mode; } else if (response[0]=='^' && !top) { return (Model*)0; } else if (response.size()==1) { // Convert alphanumeric response to index number... int k = toupper(response[0])-'A'; // Make sure it is within range... if (k>=0&&k<(int)ilist.size()) { // Get that model's instance... InheritanceList::const_iterator v = ilist.begin(); advance(v,k); const Inheritance* ib = *v; if (ib==this) { return ib->make(); } else { Model* model = ib->get_model(false); // If okay... were done... if (model) { return model; } else { return 0; } } } } } } // // Inheritance::get_parameters gets a list of a model's parameters... // void Inheritance:: get_parameters(ModelParameterList& result,bool top) const { if (top) result.clear(); if (parent) { parent->get_parameters(result,false); } for (ModelParameterList::const_iterator p=parameters.begin(); p!=parameters.end(); ++p) { result.push_back(*p); } } // // Inheritance::get_modelparameter searches the list of parameters associated with // the model, and returns the information about the parameter... // const ModelParameterBase* Inheritance::get_modelparameter(const std::string& param) const { ModelParameterList mpl = get_parameters(); for (ModelParameterList::const_iterator p=parameters.begin(); p!=parameters.end(); ++p) { if ((*p)->name == param) return (*p); } return NULL; } // // Inheritance::get_model_inheritance_list gets the list of all models inherited by // a specific model... // void Inheritance:: get_model_inheritance_list(InheritanceList& result,int option) const { if (option) { result.clear(); result.push_back(this); } for (InheritanceList::const_iterator v=children.begin(); v != children.end(); ++v) { result.push_back(*v); if (option!=2) (*v)->get_model_inheritance_list(result,0); } } // // Inheritance::get_named_model returns an instantiation of a class named model. // Model* Inheritance:: get_named_model(const std::string& model,bool nothrow) const { const Inheritance *inheritance = get_named_inheritance(model,nothrow); if (inheritance) { if (!inheritance->virt) return inheritance->make(); } if (!nothrow) throw SCATMECH_exception("Model " + model + " is not instantiable"); return (Model*)0; } const Inheritance* Inheritance:: get_named_inheritance(const std::string& model,bool nothrow) const { InheritanceList ilist; get_model_inheritance_list(ilist); for (InheritanceList::const_iterator v=ilist.begin(); v!=ilist.end(); ++v) { // If that model's name matches, return its inheritance... if (model==(*v)->get_name()) return *v; } // It was never found if it got here... if (!nothrow) { ostringstream os; os << string("Cannot find a " + name + " named " + model) << endl; os << "Valid choices are" << endl; for (InheritanceList::const_iterator v = ilist.begin(); v!=ilist.end(); ++v) { os << " " << (*v)->get_name() << endl; } throw SCATMECH_exception(os.str()); } else { return (const Inheritance* )0; } } ModelParameterBase:: ModelParameterBase(const std::string& _name, const std::string& _description, const std::string& _type, const std::string& _defaultvalue, int _recalclevel, Inheritance& inherit) : ParameterInfo(_name,_description,_type,_defaultvalue,_recalclevel) { inherit.add_parameter(this); } void Model:: set_parameter_base(const std::string& parameter,const std::string& value) { if (parameter=="recalc") { recalc |= from_string(value); } else if (parameter=="quiet") { int _quiet = from_string(value); set_quiet(_quiet); } else { ModelParameterList mplist = get_inheritance().get_parameters(); string _parameter = parameter; string _subparameter=""; int pos = _parameter.find('.'); if (pos!=string::npos) { _parameter = parameter.substr(0,pos); _subparameter = parameter.substr(pos+1,parameter.size()); if (_subparameter=="") error("Subparameter missing: " + parameter); } ModelParameterList::iterator q; for (q = mplist.begin(); q != mplist.end(); ++q) { const ModelParameterBase *param = *q; string name = param->name; if (_parameter==name) { if (value!="default") { param->set_parameter(this,_subparameter,value); } else { if (param->defaultvalue!="") { param->set_parameter(this,_subparameter,param->defaultvalue); } } return; } } error("Unknown parameter " + parameter + " in set_parameter_base"); } } string Model:: get_parameter_base(const string& parameter) const { ostringstream result; if (parameter=="recalc") { result << recalc; } else if (parameter=="quiet") { result << get_quiet(); } else { ModelParameterList mplist = get_inheritance().get_parameters(); string _parameter = parameter; string _subparameter=""; int pos = _parameter.find('.'); if (pos!=string::npos) { _parameter = parameter.substr(0,pos); _subparameter = parameter.substr(pos+1,parameter.size()); if (_subparameter=="") error("Subparameter missing: " + parameter); } ModelParameterList::iterator q; for (q = mplist.begin(); q != mplist.end(); ++q) { const ModelParameterBase *param = *q; string name = param->name; if (_parameter==name) { result << param->get_parameter(this,_subparameter); return result.str(); } } error("Unknown parameter " + parameter + " in get_parameter"); } return result.str(); } ParameterInfo Model:: get_parameter_info(const string& parameter) const { ParameterInfo result; if (parameter=="recalc") { result.name="recalc"; result.type="int"; } else if (parameter=="quiet") { result.name="quiet"; result.type="int"; } else { ModelParameterList mplist = get_inheritance().get_parameters(); string _parameter = parameter; string _subparameter=""; int pos = _parameter.find('.'); if (pos!=string::npos) { _parameter = parameter.substr(0,pos); _subparameter = parameter.substr(pos+1,parameter.size()); if (_subparameter=="") error("Subparameter missing: " + parameter); } ModelParameterList::iterator q; for (q = mplist.begin(); q != mplist.end(); ++q) { const ModelParameterBase *param = *q; string name = param->name; if (_parameter==name) { if (_subparameter.size()==0) { result = *param; } else { if (param->get_inheritance()!=NULL) { Model* m =(Model*)(param->get_ptr(this)); result = m->get_parameter_info(_subparameter); } else { error("Parameter " + parameter + " does not have subparameters"); } } return result; } } error("Unknown parameter " + parameter + " in get_parameter_info"); } return result; } void Model:: init() { ModelParameterList mplist = get_inheritance().get_parameters(); ModelParameterList::iterator q; for (q = mplist.begin(); q != mplist.end(); ++q) { const ModelParameterBase *param = *q; if (param->defaultvalue!="") { param->set_parameter(this,"",param->defaultvalue); } } } void Model:: AskUser() { init(); ModelParameterList mplist = get_inheritance().get_parameters(); ModelParameterList::iterator q; for (q = mplist.begin(); q != mplist.end(); ++q) { const ModelParameterBase* param = *q; param->AskUser(this); } } void Model:: get_parameter_names_base(StringList& plist, const string& prefix) const { ModelParameterList mpl = get_inheritance().get_parameters(); for (ModelParameterList::iterator q=mpl.begin(); q!=mpl.end(); ++q) { plist.push_back(prefix+(*q)->name); if ((*q)->get_inheritance(this)!=NULL) { Model* m = (Model*)((*q)->get_ptr(this)); m->get_parameter_names_base(plist,prefix+(*q)->name+'.'); } } } void Model:: print_parameters_base(ostream& os,const string& prefix) const { //StringList vlist; //get_parameter_names(vlist); //StringList::iterator p; //for (p=vlist.begin();p!=vlist.end();++p) { // ParameterInfo info = get_parameter_info(*p); // os << *p << " = " << get_parameter(*p) // << " (" << info.type << ": " // << info.description << ')' << endl; //} ModelParameterList mplist = get_inheritance().get_parameters(); for (ModelParameterList::iterator p = mplist.begin(); p!=mplist.end(); ++p) { const ModelParameterBase *param = *p; string name = param->name; string type = param->type; string description = param->description; string newprefix = (prefix != "") ? (prefix + ".") : (""); if (param->get_inheritance(this)==NULL) { os << newprefix << name << " = " << param->get_parameter(this,"") << " (" << type << ": " << description << ")" << endl; } else { os << newprefix << name << " = " << param->get_parameter(this,"") << " (" << type << ": " << description << ")" << endl; ((Model*)(param->get_ptr(this)))->print_parameters_base(os,newprefix+name); } } } void Model:: error(const string& message) const { string message2 = "Error in class " + get_inheritance().get_name() + ": " + message + '\n'; ostringstream out; print_parameters(out); throw SCATMECH_exception(message2+out.str()); } Inheritance Model::inheritance("Model","Generalized Model",0,0); } // namespace SCATMECH