Optika GUI Toolik Version of the Day
example/AdvanceDependencyExample/main.cpp
Go to the documentation of this file.
00001 // @HEADER
00002 // ***********************************************************************
00003 // 
00004 //         Optika: A Tool For Developing Parameter Obtaining GUIs
00005 //                Copyright (2009) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, with Sandia Corporation, the 
00008 // U.S. Government retains certain rights in this software.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Kurtis Nusbaum (klnusbaum@gmail.com) 
00025 // 
00026 // ***********************************************************************
00027 // @HEADER
00028 #include "Optika_GUI.hpp"
00029 #include "Optika_SpecificParameterEntryValidators.hpp"
00030 #include "Teuchos_StandardParameterEntryValidators.hpp"
00031 #include "Optika_StandardDependencies.hpp"
00032 #include "Optika_DependencySheet.hpp"
00033 #include "Teuchos_FancyOStream.hpp"
00034 #include "Teuchos_VerboseObject.hpp"
00035 #include "Teuchos_XMLParameterListHelpers.hpp"
00036 #include "Optika_StandardConditions.hpp"
00037 
00038   /*
00039    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
00040    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!              ATTENTION              !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00041    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00042    * !!!!  PLEASE VIEW THE BASIC EXAMPLE AND DEPENDENCY EXAMPLE FIRST BEFORE READING THIS EXAMPLE.      !!!! 
00043    * !!!!  THEY PROVIDE FUNDAMENTAL KNOWLEDGE THAT WILL BE VERY HELPFUL IN UNDERSTANDING THIS EXAMPLE.  !!!!
00044    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00045    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00046    */ 
00047 
00048 //You'll notice we do things a little differently in this example from time to time. That's because I'm showing you now how to write more concise code.
00049 //I made all the previous examples very verbose because I wanted to desmonstrate what's going on, but here I'm gonna use some short cuts. I'll try to point them out
00050 //to you as I use them.  
00051 
00052 //using this namespaces means we don't have to type Teuchos:: and Optika:: before everything now.
00053 using namespace Teuchos;
00054 using namespace Optika;
00055 
00056 //ignore this for now. we'll use it later.
00057 int intFunc(int argument){
00058   return argument-9;
00059 }
00060 
00061 int main(int argc, char* argv[])
00062 {
00063   //Set up parameterlist and sublist
00064   //You can name ParameterLists to by passing their name as argument to the constructor.
00065   RCP<ParameterList> Tramonto_List = RCP<ParameterList>(new ParameterList("Root Tramonto List"));
00066   
00067   //Creating and accessing a sublist are pretty much one in the same. RCPs are good for you, so try to use them whenever you can.
00068   //Here, instead of just using sublist to access an already defined sublist, we'll actually usin it to create one.
00069   RCP<ParameterList> surfDefParams = sublist(Tramonto_List, "Surface Definition Parameters");
00070 
00071   //create our dependency sheet. This should look a little different to you. We're using rcp instead of RCP. I'll explain that in a bit.
00072   RCP<DependencySheet> depSheet1 = rcp(new DependencySheet(Tramonto_List));
00073 
00074 
00075   /*
00076    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
00077    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!   Part I: Using Dependencies in Tandem    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00078    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00079    */
00080 
00081   //Hoookay. So the goal of this first part is to setup the following parameters:
00082   // -Nsurf_types The number of surface types
00083   // -Ndim The number of dimensions
00084   // -Surf_Type An array specifying the type of surface for every surface type we have
00085   //
00086   // We're gonna need the following dependencies:
00087   // -The lengths of the array in Surf_Type is dependent upon how many surfaces we have
00088   // -The valid types of surfaces are dependent upon how many dimensions we have
00089   //
00090   // Let's get started!
00091 
00092 
00093   //Here we'll make the validator for the Nsurf_types parameter.
00094   //Teuchos::rcp is a short cut. We bascially don't have to template the rcp function now. It just knows what to template based on the argument it's given.
00095   //Normally the this line would read:
00096   //Teuchos::RCP<Optika::EnhancedNumberValidator<int> > nSurfTypesValidator  = Teuchos::RCP<Optika::EnhancedNumberValidator<int> >(new Optika::EnhancedNumberValidator<int>());
00097   //but by using the namespace stuff I should you above, and the rcp function, we can write it concisely like this:
00098   RCP<EnhancedNumberValidator<int> > nSurfTypesValidator  = rcp(new EnhancedNumberValidator<int>());
00099 
00100   //Let's say in this case you only want to set a minimum on the validator. We used the empty constructor above (which means no mins or maxs have been set), so we cna just set the min right now.
00101   nSurfTypesValidator->setMin(0);
00102   surfDefParams->set("Nsurf_types", 1, "The number of different surface types you have", nSurfTypesValidator);
00103 
00104   //Just setting the min and max now for the nDim Validator
00105   RCP<EnhancedNumberValidator<int> > nDimVali = rcp(new EnhancedNumberValidator<int>(1,3));
00106   surfDefParams->set("Ndim", 1, "Number of dimensions", nDimVali);
00107 
00108   //Now for the fun part. We're gonna set up the array. We want to use three different validators, so this array needs to implement: a validatord if Ndim=1, a validator if ndim=2, and a validator for when ndim=3.
00109   //Lets's start by making those three validators
00110   RCP<StringValidator> surfTypeVali1 = rcp<StringValidator>(new StringValidator(tuple<std::string>("Infinite Planar Wall", "Finite Planar Wall")));
00111   RCP<StringValidator> surfTypeVali2 = rcp<StringValidator>(new StringValidator(tuple<std::string>("Infinite Planar Wall", "Finite Planar Wall", "Colloids", "Pore", "Finite Pore", "Tapered Pore")));
00112   RCP<StringValidator> surfTypeVali3 = rcp<StringValidator>(new StringValidator(tuple<std::string>("Infinite Planar Wall", "Finite Planar Wall", "Colloids", "Atoms", "Point Atoms", "Finite Length Cylinder", 
00113   "Cylinder with Periodic function for the radius", "Pore", "Finite Pore", "Tapered Pore")));
00114 
00115   //Since we're gonna use them on an array we need to wrap an ArrayStringValidator around each of them. 
00116   //We could've done this in one step, but I think it looks cleaner this way, plus if you ever wanna use just these regular validators again, you can do that.
00117   RCP<ArrayStringValidator> arraySurfTypeVali1 = rcp(new ArrayStringValidator(surfTypeVali1));
00118   RCP<ArrayStringValidator> arraySurfTypeVali2 = rcp(new ArrayStringValidator(surfTypeVali2));
00119   RCP<ArrayStringValidator> arraySurfTypeVali3 = rcp(new ArrayStringValidator(surfTypeVali3));
00120 
00121   //setup the array in accordance with 1-d and 1 surfaces (the defaults we setup above). By doing it this way, 
00122   //if we ever change the default Value for Nsurf_types, we won't have to change it again down here. This is good because it'll also prevent errors (for instance when we
00123   //change the value above but now down here)
00124   Array<std::string> surfTypeArray(Teuchos::getValue<int>(surfDefParams->getEntry("Nsurf_types")), "Infinite Planar Wall");
00125 
00126   //same thing here. If we ever change Ndim, won't have to make any changes down here
00127   switch(Teuchos::getValue<int>(surfDefParams->getEntry("Ndim"))){
00128   case 1:
00129       surfDefParams->set("Surf_Type", surfTypeArray, "Array of surface types", arraySurfTypeVali1);
00130     break;
00131   case 2:
00132       surfDefParams->set("Surf_Type", surfTypeArray, "Array of surface types", arraySurfTypeVali2);
00133     break;
00134   case 3:
00135       surfDefParams->set("Surf_Type", surfTypeArray, "Array of surface types", arraySurfTypeVali3);
00136     break;
00137   default:
00138       surfDefParams->set("Surf_Type", surfTypeArray, "Array of surface types", arraySurfTypeVali1);
00139     break;
00140   }
00141 
00142   //Ok, so now for the really really fun part. setting up the dependencies. Let's do the ArrayLengthDependency first.
00143   //Since Nsurf_types and Ndim have the same parent list, we can use a short-cut for the constructor where we only have to
00144   //specify the parent list once.
00145   RCP<NumberArrayLengthDependency> surfTypeLengthDep = rcp(
00146     new NumberArrayLengthDependency(
00147       "Nsurf_types",
00148       "Surf_Type",
00149       surfDefParams
00150     )
00151   );
00152   
00153   //Now for one of the trickier dependencies, RangeValidatorDependency. First we make a map of ranges to validators. 
00154   //It's kind of overkill for our situation here because our ranges are small. But you get the idea, these ranges could be arbitrary in size.
00155   RangeValidatorDependency<int>::RangeToValidatorMap dimranges;
00156   dimranges[std::pair<int,int>(1,1)] = arraySurfTypeVali1;
00157   dimranges[std::pair<int,int>(2,2)] = arraySurfTypeVali2;
00158   dimranges[std::pair<int,int>(3,3)] = arraySurfTypeVali3;
00159   
00160   //Here we actually make the dependency. Take a look at the documentation for an explainiation of each argument
00161   RCP<RangeValidatorDependency<int> > 
00162   surfTypeValiDep = rcp(
00163     new RangeValidatorDependency<int>(
00164       "Ndim", 
00165       "Surf_Type", 
00166       surfDefParams,
00167       dimranges, 
00168       arraySurfTypeVali1
00169     )
00170   );
00171 
00172   //add dependencies
00173   depSheet1->addDependency(surfTypeLengthDep);
00174   depSheet1->addDependency(surfTypeValiDep);
00175 
00176   //BOOM! You're good to go. What all this will do is:
00177   //  -Use different validators on the array based on how many dimensions the user has selected
00178   //  -Adjust the length of the array based on how many surface types the user has specified.
00179   
00180 
00181   /*
00182    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
00183    * !!!!!!!!!!!!!!!!!!!!!!!!!!!   Part II: Multiple Dependenees and Dependents  !!!!!!!!!!!!!!!!!!!!!!!!!!!
00184    * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00185    */
00186 
00187   /*
00188    * Let's pause for a moment. Give yourself a pat on the back. You've made it really far in these examples!
00189    * So I'm gonna let you in on a little secret. Up until this point, all the dependencies you've seen have 
00190    * had only one dependee and one dependent, but the truth is all dependencies can actually have multiple 
00191    * dependents. And, if you use the super special ConditionVisualDependency, you can actually have multiple 
00192    * dependees! Holy Cow! I know right? Just blew you mind didn't I? Let's take a look and see how this all
00193    * works.
00194    */
00195 
00196   //Alright lets start off by creating a new parameter list with some more parameters.
00197   RCP<ParameterList> crazyDepList = sublist(Tramonto_List, "CRAZY AWESOME DEPENDENCY STUFF...list"); 
00198 
00199   //A number validator
00200   RCP<EnhancedNumberValidator<int> > scaleValidator = rcp(new EnhancedNumberValidator<int>(1,10));
00201 
00202   // a few parameters
00203   crazyDepList->set("Are you at all cool?", true, "Hey, it's a valid question.");
00204   crazyDepList->set("Sweetness", 7, "How sweet are you?", scaleValidator);
00205   crazyDepList->set("Awesomeness", 7, "How awesome are you?", scaleValidator);
00206   crazyDepList->set("Special parameter", "", "A parameter that only the coolest of the cool can see");
00207 
00208 
00209   //So first we'll tackle multiple dependents. Let's set up a BoolVisualDependency...WITH MULTIPLE DEPENDENTS!
00210   //First we make a map that maps the dependents to their parents.
00211   Dependency::ParameterParentMap dependents;
00212   dependents.insert(std::pair<std::string, Teuchos::RCP<Teuchos::ParameterList> >("Sweetness", crazyDepList));
00213   dependents.insert(std::pair<std::string, Teuchos::RCP<Teuchos::ParameterList> >("Awesomeness", crazyDepList));
00214 
00215   //Now we only wanna show these parameters if the user is at least some what cool. So well make the actuall dependency now.
00216   RCP<BoolVisualDependency> boolDep = rcp(new BoolVisualDependency("Are you at all cool?", crazyDepList, dependents, true));
00217   depSheet1->addDependency(boolDep);
00218 
00219   //There, now those two parameters will only show if the users is at least some what cool.
00220 
00221   //Alright, now that we've got that out off the way, it's time for the creme de la creme,
00222   //multiple dependees. This one was a doozy for me to implement and requires a little bit
00223   //of work for both of us.
00224 
00225   //There is only one type of dependency that allows for multiple dependees, the 
00226   //ConditionVisualDependency. The first thing we gotta do is make to make a condition.
00227   //This will actually take the place of our dependee. There are a few types of conditions.
00228   //The first and most basic condition is a ParameterCondition: it simply tests the
00229   //condition of a Parameter.
00230 
00231   //Here's a NumberCondition, which is a type of ParameterCondition. It simply checks to
00232   // see if the value of some number parameter is greater than 0. If greater than 0, 
00233   //the condition evaluates to true. Otherwise, it evaluates false.
00234   RCP<NumberCondition<int> > intCon1 = rcp(new NumberCondition<int>("Sweetness", crazyDepList, intFunc));
00235   RCP<NumberCondition<int> > intCon2 = rcp(new NumberCondition<int>("Awesomeness", crazyDepList, intFunc));
00236 
00237   //And here's a Bool Condition.
00238   RCP<BoolCondition> boolCon1 = rcp(new BoolCondition("Are you at all cool?", crazyDepList));
00239 
00240   //You can then combine conditions using a BinaryLogicalCondition. A BinaryLogicCondition
00241   //takes multiple conditions and evaluates them together in some fashion.
00242   
00243   //This is an And condition (an and? that sounds weird). If all the conditions it's assigned are true, it evaluates
00244   //to true. Just like a logical AND would. First we have to put all our conditions in a list.
00245   Condition::ConditionList conList1 = tuple<RCP<Condition> >(intCon1, intCon2, boolCon1);
00246 
00247   //And now we make the And Condition
00248   RCP<AndCondition> andCon1 = rcp(new AndCondition(conList1));
00249   
00250   //Now we're ready to make our ConditionVisualDependency.
00251   RCP<ConditionVisualDependency> conVis1 = rcp(new ConditionVisualDependency(andCon1, "Special parameter", crazyDepList, true));
00252 
00253   //There you have it. Now the Special parameter will only be shown if the Are you cool
00254   //at all parameter is true and both the Sweetness and Aweseomness parameters are set
00255   //to 10.
00256   depSheet1->addDependency(conVis1);
00257 
00258   //Now we run it and bask in all it's rediculous glory.
00259   getInput(Tramonto_List, depSheet1);
00260   
00261   return 0;
00262   /*
00263    * Alright, so a few final notes. 
00264    *  -All of the Parameter Conditions have a bool
00265    *   switch that allow you to say "evaluate to true if the condition is false".
00266    *  -In addition to the Bool and Number Parameter, there's also a String Parameter.
00267    *  -The other BinaryLogicConditions are Or and Equals.
00268    *  -There's also a NotCondition that negates the condition given to it.
00269    *  -You can chain together an arbitrary amount of Conditions. You could give an And condition
00270    *   a list of conditions that contained some Or coniditoins, which contained some Not conditions
00271    *   which contained some...we'll you get the idea.
00272    * That's it! You're now an Optika expert! I'm so proud of you :D Good job!
00273    */
00274 }
00275 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends