Julia equivalent for an ndarray datatype object in python

I am converting a large Python code into Julia. In my Python code, I have the ndarray datatype objects that

  1. allow me to add fieldnames to each value of an array (as in the name of a chemical species and its concentration) as well as specify its format (which is all Float64, so it does not really matter as they are all the same type), and
  2. these fieldnames are like keys and can be used to retrieve the values they are associated with. So if I want H2O, it retrieves a particular species’ (H2O) concentration.
  3. allows me to initialize a complex object (i.e., 2D arrays of these objects that have 20 species each with their chemical name) like with the zeros and empty functions in python.

In python, I would do this:
dtype1=dict(names=listofnames,formats=[np.float64*len(listofnames)]
N = np.zeros((10,10),dtype=dtype1)

  1. What would be the exact replacement type object for this in Julia?
  2. Are there any modules that I should be aware of that help me create and manipulate such objects?

So far, I have created a mutable struct - say, Species, created a constructor for default values, an ArrayofStructs as ArrayofSpecies, and used this object to fill a 2D array.

mutable struct Species
    name::String
    value::Float64
end
Species(x::String)=Species(x,0.0)
ArrayofSpeciesObject = [Species(x) for x in arrayofstrings]
A=fill(arrayofSpeciesObject,10,10) 

But I am missing the ease of retrieving values for each chemical species with their fieldnames in python as you would for dictionaries, i.e., A[i,j]["H2O"]

Is there a better way to do this?

Thanks!!

If I understand you correctly, you just want to define a struct datatype defining the elements of your array, giving its fields and types:

struct ChemicalSpecies
    name::String
    H2O::Float64
end

Then you can allocate an uninitialized 20×30 array of these values with:

a = Array{ChemicalSpecies}(undef, 20, 30)

You can also use zeros(ChemicalSpecies, 20, 30) to allocate an array initialized to zero values, as long as you define Base.zero(::Type{ChemicalSpecies}) = ChemicalSpecies(...something...), though it’s not clear to me what a “zero” would mean for a String field. You could also use a comprehension:

a = [ChemicalSpecies("", 0.0) for i = 1:20, j = 1:30]

Then you can access data with a[i,j].H2O, for example.

4 Likes

Hi Steven,

Thanks for your quick response!

I hope I am not missing something, but how would I adapt such a mutable struct for species with different names, say I have H2O, CO2, NH3.
a[i,j].H2O, a[I,j].CO2 etc. require the fieldname for each species to be its particular name.

I require like 100+ different species to be in an array object, which is in turn an array element in a 2D array.

Any chance you are dealing with chemical compositions?

You could create a composition using CoDa.jl:

julia> using CoDa
julia> c = Composition(CO₂=1.0, CH₄=0.1, N₂O=0.1)
                  3-part composition
       ┌                                        ┐ 
   CO₂ ┤■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 1.0   
   CH₄ ┤■■■■ 0.1                                  
   N₂O ┤■■■■ 0.1                                  
       └         

and then create an array of such composition objects.

These composition objects are static vectors (which are quite fast to operate on). They also have a whole set of operations defined in compositional space so you don’t mess up with ratios of the parts.

The only missing feature is the access with c.CO₂ syntax that could be easily added in case this is useful to you.

6 Likes

A struct can have as many fields as you want, and you can also construct a NamedTuple if you need to build it dynamically.

Though it’s hard to be sure what is the best data structure without knowing more about your application.

2 Likes

In case you want to experiment with the code, I’ve just added c.CO2 syntax support in the master branch. The release should be available in a few minutes in the package manager.

2 Likes

I am dealing with code designed to calculate chemistry in astrophysical objects. So essentially it has a large chemical reaction network that is solved across a 2D spatial grid. I think ultimately structs or named tuples would be helpful for my purposes!

Thanks for your responses!

Thanks juliohm! Not exactly compositions, I am actually calculating abundances of different chemical species across an astronomical object. But CoDa.jl seems very useful - I will make a note of it! Thanks for adding field access to it!

For me it looks like a (n+1)D array, where n is the space dimensionality, and in the last dimension you have the abundancies of the species. These species have all their names, reactivities etc., but these could be saved separately in a 1D array of structs.

P.S. With AxisArray you can have indexing by substance (Symbol or String) along the corresponding axis

1 Like

Can you please elaborate on the concept of abundances @onafinedayforscience? Compositions don’t need to be percentages or add up to 1. If these abundances are some sort of fraction or proportion of chemicals from a bulk of material, this is a composition.

1 Like

What I am really dealing with is number densities (1/cm^3) and mass densities (g/cm^3). By abundances, I mean like chemical species “x” with respect to the most abundant gas which is H2 - so x/H2. There are about a 100 different chemical species, most of them have negligible concentrations, some with moderate concentrations and few form the bulk of the composition of the cloud at each spatial grid point (i,j).

Yes, I am not 100% sure, but it seems like a good combination of GeoStats.jl + CoDa.jl both of which I am involved. Not so much the latter, but the former is taking a lot of my research time :slight_smile:

oh - I wasn’t aware of these modules. I also came across LabelledArrays.jl which looks perfect. Thanks for letting me know!

Catalyst.jl ?

1 Like

Catalyst.jl looks great. I will check it out - thanks!

And some more links, which could be relevant for you:

Video - JuliaCon 2018 | Solving Partial Differential Equations with Julia | Chris Rackauckas

Solving Systems of Stochastic PDEs and using GPUs in Julia

Speeding Up Jacobian Calculations

2 Likes

thank you!