SALSA Analysis Modules
module_functions.c
Go to the documentation of this file.
00001 /*! \defgroup categories Files with defined categories */
00002 /*! \defgroup functions User-accessible functions */
00003 /*! \defgroup implementation Functions only of use to the implementation */
00004 
00005 /*! \file module_functions.c \ingroup functions \anchor modules
00006   \brief User functions for accessing the analysis modules
00007 
00008   Analysis modules need to be defined with RegisterModule(), after which
00009   they can be invoked with ComputeQuantity(). See also HasQuantity().
00010   The functions AnaModRegisterStandardModules() installs all standard 
00011   available modules.
00012 
00013   There are utility functions for querying the existence of modules:
00014   GetCategories(), CategoryGetModules(),
00015   HasComputeCategory(), HasComputeModule().
00016 
00017   Utility functions: QuantityAsString(), GetDataType(), GetDataID(),
00018   GetCategoryIndex(), GetModuleIndex().
00019  */
00020 
00021 /*! \mainpage AnaMod : an Analysis Modules library
00022   \section Introduction
00023 
00024   This is a library of modules that can compute various properties of
00025   a matrix. The code heavily uses the Petsc library, and the matrix has to
00026   be stored in Petsc format.
00027 
00028   Modules are divided into several categories, each defined in its own file.
00029   Typical categories are for structural information, normlike properties, 
00030   spectral estimate. A number of modules have been supplied, but because of
00031   the modular setup, it is easy to add new modules.
00032  
00033   This library was written for use in the Salsa project
00034   (http://icl.cs.utk.edu/salsa/), but can be
00035   used independently of it. If the Salsa NMD library 
00036   (http://icl.cs.utk.edu/salsa/software/index.html) is present (see the
00037   installation instructions), its data types are used.
00038 
00039   \subpage installation
00040 
00041   \subpage usage
00042 
00043   \subpage list
00044 
00045   \subpage customization 
00046 
00047   \subpage getall
00048 
00049   \ref tracing
00050 
00051   \author Victor Eijkhout
00052   \version 1.91
00053   \date unreleased
00054 
00055   Change log:
00056   - 2.0 : internals revamped, bug fixes in simple:diagonal-dominance
00057   - 1.91 : spectrum modules with ";re" and ";im" have been renamed
00058     to "-re" and "-im" for MySQL sake.
00059   - 1.9 : fixed memory leak in dummy row computation
00060   - 1.8.a : added the stats.c file
00061   - 1.8 : much code cleanup; unit tests to ensure proper operation
00062   - 1.7 : handling of arrays is now completely changed. most routines
00063     have acquired an explicit array length parameter
00064   - 1.6 : handling of the location of slepc and such. Make sure to check
00065     the Make.inc.example file
00066   - 1.5 :
00067     - module-specific options
00068     - \c -anamod_force now has underscore for consistency
00069     - several spectrum imaginary parts were miscomputed
00070     - added SLEPC computation of spectrum
00071   - 1.4 : 
00072     - improved trace mode; incompatible change in the prototype
00073     of the trace function
00074     - removed a11 module
00075   - 1.3 :
00076     - trace mode added (see \ref tracing)
00077     - renamed header files: module_functions.h -> anamod.h ,
00078       module_types.h -> anamodtypes.h , nmdmodules.h -> anamodsalsamodules.h ,
00079       module_utils.h -> anamodutils.h
00080   - 1.2 : 
00081     - added runtime options: forced computation of single-processor
00082     modules in parallel context, of expensive modules
00083     - bug fix of aux:a11.
00084     - compatibility with gcc4 (ignoring 'const' used to be a warning,
00085     it's now an error)
00086   - 1.1 : correct handling of parallelism
00087 */
00088 
00089 /*! \page installation Installation and compiling programs
00090 
00091   \section Installation
00092 
00093   See the README file. The main thing is that you need to have Petsc installed.
00094 
00095   \section compilation Compilation of user programs
00096 
00097   The easiest way to compile a program that uses the Salsa Analysis Modules
00098   is to have these includes in your makefile:
00099 \verbatim
00100 include $(PETSC_DIR)/bmake/common/variables
00101 include $(SALSA_MODULES_DIR)/Make.inc
00102 \endverbatim
00103 
00104   The following flags for your C compiler are
00105   - line 1: Petsc option
00106   - line 2: Analysis Modules options
00107   - line 3: (optionally) options for using the NMD library; HAVE_NMD_DEFINE 
00108     has to be "-DHAVE_NMD" if the library is present
00109 \verbatim
00110 CFLAGS = \
00111     $(PETSC_INCLUDE) $(COPTFLAGS) \
00112     -I$(SALSA_MODULES_DIR) \
00113     $(HAVE_NMD_DEFINE) -I$(LIBNMD_INCLUDE_DIR) -I$(LIBXMLSC_INCLUDE_DIR)
00114 \endverbatim
00115 
00116   Your program needs to include the following header files:
00117 \verbatim
00118 #include "anamod.h"
00119 #include "anamodsalsamodules.h"
00120 \endverbatim
00121 
00122   The following link line brings together all the needed libraries
00123   (add libnmd if required)
00124 \verbatim
00125 yourprog : 
00126         $(CLINKER) -o yourprog yourprog.o \
00127             -L$(SALSA_MODULES_LIB_DIR) -lsalsamodules -lothermodules \
00128             $(PETSC_LIB)
00129 \endverbatim
00130 */
00131 
00132 /*! \page usage Use of the analysis modules
00133 
00134   \section init Library Initialization
00135 
00136   There are calls AnaModInitialize() and AnaModFinalize() which do 
00137   global allocation. These are necessary.
00138 
00139   \section registration Category registration
00140 
00141   Every category needs to be registered before use with a call
00142   
00143   Register<Category>Modules();
00144 
00145   where the available categores are \ref icmk, \ref iprs, \ref jpl, 
00146   \ref normal, \ref simple,
00147   \ref spectrum, \ref structure, \ref variance.
00148   The functions AnaModRegisterStandardModules() installs all standard 
00149   available modules.
00150 
00151   \section compute Quantity computation
00152 
00153   After registring a category, its elements can be computed as
00154 
00155   PetscErrorCode ComputeQuantity(char *cat,char *cmp,Mat A,AnalysisItem *res,PetscTruth *success);
00156 
00157   with
00158   -# the name of the category
00159   -# the name of the element
00160   -# the matrix
00161   -# the result
00162   -# a success indicator
00163 
00164   For the main user functions, see \ref modules "the module functions file"
00165 
00166   Commandline options are discussed in section \ref options.
00167 
00168   \section types Datatypes
00169 
00170   The \c AnalysisDataType type is an integer. To get a printable name
00171   of the datatype, use AnaModGetTypeName() or AnaModGetTypeMySQLName().
00172  */
00173 
00174 /*! \page list List of the available modules
00175 
00176   \subpage icmk
00177 
00178   \subpage iprs
00179 
00180   \subpage jpl
00181 
00182   \subpage normal
00183 
00184   \subpage simple
00185 
00186   \subpage spectrum
00187 
00188   \subpage structure
00189 
00190   \subpage variance
00191 */
00192 
00193 /*! \page customization Customization
00194 
00195   While this library comes with a number of categories supplied, you can 
00196   write your own category, taking any of the given ones as example.
00197 
00198   Each analysis module has to have the following prototype:
00199 \verbatim
00200 static PetscErrorCode MyModule(Mat A,AnalysisItem *rv,PetscTruth *flg)
00201 \endverbatim
00202   where
00203   - \c A is the input matrix
00204   - \c rv is the return value
00205   - \c flg is true if the quantity was succesfully computed, false otherwise
00206 
00207   The module return code should be 0 for success, anything else for
00208   (catastrophic) failure. A simple failure (or refusal) to compute should
00209   be indicated through the \c flg variable.
00210 
00211   The modules (including the return type of their computed quantities)
00212   are declared to the system by calling routine
00213 \verbatim
00214 PetscErrorCode RegisterMyModules()
00215 {
00216   PetscErrorCode ierr;
00217   PetscFunctionBegin;
00218 
00219   ierr = RegisterModule
00220     ("mycategory","mymodule",THERESULTTYPE,&MyModule); CHKERRQ(ierr);
00221   ....
00222 \endverbatim
00223   or you can make the invidual calls to RegisterModule(). 
00224   See \ref types and \ref arraytypes.
00225 */
00226 
00227 /*! \page arraytypes Array type handling
00228 
00229   The actual types are listed in \ref types ; here are some semantic issues
00230   pertaining to array types.
00231 
00232   The uniform calling structure of the modules allows only one parameter
00233   to be returned. This is a problem only for array types: we want both the 
00234   array data and the length of the array. Hence we adopt the convention that
00235   every array is longer by one element than necessary, and the zero element
00236   contains the length of the array proper. That is, to store 5 elements, 
00237   6 elements are allocated, and the zero element contains the number '5'.
00238 
00239   If, in this documentation, we refer to location array[i], we will
00240   take this to mean location `i' after the size element. Zero-based
00241   indexing is used.
00242 */
00243 
00244 /*! \page attached Attached quantities in Petsc
00245   
00246   Petsc has a mechanism where quantities can be attached to objects. 
00247   For instance, integers can be attached and queried with
00248   PetscObjectComposedDataSetInt() and PetscObjectComposedDataGetInt().
00249   Such data is attached together with the current state of the object,
00250   which means that it will be properly invalidated if the object is 
00251   altered.
00252 
00253   This composition mechanism is used in this analysis modules package.
00254   There are many quantities (such as the norms of the symmetric and 
00255   anti-symmetric part of the matrix) that can be computed together at
00256   practically the same cost as either one alone. Thus, when one is requested
00257   by calling ComputeQuantity(), the other one will be compute as well,
00258   and attached to the matrix object. A call to ComputeQuantity()
00259   for this second quantity will then just return the attached number,
00260   and not be computed separately.
00261 
00262   The routine HasQuantity() can query which quantities are already attached.
00263 
00264   As a result of the use of attached quantities, benchmarking the AnaMod
00265   modules is a bit tricky. You can forced computation of the requested 
00266   quantities by calling PetscObjectIncreaseState() on the matrix object
00267   after each call to ComputeQuantity().
00268  */
00269 #include <stdlib.h>
00270 #include <string.h>
00271 #include "anamod.h"
00272 #include "anamodsalsamodules.h"
00273 
00274 static struct{int id; const char *name,*mysqlname;} anamodtypenames[5];
00275 static int nAnaModTypeNames;
00276 static int AnaModIsInitialized = 0;
00277 
00278 int ncategories=0;
00279 categoryobject *categoryobjects = NULL;
00280 
00281 #undef __FUNCT__
00282 #define __FUNCT__ "AnaModInitialize"
00283 /*! Initializatin for AnaMod. See also AnaModFinalize() */
00284 PetscErrorCode AnaModInitialize()
00285 {
00286   PetscErrorCode ierr;
00287 
00288   PetscFunctionBegin;
00289   ierr = AllocCategoryObjects(); CHKERRQ(ierr);
00290 
00291   anamodtypenames[0].id = NMDString;
00292   anamodtypenames[0].name="string"; 
00293   anamodtypenames[0].mysqlname="VARCHAR(256)";
00294 
00295   anamodtypenames[1].id = NMDInt;
00296   anamodtypenames[1].name="int"; 
00297   anamodtypenames[1].mysqlname="INTEGER";
00298 
00299   anamodtypenames[2].id = NMDReal;
00300   anamodtypenames[2].name="real"; 
00301   anamodtypenames[2].mysqlname="DOUBLE";
00302 
00303   anamodtypenames[3].id = NMDIntarray;
00304   anamodtypenames[3].name="intarray"; 
00305   anamodtypenames[3].mysqlname="VARCHAR(1024)";
00306 
00307   anamodtypenames[4].id = NMDRealarray;
00308   anamodtypenames[4].name="realarray";
00309   anamodtypenames[4].mysqlname="VARCHAR(1024)";
00310 
00311   AnaModIsInitialized = 1; nAnaModTypeNames = 5;
00312   PetscFunctionReturn(0);
00313 }
00314 
00315 #undef __FUNCT__
00316 #define __FUNCT__ "AnaModFinalize"
00317 /*! Finalization for AnaMod. See also AnaModInitialize() */
00318 PetscErrorCode AnaModFinalize()
00319 {
00320   PetscErrorCode ierr;
00321   PetscFunctionBegin;
00322   ierr = FreeCategoryObjects(); CHKERRQ(ierr);
00323   PetscFunctionReturn(0);
00324 }
00325 
00326 #undef __FUNCT__
00327 #define __FUNCT__ "AnaModGetTypeName"
00328 PetscErrorCode AnaModGetTypeName(int id,const char **name)
00329 {
00330   int i;
00331   PetscFunctionBegin;
00332   for (i=0; i<nAnaModTypeNames; i++) {
00333     if (id==anamodtypenames[i].id) {
00334       *name = (char*)anamodtypenames[i].name; goto exit;
00335     }
00336   }
00337   SETERRQ1(1,"Unknown AnaMod datatype %d",id);
00338  exit:
00339   PetscFunctionReturn(0);
00340 }
00341 
00342 #undef __FUNCT__
00343 #define __FUNCT__ "AnaModGetTypeMySQLName"
00344 PetscErrorCode AnaModGetTypeMySQLName(int id,const char **name)
00345 {
00346   int i;
00347   PetscFunctionBegin;
00348   if (AnaModIsInitialized<1) 
00349     SETERRQ(1,"AnaMod has not been not formally initialized.\nInsert a call to AnaModInitialize() in your code");
00350   for (i=0; i<nAnaModTypeNames; i++) {
00351     if (id==anamodtypenames[i].id) {
00352       *name = (char*)anamodtypenames[i].mysqlname; goto exit;
00353     }
00354   }
00355   SETERRQ1(1,"Unknown AnaMod datatype %d",id);
00356  exit:
00357   PetscFunctionReturn(0);
00358 }
00359 
00360 #undef __FUNCT__
00361 #define __FUNCT__ "RegisterModule"
00362 /*!
00363   Register a new computational module
00364 
00365   This adds a computational routine (the \c f argument) into the modules
00366   database under the given category (\c cat) and module (\c cmp) label.
00367   If the category does not exist yet, it is created.
00368   
00369   The available types are defined in \ref types "anamodtypes.h"
00370 
00371   If the routine is NULL, only the category and component are created.
00372 
00373   Routine prototype:
00374   - problem (input)
00375   - item (output)
00376   - array length (output)
00377   - success (output)
00378 
00379   See also HasComputeModule(), ComputeQuantity().
00380 */
00381 PetscErrorCode RegisterModule
00382 (const char *cat,const char *cmp,AnalysisDataType type,
00383  PetscErrorCode(*f)(AnaModNumericalProblem,AnalysisItem*,int*,PetscTruth*))
00384 {
00385   int id; PetscErrorCode ierr;
00386   PetscFunctionBegin;
00387 
00388   if (!AnaModIsInitialized)
00389     SETERRQ(1,"AnaMod not initialized: insert call to AnaModInitialize()\n");
00390   /*
00391    * Check for illegal names
00392    */
00393   if (strchr(cat,':')) SETERRQ(1,"Illegal colon in category name");
00394   if (strchr(cmp,':')) SETERRQ(1,"Illegal colon in component name");
00395 
00396 #if defined(ANAMODDEBUG)
00397   printf("Defining module <%s:%s>\n",cat,cmp);
00398 #endif
00399   ierr = PetscObjectComposedDataRegister(&id); CHKERRQ(ierr);
00400   ierr = CategoryComponentSetModule(cat,cmp,type,id,f); CHKERRQ(ierr);
00401 
00402   PetscFunctionReturn(0);
00403 }
00404 
00405 #undef __FUNCT__
00406 #define __FUNCT__ "DeRegisterCategory"
00407 /*! Deallocate the storage for a particular category of analysis modules.
00408  No longer needed. */
00409 PetscErrorCode DeRegisterCategory(const char *cat)
00410 {
00411 /*   categoryobject catg; */
00412 /*   PetscTruth flg; PetscErrorCode ierr; */
00413   PetscFunctionBegin;
00414 
00415   printf("Please remove use of legacy function DeRegisterCategory\n");
00416 /*   ierr = GetCategory(cat,&catg,&flg); CHKERRQ(ierr); */
00417 /*   if (!flg) SETERRQ1(1,"Invalid category <%s>",cat); */
00418 /*   ierr = DestroyCategoryObject(catg); CHKERRQ(ierr); */
00419   PetscFunctionReturn(0);
00420 }
00421 
00422 #undef __FUNCT__
00423 #define __FUNCT__ "DeregisterModules"
00424 /*! This function is no longer needed */
00425 PetscErrorCode DeregisterModules()
00426 {
00427 /*   int icat,ncat; const char **cat; */
00428 /*   PetscErrorCode ierr; */
00429   PetscFunctionBegin;
00430   printf("Please remove use of legacy function DeRegisterModules\n");
00431 /*   ierr = GetCategories(&ncat,&cat); CHKERRQ(ierr); */
00432 /*   for (icat=0; icat<ncat; icat++) { */
00433 /*     ierr = DeRegisterCategory(cat[icat]); CHKERRQ(ierr); */
00434 /*   } */
00435   PetscFunctionReturn(0);
00436 }
00437 
00438 /*! \page getall Bulk computation
00439   After the modules have been installed, the typical user will only
00440   use ComputeQuantity(). However, for purposes of reporting and such
00441   it may be necessary to query systematicaly the available modules.
00442   This can be done with GetCategories() and CategoryGetModules().
00443 
00444   Related: HasComputeCategory(), HasComputeModule().
00445 
00446   Auxiliary routines: GetCategoryIndex(), GetModuleIndex().
00447 */
00448 #undef __FUNCT__
00449 #define __FUNCT__ "HasComputeCategory"
00450 /*! Query whether a specified category has been declared. */
00451 PetscErrorCode HasComputeCategory(const char *cat,PetscTruth *f)
00452 {
00453   PetscErrorCode ierr;
00454   PetscFunctionBegin;
00455   ierr = GetCategory(cat,PETSC_NULL,f); CHKERRQ(ierr);
00456   PetscFunctionReturn(0);
00457 }
00458 
00459 #undef __FUNCT__
00460 #define __FUNCT__ "HasComputeModule"
00461 /*!
00462   Query whether a specified module exists inside a specified category. 
00463   The category need not itself have been declared.
00464  */
00465 PetscErrorCode HasComputeModule(const char *cat,const char *cmp,PetscTruth *f)
00466 {
00467   categoryobject catg; PetscErrorCode ierr;
00468   PetscFunctionBegin;
00469   ierr = GetCategory(cat,&catg,f); CHKERRQ(ierr);
00470   if (*f) {
00471     ierr = CategoryGetComponent(catg,cmp,PETSC_NULL,f); CHKERRQ(ierr);
00472   }
00473   PetscFunctionReturn(0);
00474 }
00475 
00476 #define MODE_RETRIEVE 1
00477 #define MODE_COMPUTE 0
00478 #undef __FUNCT__
00479 #define __FUNCT__ "ComputeOrRetrieveQuantity"
00480 static PetscErrorCode ComputeOrRetrieveQuantity
00481 (AnaModNumericalProblem prob,const char *cat,const char *cmp,
00482  AnalysisItem *res,int *rreslen,PetscTruth *success,int mode)
00483 {
00484   categoryobject catg; componentobject cmpt; PetscTruth flg,trace;
00485   int reslen; PetscErrorCode ierr;
00486   
00487   PetscFunctionBegin;
00488   ierr = AnaModHasTrace(&trace); CHKERRQ(ierr);
00489 
00490   /*
00491    * Get the module and compute
00492    */
00493   ierr = GetCategory(cat,&catg,&flg); CHKERRQ(ierr);
00494   if (!flg) SETERRQ1(1,"Could not find category <%s>",cat);
00495   ierr = CategoryGetComponent(catg,cmp,&cmpt,&flg); CHKERRQ(ierr);
00496   if (!flg) SETERRQ1(1,"Could not find component <%s>",cmp);
00497   if (mode==MODE_COMPUTE) {
00498     ierr = ComponentCompute(cmpt,prob,res,&reslen,&flg); CHKERRQ(ierr);
00499   } else if (mode==MODE_RETRIEVE) {
00500     ierr = ComponentRetrieve(cmpt,prob,res,&reslen,&flg); CHKERRQ(ierr);
00501   } else SETERRQ(1,"Invalid mode");
00502 
00503   if (rreslen) *rreslen = reslen;
00504   if (success) *success = flg;
00505 
00506   /*
00507    * Tracing
00508    */
00509   if (trace) {
00510     if (flg) {
00511       char *string; PetscTruth trace_arrays; AnalysisDataType t;
00512 
00513       ierr = ComponentGetType(cmpt,&t); CHKERRQ(ierr);
00514       ierr = AnaModTraceArrays(&trace_arrays); CHKERRQ(ierr);
00515       if (t<ANALYSISINTARRAY || trace_arrays) {
00516         ierr = QuantityAsString(res,t,(const char**)&string); CHKERRQ(ierr);
00517         ierr = AnaModTraceMessage
00518           ("Anamod computed <%s:%s> = <%s>\n",cat,cmp,string); CHKERRQ(ierr);
00519         ierr = PetscFree(string); CHKERRQ(ierr);
00520       }
00521     } else {
00522       ierr = AnaModTraceMessage
00523         ("Anamod failed to compute <%s:%s>\n",cat,cmp); CHKERRQ(ierr);
00524     }
00525   }
00526 
00527   PetscFunctionReturn(0);
00528 }
00529 
00530 #undef __FUNCT__
00531 #define __FUNCT__ "ComputeQuantity"
00532 /*!
00533   Compute a computational module from a certain category. 
00534 
00535   Argument:
00536   -# the name of the category (see GetCategories())
00537   -# the name of the module (see CategoryGetModules())
00538   -# the matrix
00539   -# a pointer to the result. This is given as \c "(AnalysisItem*)&res" ;
00540     see \ref types for the definition of the AnalysisItem data type
00541   -# the length of the result if the result is an array. This
00542     argument can be NULL.
00543   -# a success indicator. Failure can have obvious causes,
00544     such as breakdown of an internal routine, but the routine can also
00545     refuse to compute a quantity if doing so would be too expensive (see
00546     an example in the \ref normal category).
00547 
00548   A call to this routine need not
00549   involve actual computation: the requested quantity can already be attached
00550   to the matrix object (see \ref attached "attached quantities" for details).
00551   This mechanism is used in all the standard modules that come with the 
00552   AnaMod package.
00553 
00554   The workings of this function can be traced by specifying a trace function;
00555   see \ref tracing.
00556 */
00557 PetscErrorCode ComputeQuantity
00558 (AnaModNumericalProblem prob,const char *cat,const char *cmp,
00559  AnalysisItem *res,int *rreslen,PetscTruth *success)
00560 {
00561   PetscErrorCode ierr;
00562   PetscFunctionBegin;
00563   if (!AnaModIsInitialized)
00564     SETERRQ(1,"AnaMod not initialized: insert call to AnaModInitialize()\n");
00565   ierr = ComputeOrRetrieveQuantity
00566     (prob,cat,cmp,res,rreslen,success,MODE_COMPUTE); CHKERRQ(ierr);
00567   PetscFunctionReturn(0);
00568 }
00569 
00570 #undef __FUNCT__
00571 #define __FUNCT__ "RetrieveQuantity"
00572 /*! Retrieve an attached quantity. 
00573   Note that this does not report the length of arrays; you have to 
00574   know under which name this is stored.
00575 */
00576 PetscErrorCode RetrieveQuantity
00577 (AnaModNumericalProblem prob,const char *cat,const char *cmp,
00578  AnalysisItem *res,int *rreslen,PetscTruth *success)
00579 {
00580   PetscErrorCode ierr;
00581   PetscFunctionBegin;
00582   ierr = ComputeOrRetrieveQuantity
00583     (prob,cat,cmp,res,rreslen,success,MODE_RETRIEVE); CHKERRQ(ierr);
00584   PetscFunctionReturn(0);
00585 }
00586  
00587 #undef __FUNCT__
00588 #define __FUNCT__ "GetDataID"
00589  PetscErrorCode GetDataID(const char *cat,const char *cmp,int *id,PetscTruth *f)
00590  {
00591    categoryobject catg; componentobject cmpt; PetscTruth flg;
00592   PetscErrorCode ierr;
00593   PetscFunctionBegin;
00594   ierr = GetCategory(cat,&catg,&flg); CHKERRQ(ierr);
00595   if (!flg) {
00596     if (!f) SETERRQ(1,"Could not find cat/cmp, but no flag to report this");
00597     *f = PETSC_FALSE; PetscFunctionReturn(0);
00598   }
00599   ierr = CategoryGetComponent(catg,cmp,&cmpt,&flg); CHKERRQ(ierr);
00600   if (!flg) {
00601     if (!f) SETERRQ(1,"Could not find cat/cmp, but no flag to report this");
00602     *f = PETSC_FALSE; PetscFunctionReturn(0);
00603   }
00604   ierr = ComponentGetId(cmpt,id); CHKERRQ(ierr);
00605   if (f) *f = PETSC_TRUE;
00606   PetscFunctionReturn(0);
00607 }
00608 
00609 #undef __FUNCT__
00610 #define __FUNCT__ "GetDataType"
00611 PetscErrorCode GetDataType
00612    (const char *cat,const char *cmp,AnalysisDataType *t,PetscTruth *f)
00613 {
00614   categoryobject catg; componentobject cmpt; PetscTruth flg;
00615   PetscErrorCode ierr;
00616   PetscFunctionBegin;
00617   ierr = GetCategory(cat,&catg,&flg); CHKERRQ(ierr);
00618   if (!flg) {
00619     if (!f) SETERRQ(1,"Could not find cat/cmp, but no flag to report this");
00620     *f = PETSC_FALSE; PetscFunctionReturn(0);
00621   }
00622   ierr = CategoryGetComponent(catg,cmp,&cmpt,&flg); CHKERRQ(ierr);
00623   if (!flg) {
00624     if (!f) SETERRQ(1,"Could not find cat/cmp, but no flag to report this");
00625     *f = PETSC_FALSE; PetscFunctionReturn(0);
00626   }
00627   ierr = ComponentGetType(cmpt,t); CHKERRQ(ierr);
00628   if (f) *f = PETSC_TRUE;
00629   PetscFunctionReturn(0);
00630 }
00631 
00632 #undef __FUNCT__
00633 #define __FUNCT__ "HasQuantity"
00634 /*!
00635   Check if a certain quantity is precomputed, meaning that it can 
00636   be retrieved (with a call to ComputeQuantity()) at no computational cost.
00637 
00638   The category and module names have to exist.
00639   Use HasComputeModule() to test whether
00640   a category and module is known to the system.
00641 
00642   See \ref attached "the page on attached quantities" for an explanation
00643   of the mechanism behind this routine.
00644 */
00645 PetscErrorCode HasQuantity
00646 (AnaModNumericalProblem prob,const char *cat,const char *cmp,PetscTruth *f)
00647 {
00648   categoryobject catg; componentobject cmpt;
00649   AnalysisDataType t; int id; PetscErrorCode ierr;
00650   PetscFunctionBegin;
00651   ierr = GetCategory(cat,&catg,f); CHKERRQ(ierr);
00652   if (!*f) PetscFunctionReturn(0);
00653   ierr = CategoryGetComponent(catg,cmp,&cmpt,f); CHKERRQ(ierr);
00654   if (!*f) PetscFunctionReturn(0);
00655   ierr = ComponentGetId(cmpt,&id); CHKERRQ(ierr);
00656   ierr = ComponentGetType(cmpt,&t); CHKERRQ(ierr);
00657   ierr = HasQuantityByID(prob,id,t,f); CHKERRQ(ierr);
00658   PetscFunctionReturn(0);
00659 }
00660 
00661 #undef __FUNCT__
00662 #define __FUNCT__ "HasQuantityByID"
00663 /*! Auxiliary routine with lookup by ID, which is much faster 
00664   than by string indexing.
00665 */
00666 PetscErrorCode HasQuantityByID
00667 (AnaModNumericalProblem prob,int id,AnalysisDataType type,PetscTruth *f)
00668 {
00669   Mat A = (Mat)prob; PetscReal rv,*rsv; int iv,*isv;
00670   PetscErrorCode ierr;
00671   PetscFunctionBegin;
00672   switch (type) {
00673   case ANALYSISINTEGER :
00674     ierr = PetscObjectComposedDataGetInt
00675       ((PetscObject)A,id,iv,*f); CHKERRQ(ierr);
00676     break;
00677   case ANALYSISDOUBLE :
00678     ierr = PetscObjectComposedDataGetReal
00679       ((PetscObject)A,id,rv,*f); CHKERRQ(ierr);
00680     break;
00681   case ANALYSISINTARRAY :
00682     ierr = PetscObjectComposedDataGetIntstar
00683       ((PetscObject)A,id,isv,*f); CHKERRQ(ierr);
00684     break;
00685   case ANALYSISDBLARRAY :
00686     ierr = PetscObjectComposedDataGetRealstar
00687       ((PetscObject)A,id,rsv,*f); CHKERRQ(ierr);
00688     break;
00689   default : SETERRQ1(1,"Unknown data type %d",type);
00690   }
00691   PetscFunctionReturn(0);
00692 }
00693 
00694 #undef __FUNCT__
00695 #define __FUNCT__ "RetrieveQuantityByID"
00696 /*! See also HasQuantityByID() */
00697 PetscErrorCode RetrieveQuantityByID
00698 (AnaModNumericalProblem prob,int id,AnalysisDataType type,
00699  AnalysisItem *result,PetscTruth *f)
00700 {
00701   Mat A = (Mat)prob; PetscErrorCode ierr;
00702   PetscFunctionBegin;
00703 
00704   switch (type) {
00705   case ANALYSISINTEGER :
00706     ierr = PetscObjectComposedDataGetInt
00707       ((PetscObject)A,id,result->i,*f); CHKERRQ(ierr);
00708     break;
00709   case ANALYSISDOUBLE :
00710     ierr = PetscObjectComposedDataGetReal
00711       ((PetscObject)A,id,result->r,*f); CHKERRQ(ierr);
00712     break;
00713   case ANALYSISINTARRAY :
00714     ierr = PetscObjectComposedDataGetIntstar
00715       ((PetscObject)A,id,result->ii,*f); CHKERRQ(ierr);
00716     break;
00717   case ANALYSISDBLARRAY :
00718     ierr = PetscObjectComposedDataGetRealstar
00719       ((PetscObject)A,id,result->rr,*f); CHKERRQ(ierr);
00720     break;
00721   default : SETERRQ1(1,"Unknown data type %d",type);
00722   }
00723   PetscFunctionReturn(0);
00724 }
00725 
00726 #undef __FUNCT__
00727 #define __FUNCT__ "QuantityAsString"
00728 /*!
00729   Generate a character string for a given quantity.
00730 */
00731 PetscErrorCode QuantityAsString(AnalysisItem *q,AnalysisDataType t,const char **s)
00732 {
00733   PetscErrorCode ierr; size_t l;
00734 
00735   PetscFunctionBegin;
00736   switch (t) {
00737   case ANALYSISINTEGER : 
00738     ierr = PetscMalloc(12*sizeof(char),s); CHKERRQ(ierr);
00739     ierr = PetscMemzero((void*)*s,12*sizeof(char)); CHKERRQ(ierr);
00740     sprintf((char*)*s,"%d",q->i);
00741     break;
00742   case ANALYSISDOUBLE : 
00743     ierr = PetscMalloc(22*sizeof(char),s); CHKERRQ(ierr);
00744     ierr = PetscMemzero((void*)*s,22*sizeof(char)); CHKERRQ(ierr);
00745     sprintf((char*)*s,"%e",q->r);
00746     break;
00747   case ANALYSISSTRING :
00748     ierr = PetscMalloc((strlen(q->c)+1)*sizeof(char),s); CHKERRQ(ierr);
00749     ierr = PetscMemzero((void*)*s,(strlen(q->c)+1)*sizeof(char)); CHKERRQ(ierr);
00750     sprintf((char*)*s,"%s",q->c);
00751     break;
00752   case ANALYSISINTARRAY :
00753     {
00754       int i,n,*iar;
00755       iar = q->ii;
00756       n = q->len;
00757       ierr = PetscMalloc((10*n+1)*sizeof(char),s); CHKERRQ(ierr);
00758       ierr = PetscMemzero((void*)*s,(10*n+1)*sizeof(char)); CHKERRQ(ierr);
00759       for (i=0; i<=n; i++) {
00760         ierr = PetscStrlen(*s,&l); CHKERRQ(ierr);
00761         sprintf((char*)*s+l,"%d,",iar[i]);
00762       }
00763     }
00764     break;
00765   case ANALYSISDBLARRAY :
00766     {
00767       int i,n; PetscReal *rar; 
00768       rar = q->rr;
00769       n = q->len;
00770       ierr = PetscMalloc((15*n+1)*sizeof(char),s); CHKERRQ(ierr);
00771       ierr = PetscMemzero((void*)*s,(15*n+1)*sizeof(char)); CHKERRQ(ierr);
00772       for (i=0; i<=n; i++) {
00773         ierr = PetscStrlen(*s,&l); CHKERRQ(ierr);
00774         sprintf((char*)*s+l,"%e,",rar[i]);
00775       }
00776     }
00777     break;
00778   default : SETERRQ1(1,"Cannot string quantity type %d",t);
00779   }
00780   PetscFunctionReturn(0);
00781 }
00782