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