The error comes from redefinining a struct - this is a fundamental limitation of Julia currently, it is not possible (without some tricks) to change and redefine a struct defined in a session, so if you’ve run the @with_kw struct ModelParameters part of the code once, then change the fields of ModelParameters and run it again you will see that error. If you don’t need loads of other packages and your startup time is low, the easiest way around it is to just re-start Julia when you need to change the definition of ModelParameters.
Yes that’s correct - sorry not sure what your question is here, but given the above I don’t think your problems are related to brackets?
Yes, the ellipses are what’s called splatting, basically passing one argument which is a collection (vector/tuple) and splitting it into its components when passing it into the function. In this case it splits up the NamedTuple and passes every name-value pair as one argument to the constructor. A simpler example to illustrate:
julia> f(arg1, arg2) = println("my first argument is $arg1 and the second is $arg2")
f (generic function with 1 method)
julia> x = [5, 6];
julia> f(x...)
my first argument is 5 and the second is 6
Nils, that did the trick (stopping and starting - I also had a couple of typos). I have already read in about 100 of the 400 variables but I have encountered a couple of issues related to VBA (not Julia) , which may require a re-think of the best way to handle the input file. I would value your opinion, as my ultimate goal it to present the problem to the Julia ODE solvers (and ultimately the optimizing engine) in the best way possible:
The maximum number of line continuations in a VBA write/print statement is 25, which is not enough to write all my values on one line. I could possibly join to files together or write the headings and data to a spare spreadsheet in two rows and then read it back into another file that I ultimately present to Julia … bit messy and in any case, suffers from the problem 2 below.
When I write the headings and one line and the data(values) on the line below there is no visible correspondence, as the headings are much longer than the values - basically kills my idea of having an editable data file. This was not so much of a problem when I wrote multiple lines to the file , as the correspondence between headings and values was retained.
If I write the data into two columns (headings in one column and data in the other column) can I still retain the struct format that you say is valuable for presenting to the ODE solver, This file format is essentially a table, which would be the most easy to edit. I think I would need your help on how to read in this file and set up a struct, assuming it was possible?
Note I have completed the Dictionary method that Florin outlined, so I guess this is an option for presenting and unpacking data for the solver? If it is not as good as struct or offers some limitations, then I am all for taking the best route to achieve the ultimate result.
Again many thanks for all of the help and setting me straight on many concepts. I liked the splatting explanation. Peter
Yes I would probably just use two columns, one for variable name, one for value. You can then just flip this around e.g. with DataFrames it would be:
julia> using DataFrames
julia> df = DataFrame(variable = ["Location", "Elevation"], value = ["Toowaboo", 534])
2×2 DataFrame
Row │ variable value
│ String Any
─────┼─────────────────────
1 │ Location Toowaboo
2 │ Elevation 534
julia> permutedims(df, "variable")
1×3 DataFrame
Row │ variable Location Elevation
│ String Any Any
─────┼───────────────────────────────
1 │ value Toowaboo 534
and you can get your NamedTuple from there to pass to your ModelParameters constructor.
EDIT: The downside that I notice now as I post this is that you lose the automatic type detection that CSV.jl gives you, which you could potentially sort by just writing the file back out and reading it in again in the wide format.
I will try that. Thanks. Just to be clear the Dictionary method is not as friendly as the struct approach when setting up an ODE solver problem? The Dictionary seems to have the ability to unpack just the specific variables you need for a particular function. Does the struct method offer this targeted ability as well? Thanks Peter
Knowing a bit of Python is certainly good to get started with Julia, but it’s not necessary. You could have a look at this, if you have a background in either MATLAB, R, Python, C or Lisp and need a little help for transitioning:
I’ve been using Julia for around a year now, and I’m currently working on my master thesis using Julia, so that helps enormously.
The approach is pretty much the same as in your days: I started by reading the manual and coding up really basic examples and things for fun. It’s of great help to have a kind of ‘toy project’ which you can code up bit by bit, seeing progress when you make it and being able to revise and refactor the code many times. You can be sure that I started writing horrible code (by my current standards) at first I think I turned the basic bits of my thesis project inside out for the 3rd time now. (I started the project a while ago and it turned into a thesis eventually, it didn’t start as one, else I would have ran out of time by now). [Edit: I’m still far from writing optimal code, but it’s getting better. You’ll get there, too.]
It’s just a process like learning any language. I like revisiting the docs once in a while, and also looking at the code in Julia Base is often helpful, especially if you implement your own types and need help implementing specialized functions. It’s really helpful to look at how other people solved these problems and digest that.
Oh and reading around the julia discourse here is also pretty helpful, as there are a lot of questions and answers and nice examples here.
Can’t really help with that, sorry, but similar questions have been asked multiple times here. Maybe you find something there:
And finally:
Both are fine. With a dictionary holding different types, you need to make sure to annotate the types when you unpack them (for performance reasons), with Nils’ struct approach that comes for free.
Nils, it appears that the following statement can be used to read in a vertical file by using the transpose = true option in the argument list of the CSV.read function. Do you concur? I am not sure what the pool = false does. Could you elaborate a little
input_data = Tables.rowtable(CSV.File("MyFile_Vertical.txt",transpose = true, delim =',', pool = false));
In conclusion, if the above works, then I now have two paths to import my parameters (Dictionary and struct). Thanks again to you both for staying the journey. Peter
Yes, I forgot about that CSV option - indeed you can just read it in transposed in that way.
As for pool:
help?> CSV.File
CSV.File(source; kwargs...) => CSV.File
(...)
• pool::Union{Bool, Float64}=0.1: if true, all columns detected as String will be internally pooled; alternatively, the proportion of unique
values below which String columns should be pooled (by default 0.1, meaning that if the # of unique strings in a column is under 10%, it will
be pooled)
“pooling” here refers to compressing a string column by only storing unique strings and a lookup table, and then replacing the strings in the column with the lookup value.
Nils, “pool” is a powerful option! Just to let you know, I have successfully read-in all my variables, into both a struct and a Dictionary. Next week I will try to connect up my modules, and develop the coefficients that the RHS of my 123 ODE’s require. I only have a week left before I go on Xmas break. Best wishes to you both. Peter