@@ -721,6 +721,223 @@ 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+ buffers = map (Base. Fix1 (__apply_copy_template, src), cp. template)
782+ if cp. template isa Tuple
783+ buffers = collect (buffers)
784+ end
785+ reshape (buffers, cp. size)
786+ end
787+ end
788+
789+ struct IndepVarTemplate end
790+ const IV_TEMPLATE = IndepVarTemplate ()
791+
792+ Base. @nospecializeinfer function __specialize_templates (template:: Vector{Any} , elem_types:: Set{DataType} )
793+ if length (template) <= 4
794+ return Tuple (template)
795+ elseif length (elem_types) <= 4
796+ return Vector {Union{collect(elem_types)...}} (template)
797+ else
798+ return template
799+ end
800+ end
801+
802+ function CopyParamsByTemplate (srcsys:: AbstractSystem , syms:: AbstractArray{SymbolicT} ; kws... )
803+ template = []
804+ elem_types = Set {DataType} ()
805+ iv = get_iv (srcsys)
806+ for sym in syms
807+ if iv isa SymbolicT && isequal (iv, sym)
808+ push! (template, IV_TEMPLATE)
809+ push! (elem_types, IndepVarTemplate)
810+ continue
811+ end
812+ symidx = parameter_index (srcsys, sym)
813+ if symidx === nothing
814+ symidx = variable_index (srcsys, sym)
815+ if symidx === nothing
816+ if isempty (template)
817+ push! (elem_types, Vector{SymbolicT})
818+ push! (template, SymbolicT[sym])
819+ continue
820+ end
821+ prev = template[end ]
822+ if prev isa Vector{SymbolicT}
823+ push! (prev, sym)
824+ else
825+ push! (elem_types, Vector{SymbolicT})
826+ push! (template, SymbolicT[sym])
827+ end
828+ continue
829+ end
830+ if isempty (template)
831+ push! (elem_types, UnitRange{Int})
832+ push! (template, symidx: symidx)
833+ continue
834+ end
835+ prev = template[end ]
836+ if prev isa UnitRange{Int} && last (prev) + 1 == symidx
837+ template[end ] = first (prev): symidx
838+ else
839+ push! (elem_types, UnitRange{Int})
840+ push! (template, symidx: symidx)
841+ end
842+ continue
843+ elseif symidx isa Int
844+ symidx = ParameterIndex (SciMLStructures. Tunable (), symidx)
845+ end
846+ portion = symidx. portion
847+ _bufidx = symidx. idx
848+ bufidx:: UnitRange{Int} = if _bufidx isa AbstractVector{Int}
849+ @assert isequal (vec (_bufidx), first (_bufidx): last (_bufidx))
850+ subidx = nothing
851+ first (_bufidx): last (_bufidx)
852+ elseif _bufidx isa Int
853+ subidx = nothing
854+ _bufidx: _bufidx
855+ elseif _bufidx isa NTuple{2 , Int}
856+ subidx = _bufidx[1 ]
857+ _bufidx[2 ]: _bufidx[2 ]
858+ else
859+ # Will error due to the typeassert on `bufidx`
860+ nothing
861+ end
862+ if isempty (template)
863+ pidx = if subidx === nothing
864+ ParameterIndex (symidx. portion, bufidx)
865+ else
866+ ParameterIndex (symidx. portion, (subidx, bufidx))
867+ end
868+ push! (template, pidx)
869+ push! (elem_types, typeof (pidx))
870+ continue
871+ end
872+ prev = template[end ]
873+ 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))
874+ if subidx === nothing
875+ template[end ] = ParameterIndex (prev. portion, first (prev. idx): last (bufidx))
876+ else
877+ template[end ] = ParameterIndex (prev. portion, (subidx, first (prev. idx[2 ]): last (bufidx)))
878+ end
879+ elseif subidx === nothing
880+ push! (template, ParameterIndex (symidx. portion, bufidx))
881+ push! (elem_types, typeof (template[end ]))
882+ else
883+ push! (template, ParameterIndex (symidx. portion, (subidx, bufidx)))
884+ push! (elem_types, typeof (template[end ]))
885+ end
886+ end
887+
888+ for i in eachindex (template)
889+ if template[i] isa Vector{SymbolicT}
890+ template[i] = concrete_getu (srcsys, template[i]; wrap_as_any = true , kws... )
891+ delete! (elem_types, Vector{SymbolicT})
892+ push! (elem_types, typeof (template[i]))
893+ end
894+ end
895+
896+ return CopyParamsByTemplate {true} (__specialize_templates (template, elem_types), size (syms))
897+ end
898+
899+ function CopyParamsByTemplate (srcsys:: AbstractSystem , syms:: AbstractArray ; kws... )
900+ template = []
901+ elem_types = Set {DataType} ()
902+ for sym in syms
903+ push! (template, CopyParamsByTemplate (srcsys, sym; kws... ))
904+ push! (elem_types, typeof (template[end ]))
905+ end
906+ return CopyParamsByTemplate {false} (__specialize_templates (template, elem_types), size (syms))
907+ end
908+
909+ struct MTKParametersReconstructor{T, I, D, C, N}
910+ tunables_fn:: T
911+ initials_fn:: I
912+ discretes_fn:: D
913+ consts_fn:: C
914+ nonnumerics_fn:: N
915+ diffcache_buffer_idx:: Int
916+ end
917+
918+ # TODO : make this infer when the nonnumerics are non-trivial
919+ function (recon:: MTKParametersReconstructor )(src, dst)
920+ src_ps = parameter_values (src)
921+ dst_ps = parameter_values (dst)
922+ oldcache = dst_ps. caches
923+ # I don't know why but this makes it infer properly
924+ if recon. tunables_fn isa ComposedFunction
925+ tunablevals = recon. tunables_fn. outer (recon. tunables_fn. inner (src))
926+ else
927+ tunablevals = recon. tunables_fn (src)
928+ end
929+ initialvals = recon. initials_fn (src)
930+ nonnumerics = recon. nonnumerics_fn (src):: typeof (dst_ps. nonnumeric)
931+ (; diffcache_buffer_idx) = recon
932+ if ! iszero (diffcache_buffer_idx)
933+ @set! nonnumerics[diffcache_buffer_idx] = DiffCacheAllocatorAPIWrapper {ForwardDiff.valtype(eltype(initialvals))} .(nonnumerics[diffcache_buffer_idx])
934+ end
935+ return MTKParameters (
936+ tunablevals, initialvals, recon. discretes_fn (src),
937+ recon. consts_fn (src), nonnumerics, oldcache isa Tuple{} ? () : copy .(oldcache)
938+ )
939+ end
940+
724941"""
725942 $(TYPEDSIGNATURES)
726943
@@ -735,10 +952,10 @@ takes a value provider of `srcsys` and a value provider of `dstsys` and returns
735952 unwrapped.
736953- `p_constructor`: The `p_constructor` argument to `process_SciMLProblem`.
737954"""
738- function get_mtkparameters_reconstructor (
955+ function MTKParametersReconstructor (
739956 srcsys:: AbstractSystem , dstsys:: AbstractSystem ;
740957 initials = false , unwrap_initials = false , p_constructor = identity,
741- eval_expression = false , eval_module = @__MODULE__ , force_time_independent = false ,
958+ force_time_independent = false ,
742959 kwargs...
743960 )
744961 _p_constructor = p_constructor
@@ -757,32 +974,27 @@ function get_mtkparameters_reconstructor(
757974 tunable_getter = if isempty (tunable_syms)
758975 Returns (SVector {0, Float64} ())
759976 else
760- p_constructor ∘ concrete_getu (
761- srcsys, tunable_syms; eval_expression, eval_module,
762- force_time_independent, kwargs...
763- )
977+ p_constructor ∘ CopyParamsByTemplate (srcsys, tunable_syms; kwargs... )
764978 end
765979 initials_getter = if initials && ! isempty (syms[2 ])
766- initsyms = Vector {Any} ( syms[2 ])
767- allsyms = Set (variable_symbols (srcsys))
980+ initsyms = syms[2 ]:: Vector{SymbolicT}
981+ allsyms = Set {SymbolicT} (variable_symbols (srcsys))
768982 if unwrap_initials
769983 for i in eachindex (initsyms)
770984 sym = initsyms[i]
771- innersym = if operation (sym) === getindex
772- sym, idxs... = arguments (sym)
773- only (arguments (sym))[idxs... ]
985+ arr, isarr = split_indexed_var (sym)
986+ innersym = if isarr
987+ sidx = get_stable_index (sym)
988+ first (arguments (arr))[sidx]
774989 else
775- only (arguments (sym ))
990+ first (arguments (arr ))
776991 end
777992 if innersym in allsyms
778993 initsyms[i] = innersym
779994 end
780995 end
781996 end
782- p_constructor ∘ concrete_getu (
783- srcsys, initsyms; eval_expression, eval_module,
784- force_time_independent, kwargs...
785- )
997+ p_constructor ∘ CopyParamsByTemplate (srcsys, initsyms; kwargs... )
786998 else
787999 Returns (SVector {0, Float64} ())
7881000 end
@@ -795,29 +1007,25 @@ function get_mtkparameters_reconstructor(
7951007 p_constructor (map (x -> x. length, bufsizes))
7961008 end
7971009 )
1010+
7981011 # discretes need to be blocked arrays
7991012 # the `getu` returns a tuple of arrays corresponding to `p.discretes`
8001013 # `Base.Fix1(...)` applies `p_constructor` to each of the arrays in the tuple
8011014 # `Base.Fix2(...)` does `BlockedArray.(tuple_of_arrs, blockarrsizes)` returning a
8021015 # tuple of `BlockedArray`s
8031016 Base. Fix2 (Broadcast. BroadcastFunction (BlockedArray), blockarrsizes) ∘
804- Base. Fix1 (broadcast, p_constructor) ∘
1017+ Base. Fix1 (broadcast, p_constructor) ∘ Tuple ∘
8051018 # This `broadcast.(collect, ...)` avoids `ReshapedArray`/`SubArray`s from
8061019 # appearing in the result.
807- concrete_getu (
808- srcsys, Tuple (broadcast .(collect, syms[3 ]));
809- eval_expression, eval_module, force_time_independent, kwargs...
810- )
1020+ CopyParamsByTemplate (srcsys, broadcast .(collect, syms[3 ]); kwargs... )
8111021 end
812- const_getter = if syms[4 ] == ( )
1022+ const_getter = if isempty ( syms[4 ])
8131023 Returns (())
8141024 else
815- Base. Fix1 (broadcast, p_constructor) ∘ concrete_getu (
816- srcsys, Tuple (syms[4 ]);
817- eval_expression, eval_module, force_time_independent, kwargs...
818- )
1025+ Base. Fix1 (broadcast, p_constructor) ∘ Tuple ∘ CopyParamsByTemplate (srcsys, syms[4 ]; kwargs... )
8191026 end
820- nonnumeric_getter = if syms[5 ] == ()
1027+ diffcache_buffer_idx = 0
1028+ nonnumeric_getter = if isempty (syms[5 ])
8211029 Returns (())
8221030 else
8231031 ic = get_index_cache (dstsys)
@@ -828,44 +1036,19 @@ function get_mtkparameters_reconstructor(
8281036 )
8291037
8301038 diffcache_params = SU. getmetadata (dstsys, DiffCacheParams, Dict {SymbolicT, Int} ()):: Dict{SymbolicT, Int}
831- diffcache_buffer_idx = 0
8321039 if ! isempty (diffcache_params)
8331040 representative = first (keys (diffcache_params))
8341041 diffcache_buffer_idx, _ = ic. nonnumeric_idx[representative]
8351042 @set! buftypes[diffcache_buffer_idx] = identity
1043+ for (i, sym) in enumerate (syms[5 ][diffcache_buffer_idx])
1044+ end
8361045 end
8371046 # nonnumerics retain the assigned buffer type without narrowing
8381047 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
1048+ Base. Fix1 (Broadcast. BroadcastFunction (call), buftypes) ∘ Tuple ∘ CopyParamsByTemplate (srcsys, syms[5 ]; kwargs... )
8661049 end
8671050
868- return getter
1051+ return MTKParametersReconstructor (tunable_getter, initials_getter, discs_getter, const_getter, nonnumeric_getter, diffcache_buffer_idx)
8691052end
8701053
8711054function call (f, args... )
@@ -893,7 +1076,7 @@ function ReconstructInitializeprob(
8931076 kwargs...
8941077 )
8951078 if is_split (dstsys)
896- pgetter = get_mtkparameters_reconstructor (
1079+ pgetter = MTKParametersReconstructor (
8971080 srcsys, dstsys; p_constructor, eval_expression, eval_module,
8981081 force_time_independent = is_steadystateprob, kwargs...
8991082 )
@@ -973,7 +1156,7 @@ function construct_initializeprobpmap(
9731156 )
9741157 @assert is_initializesystem (initsys)
9751158 if is_split (sys)
976- return let getter = get_mtkparameters_reconstructor (
1159+ return let getter = MTKParametersReconstructor (
9771160 initsys, sys; initials = true , unwrap_initials = true , p_constructor,
9781161 eval_expression, eval_module, kwargs...
9791162 )
0 commit comments