OOFEM 3.0
Loading...
Searching...
No Matches
inputrecord.C
Go to the documentation of this file.
1/*
2 *
3 * ##### ##### ###### ###### ### ###
4 * ## ## ## ## ## ## ## ### ##
5 * ## ## ## ## #### #### ## # ##
6 * ## ## ## ## ## ## ## ##
7 * ## ## ## ## ## ## ## ##
8 * ##### ##### ## ###### ## ##
9 *
10 *
11 * OOFEM : Object Oriented Finite Element Code
12 *
13 * Copyright (C) 1993 - 2025 Borek Patzak
14 *
15 *
16 *
17 * Czech Technical University, Faculty of Civil Engineering,
18 * Department of Structural Mechanics, 166 29 Prague, Czech Republic
19 *
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
29 *
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
33 */
34
35#include "inputrecord.h"
36#include "error.h"
37#include "datareader.h"
38#include <sstream>
39#include <iomanip>
40#include <set>
41
42
43namespace oofem {
44
45// maximum message length for error messages (otherwise ellipsized)
46constexpr static int maxMsgLen=80;
47
48/* MIT-licensed, from https://github.com/guilhermeagostinelli/levenshtein/blob/master/levenshtein.cpp */
49int InputRecord::giveLevenshteinDist(const std::string& word1, const std::string& word2){
50 int size1 = word1.size();
51 int size2 = word2.size();
52 // Verification matrix i.e. 2D array which will store the calculated distance.
53 // int verif[size1 + 1][size2 + 1];
54 std::vector<std::vector<int>> verif(size1+1);
55 for(int i=0; i<=size1; i++){ verif[i].resize(size2+1); }
56
57
58 // If one of the words has zero length, the distance is equal to the size of the other word.
59 if (size1 == 0)
60 return size2;
61 if (size2 == 0)
62 return size1;
63
64 // Sets the first row and the first column of the verification matrix with the numerical order from 0 to the length of each word.
65 for (int i = 0; i <= size1; i++)
66 verif[i][0] = i;
67 for (int j = 0; j <= size2; j++)
68 verif[0][j] = j;
69
70 // Verification step / matrix filling.
71 for (int i = 1; i <= size1; i++) {
72 for (int j = 1; j <= size2; j++) {
73 // Sets the modification cost.
74 // 0 means no modification (i.e. equal letters) and 1 means that a modification is needed (i.e. unequal letters).
75 int cost = (word2[j - 1] == word1[i - 1]) ? 0 : 1;
76
77 // Sets the current position of the matrix as the minimum value between a (deletion), b (insertion) and c (substitution).
78 // a = the upper adjacent value plus 1: verif[i - 1][j] + 1
79 // b = the left adjacent value plus 1: verif[i][j - 1] + 1
80 // c = the upper left adjacent value plus the modification cost: verif[i - 1][j - 1] + cost
81 verif[i][j] = std::min(
82 std::min(verif[i - 1][j] + 1, verif[i][j - 1] + 1),
83 verif[i - 1][j - 1] + cost
84 );
85 }
86 }
87 // The last position of the matrix will contain the Levenshtein distance.
88 return verif[size1][size2];
89}
90
91std::string InputRecord::error_msg_with_hints(const std::string& val, const std::map<int,std::vector<std::string>>& v2nn) {
92 //std::string InputRecord::error_msg_with_hints(const std::string& val, const std::vector<std::string>& all_names){
93 std::ostringstream oss, oss2;
94 std::string minName; int minDist=1000;
95 for(const auto& [num,names]: v2nn){
96 oss2<<" "<<std::setfill(' ')<<std::setw(3)<<num<<":";
97 for(const auto& name: names){
98 oss2<<" "<<name;
99 if(!val.empty()){
100 if(int ld=giveLevenshteinDist(val,name); ld<minDist){ minDist=ld; minName=name; }
101 }
102 }
103 oss2<<"\n";
104 }
105 if(minDist<=4) oss<<" (did you mean '"<<minName<<"'?)";
106 oss<<".\nPossible values:\n"<<oss2.str();
107 return oss.str();
108}
109
110
111#ifdef _USE_TRACE_FIELDS
112 bool InputRecord::TraceFields::active=false;
113 std::ofstream InputRecord::TraceFields::out;
114 void InputRecord::TraceFields::write(const std::string& s){
115 if(!InputRecord::TraceFields::active) return;
116 size_t hash=std::hash<std::string>{}(s);
117 static std::set<size_t> written;
118 if(written.count(hash)>0) return;
119 written.insert(hash);
120 InputRecord::TraceFields::out<<s<<std::endl;
121 }
122
123 void InputRecord::traceEnum(const std::string& name, const std::map<int,std::vector<std::string>>& val2names){
124 if(!InputRecord::TraceFields::active) return;
125 std::ostringstream rec;
126 // write as tag;id;json
127 rec<<"~Enum~;"<<name<<";";
128 int i=0;
129 for(const auto& kvv: val2names){
130 rec<<(i++==0?'{':',')<<'"'<<kvv.first<<"\":";
131 int j=0;
132 for(const auto& v: kvv.second) rec<<(j++==0?'[':',')<<'"'<<v<<'"';
133 rec<<']';
134 }
135 rec<<'}';
136 InputRecord::TraceFields::write(rec.str());
137 }
138#endif
139
140InputRecord :: InputRecord(DataReader* r){
141 reader = r;
142}
143
145InputRecord :: giveReader() const {
146 return reader;
147}
148
149std::shared_ptr<InputRecord>
151 // we could just return this->shared_from_this, but it throws std::bad_weak_ptr (with no backtrace)
152 // so we do essentially the same, but provide a nice message and abort immediately
153 auto weak=this->weak_from_this();
154 std::shared_ptr<InputRecord> ret=weak.lock();
155 if(!ret) OOFEM_ERROR("shared_ptr<InputRecord>::ptr(): object lifetime expired (programming error)");
156 return ret;
157}
158
159
160#ifdef _INPUTRECORD_OPTIONAL_OLD
161void
162InputRecord :: giveOptionalField(int &answer, InputFieldType id)
163{
164 if ( this->hasField(id) ) {
165 try {
166 this->giveField(answer, id);
167 } catch ( MissingKeywordInputException & ) { }
168 }
169}
170
171void
172InputRecord :: giveOptionalField(double &answer, InputFieldType id)
173{
174 if ( this->hasField(id) ) {
175 try {
176 this->giveField(answer, id);
177 } catch ( MissingKeywordInputException & ) { }
178 }
179}
180
181void
182InputRecord :: giveOptionalField(bool &answer, InputFieldType id)
183{
184 if ( this->hasField(id) ) {
185 try {
186 this->giveField(answer, id);
187 } catch ( MissingKeywordInputException & ) { }
188 }
189}
190
191void
192InputRecord :: giveOptionalField(std :: string &answer, InputFieldType id)
193{
194 if ( this->hasField(id) ) {
195 try {
196 this->giveField(answer, id);
197 } catch ( MissingKeywordInputException & ) { }
198 }
199}
200
201void
202InputRecord :: giveOptionalField(FloatArray &answer, InputFieldType id)
203{
204 if ( this->hasField(id) ) {
205 try {
206 this->giveField(answer, id);
207 } catch ( MissingKeywordInputException & ) { }
208 }
209}
210
211void
212InputRecord :: giveOptionalField(IntArray &answer, InputFieldType id)
213{
214 if ( this->hasField(id) ) {
215 try {
216 this->giveField(answer, id);
217 } catch ( MissingKeywordInputException & ) { }
218 }
219}
220
221void
222InputRecord :: giveOptionalField(FloatMatrix &answer, InputFieldType id)
223{
224 if ( this->hasField(id) ) {
225 try {
226 this->giveField(answer, id);
227 } catch ( MissingKeywordInputException & ) { }
228 }
229}
230
231void
232InputRecord :: giveOptionalField(std :: vector< std :: string > &answer, InputFieldType id)
233{
234 if ( this->hasField(id) ) {
235 try {
236 this->giveField(answer, id);
237 } catch ( MissingKeywordInputException & ) { }
238 }
239}
240
241void
242InputRecord :: giveOptionalField(Dictionary &answer, InputFieldType id)
243{
244 if ( this->hasField(id) ) {
245 try {
246 this->giveField(answer, id);
247 } catch ( MissingKeywordInputException & ) { }
248 }
249}
250
251void
252InputRecord :: giveOptionalField(std :: list< Range > &answer, InputFieldType id)
253{
254 if ( this->hasField(id) ) {
255 try {
256 this->giveField(answer, id);
257 } catch ( MissingKeywordInputException & ) { }
258 }
259}
260
261void
262InputRecord :: giveOptionalField(ScalarFunction &answer, InputFieldType id)
263{
264 if ( this->hasField(id) ) {
265 try {
266 this->giveField(answer, id);
267 } catch ( MissingKeywordInputException & ) { }
268 }
269}
270#endif
271
272
274 record(ir.giveRecordAsString()), keyword(std::move(keyword)), number(number)
275{ }
276
277
279 InputException(ir, std::move(kw), n)
280{
281 msg = ir.giveLocation()+": missing keyword \"" + keyword + "\"" \
282 "\n \"" + record.substr(0, maxMsgLen) + (record.size()>maxMsgLen?"...":"")+ "\"";
283}
284
285
287 InputException(ir, std::move(kw), n)
288{
289 msg = ir.giveLocation()+": bad format for keyword \"" + keyword + "\"" \
290 "\n \"" + record.substr(0, maxMsgLen) + (record.size()>maxMsgLen?"...":"") + "\"";
291}
292
293
294ValueInputException::ValueInputException(const InputRecord& ir, std::string kw, const std::string &reason) :
295 InputException(ir, std::move(kw), -1)
296{
297 msg = ir.giveLocation()+": value input error for keyword \"" + keyword + "\"" + \
298 "\nReason: \"" + reason + "\"\n" + \
299 "\n \"" + record.substr(0, maxMsgLen) + (record.size()>maxMsgLen?"...":"") + "\"";
300}
301
302
303const char* MissingKeywordInputException::what() const noexcept
304{
305 return msg.c_str();
306}
307
308
309const char* BadFormatInputException::what() const noexcept
310{
311 return msg.c_str();
312}
313
314const char* ValueInputException::what() const noexcept
315{
316 return msg.c_str();
317}
318
319
320ComponentInputException::ComponentInputException(const std::string keyword, ComponentType ct, int number, const std::string &reason)
321{
322 std::string cname;
323 if (ct==ctDofManager) {
324 cname = "DofManager";
325 } else if (ct ==ctElement) {
326 cname = "Element";
327 }
328 msg = "Value input error for keyword \"" + keyword + "\"" + \
329 "\nReason: \"" + reason + "\"\n" + \
330 cname + "[" + std::to_string(number) + "]" + "\"";
331}
332
333
334ComponentInputException::ComponentInputException(ComponentType ct, int number, const std::string &reason)
335{
336 std::string cname;
337 if (ct==ctDofManager) {
338 cname = "DofManager";
339 } else if (ct ==ctElement) {
340 cname = "Element";
341 }
342 msg = "Value input error, reason: \"" + reason + "\"\n" + \
343 cname + "[" + std::to_string(number) + "]" + "\"";
344}
345
346const char* ComponentInputException::what() const noexcept
347{
348 return msg.c_str();
349}
350
351} // end namespace oofem
const char * what() const noexcept override
BadFormatInputException(const InputRecord &ir, std::string keyword, int number)
ComponentInputException(const std::string keyword, ComponentType ct, int number, const std::string &reason)
const char * what() const noexcept override
InputException(const InputRecord &ir, std::string keyword, int number)
DataReader * reader
Definition inputrecord.h:99
std::shared_ptr< InputRecord > ptr()
static int giveLevenshteinDist(const std::string &word1, const std::string &word2)
Definition inputrecord.C:49
static std::string error_msg_with_hints(const std::string &val, const std::map< int, std::vector< std::string > > &v2nn)
Definition inputrecord.C:91
virtual std::string giveLocation() const =0
MissingKeywordInputException(const InputRecord &ir, std::string keyword, int number)
const char * what() const noexcept override
ValueInputException(const InputRecord &ir, std::string keyword, const std::string &reason)
const char * what() const noexcept override
#define OOFEM_ERROR(...)
Definition error.h:79
static constexpr int maxMsgLen
Definition inputrecord.C:46
const char * InputFieldType
Identifier of fields in input records.
Definition inputrecord.h:59

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011