OOFEM 3.0
Loading...
Searching...
No Matches
fastmarchingmethod.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 "fastmarchingmethod.h"
36#include "domain.h"
37#include "mathfem.h"
38#include "node.h"
39#include "element.h"
40#include "connectivitytable.h"
41
42#include <cstdlib>
43
44namespace oofem {
45void
46FastMarchingMethod :: solve(FloatArray &dmanValues,
47 const std :: list< int > &bcDofMans,
48 double F)
49{
50 int candidate;
51 ConnectivityTable *ct = domain->giveConnectivityTable();
52
53
54 this->dmanValuesPtr = & dmanValues;
55 // tag points with boundary value as known
56 // then tag as trial all points that are one grid point away
57 // finally tag as far all other grid points
58 this->initialize(dmanValues, bcDofMans, F);
59
60 // let candidate be the thrial point with smallest T value
61 while ( ( candidate = this->getSmallestTrialDofMan() ) ) {
62 // add the candidate to known, remove it from trial
63 dmanRecords.at(candidate - 1).status = FMM_Status_KNOWN;
64 // tag as trial all neighbors of candidate that are not known
65 // if the neighbor is in far, remove and add it to the trial set
66 // and recompute the values of T at all trial neighbors of candidate
67 for ( int neighborElem: *ct->giveDofManConnectivityArray(candidate) ) {
68 Element *ie = domain->giveElement( neighborElem );
69 for ( int jn: ie->giveDofManArray() ) {
70 if ( dmanRecords.at(jn - 1).status != FMM_Status_KNOWN ) {
71 // recompute the value of T at candidate trial neighbor
72 this->updateTrialValue(dmanValues, jn, F);
73 }
74 }
75 }
76 }
77}
78
79
80
81void
82FastMarchingMethod :: initialize(FloatArray &dmanValues,
83 const std :: list< int > &bcDofMans,
84 double F)
85{
86 // tag points with boundary value as known
87 // then tag as trial all points that are one grid point away
88 // finally tag as far all other grid points
89 int i;
90 int nnode = domain->giveNumberOfDofManagers();
91 ConnectivityTable *ct = domain->giveConnectivityTable();
92
93 // all points are far by default
94 dmanRecords.resize(nnode);
95 for ( i = 0; i < nnode; i++ ) {
96 dmanRecords [ i ].status = FMM_Status_FAR;
97 }
98
99 // first tag all boundary points
100
101 for ( int jnode: bcDofMans ) {
102 if ( jnode > 0 ) {
103 dmanRecords.at(jnode - 1).status = FMM_Status_KNOWN;
104 } else {
105 dmanRecords.at(-jnode - 1).status = FMM_Status_KNOWN_BOUNDARY;
106 }
107 }
108
109 // tag as trial all points that are one grid point away
110 for ( int jnode: bcDofMans ) {
111 jnode = abs(jnode);
112
113 for ( int neighbor: *ct->giveDofManConnectivityArray(jnode) ) {
115 if ( neighbor == i ) {
116 continue;
117 }
118
119 Element *neighborElem = domain->giveElement( neighbor );
120 for ( int neighborNode: neighborElem->giveDofManArray() ) {
121 if ( ( dmanRecords.at(neighborNode - 1).status != FMM_Status_KNOWN ) &&
122 ( dmanRecords.at(neighborNode - 1).status != FMM_Status_KNOWN_BOUNDARY ) &&
123 ( dmanRecords.at(neighborNode - 1).status != FMM_Status_TRIAL ) ) {
124 this->updateTrialValue(dmanValues, neighborNode, F);
125 }
126 }
127 }
128 }
129}
130
131
132void
133FastMarchingMethod :: updateTrialValue(FloatArray &dmanValues, int id, double F)
134{
135 int ai, bi, ci, h, nroot, _ind = 0;
136 double at, bt, ht, a, b, u, cos_fi, sin_fi, _a, _b, _c, r1, r2, r3, t = 0.0, _h;
137 bool reg_upd_flag;
138 FloatArray cb, ca;
139 ConnectivityTable *ct = domain->giveConnectivityTable();
140
141
142 // first look for suitable element that can produce admissible value
143 // algorithm limited to non-obtuse 2d triangulations
144 for ( int neighborElem: *ct->giveDofManConnectivityArray(id) ) {
145 // test element if admissible
146 Element *ie = domain->giveElement( neighborElem );
147 if ( ie->giveGeometryType() == EGT_triangle_1 ) {
148 for ( int j = 1; j <= 3; j++ ) {
149 if ( ie->giveDofManagerNumber(j) == id ) {
150 _ind = j;
151 }
152 }
153
154 ci = ie->giveDofManagerNumber(_ind);
155 ai = ie->giveDofManagerNumber(1 + ( _ind ) % 3);
156 bi = ie->giveDofManagerNumber(1 + ( _ind + 1 ) % 3);
157
158 if ( ( dmanRecords.at(ai - 1).status == FMM_Status_KNOWN ) &&
159 ( dmanRecords.at(bi - 1).status == FMM_Status_KNOWN ) ) {
160 at = dmanValues.at(ai);
161 bt = dmanValues.at(bi);
162 if ( fabs(at) > fabs(bt) ) {
163 h = ai;
164 ai = bi;
165 bi = h;
166 ht = at;
167 at = bt;
168 bt = ht;
169 }
170
171 // get nodal coordinates
172 const auto &ac = domain->giveNode(ai)->giveCoordinates();
173 const auto &bc = domain->giveNode(bi)->giveCoordinates();
174 const auto &cc = domain->giveNode(ci)->giveCoordinates();
175
176 // a = distance of BC
177 a = distance(cc, bc);
178 // b = distance of AC
179 b = distance(cc, ac);
180 // compute fi angle
181 cb.beDifferenceOf(bc, cc);
182 cb.normalize();
183 ca.beDifferenceOf(ac, cc);
184 ca.normalize();
185 cos_fi = cb.dotProduct(ca);
186 sin_fi = sqrt(1.0 - cos_fi * cos_fi);
187 u = fabs(bt);
188 // compute quadratic equation coefficients for t
189 _a = ( a * a + b * b - 2.0 * a * b * cos_fi );
190 _b = 2.0 * b * u * ( a * cos_fi - b );
191 _c = b * b * ( u * u - F * F * a * a * sin_fi * sin_fi );
192 cubic3r(0.0, _a, _b, _c, & r1, & r2, & r3, & nroot);
193 reg_upd_flag = true;
194
195 if ( nroot == 0 ) {
196 reg_upd_flag = false;
197 } else if ( nroot == 1 ) {
198 t = r1;
199 } else if ( r1 >= 0.0 ) {
200 t = r1;
201 } else if ( r2 >= 0.0 ) {
202 t = r2;
203 } else {
204 reg_upd_flag = false;
205 }
206
207 if ( reg_upd_flag ) {
208 _h = b * ( t - u ) / t;
209 if ( ( t > u ) && ( _h > a * cos_fi ) && ( _h < a / cos_fi ) ) {
210 if ( dmanRecords.at(ci - 1).status == FMM_Status_FAR ) {
211 dmanValues.at(ci) = sgn(F) * t + at;
212 } else if ( F > 0. ) {
213 dmanValues.at(ci) = min(dmanValues.at(ci), sgn(F) * t + at);
214 } else {
215 dmanValues.at(ci) = max(dmanValues.at(ci), sgn(F) * t + at);
216 }
217 } else {
218 reg_upd_flag = false;
219 }
220 }
221
222 if ( !reg_upd_flag ) {
223 if ( F > 0. ) {
224 _h = min(b * F + at, a * F + bt);
225 } else {
226 _h = max(b * F + at, a * F + bt);
227 }
228
229 if ( dmanRecords.at(ci - 1).status == FMM_Status_FAR ) {
230 dmanValues.at(ci) = _h;
231 } else if ( F > 0. ) {
232 dmanValues.at(ci) = min(dmanValues.at(ci), _h);
233 } else {
234 dmanValues.at(ci) = max(dmanValues.at(ci), _h);
235 }
236 }
237
238 // if not yet in queue (trial for the first time), put it there
239 if ( dmanRecords.at(ci - 1).status != FMM_Status_TRIAL ) {
240 dmanTrialQueue.push(ci);
241 }
242
243 dmanRecords.at(ci - 1).status = FMM_Status_TRIAL;
244 } // admissible triangle
245 } // end EGT_triangle_1 element type
246 }
247}
248
249int
250FastMarchingMethod :: getSmallestTrialDofMan()
251{
252 int answer;
253 if ( dmanTrialQueue.empty() ) {
254 return 0;
255 }
256
257 answer = dmanTrialQueue.top();
258 dmanTrialQueue.pop();
259 return answer;
260}
261} // end namespace oofem
const IntArray * giveDofManConnectivityArray(int dofman)
const IntArray & giveDofManArray() const
Definition element.h:611
int giveDofManagerNumber(int i) const
Definition element.h:609
virtual Element_Geometry_Type giveGeometryType() const =0
std ::vector< FMM_DofmanRecord > dmanRecords
Array of DofManager records.
std ::priority_queue< int, std ::vector< int >, FMM_DofmanRecordDelegate_greater > dmanTrialQueue
Priority queue for trial T values.
void initialize(FloatArray &dmanValues, const std ::list< int > &bcDofMans, double F)
Initialize receiver.
@ FMM_Status_TRIAL
Trial nodes, candidates for known (accepted).
@ FMM_Status_FAR
Nodes not yet visited.
@ FMM_Status_KNOWN_BOUNDARY
Boundary nodes, from which the front will not propagate.
@ FMM_Status_KNOWN
Accepted nodes.
const FloatArray * dmanValuesPtr
Pointer to working set of dmanValues.
int getSmallestTrialDofMan()
Get the trial point with smallest T; zero if empty.
void updateTrialValue(FloatArray &dmanValues, int id, double F)
Updates the distance of trial node with given id).
double & at(Index i)
Definition floatarray.h:202
double dotProduct(const FloatArray &x) const
Definition floatarray.C:524
void beDifferenceOf(const FloatArray &a, const FloatArray &b)
Definition floatarray.C:403
FloatArrayF< N > min(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
FloatArrayF< N > max(const FloatArrayF< N > &a, const FloatArrayF< N > &b)
void cubic3r(double a, double b, double c, double d, double *r1, double *r2, double *r3, int *num)
Definition mathfem.C:155
double sgn(double i)
Returns the signum of given value (if value is < 0 returns -1, otherwise returns 1).
Definition mathfem.h:104
double distance(const FloatArray &x, const FloatArray &y)

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