BELFEM 0.9.0
Berkeley Lab Finite Element Framework
Loading...
Searching...
No Matches
cl_JcFunction_Database.hpp
Go to the documentation of this file.
1/*
2 * BELFEM -- The Berkeley Lab Finite Element Framework
3 * Copyright (c) 2026, The Regents of the University of California,
4 * through Lawrence Berkeley National Laboratory (subject to receipt of any required
5 * approvals from the U.S. Dept. of Energy). All rights reserved.
6 *
7 * Developers: Christian Messe, Gregory Giard
8 *
9 * See the top-level LICENSE file for the complete license and disclaimer.
10 */
11
12#ifndef BELFEM_CL_JCFUNCTION_DATABASE_HPP
13#define BELFEM_CL_JCFUNCTION_DATABASE_HPP
14#include <algorithm>
15#include <cmath>
16#include "constants.hpp"
17#include "commtools.hpp"
18#include "cl_JcFunction.hpp"
19#include "cl_Database.hpp"
20#include "fn_min.hpp"
21namespace belfem
22{
23 namespace material
24 {
25//------------------------------------------------------------------------------
26
62 {
63 Database * mDatabase ;
64 const real mTmin ;
65 const real mTmax ;
66 const real mBmin ;
67 const real mBmax ;
68 const real mAngleMin ;
69 const real mAngleMax ;
70 const real mInvLn10 = 1.0/std::log( 10. );
71
76 Vector< real > mSelfFieldT ;
77 Vector< real > mSelfFieldValue ;
78 bool mHaveSelfField = false ;
79
80 public:
81
109 JcFunctionDatabase( const string & aPath, const string & aLabel ) :
110 JcFunction(),
111 mDatabase( new Database( aPath, aLabel ) ),
112 mTmin( mDatabase->min( 0 ) ),
113 mTmax( mDatabase->max( 0 ) ),
114 mBmin( std::pow( 10., mDatabase->min( 1 ) ) ),
115 mBmax( std::pow( 10., mDatabase->max( 1 ) ) ),
116 mAngleMin( mDatabase->min( 2 ) ),
117 mAngleMax( mDatabase->max( 2 ) )
118 {
119 // the caller delivers the UNFOLDED angle theta in [ 0, pi ]
120 // a folded export covering less than that range
121 // would silently wrap or extrapolate — the angle coordinate
122 // is not clamped by Database::evaluate. Coverage test, not a
123 // width test: [ -pi/2, pi/2 ] has width pi and is still wrong
124 BELFEM_ERROR( mAngleMin <= 1e-6
125 && mAngleMax >= constant::pi - 1e-6,
126 "angular range of database %s spans [ %g, %g ] rad, but the unfolded\n"
127 "bn_angle contract requires coverage of [ 0, pi ]: a folded export\n"
128 "would silently mis-sample theta > pi/2",
129 aLabel.c_str(), ( double ) mAngleMin, ( double ) mAngleMax );
130
134
135 this->load_self_field( aPath, aLabel );
136 }
137
153 void
154 load_self_field( const string & aPath,
155 const string & aLabel )
156 {
157 // Which raw column carries this function: the jc table is built
158 // from the sheet current per width and needs the layer thickness
159 // to become a current density; n is dimensionless and is read
160 // straight. n is NOT given the jc treatment -- its low-field
161 // behaviour is its own.
162 const bool tIsJc = aLabel == "jc" ;
163 const string tColumn = tIsJc ? "icw" : "n" ;
164
165 Vector< real > tT ;
166 Vector< real > tValue ;
167
168 #ifdef BELFEM_HDF5
169 if ( comm_rank() == 0 )
170 {
171 // raw handle rather than the HDF5 wrapper: /source is a
172 // SIBLING of the group Database opened, and the wrapper
173 // exposes no root handle to probe. Same idiom as
174 // fn_rho_database_is_current.hpp
175 hid_t tFile = H5Fopen( aPath.c_str(),
176 H5F_ACC_RDONLY, H5P_DEFAULT );
177
178 if ( tFile >= 0 )
179 {
180 // tri-state, as in rho_database_is_current: only a
181 // definite hit counts, a probe error falls through to
182 // the historical clamp
183 if ( H5Lexists( tFile, "source", H5P_DEFAULT ) > 0 )
184 {
185 hid_t tGroup = H5Gopen2( tFile, "source", H5P_DEFAULT );
186
187 if ( tGroup >= 0 )
188 {
189 herr_t tStatus = 0 ;
190
191 if ( hdf5::dataset_exists( tGroup, "points" )
192 && hdf5::dataset_exists( tGroup, "columns" ) )
193 {
194 Cell< string > tColumns ;
196 tGroup, "columns", tColumns, tStatus );
197
198 Matrix< real > tPoints ;
200 tGroup, "points", tPoints, tStatus );
201
202 // columns located by NAME, never by position:
203 // the raw schema belongs to the data source
204 index_t tIt = tColumns.size() ;
205 index_t tIb = tColumns.size() ;
206 index_t tIv = tColumns.size() ;
207
208 for ( index_t k = 0; k < tColumns.size(); ++k )
209 {
210 if ( tColumns( k ) == "temperature" ) tIt = k ;
211 if ( tColumns( k ) == "field" ) tIb = k ;
212 if ( tColumns( k ) == tColumn ) tIv = k ;
213 }
214
215 // the schema promises columns.size() == points.n_cols,
216 // but a malformed file must not become out-of-bounds
217 // access in a release build ( code-audit finding 4 )
218 if ( tIt < tPoints.n_cols()
219 && tIb < tPoints.n_cols()
220 && tIv < tPoints.n_cols()
221 && tIt < tColumns.size()
222 && tIb < tColumns.size()
223 && tIv < tColumns.size() )
224 {
225 // reduce UNSCALED first; the calibration
226 // below needs the curve's own 77.5 K value
228 tPoints, tIt, tIb, tIv,
229 1.0, tT, tValue );
230
231 if ( tIsJc && tT.length() > 0 )
232 {
233 // The raw column's UNIT belongs to the data
234 // vendor, not to us -- sp-ap ships icw in
235 // A/cm while meta declares A/m, and assuming
236 // either silently breaks the other
237 // ( measured: reading A/cm as A/m left J0
238 // 100x low and the monotonicity guard
239 // clamped every call ). So the curve is
240 // CALIBRATED: scaled so its 77.5 K value
241 // equals the table's own declared level,
242 // Icw_77p5K_sf / t_eff. No unit assumption
243 // survives that.
244 real tScale = 0.0 ;
245
246 if ( hdf5::group_exists( tFile, "meta" ) )
247 {
248 hid_t tMeta = H5Gopen2( tFile, "meta",
249 H5P_DEFAULT );
250 if ( tMeta >= 0 )
251 {
252 real tIcw = 0.0 ;
253 real tTeff = 0.0 ;
254 if ( hdf5::dataset_exists( tMeta,
255 "Icw_77p5K_sf_A_per_m" ) )
256 {
258 tMeta, "Icw_77p5K_sf_A_per_m",
259 tIcw, tStatus );
260 }
261 if ( hdf5::dataset_exists( tMeta,
262 "t_eff_m" ) )
263 {
265 tMeta, "t_eff_m",
266 tTeff, tStatus );
267 }
268 H5Gclose( tMeta );
269
270 if ( tIcw > 0.0 && tTeff > 0.0 )
271 {
272 real tDummy ;
273 const real tCurve77p5 =
274 interp_curve( tT, tValue,
275 77.5, tDummy );
276 if ( tCurve77p5 > 0.0 )
277 {
278 tScale = ( tIcw / tTeff )
279 / tCurve77p5 ;
280 }
281 }
282 }
283 }
284
285 if ( tScale > 0.0 )
286 {
287 for ( belfem::index_t k = 0;
288 k < tValue.length(); ++k )
289 {
290 tValue( k ) *= tScale ;
291 }
292 }
293 else
294 {
295 // no declared level to calibrate against:
296 // keep the clamp rather than guess a unit
297 tT.set_size( 0, 0.0 );
298 tValue.set_size( 0, 0.0 );
299 }
300 }
301 }
302 }
303 H5Gclose( tGroup );
304 }
305 }
306 H5Fclose( tFile );
307 }
308 }
309 #endif
310
311 // the LENGTH is decided on rank 0 and must reach the others
312 // before the payload: a few dozen entries, so broadcast rather
313 // than the chunked share/receive pair
314 uint tN = ( comm_rank() == 0 ) ? ( uint ) tT.length() : 0 ;
315 broadcast( tN );
316
317 if ( tN == 0 ) return ;
318
319 if ( comm_rank() != 0 )
320 {
321 tT.set_size( tN, 0.0 );
322 tValue.set_size( tN, 0.0 );
323 }
324 broadcast( tT );
325 broadcast( tValue );
326
327 mSelfFieldT = tT ;
328 mSelfFieldValue = tValue ;
329 mHaveSelfField = true ;
330 }
331
342 void
344 const Matrix< real > & aPoints,
345 const index_t aColT,
346 const index_t aColB,
347 const index_t aColV,
348 const real aScale,
349 Vector< real > & aT,
350 Vector< real > & aValue ) const
351 {
352 const index_t tNumRows = aPoints.n_rows() ;
353
354 // one setpoint's temperature jitter is a few hundredths of a
355 // kelvin; the setpoint spacing is 2.5 K
356 constexpr real tTol = 0.25 ;
357
358 Cell< real > tT ;
359 Cell< real > tSum ;
360 Cell< uint > tCount ;
361
362 for ( index_t i = 0; i < tNumRows; ++i )
363 {
364 const real tB = aPoints( i, aColB ) ;
365 const real tTi = aPoints( i, aColT ) ;
366 const real tVi = aPoints( i, aColV ) ;
367
368 // exact self-field rows only. The source carries NaNs in
369 // rows where a fit did not converge; those must not enter
370 // an average
371 if ( tB != 0.0 ) continue ;
372 if ( ! std::isfinite( tTi ) ) continue ;
373 if ( ! std::isfinite( tVi ) ) continue ;
374 if ( tVi <= 0.0 ) continue ;
375
376 index_t tBin = tT.size() ;
377 for ( index_t k = 0; k < tT.size(); ++k )
378 {
379 if ( std::abs( tT( k ) - tTi ) < tTol ) { tBin = k ; break ; }
380 }
381
382 if ( tBin == tT.size() )
383 {
384 tT.push( tTi );
385 tSum.push( tVi );
386 tCount.push( 1 );
387 }
388 else
389 {
390 tSum( tBin ) += tVi ;
391 ++tCount( tBin ) ;
392 }
393 }
394
395 const index_t tNumBins = tT.size() ;
396 if ( tNumBins < 2 ) return ;
397
398 // ascending in T, as self_field() assumes
399 Vector< index_t > tOrder( tNumBins );
400 for ( index_t k = 0; k < tNumBins; ++k ) tOrder( k ) = k ;
401
402 for ( index_t a = 0; a + 1 < tNumBins; ++a )
403 {
404 for ( index_t b = a + 1; b < tNumBins; ++b )
405 {
406 if ( tT( tOrder( b ) ) < tT( tOrder( a ) ) )
407 {
408 const index_t tSwap = tOrder( a ) ;
409 tOrder( a ) = tOrder( b ) ;
410 tOrder( b ) = tSwap ;
411 }
412 }
413 }
414
415 aT.set_size( tNumBins, 0.0 );
416 aValue.set_size( tNumBins, 0.0 );
417
418 for ( index_t k = 0; k < tNumBins; ++k )
419 {
420 const index_t j = tOrder( k ) ;
421 aT( k ) = tT( j ) ;
422 aValue( k ) = aScale * tSum( j )
423 / static_cast< real >( tCount( j ) ) ;
424 }
425 }
426
431 {
432 delete mDatabase ;
433 }
434
437 real
438 min_value() const override
439 {
440 return std::pow( 10., min( mDatabase->values() ) ) ;
441 }
442
443 //--------------------------------------------------------------
444 // low-field transition
445 //--------------------------------------------------------------
446 //
447 // Below mBmin the table has no data and the historical behaviour
448 // was a hard clamp: jc constant in B, d/dB identically zero. Two
449 // problems, both measured. The clamp is wrong by up to 23 % near
450 // Tc ( the deck's whole self-field range sits under the floor ),
451 // and the tangent jumps from 0 to the spline slope the instant
452 // |B| crosses mBmin, which is a Newton tangent.
453 //
454 // The replacement is a quadratic in LINEAR B -- the same move
455 // Copper::create_kohler makes for magnetoresistance, where the
456 // physical boundary condition is built into the polynomial's form
457 // rather than imposed afterwards:
458 //
459 // jc(B) = J0 + c B + b B^2
460 //
461 // anchored at the MEASURED angle-free self-field level J0(T) and
462 // matching the table's own value and slope at mBmin, so the join
463 // is C1 and nothing at or above mBmin changes.
464 //
465 // Two properties are not conveniences, they are what the data and
466 // the literature require:
467 //
468 // * The linear term is KEPT. The Kim family used throughout the
469 // HTS literature -- jc = jc0 / ( 1 + |B_eff|/B0 )^alpha, e.g.
470 // Riva et al. 2023 Eq. 2 and Denis et al. 2026 Eq. 11, with
471 // Messe et al. 2023 §2.6 naming Kim 1962 -- has
472 // d jc / d|B| = -jc0 alpha / B0 at B = 0: FINITE and non-zero.
473 // A form with zero slope at the origin would contradict it.
474 // * J0 is ANGLE-FREE, and by measurement rather than by fiat. In
475 // the Kim family the anisotropy enters only inside |B_eff|, so
476 // it vanishes with the field; the embedded source rows agree,
477 // scattering only 0.25-0.73 % across 55 stage angles at B = 0
478 // while the table spreads ~4 % at mBmin. Carrying the mBmin
479 // angular shape down to the axis was measured to overshoot the
480 // permitted spread by an order of magnitude, which is why J0
481 // cannot be extrapolated from the table and is read instead.
482 //
483 // Monotone as long as J0 >= jc(mBmin, theta) for every theta,
484 // which the measurements satisfy; see the guard in eval().
485
489 static real
491 const Vector< real > & aValue,
492 const real T, real & dJ0dT )
493 {
494 const index_t tN = aT.length() ;
495
496 if ( T <= aT( 0 ) )
497 {
498 dJ0dT = 0.0 ;
499 return aValue( 0 ) ;
500 }
501 if ( T >= aT( tN - 1 ) )
502 {
503 dJ0dT = 0.0 ;
504 return aValue( tN - 1 ) ;
505 }
506
507 index_t k = 1 ;
508 while ( k < tN - 1 && aT( k ) < T ) ++k ;
509
510 const real tDT = aT( k ) - aT( k - 1 ) ;
511 dJ0dT = ( aValue( k ) - aValue( k - 1 ) ) / tDT ;
512
513 return aValue( k - 1 )
514 + dJ0dT * ( T - aT( k - 1 ) ) ;
515 }
516
517 real
518 self_field( const real T, real & dJ0dT ) const
519 {
520 // every internal caller sits behind mHaveSelfField; a future
521 // external caller must not turn an empty curve into an
522 // out-of-bounds read ( code-audit, Grok finding 4 )
523 BELFEM_ASSERT( mHaveSelfField,
524 "self_field() called on a table without a self-field curve" );
525 return interp_curve( mSelfFieldT, mSelfFieldValue, T, dJ0dT ) ;
526 }
527
529 void
530 edge_value_and_slope( const real angle, const real T,
531 real & V, real & S ) const
532 {
533 const real tTc = std::clamp( T, mTmin, mTmax ) ;
534 const real tU = std::log( mBmin ) * mInvLn10 ;
535 const real tTh = this->wrap_angle( angle ) ;
536
537 // the VALUE goes through eval() rather than the raw spline so
538 // that anything eval() applies to the stored field ( e.g. a
539 // lift-factor reference shift ) reaches the bridge too; the
540 // log-slope is invariant under such an additive shift, so the
541 // derivative may read the spline directly
542 V = this->eval( mBmin, angle, T ) ;
543 S = V * mDatabase->evaluate_derivy( tTc, tU, tTh ) / mBmin ;
544 }
545
555 real
556 wrap_angle( const real angle ) const
557 {
558 return angle < mAngleMin - 1e-6 ? angle + constant::pi :
559 angle > mAngleMax + 1e-6 ? angle - constant::pi :
560 std::clamp( angle, mAngleMin, mAngleMax );
561 }
562
586 real
587 eval( const real normB, const real angle, const real T ) const override
588 {
589 if ( mHaveSelfField && normB < mBmin )
590 {
591 real tJ0dT ;
592 const real tJ0 = this->self_field( T, tJ0dT ) ;
593 real tV, tS ;
594 this->edge_value_and_slope( angle, T, tV, tS ) ;
595
596 // a table whose edge value exceeds the measured
597 // self-field level cannot be bridged monotonically --
598 // that is an inconsistent table, not a physical case
599 if ( tJ0 < tV ) return tV ;
600
601 const real tD = tV - tJ0 ;
602 real tC = 2. * tD / mBmin - tS ;
603 real tB ;
604
605 // monotone limiter ( code-audit finding 2 ): with a steep
606 // table slope and a small lift the exact-match quadratic
607 // turns non-monotone ( measured: 60 % of (T,theta) pairs,
608 // worst interior hump 6.1 % near Tc ). Where c would be
609 // positive, fall to the pure parabola: value match kept,
610 // monotone by construction, tangents endpoint-exact; the
611 // cost is a bounded one-sided slope kink at the join, at
612 // angles where the lift is nearly zero anyway
613 if ( tC > 0.0 )
614 {
615 tC = 0.0 ;
616 tB = tD / ( mBmin * mBmin ) ;
617 }
618 else
619 {
620 tB = ( tS - tD / mBmin ) / mBmin ;
621 }
622
623 return tJ0 + normB * ( tC + normB * tB ) ;
624 }
625
626 return std::pow( 10.,
627 mDatabase->evaluate(
628 std::clamp( T, mTmin, mTmax ),
629 std::log( std::clamp( normB, mBmin, mBmax ) ) * mInvLn10,
630 this->wrap_angle( angle ) ) );
631 }
632
649 real
650 deval_dB( const real normB, const real angle, const real T ) const override
651 {
652 if ( mHaveSelfField && normB < mBmin )
653 {
654 real tJ0dT ;
655 const real tJ0 = this->self_field( T, tJ0dT ) ;
656 real tV, tS ;
657 this->edge_value_and_slope( angle, T, tV, tS ) ;
658 if ( tJ0 < tV ) return 0.0 ;
659
660 const real tD = tV - tJ0 ;
661 real tC = 2. * tD / mBmin - tS ;
662 real tB ;
663
664 // monotone limiter -- same branch as eval(), so the
665 // tangent differentiates the returned value exactly
666 if ( tC > 0.0 )
667 {
668 tC = 0.0 ;
669 tB = tD / ( mBmin * mBmin ) ;
670 }
671 else
672 {
673 tB = ( tS - tD / mBmin ) / mBmin ;
674 }
675
676 // -> tS at mBmin ( C1 ) on the exact branch, -> tC
677 // finite at B = 0 ( Kim ) where the limiter is idle
678 return tC + 2. * tB * normB ;
679 }
680
681 if ( normB <= mBmin || normB >= mBmax ) return 0.0 ;
682
683 return this->eval( normB, angle, T )
684 * mDatabase->evaluate_derivy(
685 std::clamp( T, mTmin, mTmax ),
686 std::log( normB ) * mInvLn10,
687 this->wrap_angle( angle ) )
688 / normB ;
689 }
690
698 real
699 deval_dbeta( const real normB, const real angle, const real T ) const override
700 {
701 if ( mHaveSelfField && normB < mBmin )
702 {
703 // J0 is angle-free, so only c and b carry theta:
704 // d/dtheta = Vth ( 2 beta - beta^2 )
705 // + Sth mBmin ( beta^2 - beta ), beta = B/mBmin
706 // EXACT at both ends -- the second bracket vanishes at
707 // beta = 0 and beta = 1, so this reproduces 0 at zero
708 // field and the table's own dV/dtheta at mBmin.
709 //
710 // DECLARED APPROXIMATION: Sth = d/dtheta ( dV/dB ) needs a
711 // MIXED spline partial that Database does not expose, and
712 // is taken as zero. The dropped term is bounded by
713 // |Sth| mBmin/4 ( the extremum of beta^2 - beta ), i.e. it
714 // is worst mid-interval and exactly zero where the tangent
715 // has to match. Supplying mixed partials would remove it.
716 real tJ0dT ;
717 const real tJ0 = this->self_field( T, tJ0dT ) ;
718 real tV, tS ;
719 this->edge_value_and_slope( angle, T, tV, tS ) ;
720
721 const real tVth0 = tV * mDatabase->evaluate_derivz(
722 std::clamp( T, mTmin, mTmax ),
723 std::log( mBmin ) * mInvLn10,
724 this->wrap_angle( angle ) ) / mInvLn10 ;
725
726 // inconsistent table: eval() degrades to the historical
727 // clamp, so the tangent must be the CLAMP's tangent --
728 // the value still varies with theta there, and a zero
729 // here would hand Newton a derivative that does not
730 // differentiate the value ( code-audit finding 1 )
731 if ( tJ0 < tV ) return tVth0 ;
732
733 const real tBeta = normB / mBmin ;
734
735 // limiter branch: value = J0 + D(theta) beta^2, so the
736 // theta shape factor is beta^2 instead of beta( 2-beta );
737 // both are endpoint-exact ( 0 at B = 0, tVth0 at mBmin )
738 const real tD = tV - tJ0 ;
739 const bool tLimited = ( 2. * tD / mBmin - tS ) > 0.0 ;
740
741 return tVth0 * ( tLimited ? tBeta * tBeta
742 : tBeta * ( 2. - tBeta ) ) ;
743 }
744
745 return this->eval( normB, angle, T )
746 * mDatabase->evaluate_derivz(
747 std::clamp( T, mTmin, mTmax ),
748 std::log( std::clamp( normB, mBmin, mBmax ) ) * mInvLn10,
749 this->wrap_angle( angle ) )
750 / mInvLn10 ;
751 }
752
760 real
761 deval_dT( const real normB, const real angle, const real T ) const override
762 {
763 if ( mHaveSelfField && normB < mBmin )
764 {
765 // d/dT = J0' + ( VT - J0' )( 2 beta - beta^2 )
766 // + ST mBmin ( beta^2 - beta )
767 // exact at beta = 0 ( -> J0', the measured self-field
768 // slope ) and at beta = 1 ( -> VT, the table's own dV/dT ).
769 // ST is dropped on the same bound as Sth in deval_dbeta.
770 real tJ0dT ;
771 const real tJ0 = this->self_field( T, tJ0dT ) ;
772 real tV, tS ;
773 this->edge_value_and_slope( angle, T, tV, tS ) ;
774
775 const real tVT = ( T <= mTmin || T >= mTmax ) ? 0.0 :
776 tV * mDatabase->evaluate_derivx(
777 T,
778 std::log( mBmin ) * mInvLn10,
779 this->wrap_angle( angle ) ) / mInvLn10 ;
780
781 // inconsistent table: clamp value, clamp tangent -- see
782 // deval_dbeta. dT is a live thermal Newton tangent
783 if ( tJ0 < tV ) return tVT ;
784
785 const real tBeta = normB / mBmin ;
786
787 // shape factor follows eval()'s limiter branch
788 const real tD = tV - tJ0 ;
789 const bool tLimited = ( 2. * tD / mBmin - tS ) > 0.0 ;
790 const real tShape = tLimited ? tBeta * tBeta
791 : tBeta * ( 2. - tBeta ) ;
792
793 return tJ0dT + ( tVT - tJ0dT ) * tShape ;
794 }
795
796 if ( T <= mTmin || T >= mTmax ) return 0.0 ;
797
798 return this->eval( normB, angle, T )
799 * mDatabase->evaluate_derivx(
800 T,
801 std::log( std::clamp( normB, mBmin, mBmax ) ) * mInvLn10,
802 this->wrap_angle( angle ) )
803 / mInvLn10 ;
804 }
805 };
806 }
807}
808#endif //BELFEM_CL_JCFUNCTIONDATABASE_HPP
#define BELFEM_ERROR(aCheck,...)
Definition assert.hpp:264
#define BELFEM_ASSERT(aCheck,...)
Definition assert.hpp:244
Base class hierarchy for critical current density (Jc) and n-value functions.
size_t size() const
return the size of the Cell
Definition cl_Cell.hpp:181
void push(const T &aValue)
push an entry to the end of the cell (copy version)
Definition cl_Cell.hpp:262
Precomputed lookup table on a tensor grid; evaluation, derivatives and HDF5 persistence.
Definition cl_Database.hpp:30
size_t n_rows() const
Definition cl_AR_Matrix.hpp:205
size_t n_cols() const
Definition cl_AR_Matrix.hpp:213
void set_size(const size_t aNumRows)
change the size of the vector
Definition cl_AR_Vector.hpp:237
size_t length() const
get the length of the vector
Definition cl_AR_Vector.hpp:257
real deval_dbeta(const real normB, const real angle, const real T) const override
d(value)/dθ from the spline
Definition cl_JcFunction_Database.hpp:699
~JcFunctionDatabase() override
Destructor - deletes the database.
Definition cl_JcFunction_Database.hpp:430
void edge_value_and_slope(const real angle, const real T, real &V, real &S) const
the table's own value and d/dB at the low-field edge
Definition cl_JcFunction_Database.hpp:530
real deval_dT(const real normB, const real angle, const real T) const override
d(value)/dT from the spline, clamp-consistent
Definition cl_JcFunction_Database.hpp:761
real self_field(const real T, real &dJ0dT) const
Definition cl_JcFunction_Database.hpp:518
real wrap_angle(const real angle) const
Wrap the caller's angle into the table window.
Definition cl_JcFunction_Database.hpp:556
static real interp_curve(const Vector< real > &aT, const Vector< real > &aValue, const real T, real &dJ0dT)
Definition cl_JcFunction_Database.hpp:490
void reduce_self_field_rows(const Matrix< real > &aPoints, const index_t aColT, const index_t aColB, const index_t aColV, const real aScale, Vector< real > &aT, Vector< real > &aValue) const
Bin the B = 0 rows by temperature and average over angle.
Definition cl_JcFunction_Database.hpp:343
real eval(const real normB, const real angle, const real T) const override
Evaluate Jc or n at given field, angle, and temperature.
Definition cl_JcFunction_Database.hpp:587
JcFunctionDatabase(const string &aPath, const string &aLabel)
Constructor - loads database from file.
Definition cl_JcFunction_Database.hpp:109
void load_self_field(const string &aPath, const string &aLabel)
Read the measured B = 0 level from the table's /source.
Definition cl_JcFunction_Database.hpp:154
real deval_dB(const real normB, const real angle, const real T) const override
d(value)/d|B| from the spline, clamp-consistent
Definition cl_JcFunction_Database.hpp:650
real min_value() const override
Definition cl_JcFunction_Database.hpp:438
void set_dependency(const JcParameter aParameter)
Mark function as depending on a parameter.
Definition cl_JcFunction.cpp:20
JcFunction()=default
Default constructor.
Smallest entry of a vector, matrix or column view.
const real pi
circle number
Definition constants.hpp:41
bool group_exists(hid_t aLoc, const std::string &aLabel)
test if a group exists ( tests for a link of that name; the link type is not checked )
Definition hdf5_tools.hpp:54
void load_scalar_from_file(hid_t &aLoc, const std::string &aLabel, T &aValue, herr_t &aStatus)
Definition hdf5_tools.hpp:300
void load_strings_from_file(hid_t &aLoc, const std::string &aLabel, Cell< string > &aCell, herr_t &aStatus)
Definition hdf5_tools.hpp:1023
void load_matrix_from_file(hid_t &aLoc, const std::string &aLabel, Matrix< T > &aMatrix, herr_t &aStatus, const bool aTranspose=false)
Definition hdf5_tools.hpp:841
bool dataset_exists(hid_t aLoc, const std::string &aLabel)
test if a dataset exists ( tests for a link of that name; the link type is not checked )
Definition hdf5_tools.hpp:37
Definition cl_BhCurve.cpp:19
@ angleNxB
Definition cl_JcFunction.hpp:82
@ normB
Definition cl_JcFunction.hpp:81
@ T
Definition cl_JcFunction.hpp:83
USER GUIDES:
Definition cl_Capacitor.cpp:16
proc_t comm_rank()
Returns the rank of the current process in the communicator.
Definition commtools.cpp:30
int hid_t
Definition hdf5_types.hpp:20
unsigned int uint
Definition typedefs.hpp:30
T max(const Vector< T > &aVector)
Definition fn_AR_max.hpp:24
T min(const Vector< T > &aVector)
Definition fn_AR_min.hpp:25
void broadcast(Cell< string > &aData, const proc_t aRoot)
Definition commtools.cpp:276
uint32_t index_t
Definition typedefs.hpp:52
int herr_t
Definition hdf5_types.hpp:21
double real
Definition typedefs.hpp:36