I think everything would be cleaner if your higher-order function was responsible only for factorizing the code that can be factorized everywhere (and not more). This would avoid the need for a test within the nested loops.
For example:
function operate_integration_points!(f, time)
for problem in get_problems(analysis)
for element in get_elements(problem)
for ip in get_integration_points(element)
f(problem, element, ip, time)
end
end
end
end
If you do this, the function f
passed as argument should now be responsible for determining the material
from other arguments. In the specific case of material_preprocess_analysis!
, this would look like
function material_preprocess_analysis_aux!(problem, element, ip, time)
material_type = getfield(Materials, problem.properties.material_model)
material = Material(material_type, tuple())
ip.fields["material"] = field(material)
material_preprocess_analysis!(material, element, ip, time)
end
operate_integration_points!(material_preprocess_analysis_aux!, time)
while in the general case, you would have:
function material_preprocess_increment_aux!(problem, element, ip, time)
material = ip("material", time)
material_preprocess_increment!(material, element, ip, time)
end
operate_integration_points!(material_preprocess_increment_aux!, time)
Now, instead of defining auxilliary functions, you might want to use Julia’s special do
syntax. The last block of code above could be written instead like this:
operate_integration_points!(time) do problem, element, ip, time
material = ip("material", time)
material_preprocess_increment!(material, element, ip, time)
end
Finally, if you have many preprocessing functions which fall in the general case, and you want to factor out the logic of getting the material first, before calling the preprocessing step on it, you can use something like this:
aux(preprocess!) = (problem, element, ip, time) -> begin
material = ip("material", time)
preprocess!(material, element, ip, time)
end
operate_integration_points!(aux(material_preprocess_increment!), time)
operate_integration_points!(aux(material_preprocess_iteration!), time)
Does this make sense?