-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
large values for the Pinball env #185
Comments
By default initial field do you mean all zeros? I would say that's likely expected behavior - I would recommend initializing with a nonzero field if at all possible, whether a snapshot from a previous transient run, a perturbed steady-state solution, mean field, etc. |
@jcallaham Hello, The initial field is the default field when you do not provide Thanks to your example on the Cavity, I also tried with a perturbed steady-state flow, and I observed the same behaviour. I will provide you with some evidence. |
Can you share the code to reproduce in the case of the perturbed
steady-state flow? I haven't seen anything that looks like the screenshot
you shared when I've done that.
…On Wed, Sep 11, 2024, 10:45 AM Hosseinkhan Rémy ***@***.***> wrote:
@jcallaham <https://github.com/jcallaham> Hello,
The initial field is the default field when you do not provide restart or
apply load_checkpoint to the flow. So I guess it is zero. I also tried
with a perturbated steady-state flow and I observe the same behaviour.
—
Reply to this email directly, view it on GitHub
<#185 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AG6KRLTJI6HTBPU5OY6AIIDZWBJSDAVCNFSM6AAAAABN655GU2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNBTHA4DOMJZG4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Just for information:
Then you answered a fix on the control term has been applied in #132 . I will come back with a minimal working example (if there is indeed an issue from my side). |
This code should be self-contained. I changed the signature of You can observe a large amount of energy at the beginning of the run (note that I am a beginner in CFD, and this may be normal to an initiate; however, for data-driven control, the associated value is an anomaly). This could cause issues because the user needs to find stable initial checkpoints for all flows or let the flow evolve for some amount of time before interacting with it. #146 is thus important, I think. This behaviour is observed for any mesh. PS: Sorry the code is a bit long, but there are a lot of boilerplate and quite simple functions. import pathlib
from typing import Type
# import tempfile
import firedrake as fd # pyright: ignore [reportMissingImports]
import hydrogym.firedrake as hgym
# from tensorboard.compat.proto.types_pb2 import DT_STRING
LIST_MESHES = ["coarse", "medium", "fine"]
LIST_STR_FLOWS = ["cylinder", "pinball", "cavity", "backward_facing_step"]
ACTION_MAGNITUDE = 0.0
N_STEPS = 10
DT = 0.0001
# noinspection DuplicatedCode
def integrate_no_control(gym_env: hgym.FlowEnv, n_steps: int | float) -> None:
assert (float(n_steps)).is_integer(), "n_steps must be an integer"
n_steps = int(n_steps)
array_action = gym_env.action_space.sample() * ACTION_MAGNITUDE
for i in range(n_steps):
# gym_env.step(array_action)
obs, reward, done, info = gym_env.step(array_action)
print(f"Step {i} - Obs {obs} - Reward {reward} - Done {done} - Info {info}")
def get_hydrogym_flow(name_flow: str) -> Type[hgym.FlowConfig]:
assert name_flow in LIST_STR_FLOWS, "Invalid flow name"
if name_flow == "cylinder":
return hgym.Cylinder
elif name_flow == "pinball":
return hgym.Pinball
elif name_flow == "cavity":
return hgym.Cavity
elif name_flow == "backward_facing_step":
return hgym.Step
else:
raise ValueError("Invalid flow name")
def reynolds_curriculum(
name_flow: str,
reynolds_number: int,
) -> list[int]:
assert name_flow in LIST_STR_FLOWS, "Invalid flow name"
assert reynolds_number > 0, "Reynolds number must be positive"
list_reynolds_cavity = [500, 1000, 2000, 4000, 7500]
list_reynolds_pinball = [60, 80, 90, 100, 120, 130]
list_reynolds_cylinder = [100, 120, 130]
if name_flow == "cavity" and reynolds_number > min(list_reynolds_cavity):
# Extract sub-list of Reynolds numbers
list_curriculum = [
reynolds for reynolds in list_reynolds_cavity if reynolds < reynolds_number
]
list_curriculum.append(reynolds_number)
elif name_flow == "pinball" and reynolds_number > min(list_reynolds_pinball):
# Extract sub-list of Reynolds numbers
list_curriculum = [
reynolds for reynolds in list_reynolds_pinball if reynolds < reynolds_number
]
list_curriculum.append(reynolds_number)
elif name_flow == "cylinder" and reynolds_number > min(list_reynolds_cylinder):
# Extract sub-list of Reynolds numbers
list_curriculum = [
reynolds
for reynolds in list_reynolds_cylinder
if reynolds < reynolds_number
]
list_curriculum.append(reynolds_number)
else:
list_curriculum = [reynolds_number]
return list_curriculum
def compute_steady_state(flow: hgym.FlowConfig,
reynolds_number: int,
name_mesh_resolution: str,
stabilization: str = "none", solver_parameters=None):
if solver_parameters is None:
solver_parameters = {}
assert stabilization in [
"none",
"gls",
], "Invalid stabilization method" # TODO: Augment stabilization methods
assert name_mesh_resolution in LIST_MESHES, "Invalid mesh resolution"
assert reynolds_number > 0, "Reynolds number must be positive"
# Generate
solver = hgym.NewtonSolver(
flow=flow,
stabilization=stabilization, # pyright: ignore [reportCallIssue]
solver_parameters=solver_parameters,
)
# Degree of freedom
dof: int = flow.mixed_space.dim()
hgym.print(f"Total dof: {dof} --- dof/rank: {int(dof / fd.COMM_WORLD.size)}")
# Get the Reynolds curriculum
list_reynolds_curriculum = reynolds_curriculum(
# Extract flow name from the class name
name_flow=flow.__class__.__name__.lower(),
reynolds_number=reynolds_number
)
for reynolds_number in list_reynolds_curriculum:
flow.Re.assign(reynolds_number)
hgym.print(f"Steady solve at Re={reynolds_number}")
solver.solve()
# pressure = flow.p
# velocity = flow.u
# vorticity = flow.vorticity()
# if path_output_data is not None create a temporary directory
# if path_output_data is None:
# path_output_data = tempfile.TemporaryDirectory().name
# if path_output_data is not None:
# # noinspection PyTypeChecker
# # Create output directory with Pathlib
# pathlib.Path(path_output_data).mkdir(parents=True, exist_ok=True)
#
# with tempfile.TemporaryDirectory() as tmpfile:
# if path_output_data is None:
# path_output_data = tmpfile
# # Save the solution
# flow.save_checkpoint(f"{path_output_data}/{reynolds_number}_steady.h5")
# # noinspection PyUnresolvedReferences
# pvd = fd.output.VTKFile(f"{path_output_data}/{reynolds_number}_steady.pvd")
# pvd.write(velocity, pressure, vorticity)
return flow
if __name__ == "__main__":
def main():
name_flow = "pinball"
reynolds_number = 10
name_mesh_resolution = "fine"
stabilization = "none"
solver_parameters = {"snes_monitor": None}
# Output directory
# name_directory = "_".join(
# [name_flow, str(reynolds_number), name_mesh_resolution,
# stabilization])
# path_output_data = (f"{PATH_PROJECT_ROOT}/data/steady_state"
# f"/{name_flow}/{name_directory}")
path_output_data = None
# Create output directory with Pathlib
if path_output_data is not None:
# noinspection PyTypeChecker
pathlib.Path(path_output_data).mkdir(parents=True, exist_ok=True)
n_steps = N_STEPS
dt = DT
# path_initial_vectorfield =
# Integrate
dict_hydrogym_config = {
"flow": get_hydrogym_flow(name_flow=name_flow),
"flow_config": {
# "restart": path_initial_vectorfield,
"mesh": name_mesh_resolution,
},
"solver": hgym.SemiImplicitBDF, # pyright: ignore [reportAttributeAccessIssue]
"solver_config": {
"dt": dt,
},
# "callbacks": None,
}
gym_env = hgym.FlowEnv(env_config=dict_hydrogym_config)
# DEBUG: This should set the steady state solution as the initial condition !
compute_steady_state(flow=gym_env.flow, # pyright: ignore
reynolds_number=reynolds_number,
name_mesh_resolution=name_mesh_resolution,
stabilization=stabilization,
solver_parameters=solver_parameters)
#
# # Create hydrogym environment
integrate_no_control(gym_env=gym_env, n_steps=n_steps)
main() OuputRemark the large values at the beginning.
|
Regarding this,
I do not observe any explosion with actions sampled uniformly up to twice the maximum magnitude of the action space anymore. |
Okay, I think what's happening in the case of your code is that the BDF solver is created when the flow field is uniformly zero, so all the historical fields I guess the assumption in the # ... steady-state solve
# Create hydrogym environment
gym_env.solver = hgym.SemiImplicitBDF(gym_env.flow, dt=dt) # Create a new solver initialized with the steady-state fields
integrate_no_control(gym_env=gym_env, n_steps=n_steps) Otherwise I would recommend pre-computing the steady state and storing it as a restart and then initializing the However, I do think that this should work if you were to call |
Thank you very much.
This is what I do in practice.
Does
If I get it correctly, the zero initialisation of the previous values creates very large derivatives for the first steps, which causes the observed behaviour? |
Yes exactly. If you create a
Yes, the time derivative term in the NS residual is estimated like this for BDF: k_idx = k - 1
u_BDF = sum(beta * u_n for beta, u_n in zip(_beta_BDF[k_idx], self.u_prev))
alpha_k = _alpha_BDF[k_idx]
u_t = (alpha_k * u - u_BDF) / h # BDF estimate of time derivative So if the |
Hi @jcallaham , I have some questions regarding the behaviour of the flow under control. Thank you very much!!:) Illustrations: Cylinder FlowThe observation
|
I would say this is likely a result of what you might call "feedthrough". In a linear system
if the matrix D is not zero then the output depends directly on the input. I've only done this linear analysis for the cylinder, but at least in that case I can confirm that the feedthrough matrix is nonzero. With that in mind, here's how I would explain your results:
You might confirm this by looking for coherence between the input and output at frequencies well above the natural oscillation frequency of the flow. If there is coherence, it would tend to support the idea that there is a feedthrough effect. Unless you suspect this is a bug, I might go ahead and close this issue - we can continue in the discussion section if you want. |
@jcallaham Thank you very much. I will read a bit about "Feedthrough" and related concepts soon. Indeed, you can close this issue or, if possible, transform it into a discussion now. Don't you think that there are possible issues with integration (on the boundary) since the signal Best, |
Hello, @jcallaham
By running the Pinball Re=30 or Re=130 with the default initial field, I observe very large values of the observation at the beginning.
It looks like it is independent of the mesh (I tried with a coarse and the fine mesh), see above for 0.2s:
The text was updated successfully, but these errors were encountered: