Skip to main content

Let me first start with one remark: The openAPI client generation is one awesome addition!!! 😀

With a bit of a simple workaround I was able to create relatively easy an AIMMS library that was able to import a rather large and complex JSON file that had a quite deep nested structure in it.

Now that I have the data in an AIMMS library, I know am trying to write the code that parses the information from the library into the actual AIMMS sets/parameters that I will use in a model.

For this part, one of the problems of the nesting is that the generated library works on lots of subsets of integers that restart counting from 0 every time

 

In the following example (that hopefully illustrates it enough)

Locations property (contains list of locations):

  • Element 1 in locations list (will map to i_locations=1 in aimms library)
    • LocationName: Location A
    • Products   (contains list of products)
      • Element 1 in productions list  (contains dictionary of name/color, maps to locations::product::i_product=1 in aimms library)
        • name: product1 (defined over locations and product index in aimms library)
        • color: green  (defined over locations and product index in aimms library)
      • Element 2 in productions list (contains dictionary of name/color, maps to i_product=2 in aimms library)
  • Element 2 in locations list (will map to i_locations=2 in aimms library)
    • locationname: location B
    • Products (contains list of products)
      • Element 1 in productions list (maps to locations::product::i_product=1 in aimms library)
        • name: product2 ((defined over locations and product index in aimms library)
        • color: green (defined over locations and product index in aimms library)

 

My first approach was to go step by step deeper and keep on creating elements in my main model set sProducts. When doing this and creating mappings, I will always have to keep the reference to both indices locations and product because the product index just keeps on resetting to 1 for every new location.

In my particular usecase, I would rather have the index counters to never reset, but just always keep on counting. That would allow me to create easy 1 to 1 mappings from json id number to aimms set elements. That means I would basically just create a set in my main model for locations and one for products and use stringtoelement with the name/locationname property of the product and location respectively. Any duplicates (e.g. if Product 5 occurs both in location A and location 😎 will automatically be mapped from unique json array ids to the same main model product set elements (which is correct, name property is the unique identifier for the product)

 

I have found that if I modify the mapping file and empty the interactive-reset attribute for the ArrayMapping nodes in the generated mapping XML file, it looks like this does exactly what I need it to do.

Since i have not used the DEX library and mappings that much yet, would like to know if my above reasoning is correct or whether I am making a big mistake in my logic somewhere.

 

 

 

hi @gdiepen 

First of all, you know that you can also use dex::schema::ParseJSONSchema to generate a library for creating a mapping and identifiers for just a json schema, and that you don't have to do trickery to wrap it in a openapi spec?

I've added an option dex::schema::IterativeResetArrays in DEX 2.1.2.54 that steers whether iterative-reset attributes are added to array mappings when generating mapping files from a json schema. Notice, that with this option set to 0, you should call dex::ResetMappingData prior to calling dex::ReadFromFile to reset the iterative counters manually. 

Finally, you can already embed special extensions (x-aimms-...) in a json schema to steer the generator (e.g. to set the identifier names). I've played with the idea to also allow to set x-aimms extensions in a schema that would allow mapping schema elements to existing indices and identifiers in the model. That would relieve you of having to do the mapping of generated data to your model identifiers afterwards by hand. So far, we haven't pursued that idea any further as working with generated identifiers was dazzlingly complex enough by itself. 


hi @MarcelRoelofs ,

 

it was relatively easy for me to create the openapi spec, because I have been working a lot with FastAPI recently, so very easy for me to create the pydantic model to read in the data structure. For reading in the file, I actually don’t use the web api anymore, I just use the library and call the read functions directly, similar to what you would do with just the json files I assume.

 

I have less experience with creating json schemas, but if I have some time later this week, will take a look at that.

With regards to the resets, for some of the identifiers I actually do want the reset to make my life a bit easier: there are some identifiers / columns that represent a time index and for those it is easy to have them always start at 0 to be able to map them easily using ordinal position. For things like products in my example, there I don’t want the reset.

So in my current setup, I am creating the library using the openapi spec and then modifying the generated json mapping files to remove the reset for everything but the time based counters.

There probably are easier ways, I was actually already quite impressed that with relatively little effort I was able to read in a complex, nested json file in AIMMS (which honestly before I would have not known how to achieve easily).

 

Thanks again for these kind of cool features!


I actually saw that pydantic (used by fastapi) also allows me to directly export the model into a json schema file 🙂 Guess I could have saved a tiny step there...


Reply


Didn't find what you were looking for? Try searching on our documentation pages:

AIMMS Developer & PRO | AIMMS How-To | AIMMS SC Navigator