text:
# This file holds the definition of the functions pertaining to the
#   PersonnelDatabase type.

# The functions of the PersonnelDatabase require the HistoryEntry, History, and
#   Personnel types.
requiredTypes = [ "personnel", "personnelDatabase" ]

for reqType in requiredTypes
    if !isdefined( Symbol( uppercase( string( reqType[ 1 ] ) ) * reqType[ 2:end ] ) )
        include( joinpath( typePath, reqType * ".jl" ) )
    end  # if !isdefined( Symbol( ...
end  # for reqType in requiredTypes

# Load in the type aliases.
include( joinpath( typePath, "typeAliases.jl" ) )

# This function tests if the database has the requested attribute.
export hasAttribute
function hasAttribute( dbase::PersonnelDatabase, attr::AttributeType )
    return Symbol( attr ) ∈ dbase.attrs
end  # hasAttribute( dbase, attr )

# This function adds the given attribute to the database, initializing the
#   attribute. If some personnel records have this attribute already, it will be
#   overwritten!
export addAttribute!
function addAttribute!( dbase::PersonnelDatabase, attr::AttributeType,
    initContent = nothing )
    tmpAttr = Symbol( attr )

    # Do nothing if the attribute exists in the database.
    if hasAttribute( dbase, tmpAttr )
        return
    end  # if hasAttribute( dbase, tmpAttr )

    push!( dbase.attrs, tmpAttr )

    # Update all personnel records to have this attribute.
    map( person -> person[ tmpAttr ] = initContent, dbase.dbase )
end  # addAttribute!( dbase, attr, initContent )

# This function adds the given attributes to the database.
export addAttributes!
function addAttributes!( dbase::PersonnelDatabase, attrs::Vector{Symbol} )
    map( attr -> addAttribute!( dbase, attr ), attrs )
end  # addAttributes!( dbase, attrs )

function addAttributes!( dbase::PersonnelDatabase, attrs::Vector{String} )
    map( attr -> addAttribute!( dbase, Symbol( attr ) ), attrs )
end  # addAttributes!( dbase, attrs )

# This function removes the given attribute from the database.
export removeAttribute!
function removeAttribute!( dbase::PersonnelDatabase, attr::AttributeType )
    tmpAttr = Symbol( attr )

    # If the attribute doesn't exist, or it is the ID key, do nothing.
    if !hasAttribute( dbase, tmpAttr ) || ( tmpAttr === dbase.idKey )
        return
    end  # if ( attr ∉ dbase.attrs ) || ...

    # Otherwise, remove attribute from list.
    index = find( x -> x == tmpAttr, dbase.attrs )
    deleteat!( dbase.attrs, index[ 1 ] )

    # Delete field from personnel records.
    map( person -> removeAttribute!( person, tmpAttr ), dbase.dbase )
end  # removeAttribute!( dbase, fiattreld )

# This function removes the given attributes from the database.
export removeAttributes!
function removeAttributes!( dbase::PersonnelDatabase, attrs::Vector{Symbol} )
    # Find all of the requested attributes that are present in the database, and
    #   which aren't the ID field.
    tmpAttrs = attrs[ unique( find( attr -> ( attr ∈ dbase.attrs ) &&
        ( attr !== dbase.idKey ), attrs ) ) ]

    if isempty( tmpAttrs )
        return
    end  # if isempty( tmpAttrs )

    # Find the indices of all the database attributes slated for removal and
    #   remove them.
    attrsIndex = find( attr -> attr ∈ tmpAttrs, dbase.attrs )
    deleteat!( dbase.attrs, sort( attrsIndex ) )

    # Remove the appropriate attributes from the personnel records.
    map( attr -> map( person -> removeAttribute!( person, attr ), dbase.dbase ),
        tmpAttrs )
end  # removeAttributes!( dbase, attrs )

# This function changes the key field of the database. The old key is kept to
#   make sure nothing gets broken.
export changeKey!
function changeKey!( dbase::PersonnelDatabase, key::AttributeType )
    tmpKey = Symbol( key )

    if !hasAttribute( dbase, tmpKey )
        warn( "Proposed ID \"$tmpKey\" is not a database attribute. ",
            "Ignoring request." )
        return
    end  # if tmpKey ∉ dbase.attrs

    # Stringify the contents of the propsed new ID key.
    map( person -> person[ tmpKey ] = string( person[ tmpKey ] ), dbase.dbase )

    # Check if the new key is unique.
    ids = dbase[ tmpKey ]

    if length( ids ) > length( unique( ids ) )
        warn( "Proposed ID \"$tmpKey\" does not have unique values." )
        return
    end  # if length( ids ) ...

    dbase.idKey = tmpKey
end  # changeKey!( dbase, key )

# This function adds an entry to the database.
export addPersonnel!
function addPersonnel!( dbase::PersonnelDatabase, person::Personnel )
    # Check if the person has the ID key of the database.
    if !hasAttribute( person, dbase.idKey )
        warn( "Person does not have the \"$(dbase.idKey)\" attribute. ",
            "Ignoring request." )
        return
    end  # if !hasAttribute( person, dbase.idKey )

    id = string( person[ dbase.idKey ] )

    # Check if the person's ID is not yet in the database.
    if exists( dbase, id )
        warn( "The database already contains an entry with ID \"$id\". ",
            "Ignoring request." )
        return
    end  # if exists( dbase, id )

    # Udate the database attribute list.
    addAttributes!( dbase, collect( keys( person.persData ) ) )

    # We create a new record here to make sure that we don't change the original
    #   personnel record.
    newPerson = person
    newPerson[ dbase.idKey ] = id

    # Add attributes that are in the database, but which aren't in the perosnnel
    #   record.
    newAttrs = dbase.attrs[ find( attr -> !hasAttribute( person, attr ),
        dbase.attrs ) ]
    map( attr -> newPerson[ attr ] = nothing, newAttrs )

    # Add the enriched copy of the personnel record to the database.
    push!( dbase.dbase, newPerson )
    dbase.persSize += 1
end  # addPersonnel!( dbase, person )

# This function adds a number of personnel records to the database.
function addPersonnel!( dbase::PersonnelDatabase, persons::Vector{Personnel} )
    map( person -> addPersonnel!( dbase, person ), persons )
end  # addPersonnel!( dbase, persons )

# This function adds a new personnel record with the given ID to the database.
function addPersonnel!( dbase::PersonnelDatabase, personID::String )
    # Check if the person's ID is not yet in the database.
    if exists( dbase, personID )
        warn( "The database already contains an entry with ID \"$personID\". ",
            "Ignoring request." )
        return
    end  # if exists( dbase, personID )

    # Create a new record with the requested ID.
    newPerson = Personnel( dbase.idKey, personID )

    # Add attributes that are in the database, but which aren't in the perosnnel
    #   record.
    newAttrs = dbase.attrs[ find( attr -> !hasAttribute( newPerson, attr ),
        dbase.attrs ) ]
    map( attr -> newPerson[ attr ] = nothing, newAttrs )

    # Add the enriched copy of the personnel record to the database.
    push!( dbase.dbase, newPerson )
    dbase.persSize += 1
end  # addPersonnel!( dbase, personID )

# This function adds new personnel records with the given IDs to the database.
function addPersonnel!( dbase::PersonnelDatabase, personIDs::Vector{String} )
    map( id -> addPersonnel!( dbase, id ), personIDs )
end  # addPersonnel!( dbase, personIDs )

# This function removes the personnel member with the requiested ID from the
#   database. If there is no personnel member with this ID, nothing happens.
export removePersonnel!
function removePersonnel!( dbase::PersonnelDatabase, id::String )
    index = getPosition( dbase, id )

    if index != 0
        removePersonnel!( dbase, index, false )
    end  # if index != 0
end  # removePersonnel!( dbase, id )

function removePersonnel!( dbase::PersonnelDatabase, ind::T,
    verifyIndex::Bool = true ) where T <: Integer
    if verifyIndex && ( ( ind <= 0 ) || ( ind > dbase.persSize ) )
        return
    end  # if verifyIndex && ...

    deleteat!( dbase.dbase, ind )
    dbase.persSize -= 1
end  # removePersonnel!( dbase, ind, verifyIndex )

function removePersonnel!( dbase::PersonnelDatabase, ids::Vector{String} )
    indices = Vector{Int}()

    for id in ids
        index = getPosition( dbase, id )

        if index != 0
            push!( indices, index )
        end  # if index != 0
    end  # for id in ids

    removePersonnel!( dbase, indices, false )
end  # removePersonnel!( dbase, ids )

function removePersonnel!( dbase::PersonnelDatabase, inds::Vector{Int},
    verifyIndices::Bool= true )
    indices = Vector{Int}()

    # Check which indices are valid.
    if verifyIndices
        for index in inds
            if ( index > 0 ) && ( index <= dbase.persSize )
                push!( indices, index )
            end  # if ( index > 0 ) && ...
        end  # for index ...
    else
        indices = inds
    end  # if verifyIndices

    # Delete the records with those indices.
    indices = unique( indices )
    deleteat!( dbase.dbase, sort( indices ) )
    dbase.persSize -= length( indices )
end  # removePersonnel!( dbase, inds, verifyIndices )

# This function tests if a personnel member with the requested ID exists in the
#   personnel database.
export exists
function exists( dbase::PersonnelDatabase, id::String )
    return getPosition( dbase, id ) != 0
end  # exists( dbase, id )

# This function returns the position of the person with the given ID in the
#   personnel database. If the ID doesn't exist, 0 is returned.
function getPosition( dbase::PersonnelDatabase, id::String )
    index = find( x -> x[ dbase.idKey ] == id, dbase.dbase )
    return isempty( index ) ? 0 : index[ 1 ]
end  # getPosition( dbase, id )

# This function selects all the records in the database with a specific value
#   for the given attribute.  (necessary?)
export selectRecords
function selectRecords( dbase::PersonnelDatabase, attr::AttributeType, val )
    tmpAttr = Symbol( attr )
    output = Vector{Personnel}()

    if !hasAttribute( dbase, tmpAttr )
        return output
    end # !hasAttribute( dbase, tmpAttr )

    map( person -> if ( person[ tmpAttr ] == val ) push!( output, person ) end,
        dbase.dbase )
    return output
end  # selectRecords( dbase, attr, val )

# This function adds a value to a vector attribute. If the attribute's value is
#   nothing, a vector will be created. If the attribute's value is not a vector,
#   nothing will happen.
export addValue
# The function using id as a String has to be written like this, because
#   otherwise a KeyError is thrown!
function addValue( dbase::PersonnelDatabase, id::String, attr::AttributeType,
    value::String )
    index = getPosition( dbase, id )
    addValue( dbase, index, attr, value )
end  # addValue( dbase, id, attr, value )

function addValue( dbase::PersonnelDatabase, ind::Int, attr::AttributeType,
    value::String )
    if ( ind <= 0 ) || ( ind > dbase.persSize )
        return
    end  # if ( ind <= 0 ) || ...

    addValue( dbase[ ind ], attr, value )
end  # addValue( dbase, id, key, value )

# This function gets the number of entries in the personnel database.
function Base.length( dbase::PersonnelDatabase )
    return dbase.persSize
end  # length( dbase )

# This function clears the database, and sets the key to the provided symbol.
export clearPDB!
function clearPDB!( dbase::PersonnelDatabase, key::Symbol = :id )
    empty!( dbase.attrs )
    empty!( dbase.dbase )
    dbase.persSize = 0
    addAttribute!( dbase, key )
    changeKey!( dbase, key )
end  # clearPDB!( dbase, key )

function clearPDB!( dbase::PersonnelDatabase, key::String )
    clearPDB!( dbase, Symbol( key ) )
end  # clearPDB!( dbase, key )

# This function retrieves the personnel member with the requested ID.
function Base.getindex( dbase::PersonnelDatabase, id::String )
    index = getPosition( dbase, id )

    # Throw an error if the personnel member with the requested ID doesn't
    #   exist.
    if index == 0
        error( "No personnel member with $(string( dbase.idKey )) \"$id\" on ",
            "record." )
    end # if index == 0

    return dbase.dbase[ index ]
end  # Base.getIndex( dbase, id )

# This function retrieves the personnel member with the requested index.
function Base.getindex( dbase::PersonnelDatabase, ind::T ) where T <: Integer
    if ( ind <= 0 ) || ( ind > dbase.persSize )
        error( "Cannot request personnel with index $ind: personnel database ",
            "size is only $(dbase.persSize)." )
    end  # if ind > dbase.persSize

    return dbase.dbase[ ind ]
end  # Base.getindex( dbase, ind )

# This function retrieves the personnel with the requested IDs.
function Base.getindex( dbase::PersonnelDatabase, indices::DbIndexArrayType )
    return map( index -> dbase[ index ], indices )
end  # Base.getindex( dbase, indices )

# This function retrieves the requested field from the personnel with the
#   requested ID.
function Base.getindex( dbase::PersonnelDatabase, index::DbIndexType,
    attr::AttributeType )
    return dbase[ index ][ Symbol( attr ) ]
end  # Base.getindex( dbase, index, attr )

# This function retrieves the requested attribute from the personnel with the
#   requested IDs.
function Base.getindex( dbase::PersonnelDatabase, indices::DbIndexArrayType,
    attr::AttributeType )
    tmpAttr = Symbol( attr )
    output = similar( indices, Any )
    map( ii -> output[ ii ] = dbase[ indices[ ii ], tmpAttr ],
        eachindex( indices ) )
    return output
end  # Base.getindex( dbase, indices, attr )

# This function retrieves the requested attribute at the given time from the
#   personnel record with the requested index.
function Base.getindex( dbase::PersonnelDatabase, index::DbIndexType,
    attr::AttributeType, timestamp::T ) where T <: Real
    person = dbase[ index ]
    return person[ attr, timestamp ]
end  # Base.getindex( dbase, index, attr, timestamp )

# This function retrieves the requested attribute from the entire database.
# XXX There is no overload of this function with a String as second argument
#   because such a function has been defined prior to retrieve the personnel
#   member with that value as ID.
function Base.getindex( dbase::PersonnelDatabase, field::Symbol )
    return dbase[ collect( 1:dbase.persSize ), field ]
end  # Base.getindex( dbase, field )

# This function sets the given attribute from the personnel with the requested
#   ID to the provided value. If the attribute does not exist, it gets created
#   first. If there is no personnel in the database with the provided ID, an
#   error gets generated.
function Base.setindex!( dbase::PersonnelDatabase, data, id::String,
    attr::AttributeType )
    index = getPosition( dbase, id )

    # Throw an error if the personnel member with the requested ID doesn't
    #   exist.
    if index == 0
        error( "No personnel member with $(string( dbase.idKey )) \"$id\" on ",
            "record." )
    end  # if index == 0

    # Make sure the database has the requested field, then fill it in as needed.
    tmpAttr = Symbol( attr )
    addAttribute!( dbase, tmpAttr )
    dbase[ index ][ tmpAttr ] = tmpAttr == dbase.idKey ? String( data ) : data
end  # Base.setindex!( dbase, data, id, attr )

function Base.setindex!( dbase::PersonnelDatabase, data, ind::T,
    attr::AttributeType ) where T <: Integer
    # Check if the index is in bounds.
    if ( ind <= 0 ) || ( ind > dbase.persSize )
        error( "Cannot request personnel with index $ind: personnel database ",
            "size is only $(dbase.persSize)." )
    end  # if ( ind <= 0 ) || ...

    # Make sure the database has the requested attribute, then fill it in as
    #   needed.
    tmpAttr = Symbol( attr )
    addAttribute!( dbase, tmpAttr )
    dbase[ ind ][ tmpAttr ] = data
end  # Base.setindex!( dbase, data, ind, attr )

# This function sets the given attribute at the given time from the personnel
#   with the requested ID to the provided value. If the attribute does not
#   exist, it gets created first. If there is no personnel in the database with
#   the provided ID, an error gets generated.
function Base.setindex!( dbase::PersonnelDatabase, data, index::DbIndexType,
    attr::AttributeType, timestamp::T ) where T <: Real
    tmpAttr = Symbol( attr )

    if !hasAttribute( dbase, tmpAttr )
        addAttribute!( dbase, tmpAttr, Dict{Symbol, History}() )
    end  # if !hasAttribute( dbase, tmpAttr )

    person = dbase[ index ]
    person[ attr, timestamp ] = data
end  # setindex!( dbase, data, index, attr, timestamp )

# This function prints the database.
function Base.show( io::IO, dbase::PersonnelDatabase )
    print( io, "ID key: $(dbase.idKey)" )
    print( io, "\nAttributes: $(dbase.attrs)" )

    if dbase.persSize == 0
        print( io, "\nNo persons in database." )
        return
    end  # if dbase.persSize == 0

    print( io, "\nPersonnel members" )
    map( person -> displayPersonnel( io, person, dbase.idKey ), dbase.dbase )
end  # Base.show( io, dbase )


text:
# -*- coding: utf-8 -*-
using ModelingToolkit
using MacroTools
using SemanticModels
using SemanticModels.ModelTools.PetriModels
import MacroTools: postwalk
using Test
using Petri

# +
@variables S, I, R

# generated by AMIDOL, basic SIR Model
sir = Petri.Model([S, I, R],
                 [(S+I, 2I), (I,R)])

# +
@variables I′, R′

# rule1 = SI <- SI -> SII
si = Petri.Model([S, I, R],
                 [(S+I, 2I)])

sii = Petri.Model([S, I, I′, R],
                  [(S+I,  2I ),
                   (S+I′, 2I′)]
                 )

rule1 = PetriModels.PetriSpan(si, si, sii)

# +
# rule2 = I <- I -> IR
i = Petri.Model([I′], Tuple{Operation,Operation}[])

ir = Petri.Model([I′, R′], [(I′, R′)])

rule2 = PetriModels.PetriSpan(i, i, ir)

# +
# rule3 = IRI′R′ <- II′ -> II′R
irir = Petri.Model([I, I′, R, R′], [(I, R), (I′, R′)])

ii = Petri.Model([I, I′], Tuple{Operation,Operation}[])

iir = Petri.Model([I, I′, R], [(I, R), (I′, R)])

rule3 = PetriModels.PetriSpan(irir, ii, iir)

# +
# Apply rules to each model in succession

siir = PetriModels.solve(PetriModels.DPOProblem(rule1, sir))

siirr = PetriModels.solve(PetriModels.DPOProblem(rule2, siir))

c′ = PetriModels.dropdown(irir, ii, siirr)
siir′ = PetriModels.solve(PetriModels.DPOProblem(rule3, c′))

println(sir.Δ)
println()
println(siir′.Δ)

ext: jl


text:
using Iris
using Test

@testset "Shapes" begin
    @testset "1D" begin
        @testset "Interval" begin
            i = Interval(0,1; reference=:left)
            @test i.origin.x≈0
            i = Interval(0,1; reference=:right)
            @test i.origin.x≈1
            i = Interval(0,1; reference=:center)
            @test i.origin.x≈.5
            @test i(.5)
            @test !i(-.5)
            @test !i(1.5)
            @test ndims(i)==1
            @test Iris.Common.nsides(i) == 2
        end
    end
    @testset "2D" begin
        @testset "Circle" begin
            c = Circle(1,0,0; reference=:bottom)
            @test c.origin≈Point(0,1)
            c = Circle(1,0,0; reference=:top)
            @test c.origin≈Point(0,-1)
            c = Circle(5,Point(0,0); ϕ=π/3, reference=:left)
            @test c.origin≈Point(5/2,5sqrt(3)/2)
            c = Circle(10,0,0; reference=:right)
            @test c.origin≈Point(-10,0)
            @test !c(Point(.1,0))
            @test c(Point(-.1,0))
            @test c(Point(-10,10-2eps(10.)))
            @test !c(Point(-10,-10-2eps(10.)))
        end
        @testset "Square" begin
            s = Square(1,0,0; reference=:bottom)
            @test s.origin≈Point(0,1/2)
            s = Square(1,0,0; reference=:top)
            @test s.origin≈Point(0,-1/2)
            s = Square(2,Point(0,0); ϕ=π/3, reference=:left)
            @test s.origin≈Point(1/2,1sqrt(3)/2)
            s = Square(10,0,0; reference=:right)
            @test s.origin≈Point(-10/2,0)
            @test !s(Point(.1,0))
            @test s(Point(-.1,0))
            @test s(Point(-5,5-2eps(5.)))
        end
        @testset "Rectangle" begin
            r = Rectangle(1,.5,0,0; reference=:bottom)
            @test r.origin≈Point(0,.25)
            r = Rectangle(1,.5,0,0; reference=:top)
            @test r.origin≈Point(0,-.25)
            r = Rectangle(2,1,Point(0,0); ϕ=π/3, reference=:left)
            @test r.origin≈Point(1/2,sqrt(3)/2)
            r = Rectangle(10,1,0,0; reference=:right)
            @test r.origin≈Point(-10/2,0)
            @test !r(Point(.1,0))
            @test r(Point(-.1,0))
            @test r(Point(-1,.5-2eps(.5)))
            @test !r(Point(-1,-1-2eps(1.)))
        end
    end
end


text:
module PotentialFitting

using Reexport
using ScikitLearn
@reexport using PotentialCalculation

export AbstractPotential,
       AbstractClusterPotential,
       AbstractPairPotential,
       calculate_potential,
       get_potential!,
       MoleculePairPotential,
       PairPotentialTopology,
       ClusterPotentialTopology,
       PairTopologyIndices,
       potential_variables,
       PotentialTopology,

       FitData,
       Fitter,
       fit_potential!,
       get_molecules,
       give_fittable_x,
       give_predictable_x,
       predict_potential,
       rmsd,
       setweight_e_less!,
       setweight_e_more!,

       min_distance,
       plot_potential,
       plot_compare,
       scan_compare,
       scan_visualize,
       visualize_points,
       visualize_point_bio3dview,

       LennardJones,
       GeneralPowers,
       GeneralAngle

include("potentials.jl")
include("fit.jl")
include("visualize.jl")
include("potentials/LennardJones.jl")
include("potentials/GeneralPowers.jl")
include("potentials/GeneralAngle.jl")

end # module


text:
using OrdinaryDiffEq
using Trixi

###############################################################################
# semidiscretization of the compressible Euler equations
gamma = 2.0
equations_euler = CompressibleEulerEquations1D(gamma)

initial_condition = initial_condition_eoc_test_coupled_euler_gravity

polydeg = 3
solver_euler = DGSEM(polydeg, flux_hll)

coordinates_min = 0.0
coordinates_max = 2.0
mesh = TreeMesh(coordinates_min, coordinates_max,
                initial_refinement_level=2,
                n_cells_max=10_000)

semi_euler = SemidiscretizationHyperbolic(mesh, equations_euler, initial_condition, solver_euler)

###############################################################################
# semidiscretization of the hyperbolic diffusion equations
equations_gravity = HyperbolicDiffusionEquations1D()

solver_gravity = DGSEM(polydeg, flux_lax_friedrichs)

semi_gravity = SemidiscretizationHyperbolic(mesh, equations_gravity, initial_condition, solver_gravity,
                                            source_terms=source_terms_harmonic)

###############################################################################
# combining both semidiscretizations for Euler + self-gravity
parameters = ParametersEulerGravity(background_density=2.0, # aka rho0
                                    gravitational_constant=1.0, # aka G
                                    cfl=1.5,
                                    resid_tol=1.0e-10,
                                    n_iterations_max=1000,
                                    timestep_gravity=timestep_gravity_erk52_3Sstar!)

semi = SemidiscretizationEulerGravity(semi_euler, semi_gravity, parameters)

###############################################################################
# ODE solvers, callbacks etc.
tspan = (0.0, 0.5)
ode = semidiscretize(semi, tspan);

summary_callback = SummaryCallback()

analysis_interval = 100
analysis_callback = AnalysisCallback(semi_euler, interval=analysis_interval,
                                     save_analysis=true)

alive_callback = AliveCallback(analysis_interval=analysis_interval)

save_restart = SaveRestartCallback(interval=100,
                                   save_final_restart=true)

save_solution = SaveSolutionCallback(interval=10,
                                     save_initial_solution=true,
                                     save_final_solution=true,
                                     solution_variables=cons2prim)

stepsize_callback = StepsizeCallback(cfl=1.1)

callbacks = CallbackSet(summary_callback,
                        analysis_callback,
                        alive_callback,
                        save_restart,
                        save_solution,
                        stepsize_callback)

###############################################################################
# run the simulation
sol = solve(ode, CarpenterKennedy2N54(williamson_condition=false),
            dt=1.0, # solve needs some value here but it will be overwritten by the stepsize_callback
            save_everystep=false, callback=callbacks);
summary_callback() # print the timer summary
println("Number of gravity subcycles: ", semi.gravity_counter.ncalls_since_readout)