szaghi / FLAP

Fortran command Line Arguments Parser for poor people
151 stars 34 forks source link

General parameter handler #55

Closed victorsndvg closed 7 years ago

victorsndvg commented 8 years ago

Hi Stefano,

we would like to have a type(ParameterList) data type in our application following the flavour of the following class in Trilinos, Section 9.6 of the tutorial and i Doxygen documentation.

This is essentially a data base which stores <key,value> pairs, with key being character strings, and value a generic (polymorphic?) data type. (e.g., it can be either a intrinsic data type, or even a type(ParameterList), recursively).

We believe that the internals of this data structure would ressemble those of the CLI. The difference being that the life cycle of each <key,value> pair can be handled by means of add/set/get/del TBPs of the data type, instead of being filled up with the result of a parsing process.

What do you think? Do you agree? Would it be easy to implement type(ParameterList) reusing (part of the) of the components available in FLAP? Would it be useful for the users of FLAP?

Eventually, as additional features, a type(ParameterList) could be either built from a CLI or read from a XML file.

Best regards, Víctor

szaghi commented 8 years ago

Hi Victor,

unfortunately I completely do not understand you... sorry! Can you give me a concrete example/scenario on how FLAP could be useful for this type(ParameterList) data base? In particular:

do you want to implement an actual Fortran type? like

type ParameterList
  !...
endtype ParameterList

and the define an instance of it

type(ParameterList):: foo

do you want to select the type at runtime by CLI?

my_cli --type 'ParameterList'

in case... wow! How this work?

Really, I am very sorry, but for the moment I am very confused by your question. Please, elaborate it more, the Trillinos example does not help me much.

victorsndvg commented 8 years ago

Hello @szaghi,

let me first clarify from the begining that type(ParameterList) and type(CLI) are classes with different purpose, behaviour and semantics. However, I believe (may be wrongly) that there is similarity in the way the might be internally organized, so that I wonder to what extent I could re-use/modify/add some of the components of FLAP to implement this new data type. This is only a possibility that I would like consider. If this cannot be fulfilled, then I can forget about this idea, and then write type(ParameterList) from scratch.

With respect to the structure and semantics of type(ParameterList), I have added the following (pseudocode with many questions still open) gist that I expect that would help to clarify what I am interested in:

https://gist.github.com/victorsndvg/6d4d95d9c38ee01f674c

Best regards, Víctor.

szaghi commented 8 years ago

Hi Victor,

I have added some comments on your gist.

victorsndvg commented 8 years ago

Hi @szaghi ,

thank you! it is a good explanation and also good source files :) Probably your work can be a perfect start point.

I only have a doubt about the use of Data_Type_Hash_Table. Have you used it in any sample code? It seems that the choice of working with unlimited polymorphic data types makes the client more complex because of the delegation of the data type management on it. I'm right? what do you think?

I will try to read some more info before starting the development. You will know about this ParameterList as soon as possible.

Thanks, again. You are always ready to help.

szaghi commented 8 years ago

Hi Victor,

you are too kind.

Yes, my hash table is used in production... into OFF of course. I report just an example of usage.

the main container of OFF is global that is something similar to:

type, public:: Type_Global
  type(Type_CompiledCode):: cco        !< Compiled code used options.
  type(Type_OS)::           OS         !< Running architecture.
  type(Type_Parallel)::     parallel   !< Parallelization data.
  type(Type_Space_Step)::   space_step !< Space step data.
  type(Type_Time_Step)::    time_step  !< Time step data.
  type(Type_Species)::      species0   !< Initial species.
  type(Type_Adimensional):: adim       !< Non-dimensionalization data.
  type(Type_BC_in1)::       bc_in1     !< Inflow 1 boundary conditions.
  type(Type_Tree)::         block_dims !< Mesh global dimensions (blocks of all processes), tree of Type_Block_Dimensions.
  type(Type_Tree)::         block      !< Block-level data (blocks of myrank), tree of Type_SBlock.
  contains
    procedure:: free                 ! Procedure for freeing dynamic memory.
    procedure:: set_Ns_from_species0 ! Procedure for setting the number of species accordingly species0.
    procedure:: set_Nrk_from_rk_ord  ! Procedure for setting the number of Runge-Kutta stages from time order accuracy, rk_ord.
    procedure:: blocks_init          ! Procedure for initializing blocks memory.
    procedure:: blocks_dims_update   ! Procedure for updating blocks dimensions form mesh ones.
    procedure:: solve                ! Procedure for solving the conservation equations for one grid level.
    procedure:: boundary_conditions  ! Procedure for imposing the boundary conditions for one grid level.
    final::     finalize             ! Procedure for freeing dynamic memory when finalizing.
endtype Type_Global

Note that the blocks (that are structured mesh based on of general curvilinear hesaedron cells) are of type of tree that in turns are octree based on the hash table, thus the answer is yes the unlimited polymorphic hash table is used in a real code, see it here.

As you guess, the unlimited polymorphic is very flexible and handy facility, but it has some cons. In particular, anytime you use a polymorphic object you must wrap it into a select type. Indeed, into OFF I violates this rule using pointer assignments. For example using an OFF block is done as:

type(Type_Block_Dimensions), pointer:: blkdims !< Pointer for scanning global%block_dims tree.
integer(I8P)::                         ID      !< Counter.
...
do while(global%block_dims%loopID(ID=ID))
  blkdims => global%block_dims%dat(ID=ID)
  blkdims%Np = global%species0%Np
  blkdims%Nc = global%species0%Nc
  blkdims%Ns = global%species0%Ns
enddo

note that ID is my hash table key, the unique block ID indexed into my octree structure and loopID is a method that loops over all block returning the ID counter that I save into local ID variable (very elegant...). The method dat returns a pointer to the unlimited polymorphic object, that in the example are the block dimensions specification. Note also that I do not wrap the block usage into a select type because I (ab)use of pointer assignment. During the last year I realized that this violates the standard, thus the corrected standard compliant code should be:

type(Type_Block_Dimensions), pointer:: blkdims !< Pointer for scanning global%block_dims tree.
integer(I8P)::                         ID      !< Counter.
...
do while(global%block_dims%loopID(ID=ID))
  select type(global%block_dims%dat(ID=ID))
  type is(Type_Block_Dimensions)
    blkdims => global%block_dims%dat(ID=ID)
    blkdims%Np = global%species0%Np
    blkdims%Nc = global%species0%Nc
    blkdims%Ns = global%species0%Ns
  endselect
enddo

This last example is obviously less concise, but it should be the right way. I have not yet found the time to correct OFF, thus if you read it remember of this pointer assignment abuse.

I will happy to see your ParameterList object.

See you soon.

P.S. I am sorry for Lib_VTK_IO, but for the moment I have no time for it. However, I have not left the aim to integrate your importers, it is just delayed for some weeks/month.

victorsndvg commented 8 years ago

Hi @szaghi ,

I understand your approach with pointers. I assume that you are using the unlimited polymorphic hash table for managing non-mixed datatypes (e.g. integers, floats and any derived type at same time).

I know that its mandatory to select the type before the assignment. In the way of using mixed types inside the hast table, now my doubt is, which is the best way to develop a new layer for managing data types in the OOP hierarchy. It should be easy extendible...

Don't worry about Lib_VTK_IO. I follow you and I know that you are very bussy :)

szaghi commented 7 years ago

@victorsndvg

I am closing this, feel free to reopen at your convenience.

Cheers

victorsndvg commented 7 years ago

Ok @szaghi , finally we implement and had-hoc layer managing FLAP and FPL in order to manage our application parameters .

Thanks!

victorsndvg commented 5 years ago

@szaghi ,

I'm revisiting FLAP so here I'm going to update our approach to solve this issue in our project.

What we intended to implement was a smart way to obtain parameters from the CLI and propagate them all along the project till the point they are used and using a single data type (dictionary).

Finally we implement a intermediate layer to manage FLAP and FPL. This layer is in charge of:

  1. defining key-value pairs (inside the FPL),
  2. publishing (into the CLI, FPL -> FLAP),
  3. parsing (from the CLI, by means of FLAP)
  4. and storing key-value (FLAP -> FPL)

You can visit the code of the wrapper here: https://github.com/fempar/fempar/blob/experimental/Sources/Lib/Tools/parameter_handler.f90

Finally we implement an extension of this data type to manage concrete parameters of our project: https://github.com/fempar/fempar/blob/experimental/Sources/Lib/Tools/fempar_parameter_handler.f90

We are currently updating/refactoring this part of the project (refactoring, singleton patterns, etc.). Soon it's going to slightly change in order to obtain a better design and stronger consistency.

Hope to be useful.

szaghi commented 5 years ago

@victorsndvg

thank you very much, it is really interesting.

I'll study your code soon, thanks!