diff --git a/FCF.py b/FCF.py index b2d7034..339adb3 100644 --- a/FCF.py +++ b/FCF.py @@ -15,5 +15,5 @@ **blockOps) parareal_fcf.plotGraph(N=nBlocks, K=nBlocks, figSize=(6.4*2, 4.8*2)) # parareal_fcf.plotGraphForOneBlock(N=nBlocks, K=nBlocks, plotBlock=4, plotIter=2, figSize=(6.4*2, 4.8*2)) -parareal_fcf.plotSchedule(N=nBlocks, K=nBlocks, nProc=nBlocks, schedulerType="BLOCK-BY-BLOCK") - +fig = parareal_fcf.plotSchedule(N=nBlocks, K=nBlocks, nProc=nBlocks, schedulerType="BLOCK-BY-BLOCK") +fig.show() diff --git a/README.md b/README.md index 176ee53..9e11c06 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ that uses the [blockops] code for specific application and experiments. Currentl https://jupyterhub.mat.tu-harburg.de/blockops/, and here is the current list of WebApp : - [Accuracy (and stability) of general time-discretization on the Complex Plane](./accuracy) -- [Automatic Generation of Parareal Task Scheduling using different strategies](./pararealSchedule) +- [Automatic Generation of Task Scheduling for Parareal](./pararealSchedule) +- [Automatic Generation of Task Scheduling for Parareal with Overlap (MGRIT-FCF)](./pararealFCFSchedule) The WebApps are currently under development : current could be improved, and other WebApp could also be added, see the [demo WebApp](./demo) for an example. diff --git a/scripts/07_pararealSpeedup.py b/scripts/07_pararealSpeedup.py index c1abaff..c1d6c87 100644 --- a/scripts/07_pararealSpeedup.py +++ b/scripts/07_pararealSpeedup.py @@ -11,4 +11,5 @@ "(F - G) u_{n}^k + G * u_{n}^{k+1}", propagator="F", predictor="G", F=F, G=G, I=I, name='Parareal') -parareal.plotSchedule(N, K, nProc=N, schedulerType='LOWEST-COST-FIRST') \ No newline at end of file +fig = parareal.plotSchedule(N, K, nProc=N, schedulerType='LOWEST-COST-FIRST') +fig.show() \ No newline at end of file diff --git a/scripts/08_pararealFCFSpeedup.py b/scripts/08_pararealFCFSpeedup.py new file mode 100644 index 0000000..4832e58 --- /dev/null +++ b/scripts/08_pararealFCFSpeedup.py @@ -0,0 +1,15 @@ +from blockops import BlockOperator, BlockIteration + +G = BlockOperator('G', cost=0.1) +F = BlockOperator('F', cost=1) +N = 8 +K = 3 + +blockOps = dict(F=F, G=G) + +parareal_fcf = BlockIteration( + update="(F-G)*F*u_{n-1}^k + G*u_{n}^{k+1}", + predictor="G", propagator="F", **blockOps) +fig = parareal_fcf.plotSchedule( + N=N, K=K, nProc=N, schedulerType="BLOCK-BY-BLOCK") +fig.show() diff --git a/web_apps/pararealFCFSchedule.md b/web_apps/pararealFCFSchedule.md new file mode 100644 index 0000000..0004626 --- /dev/null +++ b/web_apps/pararealFCFSchedule.md @@ -0,0 +1,3 @@ +## Documentation + +... incoming ... \ No newline at end of file diff --git a/web_apps/pararealFCFSchedule.py b/web_apps/pararealFCFSchedule.py new file mode 100644 index 0000000..c3b5ebf --- /dev/null +++ b/web_apps/pararealFCFSchedule.py @@ -0,0 +1,139 @@ +from typing import Any + +from dynamic_site.app import App, ResponseStages +from dynamic_site.stage import parameters as par +import dynamic_site.stage.stages as stages + +from blockops import BlockOperator, BlockIteration + +# =================== +# Documentation Stage +# =================== + +s1_docs = stages.DocsStage( + "Quick Documentation", + r""" +Consider the block update formula of Parareal with overlap +(MGRIT with FCF relaxation) : + +$$ +u^{k+1}_{n+1} = F^2 (u^{k}_{n-1}) + G(u^{k+1}_n) - G \circ F(u^{k}_{n-1}) +$$ + +Define the number of blocks $N$ (time-intervals), the number of iterations $K$ +(eventually different for each block), and the cost of $F$ +and $G$. +Then choose a scheduler type : + +- BLOCK-BY-BLOCK : uses $N$ processors, where each processor is dedicated +to one time block +- LOWEST-COST-FIRST : uses $N$ processors, and compute first the tasks +with lower cost +- OPTIMAL : eventually use more than $N$ processors to minimize the +overall computation time +""", +) + +# ============== +# Settings Stage +# ============== + +SCHEDULERS = ['LOWEST-COST-FIRST', 'OPTIMAL', 'BLOCK-BY-BLOCK'] + +pararealSettings = [ + par.StrictlyPositiveInteger( + unique_id="nBlocks", name="$N$", + placeholder="Number of Blocks", + doc="Strictly positive integer", + optional=False, + ), + par.FloatList( + unique_id="nIter", name="$K$", + placeholder="Number of Iterations", + doc="Number of iteration for each block (1 or N values)", + optional=False, + ), + par.Float( + unique_id='costF', name='Computation time for $F$', + placeholder='Floating point number', + doc='Computation time for the fine solver', + optional=False + ), + par.Float( + unique_id='costG', name='Computation time for $G$', + placeholder='Floating point number', + doc='Computation time for the coarse solver', + optional=False + ), + par.Enumeration( + unique_id='schedulerType', name='Scheduler Type', + placeholder='', + doc='Type of scheduler use for Parareal', + optional=False, + choices=SCHEDULERS, + value='BLOCK-BY-BLOCK' + ), +] + +s1_settings = stages.SettingsStage( + "pararealSettings", "Parareal Settings", pararealSettings, False +) + + +# =========== +# Plots Stage +# =========== + +s1_plot = stages.PlotsStage("Parareal FCF Schedule", None) + +# ==================================================== +# Accuracy App +# ==================================================== +class PararealSchedule(App): + def __init__(self) -> None: + super().__init__(title="Parareal FCF Schedule") + + def compute(self, response_data: dict[str, Any] | None) -> ResponseStages: + + # Create a response, where stages will be added to + r = ResponseStages() + + # Initial request + r.add_docs_stage(s1_docs) + if not response_data: + r.add_settings_stage(s1_settings) + r.add_plot_stage(s1_plot) + return r + + # Convert parameters to correct types + pararealSettings = s1_settings.convert_to_types( + response_data["pararealSettings"] + ) + # Add the settings with the set values + r.add_settings_stage( + s1_settings.copy_from_response(response_data["pararealSettings"]) + ) + + G = BlockOperator('G', cost=pararealSettings['costG']) + F = BlockOperator('F', cost=pararealSettings['costF']) + N = pararealSettings['nBlocks'] + K = [int(k) for k in pararealSettings['nIter']] + K = K[0] if len(K) == 1 else K + + schedulerType = pararealSettings['schedulerType'] + + pararealFCF = BlockIteration( + "(F - G)*F u_{n-1}^k + G u_{n}^{k+1}", + propagator="F", predictor="G", F=F, G=G, name='PararealFCF') + + fig = pararealFCF.plotSchedule(N, K, nProc=N, schedulerType=schedulerType) + + # === Response === + + plot_stage = s1_plot.copy() + plot_stage.plot = fig.to_json() + r.add_plot_stage(plot_stage) + + return r + +