@@ -721,6 +721,219 @@ function (pca::PConstructorApplicator)(x::AbstractArray{<:AbstractArray})
721721 return pca. p_constructor (pca .(x))
722722end
723723
724+ """
725+ $TYPEDEF
726+
727+ Callable struct designed for use by `MTKParametersReconstructor`. Uses a fixed set of templates to
728+ act as a very dynamic (and limited) observed function returning an array. See `__apply_copy_template`
729+ for the supported templates.
730+ """
731+ struct CopyParamsByTemplate{IsRoot, T, N}
732+ """
733+ List of templates.
734+ """
735+ template:: T # TODO : This field is parametric because I thought we might want to specialize it in some cases.
736+ """
737+ Size of the returned buffer.
738+ """
739+ size:: NTuple{N, Int}
740+ end
741+
742+ function CopyParamsByTemplate {IR} (temp:: T , size:: NTuple{N, Int} ) where {IR, T, N}
743+ return CopyParamsByTemplate {IR, T, N} (temp, size)
744+ end
745+
746+ function __apply_copy_template (valp, template)
747+ p = parameter_values (valp)
748+ u = state_values (valp)
749+ if template isa ParameterIndex{SciMLStructures. Tunable, UnitRange{Int}}
750+ if p isa MTKParameters
751+ return p. tunable[template. idx]
752+ else
753+ return p[template. idx]
754+ end
755+ elseif template isa ParameterIndex{SciMLStructures. Initials, UnitRange{Int}}
756+ return p. initials[template. idx]
757+ elseif template isa ParameterIndex{SciMLStructures. Discrete, Tuple{Int, UnitRange{Int}}}
758+ return p. discrete[template. idx[1 ]][template. idx[2 ]]
759+ elseif template isa ParameterIndex{SciMLStructures. Constants, Tuple{Int, UnitRange{Int}}}
760+ return p. constant[template. idx[1 ]][template. idx[2 ]]
761+ elseif template isa ParameterIndex{Nonnumeric, Tuple{Int, UnitRange{Int}}}
762+ return p. nonnumeric[template. idx[1 ]][template. idx[2 ]]
763+ elseif template isa UnitRange{Int}
764+ return u[template]
765+ elseif template isa ObservedWrapper
766+ return template (valp)
767+ elseif template isa CopyParamsByTemplate
768+ return template (valp)
769+ elseif template isa IndepVarTemplate
770+ return current_time (valp)
771+ else
772+ # MethodError because this is a manual dispatch chain
773+ throw (MethodError (__apply_copy_template, (valp, template)))
774+ end
775+ end
776+
777+ function (cp:: CopyParamsByTemplate{IsRoot} )(src) where {IsRoot}
778+ if IsRoot
779+ reshape (mapreduce (Base. Fix1 (__apply_copy_template, src), vcat, cp. template), cp. size)
780+ else
781+ reshape (map (Base. Fix1 (__apply_copy_template, src), cp. template), cp. size)
782+ end
783+ end
784+
785+ struct IndepVarTemplate end
786+ const IV_TEMPLATE = IndepVarTemplate ()
787+
788+ Base. @nospecializeinfer function __specialize_templates (template:: Vector{Any} , elem_types:: Set{DataType} )
789+ if length (template) <= 4
790+ return Tuple (template)
791+ elseif length (elem_types) <= 4
792+ return Vector {Union{collect(elem_types)...}} (template)
793+ else
794+ return template
795+ end
796+ end
797+
798+ function CopyParamsByTemplate (srcsys:: AbstractSystem , syms:: AbstractArray{SymbolicT} ; kws... )
799+ template = []
800+ elem_types = Set {DataType} ()
801+ iv = get_iv (srcsys)
802+ for sym in syms
803+ if iv isa SymbolicT && isequal (iv, sym)
804+ push! (template, IV_TEMPLATE)
805+ push! (elem_types, IndepVarTemplate)
806+ continue
807+ end
808+ symidx = parameter_index (srcsys, sym)
809+ if symidx === nothing
810+ symidx = variable_index (srcsys, sym)
811+ if symidx === nothing
812+ if isempty (template)
813+ push! (elem_types, Vector{SymbolicT})
814+ push! (template, SymbolicT[sym])
815+ continue
816+ end
817+ prev = template[end ]
818+ if prev isa Vector{SymbolicT}
819+ push! (prev, sym)
820+ else
821+ push! (elem_types, Vector{SymbolicT})
822+ push! (template, SymbolicT[sym])
823+ end
824+ continue
825+ end
826+ if isempty (template)
827+ push! (elem_types, UnitRange{Int})
828+ push! (template, symidx: symidx)
829+ continue
830+ end
831+ prev = template[end ]
832+ if prev isa UnitRange{Int} && last (prev) + 1 == symidx
833+ template[end ] = first (prev): symidx
834+ else
835+ push! (elem_types, UnitRange{Int})
836+ push! (template, symidx: symidx)
837+ end
838+ continue
839+ elseif symidx isa Int
840+ symidx = ParameterIndex (SciMLStructures. Tunable (), symidx)
841+ end
842+ portion = symidx. portion
843+ _bufidx = symidx. idx
844+ bufidx:: UnitRange{Int} = if _bufidx isa AbstractVector{Int}
845+ @assert isequal (vec (_bufidx), first (_bufidx): last (_bufidx))
846+ subidx = nothing
847+ first (_bufidx): last (_bufidx)
848+ elseif _bufidx isa Int
849+ subidx = nothing
850+ _bufidx: _bufidx
851+ elseif _bufidx isa NTuple{2 , Int}
852+ subidx = _bufidx[1 ]
853+ _bufidx[2 ]: _bufidx[2 ]
854+ else
855+ # Will error due to the typeassert on `bufidx`
856+ nothing
857+ end
858+ if isempty (template)
859+ pidx = if subidx === nothing
860+ ParameterIndex (symidx. portion, bufidx)
861+ else
862+ ParameterIndex (symidx. portion, (subidx, bufidx))
863+ end
864+ push! (template, pidx)
865+ push! (elem_types, typeof (pidx))
866+ continue
867+ end
868+ prev = template[end ]
869+ if prev isa ParameterIndex && prev. portion === symidx. portion && (subidx === nothing && last (prev. idx) + 1 == first (bufidx) || subidx == prev. idx[1 ] && last (prev. idx[2 ]) + 1 == first (bufidx))
870+ if subidx === nothing
871+ template[end ] = ParameterIndex (prev. portion, first (prev. idx): last (bufidx))
872+ else
873+ template[end ] = ParameterIndex (prev. portion, (subidx, first (prev. idx[2 ]): last (bufidx)))
874+ end
875+ elseif subidx === nothing
876+ push! (template, ParameterIndex (symidx. portion, bufidx))
877+ push! (elem_types, typeof (template[end ]))
878+ else
879+ push! (template, ParameterIndex (symidx. portion, (subidx, bufidx)))
880+ push! (elem_types, typeof (template[end ]))
881+ end
882+ end
883+
884+ for i in eachindex (template)
885+ if template[i] isa Vector{SymbolicT}
886+ template[i] = concrete_getu (srcsys, template[i]; wrap_as_any = true , kws... )
887+ delete! (elem_types, Vector{SymbolicT})
888+ push! (elem_types, typeof (template[i]))
889+ end
890+ end
891+
892+ return CopyParamsByTemplate {true} (__specialize_templates (template, elem_types), size (syms))
893+ end
894+
895+ function CopyParamsByTemplate (srcsys:: AbstractSystem , syms:: AbstractArray ; kws... )
896+ template = []
897+ elem_types = Set {DataType} ()
898+ for sym in syms
899+ push! (template, CopyParamsByTemplate (srcsys, sym; kws... ))
900+ push! (elem_types, typeof (template[end ]))
901+ end
902+ return CopyParamsByTemplate {false} (__specialize_templates (template, elem_types), size (syms))
903+ end
904+
905+ struct MTKParametersReconstructor{T, I, D, C, N}
906+ tunables_fn:: T
907+ initials_fn:: I
908+ discretes_fn:: D
909+ consts_fn:: C
910+ nonnumerics_fn:: N
911+ diffcache_buffer_idx:: Int
912+ end
913+
914+ # TODO : make this infer when the nonnumerics are non-trivial
915+ function (recon:: MTKParametersReconstructor )(src, dst)
916+ src_ps = parameter_values (src)
917+ dst_ps = parameter_values (dst)
918+ oldcache = dst_ps. caches
919+ # I don't know why but this makes it infer properly
920+ if recon. tunables_fn isa ComposedFunction
921+ tunablevals = recon. tunables_fn. outer (recon. tunables_fn. inner (src))
922+ else
923+ tunablevals = recon. tunables_fn (src)
924+ end
925+ initialvals = recon. initials_fn (src)
926+ nonnumerics = recon. nonnumerics_fn (src):: typeof (dst_ps. nonnumeric)
927+ (; diffcache_buffer_idx) = recon
928+ if ! iszero (diffcache_buffer_idx)
929+ @set! nonnumerics[diffcache_buffer_idx] = DiffCacheAllocatorAPIWrapper {ForwardDiff.valtype(eltype(initialvals))} .(nonnumerics[diffcache_buffer_idx])
930+ end
931+ return MTKParameters (
932+ tunablevals, initialvals, recon. discretes_fn (src),
933+ recon. consts_fn (src), nonnumerics, oldcache isa Tuple{} ? () : copy .(oldcache)
934+ )
935+ end
936+
724937"""
725938 $(TYPEDSIGNATURES)
726939
@@ -735,10 +948,10 @@ takes a value provider of `srcsys` and a value provider of `dstsys` and returns
735948 unwrapped.
736949- `p_constructor`: The `p_constructor` argument to `process_SciMLProblem`.
737950"""
738- function get_mtkparameters_reconstructor (
951+ function MTKParametersReconstructor (
739952 srcsys:: AbstractSystem , dstsys:: AbstractSystem ;
740953 initials = false , unwrap_initials = false , p_constructor = identity,
741- eval_expression = false , eval_module = @__MODULE__ , force_time_independent = false ,
954+ force_time_independent = false ,
742955 kwargs...
743956 )
744957 _p_constructor = p_constructor
@@ -757,32 +970,27 @@ function get_mtkparameters_reconstructor(
757970 tunable_getter = if isempty (tunable_syms)
758971 Returns (SVector {0, Float64} ())
759972 else
760- p_constructor ∘ concrete_getu (
761- srcsys, tunable_syms; eval_expression, eval_module,
762- force_time_independent, kwargs...
763- )
973+ p_constructor ∘ CopyParamsByTemplate (srcsys, tunable_syms; kwargs... )
764974 end
765975 initials_getter = if initials && ! isempty (syms[2 ])
766- initsyms = Vector {Any} ( syms[2 ])
767- allsyms = Set (variable_symbols (srcsys))
976+ initsyms = syms[2 ]:: Vector{SymbolicT}
977+ allsyms = Set {SymbolicT} (variable_symbols (srcsys))
768978 if unwrap_initials
769979 for i in eachindex (initsyms)
770980 sym = initsyms[i]
771- innersym = if operation (sym) === getindex
772- sym, idxs... = arguments (sym)
773- only (arguments (sym))[idxs... ]
981+ arr, isarr = split_indexed_var (sym)
982+ innersym = if isarr
983+ sidx = get_stable_index (sym)
984+ first (arguments (arr))[sidx]
774985 else
775- only (arguments (sym ))
986+ first (arguments (arr ))
776987 end
777988 if innersym in allsyms
778989 initsyms[i] = innersym
779990 end
780991 end
781992 end
782- p_constructor ∘ concrete_getu (
783- srcsys, initsyms; eval_expression, eval_module,
784- force_time_independent, kwargs...
785- )
993+ p_constructor ∘ CopyParamsByTemplate (srcsys, initsyms; kwargs... )
786994 else
787995 Returns (SVector {0, Float64} ())
788996 end
@@ -795,29 +1003,25 @@ function get_mtkparameters_reconstructor(
7951003 p_constructor (map (x -> x. length, bufsizes))
7961004 end
7971005 )
1006+
7981007 # discretes need to be blocked arrays
7991008 # the `getu` returns a tuple of arrays corresponding to `p.discretes`
8001009 # `Base.Fix1(...)` applies `p_constructor` to each of the arrays in the tuple
8011010 # `Base.Fix2(...)` does `BlockedArray.(tuple_of_arrs, blockarrsizes)` returning a
8021011 # tuple of `BlockedArray`s
8031012 Base. Fix2 (Broadcast. BroadcastFunction (BlockedArray), blockarrsizes) ∘
804- Base. Fix1 (broadcast, p_constructor) ∘
1013+ Base. Fix1 (broadcast, p_constructor) ∘ Tuple ∘
8051014 # This `broadcast.(collect, ...)` avoids `ReshapedArray`/`SubArray`s from
8061015 # appearing in the result.
807- concrete_getu (
808- srcsys, Tuple (broadcast .(collect, syms[3 ]));
809- eval_expression, eval_module, force_time_independent, kwargs...
810- )
1016+ CopyParamsByTemplate (srcsys, broadcast .(collect, syms[3 ]); kwargs... )
8111017 end
812- const_getter = if syms[4 ] == ( )
1018+ const_getter = if isempty ( syms[4 ])
8131019 Returns (())
8141020 else
815- Base. Fix1 (broadcast, p_constructor) ∘ concrete_getu (
816- srcsys, Tuple (syms[4 ]);
817- eval_expression, eval_module, force_time_independent, kwargs...
818- )
1021+ Base. Fix1 (broadcast, p_constructor) ∘ Tuple ∘ CopyParamsByTemplate (srcsys, syms[4 ]; kwargs... )
8191022 end
820- nonnumeric_getter = if syms[5 ] == ()
1023+ diffcache_buffer_idx = 0
1024+ nonnumeric_getter = if isempty (syms[5 ])
8211025 Returns (())
8221026 else
8231027 ic = get_index_cache (dstsys)
@@ -828,44 +1032,19 @@ function get_mtkparameters_reconstructor(
8281032 )
8291033
8301034 diffcache_params = SU. getmetadata (dstsys, DiffCacheParams, Dict {SymbolicT, Int} ()):: Dict{SymbolicT, Int}
831- diffcache_buffer_idx = 0
8321035 if ! isempty (diffcache_params)
8331036 representative = first (keys (diffcache_params))
8341037 diffcache_buffer_idx, _ = ic. nonnumeric_idx[representative]
8351038 @set! buftypes[diffcache_buffer_idx] = identity
1039+ for (i, sym) in enumerate (syms[5 ][diffcache_buffer_idx])
1040+ end
8361041 end
8371042 # nonnumerics retain the assigned buffer type without narrowing
8381043 Base. Fix1 (broadcast, _p_constructor) ∘
839- Base. Fix1 (Broadcast. BroadcastFunction (call), buftypes) ∘
840- concrete_getu (
841- srcsys, Tuple (syms[5 ]);
842- eval_expression, eval_module, force_time_independent, kwargs...
843- )
844- end
845- getters = (
846- tunable_getter, initials_getter, discs_getter, const_getter, nonnumeric_getter,
847- )
848- getter = let getters = getters, diffcache_buffer_idx = diffcache_buffer_idx
849- function _getter (valp, initprob)
850- oldcache = parameter_values (initprob). caches
851- tunablevals = getters[1 ](valp)
852- initialvals = getters[2 ](valp)
853- nonnumerics = getters[5 ](valp)
854- if ! iszero (diffcache_buffer_idx)
855- @set! nonnumerics[diffcache_buffer_idx] = DiffCacheAllocatorAPIWrapper {ForwardDiff.valtype(eltype(initialvals))} .(nonnumerics[diffcache_buffer_idx])
856- end
857- return promote_with_nothing (
858- promote_type_with_nothing (eltype (tunablevals), initialvals),
859- MTKParameters (
860- tunablevals, initialvals, getters[3 ](valp),
861- getters[4 ](valp), nonnumerics, oldcache isa Tuple{} ? () :
862- copy .(oldcache)
863- )
864- )
865- end
1044+ Base. Fix1 (Broadcast. BroadcastFunction (call), buftypes) ∘ Tuple ∘ CopyParamsByTemplate (srcsys, syms[5 ]; kwargs... )
8661045 end
8671046
868- return getter
1047+ return MTKParametersReconstructor (tunable_getter, initials_getter, discs_getter, const_getter, nonnumeric_getter, diffcache_buffer_idx)
8691048end
8701049
8711050function call (f, args... )
@@ -893,7 +1072,7 @@ function ReconstructInitializeprob(
8931072 kwargs...
8941073 )
8951074 if is_split (dstsys)
896- pgetter = get_mtkparameters_reconstructor (
1075+ pgetter = MTKParametersReconstructor (
8971076 srcsys, dstsys; p_constructor, eval_expression, eval_module,
8981077 force_time_independent = is_steadystateprob, kwargs...
8991078 )
@@ -973,7 +1152,7 @@ function construct_initializeprobpmap(
9731152 )
9741153 @assert is_initializesystem (initsys)
9751154 if is_split (sys)
976- return let getter = get_mtkparameters_reconstructor (
1155+ return let getter = MTKParametersReconstructor (
9771156 initsys, sys; initials = true , unwrap_initials = true , p_constructor,
9781157 eval_expression, eval_module, kwargs...
9791158 )
0 commit comments