From b3b0b2e1202c1503ce013a3b34ad1f40d434459d Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 10:15:04 +0200 Subject: [PATCH 1/7] Remove leftover comments. --- backends/dealii/include/laplace.h | 350 +----------------------------- 1 file changed, 8 insertions(+), 342 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 170f8fc..970a260 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -1,50 +1,9 @@ -/* ------------------------------------------------------------------------ - * - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright (C) 2010 - 2024 by the deal.II authors - * - * This file is part of the deal.II library. - * - * Part of the source code is dual licensed under Apache-2.0 WITH - * LLVM-exception OR LGPL-2.1-or-later. Detailed license information - * governing the source code and code contributions can be found in - * LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II. - * - * ------------------------------------------------------------------------ - * - * Authors: Wolfgang Bangerth, Texas A&M University, 2009, 2010 - * Timo Heister, University of Goettingen, 2009, 2010 - */ - -// @sect3{Include files} -// -// Most of the include files we need for this program have already been -// discussed in previous programs. In particular, all of the following should -// already be familiar friends: #include #include #include #include -// This program can use either PETSc or Trilinos for its parallel -// algebra needs. By default, if deal.II has been configured with -// PETSc, it will use PETSc. Otherwise, the following few lines will -// check that deal.II has been configured with Trilinos and take that. -// -// But there may be cases where you want to use Trilinos, even though -// deal.II has *also* been configured with PETSc, for example to -// compare the performance of these two libraries. To do this, -// add the following \#define to the source code: -// @code -// #define FORCE_USE_OF_TRILINOS -// @endcode -// -// Using this logic, the following lines will then import either the -// PETSc or Trilinos wrappers into the namespace `LA` (for linear -// algebra). In the former case, we are also defining the macro -// `USE_PETSC_LA` so that we can detect if we are using PETSc (see -// solve() for an example where this is necessary). namespace LA { #if defined(DEAL_II_WITH_PETSC) && !defined(DEAL_II_PETSC_WITH_COMPLEX) && \ @@ -60,6 +19,13 @@ namespace LA #endif } // namespace LA +#include +#include +#include + +#include +#include + #include #include @@ -72,58 +38,13 @@ namespace LA #include #include #include +#include #include #include #include #include -// The following, however, will be new or be used in new roles. Let's walk -// through them. The first of these will provide the tools of the -// Utilities::System namespace that we will use to query things like the -// number of processors associated with the current MPI universe, or the -// number within this universe the processor this job runs on is: -#include -// The next one provides a class, ConditionOStream that allows us to write -// code that would output things to a stream (such as std::cout) -// on every processor but throws the text away on all but one of them. We -// could achieve the same by simply putting an if statement in -// front of each place where we may generate output, but this doesn't make the -// code any prettier. In addition, the condition whether this processor should -// or should not produce output to the screen is the same every time -- and -// consequently it should be simple enough to put it into the statements that -// generate output itself. -#include -// After these preliminaries, here is where it becomes more interesting. As -// mentioned in the @ref distributed topic, one of the fundamental truths of -// solving problems on large numbers of processors is that there is no way for -// any processor to store everything (e.g. information about all cells in the -// mesh, all degrees of freedom, or the values of all elements of the solution -// vector). Rather, every processor will own a few of each of these -// and, if necessary, may know about a few more, for example the ones -// that are located on cells adjacent to the ones this processor owns -// itself. We typically call the latter ghost cells, ghost nodes -// or ghost elements of a vector. The point of this discussion here is -// that we need to have a way to indicate which elements a particular -// processor owns or need to know of. This is the realm of the IndexSet class: -// if there are a total of $N$ cells, degrees of freedom, or vector elements, -// associated with (non-negative) integral indices $[0,N)$, then both the set -// of elements the current processor owns as well as the (possibly larger) set -// of indices it needs to know about are subsets of the set $[0,N)$. IndexSet -// is a class that stores subsets of this set in an efficient format: -#include -// The next header file is necessary for a single function, -// SparsityTools::distribute_sparsity_pattern. The role of this function will -// be explained below. -#include -// The final two, new header files provide the class -// parallel::distributed::Triangulation that provides meshes distributed -// across a potentially very large number of processors, while the second -// provides the namespace parallel::distributed::GridRefinement that offers -// functions that can adaptively refine such distributed meshes: -#include -#include - #include #include #include @@ -131,31 +52,6 @@ namespace LA using namespace dealii; -// @sect3{The LaplaceProblem class template} - -// Next let's declare the main class of this program. Its structure is -// almost exactly that of the step-6 tutorial program. The only significant -// differences are: -// - The mpi_communicator variable that -// describes the set of processors we want this code to run on. In practice, -// this will be MPI_COMM_WORLD, i.e. all processors the batch scheduling -// system has assigned to this particular job. -// - The presence of the pcout variable of type ConditionOStream. -// - The obvious use of parallel::distributed::Triangulation instead of -// Triangulation. -// - The presence of two IndexSet objects that denote which sets of degrees of -// freedom (and associated elements of solution and right hand side vectors) -// we own on the current processor and which we need (as ghost elements) for -// the algorithms in this program to work. -// - The fact that all matrices and vectors are now distributed. We use -// either the PETSc or Trilinos wrapper classes so that we can use one of -// the sophisticated preconditioners offered by Hypre (with PETSc) or ML -// (with Trilinos). Note that as part of this class, we store a solution -// vector that does not only contain the degrees of freedom the current -// processor owns, but also (as ghost elements) all those vector elements -// that correspond to "locally relevant" degrees of freedom (i.e. all -// those that live on locally owned cells or the layer of ghost cells that -// surround it). template class LaplaceProblem { @@ -197,18 +93,6 @@ class LaplaceProblem TimerOutput computing_timer; }; -// @sect3{The LaplaceProblem class implementation} - -// @sect4{Constructor} - -// Constructors and destructors are rather trivial. In addition to what we -// do in step-6, we set the set of processors we want to work on to all -// machines available (MPI_COMM_WORLD); ask the triangulation to ensure that -// the mesh remains smooth and free to refined islands, for example; and -// initialize the pcout variable to only allow processor zero -// to output anything. The final piece is to initialize a timer that we -// use to determine how much compute time the different parts of the program -// take: template LaplaceProblem::LaplaceProblem() : mpi_communicator(MPI_COMM_WORLD) @@ -225,22 +109,6 @@ LaplaceProblem::LaplaceProblem() TimerOutput::wall_times) {} -// @sect4{LaplaceProblem::setup_system} - -// The following function is, arguably, the most interesting one in the -// entire program since it goes to the heart of what distinguishes %parallel -// step-40 from sequential step-6. -// -// At the top we do what we always do: tell the DoFHandler object to -// distribute degrees of freedom. Since the triangulation we use here is -// distributed, the DoFHandler object is smart enough to recognize that on -// each processor it can only distribute degrees of freedom on cells it -// owns; this is followed by an exchange step in which processors tell each -// other about degrees of freedom on ghost cell. The result is a DoFHandler -// that knows about the degrees of freedom on locally owned cells and ghost -// cells (i.e. cells adjacent to locally owned cells) but nothing about -// cells that are further away, consistent with the basic philosophy of -// distributed computing that no processor can know everything. template void LaplaceProblem::setup_system() @@ -254,58 +122,14 @@ LaplaceProblem::setup_system() << " Number of degrees of freedom: " << dof_handler.n_dofs() << std::endl; - // The next two lines extract some information we will need later on, - // namely two index sets that provide information about which degrees of - // freedom are owned by the current processor (this information will be - // used to initialize solution and right hand side vectors, and the system - // matrix, indicating which elements to store on the current processor and - // which to expect to be stored somewhere else); and an index set that - // indicates which degrees of freedom are locally relevant (i.e. live on - // cells that the current processor owns or on the layer of ghost cells - // around the locally owned cells; we need all of these degrees of - // freedom, for example, to estimate the error on the local cells). locally_owned_dofs = dof_handler.locally_owned_dofs(); locally_relevant_dofs = DoFTools::extract_locally_relevant_dofs(dof_handler); - // Next, let us initialize the solution and right hand side vectors. As - // mentioned above, the solution vector we seek does not only store - // elements we own, but also ghost entries; on the other hand, the right - // hand side vector only needs to have the entries the current processor - // owns since all we will ever do is write into it, never read from it on - // locally owned cells (of course the linear solvers will read from it, - // but they do not care about the geometric location of degrees of - // freedom). locally_relevant_solution.reinit(locally_owned_dofs, locally_relevant_dofs, mpi_communicator); system_rhs.reinit(locally_owned_dofs, mpi_communicator); - // The next step is to compute hanging node and boundary value - // constraints, which we combine into a single object storing all - // constraints. - // - // As with all other things in %parallel, the mantra must be that no - // processor can store all information about the entire universe. As a - // consequence, we need to tell the AffineConstraints object for which - // degrees of freedom it can store constraints and for which it may not - // expect any information to store. In our case, as explained in the - // @ref distributed topic, the degrees of freedom we need to care about on - // each processor are the locally relevant ones, so we pass this to the - // AffineConstraints::reinit() function as a second argument. A further - // optimization, AffineConstraint can avoid certain operations if you also - // provide it with the set of locally owned degrees of freedom -- the - // first argument to AffineConstraints::reinit(). - // - // (What would happen if we didn't pass this information to - // AffineConstraints, for example if we called the argument-less version of - // AffineConstraints::reinit() typically used in non-parallel codes? In that - // case, the AffineConstraints class will allocate an array - // with length equal to the largest DoF index it has seen so far. For - // processors with large numbers of MPI processes, this may be very large -- - // maybe on the order of billions. The program would then allocate more - // memory than for likely all other operations combined for this single - // array. Fortunately, recent versions of deal.II would trigger an assertion - // that tells you that this is considered a bug.) constraints.clear(); constraints.reinit(locally_owned_dofs, locally_relevant_dofs); DoFTools::make_hanging_node_constraints(dof_handler, constraints); @@ -315,28 +139,6 @@ LaplaceProblem::setup_system() constraints); constraints.close(); - // The last part of this function deals with initializing the matrix with - // accompanying sparsity pattern. As in previous tutorial programs, we use - // the DynamicSparsityPattern as an intermediate with which we - // then initialize the system matrix. To do so, we have to tell the sparsity - // pattern its size, but as above, there is no way the resulting object will - // be able to store even a single pointer for each global degree of - // freedom; the best we can hope for is that it stores information about - // each locally relevant degree of freedom, i.e., all those that we may - // ever touch in the process of assembling the matrix (the - // @ref distributed_paper "distributed computing paper" has a long - // discussion why one really needs the locally relevant, and not the small - // set of locally active degrees of freedom in this context). - // - // So we tell the sparsity pattern its size and what DoFs to store - // anything for and then ask DoFTools::make_sparsity_pattern to fill it - // (this function ignores all cells that are not locally owned, mimicking - // what we will do below in the assembly process). After this, we call a - // function that exchanges entries in these sparsity pattern between - // processors so that in the end each processor really knows about all the - // entries that will exist in that part of the finite element matrix that - // it will own. The final step is to initialize the matrix with the - // sparsity pattern. DynamicSparsityPattern dsp(locally_relevant_dofs); DoFTools::make_sparsity_pattern(dof_handler, dsp, constraints, false); @@ -351,33 +153,6 @@ LaplaceProblem::setup_system() mpi_communicator); } -// @sect4{LaplaceProblem::assemble_system} - -// The function that then assembles the linear system is comparatively -// boring, being almost exactly what we've seen before. The points to watch -// out for are: -// - Assembly must only loop over locally owned cells. There -// are multiple ways to test that; for example, we could compare a cell's -// subdomain_id against information from the triangulation as in -// cell->subdomain_id() == -// triangulation.locally_owned_subdomain(), or skip all cells for -// which the condition cell->is_ghost() || -// cell->is_artificial() is true. The simplest way, however, is to -// simply ask the cell whether it is owned by the local processor. -// - Copying local contributions into the global matrix must include -// distributing constraints and boundary values not just from the local -// matrix and vector into the global ones, but in the process -// also -- possibly -- from one MPI process to other processes if the -// entries we want to write to are not stored on the current process. -// Interestingly, this requires essentially no additional work: The -// AffineConstraints class we already used in step-6 is perfectly -// capable to also do this in parallel, and the only difference in this -// regard is that at the very end of the function, we have to call a -// `compress()` function on the global matrix and right hand side vector -// objects (see the description of what this does just before these calls). -// - The way we compute the right hand side (given the -// formula stated in the introduction) may not be the most elegant but will -// do for a program whose focus lies somewhere entirely different. template void LaplaceProblem::assemble_system() @@ -435,54 +210,10 @@ LaplaceProblem::assemble_system() cell_matrix, cell_rhs, local_dof_indices, system_matrix, system_rhs); } - // In the operations above, specifically the call to - // `distribute_local_to_global()` in the last line, every MPI - // process was only working on its local data. If the operation - // required adding something to a matrix or vector entry that is - // not actually stored on the current process, then the matrix or - // vector object keeps track of this for a later data exchange, - // but for efficiency reasons, this part of the operation is only - // queued up, rather than executed right away. But now that we got - // here, it is time to send these queued-up additions to those - // processes that actually own these matrix or vector entries. In - // other words, we want to "finalize" the global data - // structures. This is done by invoking the function `compress()` - // on both the matrix and vector objects. See - // @ref GlossCompress "Compressing distributed objects" - // for more information on what `compress()` actually does. system_matrix.compress(VectorOperation::add); system_rhs.compress(VectorOperation::add); } -// @sect4{LaplaceProblem::solve} - -// Even though solving linear systems on potentially tens of thousands of -// processors is by far not a trivial job, the function that does this is -- -// at least at the outside -- relatively simple. Most of the parts you've -// seen before. There are really only two things worth mentioning: -// - Solvers and preconditioners are built on the deal.II wrappers of PETSc -// and Trilinos functionality. It is relatively well known that the -// primary bottleneck of massively %parallel linear solvers is not -// actually the communication between processors, but the fact that it is -// difficult to produce preconditioners that scale well to large numbers -// of processors. Over the second half of the first decade of the 21st -// century, it has become clear that algebraic multigrid (AMG) methods -// turn out to be extremely efficient in this context, and we will use one -// of them -- either the BoomerAMG implementation of the Hypre package -// that can be interfaced to through PETSc, or a preconditioner provided -// by ML, which is part of Trilinos -- for the current program. The rest -// of the solver itself is boilerplate and has been shown before. Since -// the linear system is symmetric and positive definite, we can use the CG -// method as the outer solver. -// - Ultimately, we want a vector that stores not only the elements -// of the solution for degrees of freedom the current processor owns, but -// also all other locally relevant degrees of freedom. On the other hand, -// the solver itself needs a vector that is uniquely split between -// processors, without any overlap. We therefore create a vector at the -// beginning of this function that has these properties, use it to solve the -// linear system, and only assign it to the vector we want at the very -// end. This last step ensures that all ghost elements are also copied as -// necessary. template void LaplaceProblem::solve() @@ -518,20 +249,6 @@ LaplaceProblem::solve() locally_relevant_solution = completely_distributed_solution; } -// @sect4{LaplaceProblem::refine_grid} - -// The function that estimates the error and refines the grid is again -// almost exactly like the one in step-6. The only difference is that the -// function that flags cells to be refined is now in namespace -// parallel::distributed::GridRefinement -- a namespace that has functions -// that can communicate between all involved processors and determine global -// thresholds to use in deciding which cells to refine and which to coarsen. -// -// Note that we didn't have to do anything special about the -// KellyErrorEstimator class: we just give it a vector with as many elements -// as the local triangulation has cells (locally owned cells, ghost cells, -// and artificial ones), but it only fills those entries that correspond to -// cells that are locally owned. template void LaplaceProblem::refine_grid() @@ -550,42 +267,6 @@ LaplaceProblem::refine_grid() triangulation.execute_coarsening_and_refinement(); } -// @sect4{LaplaceProblem::output_results} - -// Compared to the corresponding function in step-6, the one here is -// a tad more complicated. There are two reasons: the first one is -// that we do not just want to output the solution but also for each -// cell which processor owns it (i.e. which "subdomain" it is -// in). Secondly, as discussed at length in step-17 and step-18, -// generating graphical data can be a bottleneck in -// parallelizing. In those two programs, we simply generate one -// output file per process. That worked because the -// parallel::shared::Triangulation cannot be used with large numbers -// of MPI processes anyway. But this doesn't scale: Creating a -// single file per processor will overwhelm the filesystem with a -// large number of processors. -// -// We here follow a more sophisticated approach that uses -// high-performance, parallel IO routines using MPI I/O to write to -// a small, fixed number of visualization files (here 8). We also -// generate a .pvtu record referencing these .vtu files, which can -// be opened directly in visualizatin tools like ParaView and VisIt. -// -// To start, the top of the function looks like it usually does. In addition -// to attaching the solution vector (the one that has entries for all locally -// relevant, not only the locally owned, elements), we attach a data vector -// that stores, for each cell, the subdomain the cell belongs to. This is -// slightly tricky, because of course not every processor knows about every -// cell. The vector we attach therefore has an entry for every cell that the -// current processor has in its mesh (locally owned ones, ghost cells, and -// artificial cells), but the DataOut class will ignore all entries that -// correspond to cells that are not owned by the current processor. As a -// consequence, it doesn't actually matter what values we write into these -// vector entries: we simply fill the entire vector with the number of the -// current MPI process (i.e. the subdomain_id of the current process); this -// correctly sets the values we care for, i.e. the entries that correspond -// to locally owned cells, while providing the wrong value for all other -// elements -- but these are then ignored anyway. template void LaplaceProblem::output_results(const unsigned int cycle, @@ -604,25 +285,10 @@ LaplaceProblem::output_results(const unsigned int cycle, data_out.build_patches(); - // The final step is to write this data to disk. We write up to 8 VTU files - // in parallel with the help of MPI-IO. Additionally a PVTU record is - // generated, which groups the written VTU files. data_out.write_vtu_with_pvtu_record( dir.string() + "/", "solution", cycle, mpi_communicator, 2, 8); } -// @sect4{LaplaceProblem::run} - -// The function that controls the overall behavior of the program is again -// like the one in step-6. The minor difference are the use of -// pcout instead of std::cout for output to the -// console (see also step-17). -// -// A functional difference to step-6 is the use of a square domain and that -// we start with a slightly finer mesh (5 global refinement cycles) -- there -// just isn't much of a point showing a massively %parallel program starting -// on 4 cells (although admittedly the point is only slightly stronger -// starting on 1024). template void LaplaceProblem::run(const std::string &dir) From 436fedddd18bcd4647e422c4b77b595199e458a8 Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 11:03:36 +0200 Subject: [PATCH 2/7] add to --- backends/dealii/include/laplace.h | 5 +-- backends/dealii/include/register_types.h | 6 ++- backends/dealii/tests/dealii_mpi.cc | 23 +++++------ test_files/laplace.json | 50 ++++++++++++++++++++---- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 970a260..43d9794 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -59,7 +59,7 @@ class LaplaceProblem LaplaceProblem(); void - run(const std::string &dir); + run(unsigned int n_cycles, const std::string &dir); private: void @@ -291,7 +291,7 @@ LaplaceProblem::output_results(const unsigned int cycle, template void -LaplaceProblem::run(const std::string &dir) +LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) { if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) { @@ -308,7 +308,6 @@ LaplaceProblem::run(const std::string &dir) << " on " << Utilities::MPI::n_mpi_processes(mpi_communicator) << " MPI rank(s)..." << std::endl; - const unsigned int n_cycles = 8; for (unsigned int cycle = 0; cycle < n_cycles; ++cycle) { pcout << "Cycle " << cycle << ':' << std::endl; diff --git a/backends/dealii/include/register_types.h b/backends/dealii/include/register_types.h index f5c98c4..9a8edcd 100644 --- a/backends/dealii/include/register_types.h +++ b/backends/dealii/include/register_types.h @@ -174,10 +174,14 @@ namespace coral "poisson_solver"}); NodeObject::register_type>(); - NodeObject::register_method, void, const std::string &>( + NodeObject::register_method, + void, + unsigned int, + const std::string &>( &LaplaceProblem::run, {"LaplaceProblem::run<" + Utilities::dim_string(dim, spacedim) + ">", "laplace_problem", + "n_cycles", "output_dir"}); } diff --git a/backends/dealii/tests/dealii_mpi.cc b/backends/dealii/tests/dealii_mpi.cc index bd576ba..bf61414 100644 --- a/backends/dealii/tests/dealii_mpi.cc +++ b/backends/dealii/tests/dealii_mpi.cc @@ -105,7 +105,8 @@ TEST_F(DealiiMPITest, LaplaceProblem) auto run_method = make_node("LaplaceProblem::run<2>"); auto output_dir_string = make_node(std::string(output_dir.path())); - run_method->set_arguments({laplace, output_dir_string}); + auto n_cycles = make_node(static_cast(4)); + run_method->set_arguments({laplace, n_cycles, output_dir_string}); (*run_method)(); } @@ -128,22 +129,18 @@ TEST_F(DealiiMPITest, LaplaceProblemNetwork) ASSERT_FALSE(json_data.empty()) << "JSON data is empty."; - // Update the initialize constant - // Node 5 contains the bool value - if (json_data["workflow"]["nodes"].contains("5") && - json_data["workflow"]["nodes"]["5"].contains("value")) - { - json_data["workflow"]["nodes"]["5"]["value"] = "false"; - } - // Update the output file path to use the test output directory - // Node 2 contains the output filename - if (json_data["workflow"]["nodes"].contains("2") && - json_data["workflow"]["nodes"]["2"].contains("value")) + // Node 3 contains the output filename + const std::string path_node_no = "3"; + if (json_data["workflow"]["nodes"].contains(path_node_no) && + json_data["workflow"]["nodes"][path_node_no].contains("value")) { - json_data["workflow"]["nodes"]["2"]["value"] = output_dir.path().string(); + json_data["workflow"]["nodes"][path_node_no]["value"] = + output_dir.path().string(); } + std::cout << json_data.dump(4) << std::endl; + network.from_json(json_data); slog_debug("Network has %u nodes and %u connections", diff --git a/test_files/laplace.json b/test_files/laplace.json index 524d727..07e16ce 100644 --- a/test_files/laplace.json +++ b/test_files/laplace.json @@ -9,27 +9,61 @@ "nodes": { "0": { "type": "LaplaceProblem::run<2>", - "position": { "x": 293.7562932408905, "y": 327.37380674085716 }, + "position": { + "x": 435.17307500000004, + "y": 203.75759999999997 + }, "qualified_id": "0" }, "1": { "type": "LaplaceProblem<2>", - "position": { "x": -183.0478681433714, "y": 226.5708997085626 }, + "position": { + "x": 56.196875000000105, + "y": 24.791200000000146 + }, "qualified_id": "1" }, "2": { - "type": "std::string", - "position": { "x": -164.89097078018403, "y": 417.02495316403406 }, - "value": "/app/build/output/", + "type": "unsigned int", + "position": { + "x": 44.79207500000011, + "y": 230.07760000000005 + }, + "value": "4", "qualified_id": "2" + }, + "3": { + "type": "std::string", + "position": { + "x": 10.577675000000127, + "y": 367.97200000000004 + }, + "value": "/app/build/output", + "qualified_id": "3" } }, "edges": { - "0": { "source": 1, "target": 0, "source_output": 0, "target_input": 0 }, - "1": { "source": 2, "target": 0, "source_output": 0, "target_input": 1 } + "0": { + "source": 1, + "target": 0, + "source_output": 0, + "target_input": 0 + }, + "1": { + "source": 2, + "target": 0, + "source_output": 0, + "target_input": 1 + }, + "2": { + "source": 3, + "target": 0, + "source_output": 0, + "target_input": 2 + } } }, "version": 1, "author": "dealiix-platform", - "date_time_utc": "2026-03-11T11:35:34.762Z" + "date_time_utc": "2026-04-24T08:34:58.352Z" } From ba4b063b708f2f6857d11f8ddf689153c67c4023 Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 11:12:40 +0200 Subject: [PATCH 3/7] Hardened test --- backends/dealii/tests/dealii_mpi.cc | 44 +++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/backends/dealii/tests/dealii_mpi.cc b/backends/dealii/tests/dealii_mpi.cc index bf61414..57541ce 100644 --- a/backends/dealii/tests/dealii_mpi.cc +++ b/backends/dealii/tests/dealii_mpi.cc @@ -13,6 +13,37 @@ using namespace dealii; using namespace coral; using coral_test::ScopedTestOutputDir; +/* + * Find a node with certain value in json and replace it. + */ +void +replace_value(nlohmann::json &j, + const std::string &target, + const std::string &replacement) +{ + if (j.is_string()) + { + if (j == target) + { + j = replacement; // modify in place + } + } + else if (j.is_object()) + { + for (auto &[key, value] : j.items()) + { + replace_value(value, target, replacement); + } + } + else if (j.is_array()) + { + for (auto &item : j) + { + replace_value(item, target, replacement); + } + } +} + /** * MPI-aware wrapper around ScopedTestOutputDir. * @@ -129,17 +160,8 @@ TEST_F(DealiiMPITest, LaplaceProblemNetwork) ASSERT_FALSE(json_data.empty()) << "JSON data is empty."; - // Update the output file path to use the test output directory - // Node 3 contains the output filename - const std::string path_node_no = "3"; - if (json_data["workflow"]["nodes"].contains(path_node_no) && - json_data["workflow"]["nodes"][path_node_no].contains("value")) - { - json_data["workflow"]["nodes"][path_node_no]["value"] = - output_dir.path().string(); - } - - std::cout << json_data.dump(4) << std::endl; + // Replace output value according to `output_dir` + replace_value(json_data, "/app/build/output", output_dir.path().string()); network.from_json(json_data); From e92aaa9be6a21c98cd30cc501f715ca9c1d05c1c Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 13:00:32 +0200 Subject: [PATCH 4/7] Add generate grid methods to . --- backends/dealii/include/laplace.h | 45 ++++++++++++++++++++---- backends/dealii/include/register_types.h | 22 ++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 43d9794..4b56845 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -58,6 +58,14 @@ class LaplaceProblem public: LaplaceProblem(); + void + make_grid_from_generator(const std::string &name, + const std::string &arguments, + unsigned int n_refinements); + + void + make_grid_from_file(const std::string &filename, unsigned int n_refinements); + void run(unsigned int n_cycles, const std::string &dir); @@ -289,10 +297,40 @@ LaplaceProblem::output_results(const unsigned int cycle, dir.string() + "/", "solution", cycle, mpi_communicator, 2, 8); } +template +void +LaplaceProblem::make_grid_from_generator(const std::string &name, + const std::string &arguments, + unsigned int n_refinements) +{ + GridGenerator::generate_from_name_and_arguments(triangulation, + name, + arguments); + + triangulation.refine_global(n_refinements); +} + +template +void +LaplaceProblem::make_grid_from_file(const std::string &filename, + unsigned int n_refinements) +{ + GridIn gridin; + gridin.attach_triangulation(triangulation); + std::ifstream f(filename); + AssertThrow(f, ExcMessage("Could not open mesh file " + filename)); + gridin.read(f); + + triangulation.refine_global(n_refinements); +} + template void LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) { + // Temporary + make_grid_from_generator("hyper_cube", "0.0 : 1.0 : false", 5); + if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) { if (!std::filesystem::exists(dir)) @@ -312,12 +350,7 @@ LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) { pcout << "Cycle " << cycle << ':' << std::endl; - if (cycle == 0) - { - GridGenerator::hyper_cube(triangulation); - triangulation.refine_global(5); - } - else + if (cycle > 0) refine_grid(); setup_system(); diff --git a/backends/dealii/include/register_types.h b/backends/dealii/include/register_types.h index 9a8edcd..79b9d68 100644 --- a/backends/dealii/include/register_types.h +++ b/backends/dealii/include/register_types.h @@ -174,6 +174,28 @@ namespace coral "poisson_solver"}); NodeObject::register_type>(); + NodeObject::register_method, + void, + const std::string &, + const std::string &, + unsigned int>( + &LaplaceProblem::make_grid_from_generator, + {"LaplaceProblem::make_grid_from_generator<" + + Utilities::dim_string(dim, spacedim) + ">", + "laplace_problem", + "generator_name", + "generator_arguments", + "n_refinements"}); + NodeObject::register_method, + void, + const std::string &, + unsigned int>( + &LaplaceProblem::make_grid_from_file, + {"LaplaceProblem::make_grid_from_file<" + + Utilities::dim_string(dim, spacedim) + ">", + "laplace_problem", + "file_name", + "n_refinements"}); NodeObject::register_method, void, unsigned int, From da2728dbdc7d7d998cd346432b285b98dcb981dc Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 17:37:56 +0200 Subject: [PATCH 5/7] Complete tests. --- backends/dealii/include/laplace.h | 3 - backends/dealii/tests/dealii_mpi.cc | 11 ++- test_files/laplace.json | 101 +++++++++++++++++++++------- 3 files changed, 87 insertions(+), 28 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 4b56845..9a40f60 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -328,9 +328,6 @@ template void LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) { - // Temporary - make_grid_from_generator("hyper_cube", "0.0 : 1.0 : false", 5); - if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) { if (!std::filesystem::exists(dir)) diff --git a/backends/dealii/tests/dealii_mpi.cc b/backends/dealii/tests/dealii_mpi.cc index 57541ce..b9a1285 100644 --- a/backends/dealii/tests/dealii_mpi.cc +++ b/backends/dealii/tests/dealii_mpi.cc @@ -134,9 +134,18 @@ TEST_F(DealiiMPITest, LaplaceProblem) ASSERT_TRUE((*laplace)()); ASSERT_TRUE(laplace->ready()); - auto run_method = make_node("LaplaceProblem::run<2>"); + auto run_method = make_node("LaplaceProblem::run<2>"); + auto grid_method = make_node("LaplaceProblem::make_grid_from_generator<2>"); auto output_dir_string = make_node(std::string(output_dir.path())); + auto generator_name = make_node(std::string("hyper_cube")); + auto generator_args = make_node(std::string("0.0 : 1.0 : false")); auto n_cycles = make_node(static_cast(4)); + auto n_refinements = make_node(static_cast(5)); + + grid_method->set_arguments( + {laplace, generator_name, generator_args, n_refinements}); + (*grid_method)(); + run_method->set_arguments({laplace, n_cycles, output_dir_string}); (*run_method)(); } diff --git a/test_files/laplace.json b/test_files/laplace.json index 07e16ce..0aeaf9c 100644 --- a/test_files/laplace.json +++ b/test_files/laplace.json @@ -1,63 +1,116 @@ { - "plugin": { - "MPI": { - "enabled": true, - "max_num_threads": 1 - } - }, "workflow": { "nodes": { "0": { - "type": "LaplaceProblem::run<2>", + "type": "LaplaceProblem<2>", "position": { - "x": 435.17307500000004, - "y": 203.75759999999997 + "x": 79.69387500000005, + "y": -85.76799999999994 }, "qualified_id": "0" }, "1": { - "type": "LaplaceProblem<2>", + "type": "LaplaceProblem::make_grid_from_generator<2>", "position": { - "x": 56.196875000000105, - "y": 24.791200000000146 + "x": 510.76237499999996, + "y": 25.85600000000001 }, "qualified_id": "1" }, "2": { - "type": "unsigned int", + "type": "std::string", "position": { - "x": 44.79207500000011, - "y": 230.07760000000005 + "x": 48.52237500000004, + "y": 68.19199999999996 }, - "value": "4", + "value": "hyper_cube", "qualified_id": "2" }, "3": { "type": "std::string", "position": { - "x": 10.577675000000127, - "y": 367.97200000000004 + "x": 51.97837500000003, + "y": 196.92799999999997 }, - "value": "/app/build/output", + "value": "0.0 : 1.0 : false", "qualified_id": "3" + }, + "4": { + "type": "unsigned int", + "position": { + "x": 47.65837500000005, + "y": 310.112 + }, + "value": "5", + "qualified_id": "4" + }, + "5": { + "type": "LaplaceProblem::run<2>", + "position": { + "x": 520.0293149999998, + "y": 363.50719999999984 + }, + "qualified_id": "5" + }, + "6": { + "type": "unsigned int", + "position": { + "x": 43.5160350000001, + "y": 425.71519999999987 + }, + "value": "4", + "qualified_id": "6" + }, + "7": { + "type": "std::string", + "position": { + "x": 46.004355000000075, + "y": 538.9337599999999 + }, + "value": "/app/build/output", + "qualified_id": "7" } }, "edges": { "0": { - "source": 1, - "target": 0, + "source": 0, + "target": 1, "source_output": 0, "target_input": 0 }, "1": { "source": 2, - "target": 0, + "target": 1, "source_output": 0, "target_input": 1 }, "2": { "source": 3, - "target": 0, + "target": 1, + "source_output": 0, + "target_input": 2 + }, + "3": { + "source": 4, + "target": 1, + "source_output": 0, + "target_input": 3 + }, + "4": { + "source": 1, + "target": 5, + "source_output": 0, + "target_input": 0 + }, + "5": { + "source": 6, + "target": 5, + "source_output": 0, + "target_input": 1 + }, + "6": { + "source": 7, + "target": 5, "source_output": 0, "target_input": 2 } @@ -65,5 +118,5 @@ }, "version": 1, "author": "dealiix-platform", - "date_time_utc": "2026-04-24T08:34:58.352Z" + "date_time_utc": "2026-04-24T15:31:31.223Z" } From 0c7f62114e6024520865e513f1a579d5f4fb81ba Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Fri, 24 Apr 2026 19:18:59 +0200 Subject: [PATCH 6/7] Implement rhs parsed from string. Update tests. --- backends/dealii/include/laplace.h | 32 ++++--- backends/dealii/include/register_types.h | 2 + backends/dealii/tests/dealii_mpi.cc | 9 +- test_files/laplace.json | 113 ++++++++++++++--------- 4 files changed, 93 insertions(+), 63 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 9a40f60..3c5090d 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -20,6 +20,7 @@ namespace LA } // namespace LA #include +#include #include #include @@ -67,13 +68,13 @@ class LaplaceProblem make_grid_from_file(const std::string &filename, unsigned int n_refinements); void - run(unsigned int n_cycles, const std::string &dir); + run(unsigned int n_cycles, const std::string &rhs, const std::string &dir); private: void setup_system(); void - assemble_system(); + assemble_system(const std::string &rhs); void solve(); void @@ -163,10 +164,15 @@ LaplaceProblem::setup_system() template void -LaplaceProblem::assemble_system() +LaplaceProblem::assemble_system(const std::string &rhs) { TimerOutput::Scope t(computing_timer, "assembly"); + FunctionParser rhs_function; + rhs_function.initialize(FunctionParser::default_variable_names(), + rhs, + {{"pi", numbers::PI}}); + const QGauss quadrature_formula(fe.degree + 1); FEValues fe_values(fe, @@ -174,8 +180,9 @@ LaplaceProblem::assemble_system() update_values | update_gradients | update_quadrature_points | update_JxW_values); - const unsigned int dofs_per_cell = fe.n_dofs_per_cell(); - const unsigned int n_q_points = quadrature_formula.size(); + const unsigned int dofs_per_cell = fe.n_dofs_per_cell(); + const unsigned int n_q_points = quadrature_formula.size(); + std::vector rhs_values(n_q_points); FullMatrix cell_matrix(dofs_per_cell, dofs_per_cell); Vector cell_rhs(dofs_per_cell); @@ -189,16 +196,11 @@ LaplaceProblem::assemble_system() cell_matrix = 0.; cell_rhs = 0.; + rhs_function.value_list(fe_values.get_quadrature_points(), rhs_values); for (unsigned int q_point = 0; q_point < n_q_points; ++q_point) { - const double rhs_value = - (fe_values.quadrature_point(q_point)[1] > - 0.5 + - 0.25 * std::sin(4.0 * numbers::PI * - fe_values.quadrature_point(q_point)[0]) ? - 1. : - -1.); + const double rhs_value = rhs_values[q_point]; for (unsigned int i = 0; i < dofs_per_cell; ++i) { @@ -326,7 +328,9 @@ LaplaceProblem::make_grid_from_file(const std::string &filename, template void -LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) +LaplaceProblem::run(unsigned int n_cycles, + const std::string &rhs, + const std::string &dir) { if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) { @@ -351,7 +355,7 @@ LaplaceProblem::run(unsigned int n_cycles, const std::string &dir) refine_grid(); setup_system(); - assemble_system(); + assemble_system(rhs); solve(); output_results(cycle, dir); diff --git a/backends/dealii/include/register_types.h b/backends/dealii/include/register_types.h index 79b9d68..519a6b1 100644 --- a/backends/dealii/include/register_types.h +++ b/backends/dealii/include/register_types.h @@ -199,11 +199,13 @@ namespace coral NodeObject::register_method, void, unsigned int, + const std::string &, const std::string &>( &LaplaceProblem::run, {"LaplaceProblem::run<" + Utilities::dim_string(dim, spacedim) + ">", "laplace_problem", "n_cycles", + "rhs", "output_dir"}); } diff --git a/backends/dealii/tests/dealii_mpi.cc b/backends/dealii/tests/dealii_mpi.cc index b9a1285..acceabc 100644 --- a/backends/dealii/tests/dealii_mpi.cc +++ b/backends/dealii/tests/dealii_mpi.cc @@ -139,14 +139,17 @@ TEST_F(DealiiMPITest, LaplaceProblem) auto output_dir_string = make_node(std::string(output_dir.path())); auto generator_name = make_node(std::string("hyper_cube")); auto generator_args = make_node(std::string("0.0 : 1.0 : false")); - auto n_cycles = make_node(static_cast(4)); - auto n_refinements = make_node(static_cast(5)); + auto rhs_expression = + make_node(std::string("if(y > 0.5 + 0.25 * sin(4 * pi * x), 1.0, -1.0)")); + auto n_cycles = make_node(static_cast(4)); + auto n_refinements = make_node(static_cast(5)); grid_method->set_arguments( {laplace, generator_name, generator_args, n_refinements}); (*grid_method)(); - run_method->set_arguments({laplace, n_cycles, output_dir_string}); + run_method->set_arguments( + {laplace, n_cycles, rhs_expression, output_dir_string}); (*run_method)(); } diff --git a/test_files/laplace.json b/test_files/laplace.json index 0aeaf9c..d4d304c 100644 --- a/test_files/laplace.json +++ b/test_files/laplace.json @@ -1,122 +1,143 @@ { + "plugin": { + "MPI": { + "enabled": true, + "max_num_threads": 1 + } + }, "workflow": { "nodes": { "0": { "type": "LaplaceProblem<2>", "position": { - "x": 79.69387500000005, - "y": -85.76799999999994 + "x": -321.3456749999997, + "y": -191.9663999999999 }, "qualified_id": "0" }, - "1": { - "type": "LaplaceProblem::make_grid_from_generator<2>", - "position": { - "x": 510.76237499999996, - "y": 25.85600000000001 - }, - "qualified_id": "1" - }, "2": { - "type": "std::string", + "type": "LaplaceProblem::make_grid_from_generator<2>", "position": { - "x": 48.52237500000004, - "y": 68.19199999999996 + "x": 201.41212500000017, + "y": -98.31359999999991 }, - "value": "hyper_cube", "qualified_id": "2" }, "3": { "type": "std::string", "position": { - "x": 51.97837500000003, - "y": 196.92799999999997 + "x": -361.5702749999997, + "y": -86.9087999999999 }, - "value": "0.0 : 1.0 : false", + "value": "hyper_cube", "qualified_id": "3" }, "4": { - "type": "unsigned int", + "type": "std::string", "position": { - "x": 47.65837500000005, - "y": 310.112 + "x": 318.5705250000001, + "y": 263.52959999999996 }, - "value": "5", + "value": "if(y > 0.5 + 0.25 * sin(4 * pi * x), 1.0, -1.0)", "qualified_id": "4" }, "5": { - "type": "LaplaceProblem::run<2>", + "type": "std::string", "position": { - "x": 520.0293149999998, - "y": 363.50719999999984 + "x": -360.5334749999997, + "y": 46.838400000000036 }, + "value": "0.0 : 1.0 : false", "qualified_id": "5" }, "6": { "type": "unsigned int", "position": { - "x": 43.5160350000001, - "y": 425.71519999999987 + "x": -368.82787499999966, + "y": 168.144 }, - "value": "4", + "value": "5", "qualified_id": "6" }, "7": { + "type": "LaplaceProblem::run<2>", + "position": { + "x": 738.474525, + "y": 56.16960000000006 + }, + "qualified_id": "7" + }, + "8": { "type": "std::string", "position": { - "x": 46.004355000000075, - "y": 538.9337599999999 + "x": 320.64412500000003, + "y": 368.24639999999994 }, "value": "/app/build/output", - "qualified_id": "7" + "qualified_id": "8" + }, + "9": { + "type": "unsigned int", + "position": { + "x": 324.7913250000001, + "y": 160.8864 + }, + "value": "4", + "qualified_id": "9" } }, "edges": { "0": { "source": 0, - "target": 1, + "target": 2, "source_output": 0, "target_input": 0 }, "1": { - "source": 2, - "target": 1, + "source": 3, + "target": 2, "source_output": 0, "target_input": 1 }, "2": { - "source": 3, - "target": 1, + "source": 5, + "target": 2, "source_output": 0, "target_input": 2 }, "3": { - "source": 4, - "target": 1, + "source": 6, + "target": 2, "source_output": 0, "target_input": 3 }, "4": { - "source": 1, - "target": 5, + "source": 2, + "target": 7, "source_output": 0, "target_input": 0 }, "5": { - "source": 6, - "target": 5, + "source": 4, + "target": 7, "source_output": 0, - "target_input": 1 + "target_input": 2 }, "6": { - "source": 7, - "target": 5, + "source": 8, + "target": 7, "source_output": 0, - "target_input": 2 + "target_input": 3 + }, + "7": { + "source": 9, + "target": 7, + "source_output": 0, + "target_input": 1 } } }, "version": 1, "author": "dealiix-platform", - "date_time_utc": "2026-04-24T15:31:31.223Z" + "date_time_utc": "2026-04-24T17:15:50.256Z" } From 653f890cb6e657141aedc5f9806248c46fd2037c Mon Sep 17 00:00:00 2001 From: Matteo Poggi Date: Mon, 27 Apr 2026 11:21:57 +0200 Subject: [PATCH 7/7] Add preconditioner name to LaplaceProblem::run node. --- backends/dealii/include/laplace.h | 58 ++++++++--- backends/dealii/include/register_types.h | 2 + backends/dealii/tests/dealii_mpi.cc | 3 +- test_files/laplace.json | 119 +++++++++++++---------- 4 files changed, 116 insertions(+), 66 deletions(-) diff --git a/backends/dealii/include/laplace.h b/backends/dealii/include/laplace.h index 3c5090d..7ec35e2 100644 --- a/backends/dealii/include/laplace.h +++ b/backends/dealii/include/laplace.h @@ -68,7 +68,10 @@ class LaplaceProblem make_grid_from_file(const std::string &filename, unsigned int n_refinements); void - run(unsigned int n_cycles, const std::string &rhs, const std::string &dir); + run(unsigned int n_cycles, + const std::string &rhs, + const std::string &preconditioner_name, + const std::string &dir); private: void @@ -76,7 +79,7 @@ class LaplaceProblem void assemble_system(const std::string &rhs); void - solve(); + solve(const std::string &preconditioner_name); void refine_grid(); void @@ -226,7 +229,7 @@ LaplaceProblem::assemble_system(const std::string &rhs) template void -LaplaceProblem::solve() +LaplaceProblem::solve(const std::string &preconditioner_name) { TimerOutput::Scope t(computing_timer, "solve"); @@ -237,19 +240,47 @@ LaplaceProblem::solve() 1e-6 * system_rhs.l2_norm()); LA::SolverCG solver(solver_control); - LA::MPI::PreconditionAMG::AdditionalData data; + if (preconditioner_name == "amg") + { + LA::MPI::PreconditionAMG::AdditionalData data; #ifdef USE_PETSC_LA - data.symmetric_operator = true; + data.symmetric_operator = true; #else - /* Trilinos defaults are good */ + /* Trilinos defaults are good */ #endif - LA::MPI::PreconditionAMG preconditioner; - preconditioner.initialize(system_matrix, data); + LA::MPI::PreconditionAMG prec; + prec.initialize(system_matrix, data); + + solver.solve(system_matrix, + completely_distributed_solution, + system_rhs, + prec); + } + else if (preconditioner_name == "jacobi") + { + LA::MPI::PreconditionJacobi prec; + prec.initialize(system_matrix); + solver.solve(system_matrix, + completely_distributed_solution, + system_rhs, + prec); + } + else if (preconditioner_name == "ssor") + { + LA::MPI::PreconditionSSOR prec; + prec.initialize(system_matrix); + solver.solve(system_matrix, + completely_distributed_solution, + system_rhs, + prec); + } + else + { + AssertThrow(false, + ExcMessage("Unknown preconditioner: " + preconditioner_name + + ". Use 'amg', 'jacobi' or 'ssor'.")); + } - solver.solve(system_matrix, - completely_distributed_solution, - system_rhs, - preconditioner); pcout << " Solved in " << solver_control.last_step() << " iterations." << std::endl; @@ -330,6 +361,7 @@ template void LaplaceProblem::run(unsigned int n_cycles, const std::string &rhs, + const std::string &preconditioner_name, const std::string &dir) { if (Utilities::MPI::this_mpi_process(mpi_communicator) == 0) @@ -356,7 +388,7 @@ LaplaceProblem::run(unsigned int n_cycles, setup_system(); assemble_system(rhs); - solve(); + solve(preconditioner_name); output_results(cycle, dir); computing_timer.print_summary(); diff --git a/backends/dealii/include/register_types.h b/backends/dealii/include/register_types.h index 519a6b1..9187852 100644 --- a/backends/dealii/include/register_types.h +++ b/backends/dealii/include/register_types.h @@ -200,12 +200,14 @@ namespace coral void, unsigned int, const std::string &, + const std::string &, const std::string &>( &LaplaceProblem::run, {"LaplaceProblem::run<" + Utilities::dim_string(dim, spacedim) + ">", "laplace_problem", "n_cycles", "rhs", + "preconditioner_name", "output_dir"}); } diff --git a/backends/dealii/tests/dealii_mpi.cc b/backends/dealii/tests/dealii_mpi.cc index acceabc..7b4abe3 100644 --- a/backends/dealii/tests/dealii_mpi.cc +++ b/backends/dealii/tests/dealii_mpi.cc @@ -138,6 +138,7 @@ TEST_F(DealiiMPITest, LaplaceProblem) auto grid_method = make_node("LaplaceProblem::make_grid_from_generator<2>"); auto output_dir_string = make_node(std::string(output_dir.path())); auto generator_name = make_node(std::string("hyper_cube")); + auto prec_name = make_node(std::string("amg")); auto generator_args = make_node(std::string("0.0 : 1.0 : false")); auto rhs_expression = make_node(std::string("if(y > 0.5 + 0.25 * sin(4 * pi * x), 1.0, -1.0)")); @@ -149,7 +150,7 @@ TEST_F(DealiiMPITest, LaplaceProblem) (*grid_method)(); run_method->set_arguments( - {laplace, n_cycles, rhs_expression, output_dir_string}); + {laplace, n_cycles, rhs_expression, prec_name, output_dir_string}); (*run_method)(); } diff --git a/test_files/laplace.json b/test_files/laplace.json index d4d304c..4c8883e 100644 --- a/test_files/laplace.json +++ b/test_files/laplace.json @@ -7,27 +7,28 @@ }, "workflow": { "nodes": { - "0": { + "1": { "type": "LaplaceProblem<2>", "position": { - "x": -321.3456749999997, - "y": -191.9663999999999 + "x": 50.38064200000011, + "y": -47.119423999999924 }, - "qualified_id": "0" + "qualified_id": "1" }, "2": { - "type": "LaplaceProblem::make_grid_from_generator<2>", + "type": "unsigned int", "position": { - "x": 201.41212500000017, - "y": -98.31359999999991 + "x": 17.534818000000172, + "y": 294.775744 }, + "value": "5", "qualified_id": "2" }, "3": { "type": "std::string", "position": { - "x": -361.5702749999997, - "y": -86.9087999999999 + "x": 24.99977800000015, + "y": 52.91104000000003 }, "value": "hyper_cube", "qualified_id": "3" @@ -35,109 +36,123 @@ "4": { "type": "std::string", "position": { - "x": 318.5705250000001, - "y": 263.52959999999996 + "x": 20.520802000000145, + "y": 175.33638400000004 }, - "value": "if(y > 0.5 + 0.25 * sin(4 * pi * x), 1.0, -1.0)", + "value": "0.0 : 1.0 : false", "qualified_id": "4" }, "5": { "type": "std::string", "position": { - "x": -360.5334749999997, - "y": 46.838400000000036 + "x": 747.607906, + "y": 472.441792 }, - "value": "0.0 : 1.0 : false", + "value": "if(y > 0.5 + 0.25 * sin(4 * pi * x), 1.0, -1.0)", "qualified_id": "5" }, - "6": { - "type": "unsigned int", - "position": { - "x": -368.82787499999966, - "y": 168.144 - }, - "value": "5", - "qualified_id": "6" - }, "7": { - "type": "LaplaceProblem::run<2>", + "type": "LaplaceProblem::make_grid_from_generator<2>", "position": { - "x": 738.474525, - "y": 56.16960000000006 + "x": 611.745634, + "y": 58.88300800000006 }, "qualified_id": "7" }, "8": { - "type": "std::string", + "type": "LaplaceProblem::run<2>", "position": { - "x": 320.64412500000003, - "y": 368.24639999999994 + "x": 1213.4214099999997, + "y": 227.59110400000003 }, - "value": "/app/build/output", "qualified_id": "8" }, "9": { + "type": "std::string", + "position": { + "x": 749.1008979999999, + "y": 588.895168 + }, + "value": "amg", + "qualified_id": "9" + }, + "10": { "type": "unsigned int", "position": { - "x": 324.7913250000001, - "y": 160.8864 + "x": 747.6079059999998, + "y": 354.49542399999996 }, "value": "4", - "qualified_id": "9" + "qualified_id": "10" + }, + "11": { + "type": "std::string", + "position": { + "x": 752.086882, + "y": 706.8415359999999 + }, + "value": "/app/build/output", + "qualified_id": "11" } }, "edges": { "0": { - "source": 0, - "target": 2, + "source": 1, + "target": 7, "source_output": 0, "target_input": 0 }, "1": { "source": 3, - "target": 2, + "target": 7, "source_output": 0, "target_input": 1 }, "2": { - "source": 5, - "target": 2, + "source": 4, + "target": 7, "source_output": 0, "target_input": 2 }, "3": { - "source": 6, - "target": 2, + "source": 2, + "target": 7, "source_output": 0, "target_input": 3 }, "4": { - "source": 2, - "target": 7, + "source": 7, + "target": 8, "source_output": 0, "target_input": 0 }, "5": { - "source": 4, - "target": 7, + "source": 10, + "target": 8, "source_output": 0, - "target_input": 2 + "target_input": 1 }, "6": { - "source": 8, - "target": 7, + "source": 5, + "target": 8, "source_output": 0, - "target_input": 3 + "target_input": 2 }, "7": { "source": 9, - "target": 7, + "target": 8, "source_output": 0, - "target_input": 1 + "target_input": 3 + }, + "8": { + "source": 11, + "target": 8, + "source_output": 0, + "target_input": 4 } } }, "version": 1, "author": "dealiix-platform", - "date_time_utc": "2026-04-24T17:15:50.256Z" + "date_time_utc": "2026-04-27T09:17:09.753Z" }