1 /**
2 * @cond doxygenLibsbmlInternal
3 *
4 * @file    SpatialUniqueBoundaryConditionsCheck.cpp
5 * @brief   Ensure that spatial compartment mappings' unit sizes sum to one.
6 * @author  Sarah Keating, Lucian Smith
7 *
8 * <!--------------------------------------------------------------------------
9 * This file is part of libSBML.  Please visit http://sbml.org for more
10 * information about SBML, and the latest version of libSBML.
11  *
12  * Copyright (C) 2020 jointly by the following organizations:
13  *     1. California Institute of Technology, Pasadena, CA, USA
14  *     2. University of Heidelberg, Heidelberg, Germany
15  *     3. University College London, London, UK
16 *
17 * Copyright (C) 2019 jointly by the following organizations:
18 *     1. California Institute of Technology, Pasadena, CA, USA
19 *     2. University of Heidelberg, Heidelberg, Germany
20 *
21 * Copyright (C) 2013-2018 jointly by the following organizations:
22 *     1. California Institute of Technology, Pasadena, CA, USA
23 *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
24 *     3. University of Heidelberg, Heidelberg, Germany
25 *
26 * Copyright (C) 2009-2013 jointly by the following organizations:
27 *     1. California Institute of Technology, Pasadena, CA, USA
28 *     2. EMBL European Bioinformatics Institute (EMBL-EBI), Hinxton, UK
29 *
30 * Copyright (C) 2006-2008 by the California Institute of Technology,
31 *     Pasadena, CA, USA
32 *
33 * Copyright (C) 2002-2005 jointly by the following organizations:
34 *     1. California Institute of Technology, Pasadena, CA, USA
35 *     2. Japan Science and Technology Agency, Japan
36 *
37 * This library is free software; you can redistribute it and/or modify it
38 * under the terms of the GNU Lesser General Public License as published by
39 * the Free Software Foundation.  A copy of the license agreement is provided
40 * in the file named "LICENSE.txt" included with this software distribution
41 * and also available online as http://sbml.org/software/libsbml/license.html
42 * ---------------------------------------------------------------------- -->*/
43 
44 #include "SpatialUniqueBoundaryConditionsCheck.h"
45 #include <sbml/packages/spatial/extension/SpatialParameterPlugin.h>
46 
47 #include <set>
48 #include <map>
49 
50 /** @cond doxygenIgnored */
51 using namespace std;
52 /** @endcond */
53 
54 LIBSBML_CPP_NAMESPACE_BEGIN
55 #ifdef __cplusplus
56 
57 
58 /*
59 * Creates a new Constraint with the given constraint id.
60 */
SpatialUniqueBoundaryConditionsCheck(unsigned int id,SpatialValidator & v)61 SpatialUniqueBoundaryConditionsCheck::SpatialUniqueBoundaryConditionsCheck(unsigned int id, SpatialValidator & v):
62   TConstraint<Model>(id, v)
63 {
64 }
65 
66 /*
67 * Destroys this Constraint.
68 */
~SpatialUniqueBoundaryConditionsCheck()69 SpatialUniqueBoundaryConditionsCheck::~SpatialUniqueBoundaryConditionsCheck ()
70 {
71 }
72 
73 
74 /*
75 * Checks that all ids on the following Model objects are unique:
76 * event assignments and assignment rules.
77 */
78 void
check_(const Model & m,const Model &)79 SpatialUniqueBoundaryConditionsCheck::check_(const Model& m, const Model&)
80 {
81   if (m.getLevel() < 3) {
82     return;
83   }
84   set<pair<string, string> > dirichlet_targets, neumann_targets, robin_in_targets, robin_value_targets, robin_sum_targets;
85   for (unsigned long p = 0; p < m.getNumParameters(); p++) {
86     const Parameter* param = m.getParameter(p);
87     const SpatialParameterPlugin* spp = static_cast<const SpatialParameterPlugin*>(param->getPlugin("spatial"));
88     if (spp == NULL) {
89       continue;
90     }
91     if (spp->isSetBoundaryCondition()) {
92       const BoundaryCondition* bc = spp->getBoundaryCondition();
93       if (!bc->isSetVariable()) {
94         continue;
95       }
96       string var = bc->getVariable();
97       msg = "A <boundaryCondition>";
98       if (bc->isSetId()) {
99         msg += " with an id of '" + bc->getId() + "'";
100       }
101       msg += " has a variable of '";
102       msg += var + "'";
103       string target = "";
104       if (bc->isSetCoordinateBoundary()) {
105         target = bc->getCoordinateBoundary();
106         msg += " and a coordinateBoundary of '";
107         msg += target + "'";
108       }
109       else if (bc->isSetBoundaryDomainType()) {
110         target = bc->getBoundaryDomainType();
111         msg += " and a boundaryDomain of '";
112         msg += target + "'";
113       }
114       if (target == "") {
115         continue;
116       }
117       pair<string, string> bc_pair = make_pair(var, target);
118       msg += ", with a type of '" + bc->getTypeAsString() + "'";
119       BoundaryKind_t bk = bc->getType();
120       if (dirichlet_targets.find(bc_pair) != dirichlet_targets.end()) {
121         msg += ", but another <boundaryCondition> of type 'Dirichlet' already exists for that species boundary.";
122         logFailure(m);
123         continue;
124       }
125       if (neumann_targets.find(bc_pair) != neumann_targets.end()) {
126         msg += ", but another <boundaryCondition> of type 'Neumann' already exists for that species boundary.";
127         logFailure(m);
128         continue;
129       }
130       if (robin_in_targets.find(bc_pair) != robin_in_targets.end()) {
131         if (bk != SPATIAL_BOUNDARYKIND_ROBIN_SUM && bk != SPATIAL_BOUNDARYKIND_ROBIN_VALUE_COEFFICIENT) {
132           msg += ", but another <boundaryCondition> of type 'Robin_inwardNormalGradientCoefficient' already exists for that species boundary.";
133           logFailure(m);
134           continue;
135         }
136       }
137       if (robin_value_targets.find(bc_pair) != robin_value_targets.end()) {
138         if (bk != SPATIAL_BOUNDARYKIND_ROBIN_SUM && bk != SPATIAL_BOUNDARYKIND_ROBIN_INWARD_NORMAL_GRADIENT_COEFFICIENT) {
139           msg += ", but another <boundaryCondition> of type 'Robin_valueCoefficient' already exists for that species boundary.";
140           logFailure(m);
141           continue;
142         }
143       }
144       if (robin_sum_targets.find(bc_pair) != robin_sum_targets.end()) {
145         if (bk != SPATIAL_BOUNDARYKIND_ROBIN_INWARD_NORMAL_GRADIENT_COEFFICIENT && bk != SPATIAL_BOUNDARYKIND_ROBIN_VALUE_COEFFICIENT) {
146           msg += ", but another <boundaryCondition> of type 'Robin_sum' already exists for that species boundary.";
147           logFailure(m);
148           continue;
149         }
150       }
151 
152 
153       switch (bk) {
154       case SPATIAL_BOUNDARYKIND_DIRICHLET:
155         dirichlet_targets.insert(bc_pair);
156         break;
157       case SPATIAL_BOUNDARYKIND_NEUMANN:
158         neumann_targets.insert(bc_pair);
159         break;
160       case SPATIAL_BOUNDARYKIND_ROBIN_INWARD_NORMAL_GRADIENT_COEFFICIENT:
161         robin_in_targets.insert(bc_pair);
162         break;
163       case SPATIAL_BOUNDARYKIND_ROBIN_SUM:
164         robin_sum_targets.insert(bc_pair);
165         break;
166       case SPATIAL_BOUNDARYKIND_ROBIN_VALUE_COEFFICIENT:
167         robin_value_targets.insert(bc_pair);
168         break;
169       }
170     }
171   }
172 
173   //Now check for exactly three Robin boundaries:
174   for (set<pair<string, string> >::iterator r_i_pair = robin_in_targets.begin(); r_i_pair != robin_in_targets.end(); r_i_pair++) {
175     pair<string, string> rip = *r_i_pair;
176     string msg1 = "A <boundaryCondition> has a variable of '";
177     msg1 += rip.first + "' and a target of '" + rip.second;
178     msg1 += "', with a type of 'Robin_inwardNormalGradientCoefficient', but there is no corresponding <boundaryCondition> with the same variable and target with type '";
179     if (robin_sum_targets.find(rip) == robin_sum_targets.end()) {
180       msg = msg1 + "Robin_sum'.";
181       logFailure(m);
182       robin_sum_targets.insert(rip);
183     }
184     if (robin_value_targets.find(rip) == robin_value_targets.end()) {
185       msg = msg1 + "Robin_valueCoefficient'.";
186       logFailure(m);
187       robin_value_targets.insert(rip);
188     }
189   }
190 
191   for (set<pair<string, string> >::iterator r_i_pair = robin_sum_targets.begin(); r_i_pair != robin_sum_targets.end(); r_i_pair++) {
192     pair<string, string> rip = *r_i_pair;
193     string msg1 = "A <boundaryCondition> has a variable of '";
194     msg1 += rip.first + "' and a target of '" + rip.second;
195     msg1 += "', with a type of 'Robin_sum', but there is no corresponding <boundaryCondition> with the same variable and target with type '";
196     if (robin_in_targets.find(rip) == robin_in_targets.end()) {
197       msg = msg1 + "Robin_inwardNormalGradientCoefficient'.";
198       logFailure(m);
199       robin_in_targets.insert(rip);
200     }
201     if (robin_value_targets.find(rip) == robin_value_targets.end()) {
202       msg = msg1 + "Robin_valueCoefficient'.";
203       logFailure(m);
204       robin_value_targets.insert(rip);
205     }
206   }
207 
208   for (set<pair<string, string> >::iterator r_i_pair = robin_value_targets.begin(); r_i_pair != robin_value_targets.end(); r_i_pair++) {
209     pair<string, string> rip = *r_i_pair;
210     string msg1 = "A <boundaryCondition> has a variable of '";
211     msg1 += rip.first + "' and a target of '" + rip.second;
212     msg1 += "', with a type of 'Robin_valueCoefficient', but there is no corresponding <boundaryCondition> with the same variable and target with type '";
213     if (robin_in_targets.find(rip) == robin_in_targets.end()) {
214       msg = msg1 + "Robin_inwardNormalGradientCoefficient'.";
215       logFailure(m);
216       robin_in_targets.insert(rip);
217     }
218     if (robin_sum_targets.find(rip) == robin_sum_targets.end()) {
219       msg = msg1 + "Robin_sum'.";
220       logFailure(m);
221       robin_sum_targets.insert(rip);
222     }
223   }
224 }
225 
226 
227 #endif /* __cplusplus */
228 
229 LIBSBML_CPP_NAMESPACE_END
230 /** @endcond */
231