I've used abstract function types to something similar to what I think you
may be wanting. The following is a simple example of this method, which
hopefully may give you some ideas:

Firstly, say I have a model which has a value x and I wish to apply a
simulation function, which takes an argument sigma, to the model . The
following julia file (Mdl.jl) shows how we could define firstly an abstract
type SimFn for implementations of alternative simulation functions, then a
type Mdl for the model. We also provide say a standard implementation
StdSim, a concrete implementation of SimFn. We have constructors to
instantiate Mdl and StdSim instances. We'll use doSim on model instances to
run the simulation (say):

# file Mdl.jl    (julia 0.3)

abstract SimFn

type Mdl
    x
    simfn::SimFn
    Mdl(x,simfn)=new(x,simfn)
end
doSim(mdl::Mdl) = doSim(mdl.simfn, mdl)

type StdSim <: SimFn
   sigma
   StdSim(sigma)=new(sigma)
end

function doSim(sim::StdSim, mdl::Mdl)
    parm = sim.sigma * mdl.x
    println("doSim from StdSim, sigma is: ",sim.sigma)
    return parm
end

Now, here's a REPL session showing a "standard" simulation say ...

# REPL session ....

julia> include("Mdl.jl")
=> doSim (generic function with 2 methods)

julia> mdl = Mdl(10.0, StdSim(0.4))
=> Mdl(10.0,StdSim(0.4))

julia> p = doSim(mdl)
=> doSim from StdSim, sigma is: 0.4
=> 4.0

But, assume we now wish to try out different implementations of SimFn, but
with the same model.  Say we wish to try out a FooSim simulation, but this
needs an additional argument "fac". So, we implement this in a separate
file:

# sims_impl.jl - sample implementation FooSim for Mdl

type FooSim <: SimFn
   sigma
   fac
   FooSim(sigma,fac)=new(sigma,fac)
end

function doSim(sim::FooSim, mdl::Mdl)
    parm = sim.sigma * sim.fac * mdl.x
    println("doSim from FooSim, sigma is: ",sim.sigma," fac is: ",sim.fac)
    return parm
end

# more  (of the same) REPL session ....

julia> include("sims_impl.jl")   # could use reload here as well
=> doSim (generic function with 3 methods)

julia> mdl.simfn = FooSim(0.4, 0.5)
=> FooSim(0.4,0.5)

julia> p = doSim(mdl)
=> doSim from FooSim, sigma is: 0.4 fac is: 0.5
=> 2.0

Key concept here is we are using Julia's multiple dispatch with concrete
implementations of an abtract/generic function type to achieve the
polymorphism. Note how the arguments to doSim are carried by the FooSim
instance. So, we achieve a much better solution than anonymous functions
and closures.

This is just one of the many reasons why I am blown away by this language!

Hope that helps,
-- Adrian.







On Sat, Jul 19, 2014 at 1:21 PM, Tim Holy <[email protected]> wrote:

> I'm not certain I fully understand your constraints, but suppose
> include("input_deck.jl") results in a function called input_deck being
> defined.
> Then you could pass input_deck as an argument to your simulation code.
>
> If you have many deck-specific functions, you could have files "Deck1.jl",
> "Deck2.jl", "Deck3.jl" all define functions according to some deck API.
> Crucially, all of these define their code inside a module just called Deck
> (without the file-specific extension). Then when you want to run your
> simulation, say something like
>     require("Deck2.jl") # load particular settings
>     using Simulator      # inside Simulator is a "using Deck" expression
>     run_simulator()
>
> For your second question, could you just build a Set containing all the
> variables to be recorded? And then have code do this:
>     if in(:vehicle_model, recordedvars)
>         add_variable(data_record_file, :vehicle_model, vehicle_model)
>     end
>
> --Tim
>
> On Friday, July 18, 2014 03:48:31 PM [email protected] wrote:
> > First, I'm having a blast learning Julia.  Thanks to all those who have
> > worked on it.
> >
> > I'm an aerospace engineer who works on the design and analysis of
> planetary
> > entry vehicles.  Our workhorse tools are flight mechanics/dynamics
> > simulations, which at their core just integrate the equations of motion
> of
> > the vehicles.  We make extensive use of Monte Carlo for our analyses.  We
> > have historically had a clear separation between the simulation model
> code
> > and the "input deck" (we still use the term, even though it is originally
> > from when my older colleagues were using decks of punch cards to run
> their
> > simulations).  The input deck defines the case to be simulated: how many
> > vehicles, the aerodynamic properties of the vehicles, etc.  This clear
> > distinction allows us to run a variety of cases with a single set of
> > simulation model code.
> >
> > Our current simulations use C++ for the model code.  The input deck is in
> > Python, and has access to the model code thanks to SWIG.  It works pretty
> > nicely.
> >
> > But C++ is daunting to my colleagues (and I grow weary of it myself).  I
> > think Julia would be more approachable.  It would also be nice to have
> the
> > input deck and model code be the same language.
> >
> > So I've started experimenting with making a simple simulation in Julia.
> >  I'm having some trouble figuring out the best way to implement some of
> the
> > features, and I was hoping that you might have some advice.
> >
> > There are two things I'm struggling with.  First, how could I implement
> our
> > "input deck" concept with Julia?  The main issue I see is that I'd like
> to
> > have a function that performs a single run of the simulation with a
> > specified input deck, since that would so easily grow to a Monte Carlo
> > capability.  But I can't use include("input_deck.jl") inside a function
> > body.  Our input decks can be complex, and we often organize them into
> > multiple files, so I'd also like to be able to "include" those other
> files
> > from within the input deck.  The only way I can think to do this right
> now
> > is to work in the global scope, and then have a second Julia program
> that I
> > can parallelize that would then start a new Julia process to run each
> case.
> >
> > Second, the input deck specifies which variables are to be recorded
> during
> > the run.  In C, it's easy to just keep a pointer to a variable and grab
> > it's value whenever the data recording code needs it.  In Julia, it seems
> > like closures/anonymous functions are probably the best way to do this.
> >  That is, in the input deck, the user would do:
> >
> > # Somewhere earlier in the input deck, the user has done
> > some_vehicle = new_vehicle()
> >
> > # Then they set up the data recording
> > data_record_file = new_data_record_file()
> > add_variable(data_record_file,()->some_vehicle.some_model.some_variable)
> >
> > Which I could of course make more convenient with a  macro.  Is there a
> > better way?  I was tinkering with using Expressions and automatically
> > building the functions (for speed), but that again limits me to working
> in
> > the global scope.
> >
> > Thank you all for reading such a long post.  I hope my explanation make
> > sense, but if not, I'd be happy to attempt to clarify.  I really
> appreciate
> > the help!
> >
> > Daniel
>
>

Reply via email to